1package com.fs.starfarer.api.impl.campaign.rulecmd.salvage;
4import java.util.ArrayList;
5import java.util.LinkedHashMap;
8import java.util.Random;
10import org.lwjgl.input.Keyboard;
11import org.lwjgl.util.vector.Vector2f;
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;
92 protected TextPanelAPI
text;
94 protected SalvageEntityGenDataSpec
spec;
97 protected InteractionDialogAPI
dialog;
98 private DebrisFieldTerrainPlugin debris;
99 private Map<String, MemoryAPI> memoryMap;
102 public boolean execute(String ruleId, InteractionDialogAPI
dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) {
105 this.memoryMap = memoryMap;
107 String command = params.get(0).getString(memoryMap);
108 if (command ==
null)
return false;
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);
118 spec = SalvageEntityGeneratorOld.getSalvageSpec(specId);
129 Object test =
entity.getMemoryWithoutUpdate().get(MemFlags.SALVAGE_DEBRIS_FIELD);
130 if (test instanceof DebrisFieldTerrainPlugin) {
131 debris = (DebrisFieldTerrainPlugin) test;
134 if (command.equals(
"showCost")) {
135 if (debris ==
null) {
141 }
else if (command.equals(
"performSalvage")) {
143 }
else if (command.equals(
"descDebris")) {
144 showDebrisDescription();
145 }
else if (command.equals(
"checkAccidents")) {
147 }
else if (command.equals(
"demolish")) {
149 }
else if (command.equals(
"canBeMadeRecoverable")) {
151 }
else if (command.equals(
"showRecoverable")) {
158 private void demolish() {
159 boolean isDebrisField = Entities.DEBRIS_FIELD_SHARED.equals(
entity.getCustomEntityType());
160 if (!isDebrisField) {
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;
183 private void checkAccidents() {
184 if (debris ==
null) {
185 memory.set(
"$option",
"salPerform");
186 FireBest.fire(
null,
dialog, memoryMap,
"DialogOptionSelected");
190 float accidentProbability = getAccidentProbability();
193 long seed =
memory.getLong(MemFlags.SALVAGE_SEED);
194 Random random = Misc.getRandom(seed, 175);
196 if (random.nextFloat() > accidentProbability) {
197 memory.set(
"$option",
"salPerform");
198 FireBest.fire(
null,
dialog, memoryMap,
"DialogOptionSelected");
203 Color bad = Misc.getNegativeHighlightColor();
204 Color highlight = Misc.getHighlightColor();
207 float reqCrew = (int) requiredRes.get(Commodities.CREW);
208 float reqMachinery = (int) requiredRes.get(Commodities.HEAVY_MACHINERY);
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;
216 float fMachinery = machinery / reqMachinery;
217 if (fMachinery < 0) fMachinery = 0;
218 if (fMachinery > 1) fMachinery = 1;
224 float lossValue = reqCrew * fCrew * 5f;
225 lossValue += (1f - debris.getParams().density / debris.getParams().baseDensity) * 500f;
226 lossValue *= 0.5f + random.nextFloat();
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);
233 CargoAPI losses = Global.getFactory().createCargo(
true);
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);
243 int crewLost = losses.getCrew();
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);
251 int machineryLost = (int) losses.getCommodityQuantity(Commodities.HEAVY_MACHINERY);
252 if (crewLost > crew) crewLost = (int) crew;
253 if (machineryLost > machinery) machineryLost = (int) machinery;
255 if (crewLost <= 0 && machineryLost <= 0) {
256 memory.set(
"$option",
"salPerform");
257 FireBest.fire(
null,
dialog, memoryMap,
"DialogOptionSelected");
261 for (CargoStackAPI stack : losses.getStacksCopy()) {
262 cargo.removeCommodity(stack.getCommodityId(), stack.getSize());
267 text.setFontInsignia();
268 text.addParagraph(
"An accident during the operation has resulted in the loss of ");
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);
277 text.appendToLastParagraph(
"" + crewLost +
" crew and " + machineryLost +
" heavy machinery.");
278 text.highlightInLastPara(highlight,
"" + crewLost,
"" + machineryLost);
282 Global.getSoundPlayer().playSound(
"hit_solid", 1, 1, Global.getSoundPlayer().getListenerPos(),
new Vector2f());
285 options.addOption(
"Continue",
"salPerform");
290 private void showDebrisDescription() {
291 if (debris ==
null)
return;
293 float daysLeft = debris.getDaysLeft();
294 if (daysLeft >= 1000) {
295 text.addParagraph(
"The field appears stable and will not drift apart any time soon.");
297 String atLeastTime = Misc.getAtLeastStringForDays((
int) daysLeft);
298 text.addParagraph(
"The field is unstable, but should not drift apart for " + atLeastTime +
".");
320 for (DropData data : debris.getEntity().getDropValue()) {
321 lootValue += data.value;
323 for (DropData data : debris.getEntity().getDropRandom()) {
324 if (data.value > 0) {
325 lootValue += data.value;
330 float d = debris.getParams().density;
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());
349 text.appendToLastParagraph(
" Long-range scans indicate it's likely something of value could be found inside.");
350 text.highlightLastInLastPara(
"likely", Misc.getPositiveHighlightColor());
353 float accidentProbability = getAccidentProbability();
354 if (accidentProbability <= 0.2f) {
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");
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");
368 Map<String, Integer> result =
new LinkedHashMap<String, Integer>();
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);
374 SalvageEntityGenDataSpec
spec = SalvageEntityGeneratorOld.getSalvageSpec(specId);
375 float mult = 1f +
spec.getSalvageRating() * 9f;
377 Object test =
entity.getMemoryWithoutUpdate().get(MemFlags.SALVAGE_DEBRIS_FIELD);
378 if (test instanceof DebrisFieldTerrainPlugin) {
379 DebrisFieldTerrainPlugin debris = (DebrisFieldTerrainPlugin) test;
383 int crew = Math.round((
int) (
BASE_CREW * mult) / 10f) * 10;
384 int machinery = Math.round((
int) (
BASE_MACHINERY * mult) / 10f) * 10;
386 result.put(Commodities.CREW, crew);
387 result.put(Commodities.HEAVY_MACHINERY, machinery);
394 MutableStat valueRecovery =
new MutableStat(1f);
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");
406 for (String commodityId : requiredRes.keySet()) {
407 float required = requiredRes.get(commodityId);
408 float available = (int)
cargo.getCommodityQuantity(commodityId);
409 if (required <= 0)
continue;
412 float val = Math.min(available / required, 1f) * per;
413 int percent = (int) Math.round(val * 100f);
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");
420 valueRecovery.modifyMultAlways(
"" + i++, val, Misc.ucFirst(
spec.getLowerCaseName()) +
" available");
427 boolean modified =
false;
428 if (withSkillMultForRares) {
429 for (StatMod mod :
playerFleet.getStats().getDynamic().getStat(Stats.SALVAGE_VALUE_MULT_FLEET_INCLUDES_RARE).getFlatMods().values()) {
431 valueRecovery.modifyPercentAlways(
"" + i++, (
int) Math.round(mod.value * 100f), mod.desc);
436 for (StatMod mod :
playerFleet.getStats().getDynamic().getStat(Stats.SALVAGE_VALUE_MULT_FLEET_NOT_RARE).getFlatMods().values()) {
438 valueRecovery.modifyPercentAlways(
"" + i++, (
int) Math.round(mod.value * 100f), mod.desc);
442 valueRecovery.modifyPercentAlways(
"" + i++, (
int) Math.round(0f),
"Salvaging skill");
446 valueRecovery.modifyPercentAlways(
"" + i++, (
int) Math.round(fleetSalvageShips * 100f),
"Fleetwide salvaging capability");
448 return valueRecovery;
462 Color bad = Misc.getNegativeHighlightColor();
463 Color highlight = Misc.getHighlightColor();
471 text.addParagraph(
"You receive a preliminary assessment of a potential salvage operation from the exploration crews.");
473 ResourceCostPanelAPI cost =
text.addCostPanel(
"Crew & machinery: required (available)",
COST_HEIGHT,
475 cost.setNumberOnlyMode(
true);
476 cost.setWithBorder(
false);
477 cost.setAlignment(Alignment.LMID);
479 for (String commodityId : requiredRes.keySet()) {
480 int required = requiredRes.get(commodityId);
481 int available = (int)
cargo.getCommodityQuantity(commodityId);
483 if (required >
cargo.getQuantity(CargoItemType.RESOURCES, commodityId)) {
486 cost.addCost(commodityId,
"" + required +
" (" + available +
")", curr);
494 int valuePercent = (int)Math.round(valueRecovery.getModifiedValue() * 100f);
495 if (valuePercent < 0) valuePercent = 0;
496 String valueString =
"" + valuePercent +
"%";
497 Color valueColor = highlight;
499 if (valuePercent < 100) {
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());
515 return new StatModValueGetter() {
516 boolean percent =
false;
517 public String getPercentValue(StatMod mod) {
521 if (mod.desc ==
null || mod.desc.isEmpty())
return "";
523 String prefix = mod.getValue() >= 0 ?
"+" :
"";
524 return prefix + (int)(mod.getValue()) +
"%";
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();
537 float fuelMult =
playerFleet.getStats().getDynamic().getValue(Stats.FUEL_SALVAGE_VALUE_MULT_FLEET);
538 String fuelStr =
"" + (int)Math.round((fuelMult - 1f) * 100f) +
"%";
540 float rareMult =
playerFleet.getStats().getDynamic().getValue(Stats.SALVAGE_VALUE_MULT_FLEET_INCLUDES_RARE);
541 String rareStr =
"" + (int)Math.round((rareMult - 1f) * 100f) +
"%";
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);
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.");
558 text.addPara(
"The recovery effectiveness does not affect the chance of finding rare and valuable items.");
565 Color bad = Misc.getNegativeHighlightColor();
566 Color highlight = Misc.getHighlightColor();
576 ResourceCostPanelAPI cost =
text.addCostPanel(
"Crew & machinery: required (available)",
COST_HEIGHT,
578 cost.setNumberOnlyMode(
true);
579 cost.setWithBorder(
false);
580 cost.setAlignment(Alignment.LMID);
582 for (String commodityId : requiredRes.keySet()) {
583 int required = requiredRes.get(commodityId);
584 int available = (int)
cargo.getCommodityQuantity(commodityId);
586 if (required >
cargo.getQuantity(CargoItemType.RESOURCES, commodityId)) {
589 cost.addCost(commodityId,
"" + required +
" (" + available +
")", curr);
596 valueRecovery.modifyMult(
"debris_mult", overallMult,
"Debris field density");
598 int valuePercent = (int)Math.round(valueRecovery.getModifiedValue() * 100f);
599 if (valuePercent < 0) valuePercent = 0;
600 String valueString =
"" + valuePercent +
"%";
601 Color valueColor = highlight;
603 if (valuePercent < 100) {
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());
625 float overallMult = 1f;
626 if (debris !=
null) {
640 DebrisFieldParams params = debris.getParams();
641 if (params.baseDensity > 0) {
653 long seed =
memory.getLong(MemFlags.SALVAGE_SEED);
654 Random random = Misc.getRandom(seed, 100);
656 Misc.stopPlayerFleet();
667 float valueMultFleet = valueRecovery.getModifiedValue();
668 float rareItemSkillMult =
playerFleet.getStats().getDynamic().getValue(Stats.SALVAGE_VALUE_MULT_FLEET_INCLUDES_RARE);
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());
682 if (debris !=
null) {
688 float fuelMult =
playerFleet.getStats().getDynamic().getValue(Stats.FUEL_SALVAGE_VALUE_MULT_FLEET);
689 CargoAPI salvage =
generateSalvage(random, valueMultFleet, rareItemSkillMult, overallMult, fuelMult, dropValue, dropRandom);
692 CargoAPI extra = BaseSalvageSpecial.getCombinedExtraSalvage(memoryMap);
693 salvage.addAll(extra);
694 BaseSalvageSpecial.clearExtraSalvage(memoryMap);
695 if (!extra.isEmpty()) {
696 ListenerUtil.reportExtraSalvageShown(
entity);
701 if (debris !=
null) {
702 debris.getParams().density -= overallMult;
703 if (debris.getParams().density < 0) debris.getParams().density = 0;
705 debris.getEntity().getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, random.nextLong());
707 debris.setScavenged(
true);
711 if (!salvage.isEmpty()) {
712 dialog.getVisualPanel().showLoot(
"Salvaged", salvage,
false,
true,
true,
new CoreInteractionListener() {
713 public void coreUIDismissed() {
715 if (
entity.hasSalvageXP()) {
716 xp = (long) (
float)
entity.getSalvageXP();
717 }
else if (
spec !=
null &&
spec.getXpSalvage() > 0) {
718 xp = (long)
spec.getXpSalvage();
720 if (!
memory.contains(
"$doNotDismissDialogAfterSalvage")) {
744 text.addParagraph(
"Operations conclude with nothing of value found.");
746 String leave =
"Leave";
747 if (
memory.contains(
"$salvageLeaveText")) {
748 leave =
memory.getString(
"$salvageLeaveText");
750 options.addOption(leave,
"defaultLeave");
751 options.setShortcut(
"defaultLeave", Keyboard.KEY_ESCAPE,
false,
false,
false,
true);
755 boolean isDebrisField = Entities.DEBRIS_FIELD_SHARED.equals(
entity.getCustomEntityType());
756 if (!isDebrisField) {
757 if (!
spec.hasTag(Tags.SALVAGE_ENTITY_NO_DEBRIS)) {
760 if (!
spec.hasTag(Tags.SALVAGE_ENTITY_NO_REMOVE)) {
761 Misc.fadeAndExpire(
entity, 1f);
767 playerFleet.getStats().addTemporaryModFlat(0.25f,
"salvage_ops",
780 if (random ==
null) random =
new Random();
782 Misc.fadeAndExpire(
entity, 1f);
784 float salvageRating =
spec.getSalvageRating();
787 float debrisFieldRadius = 200f + salvageRating * 400f;
789 float density = 0.5f + salvageRating * 0.5f;
792 density = 0.5f + salvageRating * 0.5f;
795 float duration = 10f + salvageRating * 20f;
797 DebrisFieldParams params =
new DebrisFieldParams(debrisFieldRadius, density, duration, duration * 0.5f);
798 params.source = DebrisFieldSource.PLAYER_SALVAGE;
807 float xp =
spec.getXpSalvage() * 0.25f;
808 if (
entity.hasSalvageXP()) {
809 xp =
entity.getSalvageXP() * 0.25f;
812 params.baseSalvageXP = (long) xp;
815 SectorEntityToken debris = Misc.addDebrisField(
entity.getContainingLocation(), params,
null);
818 CargoAPI extra = BaseSalvageSpecial.getCombinedExtraSalvage(memoryMap);
819 if (extra !=
null && !extra.isEmpty()) {
838 BaseSalvageSpecial.addExtraSalvage(extra, debris.getMemoryWithoutUpdate(), -1f);
849 debris.setSensorProfile(
null);
850 debris.setDiscoverable(
null);
853 debris.setFaction(
entity.getFaction().getId());
855 debris.getDropValue().clear();
856 debris.getDropRandom().clear();
858 for (DropData data :
spec.getDropValue()) {
859 DropData copy = data.clone();
860 copy.valueMult = valueMult;
861 debris.addDropValue(data.clone());
863 for (DropData data :
spec.getDropRandom()) {
864 DropData copy = data.clone();
865 copy.valueMult = valueMult;
866 debris.addDropRandom(copy);
869 for (DropData data :
entity.getDropValue()) {
870 DropData copy = data.clone();
871 copy.valueMult = valueMult;
872 debris.addDropValue(data.clone());
874 for (DropData data :
entity.getDropRandom()) {
875 DropData copy = data.clone();
876 copy.valueMult = valueMult;
877 debris.addDropRandom(copy);
881 if (
entity.getOrbit() !=
null) {
882 debris.setOrbit(
entity.getOrbit().makeCopy());
884 debris.getLocation().set(
entity.getLocation());
887 long seed =
memory.getLong(MemFlags.SALVAGE_SEED);
889 debris.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, Misc.getRandom(seed, 150).nextLong());
900 return valueModShips;
915 float r = field.getParams().bandWidthInEngine;
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);
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();
948 if (dropRandom !=
null) {
949 for (DropData data : dropRandom) {
952 int chances = data.chances;
953 if (data.maxChances > chances) {
954 chances = chances + random.nextInt(data.maxChances - chances + 1);
961 float modifiedChances = chances;
962 modifiedChances *= overallMult;
963 if (data.value <= 0) {
964 modifiedChances *= randomMult;
966 modifiedChances *= data.valueMult;
967 float rem = modifiedChances - (int) modifiedChances;
969 chances = (int) modifiedChances + (random.nextFloat() < rem ? 1 : 0);
971 WeightedRandomPicker<DropGroupRow> picker = data.getCustom();
972 if (picker ==
null && data.group ==
null)
continue;
973 if (picker ==
null) {
974 picker = DropGroupRow.getPicker(data.group);
977 Random innerRandom = Misc.getRandom(random.nextLong(), 5);
979 picker.setRandom(innerRandom);
980 for (
int i = 0; i < chances; i++) {
984 DropGroupRow row = picker.pick();
985 if (row.isMultiValued()) {
986 row = row.resolveToSpecificItem(innerRandom);
989 if (row.isNothing())
continue;
991 float baseUnitValue = row.getBaseUnitValue();
994 if (data.value > 0) {
995 float randMult = StarSystemGenerator.getNormalRandom(innerRandom, 0.5f, 1.5f);
998 qty = (data.value * valueMult * randMult) / baseUnitValue;
1000 if (valueMult <= 0)
continue;
1001 if (qty < 1) qty = 1;
1005 if (row.isWeapon()) {
1006 result.addWeapons(row.getWeaponId(), (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) {
1017 result.addItems(CargoItemType.SPECIAL,
1018 new SpecialItemData(row.getSpecialItemId(), row.getSpecialItemData()), (
int) qty);
1020 result.addCommodity(row.getCommodity(), qty);
1027 if (dropValue !=
null) {
1029 for (DropData data : dropValue) {
1032 float maxValue = data.value;
1037 if (data.value > 1) {
1038 maxValue *= valueMult;
1041 maxValue *= overallMult;
1042 maxValue *= data.valueMult;
1044 float randMult = StarSystemGenerator.getNormalRandom(random, 0.5f, 1.5f);
1045 maxValue *= randMult;
1048 WeightedRandomPicker<DropGroupRow> picker = data.getCustom();
1049 if (picker ==
null && data.group ==
null)
continue;
1050 if (picker ==
null) {
1051 picker = DropGroupRow.getPicker(data.group);
1053 picker.setRandom(random);
1055 int nothingInARow = 0;
1056 while (value < maxValue && nothingInARow < 10) {
1057 DropGroupRow row = picker.pick();
1058 if (row.isMultiValued()) {
1059 row = row.resolveToSpecificItem(random);
1061 if (row.isNothing()) {
1069 float baseUnitValue = row.getBaseUnitValue();
1072 float currValue = baseUnitValue * qty;
1075 if (row.isWeapon()) {
1076 if (value <= maxValue) {
1077 result.addWeapons(row.getWeaponId(), (int) qty);
1083 }
else if (row.isFighterWing()) {
1084 if (value <= maxValue) {
1085 result.addItems(CargoItemType.FIGHTER_CHIP, row.getFighterWingId(), (int) qty);
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) {
1093 result.addItems(CargoItemType.SPECIAL,
1094 new SpecialItemData(row.getSpecialItemId(), row.getSpecialItemData()), (
int) qty);
1096 if (value <= maxValue) {
1097 result.addCommodity(row.getCommodity(), qty);
1105 float fuel = result.getFuel();
1106 if (fuelMult > 1f) {
1107 result.addFuel((
int) Math.round(fuel * (fuelMult - 1f)));
1121 if (Misc.getSalvageSpecial(
entity) instanceof ShipRecoverySpecialData) {
1124 if (
entity.hasTag(Tags.UNRECOVERABLE)) {
1133 ShipVariantAPI variant = plugin.
getData().ship.getVariant();
1134 if (variant !=
null && !Misc.isUnboardable(variant.getHullSpec())) {
1144 Object prev = Misc.getSalvageSpecial(
entity);
1146 Misc.setPrevSalvageSpecial(
entity, prev);
1149 ShipRecoverySpecialData data =
new ShipRecoverySpecialData(
null);
1151 data.addShip(plugin.
getData().ship.clone());
1152 data.storyPointRecovery =
true;
1153 Misc.setSalvageSpecial(
entity, data);
1155 long seed = Misc.getSalvageSeed(
entity);
1156 entity.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, seed);
static SettingsAPI getSettings()
static SoundPlayerAPI getSoundPlayer()
static FactoryAPI getFactory()
static SectorAPI getSector()
DerelictShipData getData()
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)
void convertToDebrisField(Random random, float valueMult)
void printSalvageModifiers()
float computeOverallMultForDebrisField()
static float FIELD_MIN_SALVAGE_MULT
void showCostDebrisField()
static int FIELD_RADIUS_MAX_REQ_MULT
static int BASE_MACHINERY
boolean canBeMadeRecoverable()
void convertToDebrisField(float valueMult)
static int FIELD_RADIUS_FOR_MAX_REQ
static float getPlayerShipsSalvageModUncapped()
StatModValueGetter getModPrinter()
static float getDebrisReqMult(DebrisFieldTerrainPlugin field)
boolean execute(String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
InteractionDialogAPI dialog
MutableStat getValueRecoveryStat(boolean withSkillMultForRares)
CampaignFleetAPI playerFleet
static float SALVAGE_DETECTION_MOD_FLAT
static float FIELD_CONTENT_MULTIPLIER_AFTER_DEMOLITION
static int FIELD_RADIUS_FOR_BASE_REQ
static float FIELD_CONTENT_MULTIPLIER_AFTER_SALVAGE
SalvageEntityGenDataSpec spec
static Map< String, Integer > computeRequiredToSalvage(SectorEntityToken entity)
static float FIELD_SALVAGE_FRACTION_PER_ATTEMPT
CargoAPI createCargo(boolean unlimitedStacks)
float getFloat(String key)
Vector2f getListenerPos()
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)