1package com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special;
3import java.util.ArrayList;
6import org.lwjgl.input.Keyboard;
8import com.fs.starfarer.api.Global;
9import com.fs.starfarer.api.campaign.CampaignFleetAPI;
10import com.fs.starfarer.api.campaign.CargoAPI;
11import com.fs.starfarer.api.campaign.CargoStackAPI;
12import com.fs.starfarer.api.campaign.FactionAPI;
13import com.fs.starfarer.api.campaign.FleetMemberPickerListener;
14import com.fs.starfarer.api.campaign.InteractionDialogAPI;
15import com.fs.starfarer.api.campaign.PlanetAPI;
16import com.fs.starfarer.api.campaign.SectorEntityToken;
17import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
18import com.fs.starfarer.api.characters.PersonAPI;
19import com.fs.starfarer.api.combat.ShipVariantAPI;
20import com.fs.starfarer.api.fleet.FleetMemberAPI;
21import com.fs.starfarer.api.fleet.FleetMemberType;
22import com.fs.starfarer.api.impl.campaign.DModManager;
23import com.fs.starfarer.api.impl.campaign.FleetEncounterContext;
24import com.fs.starfarer.api.impl.campaign.ids.Commodities;
25import com.fs.starfarer.api.impl.campaign.ids.Entities;
26import com.fs.starfarer.api.impl.campaign.ids.Factions;
27import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
28import com.fs.starfarer.api.impl.campaign.ids.Stats;
29import com.fs.starfarer.api.impl.campaign.ids.Tags;
30import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity;
31import com.fs.starfarer.api.impl.campaign.rulecmd.FireAll;
32import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
33import com.fs.starfarer.api.impl.campaign.rulecmd.ShowDefaultVisual;
34import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialData;
35import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialDialogPlugin;
36import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialPlugin;
37import com.fs.starfarer.api.loading.HullModSpecAPI;
38import com.fs.starfarer.api.util.Misc;
39import com.fs.starfarer.api.util.WeightedRandomPicker;
43 public static final String
RECOVER =
"recover";
44 public static final String
NOT_NOW =
"not_now";
49 public static enum ShipCondition {
57 public static class PerShipData
implements Cloneable {
58 public ShipCondition condition = ShipCondition.AVERAGE;
59 public String variantId =
null;
62 public String shipName =
null;
63 public String fleetMemberId =
null;
64 public boolean addDmods =
true;
65 public boolean pruneWeapons =
true;
66 public Boolean nameAlwaysKnown =
null;
67 public float sModProb = 0f;
68 public PerShipData(String variantId, ShipCondition condition) {
69 this(variantId, condition, 0f);
71 public PerShipData(String variantId, ShipCondition condition,
float sModProb) {
74 public PerShipData(
ShipVariantAPI variant, ShipCondition condition, String shipName, String factionIdForShipName,
float sModProb) {
75 this.variant = variant;
76 this.condition = condition;
78 if (shipName !=
null) {
79 this.shipName = shipName;
85 this.sModProb = sModProb;
88 public PerShipData(String variantId, ShipCondition condition, String factionIdForShipName,
float sModProb) {
89 this.variantId = variantId;
90 this.condition = condition;
95 this.sModProb = sModProb;
98 public ShipVariantAPI getVariant() {
99 ShipVariantAPI result = variant;
100 if (result ==
null && variantId !=
null) {
101 result = Global.getSettings().getVariant(variantId);
107 public PerShipData clone() {
108 try {
return (PerShipData) super.clone(); }
catch (CloneNotSupportedException e) {
return null; }
113 public static class ShipRecoverySpecialData
implements SalvageSpecialData {
114 public List<PerShipData> ships =
new ArrayList<PerShipData>();
115 public String desc =
null;
116 public Boolean storyPointRecovery =
null;
117 public Boolean notNowOptionExits =
null;
118 public Boolean noDescriptionText =
null;
120 public ShipRecoverySpecialData(String desc) {
124 public void addShip(PerShipData ship) {
127 public void addShip(String variantId, ShipCondition condition,
float sModProb) {
128 ships.add(
new PerShipData(variantId, condition, sModProb));
130 public void addShip(String variantId, ShipCondition condition, String factionIdForShipName,
float sModProb) {
131 ships.add(
new PerShipData(variantId, condition, factionIdForShipName, sModProb));
134 public SalvageSpecialPlugin createSpecialPlugin() {
139 protected ShipRecoverySpecialData
data;
143 ShipRecoverySpecialData
data =
null;
144 if (o instanceof ShipRecoverySpecialData) {
145 data = (ShipRecoverySpecialData) o;
148 if (
data ==
null && !create)
return null;
149 if (o !=
null &&
data ==
null && !replace)
return null;
152 data =
new ShipRecoverySpecialData(desc);
165 super.init(
dialog, specialData);
167 data = (ShipRecoverySpecialData) specialData;
174 if (
data.ships.isEmpty()) {
181 protected List<FleetMemberAPI>
members =
new ArrayList<FleetMemberAPI>();
182 protected List<FleetMemberAPI>
recovered =
new ArrayList<FleetMemberAPI>();
186 for (PerShipData curr :
data.ships) {
214 if (
data.notNowOptionExits !=
null &&
data.notNowOptionExits) {
232 return data !=
null && data.storyPointRecovery !=
null &&
data.storyPointRecovery;
238 if (
data.noDescriptionText !=
null &&
data.noDescriptionText) {
247 boolean withDesc = !debris && !wreck;
250 addText(
"Some time later, you hear back from your chief engineer, " +
251 "who mumbles about being a miracle worker to someone offscreen before " +
252 "noticing you've picked up the call.");
254 addText(
"\"Commander, looks like we might be able to pull this off, though I'll say you're not going to " +
255 "find what I'm going to do in any manual. And it wouldn't pass any inspection, but then again " +
256 "we're not in the Hegemony fleet. It'll fly, though.");
258 addText(
"\"Commander, looks like we might be able to pull this off, though I'll say you're not going to " +
259 "find what I'm going to do in any manual. And it wouldn't pass any inspection, but then again " +
260 "we're not in the Hegemony fleet. These ships can be made to fly again, though.");
269 String ships =
"several ships";
270 String they =
"they";
277 if (
data.storyPointRecovery !=
null &&
data.storyPointRecovery) {
278 addText(
"A crack engineering team sent to the wreck reports successfully preparing it " +
282 addText(
"Salvage crews boarding the wreck discover that many essential systems " +
283 "are undamaged and the ship could be restored to basic functionality.");
286 if (es !=
null && !es.cargo.
isEmpty()) {
287 addText(
"There are also indications that it has some sort of cargo on board.");
292 addText(
"Close-range scans of the debris field reveal " + ships +
293 " that could be restored to basic functionality.");
294 }
else if (withDesc) {
295 String desc =
data.desc;
296 if (desc ==
null) desc =
"floating near";
300 addText(
"Salvage crews report " + ships +
" " + desc +
". " +
301 "Closer inspection reveals " + they +
" could be restored to basic functionality.");
303 addText(
"Salvage crews report " + ships +
" " + desc +
" the $shortName. " +
304 "Closer inspection reveals " + they +
" could be restored to basic functionality.");
310 text.
addPara(
"The crew chief also reports that the hull has undergone %s, which appear to have " +
311 "survived its present state.",
317 addText(
"If not recovered, the ship will be scuttled, " +
318 "and any fitted weapons and fighter LPCs will be retrieved.");
321 addText(
"Any ships that aren't recovered will be scuttled, " +
322 "and any fitted weapons and fighter LPCs will be retrieved.");
328 if (shipData.variant ==
null && shipData.variantId ==
null) {
333 if (shipData.variantId !=
null) {
349 if (shipData.fleetMemberId !=
null) {
350 member.
setId(shipData.fleetMemberId);
353 if (shipData.captain !=
null) {
357 if (
isNameKnown(shipData.condition) || (shipData.nameAlwaysKnown !=
null && shipData.nameAlwaysKnown)) {
367 return condition == ShipCondition.PRISTINE || condition == ShipCondition.GOOD;
376 reduction =
random.nextInt(reduction + 1);
382 for (
int i = 0; i < hits; i++) {
391 variant = variant.
clone();
395 dmods = Math.max(0, dmods - dModsAlready);
397 if (dmods > 0 && shipData.addDmods) {
402 if (dmods > 0 && shipData.addDmods) {
406 if (shipData.sModProb > 0 &&
random.nextFloat() < shipData.sModProb) {
408 float r =
random.nextFloat();
411 }
else if (r > 0.5f) {
425 for (
int i = 0; i < num && !picker.
isEmpty(); i++) {
433 if (shipData.pruneWeapons) {
443 case PRISTINE:
return 1f;
444 case GOOD:
return 0.6f +
random.nextFloat() * 0.2f;
445 case AVERAGE:
return 0.4f +
random.nextFloat() * 0.2f;
446 case BATTERED:
return 0.2f +
random.nextFloat() * 0.2f;
447 case WRECKED:
return random.nextFloat() * 0.1f;
454 if (condition == ShipCondition.PRISTINE)
return 0;
458 case AVERAGE:
return 1 +
random.nextInt(2);
459 case BATTERED:
return 2 +
random.nextInt(2);
460 case WRECKED:
return 3 +
random.nextInt(2);
467 case PRISTINE:
return 1f;
468 case GOOD:
return 0.67f;
469 case AVERAGE:
return 0.5f;
470 case BATTERED:
return 0.33f;
471 case WRECKED:
return 0.2f;
477 if (condition == ShipCondition.PRISTINE)
return 0;
478 if (condition == ShipCondition.WRECKED)
return 20;
483 case GOOD:
return 2 +
random.nextInt(2);
484 case AVERAGE:
return 4 +
random.nextInt(3);
485 case BATTERED:
return 7 +
random.nextInt(6);
490 case GOOD:
return 1 +
random.nextInt(2);
491 case AVERAGE:
return 2 +
random.nextInt(3);
492 case BATTERED:
return 4 +
random.nextInt(4);
497 case GOOD:
return 1 +
random.nextInt(2);
498 case AVERAGE:
return 2 +
random.nextInt(2);
499 case BATTERED:
return 3 +
random.nextInt(3);
505 case AVERAGE:
return 2;
506 case BATTERED:
return 3;
545 if (
RECOVER.equals(optionData)) {
552 if (
data.notNowOptionExits !=
null &&
data.notNowOptionExits) {
560 List<FleetMemberAPI> pool =
members;
561 List<FleetMemberAPI> storyPool =
new ArrayList<FleetMemberAPI>();
569 public void pickedFleetMembers(List<FleetMemberAPI> selected) {
570 if (selected.isEmpty())
return;
575 int index =
members.indexOf(member);
577 PerShipData shipData =
data.ships.get(index);
578 data.ships.remove(index);
582 member.setShipName(shipData.shipName);
583 if (shipData.fleetMemberId !=
null) {
584 member.setId(shipData.fleetMemberId);
592 float hull = (float) Math.random() * (maxHull - minHull) + minHull;
593 hull = Math.max(hull, member.getStatus().getHullFraction());
594 member.getStatus().setHullFraction(hull);
596 float cr = (float) Math.random() * (maxCR - minCR) + minCR;
597 member.getRepairTracker().setCR(cr);
608 SalvageSpecialDialogPlugin plugin = (SalvageSpecialDialogPlugin)
dialog.
getPlugin();
617 public void cancelledFleetMemberPicking() {
621 }
else if (
NOT_NOW.equals(optionData)) {
622 if (
data.notNowOptionExits !=
null &&
data.notNowOptionExits) {
655 if (extra !=
null && !extra.
isEmpty()) {
656 addText(
"Your crews find some securely stowed cargo during the recovery operation.");
725 for (String wingId : variant.
getWings()) {
static SettingsAPI getSettings()
static FactoryAPI getFactory()
static SectorAPI getSector()
static void reportShipsRecovered(List< FleetMemberAPI > ships, InteractionDialogAPI dialog)
static void reportSpecialCargoGainedFromRecoveredDerelict(CargoAPI loot, InteractionDialogAPI dialog)
static void addDMods(FleetMemberData data, boolean own, CampaignFleetAPI recoverer, Random random)
static boolean setDHull(ShipVariantAPI variant)
static int getNumDMods(ShipVariantAPI variant)
static void prepareShipForRecovery(FleetMemberAPI member, boolean retainAllHullmods, boolean retainKnownHullmods, boolean clearSMods, float weaponRetainProb, float wingRetainProb, Random salvageRandom)
static final String HEAVY_MACHINERY
static final String SUPPLIES
static final String WRECK
static final String DEBRIS_FIELD_SHARED
static final String NEUTRAL
static final String INDEPENDENT
static final String PATROL_SMALL
static final String RECOVERED_HULL_MIN
static final String RECOVERED_HULL_MAX
static final String RECOVERED_CR_MAX
static final String SHIP_DMOD_REDUCTION
static final String RECOVERED_CR_MIN
static void addStackGainText(CargoStackAPI stack, TextPanelAPI text)
static boolean fire(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
static boolean fire(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
boolean execute(String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
Map< String, MemoryAPI > memoryMap
void setDone(boolean done)
InteractionDialogAPI dialog
void addText(String format)
void addTempExtraSalvage(CargoAPI cargo)
static CargoAPI getCombinedExtraSalvage(Map< String, MemoryAPI > memoryMap)
void setShowAgain(boolean showAgain)
void setEndWithContinue(boolean endWithContinue)
CampaignFleetAPI playerFleet
static void clearExtraSalvage(Map< String, MemoryAPI > memoryMap)
void setShouldAbortSalvageAndRemoveEntity(boolean shouldAbortSalvageAndRemoveEntity)
static ExtraSalvage getExtraSalvage(SectorEntityToken entity)
List< FleetMemberAPI > recovered
static ShipRecoverySpecialData getSpecialData(SectorEntityToken entity, String desc, boolean create, boolean replace)
void optionSelected(String optionText, Object optionData)
static final String RECOVER
void addExtraSalvageFromUnrecoveredShips()
static boolean isNameKnown(ShipCondition condition)
float getFighterWeaponRetainProb(ShipCondition condition)
void prepareMember(FleetMemberAPI member, PerShipData shipData)
ShipRecoverySpecialData data
boolean isStoryPointRecovery()
static final String RECOVERY_FINISHED
static final String NOT_NOW
int getHitsForCondition(FleetMemberAPI member, ShipCondition condition)
void init(InteractionDialogAPI dialog, Object specialData)
int getDmodsForCondition(ShipCondition condition)
float getHullForCondition(ShipCondition condition)
void addMember(PerShipData shipData)
void addStuffFromMember(CargoAPI cargo, FleetMemberAPI member)
static final String ABORT_CONTINUE
List< FleetMemberAPI > members
static Color getStoryOptionColor()
static Object getSalvageSpecial(SectorEntityToken entity)
static Object getPrevSalvageSpecial(SectorEntityToken entity)
static List< Token > tokenize(String string)
static void setSalvageSpecial(SectorEntityToken entity, Object data)
static int getCurrSpecialMods(ShipVariantAPI variant)
static boolean isUnboardable(FleetMemberAPI member)
CargoAPI createCargo(boolean unlimitedStacks)
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
FleetMemberAPI createFleetMember(FleetMemberType type, String variantOrWingId)
HullModSpecAPI getHullModSpec(String modId)
FleetDataAPI getFleetData()
MutableFleetStatsAPI getStats()
void addWeapons(String id, int count)
void addAll(CargoAPI other)
List< CargoStackAPI > getStacksCopy()
void addCommodity(String commodityId, float quantity)
void addFighters(String id, int count)
String pickRandomShipName()
void addFleetMember(FleetMemberAPI member)
List< FleetMemberAPI > getMembersListCopy()
void setOptionColor(Object optionId, Color color)
InteractionDialogPlugin getPlugin()
SectorEntityToken getInteractionTarget()
void showFleetMemberRecoveryDialog(String title, List< FleetMemberAPI > pool, FleetMemberPickerListener listener)
void addOption(String text, Object data)
void setShortcut(Object data, int code, boolean ctrl, boolean alt, boolean shift, boolean putLast)
FactionAPI getFaction(String factionId)
String getCustomEntityType()
boolean hasTag(String tag)
MemoryAPI getMemoryWithoutUpdate()
LabelAPI addPara(String text)
void showFleetMemberInfo(FleetMemberAPI member)
void showFleetInfo(String titleOne, CampaignFleetAPI one, String titleTwo, CampaignFleetAPI two)
void set(String key, Object value)
boolean isBuiltInWing(int index)
Collection< String > getHullMods()
String getWeaponId(String slotId)
List< String > getWings()
void setOriginalVariant(String targetVariant)
ShipHullSpecAPI getHullSpec()
List< String > getNonBuiltInWeaponSlots()
void addPermaMod(String modId)
void autoGenerateWeaponGroups()
Set< String > getPermaMods()
ShipVariantAPI getVariant()
void setCaptain(PersonAPI commander)
void setShipName(String name)
FleetMemberStatusAPI getStatus()
RepairTrackerAPI getRepairTracker()
ShipHullSpecAPI getHullSpec()
void setVariant(ShipVariantAPI variant, boolean withRefit, boolean withStatsUpdate)
void applyDamage(float hitStrength)
void setHullFraction(float fraction)
void setRandom(Random random)
DynamicStatsAPI getDynamic()
float getFuelFromScuttling()
float getHeavyMachineryFromScuttling()
float getSuppliesFromScuttling()
boolean hasTag(String tag)
boolean isHiddenEverywhere()
float getValue(String id)