Starsector API
Loading...
Searching...
No Matches
SalvageEntity.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.rulecmd.salvage;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.LinkedHashMap;
6import java.util.List;
7import java.util.Map;
8import java.util.Random;
9
10import org.lwjgl.input.Keyboard;
11import org.lwjgl.util.vector.Vector2f;
12
13import com.fs.starfarer.api.Global;
14import com.fs.starfarer.api.campaign.CampaignFleetAPI;
15import com.fs.starfarer.api.campaign.CargoAPI;
16import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
17import com.fs.starfarer.api.campaign.CargoStackAPI;
18import com.fs.starfarer.api.campaign.CoreInteractionListener;
19import com.fs.starfarer.api.campaign.FactionAPI;
20import com.fs.starfarer.api.campaign.InteractionDialogAPI;
21import com.fs.starfarer.api.campaign.OptionPanelAPI;
22import com.fs.starfarer.api.campaign.ResourceCostPanelAPI;
23import com.fs.starfarer.api.campaign.SectorEntityToken;
24import com.fs.starfarer.api.campaign.SpecialItemData;
25import com.fs.starfarer.api.campaign.TextPanelAPI;
26import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
27import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
28import com.fs.starfarer.api.campaign.rules.MemoryAPI;
29import com.fs.starfarer.api.combat.MutableStat;
30import com.fs.starfarer.api.combat.MutableStat.StatMod;
31import com.fs.starfarer.api.combat.ShipVariantAPI;
32import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin;
33import com.fs.starfarer.api.impl.campaign.RepairGantry;
34import com.fs.starfarer.api.impl.campaign.ids.Commodities;
35import com.fs.starfarer.api.impl.campaign.ids.Entities;
36import com.fs.starfarer.api.impl.campaign.ids.Items;
37import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
38import com.fs.starfarer.api.impl.campaign.ids.Stats;
39import com.fs.starfarer.api.impl.campaign.ids.Tags;
40import com.fs.starfarer.api.impl.campaign.procgen.DropGroupRow;
41import com.fs.starfarer.api.impl.campaign.procgen.SalvageEntityGenDataSpec;
42import com.fs.starfarer.api.impl.campaign.procgen.SalvageEntityGenDataSpec.DropData;
43import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
44import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageEntityGeneratorOld;
45import com.fs.starfarer.api.impl.campaign.rulecmd.BaseCommandPlugin;
46import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
47import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.BaseSalvageSpecial;
48import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipRecoverySpecialData;
49import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin;
50import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldParams;
51import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldSource;
52import com.fs.starfarer.api.ui.Alignment;
53import com.fs.starfarer.api.ui.TooltipMakerAPI;
54import com.fs.starfarer.api.ui.TooltipMakerAPI.StatModValueGetter;
55import com.fs.starfarer.api.util.Misc;
56import com.fs.starfarer.api.util.Misc.Token;
57import com.fs.starfarer.api.util.WeightedRandomPicker;
58
63public class SalvageEntity extends BaseCommandPlugin {
64
65 public static float SALVAGE_DETECTION_MOD_FLAT = 1000;
66
67 public static int FIELD_RADIUS_FOR_BASE_REQ = 200;
68 public static int FIELD_RADIUS_FOR_MAX_REQ = 1000;
69 public static int FIELD_RADIUS_MAX_REQ_MULT = 10;
70 public static float FIELD_MIN_SALVAGE_MULT = 0.01f;
71
72
73
74 //public static float FIELD_SALVAGE_FRACTION_PER_ATTEMPT = 0.5f;
75 public static float FIELD_SALVAGE_FRACTION_PER_ATTEMPT = 1f;
76
77 public static float FIELD_CONTENT_MULTIPLIER_AFTER_SALVAGE = 0.25f;
78 //public static float FIELD_CONTENT_MULTIPLIER_AFTER_DEMOLITION = 0.65f;
80
81 public static int BASE_MACHINERY = 10;
82 public static int BASE_CREW = 30;
83 public static int MIN_MACHINERY = 5;
84
85 public static float COST_HEIGHT = 67;
86
87
88 protected CampaignFleetAPI playerFleet;
89 protected SectorEntityToken entity;
90 protected FactionAPI playerFaction;
91 protected FactionAPI entityFaction;
92 protected TextPanelAPI text;
93 protected OptionPanelAPI options;
94 protected SalvageEntityGenDataSpec spec;
95 protected CargoAPI cargo;
96 protected MemoryAPI memory;
97 protected InteractionDialogAPI dialog;
98 private DebrisFieldTerrainPlugin debris;
99 private Map<String, MemoryAPI> memoryMap;
100
101
102 public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) {
103
104 this.dialog = dialog;
105 this.memoryMap = memoryMap;
106
107 String command = params.get(0).getString(memoryMap);
108 if (command == null) return false;
109
110 memory = getEntityMemory(memoryMap);
111
112 entity = dialog.getInteractionTarget();
113
114 String specId = entity.getCustomEntityType();
115 if (specId == null || entity.getMemoryWithoutUpdate().contains(MemFlags.SALVAGE_SPEC_ID_OVERRIDE)) {
116 specId = entity.getMemoryWithoutUpdate().getString(MemFlags.SALVAGE_SPEC_ID_OVERRIDE);
117 }
118 spec = SalvageEntityGeneratorOld.getSalvageSpec(specId);
119
120 text = dialog.getTextPanel();
121 options = dialog.getOptionPanel();
122
123 playerFleet = Global.getSector().getPlayerFleet();
124 cargo = playerFleet.getCargo();
125
126 playerFaction = Global.getSector().getPlayerFaction();
127 entityFaction = entity.getFaction();
128
129 Object test = entity.getMemoryWithoutUpdate().get(MemFlags.SALVAGE_DEBRIS_FIELD);
130 if (test instanceof DebrisFieldTerrainPlugin) {
131 debris = (DebrisFieldTerrainPlugin) test;
132 }
133
134 if (command.equals("showCost")) {
135 if (debris == null) {
136 showCost();
137 } else {
138 //showCost();
140 }
141 } else if (command.equals("performSalvage")) {
143 } else if (command.equals("descDebris")) {
144 showDebrisDescription();
145 } else if (command.equals("checkAccidents")) {
146 checkAccidents();
147 } else if (command.equals("demolish")) {
148 demolish();
149 } else if (command.equals("canBeMadeRecoverable")) {
150 return canBeMadeRecoverable();
151 } else if (command.equals("showRecoverable")) {
153 }
154
155 return true;
156 }
157
158 private void demolish() {
159 boolean isDebrisField = Entities.DEBRIS_FIELD_SHARED.equals(entity.getCustomEntityType());
160 if (!isDebrisField) {
162
163 Global.getSoundPlayer().playSound("hit_heavy", 1, 1, Global.getSoundPlayer().getListenerPos(), new Vector2f());
164
165 dialog.dismiss();
166
167// text.addParagraph("Salvage crews set targeting beacons at key points in the structure, " +
168// "and you give the order to fire once everyone is safely off.");
169// text.addParagraph("Salvage crews set targeting beacons at key points in the structure.");
170// options.clearOptions();
171// options.addOption("Leave", "defaultLeave");
172// options.setShortcut("defaultLeave", Keyboard.KEY_ESCAPE, false, false, false, true);
173 }
174 }
175
176 private float getAccidentProbability() {
177 if (debris == null) return 0f;
178 float accidentProbability = 0.2f + 0.8f * (1f - debris.getParams().density);
179 if (accidentProbability > 0.9f) accidentProbability = 0.9f;
180 return accidentProbability;
181 }
182
183 private void checkAccidents() {
184 if (debris == null) {
185 memory.set("$option", "salPerform");
186 FireBest.fire(null, dialog, memoryMap, "DialogOptionSelected");
187 return;
188 }
189
190 float accidentProbability = getAccidentProbability();
191 //accidentProbability = 1f;
192
193 long seed = memory.getLong(MemFlags.SALVAGE_SEED);
194 Random random = Misc.getRandom(seed, 175);
195
196 if (random.nextFloat() > accidentProbability) {
197 memory.set("$option", "salPerform");
198 FireBest.fire(null, dialog, memoryMap, "DialogOptionSelected");
199 return;
200 }
201
202 Color color = playerFaction.getColor();
203 Color bad = Misc.getNegativeHighlightColor();
204 Color highlight = Misc.getHighlightColor();
205
206 Map<String, Integer> requiredRes = computeRequiredToSalvage(entity);
207 float reqCrew = (int) requiredRes.get(Commodities.CREW);
208 float reqMachinery = (int) requiredRes.get(Commodities.HEAVY_MACHINERY);
209
210 float crew = playerFleet.getCargo().getCrew();
211 float machinery = playerFleet.getCargo().getCommodityQuantity(Commodities.HEAVY_MACHINERY);
212 float fCrew = crew / reqCrew;
213 if (fCrew < 0) fCrew = 0;
214 if (fCrew > 1) fCrew = 1;
215
216 float fMachinery = machinery / reqMachinery;
217 if (fMachinery < 0) fMachinery = 0;
218 if (fMachinery > 1) fMachinery = 1;
219
220
221// CommoditySpecAPI crewSpec = Global.getSector().getEconomy().getCommoditySpec(Commodities.CREW);
222// CommoditySpecAPI machinerySpec = Global.getSector().getEconomy().getCommoditySpec(Commodities.HEAVY_MACHINERY);
223
224 float lossValue = reqCrew * fCrew * 5f;
225 lossValue += (1f - debris.getParams().density / debris.getParams().baseDensity) * 500f;
226 lossValue *= 0.5f + random.nextFloat();
227 //lossValue *= StarSystemGenerator.getNormalRandom(random, 0.5f, 1.5f);
228
229 WeightedRandomPicker<String> lossPicker = new WeightedRandomPicker<String>(random);
230 lossPicker.add(Commodities.CREW, 10f + 100f * (1f - fMachinery));
231 lossPicker.add(Commodities.HEAVY_MACHINERY, 10f + 100f * fMachinery);
232
233 CargoAPI losses = Global.getFactory().createCargo(true);
234 float loss = 0;
235 while (loss < lossValue) {
236 String id = lossPicker.pick();
237 CommoditySpecAPI spec = Global.getSector().getEconomy().getCommoditySpec(id);
238 loss += spec.getBasePrice();
239 losses.addCommodity(id, 1f);
240 }
241 losses.sort();
242
243 int crewLost = losses.getCrew();
244 if (crewLost > 0) {
245 losses.removeCrew(crewLost);
246 crewLost *= playerFleet.getStats().getDynamic().getValue(Stats.NON_COMBAT_CREW_LOSS_MULT);
247 if (crewLost < 1) crewLost = 1;
248 losses.addCrew(crewLost);
249 }
250
251 int machineryLost = (int) losses.getCommodityQuantity(Commodities.HEAVY_MACHINERY);
252 if (crewLost > crew) crewLost = (int) crew;
253 if (machineryLost > machinery) machineryLost = (int) machinery;
254
255 if (crewLost <= 0 && machineryLost <= 0) {
256 memory.set("$option", "salPerform");
257 FireBest.fire(null, dialog, memoryMap, "DialogOptionSelected");
258 }
259
260
261 for (CargoStackAPI stack : losses.getStacksCopy()) {
262 cargo.removeCommodity(stack.getCommodityId(), stack.getSize());
263 }
264
265
266
267 text.setFontInsignia();
268 text.addParagraph("An accident during the operation has resulted in the loss of ");
269
270 if (crewLost <= 0) {
271 text.appendToLastParagraph("" + machineryLost + " heavy machinery.");
272 text.highlightInLastPara(highlight, "" + machineryLost);
273 } else if (machineryLost <= 0) {
274 text.appendToLastParagraph("" + crewLost + " crew.");
275 text.highlightInLastPara(highlight, "" + crewLost);
276 } else {
277 text.appendToLastParagraph("" + crewLost + " crew and " + machineryLost + " heavy machinery.");
278 text.highlightInLastPara(highlight, "" + crewLost, "" + machineryLost);
279 }
280
281
282 Global.getSoundPlayer().playSound("hit_solid", 1, 1, Global.getSoundPlayer().getListenerPos(), new Vector2f());
283
284 options.clearOptions();
285 options.addOption("Continue", "salPerform");
286 //FireBest.fire(null, dialog, memoryMap, "PerformSalvage");
287 //FireBest.fire(null, dialog, memoryMap, "PerformSalvage");
288 }
289
290 private void showDebrisDescription() {
291 if (debris == null) return;
292
293 float daysLeft = debris.getDaysLeft();
294 if (daysLeft >= 1000) {
295 text.addParagraph("The field appears stable and will not drift apart any time soon.");
296 } else {
297 String atLeastTime = Misc.getAtLeastStringForDays((int) daysLeft);
298 text.addParagraph("The field is unstable, but should not drift apart for " + atLeastTime + ".");
299 }
300
301// boolean stillHot = debris.getGlowDaysLeft() > 0;
302// switch (debris.getParams().source) {
303// case BATTLE:
304// text.addParagraph("Pieces of ships, weapons, and escape pods litter the starscape.");
305// break;
306// case MIXED:
307// text.addParagraph("Pieces of ships, weapons, and escape pods litter the starscape.");
308// break;
309// case PLAYER_SALVAGE:
310// break;
311// case SALVAGE:
312// break;
313// }
314
315// if (stillHot) {
316// text.appendToLastParagraph(" Some of the pieces of debris are still radiating heat, making any salvage operations more dangerous.");
317// }
318
319 float lootValue = 0;
320 for (DropData data : debris.getEntity().getDropValue()) {
321 lootValue += data.value;
322 }
323 for (DropData data : debris.getEntity().getDropRandom()) {
324 if (data.value > 0) {
325 lootValue += data.value;
326 } else {
327 lootValue += 500; // close enough
328 }
329 }
330 float d = debris.getParams().density;
331
332 lootValue *= d;
333
334 // doesn't work because "extra" expires
335// ExtraSalvage extra = BaseSalvageSpecial.getExtraSalvage(memoryMap);
336// if (extra != null) {
337// for (CargoStackAPI stack : extra.cargo.getStacksCopy()) {
338// lootValue += stack.getBaseValuePerUnit() * stack.getSize();
339// }
340// }
341
342 if (lootValue < 500) {
343 text.appendToLastParagraph(" Long-range scans indicate it's unlikely anything of much value would be found inside.");
344 text.highlightLastInLastPara("unlikely", Misc.getNegativeHighlightColor());
345 } else if (lootValue < 2500) {
346 text.appendToLastParagraph(" Long-range scans indicate it's possible something of value could be found inside.");
347 text.highlightLastInLastPara("possible", Misc.getHighlightColor());
348 } else {
349 text.appendToLastParagraph(" Long-range scans indicate it's likely something of value could be found inside.");
350 text.highlightLastInLastPara("likely", Misc.getPositiveHighlightColor());
351 }
352
353 float accidentProbability = getAccidentProbability();
354 if (accidentProbability <= 0.2f) {
355 //text.addParagraph("There are indications of some easy pickings to be had, and the risk of an accident during a salvage operation is low.");
356 text.addPara("There are indications of some easy pickings to be had, and the risk of an accident during a salvage operation is low.",
357 Misc.getPositiveHighlightColor(), "low");
358 } else if (accidentProbability < 0.7f) {
359 text.addPara("There are indications that what salvage is to be had may not be easy to get to, " +
360 "and there's %s risk involved in running a salvage operation.", Misc.getHighlightColor(), "significant");
361 } else {
362 text.addPara("The salvage that remains is extremely difficult to get to, " +
363 "and there's %s risk involved in running a salvage operation.", Misc.getNegativeHighlightColor(), "high");
364 }
365 }
366
367 public static Map<String, Integer> computeRequiredToSalvage(SectorEntityToken entity) {
368 Map<String, Integer> result = new LinkedHashMap<String, Integer>();
369
370 String specId = entity.getCustomEntityType();
371 if (specId == null || entity.getMemoryWithoutUpdate().contains(MemFlags.SALVAGE_SPEC_ID_OVERRIDE)) {
372 specId = entity.getMemoryWithoutUpdate().getString(MemFlags.SALVAGE_SPEC_ID_OVERRIDE);
373 }
374 SalvageEntityGenDataSpec spec = SalvageEntityGeneratorOld.getSalvageSpec(specId);
375 float mult = 1f + spec.getSalvageRating() * 9f;
376
377 Object test = entity.getMemoryWithoutUpdate().get(MemFlags.SALVAGE_DEBRIS_FIELD);
378 if (test instanceof DebrisFieldTerrainPlugin) {
379 DebrisFieldTerrainPlugin debris = (DebrisFieldTerrainPlugin) test;
380 mult = getDebrisReqMult(debris);
381 }
382
383 int crew = Math.round((int) (BASE_CREW * mult) / 10f) * 10;
384 int machinery = Math.round((int) (BASE_MACHINERY * mult) / 10f) * 10;
385
386 result.put(Commodities.CREW, crew);
387 result.put(Commodities.HEAVY_MACHINERY, machinery);
388
389 return result;
390 }
391
392 protected MutableStat getValueRecoveryStat(boolean withSkillMultForRares) {
393 Map<String, Integer> requiredRes = computeRequiredToSalvage(entity);
394 MutableStat valueRecovery = new MutableStat(1f);
395 int i = 0;
396
397 float machineryContrib = 0.75f;
398 valueRecovery.modifyPercent("base", -100f);
399 if (machineryContrib < 1f) {
400 valueRecovery.modifyPercent("base_positive", (int) Math.round(100f - 100f * machineryContrib), "Base effectiveness");
401 }
402 //valueRecovery.modifyPercent("base", -75f);
403
404 float per = 0.5f;
405 per = 1f;
406 for (String commodityId : requiredRes.keySet()) {
407 float required = requiredRes.get(commodityId);
408 float available = (int) cargo.getCommodityQuantity(commodityId);
409 if (required <= 0) continue;
410 CommoditySpecAPI spec = Global.getSector().getEconomy().getCommoditySpec(commodityId);
411
412 float val = Math.min(available / required, 1f) * per;
413 int percent = (int) Math.round(val * 100f);
414 //valueRecovery.modifyPercent("" + i++, percent, Misc.ucFirst(spec.getLowerCaseName()) + " requirements met");
415 if (Commodities.HEAVY_MACHINERY.equals(commodityId)) {
416 val = Math.min(available / required, machineryContrib) * per;
417 percent = (int) Math.round(val * 100f);
418 valueRecovery.modifyPercentAlways("" + i++, percent, Misc.ucFirst(spec.getLowerCaseName()) + " available");
419 } else {
420 valueRecovery.modifyMultAlways("" + i++, val, Misc.ucFirst(spec.getLowerCaseName()) + " available");
421 }
422// float val = Math.max(1f - available / required, 0f) * per;
423// int percent = -1 * (int) Math.round(val * 100f);
424// valueRecovery.modifyPercent("" + i++, percent, "Insufficient " + spec.getLowerCaseName());
425 }
426
427 boolean modified = false;
428 if (withSkillMultForRares) {
429 for (StatMod mod : playerFleet.getStats().getDynamic().getStat(Stats.SALVAGE_VALUE_MULT_FLEET_INCLUDES_RARE).getFlatMods().values()) {
430 modified = true;
431 valueRecovery.modifyPercentAlways("" + i++, (int) Math.round(mod.value * 100f), mod.desc);
432 }
433 }
434
435 {
436 for (StatMod mod : playerFleet.getStats().getDynamic().getStat(Stats.SALVAGE_VALUE_MULT_FLEET_NOT_RARE).getFlatMods().values()) {
437 modified = true;
438 valueRecovery.modifyPercentAlways("" + i++, (int) Math.round(mod.value * 100f), mod.desc);
439 }
440 }
441 if (!modified) {
442 valueRecovery.modifyPercentAlways("" + i++, (int) Math.round(0f), "Salvaging skill");
443 }
444
445 float fleetSalvageShips = getPlayerShipsSalvageModUncapped();
446 valueRecovery.modifyPercentAlways("" + i++, (int) Math.round(fleetSalvageShips * 100f), "Fleetwide salvaging capability");
447
448 return valueRecovery;
449 }
450
451// protected StatBonus getRareRecoveryStat() {
452// StatBonus rareRecovery = new StatBonus();
453// int i = 0;
454// for (StatMod mod : playerFleet.getStats().getDynamic().getMod(Stats.SALVAGE_MAX_RATING).getFlatBonuses().values()) {
455// rareRecovery.modifyPercent("" + i++, (int) Math.round(mod.value * 100f), mod.desc);
456// }
457// return rareRecovery;
458// }
459
460 public void showCost() {
461 Color color = playerFaction.getColor();
462 Color bad = Misc.getNegativeHighlightColor();
463 Color highlight = Misc.getHighlightColor();
464
465 float pad = 3f;
466 float opad = 10f;
467 float small = 5f;
468
469 Map<String, Integer> requiredRes = computeRequiredToSalvage(entity);
470
471 text.addParagraph("You receive a preliminary assessment of a potential salvage operation from the exploration crews.");
472
473 ResourceCostPanelAPI cost = text.addCostPanel("Crew & machinery: required (available)", COST_HEIGHT,
474 color, playerFaction.getDarkUIColor());
475 cost.setNumberOnlyMode(true);
476 cost.setWithBorder(false);
477 cost.setAlignment(Alignment.LMID);
478
479 for (String commodityId : requiredRes.keySet()) {
480 int required = requiredRes.get(commodityId);
481 int available = (int) cargo.getCommodityQuantity(commodityId);
482 Color curr = color;
483 if (required > cargo.getQuantity(CargoItemType.RESOURCES, commodityId)) {
484 curr = bad;
485 }
486 cost.addCost(commodityId, "" + required + " (" + available + ")", curr);
487 }
488 cost.update();
489
490
491 MutableStat valueRecovery = getValueRecoveryStat(true);
492
493 //rareRecovery.unmodify();
494 int valuePercent = (int)Math.round(valueRecovery.getModifiedValue() * 100f);
495 if (valuePercent < 0) valuePercent = 0;
496 String valueString = "" + valuePercent + "%";
497 Color valueColor = highlight;
498
499 if (valuePercent < 100) {
500 valueColor = bad;
501 }
502
503 TooltipMakerAPI info = text.beginTooltip();
504 info.setParaSmallInsignia();
505 info.addPara("Resource recovery effectiveness: %s", 0f, valueColor, valueString);
506 if (!valueRecovery.isUnmodified()) {
507 info.addStatModGrid(300, 50, opad, small, valueRecovery, true, getModPrinter());
508 }
509 text.addTooltip();
510
512 }
513
514 protected StatModValueGetter getModPrinter() {
515 return new StatModValueGetter() {
516 boolean percent = false;
517 public String getPercentValue(StatMod mod) {
518 percent = true;
519
520 // should make it not shown; it's a "base" value that has to be applied to make the calculations work with multipliers
521 if (mod.desc == null || mod.desc.isEmpty()) return "";
522
523 String prefix = mod.getValue() >= 0 ? "+" : "";
524 return prefix + (int)(mod.getValue()) + "%";
525 }
526 public String getMultValue(StatMod mod) {percent = false; return null;}
527 public String getFlatValue(StatMod mod) {percent = false; return null;}
528 public Color getModColor(StatMod mod) {
529 if ((!percent && mod.getValue() < 1f) || mod.getValue() < 0) return Misc.getNegativeHighlightColor();
530 return null;
531 }
532 };
533 }
534
535 protected void printSalvageModifiers() {
536
537 float fuelMult = playerFleet.getStats().getDynamic().getValue(Stats.FUEL_SALVAGE_VALUE_MULT_FLEET);
538 String fuelStr = "" + (int)Math.round((fuelMult - 1f) * 100f) + "%";
539
540 float rareMult = playerFleet.getStats().getDynamic().getValue(Stats.SALVAGE_VALUE_MULT_FLEET_INCLUDES_RARE);
541 String rareStr = "" + (int)Math.round((rareMult - 1f) * 100f) + "%";
542
543 if (fuelMult > 1f && rareMult > 1f) {
544 text.addPara("Your fleet also has a %s bonus to the amount of fuel recovered, and " +
545 "a %s bonus to the number of rare items found.",
546 Misc.getHighlightColor(), fuelStr, rareStr);
547 } else if (fuelMult > 1) {
548 text.addPara("Your fleet also has a %s bonus to the amount of fuel recovered.",
549 Misc.getHighlightColor(), fuelStr);
550 } else if (rareMult > 1) {
551 text.addPara("Your fleet also has a %s bonus to the number of rare items found.",
552 Misc.getHighlightColor(), rareStr);
553 }
554
555 if (debris != null) {
556 text.addParagraph("The density of the debris field affects both the amount of resources and the number of rare items found.");
557 } else {
558 text.addPara("The recovery effectiveness does not affect the chance of finding rare and valuable items.");
559 }
560
561 }
562
563 public void showCostDebrisField() {
564 Color color = playerFaction.getColor();
565 Color bad = Misc.getNegativeHighlightColor();
566 Color highlight = Misc.getHighlightColor();
567
568 float pad = 3f;
569 float opad = 10f;
570 float small = 5f;
571
572 Map<String, Integer> requiredRes = computeRequiredToSalvage(entity);
573
574 //text.addParagraph("You receive a preliminary assessment of a potential salvage operation from the exploration crews.");
575
576 ResourceCostPanelAPI cost = text.addCostPanel("Crew & machinery: required (available)", COST_HEIGHT,
577 color, playerFaction.getDarkUIColor());
578 cost.setNumberOnlyMode(true);
579 cost.setWithBorder(false);
580 cost.setAlignment(Alignment.LMID);
581
582 for (String commodityId : requiredRes.keySet()) {
583 int required = requiredRes.get(commodityId);
584 int available = (int) cargo.getCommodityQuantity(commodityId);
585 Color curr = color;
586 if (required > cargo.getQuantity(CargoItemType.RESOURCES, commodityId)) {
587 curr = bad;
588 }
589 cost.addCost(commodityId, "" + required + " (" + available + ")", curr);
590 }
591 cost.update();
592
593
594 MutableStat valueRecovery = getValueRecoveryStat(true);
595 float overallMult = computeOverallMultForDebrisField();
596 valueRecovery.modifyMult("debris_mult", overallMult, "Debris field density");
597 //rareRecovery.unmodify();
598 int valuePercent = (int)Math.round(valueRecovery.getModifiedValue() * 100f);
599 if (valuePercent < 0) valuePercent = 0;
600 String valueString = "" + valuePercent + "%";
601 Color valueColor = highlight;
602
603 if (valuePercent < 100) {
604 valueColor = bad;
605 }
606
607 TooltipMakerAPI info = text.beginTooltip();
608 info.setParaSmallInsignia();
609 info.addPara("Scavenging effectiveness: %s", 0f, valueColor, valueString);
610 if (!valueRecovery.isUnmodified()) {
611 info.addStatModGrid(300, 50, opad, small, valueRecovery, true, getModPrinter());
612 }
613 text.addTooltip();
614
615// text.addParagraph("The density of the debris field affects both the amount resources and the number of rare items found.");
616
617// text.addParagraph("It's possible to scavenge using fewer crew and less machinery than required, but using fewer crew will reduce " +
618// "the amount of salvage recovered, while having less machinery will increase the danger to crew.");
619
621
622 }
623
625 float overallMult = 1f;
626 if (debris != null) {
627// Map<String, Integer> reqs = computeRequiredToSalvage(entity);
628// float crewMax = 1f;
629// if (reqs.get(Commodities.CREW) != null) {
630// crewMax = reqs.get(Commodities.CREW);
631// }
632// float crew = playerFleet.getCargo().getCrew();
633// float f = crew / crewMax;
634// if (f < 0) f = 0;
635// if (f > 1) f = 1;
636//
637// //if (Global.getSettings().isDevMode()) f = 1f;
638
639 float f = 1f;
640 DebrisFieldParams params = debris.getParams();
641 if (params.baseDensity > 0) {
642 overallMult = params.density / params.baseDensity * f * FIELD_SALVAGE_FRACTION_PER_ATTEMPT;
643 } else {
644 overallMult = 0f;
645 }
646 if (overallMult < FIELD_MIN_SALVAGE_MULT) overallMult = FIELD_MIN_SALVAGE_MULT;
647 }
648 return overallMult;
649 }
650
651
652 public void performSalvage() {
653 long seed = memory.getLong(MemFlags.SALVAGE_SEED);
654 Random random = Misc.getRandom(seed, 100);
655
656 Misc.stopPlayerFleet();
657
658// if (Global.getSettings().isDevMode()) {
659// random = Misc.random;
660// }
661
662// float salvageRating = spec.getSalvageRating();
663// float valueMultFleet = playerFleet.getStats().getDynamic().getValue(Stats.SALVAGE_VALUE_MULT_FLEET_INCLUDES_RARE);
664// float valueModShips = getPlayerShipsSalvageMod(salvageRating);
665
666 MutableStat valueRecovery = getValueRecoveryStat(true);
667 float valueMultFleet = valueRecovery.getModifiedValue();
668 float rareItemSkillMult = playerFleet.getStats().getDynamic().getValue(Stats.SALVAGE_VALUE_MULT_FLEET_INCLUDES_RARE);
669
670 List<DropData> dropValue = new ArrayList<DropData>(spec.getDropValue());
671 List<DropData> dropRandom = new ArrayList<DropData>(spec.getDropRandom());
672 dropValue.addAll(entity.getDropValue());
673 dropRandom.addAll(entity.getDropRandom());
674
675// DropData d = new DropData();
676// d.group = "misc_test";
677// d.chances = 1500;
678// dropRandom.add(d);
679
680
681 float overallMult = computeOverallMultForDebrisField();
682 if (debris != null) {
683 // to avoid same special triggering over and over while scavenging through
684 // the same debris field repeatedly
685 BaseCommandPlugin.getEntityMemory(memoryMap).unset(MemFlags.SALVAGE_SPECIAL_DATA);
686 }
687
688 float fuelMult = playerFleet.getStats().getDynamic().getValue(Stats.FUEL_SALVAGE_VALUE_MULT_FLEET);
689 CargoAPI salvage = generateSalvage(random, valueMultFleet, rareItemSkillMult, overallMult, fuelMult, dropValue, dropRandom);
690
691 //ExtraSalvage extra = BaseSalvageSpecial.getExtraSalvage(memoryMap);
692 CargoAPI extra = BaseSalvageSpecial.getCombinedExtraSalvage(memoryMap);
693 salvage.addAll(extra);
694 BaseSalvageSpecial.clearExtraSalvage(memoryMap);
695 if (!extra.isEmpty()) {
696 ListenerUtil.reportExtraSalvageShown(entity);
697 }
698
699 //salvage.addCommodity(Commodities.ALPHA_CORE, 1);
700
701 if (debris != null) {
702 debris.getParams().density -= overallMult;
703 if (debris.getParams().density < 0) debris.getParams().density = 0;
704
705 debris.getEntity().getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, random.nextLong());
706 //System.out.println("Post-salvage density: " + debris.getParams().density);
707 debris.setScavenged(true);
708 }
709
710 //if (loot)
711 if (!salvage.isEmpty()) {
712 dialog.getVisualPanel().showLoot("Salvaged", salvage, false, true, true, new CoreInteractionListener() {
713 public void coreUIDismissed() {
714 long xp = 0;
715 if (entity.hasSalvageXP()) {
716 xp = (long) (float) entity.getSalvageXP();
717 } else if (spec != null && spec.getXpSalvage() > 0) {
718 xp = (long) spec.getXpSalvage();
719 }
720 if (!memory.contains("$doNotDismissDialogAfterSalvage")) {
721 dialog.dismiss();
722 dialog.hideTextPanel();
723 dialog.hideVisualPanel();
724
725 if (xp > 0) {
726 Global.getSector().getPlayerPerson().getStats().addXP(xp);
727 }
728 } else {
729 if (xp > 0) {
730 Global.getSector().getPlayerPerson().getStats().addXP(xp, dialog.getTextPanel());
731 }
732 }
733// if (entity.hasSalvageXP()) {
734// Global.getSector().getPlayerPerson().getStats().addXP((long) (float) entity.getSalvageXP());
735// } else if (spec != null && spec.getXpSalvage() > 0) {
736// Global.getSector().getPlayerPerson().getStats().addXP((long) spec.getXpSalvage());
737// }
738 //Global.getSector().setPaused(false);
739 }
740 });
741 options.clearOptions();
742 dialog.setPromptText("");
743 } else {
744 text.addParagraph("Operations conclude with nothing of value found.");
745 options.clearOptions();
746 String leave = "Leave";
747 if (memory.contains("$salvageLeaveText")) {
748 leave = memory.getString("$salvageLeaveText");
749 }
750 options.addOption(leave, "defaultLeave");
751 options.setShortcut("defaultLeave", Keyboard.KEY_ESCAPE, false, false, false, true);
752 }
753
754
755 boolean isDebrisField = Entities.DEBRIS_FIELD_SHARED.equals(entity.getCustomEntityType());
756 if (!isDebrisField) {
757 if (!spec.hasTag(Tags.SALVAGE_ENTITY_NO_DEBRIS)) {
759 } else {
760 if (!spec.hasTag(Tags.SALVAGE_ENTITY_NO_REMOVE)) {
761 Misc.fadeAndExpire(entity, 1f);
762 }
763 }
764 }
765
766 if (playerFleet != null) {
767 playerFleet.getStats().addTemporaryModFlat(0.25f, "salvage_ops",
768 "Recent salvage operation", SALVAGE_DETECTION_MOD_FLAT,
769 playerFleet.getStats().getDetectedRangeMod());
770 Global.getSector().addPing(playerFleet, "noticed_player");
771 }
772 }
773
774
775 public void convertToDebrisField(float valueMult) {
776 convertToDebrisField(null, valueMult);
777 }
778
779 public void convertToDebrisField(Random random, float valueMult) {
780 if (random == null) random = new Random();
781
782 Misc.fadeAndExpire(entity, 1f);
783
784 float salvageRating = spec.getSalvageRating();
785 //entity.addTag(Tags.NON_CLICKABLE);
786
787 float debrisFieldRadius = 200f + salvageRating * 400f;
788
789 float density = 0.5f + salvageRating * 0.5f;
790 density = 1f;
792 density = 0.5f + salvageRating * 0.5f;
793 }
794
795 float duration = 10f + salvageRating * 20f;
796
797 DebrisFieldParams params = new DebrisFieldParams(debrisFieldRadius, density, duration, duration * 0.5f);
798 params.source = DebrisFieldSource.PLAYER_SALVAGE;
799
800// params.minSize = 12;
801// params.maxSize = 16;
802// params.defenderProb = 1;
803// params.minStr = 20;
804// params.maxStr = 30;
805// params.maxDefenderSize = 1;
806
807 float xp = spec.getXpSalvage() * 0.25f;
808 if (entity.hasSalvageXP()) {
809 xp = entity.getSalvageXP() * 0.25f;
810 }
811 if (xp >= 10) {
812 params.baseSalvageXP = (long) xp;
813 }
814
815 SectorEntityToken debris = Misc.addDebrisField(entity.getContainingLocation(), params, null);
816
817 //ExtraSalvage extra = BaseSalvageSpecial.getExtraSalvage(memoryMap);
818 CargoAPI extra = BaseSalvageSpecial.getCombinedExtraSalvage(memoryMap);
819 if (extra != null && !extra.isEmpty()) {
820 // don't prune extra cargo - it could have come from not recovering ships,
821 // and so could've been gotten by recovering and then stripping/scuttling them
822 // so shouldn't punish shortcutting that process
823 // (this can happen when "pound into scrap" vs ship derelict)
824// CargoAPI extraCopy = Global.getFactory().createCargo(true);
825// for (CargoStackAPI stack : extra.cargo.getStacksCopy()) {
826// float qty = stack.getSize();
827// qty *= valueMult;
828// if (qty < 1) {
829// if (random.nextFloat() >= qty) continue;
830// qty = 1;
831// } else {
832// qty = (int) qty;
833// }
834// extraCopy.addItems(stack.getType(), stack.getData(), qty);
835// }
836// BaseSalvageSpecial.setExtraSalvage(extraCopy, debris.getMemoryWithoutUpdate(), -1f);
837 //BaseSalvageSpecial.addExtraSalvage(extra.cargo, debris.getMemoryWithoutUpdate(), -1f);
838 BaseSalvageSpecial.addExtraSalvage(extra, debris.getMemoryWithoutUpdate(), -1f);
839 }
840
841// int count = 0;
842// for (CampaignTerrainAPI curr : entity.getContainingLocation().getTerrainCopy()) {
843// if (curr.getPlugin() instanceof DebrisFieldTerrainPlugin) {
844// count++;
845// }
846// }
847 //System.out.println("DEBRIS: " + count);
848
849 debris.setSensorProfile(null);
850 debris.setDiscoverable(null);
851 //debris.setDiscoveryXP(123f);
852
853 debris.setFaction(entity.getFaction().getId());
854
855 debris.getDropValue().clear();
856 debris.getDropRandom().clear();
857
858 for (DropData data : spec.getDropValue()) {
859 DropData copy = data.clone();
860 copy.valueMult = valueMult;
861 debris.addDropValue(data.clone());
862 }
863 for (DropData data : spec.getDropRandom()) {
864 DropData copy = data.clone();
865 copy.valueMult = valueMult;
866 debris.addDropRandom(copy);
867 }
868
869 for (DropData data : entity.getDropValue()) {
870 DropData copy = data.clone();
871 copy.valueMult = valueMult;
872 debris.addDropValue(data.clone());
873 }
874 for (DropData data : entity.getDropRandom()) {
875 DropData copy = data.clone();
876 copy.valueMult = valueMult;
877 debris.addDropRandom(copy);
878 }
879 //debris.addDropRandom("weapons_test", 10);
880
881 if (entity.getOrbit() != null) {
882 debris.setOrbit(entity.getOrbit().makeCopy());
883 } else {
884 debris.getLocation().set(entity.getLocation());
885 }
886
887 long seed = memory.getLong(MemFlags.SALVAGE_SEED);
888 if (seed != 0) {
889 debris.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, Misc.getRandom(seed, 150).nextLong());
890 }
891 }
892
893
894
895
896 public static float getPlayerShipsSalvageModUncapped() {
897 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
898 //float valueModShips = Misc.getFleetwideTotalMod(playerFleet, Stats.SALVAGE_VALUE_MULT_MOD, 0f);
899 float valueModShips = RepairGantry.getAdjustedGantryModifier(playerFleet, null, 0);
900 return valueModShips;
901 }
902// public static float getPlayerShipsSalvageMod(float salvageRating) {
903// CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
904// float valueModShips = Misc.getFleetwideTotalMod(playerFleet, Stats.SALVAGE_VALUE_MULT_MOD, 0f);
905// if (valueModShips > salvageRating) {
906// valueModShips = salvageRating;
907// }
908// return valueModShips;
909// }
910
911 public static float getDebrisReqMult(DebrisFieldTerrainPlugin field) {
912// public static int FIELD_RADIUS_FOR_BASE_REQ = 200;
913// public static int FIELD_RADIUS_FOR_MAX_REQ = 1000;
914// public static int FIELD_RADIUS_MAX_REQ_MULT = 10;
915 float r = field.getParams().bandWidthInEngine;
917 if (f < 0) f = 0;
918 if (f > 1) f = 1;
919
920 float mult = 1f + (FIELD_RADIUS_MAX_REQ_MULT - 1f) * f;
921 return mult;
922 }
923
924// public static CargoAPI generateSalvage(Random random, float valueMult, List<DropData> dropValue, List<DropData> dropRandom) {
925// return generateSalvage(random, valueMult, 1f, dropValue, dropRandom);
926// }
927 public static CargoAPI generateSalvage(Random random, float valueMult, float overallMult, float fuelMult, List<DropData> dropValue, List<DropData> dropRandom) {
928 return generateSalvage(random, valueMult, 1f, overallMult, fuelMult, dropValue, dropRandom);
929 }
930 public static CargoAPI generateSalvage(Random random, float valueMult, float randomMult,
931 float overallMult, float fuelMult, List<DropData> dropValue, List<DropData> dropRandom) {
932 if (random == null) random = new Random();
933 CargoAPI result = Global.getFactory().createCargo(true);
934
935
936 if (Misc.isEasy()) {
937 overallMult *= Global.getSettings().getFloat("easySalvageMult");
938 }
939// CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
940
941 //overallMult = 1f;
942
943// float valueMultFleet = playerFleet.getStats().getDynamic().getValue(Stats.SALVAGE_VALUE_MULT_FLEET);
944// float valueModShips = getPlayerShipsSalvageMod(salvageRating);
945
946 // check dropRandom first so that changing the drop value by dropping off crew/machinery
947 // does not change the RNG for dropRandom
948 if (dropRandom != null) {
949 for (DropData data : dropRandom) {
950 //if (random.nextFloat() < data.valueMult) continue;
951
952 int chances = data.chances;
953 if (data.maxChances > chances) {
954 chances = chances + random.nextInt(data.maxChances - chances + 1);
955 }
956// if (data.group.endsWith("misc_test")) {
957// System.out.println("fewfwefwe");
958// }
959 //WeightedRandomPicker<DropGroupRow> picker = DropGroupRow.getPicker(data.group);
960
961 float modifiedChances = chances;
962 modifiedChances *= overallMult;
963 if (data.value <= 0) {
964 modifiedChances *= randomMult;
965 }
966 modifiedChances *= data.valueMult;
967 float rem = modifiedChances - (int) modifiedChances;
968
969 chances = (int) modifiedChances + (random.nextFloat() < rem ? 1 : 0);
970
971 WeightedRandomPicker<DropGroupRow> picker = data.getCustom();
972 if (picker == null && data.group == null) continue; // meant for custom, but empty
973 if (picker == null) {
974 picker = DropGroupRow.getPicker(data.group);
975 }
976
977 Random innerRandom = Misc.getRandom(random.nextLong(), 5);
978 //innerRandom = random;
979 picker.setRandom(innerRandom);
980 for (int i = 0; i < chances; i++) {
981// if (random.nextFloat() > overallMult) continue;
982// if (random.nextFloat() > data.valueMult) continue;
983
984 DropGroupRow row = picker.pick();
985 if (row.isMultiValued()) {
986 row = row.resolveToSpecificItem(innerRandom);
987 }
988
989 if (row.isNothing()) continue;
990
991 float baseUnitValue = row.getBaseUnitValue();
992
993 float qty = 1f;
994 if (data.value > 0) {
995 float randMult = StarSystemGenerator.getNormalRandom(innerRandom, 0.5f, 1.5f);
996 //qty = (data.value * randMult * valueMult * overallMult) / baseUnitValue;
997 // valueMult and overallMult are considered in figuring out number of chances to roll
998 qty = (data.value * valueMult * randMult) / baseUnitValue;
999 qty = (int) qty;
1000 if (valueMult <= 0) continue;
1001 if (qty < 1) qty = 1;
1002 }
1003
1004
1005 if (row.isWeapon()) {
1006 result.addWeapons(row.getWeaponId(), (int) qty);
1007// } else if (row.isHullMod()) {
1008// result.addItems(CargoItemType.MOD_SPEC, row.getHullModId(), (int) qty);
1009 } else if (row.isFighterWing()) {
1010 result.addItems(CargoItemType.FIGHTER_CHIP, row.getFighterWingId(), (int) qty);
1011 } else if (row.isSpecialItem()) {
1012 if (Items.MODSPEC.equals(row.getSpecialItemId()) &&
1013 result.getQuantity(CargoItemType.SPECIAL,
1014 new SpecialItemData(row.getSpecialItemId(), row.getSpecialItemData())) > 0) {
1015 continue;
1016 }
1017 result.addItems(CargoItemType.SPECIAL,
1018 new SpecialItemData(row.getSpecialItemId(), row.getSpecialItemData()), (int) qty);
1019 } else {
1020 result.addCommodity(row.getCommodity(), qty);
1021 }
1022 }
1023 }
1024 }
1025
1026
1027 if (dropValue != null) {
1028
1029 for (DropData data : dropValue) {
1030 //if (random.nextFloat() < data.valueMult) continue;
1031
1032 float maxValue = data.value;
1033
1034 // if value is 1, it's a "guaranteed pick one out of this usually-dropRandom group"
1035 // so still allow it even if valueMult is 0 due to a lack of heavy machinery
1036 // since dropRandom works w/ no machinery, too
1037 if (data.value > 1) {
1038 maxValue *= valueMult;
1039 }
1040
1041 maxValue *= overallMult;
1042 maxValue *= data.valueMult;
1043
1044 float randMult = StarSystemGenerator.getNormalRandom(random, 0.5f, 1.5f);
1045 maxValue *= randMult;
1046
1047
1048 WeightedRandomPicker<DropGroupRow> picker = data.getCustom();
1049 if (picker == null && data.group == null) continue; // meant for custom, but empty
1050 if (picker == null) {
1051 picker = DropGroupRow.getPicker(data.group);
1052 }
1053 picker.setRandom(random);
1054 float value = 0f;
1055 int nothingInARow = 0;
1056 while (value < maxValue && nothingInARow < 10) {
1057 DropGroupRow row = picker.pick();
1058 if (row.isMultiValued()) {
1059 row = row.resolveToSpecificItem(random);
1060 }
1061 if (row.isNothing()) {
1062 nothingInARow++;
1063 continue;
1064 } else {
1065 nothingInARow = 0;
1066 }
1067 //System.out.println(nothingInARow);
1068
1069 float baseUnitValue = row.getBaseUnitValue();
1070
1071 float qty = 1f;
1072 float currValue = baseUnitValue * qty;
1073 value += currValue;
1074
1075 if (row.isWeapon()) {
1076 if (value <= maxValue) {
1077 result.addWeapons(row.getWeaponId(), (int) qty);
1078 }
1079// } else if (row.isHullMod()) {
1080// if (value <= maxValue) {
1081// result.addHullmods(row.getHullModId(), (int) qty);
1082// }
1083 } else if (row.isFighterWing()) {
1084 if (value <= maxValue) {
1085 result.addItems(CargoItemType.FIGHTER_CHIP, row.getFighterWingId(), (int) qty);
1086 }
1087 } else if (row.isSpecialItem()) {
1088 if (Items.MODSPEC.equals(row.getSpecialItemId()) &&
1089 result.getQuantity(CargoItemType.SPECIAL,
1090 new SpecialItemData(row.getSpecialItemId(), row.getSpecialItemData())) > 0) {
1091 continue;
1092 }
1093 result.addItems(CargoItemType.SPECIAL,
1094 new SpecialItemData(row.getSpecialItemId(), row.getSpecialItemData()), (int) qty);
1095 } else {
1096 if (value <= maxValue) {
1097 result.addCommodity(row.getCommodity(), qty);
1098 }
1099 }
1100 }
1101 }
1102 }
1103
1104
1105 float fuel = result.getFuel();
1106 if (fuelMult > 1f) {
1107 result.addFuel((int) Math.round(fuel * (fuelMult - 1f)));
1108 }
1109
1110 result.sort();
1111
1112 return result;
1113 }
1114
1115
1116 public boolean canBeMadeRecoverable() {
1117 if (entity.getCustomPlugin() instanceof DerelictShipEntityPlugin) {
1118
1119 //if (Misc.getSalvageSpecial(entity) != null) return false;
1120
1121 if (Misc.getSalvageSpecial(entity) instanceof ShipRecoverySpecialData) {
1122 return false;
1123 }
1124 if (entity.hasTag(Tags.UNRECOVERABLE)) {
1125 return false;
1126 }
1127
1128// int room = Global.getSettings().getMaxShipsInFleet() -
1129// Global.getSector().getPlayerFleet().getFleetData().getMembersListCopy().size();
1130// if (room < 1) return false;
1131
1132 DerelictShipEntityPlugin plugin = (DerelictShipEntityPlugin) entity.getCustomPlugin();
1133 ShipVariantAPI variant = plugin.getData().ship.getVariant();
1134 if (variant != null && !Misc.isUnboardable(variant.getHullSpec())) {
1135 return true;
1136 }
1137 }
1138 return false;
1139 }
1140
1141
1142 public void showRecoverable() {
1143
1144 Object prev = Misc.getSalvageSpecial(entity);
1145 if (prev != null) {
1146 Misc.setPrevSalvageSpecial(entity, prev);
1147 }
1148
1149 ShipRecoverySpecialData data = new ShipRecoverySpecialData(null);
1150 DerelictShipEntityPlugin plugin = (DerelictShipEntityPlugin) entity.getCustomPlugin();
1151 data.addShip(plugin.getData().ship.clone());
1152 data.storyPointRecovery = true;
1153 Misc.setSalvageSpecial(entity, data);
1154
1155 long seed = Misc.getSalvageSeed(entity);
1156 entity.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, seed);
1157 }
1158
1159}
1160
1161
1162
1163
1164
1165
1166
static SettingsAPI getSettings()
Definition Global.java:51
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:43
static FactoryAPI getFactory()
Definition Global.java:35
static SectorAPI getSector()
Definition Global.java:59
static float getAdjustedGantryModifier(CampaignFleetAPI fleet, String skipId, float add)
static MemoryAPI getEntityMemory(Map< String, MemoryAPI > memoryMap)
static CargoAPI generateSalvage(Random random, float valueMult, float randomMult, float overallMult, float fuelMult, List< DropData > dropValue, List< DropData > dropRandom)
static CargoAPI generateSalvage(Random random, float valueMult, float overallMult, float fuelMult, List< DropData > dropValue, List< DropData > dropRandom)
static float getDebrisReqMult(DebrisFieldTerrainPlugin field)
boolean execute(String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
MutableStat getValueRecoveryStat(boolean withSkillMultForRares)
static Map< String, Integer > computeRequiredToSalvage(SectorEntityToken entity)
CargoAPI createCargo(boolean unlimitedStacks)
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)