Starsector API
Loading...
Searching...
No Matches
RemnantOfficerGeneratorPlugin.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.procgen.themes;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.List;
7import java.util.Map;
8import java.util.Random;
9
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.AICoreOfficerPlugin;
12import com.fs.starfarer.api.campaign.CampaignFleetAPI;
13import com.fs.starfarer.api.campaign.FactionAPI;
14import com.fs.starfarer.api.campaign.FactionDoctrineAPI;
15import com.fs.starfarer.api.campaign.GenericPluginManagerAPI;
16import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
17import com.fs.starfarer.api.characters.PersonAPI;
18import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
19import com.fs.starfarer.api.combat.WeaponAPI.WeaponSize;
20import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
21import com.fs.starfarer.api.fleet.FleetMemberAPI;
22import com.fs.starfarer.api.impl.campaign.events.OfficerManagerEvent.SkillPickPreference;
23import com.fs.starfarer.api.impl.campaign.fleets.BaseGenerateFleetOfficersPlugin;
24import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
25import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3;
26import com.fs.starfarer.api.impl.campaign.ids.Commodities;
27import com.fs.starfarer.api.impl.campaign.ids.Factions;
28import com.fs.starfarer.api.impl.campaign.ids.Ranks;
29import com.fs.starfarer.api.impl.campaign.ids.Skills;
30import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.OfficerQuality;
31import com.fs.starfarer.api.loading.WeaponSpecAPI;
32import com.fs.starfarer.api.util.Misc;
33import com.fs.starfarer.api.util.WeightedRandomPicker;
34
36
37 protected boolean putCoresOnCivShips = false;
38 protected boolean forceIntegrateCores = false;
39 protected boolean forceNoCommander = false;
40 protected boolean derelictMode = false;
41 protected float coreMult = 1f;
42
45
47 this.derelictMode = derelictMode;
48 this.coreMult = coreMult;
49 }
50
51
52
53 public boolean isForceNoCommander() {
54 return forceNoCommander;
55 }
56
58 this.forceNoCommander = forceNoCommander;
59 }
60
61 public boolean isPutCoresOnCivShips() {
62 return putCoresOnCivShips;
63 }
64
66 this.putCoresOnCivShips = putCoresOnCivShips;
67 }
68
69 public boolean isForceIntegrateCores() {
71 }
72
74 this.forceIntegrateCores = forceIntegrateCores;
75 }
76
77 @Override
78 public int getHandlingPriority(Object params) {
79 if (!(params instanceof GenerateFleetOfficersPickData)) return -1;
80
81 GenerateFleetOfficersPickData data = (GenerateFleetOfficersPickData) params;
82
83 if (data.params != null && !data.params.withOfficers) return -1;
84
85 if (data.params.aiCores != null) return GenericPluginManagerAPI.CORE_SUBSET;
86
87 if (data.fleet == null || !data.fleet.getFaction().getId().equals(Factions.REMNANTS)) return -1;
88
90 }
91
92
93 @Override
94 public void addCommanderAndOfficers(CampaignFleetAPI fleet, FleetParamsV3 params, Random random) {
95 if (random == null) random = Misc.random;
96 FactionAPI faction = fleet.getFaction();
97 FactionDoctrineAPI doctrine = faction.getDoctrine();
98 if (!derelictMode && params != null && params.doctrineOverride != null) {
99 doctrine = params.doctrineOverride;
100 }
101 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
102 if (members.isEmpty()) return;
103
104 Map<String, AICoreOfficerPlugin> plugins = new HashMap<String, AICoreOfficerPlugin>();
105
110 String nothing = "nothing";
111
112 float fleetFP = 0f; //fleet.getFleetPoints(); <- doesn't work here, requires a call to fleet.forceSync()
113 for (FleetMemberAPI member : members) {
114 fleetFP += member.getFleetPointCost();
115 }
116 boolean allowAlphaAnywhere = fleetFP > 150f;
117 boolean allowBetaAnywhere = fleetFP > 75f;
118
119 //boolean integrate = fleetFP > 200f || params.forceIntegrateAICores;
120 boolean integrate = params != null && !params.doNotIntegrateAICores;
121 integrate |= forceIntegrateCores;
122
123 int numCommanderSkills = 0;
124 if (allowBetaAnywhere) numCommanderSkills++;
125 if (allowAlphaAnywhere) numCommanderSkills++;
126 if (params != null && params.noCommanderSkills != null && params.noCommanderSkills) numCommanderSkills = 0;
127
128
129 //float fpPerCore = 20f;
130 float fpPerCore = Global.getSettings().getFloat("baseFPPerAICore");
131
132 if (derelictMode) {
133 fpPerCore = 30 - 20f * coreMult;
134 }
135
136 int minCores = (int) (fleetFP / fpPerCore * (params != null ? params.officerNumberMult : 1f));
137 if (params != null) {
138 minCores += params.officerNumberBonus;
139 }
140 if (minCores < 1) minCores = 1;
141
142 boolean debug = true;
143 debug = false;
144
146
147 int maxSize = 0;
148 for (FleetMemberAPI member : members) {
149 if (!Misc.isAutomated(member)) continue;
150 if (member.isFighterWing()) continue;
151 if (member.isCivilian() && !putCoresOnCivShips) continue;
152 int size = member.getHullSpec().getHullSize().ordinal();
153 if (size > maxSize) {
154 maxSize = size;
155 }
156 }
157
158 List<FleetMemberAPI> allWithOfficers = new ArrayList<FleetMemberAPI>();
159 int addedCores = 0;
160 for (FleetMemberAPI member : members) {
161 if (!Misc.isAutomated(member)) continue;
162 if (member.isCivilian() && !putCoresOnCivShips) continue;
163 if (member.isFighterWing()) continue;
164
165 float fp = member.getFleetPointCost();
166
168
169 if (params != null && params.aiCores == OfficerQuality.AI_GAMMA) {
170 picker.add(Commodities.GAMMA_CORE, fp);
171 } else if (params != null && params.aiCores == OfficerQuality.AI_BETA) {
172 picker.add(Commodities.BETA_CORE, fp);
173 } else if (params != null && params.aiCores == OfficerQuality.AI_ALPHA) {
174 picker.add(Commodities.ALPHA_CORE, fp);
175 } else if (params != null && params.aiCores == OfficerQuality.AI_OMEGA) {
176 picker.add(Commodities.OMEGA_CORE, fp);
177 } else if (params != null && params.aiCores == OfficerQuality.AI_BETA_OR_GAMMA) {
178 if (member.isCapital() || member.isCruiser()) {
179 picker.add(Commodities.BETA_CORE, fp);
180 } else if (allowAlphaAnywhere) {
181 picker.add(Commodities.BETA_CORE, fp);
182 } else {
183 picker.add(Commodities.BETA_CORE, fp/2f);
184 }
185 picker.add(Commodities.GAMMA_CORE, fp);
186 } else {
187 if (derelictMode) {
188 picker.add(Commodities.GAMMA_CORE, fp);
189 } else {
190 if (member.isCapital() || member.isCruiser()) {
191 picker.add(Commodities.ALPHA_CORE, fp);
192 } else if (allowAlphaAnywhere) {
193 picker.add(Commodities.ALPHA_CORE, fp);
194 }
195
196 if (member.isCruiser() || member.isDestroyer()) {
197 picker.add(Commodities.BETA_CORE, fp/2f);
198 } else if (allowBetaAnywhere && member.isFrigate()) {
199 picker.add(Commodities.BETA_CORE, fp);
200 }
201
202 if (member.isDestroyer() || member.isFrigate()) {
203 picker.add(Commodities.GAMMA_CORE, fp);
204 }
205 }
206 }
207
208 if (addedCores >= minCores) {
209 picker.add(nothing, 10f * picker.getTotal()/fp);
210 }
211
212 String pick = picker.pick();
213 if (debug) {
214 System.out.println("Picked [" + pick + "] for " + member.getHullId());
215 }
216 AICoreOfficerPlugin plugin = plugins.get(pick);
217 if (plugin != null) {
218 addedCores++;
219
220 PersonAPI person = plugin.createPerson(pick, fleet.getFaction().getId(), random);
221 member.setCaptain(person);
222 if (integrate && !Commodities.OMEGA_CORE.equals(pick)) {
224 }
225
226 if (!member.isFighterWing() && !member.isCivilian()) {
227 withOfficers.add(member, fp);
228 }
229
230 allWithOfficers.add(member);
231 }
232
233 if (addedCores > 0 && params != null && params.officerNumberMult <= 0) {
234 break; // only want to add the fleet commander
235 }
236 }
237
238 if (withOfficers.isEmpty() && !allWithOfficers.isEmpty()) {
239 withOfficers.add(allWithOfficers.get(0), 1f);
240 }
241
242
243 FleetMemberAPI flagship = withOfficers.pick();
244 if (!derelictMode && !forceNoCommander && flagship != null) {
245 PersonAPI commander = flagship.getCaptain();
248 fleet.setCommander(commander);
249 fleet.getFleetData().setFlagship(flagship);
250 addCommanderSkills(commander, fleet, params, numCommanderSkills, random);
251 }
252 }
253
255 PersonAPI person = member.getCaptain();
256 if (!person.isAICore()) return;
257
258 person.getStats().setLevel(person.getStats().getLevel() + 1);
259
260 person.getStats().setSkipRefresh(true);
261
262// if (member.isCarrier()) {
263// person.getStats().setSkillLevel(Skills.STRIKE_COMMANDER, 2);
264// if (person.getStats().getSkillLevel(Skills.POINT_DEFENSE) <= 0) {
265// person.getStats().setSkillLevel(Skills.POINT_DEFENSE, 2);
266// person.getStats().setSkillLevel(Skills.RELIABILITY_ENGINEERING, 0);
267// }
268// } else {
269 if (member.getVariant() != null && member.getVariant().getWeaponGroups() != null) {
270 float weight = 0f;
271 float pdWeight = 0f;
272 float missileWeight = 0f;
273 for (String slotId : member.getVariant().getFittedWeaponSlots()) {
274 WeaponSpecAPI spec = member.getVariant().getWeaponSpec(slotId);
275 if (spec == null) continue;
276 float w = 1f;
277 if (spec.getSize() == WeaponSize.MEDIUM) w = 2f;
278 if (spec.getSize() == WeaponSize.LARGE) w = 4f;
279 weight += w;
280 if (spec.getAIHints().contains(AIHints.PD)) {
281 pdWeight += w;
282 }
283 if (spec.getType() == WeaponType.MISSILE) {
284 missileWeight += w;
285 }
286
287 }
288
289 float decks = member.getNumFlightDecks();
290 if (decks > 0) {
291 weight += decks * 4f;
292 pdWeight += decks * 4f;
293 }
294
295 boolean hasUsefulPD = pdWeight > weight * 0.25f;
296 boolean hasEnoughMissiles = missileWeight > weight * 0.2f;
297
298
299 if (hasUsefulPD && !hasEnoughMissiles) {
301 person.getStats().setSkipRefresh(false);
302 return;
303 }
304 }
305
306
307 if (member.getHullSpec() != null && member.getHullSpec().hasTag(Factions.DERELICT) &&
310 } else {
313 } else {
315 }
316 }
317
318 if (member.isCapital() || member.isStation()) {
319 if (person.getStats().getSkillLevel(Skills.POLARIZED_ARMOR) <= 0) {
322 }
323 }
324 //}
325
326 person.getStats().setSkipRefresh(false);
327 }
328
329
330 public static SkillPickPreference getSkillPrefForShip(FleetMemberAPI member) {
331 return FleetFactoryV3.getSkillPrefForShip(member);
332// float weight = FleetFactoryV3.getMemberWeight(member);
333// float fighters = member.getVariant().getFittedWings().size();
334// boolean wantCarrierSkills = weight > 0 && fighters / weight >= 0.5f;
335// SkillPickPreference pref = SkillPickPreference.GENERIC;
336// if (wantCarrierSkills) {
337// pref = SkillPickPreference.CARRIER;
338// } else if (member.isPhaseShip()) {
339// pref = SkillPickPreference.PHASE;
340// }
341//
342// return pref;
343 }
344
345
346 public static void addCommanderSkills(PersonAPI commander, CampaignFleetAPI fleet, FleetParamsV3 params, int numSkills, Random random) {
347 if (random == null) random = new Random();
348 if (numSkills <= 0) return;
349
350 MutableCharacterStatsAPI stats = commander.getStats();
351
352 FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
353 if (params != null && params.doctrineOverride != null) {
354 doctrine = params.doctrineOverride;
355 }
356
357 List<String> skills = new ArrayList<String>(doctrine.getCommanderSkills());
358 if (skills.isEmpty()) return;
359
360 if (random.nextFloat() < doctrine.getCommanderSkillsShuffleProbability()) {
361 Collections.shuffle(skills, random);
362 }
363
364 stats.setSkipRefresh(true);
365
366 boolean debug = true;
367 debug = false;
368 if (debug) System.out.println("Generating commander skills, person level " + stats.getLevel() + ", skills: " + numSkills);
369 int picks = 0;
370 for (String skillId : skills) {
371 if (debug) System.out.println("Selected skill: [" + skillId + "]");
372 stats.setSkillLevel(skillId, 1);
373 picks++;
374 if (picks >= numSkills) {
375 break;
376 }
377 }
378 if (debug) System.out.println("Done generating commander skills\n");
379
380 stats.setSkipRefresh(false);
382 }
383
384
385
386
387
388}
389
390
391
392
393
394
395
396
397
398
399
400
static SettingsAPI getSettings()
Definition Global.java:57
static SkillPickPreference getSkillPrefForShip(FleetMemberAPI member)
HubMissionWithTriggers.OfficerQuality aiCores
void addCommanderAndOfficers(CampaignFleetAPI fleet, FleetParamsV3 params, Random random)
static void addCommanderSkills(PersonAPI commander, CampaignFleetAPI fleet, FleetParamsV3 params, int numSkills, Random random)
static AICoreOfficerPlugin getAICoreOfficerPlugin(String commodityId)
Definition Misc.java:4230
static boolean isAutomated(MutableShipStatsAPI stats)
Definition Misc.java:5491
PersonAPI createPerson(String aiCoreId, String factionId, Random random)
void setFlagship(FleetMemberAPI flagship)
List< FleetMemberAPI > getMembersListCopy()
MutableCharacterStatsAPI getStats()
Collection< String > getFittedWeaponSlots()
WeaponSpecAPI getWeaponSpec(String slotId)
List< WeaponGroupSpec > getWeaponGroups()
EnumSet< WeaponAPI.AIHints > getAIHints()