Starsector API
Loading...
Searching...
No Matches
SimulatorPluginImpl.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl;
2
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.Collections;
6import java.util.Comparator;
7import java.util.LinkedHashSet;
8import java.util.List;
9import java.util.Map;
10import java.util.Random;
11import java.util.Set;
12
13import org.json.JSONArray;
14import org.json.JSONException;
15import org.json.JSONObject;
16
17import com.fs.starfarer.api.Global;
18import com.fs.starfarer.api.campaign.BattleAPI;
19import com.fs.starfarer.api.campaign.CampaignFleetAPI;
20import com.fs.starfarer.api.campaign.CargoAPI;
21import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
22import com.fs.starfarer.api.campaign.FactionAPI;
23import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
24import com.fs.starfarer.api.campaign.FactionDoctrineAPI;
25import com.fs.starfarer.api.campaign.FactionSpecAPI;
26import com.fs.starfarer.api.campaign.econ.MarketAPI;
27import com.fs.starfarer.api.characters.PersonAPI;
28import com.fs.starfarer.api.characters.SkillSpecAPI;
29import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
30import com.fs.starfarer.api.combat.DeployedFleetMemberAPI;
31import com.fs.starfarer.api.combat.ShipAPI;
32import com.fs.starfarer.api.combat.ShipAPI.HullSize;
33import com.fs.starfarer.api.combat.ShipCommand;
34import com.fs.starfarer.api.combat.ShipHullSpecAPI.ShipTypeHints;
35import com.fs.starfarer.api.combat.ShipSystemSpecAPI;
36import com.fs.starfarer.api.combat.ShipVariantAPI;
37import com.fs.starfarer.api.fleet.FleetMemberAPI;
38import com.fs.starfarer.api.impl.campaign.DModManager;
39import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflater;
40import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflaterParams;
41import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
42import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3;
43import com.fs.starfarer.api.impl.campaign.ids.Commodities;
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.Personalities;
47import com.fs.starfarer.api.impl.campaign.ids.ShipRoles;
48import com.fs.starfarer.api.impl.campaign.ids.Skills;
49import com.fs.starfarer.api.impl.campaign.ids.Tags;
50import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
51import com.fs.starfarer.api.impl.campaign.intel.misc.SimUpdateIntel;
52import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.OfficerQuality;
53import com.fs.starfarer.api.impl.campaign.procgen.themes.RemnantOfficerGeneratorPlugin;
54import com.fs.starfarer.api.input.InputEventAPI;
55import com.fs.starfarer.api.loading.FighterWingSpecAPI;
56import com.fs.starfarer.api.loading.HullModSpecAPI;
57import com.fs.starfarer.api.loading.VariantSource;
58import com.fs.starfarer.api.loading.WeaponSlotAPI;
59import com.fs.starfarer.api.loading.WeaponSpecAPI;
60import com.fs.starfarer.api.mission.FleetSide;
61import com.fs.starfarer.api.plugins.AutofitPlugin.AutofitPluginDelegate;
62import com.fs.starfarer.api.plugins.AutofitPlugin.AvailableFighter;
63import com.fs.starfarer.api.plugins.AutofitPlugin.AvailableWeapon;
64import com.fs.starfarer.api.plugins.SimulatorPlugin;
65import com.fs.starfarer.api.plugins.impl.CoreAutofitPlugin;
66import com.fs.starfarer.api.ui.Alignment;
67import com.fs.starfarer.api.ui.TooltipMakerAPI;
68import com.fs.starfarer.api.util.CountingMap;
69import com.fs.starfarer.api.util.Misc;
70import com.fs.starfarer.api.util.WeightedRandomPicker;
71
73
74 public static boolean INCLUDE_PLAYER_BLUEPRINTS = false;
75 public static boolean REQUIRE_AI_CORES = true;
76 public static boolean REQUIRE_AI_CORES_IN_CARGO = Global.getSettings().getBoolean("requireAICoresInCargoForSimulator");
77
78
79 public static String UNLOCKS_DATA_FILE = "core_sim_unlocks.json";
80 public static String CUSTOM_OPPONENTS_FILE = "core_sim_custom_opponents.json";
81 public static String UI_STATE_DATA_FILE = "core_sim_settings.json";
82
83 public static String DEFAULT_CAT_ID = "cat_default";
84 public static String CUSTOM_CAT_ID = "cat_custom";
85 public static String OTHER_CAT_ID = "cat_other";
86 public static String CIV_CAT_ID = "cat_civ";
87 public static String DEV_CAT_ID = "cat_dev";
88
89 public static String AGGRO_ID = "aggro";
90 public static String AGGRO_ID_CORES_ONLY = "aggro_cores";
91 public static String AGGRO_DEFAULT = "default";
92 public static String AGGRO_CAUTIOUS = "cautious";
93 public static String AGGRO_STEADY = "steady";
94 public static String AGGRO_AGGRESSIVE = "aggressive";
95 public static String AGGRO_RECKLESS = "reckless";
96 public static String AGGRO_NORMAL = "normal";
97 public static String AGGRO_DO_NOTHING = "do_nothing";
98 public static String AGGRO_DEFENSES = "defenses_only";
99 public static String AGGRO_STATIONARY = "stationary";
100
101
102 public static String OFFICERS_CUSTOM_ID = "officers_custom";
103 public static String OFFICERS_CUSTOM_NONE = "none";
104 public static String OFFICERS_CUSTOM_SOME = "some";
105 public static String OFFICERS_CUSTOM_5 = "level5";
106 public static String OFFICERS_CUSTOM_6 = "level6";
107
108 public static String OFFICERS_ID = "officers";
109 public static String OFFICERS_NONE = "none";
110 public static String OFFICERS_DEFAULT = "default";
111 public static String OFFICERS_ALL = "all";
112
113 public static String QUALITY_ID = "quality";
114 public static String QUALITY_MAX_DMODS = "max_dmods";
115 public static String QUALITY_SOME_DMODS = "some_dmods";
116 public static String QUALITY_NO_DMODS = "no_dmods";
117 public static String QUALITY_SOME_SDMODS = "some_smods";
118 public static String QUALITY_MANY_SMODS = "many_smods";
119
120 public static String AI_CORES_ID = "ai_cores";
121 public static String AI_CORES_DERELICT_ID = "ai_cores_derelict";
122 public static String AI_CORES_OMEGA_ID = "ai_cores_omega";
123 public static String AI_CORES_DEV_ID = "ai_cores_dev";
124 public static String AI_CORES_NONE = "none";
125 public static String AI_CORES_SOME = "some";
126 public static String AI_CORES_GAMMA = "gamma";
127 public static String AI_CORES_BETA = "beta";
128 public static String AI_CORES_ALPHA = "alpha";
129 public static String AI_CORES_OMEGA = "omega";
130
131 public static String RANDOMIZE_VARIANTS_ID = "randomize_variants";
132 public static String INTEGRATE_CORES_ID = "integrate_cores";
133
134
135
136 public static boolean isShowDevCategories() {
137 return (Global.getSettings().isDevMode() && !Global.getSettings().getBoolean("playtestingMode")) ||
138 !(Global.getCombatEngine().isInCampaignSim() || Global.getCombatEngine().isInMissionSim());
139 }
140
141 public static boolean isSimFullyUnlocked() {
142 return (Global.getSettings().isDevMode() && !Global.getSettings().getBoolean("playtestingMode")) ||
143 !(Global.getCombatEngine().isInCampaignSim() || Global.getCombatEngine().isInMissionSim());
144 }
145
146 public static boolean isAllStandardStuffUnlocked() {
147 return Global.getSettings().getBoolean("allStandardShipsAndFactionsUnlockedInSimulator");
148 }
149
150 public static class SimUnlocksData {
151 public LinkedHashSet<String> factions = new LinkedHashSet<String>();
152 public LinkedHashSet<String> variants = new LinkedHashSet<String>();
153
154 public void fromJSON(JSONObject json) {
155 factions = new LinkedHashSet<String>();
156 JSONArray arr = json.optJSONArray("factions");
157 if (arr != null) {
158 for (int i = 0; i < arr.length(); i++) {
159 String value = arr.optString(i);
160 if (value != null) {
161 factions.add(value);
162 }
163 }
164 }
165 variants = new LinkedHashSet<String>();
166 arr = json.optJSONArray("variants");
167 if (arr != null) {
168 for (int i = 0; i < arr.length(); i++) {
169 String value = arr.optString(i);
170 if (value != null) {
171 variants.add(value);
172 }
173 }
174 }
175 }
176
177 public JSONObject toJSON() throws JSONException {
178 JSONObject json = new JSONObject();
179
180 JSONArray arr1 = new JSONArray();
181 for (String value : factions) {
182 arr1.put(value);
183 }
184 JSONArray arr2 = new JSONArray();
185 for (String value : variants) {
186 arr2.put(value);
187 }
188
189 json.put("factions", arr1);
190 json.put("variants", arr2);
191
192 return json;
193 }
194 }
195
196
197
198
199 protected SimUIStateData uiStateData = new SimUIStateData();
200 protected Set<String> defaultOpponents = new LinkedHashSet<String>();
201 protected Set<String> customOpponents = new LinkedHashSet<String>();
202 protected boolean loadedStuff = false;
203 protected SimUnlocksData unlocksData = new SimUnlocksData();
204
207 }
208
209 public boolean coreReqsMet(String coreId) {
210 if (!REQUIRE_AI_CORES || !Global.getCombatEngine().isInCampaignSim()) return true;
211 if (isSimFullyUnlocked()) return true;
212 return Global.getSector().getPlayerFleet().getCargo().getQuantity(CargoItemType.RESOURCES, coreId) > 0;
213 }
214
215 public boolean isRequireAICoresInCargo() {
216 if (!REQUIRE_AI_CORES_IN_CARGO) return false;
217 if (isSimFullyUnlocked()) return false;
219 }
220
221
222 public void addCustomOpponents(List<String> variants) {
223 customOpponents.addAll(variants);
224 }
225
226 public void removeCustomOpponents(List<String> variants) {
227 customOpponents.removeAll(variants);
228 }
229
230 public void clearCustomOpponents() {
231 customOpponents = new LinkedHashSet<String>();
232// for (String variantId : Global.getSettings().getSimOpponents()) {
233// if (Global.getSettings().getVariant(variantId) == null) continue;
234// customOpponents.add(variantId);
235// }
236 }
237
238 public void loadCustomOpponents() {
239 try {
241 customOpponents = new LinkedHashSet<String>();
243 JSONArray arr = json.optJSONArray("opponents");
244 if (arr != null) {
245 for (int i = 0; i < arr.length(); i++) {
246 String variantId = arr.getString(i);
247 if (Global.getSettings().getVariant(variantId) == null) continue;
248 customOpponents.add(variantId);
249 }
250 }
251 } else {
253 }
254 } catch (IOException e) {
255 e.printStackTrace();
256 } catch (JSONException e) {
257 e.printStackTrace();
258 }
259 }
260
261 public void saveCustomOpponents() {
262 try {
263 JSONObject json = new JSONObject();
264 JSONArray arr = new JSONArray();
265 for (String variantId : customOpponents) {
266 arr.put(variantId);
267 }
268 json.put("opponents", arr);
270 } catch (JSONException e) {
271 e.printStackTrace();
272 } catch (IOException e) {
273 e.printStackTrace();
274 }
275 }
276
277 public void resetToDefaults(boolean withSave) {
278 uiStateData.settings.clear();
279 uiStateData.settings.put(AGGRO_ID, AGGRO_DEFAULT);
286 uiStateData.settings.put(RANDOMIZE_VARIANTS_ID, "false");
287 uiStateData.settings.put(INTEGRATE_CORES_ID, "false");
288 uiStateData.groupSize = 0;
289 if (withSave) {
291 }
292 }
293
294 public void loadUIStateData() {
295 try {
297 JSONObject json = Global.getSettings().readJSONFromCommon(UI_STATE_DATA_FILE, true);
298 uiStateData.fromJSON(json);
299 } else {
300 uiStateData.selectedCategory = DEFAULT_CAT_ID;
301 uiStateData.showAdvanced = false;
302 resetToDefaults(false);
303 }
304 } catch (IOException e) {
305 e.printStackTrace();
306 } catch (JSONException e) {
307 e.printStackTrace();
308 }
309 }
310
311 public void saveUIStateData() {
312 try {
313 JSONObject json = uiStateData.toJSON();
315 } catch (JSONException e) {
316 e.printStackTrace();
317 } catch (IOException e) {
318 e.printStackTrace();
319 }
320 }
321
322 public SimUIStateData getUIStateData() {
323 return uiStateData;
324 }
325
326 public void loadUnlocksData() {
327 try {
328 defaultOpponents.clear();
330
332 JSONObject json = Global.getSettings().readJSONFromCommon(UNLOCKS_DATA_FILE, true);
333 unlocksData.fromJSON(json);
334
335 //unlocksData.variants.addAll(Global.getSettings().getSimOpponents());
336 } else {
337
338 }
339 } catch (IOException e) {
340 e.printStackTrace();
341 } catch (JSONException e) {
342 e.printStackTrace();
343 }
344 }
345
346 public void saveUnlocksData() {
347 try {
348 JSONObject json = unlocksData.toJSON();
350 } catch (JSONException e) {
351 e.printStackTrace();
352 } catch (IOException e) {
353 e.printStackTrace();
354 }
355 }
356
357 public SimUnlocksData getUnlocksData() {
358 return unlocksData;
359 }
360
361 public List<AdvancedSimOption> getSimOptions(SimCategoryData category) {
362 List<AdvancedSimOption> result = new ArrayList<AdvancedSimOption>();
363
364 boolean custom = CUSTOM_CAT_ID.equals(category.id);
365 boolean other = OTHER_CAT_ID.equals(category.id);
366 boolean defaultCat = DEFAULT_CAT_ID.equals(category.id);
367 boolean civ = CIV_CAT_ID.equals(category.id);
368 boolean dev = DEV_CAT_ID.equals(category.id);
369 boolean customFaction = custom || civ || dev || defaultCat || other;
370
371 JSONObject json = category.faction.getCustom().optJSONObject("simulatorData");
372 boolean standardAICores = json != null && json.optBoolean("standardAICores");
373 boolean derelictAICores = json != null && json.optBoolean("derelictAICores");
374 boolean omegaAICores = json != null && json.optBoolean("omegaAICores");
375 boolean noOfficers = json != null && json.optBoolean("noOfficers");
376
377 boolean showOfficers = !standardAICores && !derelictAICores && !omegaAICores && !noOfficers;
378 boolean integrateCores = standardAICores || derelictAICores || dev || custom || other;
379
380 if (custom || defaultCat || other) {
381 showOfficers = true;
382 standardAICores = true;
383 integrateCores = true;
384 }
385
386 String aggroExtra = "";
387 String aiExtra = "";
388 if (custom || defaultCat || dev || other) {
389 aggroExtra = "\n\nDoes not affect AI cores or automated ships.";
390 aiExtra = "\n\nOnly affects automated ships.";
391 }
392
393 String aggroTitle = "Aggression / behavior";
394 String aggroId = AGGRO_ID;
395 if (!showOfficers) {
396 aggroTitle = "Behavior";
397 aggroId = AGGRO_ID_CORES_ONLY;
398 }
399
400 SimOptionSelectorData aggro = new SimOptionSelectorData(aggroId, aggroTitle, true);
401 if (showOfficers) {
402 if (custom || defaultCat || civ || dev || other) {
403 aggro.options.add(new SimOptionData(AGGRO_DEFAULT, "Default (steady)",
404 Global.getSettings().getPersonaltySpec(Personalities.STEADY).getDescription().replaceAll("officer", "aggression level") + aggroExtra, "behavior_default"));
405 } else {
406 aggro.options.add(new SimOptionData(AGGRO_DEFAULT, "Faction default",
407 "Default aggression level for the selected faction." + aggroExtra, "behavior_default"));
408 }
409 aggro.options.add(new SimOptionData(AGGRO_CAUTIOUS, "Cautious",
410 Global.getSettings().getPersonaltySpec(Personalities.CAUTIOUS).getDescription().replaceAll("officer", "aggression level") + aggroExtra, "behavior_cautious"));
411 aggro.options.add(new SimOptionData(AGGRO_STEADY, "Steady",
412 Global.getSettings().getPersonaltySpec(Personalities.STEADY).getDescription().replaceAll("officer", "aggression level") + aggroExtra, "behavior_steady"));
413 aggro.options.add(new SimOptionData(AGGRO_AGGRESSIVE, "Aggressive",
414 Global.getSettings().getPersonaltySpec(Personalities.AGGRESSIVE).getDescription().replaceAll("officer", "aggression level") + aggroExtra, "behavior_aggressive"));
415 aggro.options.add(new SimOptionData(AGGRO_RECKLESS, "Reckless",
416 Global.getSettings().getPersonaltySpec(Personalities.RECKLESS).getDescription().replaceAll("officer", "aggression level") + aggroExtra, "behavior_reckelss"));
417 } else {
418 aggro.options.add(new SimOptionData(AGGRO_NORMAL, "Normal", "Opposing ships will behave normally.", "behavior_default"));
419 }
420
421 aggro.options.add(new SimOptionData(AGGRO_DO_NOTHING, "Do nothing", "Opposing ships will not move, use shields, fire weapons, or take any other actions.", "behavior_passive"));
422 if (showOfficers) {
423 aggro.options.get(aggro.options.size() - 1).extraPad = 10f;
424 }
425 aggro.options.add(new SimOptionData(AGGRO_DEFENSES, "Stationary, defenses only", "Opposing ships will not move, but will use shields/phase cloak/other defenses and defensive ship systems, if any.", "behavior_defensive"));
426 aggro.options.add(new SimOptionData(AGGRO_STATIONARY, "Stationary", "Opposing ships will not move, but will otherwise behave normally.", "behavior_stationary"));
427 aggro.compact = false;
428 result.add(aggro);
429
430
431 if (showOfficers) {
432 if (customFaction) {
433 SimOptionSelectorData officers = new SimOptionSelectorData(OFFICERS_CUSTOM_ID, "Officers", true);
434 officers.options.add(new SimOptionData(OFFICERS_CUSTOM_NONE, "None", "No officers on any opposing ships.", "officers_none"));
435 officers.options.add(new SimOptionData(OFFICERS_CUSTOM_SOME, "Some", "Some officers, up to level 5.", "officers_some"));
436 officers.options.add(new SimOptionData(OFFICERS_CUSTOM_5, "All ships, level 5", "Level 5 officers on all opposing ships.", "officers_all"));
437 officers.options.add(new SimOptionData(OFFICERS_CUSTOM_6, "All ships, level 6", "Level 6 officers on all opposing ships.", "officers_high"));
438 result.add(officers);
439 } else {
440 SimOptionSelectorData officers = new SimOptionSelectorData(OFFICERS_ID, "Officers", true);
441 officers.options.add(new SimOptionData(OFFICERS_NONE, "None", "No officers on any opposing ships.", "officers_none"));
442 officers.options.add(new SimOptionData(OFFICERS_DEFAULT, "Faction default", "Default number and level of officers for the selected faction.", "officers_some"));
443 officers.options.add(new SimOptionData(OFFICERS_ALL, "All ships", "Maximum level officers on all opposing ships.", "officers_high"));
444 result.add(officers);
445 }
446 }
447
448 if (standardAICores || derelictAICores || omegaAICores || custom || defaultCat || dev || other) {
449 String coresId = AI_CORES_ID;
450 if (dev) {
451 coresId = AI_CORES_DEV_ID;
452 } else if (omegaAICores) {
453 coresId = AI_CORES_OMEGA_ID;
454 } else if (derelictAICores) {
455 coresId = AI_CORES_DERELICT_ID;
456 }
457 SimOptionSelectorData cores = new SimOptionSelectorData(coresId, "AI cores", false);
458 cores.options.add(new SimOptionData(AI_CORES_NONE, "None", "No AI cores on any opposing ships.", "cores_none"));
459
460 boolean enableAlpha = coreReqsMet(Commodities.ALPHA_CORE);
461 boolean enableBeta = coreReqsMet(Commodities.BETA_CORE) || enableAlpha;
462 boolean enableGamma = coreReqsMet(Commodities.GAMMA_CORE) || enableBeta;
463 boolean enableMixed = enableAlpha || (derelictAICores && enableGamma);
464
465 String reqGamma = null;
466 if (!enableGamma) reqGamma = "Requires a Gamma Core or better in your cargo.";
467 String reqBeta = null;
468 if (!enableBeta) reqBeta = "Requires a Beta Core or better in your cargo.";
469 String reqAlpha = null;
470 if (!enableAlpha) reqAlpha = "Requires an Alpha Core in your cargo.";
471 String reqMixed = null;
472 if (!enableMixed) {
473 if (derelictAICores) {
474 reqMixed = "Requires a Gamma Core or better in your cargo.";
475 } else {
476 reqMixed = "Requires an Alpha Core in your cargo.";
477 }
478 }
479
480 String coresCargoNote = "";
481 String ifPossible = "";
483 coresCargoNote = " The AI cores used are limited to the total number and type "
484 + "of cores in your cargo (and storage, if docked).";
485 ifPossible = ", if possible";
486 boolean canUseCores = enableGamma || enableBeta || enableAlpha || enableMixed;
487 if (canUseCores) {
488 enableGamma = enableBeta = enableAlpha = enableMixed = true;
489 reqGamma = reqBeta = reqAlpha = reqMixed = null;
490 } else {
491 enableGamma = enableBeta = enableAlpha = enableMixed = false;
492 reqGamma = reqBeta = reqAlpha = reqMixed = "No AI cores in cargo (or storage, if docked).";
493 }
494 }
495
496 if (standardAICores || derelictAICores || dev) {
497 cores.options.add(new SimOptionData(AI_CORES_SOME, "Mixed", "A mix of AI cores on some of the opposing ships, based on the number and size of opponents deployed." + coresCargoNote + aiExtra, enableMixed, reqMixed, "cores_mixed"));
498 cores.options.add(new SimOptionData(AI_CORES_GAMMA, "Gamma cores on all ships", "A gamma core on every opposing ship" + ifPossible + "." + coresCargoNote + aiExtra, enableGamma, reqGamma, "cores_gamma"));
499 if (standardAICores || dev) {
500 cores.options.add(new SimOptionData(AI_CORES_BETA, "Beta cores on all ships", "A beta core on every opposing ship" + ifPossible + "." + coresCargoNote + aiExtra, enableBeta, reqBeta, "cores_beta"));
501 cores.options.add(new SimOptionData(AI_CORES_ALPHA, "Alpha cores on all ships", "An alpha core on every opposing ship" + ifPossible + "." + coresCargoNote + aiExtra, enableAlpha, reqAlpha, "cores_alpha"));
502 }
503 }
504 if (dev || omegaAICores) {
505 cores.options.add(new SimOptionData(AI_CORES_OMEGA, "Omega cores on all ships", "An omega core on every opposing ship." + aiExtra, "cores_omega"));
506 }
507 if (!omegaAICores) {
508 cores.padAfter = 10f;
509 }
510 result.add(cores);
511 }
512
513 if (integrateCores) {
514 String iTooltipExtra = "";
515 if (dev) {
516 iTooltipExtra = "\n\nDoes not affect omega cores.";
517 }
518 SimOptionCheckboxData integrate = new SimOptionCheckboxData(INTEGRATE_CORES_ID, "Integrate AI cores",
519 "AI cores will be integrated into opposing ships, increasing each core's level by 1." + iTooltipExtra);
520 // no longer relevant since aggression/behavior is no longer condensed and is taller
521// if (!custom && !dev && !defaultCat && !other) {
522// integrate.padAfter += 8f;
523// }
524 result.add(integrate);
525 }
526
527
528 SimOptionSelectorData quality = new SimOptionSelectorData(QUALITY_ID, "Ship quality", true);
529 quality.options.add(new SimOptionData(QUALITY_MAX_DMODS, "Maximum d-mods", "Five d-mods on all opposing ships.", "quality_lowest"));
530 quality.options.add(new SimOptionData(QUALITY_SOME_DMODS, "Some d-mods", "Two to four d-mods on all opposing ships.", "quality_low"));
531 quality.options.add(new SimOptionData(QUALITY_NO_DMODS, "No d-mods", "No d-mods on any opposing ships.", "quality_no_dmods"));
532 quality.options.add(new SimOptionData(QUALITY_SOME_SDMODS, "Some s-mods", "One or two s-mods on all opposing ships.", "quality_high"));
533 quality.options.add(new SimOptionData(QUALITY_MANY_SMODS, "Many s-mods", "Two or three s-mods on all opposing ships.", "quality_highest"));
534 result.add(quality);
535
536 // no longer relevant since aggression/behavior is no longer condensed and is taller
537// if (!custom && !dev && !defaultCat && !other) {
538// quality.padAfter += 11f; // to line it up with the separator line between deployed/reserve
539// }
540
541
542 String rTooltipExtra = "";
543 if (customFaction) {
544 rTooltipExtra = "\n\nFor the selected category, uses a broader set of weapons than is available to most factions.";
545 }
546 SimOptionCheckboxData loadouts = new SimOptionCheckboxData(RANDOMIZE_VARIANTS_ID, "Randomized loadouts",
547 "Opposing ships have randomized loadouts when this setting is enabled." + rTooltipExtra);
548 result.add(loadouts);
549
550 return result;
551 }
552
553 public boolean showGroupDeploymentWidget(SimCategoryData category) {
554 boolean custom = CUSTOM_CAT_ID.equals(category.id);
555 boolean other = OTHER_CAT_ID.equals(category.id);
556 boolean defaultCat = DEFAULT_CAT_ID.equals(category.id);
557 boolean civ = CIV_CAT_ID.equals(category.id);
558 boolean dev = DEV_CAT_ID.equals(category.id);
559 boolean customFaction = custom || civ || dev || defaultCat;
560
561 if (civ) return false;
562
563 return true;
564 }
565
566 public SimCategoryData getCustomCategory() {
567 SimCategoryData custom = new SimCategoryData();
568 custom.id = CUSTOM_CAT_ID;
569 custom.name = "Custom";
570 custom.custom = true;
571 custom.nonFactionCategory = true;
572 custom.nameColor = Misc.getBasePlayerColor();
573 custom.iconName = Global.getSettings().getSpriteName("simulator", "customPlayerCrest");
574 custom.data = null;
575 custom.faction = createCustomFaction();
577 return custom;
578 }
579
580
581 public List<SimCategoryData> getCategories() {
582 if (!loadedStuff) {
585 loadedStuff = true;
586 }
587
588 boolean fullUnlock = isSimFullyUnlocked() || isAllStandardStuffUnlocked();
589
590 List<SimCategoryData> result = new ArrayList<SimulatorPlugin.SimCategoryData>();
591
592 Set<String> civilian = new LinkedHashSet<String>();
593
594 Set<String> other = new LinkedHashSet<String>(unlocksData.variants);
595// if (other.contains("doom_Strike")) {
596// System.out.println("23dfefewf");
597// }
598// other.clear();
601 for (String roleId : getAllRoles()) {
602 Set<String> variants = player.getVariantsForRole(roleId);
603 if (variants == null) continue;
604 other.addAll(variants);
605 }
606 }
607
608
610 if (spec == null || spec.getCustom() == null) continue;
611
612 JSONObject json = spec.getCustom().optJSONObject("simulatorData");
613 if (json == null) continue;
614
615 boolean show = json.optBoolean("showInSimulator");
616 show |= isShowDevCategories() && json.optBoolean("showInSimulatorDevModeOnly");
617
618 show &= fullUnlock || unlocksData.factions.contains(spec.getId());
619
620 if (!show) continue;
621
622 boolean includeCiv = json.optBoolean("includeCivShipsWithFaction");
623
624 SimCategoryData data = new SimCategoryData();
625 data.id = spec.getId();
626 data.name = Misc.ucFirst(spec.getDisplayName());
627 data.nameColor = spec.getBaseUIColor();
628 data.iconName = spec.getCrest();
629 data.data = spec;
630 data.variants = getVariants(spec, includeCiv, false, false);
631 data.maxVariants = getVariants(spec, includeCiv, false, true).size();
632 data.faction = Global.getSettings().createBaseFaction(spec.getId());
633
634 if (!includeCiv) {
635 civilian.addAll(getVariants(spec, true, true, false));
636 }
637
638 if (data.variants == null || data.variants.isEmpty()) continue;
639
640 other.removeAll(data.variants);
641
642 result.add(data);
643 }
644
645 other.removeAll(civilian);
646
647 Collections.sort(result, new Comparator<SimCategoryData>() {
648 public int compare(SimCategoryData o1, SimCategoryData o2) {
649 return o1.name.compareTo(o2.name);
650 }
651 });
652
653 SimCategoryData custom = getCustomCategory();
654 result.add(0, custom);
655
656 SimCategoryData def = new SimCategoryData();
657 def.id = DEFAULT_CAT_ID;
658 def.name = "Default";
659 def.nonFactionCategory = true;
660 def.nameColor = Misc.getBasePlayerColor();
661 def.iconName = Global.getSettings().getSpriteName("simulator", "defaultPlayerCrest");
662 def.data = null;
663 def.faction = createCustomFaction();
665 new LinkedHashSet<String>(Global.getSettings().getSimOpponents()))));
666 result.add(0, def);
667
668 other.removeAll(def.variants);
669
670 if (!other.isEmpty()) {
671 SimCategoryData otherCat = new SimCategoryData();
672 otherCat.id = OTHER_CAT_ID;
673 otherCat.name = "Other";
674 otherCat.nonFactionCategory = true;
675 otherCat.nameColor = Misc.getBasePlayerColor();
676 otherCat.iconName = Global.getSettings().getSpriteName("simulator", "otherPlayerCrest");
677 otherCat.data = null;
678 otherCat.faction = createCustomFaction();
679 otherCat.variants = getVariantIDList(sortVariantList(getVariantList(other)));
680 otherCat.faction = createCustomFaction();
681 if (!otherCat.variants.isEmpty()) {
682 result.add(otherCat);
683 }
684 }
685
686 if (!civilian.isEmpty()) {
688 SimCategoryData civ = new SimCategoryData();
689 civ.id = CIV_CAT_ID;
690 civ.name = "Civilian ships";
691 civ.nonFactionCategory = true;
692 civ.nameColor = neutral.getBaseUIColor();
693 civ.iconName = neutral.getCrest();
694 civ.data = null;
695 civ.variants = getVariantIDList(sortVariantList(getVariantList(civilian)));
696 civ.faction = createCustomFaction();
697 if (!civ.variants.isEmpty()) {
698 result.add(civ);
699 }
700 }
701
702 if (isShowDevCategories()) {
703 SimCategoryData dev = new SimCategoryData();
704 dev.id = DEV_CAT_ID;
705 dev.name = "DevMode stuff";
706 dev.nonFactionCategory = true;
707 dev.nameColor = Misc.getBasePlayerColor();
708 dev.iconName = Global.getSettings().getSpriteName("simulator", "devModeVariantsIcon");
709 dev.data = null;
710 dev.faction = createCustomFaction();
712 new LinkedHashSet<String>(Global.getSettings().getSimOpponentsDev()))));
713 result.add(1, dev);
714 }
715
716 return result;
717 }
718
719 public List<String> getVariants(FactionSpecAPI spec, boolean withCiv, boolean onlyCiv, boolean forceFullUnlock) {
720 if (spec == null) return new ArrayList<String>();
721
723
724 boolean fullUnlock = isSimFullyUnlocked() || forceFullUnlock || isAllStandardStuffUnlocked();
725 //fullUnlock = true;
726
727 Set<String> seen = new LinkedHashSet<String>();
728 List<ShipVariantAPI> variantList = new ArrayList<ShipVariantAPI>();
729 for (String roleId : getAllRoles()) {
730 Set<String> variants = faction.getVariantsForRole(roleId);
731 if (variants == null) continue;
732 for (String variantId : variants) {
733 if (seen.contains(variantId)) continue;
734 seen.add(variantId);
735// if (variantId.equals("onslaught_Standard")) {
736// System.out.println("3f23few");
737// }
738 if (!fullUnlock && !unlocksData.variants.contains(variantId) &&
739 !defaultOpponents.contains(variantId)) {
740 continue;
741 }
742
744 if (!isAcceptableSimVariant(v, false)) continue;
745 if (!v.isStockVariant()) continue;
746
747// if (v == null || !v.isStockVariant()) continue;
748// //if (v.isFighter()) continue;
749//
750// //if (v.getHullSpec().getHints().contains(ShipTypeHints.HIDE_IN_CODEX)) continue;
751// if (v.getHullSpec().hasTag(Tags.NO_SIM) || v.hasTag(Tags.NO_SIM)) continue;
752// if (v.getHullSpec().hasTag(Tags.RESTRICTED)) continue;
753
754 boolean civ = v.isCivilian();
755 if (civ && !withCiv) continue;
756 if (!civ && onlyCiv) continue;
757
758 variantList.add(v);
759 }
760 }
761
762 sortVariantList(variantList);
763
764 return getVariantIDList(variantList);
765 }
766
767
768 public static List<ShipVariantAPI> getVariantList(Set<String> variants) {
769 List<ShipVariantAPI> variantList = new ArrayList<ShipVariantAPI>();
770 for (String id : variants) {
772 if (v == null || !v.isStockVariant()) continue;
773 variantList.add(v);
774 }
775 return variantList;
776 }
777 public static List<String> getVariantIDList(List<ShipVariantAPI> variantList) {
778 List<String> variants = new ArrayList<String>();
779 for (ShipVariantAPI v : variantList) {
780 variants.add(v.getHullVariantId());
781 }
782 return variants;
783 }
784
785 public static List<ShipVariantAPI> sortVariantList(List<ShipVariantAPI> variantList) {
786 Collections.sort(variantList, new Comparator<ShipVariantAPI>() {
787 public int compare(ShipVariantAPI v1, ShipVariantAPI v2) {
788 if (v1.isCivilian() && !v2.isCivilian()) return 1;
789 if (v2.isCivilian() && !v1.isCivilian()) return -1;
790
791 if (v1.getHullSize().ordinal() < v2.getHullSize().ordinal()) return 1;
792 if (v1.getHullSize().ordinal() > v2.getHullSize().ordinal()) return -1;
793
794 int diff = (int) (v1.getHullSpec().getSuppliesToRecover() - v2.getHullSpec().getSuppliesToRecover());
795 if (diff != 0) return (int) Math.signum(-diff);
796
797 return v1.getHullSpec().getHullName().compareTo(v2.getHullSpec().getHullName());
798 }
799 });
800 return variantList;
801 }
802
803
804 public static List<String> getAllRoles() {
805 List<String> result = new ArrayList<String>();
806 result.add(ShipRoles.COMBAT_SMALL);
807 result.add(ShipRoles.COMBAT_MEDIUM);
808 result.add(ShipRoles.COMBAT_LARGE);
809 result.add(ShipRoles.COMBAT_CAPITAL);
813
814 result.add(ShipRoles.CIV_RANDOM);
815
816 result.add(ShipRoles.PHASE_SMALL);
817 result.add(ShipRoles.PHASE_MEDIUM);
818 result.add(ShipRoles.PHASE_LARGE);
819
820 result.add(ShipRoles.PHASE_CAPITAL);
821
822 result.add(ShipRoles.CARRIER_SMALL);
823 result.add(ShipRoles.CARRIER_MEDIUM);
824 result.add(ShipRoles.CARRIER_LARGE);
825 result.add(ShipRoles.FREIGHTER_SMALL);
826 result.add(ShipRoles.FREIGHTER_MEDIUM);
827 result.add(ShipRoles.FREIGHTER_LARGE);
828 result.add(ShipRoles.TANKER_SMALL);
829 result.add(ShipRoles.TANKER_MEDIUM);
830 result.add(ShipRoles.TANKER_LARGE);
831 result.add(ShipRoles.PERSONNEL_SMALL);
832 result.add(ShipRoles.PERSONNEL_MEDIUM);
833 result.add(ShipRoles.PERSONNEL_LARGE);
834 result.add(ShipRoles.LINER_SMALL);
835 result.add(ShipRoles.LINER_MEDIUM);
836 result.add(ShipRoles.LINER_LARGE);
837 result.add(ShipRoles.TUG);
838 result.add(ShipRoles.CRIG);
839 result.add(ShipRoles.UTILITY);
840
841 return result;
842 }
843
844
845
846 public void applySettingsToFleetMembers(List<FleetMemberAPI> members,
847 SimCategoryData category, Map<String, String> settings) {
848
849 boolean custom = CUSTOM_CAT_ID.equals(category.id);
850 boolean defaultCat = DEFAULT_CAT_ID.equals(category.id);
851 boolean civ = CIV_CAT_ID.equals(category.id);
852 boolean dev = DEV_CAT_ID.equals(category.id);
853 boolean customFaction = custom || civ || dev || defaultCat;
854
855 FactionAPI faction = category.faction;
856
857 String officers = settings.get(OFFICERS_ID);
858 if (officers == null) officers = settings.get(OFFICERS_CUSTOM_ID);
859
860 if (officers != null) {
861 if (!officers.equals(OFFICERS_NONE) && !officers.equals(OFFICERS_CUSTOM_NONE)) {
862 CampaignFleetAPI fleetNonAuto = Global.getFactory().createEmptyFleet(faction, true);
863 for (FleetMemberAPI member : members) {
864 if (Misc.isAutomated(member)) continue;
865 fleetNonAuto.getFleetData().addFleetMember(member);
866 }
867 FleetParamsV3 params = new FleetParamsV3();
868 boolean all = false;
869 if (officers.equals(OFFICERS_ALL)) {
870 all = true;
871 params.officerNumberBonus = 1000;
872 params.officerLevelBonus = 10;
873 } else if (officers.equals(OFFICERS_CUSTOM_5)) {
874 all = true;
875 params.officerNumberBonus = 1000;
876 params.officerLevelBonus = 10;
877 params.officerLevelLimit = 5;
878 } else if (officers.equals(OFFICERS_CUSTOM_6)) {
879 all = true;
880 params.officerNumberBonus = 1000;
881 params.officerLevelBonus = 10;
882 params.commander = Global.getFactory().createPerson();
884 params.officerLevelLimit = 6;
885 }
886 FleetFactoryV3.addCommanderAndOfficersV2(fleetNonAuto, params, new Random(), true, all);
887 }
888 }
889
890
891 String cores = settings.get(AI_CORES_ID);
892 boolean derelict = false;
893 if (cores == null) {
894 cores = settings.get(AI_CORES_DERELICT_ID);
895 if (cores != null) derelict = true;
896 }
897 if (cores == null) cores = settings.get(AI_CORES_OMEGA_ID);
898 if (cores == null) cores = settings.get(AI_CORES_DEV_ID);
899
900 if (cores != null) {
901 if (!cores.equals(AI_CORES_NONE)) {
902 CampaignFleetAPI fleetAuto = Global.getFactory().createEmptyFleet(faction, true);
903 for (FleetMemberAPI member : members) {
904 if (!Misc.isAutomated(member)) continue;
905 fleetAuto.getFleetData().addFleetMember(member);
906 }
907 FleetParamsV3 params = new FleetParamsV3();
908 params.doNotIntegrateAICores = true;
909 boolean all = false;
910 boolean omega = false;
911 if (cores.equals(AI_CORES_SOME)) {
912 if (derelict) {
913 params.aiCores = OfficerQuality.AI_GAMMA;
914 } else {
915 params.aiCores = OfficerQuality.AI_MIXED;
916 }
917 } else if (cores.equals(AI_CORES_GAMMA)) {
918 params.officerNumberBonus = 1000;
919 params.aiCores = OfficerQuality.AI_GAMMA;
920 all = true;
921 } else if (cores.equals(AI_CORES_BETA)) {
922 params.officerNumberBonus = 1000;
923 params.aiCores = OfficerQuality.AI_BETA;
924 all = true;
925 } else if (cores.equals(AI_CORES_ALPHA)) {
926 params.officerNumberBonus = 1000;
927 params.aiCores = OfficerQuality.AI_ALPHA;
928 all = true;
929 } else if (cores.equals(AI_CORES_OMEGA)) {
930 params.officerNumberBonus = 1000;
931 params.aiCores = OfficerQuality.AI_OMEGA;
932 all = true;
933 omega = true;
934 }
935
936 // pass in derelictMode = false regardless of derelict or not, since if it's true
937 // RemnantOfficerGeneratorPlugin does some stuff potentially undesired here
938 // Setting it to AI_GAMMA above does the job, anyway
940 if (settings.containsKey(INTEGRATE_CORES_ID) && settings.get(INTEGRATE_CORES_ID).toLowerCase().equals("true")) {
941 if (!omega) {
942 genPlugin.setForceIntegrateCores(true);
943 }
944 }
945 genPlugin.setPutCoresOnCivShips(all);
946 genPlugin.setForceNoCommander(true);
947 genPlugin.addCommanderAndOfficers(fleetAuto, params, new Random());
948
950 }
951 }
952
953 String personality = null;
954 if (settings.containsKey(AGGRO_ID) || settings.containsKey(AGGRO_ID_CORES_ONLY)) {
955 String aggro = (String) settings.get(AGGRO_ID);
956 if (aggro == null) aggro = (String) settings.get(AGGRO_ID_CORES_ONLY);
957 if (aggro.equals(AGGRO_CAUTIOUS)) {
958 personality = Personalities.CAUTIOUS;
959 } else if (aggro.equals(AGGRO_STEADY)) {
960 personality = Personalities.STEADY;
961 } else if (aggro.equals(AGGRO_AGGRESSIVE)) {
962 personality = Personalities.AGGRESSIVE;
963 } else if (aggro.equals(AGGRO_RECKLESS)) {
964 personality = Personalities.RECKLESS;
965 }
966 }
967
968 if (personality != null) {
969 for (FleetMemberAPI member : members) {
970 if (Misc.isAutomated(member)) continue;
971
972 PersonAPI captain = member.getCaptain();
973 captain.setPersonality(personality);
974 member.setPersonalityOverride(personality);
975 }
976 }
977
978
979 CampaignFleetAPI fleet = Global.getFactory().createEmptyFleet(faction, true);
980 for (FleetMemberAPI member : members) {
981 fleet.getFleetData().addFleetMember(member);
982 }
983
984 if (settings.containsKey(RANDOMIZE_VARIANTS_ID) && settings.get(RANDOMIZE_VARIANTS_ID).toLowerCase().equals("true")) {
986 params.quality = 2f; // don't add d-mods
987
988 DefaultFleetInflater inflater = new DefaultFleetInflater(params);
989 inflater.inflate(fleet);
990 }
991
992
993 if (settings.containsKey(QUALITY_ID)) {
994 for (FleetMemberAPI member : members) {
995 if (member.getVariant().isStockVariant()) {
996 ShipVariantAPI copy = member.getVariant().clone();
998 member.setVariant(copy, false, false);
999 }
1000 }
1001
1002 String quality = (String) settings.get(QUALITY_ID);
1003 if (quality.equals(QUALITY_NO_DMODS)) {
1004 // nothing to do
1005 } else if (quality.equals(QUALITY_MAX_DMODS)) {
1006 for (FleetMemberAPI member : members) {
1007 DModManager.addDMods(member, true, 5, null);
1008 }
1009 } else if (quality.equals(QUALITY_SOME_DMODS)) {
1010 Random random = new Random();
1011 for (FleetMemberAPI member : members) {
1012 int num = 2 + random.nextInt(3);
1013 DModManager.addDMods(member, true, num, null);
1014 }
1015 } else if (quality.equals(QUALITY_SOME_SDMODS)) {
1016 Random random = new Random();
1017 CoreAutofitPlugin plugin = new CoreAutofitPlugin(null);
1018 for (FleetMemberAPI member : members) {
1019 int num = 1 + random.nextInt(2);
1020 plugin.addSMods(member, num, this);
1021 }
1022 } else if (quality.equals(QUALITY_MANY_SMODS)) {
1023 Random random = new Random();
1024 CoreAutofitPlugin plugin = new CoreAutofitPlugin(null);
1025 for (FleetMemberAPI member : members) {
1026 int num = 2 + random.nextInt(2);
1027 plugin.addSMods(member, num, this);
1028 }
1029 }
1030 }
1031
1032// for (FleetMemberAPI member : members) {
1033// member.setFlagship(false, false);
1034// }
1035// fleet.getFleetData().setFlagship(null);
1036
1037 // not strictly needed anymore after changing FleetFactoryV3.addCommanderAndOfficersV2()
1038 // to make a "fake" commander
1039 // but just in case, to make sure fleetwide skills don't apply
1040 //makeFleetCommanderNormalOfficer(members);
1042 }
1043
1044 @Override
1045 public void applySettingsToDeployed(List<DeployedFleetMemberAPI> deployed, Map<String, String> settings) {
1046 if (settings.containsKey(AGGRO_ID) || settings.containsKey(AGGRO_ID_CORES_ONLY)) {
1047 String aggro = (String) settings.get(AGGRO_ID);
1048 if (aggro == null) aggro = (String) settings.get(AGGRO_ID_CORES_ONLY);
1049 final String aggro2 = aggro;
1050 if (aggro.equals(AGGRO_DO_NOTHING)) {
1051 for (DeployedFleetMemberAPI member : deployed) {
1052 final ShipAPI ship = member.getShip();
1053 if (ship == null) continue;
1054
1055 if (ship.getOwner() == 0) continue;
1056
1057 ship.setShipAI(null);
1058 ship.setHoldFire(true);
1059 ship.getLocation().y -= 2000f;
1061 protected float elapsed = 0f;
1062 @Override
1063 public void advance(float amount, List<InputEventAPI> events) {
1064 elapsed += amount;
1065 if (ship.getTravelDrive() != null) {
1066 ship.getTravelDrive().deactivate();
1067 }
1068 if (elapsed > 0.1f) {
1069 ship.getVelocity().set(0, 0);
1070 elapsed = -10000000f;
1071 }
1072
1073 ship.giveCommand(ShipCommand.DECELERATE, null, 0);
1074
1075 if (ship.isHulk()) {
1077 }
1078 }
1079
1080 });
1081 }
1082 } else if (aggro.equals(AGGRO_DEFENSES) || aggro.equals(AGGRO_STATIONARY)) {
1083 final boolean defensesOnly = aggro.equals(AGGRO_DEFENSES);
1084 for (DeployedFleetMemberAPI member : deployed) {
1085 final ShipAPI ship = member.getShip();
1086 if (ship == null) continue;
1087
1088 if (ship.getOwner() == 0) continue;
1089
1090 ship.getLocation().y -= 2000f;
1092 protected float elapsed = 0f;
1093 @Override
1094 public void advance(float amount, List<InputEventAPI> events) {
1095 elapsed += amount;
1096 if (ship.getTravelDrive() != null && ship.getTravelDrive().isActive()) {
1097 ship.getTravelDrive().deactivate();
1098 }
1099 if (elapsed > 0.1f) {
1100 ship.getVelocity().set(0, 0);
1101 elapsed = -10000000f;
1102 }
1103
1104 List<ShipAPI> all = new ArrayList<>(ship.getChildModulesCopy());
1105 all.add(ship);
1106
1107 for (ShipAPI curr : all) {
1108 if (aggro2.equals(AGGRO_DEFENSES)) {
1109 curr.setHoldFire(true);
1110 }
1111 curr.giveCommand(ShipCommand.DECELERATE, null, 0);
1112
1113 curr.blockCommandForOneFrame(ShipCommand.ACCELERATE);
1114 curr.blockCommandForOneFrame(ShipCommand.ACCELERATE_BACKWARDS);
1115 curr.blockCommandForOneFrame(ShipCommand.STRAFE_LEFT);
1116 curr.blockCommandForOneFrame(ShipCommand.STRAFE_RIGHT);
1117
1118 if (defensesOnly) {
1119 curr.blockCommandForOneFrame(ShipCommand.FIRE);
1120 curr.blockCommandForOneFrame(ShipCommand.VENT_FLUX);
1121 curr.blockCommandForOneFrame(ShipCommand.PULL_BACK_FIGHTERS);
1122 curr.blockCommandForOneFrame(ShipCommand.TOGGLE_AUTOFIRE);
1123 curr.blockCommandForOneFrame(ShipCommand.HOLD_FIRE);
1124
1125 if (curr.getSystem() != null && curr.getSystem().getSpecAPI() != null) {
1126 ShipSystemSpecAPI spec = curr.getSystem().getSpecAPI();
1127 if (!spec.hasTag(Tags.SHIP_SYSTEM_DEFENSIVE) ||
1130 curr.blockCommandForOneFrame(ShipCommand.USE_SYSTEM);
1131 }
1132 }
1133 } else {
1134 if (curr.getSystem() != null && curr.getSystem().getSpecAPI() != null) {
1135 ShipSystemSpecAPI spec = curr.getSystem().getSpecAPI();
1136 if (spec.hasTag(Tags.SHIP_SYSTEM_MOVEMENT)) {
1137 curr.blockCommandForOneFrame(ShipCommand.USE_SYSTEM);
1138 }
1139 }
1140 }
1141 }
1142
1143 if (ship.isHulk()) {
1145 }
1146 }
1147
1148 });
1149 }
1150 }
1151 }
1152
1153 }
1154
1155
1158
1159
1160 FactionDoctrineAPI d = faction.getDoctrine();
1161 d.setAggression(2);
1162 d.setCarriers(2);
1163 d.setPhaseShips(1);
1164 d.setWarships(4);
1165
1167 d.setNumShips(3);
1168 d.setOfficerQuality(3);
1169 d.setShipSize(3);
1170
1172
1173 for (String id : merc.getKnownWeapons()) {
1174 faction.addKnownWeapon(id, false);
1175 }
1176 for (String id : merc.getKnownFighters()) {
1177 faction.addKnownFighter(id, false);
1178 }
1179 for (String id : merc.getKnownHullMods()) {
1180 faction.addKnownHullMod(id);
1181 }
1182
1183 faction.getPriorityWeapons().clear();
1184 faction.getPriorityFighters().clear();
1185
1186 faction.getHullFrequency().clear();
1187
1188 return faction;
1189 }
1190
1191
1192 public static void makeFleetCommanderNormalOfficer(List<FleetMemberAPI> members) {
1193 int maxLevel = (int) Global.getSettings().getFloat("officerMaxLevel");
1194 for (FleetMemberAPI member : members) {
1195 PersonAPI captain = member.getCaptain();
1196 if (!member.isFlagship() && !captain.isDefault()) {
1197 maxLevel = Math.max(maxLevel, captain.getStats().getLevel());
1198 }
1199 }
1200 for (FleetMemberAPI member : members) {
1201 if (member.isFlagship()) {
1202 PersonAPI captain = member.getCaptain();
1203 member.setFlagship(false, false);
1204 captain.getStats().setLevel(Math.min(captain.getStats().getLevel(), maxLevel));
1205 for (String skillId : Global.getSettings().getSkillIds()) {
1206 SkillSpecAPI skill = Global.getSettings().getSkillSpec(skillId);
1207 if (skill.isAdmiralSkill()) {
1208 captain.getStats().setSkillLevel(skillId, 0);
1209 }
1210 }
1211 break;
1212 }
1213 }
1214 }
1215
1216
1217 public List<String> generateSelection(SimCategoryData category, int deploymentPoints) {
1218 List<String> result = new ArrayList<String>();
1219 if (category.variants.isEmpty()) return result;
1220
1221 FactionAPI faction = Global.getSettings().createBaseFaction(category.faction.getId());
1222
1223 category.faction.getDoctrine().copyToDoctrine(faction.getDoctrine());
1224
1225 //faction.getDoctrine().setShipSize(5);
1226 //faction.getDoctrine().setCarriers(10);
1227
1228 faction.clearShipRoleCache();
1229 faction.getRestrictToVariants().clear();
1230 faction.getKnownShips().clear();
1231
1232 for (String variantId : category.variants) {
1234 if (v == null || !v.isStockVariant()) continue;
1235 faction.addKnownShip(v.getHullSpec().getHullId(), false);
1236 faction.getRestrictToVariants().add(variantId);
1237 }
1238
1239 FleetParamsV3 params = new FleetParamsV3(
1240 null,
1242 2f, // quality - null to determine from producer/source markets and doctrine
1244 deploymentPoints * 1f, // combatPts
1245 0f, // freighterPts
1246 0f * 0.5f, // tankerPts
1247 0f * 0.5f, // transportPts
1248 0f, // linerPts
1249 0f, // utilityPts
1250 1f // qualityMod
1251 );
1252 params.maxNumShips = 100;
1253 params.factionOverride = faction;
1254 params.ignoreMarketFleetSizeMult = true;
1255 params.withOfficers = false;
1256 params.modeOverride = ShipPickMode.PRIORITY_THEN_ALL;
1257
1259// CampaignFleetAPI fleet2 = FleetFactoryV3.createFleet(params);
1260// for (FleetMemberAPI member : fleet2.getFleetData().getMembersListCopy()) {
1261// fleet.getFleetData().addFleetMember(member);
1262// }
1263 pruneFleetDownToDP(fleet, deploymentPoints, new Random());
1264
1265 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
1266 ShipVariantAPI v = member.getVariant();
1267 if (v != null && v.isStockVariant()) { // && v.getHullSize() == HullSize.FRIGATE) {
1268 result.add(v.getHullVariantId());
1269 }
1270 }
1271
1272// result.add("onslaught_Standard");
1273// result.add("onslaught_Standard");
1274
1275 return result;
1276 }
1277
1278
1279
1280
1281
1282 public void fitFighterInSlot(int index, AvailableFighter fighter, ShipVariantAPI variant) {}
1283 public void clearFighterSlot(int index, ShipVariantAPI variant) {}
1284 public void fitWeaponInSlot(WeaponSlotAPI slot, AvailableWeapon weapon, ShipVariantAPI variant) {}
1285 public void clearWeaponSlot(WeaponSlotAPI slot, ShipVariantAPI variant) {}
1286 public List<AvailableWeapon> getAvailableWeapons() {return new ArrayList<AvailableWeapon>();}
1287 public List<AvailableFighter> getAvailableFighters() {return new ArrayList<AvailableFighter>();}
1288 public boolean isPriority(WeaponSpecAPI weapon) {return false;}
1289 public boolean isPriority(FighterWingSpecAPI wing) {return false;}
1290 public void syncUIWithVariant(ShipVariantAPI variant) {}
1291 public ShipAPI getShip() {return null;}
1292 public FactionAPI getFaction() {return null;}
1293 public boolean isAllowSlightRandomization() {return false;}
1294 public boolean isPlayerCampaignRefit() {return false;}
1295 public boolean canAddRemoveHullmodInPlayerCampaignRefit(String modId) {return true;}
1296
1297 public List<String> getAvailableHullmods() {
1298 List<String> ids = new ArrayList<String>();
1300 ids.add(mod.getId());
1301 }
1302 return ids;
1303 }
1304
1305
1306 public static void pruneFleetDownToDP(CampaignFleetAPI fleet, float targetDP, Random random) {
1307 float currDP = getDP(fleet);
1308 if (currDP > targetDP) {
1309 fleet.getFleetData().sort();
1310
1311 float fpRem = currDP - targetDP;
1312
1313 while (fpRem > 0) {
1314 List<FleetMemberAPI> copy = fleet.getFleetData().getMembersListCopy();
1316 for (FleetMemberAPI curr : copy) {
1317 counts.add(curr.getHullSpec().getHullSize());
1318 }
1320 for (FleetMemberAPI curr : copy) {
1321 float dp = curr.getDeploymentPointsCost();
1322 if (dp <= fpRem) {
1323 int count = counts.getCount(curr.getHullSpec().getHullSize());
1324 float mult = 1f;
1325 if (count <= 1) {
1326 mult = 0.0001f;
1327 } else {
1328 mult = count;
1329 }
1330 picker.add(curr, dp * mult);
1331 }
1332 }
1333 FleetMemberAPI pick = picker.pick();
1334 if (pick == null) break;
1335
1336 float dp = pick.getDeploymentPointsCost();
1337 fpRem -= dp;
1338 fleet.getFleetData().removeFleetMember(pick);
1339 }
1340 }
1341 }
1342
1343 public static float getDP(CampaignFleetAPI fleet) {
1344 float total = 0f;
1345 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
1346 total += member.getDeploymentPointsCost();
1347 }
1348 return total;
1349 }
1350
1351 public void reportPlayerBattleOccurred(CampaignFleetAPI primaryWinner, BattleAPI battle) {
1352 if (!loadedStuff) {
1355 loadedStuff = true;
1356 }
1357
1358 //CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1359
1360// unlocksData.factions.clear();
1361// unlocksData.variants.clear();
1362 //unlocksData.variants.addAll(Global.getSettings().getSimOpponents());
1363
1364 LinkedHashSet<String> addedFactions = new LinkedHashSet<String>();
1365 LinkedHashSet<String> addedVariants = new LinkedHashSet<String>();
1366
1367 for (CampaignFleetAPI fleet : battle.getNonPlayerSideSnapshot()) {
1368 if (fleet.getFaction() == null ||
1369 fleet.getFaction().getFactionSpec() == null ||
1370 fleet.getFaction().getFactionSpec().getCustom() == null) continue;
1371 JSONObject json = fleet.getFaction().getFactionSpec().getCustom().optJSONObject("simulatorData");
1372 if (json == null) continue;
1373 boolean show = json.optBoolean("showInSimulator");
1374 if (!show) continue;
1375
1376 List<FleetMemberAPI> members = Misc.getSnapshotMembersLost(fleet);
1377 String fid = findBestMatchingFaction(fleet.getFaction().getId(), members);
1378
1379 if (!unlocksData.factions.contains(fid)) {
1380 unlocksData.factions.add(fid);
1381 addedFactions.add(fid);
1382 }
1383
1384 for (FleetMemberAPI member : members) {
1385// if ("LGS Dorus".equals(member.getShipName())) {
1386// System.out.println("ewfwefewfwefe");
1387// }
1388 String vid = getStockVariantId(member);
1389
1390// if (vid != null && vid.contains("executor")) {
1391// System.out.println("fwfewfe");
1392// }
1393 if (vid != null) {
1394 if (!unlocksData.variants.contains(vid)) {
1395 unlocksData.variants.add(vid);
1396 addedVariants.add(vid);
1397 }
1398 }
1399 }
1400 }
1401
1402 if (!addedVariants.isEmpty()) {
1403 addedVariants = new LinkedHashSet<String>(getVariantIDList(sortVariantList(getVariantList(
1404 new LinkedHashSet<String>(addedVariants)))));
1405 }
1406
1407 if (!addedFactions.isEmpty() || !addedVariants.isEmpty()) {
1409
1410 new SimUpdateIntel(addedFactions, addedVariants);
1411 }
1412 }
1413
1414 public boolean isAcceptableSimVariant(ShipVariantAPI v, boolean forLearning) {
1415 boolean allowAll = isSimFullyUnlocked() && !forLearning;
1416 if (v == null) return false;
1417 if ((v.getHullSpec().hasTag(Tags.NO_SIM) || v.hasTag(Tags.NO_SIM)) && !allowAll) return false;
1418 if (v.getHullSpec().hasTag(Tags.RESTRICTED) && !allowAll) return false;
1419 if (v.getHullSpec().getHints().contains(ShipTypeHints.STATION)) return false;
1420 return true;
1421 }
1422
1423 public String getStockVariantId(FleetMemberAPI member) {
1424 ShipVariantAPI v = member.getVariant();
1425 if (!isAcceptableSimVariant(v, true)) return null;
1426
1427 String vid = null;
1428 if (v.isStockVariant()) {
1429 vid = v.getHullVariantId();
1430 }
1431 if (vid == null && v.getOriginalVariant() != null) {
1432 vid = v.getOriginalVariant();
1433 }
1434 return vid;
1435 }
1436
1437 public String findBestMatchingFaction(String fleetFactionId, List<FleetMemberAPI> members) {
1438
1439 List<String> roles = getAllRoles();
1440
1441 FactionAPI best = null;
1442 float bestScore = 0f;
1443
1445 if (spec == null || spec.getCustom() == null) continue;
1446
1447 JSONObject json = spec.getCustom().optJSONObject("simulatorData");
1448 if (json == null) continue;
1449
1450 boolean show = json.optBoolean("showInSimulator");
1451 if (!show) continue;
1452
1453 FactionAPI faction = Global.getSector().getFaction(spec.getId());
1454
1455 Set<String> allVariants = new LinkedHashSet<String>();
1456 for (String roleId : roles) {
1457 allVariants.addAll(faction.getVariantsForRole(roleId));
1458 }
1459
1460 float matches = 0f;
1461 float total = 0f;
1462 for (FleetMemberAPI member : members) {
1463 String vid = getStockVariantId(member);
1464 if (vid == null) continue;
1465
1466 if (allVariants.contains(vid)) {
1467 matches++;
1468 }
1469 total++;
1470 }
1471 total = Math.max(total, 1f);
1472 float score = matches / total;
1473 if (faction.getId().equals(fleetFactionId)) {
1474 score *= 1.1f;
1475 }
1476 if (score > bestScore) {
1477 bestScore = score;
1478 best = faction;
1479 }
1480 }
1481
1482 if (best == null || bestScore <= 0) return fleetFactionId;
1483 return best.getId();
1484 }
1485
1486 public void pruneAICoresToAvailable(List<FleetMemberAPI> members) {
1487 if (!isRequireAICoresInCargo()) return;
1488
1490
1492 for (FleetMemberAPI member : members) {
1493 String coreId = getCoreId(member);
1494 if (coreId == null) continue;
1495
1496 current.add(coreId, 1);
1497 }
1498
1500 remove.putAll(current);
1501 for (String id : availableCores.keySet()) {
1502 remove.sub(id, availableCores.getCount(id));
1503 }
1504
1505 if (remove.isEmpty()) return;
1506
1508 for (FleetMemberAPI member : members) {
1509 String coreId = getCoreId(member);
1510 if (coreId == null) continue;
1511
1512 if (remove.getCount(coreId) > 0) {
1513 picker.add(member, member.getDeploymentPointsCost());
1514 }
1515 }
1516
1517 while (!remove.isEmpty() && !picker.isEmpty()) {
1518 FleetMemberAPI member = picker.pickAndRemove();
1519
1520 String coreId = getCoreId(member);
1521 if (remove.getCount(coreId) > 0) {
1522 remove.sub(coreId, 1);
1524 }
1525 }
1526 }
1527
1528 public String getCoreId(FleetMemberAPI member) {
1529 if (member == null) return null;
1530 PersonAPI captain = member.getCaptain();
1531 if (captain == null || captain.isDefault() || !captain.isAICore()) return null;;
1532 return captain.getAICoreId();
1533 }
1534
1537 CountingMap<String> deployedCores = getDeployedAICores();
1538 CountingMap<String> availableCores = new CountingMap<String>();
1539
1540 availableCores.putAll(cargoCores);
1541 for (String id : deployedCores.keySet()) {
1542 availableCores.sub(id, deployedCores.getCount(id));
1543 }
1544 return availableCores;
1545 }
1546
1548 // only checking enemy side: in campaign, these settings don't affect own side
1551 if (member.getShip() == null) continue;
1552 PersonAPI captain = member.getShip().getCaptain();
1553 if (captain == null || captain.isDefault() || !captain.isAICore()) continue;
1554 String coreId = captain.getAICoreId();
1555 if (coreId == null) continue;
1556
1557 map.add(coreId, 1);
1558 }
1559 return map;
1560 }
1561
1564
1566
1567 CargoAPI cargo = player.getCargo();
1568
1570 map.add(Commodities.BETA_CORE, (int)Math.round(cargo.getCommodityQuantity(Commodities.BETA_CORE)));
1572
1573
1575 if (cargo != null) {
1577 map.add(Commodities.BETA_CORE, (int)Math.round(cargo.getCommodityQuantity(Commodities.BETA_CORE)));
1579 }
1580
1581 return map;
1582 }
1583
1584 public void appendToTooltip(TooltipMakerAPI info, float initPad, float width, AdvancedSimOption option, Object extra) {
1586 if (option.getId().equals(AI_CORES_ID) && extra != null) {
1587 if (extra.equals(AI_CORES_SOME) ||
1588 extra.equals(AI_CORES_GAMMA) ||
1589 extra.equals(AI_CORES_BETA) ||
1590 extra.equals(AI_CORES_ALPHA)) {
1592 CargoAPI cargo = Global.getFactory().createCargo(true);
1593 for (String id : cores.keySet()) {
1594 cargo.addCommodity(id, cores.getCount(id));
1595 }
1596
1597 float opad = 10f;
1598 info.addSectionHeading("AI cores in cargo & storage", Alignment.MID, initPad);
1599 if (cargo.isEmpty()) {
1600 info.addPara(BaseIntelPlugin.INDENT + "None", opad);
1601 } else {
1602 info.showCargo(cargo, 10, true, opad);
1603 }
1604
1605 cores = getDeployedAICores();
1606 cargo = Global.getFactory().createCargo(true);
1607 for (String id : cores.keySet()) {
1608 cargo.addCommodity(id, cores.getCount(id));
1609 }
1610
1611 info.addSectionHeading("Cores already in use in simulation", Alignment.MID, initPad);
1612 if (cargo.isEmpty()) {
1613 info.addPara(BaseIntelPlugin.INDENT + "None", opad);
1614 } else {
1615 info.showCargo(cargo, 10, true, opad);
1616 }
1617
1618
1620 cargo = Global.getFactory().createCargo(true);
1621 for (String id : cores.keySet()) {
1622 cargo.addCommodity(id, cores.getCount(id));
1623 }
1624
1625 info.addSectionHeading("Cores available to deploy", Alignment.MID, initPad);
1626 if (cargo.isEmpty()) {
1627 info.addPara(BaseIntelPlugin.INDENT + "None", opad);
1628 } else {
1629 info.showCargo(cargo, 10, true, opad);
1630 }
1631 }
1632 }
1633 }
1634 }
1635
1636 @Override
1638 return null;
1639 }
1640
1641 @Override
1643 return null;
1644 }
1645
1646}
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
static SettingsAPI getSettings()
Definition Global.java:57
static FactoryAPI getFactory()
Definition Global.java:41
static CombatEngineAPI getCombatEngine()
Definition Global.java:69
static SectorAPI getSector()
Definition Global.java:65
List< String > generateSelection(SimCategoryData category, int deploymentPoints)
static void pruneFleetDownToDP(CampaignFleetAPI fleet, float targetDP, Random random)
void applySettingsToFleetMembers(List< FleetMemberAPI > members, SimCategoryData category, Map< String, String > settings)
void clearFighterSlot(int index, ShipVariantAPI variant)
void fitFighterInSlot(int index, AvailableFighter fighter, ShipVariantAPI variant)
List< AdvancedSimOption > getSimOptions(SimCategoryData category)
void appendToTooltip(TooltipMakerAPI info, float initPad, float width, AdvancedSimOption option, Object extra)
boolean showGroupDeploymentWidget(SimCategoryData category)
static List< String > getVariantIDList(List< ShipVariantAPI > variantList)
void pruneAICoresToAvailable(List< FleetMemberAPI > members)
void clearWeaponSlot(WeaponSlotAPI slot, ShipVariantAPI variant)
void reportPlayerBattleOccurred(CampaignFleetAPI primaryWinner, BattleAPI battle)
static List< ShipVariantAPI > getVariantList(Set< String > variants)
static List< ShipVariantAPI > sortVariantList(List< ShipVariantAPI > variantList)
static void makeFleetCommanderNormalOfficer(List< FleetMemberAPI > members)
List< String > getVariants(FactionSpecAPI spec, boolean withCiv, boolean onlyCiv, boolean forceFullUnlock)
void applySettingsToDeployed(List< DeployedFleetMemberAPI > deployed, Map< String, String > settings)
void fitWeaponInSlot(WeaponSlotAPI slot, AvailableWeapon weapon, ShipVariantAPI variant)
boolean isAcceptableSimVariant(ShipVariantAPI v, boolean forLearning)
String findBestMatchingFaction(String fleetFactionId, List< FleetMemberAPI > members)
static void addDMods(FleetMemberData data, boolean own, CampaignFleetAPI recoverer, Random random)
static void addCommanderAndOfficersV2(CampaignFleetAPI fleet, FleetParamsV3 params, Random random)
static CampaignFleetAPI createFleet(FleetParamsV3 params)
static final String SHIP_SYSTEM_DEFENSIVE
Definition Tags.java:498
static final String SHIP_SYSTEM_OFFENSIVE
Definition Tags.java:499
void addCommanderAndOfficers(CampaignFleetAPI fleet, FleetParamsV3 params, Random random)
void addSMods(FleetMemberAPI member, int numSmods, AutofitPluginDelegate delegate)
void add(K key, int quantity)
static List< FleetMemberAPI > getSnapshotMembersLost(CampaignFleetAPI fleet)
Definition Misc.java:748
static String ucFirst(String str)
Definition Misc.java:559
static CargoAPI getStorageCargo(MarketAPI market)
Definition Misc.java:4307
static boolean isAutomated(MutableShipStatsAPI stats)
Definition Misc.java:5491
static Color getBasePlayerColor()
Definition Misc.java:833
CargoAPI createCargo(boolean unlimitedStacks)
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
List< String > getSimOpponentsDev()
List< String > getSimOpponents()
List< FactionSpecAPI > getAllFactionSpecs()
String getSpriteName(String category, String id)
FactionSpecAPI getFactionSpec(String id)
ShipVariantAPI getVariant(String variantId)
SkillSpecAPI getSkillSpec(String skillId)
List< HullModSpecAPI > getAllHullModSpecs()
boolean getBoolean(String key)
boolean fileExistsInCommon(String filename)
void writeJSONToCommon(String filename, JSONObject json, boolean onlyIfChanged)
FactionAPI createBaseFaction(String factionId)
PersonalityAPI getPersonaltySpec(String id)
JSONObject readJSONFromCommon(String filename, boolean putInWriteCache)
List< CampaignFleetAPI > getNonPlayerSideSnapshot()
float getQuantity(CargoAPI.CargoItemType type, Object data)
void addCommodity(String commodityId, float quantity)
void addKnownShip(String hullId, boolean setTimestamp)
void addKnownFighter(String wingId, boolean setTimestamp)
Set< String > getVariantsForRole(String roleId)
void addKnownWeapon(String weaponId, boolean setTimestamp)
LinkedHashSet< String > getRestrictToVariants()
Map< String, Float > getHullFrequency()
void copyToDoctrine(FactionDoctrineAPI other)
void setAutofitRandomizeProbability(float autofitRandomizeProbability)
void addFleetMember(FleetMemberAPI member)
void removeFleetMember(FleetMemberAPI member)
List< FleetMemberAPI > getMembersListCopy()
FactionAPI getFaction(String factionId)
MutableCharacterStatsAPI getStats()
void setPersonality(String personality)
CombatFleetManagerAPI getFleetManager(FleetSide side)
void removePlugin(EveryFrameCombatPlugin plugin)
void addPlugin(EveryFrameCombatPlugin plugin)
List< DeployedFleetMemberAPI > getDeployedCopyDFM()
List< ShipAPI > getChildModulesCopy()
void setHoldFire(boolean holdFire)
void setShipAI(ShipAIPlugin ai)
void giveCommand(ShipCommand command, Object param, int groupNumber)
EnumSet< ShipTypeHints > getHints()
void setSource(VariantSource source)
void setCaptain(PersonAPI commander)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)
LabelAPI addSectionHeading(String str, Alignment align, float pad)
void showCargo(CargoAPI cargo, int max, boolean sort, float pad)