Starsector API
Loading...
Searching...
No Matches
DwellerCMD.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.rulecmd;
2
3import java.util.ArrayList;
4import java.util.LinkedHashSet;
5import java.util.List;
6import java.util.Map;
7import java.util.Random;
8import java.util.Set;
9
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.BaseCustomProductionPickerDelegateImpl;
12import com.fs.starfarer.api.campaign.CampaignFleetAPI;
13import com.fs.starfarer.api.campaign.CargoAPI;
14import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
15import com.fs.starfarer.api.campaign.FactionAPI;
16import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
17import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams;
18import com.fs.starfarer.api.campaign.FactionProductionAPI;
19import com.fs.starfarer.api.campaign.FactionProductionAPI.ItemInProductionAPI;
20import com.fs.starfarer.api.campaign.FactionProductionAPI.ProductionItemType;
21import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.DataForEncounterSide;
22import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.FleetMemberData;
23import com.fs.starfarer.api.campaign.InteractionDialogAPI;
24import com.fs.starfarer.api.campaign.OptionPanelAPI;
25import com.fs.starfarer.api.campaign.SectorEntityToken;
26import com.fs.starfarer.api.campaign.SpecialItemData;
27import com.fs.starfarer.api.campaign.SpecialItemPlugin.RightClickActionHelper;
28import com.fs.starfarer.api.campaign.TextPanelAPI;
29import com.fs.starfarer.api.campaign.impl.items.ShroudedHullmodItemPlugin;
30import com.fs.starfarer.api.campaign.impl.items.ShroudedSubstratePlugin;
31import com.fs.starfarer.api.campaign.rules.MemKeys;
32import com.fs.starfarer.api.campaign.rules.MemoryAPI;
33import com.fs.starfarer.api.combat.BattleCreationContext;
34import com.fs.starfarer.api.combat.ShipVariantAPI;
35import com.fs.starfarer.api.fleet.FleetMemberAPI;
36import com.fs.starfarer.api.fleet.ShipRolePick;
37import com.fs.starfarer.api.impl.campaign.AbyssalLightEntityPlugin;
38import com.fs.starfarer.api.impl.campaign.AbyssalLightEntityPlugin.DespawnType;
39import com.fs.starfarer.api.impl.campaign.FleetEncounterContext;
40import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl;
41import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.BaseFIDDelegate;
42import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfig;
43import com.fs.starfarer.api.impl.campaign.RuleBasedInteractionDialogPluginImpl;
44import com.fs.starfarer.api.impl.campaign.ids.Factions;
45import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
46import com.fs.starfarer.api.impl.campaign.ids.Items;
47import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
48import com.fs.starfarer.api.impl.campaign.ids.ShipRoles;
49import com.fs.starfarer.api.impl.campaign.ids.Tags;
50import com.fs.starfarer.api.loading.HullModSpecAPI;
51import com.fs.starfarer.api.loading.WeaponSpecAPI;
52import com.fs.starfarer.api.util.ListMap;
53import com.fs.starfarer.api.util.Misc;
54import com.fs.starfarer.api.util.Misc.Token;
55import com.fs.starfarer.api.util.WeightedRandomPicker;
56
59public class DwellerCMD extends BaseCommandPlugin {
60
61 public static enum DwellerStrength {
62 LOW,
63 MEDIUM,
64 HIGH,
65 EXTREME,
66 }
67
68 public static String SHROUDED_TENDRIL = "shrouded_tendril";
69 public static String SHROUDED_EYE = "shrouded_eye";
70 public static String SHROUDED_MAELSTROM = "shrouded_maelstrom";
71 public static String SHROUDED_MAW = "shrouded_maw";
72
73
75 static {
79 }
80
81 public static ListMap<String> DROP_GROUPS = new ListMap<>();
82 static {
83 DROP_GROUPS.add(SHROUDED_EYE, "drops_shrouded_eye");
84 DROP_GROUPS.add(SHROUDED_MAELSTROM, "drops_shrouded_maelstrom");
85 DROP_GROUPS.add(SHROUDED_MAW, "drops_shrouded_maw");
86 }
87
88
89
90 public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) {
91 if (dialog == null) return false;
92
93 OptionPanelAPI options = dialog.getOptionPanel();
94 TextPanelAPI text = dialog.getTextPanel();
96 CargoAPI cargo = pf.getCargo();
97
98 final SectorEntityToken entity = dialog.getInteractionTarget();
99 long seed = Misc.getSalvageSeed(entity);
100 Random random = Misc.getRandom(seed, 11);
101 //random = new Random();
102
103 String action = params.get(0).getString(memoryMap);
104
105 MemoryAPI memory = memoryMap.get(MemKeys.LOCAL);
106 if (memory == null) return false; // should not be possible unless there are other big problems already
107
108 if ("smallFleet".equals(action)) {
109 return engageFleet(dialog, memoryMap, memory, DwellerStrength.LOW, random);
110 } else if ("mediumFleet".equals(action)) {
111 return engageFleet(dialog, memoryMap, memory, DwellerStrength.MEDIUM, random);
112 } else if ("largeFleet".equals(action)) {
113 return engageFleet(dialog, memoryMap, memory, DwellerStrength.HIGH, random);
114 } else if ("hugeFleet".equals(action)) {
115 return engageFleet(dialog, memoryMap, memory, DwellerStrength.EXTREME, random);
116 } else if ("showWeaponPicker".equals(action)) {
117 showWeaponPicker(dialog, memoryMap);
118 return true;
119 } else if ("unlockHullmod".equals(action)) {
120 unlockHullmod(dialog, memoryMap);
121 return true;
122 }
123 return false;
124 }
125
126 protected void unlockHullmod(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
130
131 Global.getSoundPlayer().playUISound("ui_acquired_hullmod", 1, 1);
132 TextPanelAPI text = dialog.getTextPanel();
134 String str = modSpec.getDisplayName();
135 text.addParagraph("Acquired hull mod: " + str + "", Misc.getPositiveHighlightColor());
137 text.setFontInsignia();
138
139// Global.getSector().getCampaignUI().getMessageDisplay().addMessage(
140// "Acquired hull mod: " + modSpec.getDisplayName() + "");
141
143 }
144
145 public static int getSubstrateCost(WeaponSpecAPI spec) {
146 if (!spec.hasTag(Tags.DWELLER)) return 0;
147 String substrate = "substrate_";
148 for (String tag : spec.getTags()) {
149 if (tag.startsWith(substrate)) {
150 String num = tag.replaceFirst(substrate, "");
151 return Integer.parseInt(num);
152 }
153 }
154 return 0;
155 }
156
157 protected void showWeaponPicker(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
158
160
161 Set<String> weapons = new LinkedHashSet<>();
163 int cost = getSubstrateCost(spec);
164 if (cost > 0 && cost <= substrate) {
165 weapons.add(spec.getWeaponId());
166 }
167 }
168
170 @Override
171 public Set<String> getAvailableFighters() {
172 return new LinkedHashSet<>();
173 }
174 @Override
175 public Set<String> getAvailableShipHulls() {
176 return new LinkedHashSet<>();
177 }
178 @Override
179 public Set<String> getAvailableWeapons() {
180 return weapons;
181 }
182 @Override
183 public float getCostMult() {
184 return 1f;
185 }
186 @Override
187 public float getMaximumValue() {
188 return substrate;
189 }
190
191 @Override
192 public String getWeaponColumnNameOverride() {
193 return "Weapon";
194 }
195
196 @Override
197 public String getNoMatchingBlueprintsLabelOverride() {
198 return "No matching weapons";
199 }
200
201 @Override
202 public String getMaximumOrderValueLabelOverride() {
203 return "Shrouded Substrate available";
204 }
205
206 @Override
207 public String getCurrentOrderValueLabelOverride() {
208 return "Shrouded Substrate required";
209 }
210 @Override
211 public String getItemGoesOverMaxValueStringOverride() {
212 return "Not enough Shrouded Substrate";
213 }
214 @Override
215 public String getCustomOrderLabelOverride() {
216 return "Weapon assembly";
217 }
218 @Override
219 public String getNoProductionOrdersLabelOverride() {
220 return "No assembly orders";
221 }
222 @Override
223 public boolean withQuantityLimits() {
224 return false;
225 }
226 @Override
227 public boolean isUseCreditSign() {
228 return false;
229 }
230
231 @Override
232 public int getCostOverride(Object item) {
233 if (item instanceof WeaponSpecAPI) {
234 return getSubstrateCost((WeaponSpecAPI) item);
235 }
236 return -1;
237 }
238
239 @Override
240 public void notifyProductionSelected(FactionProductionAPI production) {
241 if (!(dialog.getPlugin() instanceof RuleBasedInteractionDialogPluginImpl)) return;
243 if (!(plugin.getCustom1() instanceof RightClickActionHelper)) return;
244 RightClickActionHelper helper = (RightClickActionHelper) plugin.getCustom1();
245
246 int cost = production.getTotalCurrentCost();
247 helper.removeFromClickedStackFirst(cost);
248 int substrate = (int) helper.getNumItems(CargoItemType.SPECIAL, new SpecialItemData(Items.SHROUDED_SUBSTRATE, null));
250
251 for (ItemInProductionAPI item : production.getCurrent()) {
252 if (item.getType() == ProductionItemType.WEAPON) {
253 helper.addItems(CargoItemType.WEAPONS, item.getSpecId(), item.getQuantity());
254 AddRemoveCommodity.addWeaponGainText(item.getSpecId(), item.getQuantity(), dialog.getTextPanel());
255 }
256 }
257
258 FireBest.fire(null, dialog, memoryMap, "SubstrateWeaponsPicked");
259
260 Global.getSoundPlayer().playUISound("ui_cargo_machinery_drop", 1f, 1f);
261 }
262 });
263 }
264
265
266 protected boolean engageFleet(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap, MemoryAPI memory, DwellerStrength str, Random random) {
267 CampaignFleetAPI fleet = createDwellerFleet(str, random);
268 if (fleet == null) return false;
269
272
273 final SectorEntityToken entity = dialog.getInteractionTarget();
274
275 dialog.setInteractionTarget(fleet);
276
278
279 FIDConfig config = new FIDConfig();
280
281 config.delegate = new BaseFIDDelegate() {
282 public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) {
283 if (!(dialog.getInteractionTarget() instanceof CampaignFleetAPI)) return;
284
285 float mult = context.computePlayerContribFraction();
286
288
289 DataForEncounterSide data = context.getDataFor(fleet);
290 List<FleetMemberAPI> losses = new ArrayList<FleetMemberAPI>();
291 for (FleetMemberData fmd : data.getOwnCasualties()) {
292 losses.add(fmd.getMember());
293 }
294
295 float min = 0f;
296 float max = 0f;
297 boolean gotGuaranteed = false;
298 for (FleetMemberAPI member : losses) {
299 if (member.getHullSpec().hasTag(Tags.DWELLER)) {
300 String key = "substrate_";
301 float [] sDrops = Misc.getFloatArray(key + member.getHullSpec().getHullId());
302 if (sDrops == null) {
303 sDrops = Misc.getFloatArray(key + member.getHullSpec().getHullSize().name());
304 }
305 if (sDrops == null) continue;
306
307 min += sDrops[0];
308 max += sDrops[1];
309
310 String hullId = member.getHullSpec().getRestoredToHullId();
311 String defeatedKey = "$defeatedDweller_" + hullId;
312 boolean firstTime = !Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(defeatedKey);
313 Global.getSector().getPlayerMemoryWithoutUpdate().set(defeatedKey, true);
314 if (firstTime && !gotGuaranteed) {
315 List<String> drops = GUARANTEED_FIRST_TIME_ITEMS.get(hullId);
316 for (String itemId : drops) {
317 SpecialItemData sid = new SpecialItemData(itemId, null);
318 boolean add = firstTime && salvage.getQuantity(CargoItemType.SPECIAL, sid) <= 0;
319 if (add) {
320 salvage.addItems(CargoItemType.SPECIAL, sid, 1);
321 gotGuaranteed = true;
322 }
323 }
324 }
325 }
326 }
327
328 long seed = Misc.getSalvageSeed(entity);
329 Random random = Misc.getRandom(seed, 50);
330 int substrate = 0;
331 if (min + max < 1f) {
332 if (random.nextFloat() < (min + max) / 2f) {
333 substrate = 1;
334 }
335 } else {
336 substrate = (int) Math.round(min + (max - min) * random.nextFloat());
337 }
338
339 if (substrate > 0) {
340 salvage.addItems(CargoItemType.SPECIAL, new SpecialItemData(Items.SHROUDED_SUBSTRATE, null), substrate);
341 }
342 }
343
344 public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) {
345 bcc.aiRetreatAllowed = false;
346 bcc.fightToTheLast = true;
347 bcc.objectivesAllowed = false;
348 bcc.enemyDeployAll = true;
349
350 // despawn the light here - the salvage gen method is only called if the player won
351 // but want to despawn the light after any fight, regardless
352 if (entity.getCustomPlugin() instanceof AbyssalLightEntityPlugin) {
354 plugin.despawn(DespawnType.FADE_OUT);
355 }
356 }
357 };
358
359 config.alwaysAttackVsAttack = true;
360 //config.alwaysPursue = true;
361 config.alwaysHarry = true;
362 config.showTransponderStatus = false;
363 //config.showEngageText = false;
364 config.lootCredits = false;
365
366 config.showCommLinkOption = false;
367 config.showEngageText = false;
368 config.showFleetAttitude = false;
369 config.showTransponderStatus = false;
370 config.showWarningDialogWhenNotHostile = false;
371 config.impactsAllyReputation = false;
372 config.impactsEnemyReputation = false;
373 config.pullInAllies = false;
374 config.pullInEnemies = false;
375 config.pullInStations = false;
376
377 config.showCrRecoveryText = false;
378 config.firstTimeEngageOptionText = "\"Battle stations!\"";
379 config.afterFirstTimeEngageOptionText = "Move in to re-engage";
380
381 if (str == DwellerStrength.LOW) {
382 config.firstTimeEngageOptionText = null;
383 config.leaveAlwaysAvailable = true;
384 } else {
385 config.leaveAlwaysAvailable = true; // except for first engagement
386 config.noLeaveOptionOnFirstEngagement = true;
387 }
388 //config.noLeaveOption = true;
389
390// config.noSalvageLeaveOptionText = "Continue";
391
392// config.dismissOnLeave = false;
393// config.printXPToDialog = true;
394
395 long seed = Misc.getSalvageSeed(entity);
396 config.salvageRandom = Misc.getRandom(seed, 75);
397
398 Global.getSector().getPlayerMemoryWithoutUpdate().set("$encounteredDweller", true);
399 Global.getSector().getPlayerMemoryWithoutUpdate().set("$encounteredMonster", true);
400 Global.getSector().getPlayerMemoryWithoutUpdate().set("$encounteredWeird", true);
401
403
404 //final InteractionDialogPlugin originalPlugin = dialog.getPlugin();
405
406 dialog.setPlugin(plugin);
407 plugin.init(dialog);
408
409
410 return true;
411 }
412
413
414
415 public static CampaignFleetAPI createDwellerFleet(DwellerStrength str, Random random) {
417
419 String typeKey = FleetTypes.PATROL_SMALL;
420 if (str == DwellerStrength.MEDIUM) typeKey = FleetTypes.PATROL_MEDIUM;
421 if (str == DwellerStrength.HIGH) typeKey = FleetTypes.PATROL_LARGE;
422 if (str == DwellerStrength.EXTREME) typeKey = FleetTypes.PATROL_LARGE;
423 f.setName(faction.getFleetTypeName(typeKey));
424
425 f.setInflater(null);
426
427 if (str == DwellerStrength.LOW) {
428 addShips(f, 6, 8, random, ShipRoles.DWELLER_TENDRIL);
429 addShips(f, 1, 1, random, ShipRoles.DWELLER_EYE);
430 addShips(f, 1, 2, random, ShipRoles.DWELLER_MAELSTROM);
431 } else if (str == DwellerStrength.MEDIUM) {
432 addShips(f, 9, 12, random, ShipRoles.DWELLER_TENDRIL);
433 int eyes = addShips(f, 1, 1, random, ShipRoles.DWELLER_EYE);
434 addShips(f, 2 - eyes, 3 - eyes, random, ShipRoles.DWELLER_MAELSTROM);
435 addShips(f, 1, 1, random, ShipRoles.DWELLER_MAW);
436 } else if (str == DwellerStrength.HIGH) {
437 addShips(f, 11, 14, random, ShipRoles.DWELLER_TENDRIL);
438 int eyes = addShips(f, 2, 3, random, ShipRoles.DWELLER_EYE);
439 addShips(f, 3 - eyes, 5 - eyes, random, ShipRoles.DWELLER_MAELSTROM);
440 addShips(f, 1, 1, random, ShipRoles.DWELLER_MAW);
441 } else if (str == DwellerStrength.EXTREME) {
442 addShips(f, 12, 15, random, ShipRoles.DWELLER_TENDRIL);
443 int eyes = addShips(f, 2, 3, random, ShipRoles.DWELLER_EYE);
444 addShips(f, 3 - eyes, 5 - eyes, random, ShipRoles.DWELLER_MAELSTROM);
445 addShips(f, 2, 2, random, ShipRoles.DWELLER_MAW);
446 }
447
450 f.getFleetData().sort();
451
453 curr.getRepairTracker().setCR(curr.getRepairTracker().getMaxCR());
454
455 // tag is added to ships now
456// ShipVariantAPI v = curr.getVariant().clone();
457// v.addTag(Tags.LIMITED_TOOLTIP_IF_LOCKED);
458// curr.setVariant(v, false, false);
459 }
460
461
462// f.getMemoryWithoutUpdate().set(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN,
463// new DwellerFIDConfig());
464// f.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE, true);
465
466 // required for proper music track to play, see: DwellerCMD
468
469// //f.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_ALWAYS_PURSUE, true);
470// f.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_ALLOW_LONG_PURSUIT, true);
472
473 return f;
474 }
475
476
477 public static int addShips(CampaignFleetAPI fleet, int min, int max, Random random, Object ... roles) {
478 if (min < 0) min = 0;
479 if (max < 0) max = 0;
480
482 if (roles.length == 1) {
483 picker.add((String) roles[0], 1f);
484 } else {
485 for (int i = 0; i < roles.length; i += 2) {
486 picker.add((String) roles[i], (float) roles[i + 1]);
487 }
488 }
489 int num = min + random.nextInt(max - min + 1);
491
492 ShipPickParams p = new ShipPickParams(ShipPickMode.ALL);
493 p.blockFallback = true;
494 p.maxFP = 1000000;
495 for (int i = 0; i < num; i++) {
496 String role = picker.pick();
497 List<ShipRolePick> picks = faction.pickShip(role, p, null, random);
498 for (ShipRolePick pick : picks) {
499 fleet.getFleetData().addFleetMember(pick.variantId);
500
501 ShipVariantAPI variant = Global.getSettings().getVariant(pick.variantId);
502 if (variant != null) {
503 String hullId = variant.getHullSpec().getRestoredToHullId();
504 List<String> dropGroups = DROP_GROUPS.get(hullId);
505 for (String group : dropGroups) {
506 fleet.addDropRandom(group, 1);
507 }
508 }
509 }
510 }
511 return num;
512 }
513}
514
static SettingsAPI getSettings()
Definition Global.java:57
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:49
static FactoryAPI getFactory()
Definition Global.java:41
static SectorAPI getSector()
Definition Global.java:65
DataForEncounterSide getDataFor(CampaignFleetAPI participantOrCombined)
static void addWeaponGainText(String weaponId, int quantity, TextPanelAPI text)
boolean engageFleet(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, MemoryAPI memory, DwellerStrength str, Random random)
void showWeaponPicker(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
boolean execute(String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
static CampaignFleetAPI createDwellerFleet(DwellerStrength str, Random random)
static int addShips(CampaignFleetAPI fleet, int min, int max, Random random, Object ... roles)
void unlockHullmod(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
static boolean fire(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
Definition FireBest.java:56
static Random getRandom(long seed, int level)
Definition Misc.java:2973
static long getSalvageSeed(SectorEntityToken entity)
Definition Misc.java:4129
static Color getHighlightColor()
Definition Misc.java:792
static float[] getFloatArray(String key)
Definition Misc.java:6858
static Color getPositiveHighlightColor()
Definition Misc.java:822
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
ShipVariantAPI getVariant(String variantId)
HullModSpecAPI getHullModSpec(String modId)
List< WeaponSpecAPI > getAllWeaponSpecs()
SoundAPI playUISound(String id, float pitch, float volume)
void setInflater(FleetInflater inflater)
void restartEncounterMusic(SectorEntityToken interactionTarget)
float getQuantity(CargoAPI.CargoItemType type, Object data)
void addItems(CargoAPI.CargoItemType itemType, Object data, float quantity)
List< ShipRolePick > pickShip(String role, ShipPickParams params)
void addFleetMember(FleetMemberAPI member)
List< FleetMemberAPI > getMembersListCopy()
void setInteractionTarget(SectorEntityToken interactionTarget)
void setPlugin(InteractionDialogPlugin plugin)
void showCustomProductionPicker(CustomProductionPickerDelegate delegate)
FactionAPI getFaction(String factionId)
CustomCampaignEntityPlugin getCustomPlugin()
void addDropRandom(String group, int chances)
void setContainingLocation(LocationAPI location)
void highlightInLastPara(Color color, String ...strings)
void set(String key, Object value)