Starsector API
Loading...
Searching...
No Matches
PlayerFleetGenPluginImpl.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.procgen;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.LinkedHashSet;
6import java.util.List;
7import java.util.Map;
8import java.util.Random;
9import java.util.Set;
10
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.campaign.BaseCustomProductionPickerDelegateImpl;
13import com.fs.starfarer.api.campaign.CampaignFleetAPI;
14import com.fs.starfarer.api.campaign.CargoAPI;
15import com.fs.starfarer.api.campaign.FactionAPI;
16import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
17import com.fs.starfarer.api.campaign.FactionProductionAPI;
18import com.fs.starfarer.api.campaign.FactionProductionAPI.ItemInProductionAPI;
19import com.fs.starfarer.api.campaign.FactionProductionAPI.ProductionItemType;
20import com.fs.starfarer.api.campaign.FleetInflater;
21import com.fs.starfarer.api.campaign.InteractionDialogAPI;
22import com.fs.starfarer.api.campaign.InteractionDialogPlugin;
23import com.fs.starfarer.api.campaign.OptionPanelAPI;
24import com.fs.starfarer.api.campaign.TextPanelAPI;
25import com.fs.starfarer.api.campaign.VisualPanelAPI;
26import com.fs.starfarer.api.campaign.econ.MarketAPI;
27import com.fs.starfarer.api.campaign.rules.MemoryAPI;
28import com.fs.starfarer.api.characters.MutableCharacterStatsAPI.SkillLevelAPI;
29import com.fs.starfarer.api.characters.OfficerDataAPI;
30import com.fs.starfarer.api.characters.PersonAPI;
31import com.fs.starfarer.api.combat.EngagementResultAPI;
32import com.fs.starfarer.api.combat.ShipAPI.HullSize;
33import com.fs.starfarer.api.combat.ShipHullSpecAPI;
34import com.fs.starfarer.api.combat.ShipHullSpecAPI.ShipTypeHints;
35import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
36import com.fs.starfarer.api.fleet.FleetMemberAPI;
37import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflaterParams;
38import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
39import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3;
40import com.fs.starfarer.api.impl.campaign.ids.Factions;
41import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
42import com.fs.starfarer.api.impl.campaign.ids.Tags;
43import com.fs.starfarer.api.loading.FighterWingSpecAPI;
44import com.fs.starfarer.api.loading.HullModSpecAPI;
45import com.fs.starfarer.api.loading.WeaponSpecAPI;
46import com.fs.starfarer.api.plugins.OfficerLevelupPlugin;
47import com.fs.starfarer.api.util.Misc;
48
49public class PlayerFleetGenPluginImpl implements InteractionDialogPlugin {
50
51 protected static enum FleetQuality {
52 MAX_DMODS,
53 NO_DMODS,
54 ONE_SMOD,
55 TWO_SMODS,
56 THREE_SMODS,
57 }
58
59 protected static enum OptionId {
60 INIT,
61 SELECT_SHIPS,
62 ADD_UNSELECTED_OFFICERS,
63 OFFICER_LEVEL_5,
64 OFFICER_LEVEL_6,
65 OFFICER_LEVEL_7,
66 OFFICERS_GO_BACK,
67
68 QUALITY_MAX_DMODS,
69 QUALITY_NO_DMODS,
70 QUALITY_1_SMODS,
71 QUALITY_2_SMODS,
72 QUALITY_2_SMODS_OMEGA,
73 QUALITY_3_SMODS,
74 QUALITY_3_SMODS_OMEGA,
75
76// SMODS_OFFICER_SHIPS_ONLY,
77// SMODS_ALL_SHIPS,
78// NORMAL_LEVEL_OFFICERS,
79// HIGH_LEVEL_OFFICERS,
80
81 ADD_OFFICERS,
82 ADD_OFFICERS_NO_SKILLS,
83 NO_OFFICERS,
84
85 CREATE_REPLACE,
86 CREATE_ADD,
87
88 LEAVE,
89 }
90
91
92 public static class FleetGenData {
93 public FactionProductionAPI prod;
94 public FleetQuality quality;
95 public boolean smodsOnAllShips = true;
96 public boolean allowOmega = false;
97 //public boolean eliteOfficers = false;
98 public boolean addOfficers = false;
99 public boolean keepOfficerPointsFree = false;
100 public boolean append = false;
101
102
103 public FleetGenData() {
104 prod = Global.getSector().getPlayerFaction().getProduction().clone();
105 prod.clear();
106 }
107 }
108
109
110 protected InteractionDialogAPI dialog;
111 protected TextPanelAPI textPanel;
112 protected OptionPanelAPI options;
113 protected VisualPanelAPI visual;
114
115 protected FleetGenData data = new FleetGenData();
116 protected CampaignFleetAPI playerFleet;
117
118 protected Set<String> ships = new LinkedHashSet<String>();
119 protected Set<String> fighters = new LinkedHashSet<String>();
120 protected Set<String> weapons = new LinkedHashSet<String>();
121 protected Set<String> unrestrictedFighters = new LinkedHashSet<String>();
122 protected Set<String> unrestrictedWeapons = new LinkedHashSet<String>();
123 protected Set<String> hullmods = new LinkedHashSet<String>();
124
125 protected static final Color HIGHLIGHT_COLOR = Global.getSettings().getColor("buttonShortcut");
126
127 public void init(InteractionDialogAPI dialog) {
128 this.dialog = dialog;
129
130
131 textPanel = dialog.getTextPanel();
132 options = dialog.getOptionPanel();
133 visual = dialog.getVisualPanel();
134
135 playerFleet = Global.getSector().getPlayerFleet();
136
137 visual.setVisualFade(0.25f, 0.25f);
138
140
141 dialog.setOptionOnEscape("Leave", OptionId.LEAVE);
142 optionSelected(null, OptionId.INIT);
143 }
144
145 public Map<String, MemoryAPI> getMemoryMap() {
146 return null;
147 }
148
149 public void backFromEngagement(EngagementResultAPI result) {
150 // no combat here, so this won't get called
151 }
152
153
154 public void optionSelected(String text, Object optionData) {
155 if (optionData == null) return;
156
157 OptionId option = (OptionId) optionData;
158
159 if (text != null) {
160 //textPanel.addParagraph(text, Global.getSettings().getColor("buttonText"));
161 dialog.addOptionSelectedText(option);
162 //textPanel.addParagraph("");
163 }
164
165 switch (option) {
166 case INIT:
168 break;
169 case SELECT_SHIPS:
171 break;
172 case ADD_UNSELECTED_OFFICERS:
174 break;
175 case OFFICERS_GO_BACK:
177 break;
178 case OFFICER_LEVEL_5:
180 break;
181 case OFFICER_LEVEL_6:
183 break;
184 case OFFICER_LEVEL_7:
186 break;
187 case QUALITY_MAX_DMODS:
188 data.quality = FleetQuality.MAX_DMODS;
190 break;
191 case QUALITY_NO_DMODS:
192 data.quality = FleetQuality.NO_DMODS;
194 break;
195 case QUALITY_1_SMODS:
196 data.quality = FleetQuality.ONE_SMOD;
198 break;
199 case QUALITY_2_SMODS:
200 data.quality = FleetQuality.TWO_SMODS;
202 break;
203 case QUALITY_2_SMODS_OMEGA:
204 data.quality = FleetQuality.TWO_SMODS;
205 data.allowOmega = true;
207 break;
208 case QUALITY_3_SMODS:
209 data.quality = FleetQuality.THREE_SMODS;
211 break;
212 case QUALITY_3_SMODS_OMEGA:
213 data.quality = FleetQuality.THREE_SMODS;
214 data.allowOmega = true;
216 break;
217 case NO_OFFICERS:
218 data.addOfficers = false;
220 break;
221 case ADD_OFFICERS:
222 data.addOfficers = true;
224 break;
225 case ADD_OFFICERS_NO_SKILLS:
226 data.addOfficers = true;
227 data.keepOfficerPointsFree = true;
229 break;
230// case NORMAL_LEVEL_OFFICERS:
231// data.eliteOfficers = false;
232// selectAppendOrReplace();
233// break;
234// case HIGH_LEVEL_OFFICERS:
235// data.eliteOfficers = true;
236// selectAppendOrReplace();
237// break;
238 case CREATE_ADD:
239 data.append = true;
240 createFleet();
241 dialog.dismiss();
242 break;
243 case CREATE_REPLACE:
244 data.append = false;
245 createFleet();
246 dialog.dismiss();
247 break;
248 case LEAVE:
249 dialog.dismiss();
250 break;
251 default:
252 break;
253 }
254 }
255
256 protected MarketAPI getNearestMarket(boolean playerOnly) {
257 MarketAPI nearest = null;
258 float minDist = Float.MAX_VALUE;
259 CampaignFleetAPI pf = Global.getSector().getPlayerFleet();
260 for (MarketAPI curr : Global.getSector().getEconomy().getMarketsCopy()) {
261 if (curr.isHidden()) continue;
262 if (playerOnly && !curr.isPlayerOwned()) continue;
263
264 float dist = Misc.getDistanceLY(pf, curr.getPrimaryEntity());
265 boolean nearer = dist < minDist;
266 if (dist == minDist && dist == 0 && nearest != null) {
267 float d1 = Misc.getDistance(pf, curr.getPrimaryEntity());
268 float d2 = Misc.getDistance(pf, nearest.getPrimaryEntity());
269 nearer = d1 < d2;
270 }
271 if (nearer) {
272 nearest = curr;
273 minDist = dist;
274 }
275 }
276 return nearest;
277 }
278
279 protected void print(String str) {
280 textPanel.appendToLastParagraph("\n" + str);
281 System.out.println(str);
282 }
283
284 protected void selectShipsAndWeapons() {
285 textPanel.addPara("--- QUICK PLAYER FLEET CREATOR ---");
286 textPanel.addPara("Ship variants will be randomly picked from those available for a given hull.");
287 textPanel.addPara("Selected weapons and fighters will be added to your cargo.");
288
289 options.clearOptions();
290 options.addOption("Select ships and weapons", OptionId.SELECT_SHIPS);
291 options.addOption("Add officers with unselected skills", OptionId.ADD_UNSELECTED_OFFICERS);
292 options.addOption("Leave", OptionId.LEAVE, null);
293 }
294
295 protected void showOfficerSelector() {
296 textPanel.addPara("Select option to instantly add an officer of that level with all unspent skills. The officer "
297 + "level will be 1 higher than selected and they will not have an initial skill.");
298 options.clearOptions();
299 options.addOption("Level 5", OptionId.OFFICER_LEVEL_5);
300 options.addOption("Level 6", OptionId.OFFICER_LEVEL_6);
301 options.addOption("Level 7", OptionId.OFFICER_LEVEL_7);
302 options.addOption("Go back", OptionId.OFFICERS_GO_BACK);
303 }
304
305 protected void selectQuality() {
306 textPanel.addPara("Select ship quality.");
307 options.clearOptions();
308 options.addOption("Maximum number of d-mods", OptionId.QUALITY_MAX_DMODS);
309 options.addOption("No d-mods", OptionId.QUALITY_NO_DMODS);
310 options.addOption("Average of 1 s-mod", OptionId.QUALITY_1_SMODS);
311 options.addOption("Average of 2 s-mods", OptionId.QUALITY_2_SMODS);
312 options.addOption("Average of 2 s-mods; allow some Omega weapons to be mounted", OptionId.QUALITY_2_SMODS_OMEGA);
313 options.addOption("Average of 3 s-mods", OptionId.QUALITY_3_SMODS);
314 options.addOption("Average of 3 s-mods; allow some Omega weapons to be mounted", OptionId.QUALITY_3_SMODS_OMEGA);
315 options.addOption("Leave", OptionId.LEAVE, null);
316 }
317
318 protected void selectOfficerLevel() {
319 textPanel.addPara("The total number of officers and their level and elite skills will be based on your character's skills.");
320 options.clearOptions();
321 options.addOption("Add officers (number / level / elite skills based on your character's skills)", OptionId.ADD_OFFICERS);
322 //options.addOption("Add officers, but do not spend their skill points", OptionId.ADD_OFFICERS_NO_SKILLS);
323 options.addOption("Do not add officers", OptionId.NO_OFFICERS);
324 options.addOption("Leave", OptionId.LEAVE, null);
325 }
326
327 protected void selectAppendOrReplace() {
328 textPanel.addPara("Select fleet creation mode.");
329 options.clearOptions();
330 options.addOption("Replace current fleet with new ships", OptionId.CREATE_REPLACE);
331 options.addOption("Add new ships to current fleet", OptionId.CREATE_ADD);
332 options.addOption("Leave", OptionId.LEAVE, null);
333 }
334
335 protected OptionId lastOptionMousedOver = null;
336 public void optionMousedOver(String optionText, Object optionData) {
337
338 }
339
340 public void advance(float amount) {
341
342 }
343
344 public Object getContext() {
345 return null;
346 }
347
348 public void showBlueprintPicker() {
349 dialog.showCustomProductionPicker(new BaseCustomProductionPickerDelegateImpl() {
350 @Override
351 public Set<String> getAvailableFighters() {
352 return fighters;
353 }
354 @Override
355 public Set<String> getAvailableShipHulls() {
356 return ships;
357 }
358 @Override
359 public Set<String> getAvailableWeapons() {
360 return weapons;
361 }
362 @Override
363 public float getCostMult() {
364 return 0.001f;
365 }
366 @Override
367 public float getMaximumValue() {
368 return 1000000;
369 }
370 public boolean withQuantityLimits() {
371 return false;
372 }
373 @Override
374 public void notifyProductionSelected(FactionProductionAPI production) {
375 //convertProdToCargo(production);
376 data.prod = production;
378 }
379 });
380 }
381
382 protected void createFleet() {
383
384 FactionProductionAPI prod = data.prod;
385 CargoAPI cargo = Global.getFactory().createCargo(true);
386
387
388 Random random = Misc.random;
389
390 float quality = 2f;
391 if (data.quality == FleetQuality.MAX_DMODS) {
392 quality = -2f;
393 }
394
395 CampaignFleetAPI ships = Global.getFactory().createEmptyFleet(Factions.PLAYER, "temp", true);
396 ships.setCommander(Global.getSector().getPlayerPerson());
397 DefaultFleetInflaterParams p = new DefaultFleetInflaterParams();
398 p.quality = quality;
399 p.mode = ShipPickMode.PRIORITY_THEN_ALL;
400 p.persistent = false;
401 p.seed = random.nextLong();
402 p.timestamp = null;
403 p.rProb = 0f;
404 p.allWeapons = true;
405
406 if (data.quality == FleetQuality.ONE_SMOD) {
407 p.averageSMods = 1;
408 } else if (data.quality == FleetQuality.TWO_SMODS) {
409 p.averageSMods = 2;
410 } else if (data.quality == FleetQuality.THREE_SMODS) {
411 p.averageSMods = 3;
412 }
413
414 FleetInflater inflater = Misc.getInflater(ships, p);
415 ships.setInflater(inflater);
416
417 for (ItemInProductionAPI pick : prod.getCurrent()) {
418 int count = pick.getQuantity();
419
420 if (pick.getType() == ProductionItemType.SHIP) {
421 List<String> variants = Global.getSettings().getHullIdToVariantListMap().get(pick.getSpecId());
422 if (variants.isEmpty()) {
423 variants.add(pick.getSpecId() + "_Hull");
424 }
425
426 for (int i = 0; i < count; i++) {
427 int index = random.nextInt(variants.size());
428 ships.getFleetData().addFleetMember(variants.get(index));
429 }
430 } else if (pick.getType() == ProductionItemType.FIGHTER) {
431 cargo.addFighters(pick.getSpecId(), count);
432 } else if (pick.getType() == ProductionItemType.WEAPON) {
433 cargo.addWeapons(pick.getSpecId(), count);
434 }
435 prod.removeItem(pick.getType(), pick.getSpecId(), count);
436 }
437
438 FactionAPI pf = Global.getSector().getPlayerFaction();
439 List<String> addedWeapons = new ArrayList<String>();
440 List<String> addedFighters = new ArrayList<String>();
441 List<String> addedHullmods = new ArrayList<String>();
442
443 if (data.allowOmega) {
444 for (String id : weapons) {
445 if (unrestrictedWeapons.contains(id)) continue;
446 WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(id);
447 if (spec.hasTag(Tags.OMEGA)) {
448 unrestrictedWeapons.add(id);
449 }
450 }
451 }
452
453 for (String id : unrestrictedWeapons) {
454 if (!pf.knowsWeapon(id)) {
455 addedWeapons.add(id);
456 pf.addKnownWeapon(id, false);
457 }
458 }
459 for (String id : unrestrictedFighters) {
460 if (!pf.knowsFighter(id)) {
461 addedFighters.add(id);
462 pf.addKnownFighter(id, false);
463 }
464 }
465 for (String id : hullmods) {
466 if (!pf.knowsHullMod(id)) {
467 addedHullmods.add(id);
468 pf.addKnownHullMod(id);
469 }
470 }
471
472 ships.inflateIfNeeded();
473
474 for (String id : addedWeapons) {
475 pf.removeKnownWeapon(id);
476 }
477 for (String id : addedFighters) {
478 pf.removeKnownFighter(id);
479 }
480 for (String id : addedHullmods) {
481 pf.removeKnownHullMod(id);
482 }
483
484 if (!data.append && !ships.isEmpty()) {
485 playerFleet.getFleetData().clear();
486 if (data.addOfficers) {
487 for (OfficerDataAPI od : playerFleet.getFleetData().getOfficersCopy()) {
488 playerFleet.getFleetData().removeOfficer(od.getPerson());
489 }
490 }
491 }
492
493 playerFleet.getCargo().addAll(cargo);
494
495 for (FleetMemberAPI member : ships.getFleetData().getMembersListCopy()) {
496 playerFleet.getFleetData().addFleetMember(member);
497 }
498
499 if (data.addOfficers) {
500 int maxOfficers = Misc.getMaxOfficers(playerFleet);
501 int add = maxOfficers - playerFleet.getFleetData().getOfficersCopy().size();
502 if (add > 0) {
503 FleetParamsV3 fp = new FleetParamsV3();
504 fp.commander = playerFleet.getCommander();
505 fp.maxOfficersToAdd = add;
506 FleetFactoryV3.addCommanderAndOfficersV2(playerFleet, fp, random);
507 }
508 }
509
510
511 playerFleet.forceSync();
512
513 cargo = playerFleet.getCargo();
514
515 int neededCrew = (int) ((playerFleet.getFleetData().getMinCrew() + cargo.getMaxPersonnel()) / 2f
516 - cargo.getCrew());
517 if (neededCrew > 0) {
518 cargo.addCrew(neededCrew);
519 }
520 cargo.addFuel(cargo.getMaxFuel() - cargo.getFuel());
521 cargo.addSupplies(cargo.getSpaceLeft() * 0.5f);
522
523
524 playerFleet.forceSync();
525
526 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) {
527 float max = member.getRepairTracker().getMaxCR();
528 member.getRepairTracker().setCR(max);
529 }
530
531
532
533 }
534
535 protected void initAvailable() {
536 for (ShipHullSpecAPI spec : Global.getSettings().getAllShipHullSpecs()) {
537 //if (spec.isDefaultDHull() || spec.isDHull()) continue;
538 if (spec.isDefaultDHull()) continue;
539 if (spec.getHullSize() == HullSize.FIGHTER) continue;
540 if (!spec.hasHullName()) continue;
541 if (spec.getHints().contains(ShipTypeHints.STATION)) continue;
542// if (spec.getHints().contains(ShipTypeHints.HIDE_IN_CODEX)) continue;
543// if (spec.getHints().contains(ShipTypeHints.UNBOARDABLE)) continue;
544 if ("shuttlepod".equals(spec.getHullId())) continue;
545 ships.add(spec.getHullId());
546 }
547
548 for (WeaponSpecAPI spec : Global.getSettings().getAllWeaponSpecs()) {
549 //if (!spec.hasTag(Items.TAG_RARE_BP) && !spec.hasTag(Items.TAG_DEALER)) continue;
550 if (spec.getAIHints().contains(AIHints.SYSTEM)) continue;
551 if (!spec.hasTag(Tags.RESTRICTED)) {
552 unrestrictedWeapons.add(spec.getWeaponId());
553 }
554 weapons.add(spec.getWeaponId());
555 }
556
557 for (FighterWingSpecAPI spec : Global.getSettings().getAllFighterWingSpecs()) {
558 if (!spec.hasTag(Tags.RESTRICTED)) {
559 unrestrictedFighters.add(spec.getId());
560 }
561 fighters.add(spec.getId());
562 }
563
564 for (HullModSpecAPI spec : Global.getSettings().getAllHullModSpecs()) {
565 hullmods.add(spec.getId());
566 }
567 }
568
569 protected void addNoSkillOfficer(int level) {
570 PersonAPI p = Global.getSector().getPlayerFaction().createRandomPerson();
571 p.getMemoryWithoutUpdate().set(MemFlags.OFFICER_SKILL_PICKS_PER_LEVEL, 10);
572 p.getMemoryWithoutUpdate().set(MemFlags.OFFICER_MAX_LEVEL, level + 1);
573 if (level >= 7) {
574 p.getMemoryWithoutUpdate().set(MemFlags.OFFICER_MAX_ELITE_SKILLS, 4);
575 }
576// p.getStats().setLevel(level + 1);
577 for (SkillLevelAPI sl : p.getStats().getSkillsCopy()) {
578 p.getStats().setSkillLevel(sl.getSkill().getId(), 0);
579 }
580 //p.setPersonality(Personalities.AGGRESSIVE);
581 OfficerLevelupPlugin plugin = (OfficerLevelupPlugin) Global.getSettings().getPlugin("officerLevelUp");
582 long xp = plugin.getXPForLevel(level + 1);
583 OfficerDataAPI od = Global.getFactory().createOfficerData(p);
584 od.addXP(xp);
585 Global.getSector().getPlayerFleet().getFleetData().addOfficer(od);
586 if (level >= 7) {
587 textPanel.addPara("Added level " + (level + 1) + " officer with NO initial skill and 4 elite skills max.");
588 } else {
589 textPanel.addPara("Added level " + (level + 1) + " officer with NO initial skill.");
590 }
591 }
592}
593
594
595
596
static SettingsAPI getSettings()
Definition Global.java:51
static FactoryAPI getFactory()
Definition Global.java:35
static SectorAPI getSector()
Definition Global.java:59
CargoAPI createCargo(boolean unlimitedStacks)
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
OfficerDataAPI createOfficerData(PersonAPI person)
ListMap< String > getHullIdToVariantListMap()
List< WeaponSpecAPI > getAllWeaponSpecs()
List< HullModSpecAPI > getAllHullModSpecs()
WeaponSpecAPI getWeaponSpec(String weaponId)
List< ShipHullSpecAPI > getAllShipHullSpecs()
List< FighterWingSpecAPI > getAllFighterWingSpecs()