Starsector API
Loading...
Searching...
No Matches
FleetFactoryV3.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.fleets;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Comparator;
6import java.util.HashMap;
7import java.util.HashSet;
8import java.util.Iterator;
9import java.util.LinkedHashSet;
10import java.util.List;
11import java.util.Map;
12import java.util.Random;
13import java.util.Set;
14
15import org.apache.log4j.Logger;
16
17import com.fs.starfarer.api.Global;
18import com.fs.starfarer.api.campaign.CampaignFleetAPI;
19import com.fs.starfarer.api.campaign.FactionAPI;
20import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
21import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams;
22import com.fs.starfarer.api.campaign.FactionDoctrineAPI;
23import com.fs.starfarer.api.campaign.FleetInflater;
24import com.fs.starfarer.api.campaign.SectorEntityToken;
25import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
26import com.fs.starfarer.api.campaign.econ.MarketAPI;
27import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
28import com.fs.starfarer.api.characters.PersonAPI;
29import com.fs.starfarer.api.characters.SkillSpecAPI;
30import com.fs.starfarer.api.combat.ShieldAPI.ShieldType;
31import com.fs.starfarer.api.combat.ShipAPI.HullSize;
32import com.fs.starfarer.api.combat.ShipHullSpecAPI.ShipTypeHints;
33import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
34import com.fs.starfarer.api.fleet.FleetMemberAPI;
35import com.fs.starfarer.api.fleet.FleetMemberType;
36import com.fs.starfarer.api.fleet.ShipRolePick;
37import com.fs.starfarer.api.impl.campaign.events.OfficerManagerEvent;
38import com.fs.starfarer.api.impl.campaign.events.OfficerManagerEvent.SkillPickPreference;
39import com.fs.starfarer.api.impl.campaign.fleets.GenerateFleetOfficersPlugin.GenerateFleetOfficersPickData;
40import com.fs.starfarer.api.impl.campaign.ids.Commodities;
41import com.fs.starfarer.api.impl.campaign.ids.Factions;
42import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
43import com.fs.starfarer.api.impl.campaign.ids.Personalities;
44import com.fs.starfarer.api.impl.campaign.ids.Ranks;
45import com.fs.starfarer.api.impl.campaign.ids.ShipRoles;
46import com.fs.starfarer.api.impl.campaign.ids.Skills;
47import com.fs.starfarer.api.impl.campaign.ids.Stats;
48import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin;
49import com.fs.starfarer.api.loading.AbilitySpecAPI;
50import com.fs.starfarer.api.loading.WeaponSlotAPI;
51import com.fs.starfarer.api.plugins.CreateFleetPlugin;
52import com.fs.starfarer.api.plugins.OfficerLevelupPlugin;
53import com.fs.starfarer.api.util.Misc;
54import com.fs.starfarer.api.util.WeightedRandomPicker;
55
56public class FleetFactoryV3 {
57
58 public static String KEY_SPAWN_FP_MULT = "$spawnFPMult";
59
60 //public static float IMPORTED_QUALITY_PENALTY = Global.getSettings().getFloat("fleetQualityPenaltyForImports");
61 public static float BASE_QUALITY_WHEN_NO_MARKET = 0.5f;
62
64
65 public static float MIN_NUM_SHIPS_DEFICIT_MULT = 0.25f;
66
67 public static int [][] BASE_COUNTS_WITH_4 = new int [][]
68 {{9, 4, 2, 0},
69 {7, 4, 2, 0},
70 {4, 3, 3, 0},
71 {1, 1, 1, 0},
72 {1, 1, 1, 1},
73 };
74 public static int [][] MAX_EXTRA_WITH_4 = new int [][]
75 {{3, 2, 1, 1},
76 {2, 2, 2, 1},
77 {2, 2, 2, 1},
78 {2, 2, 2, 3},
79 {1, 1, 1, 1},
80 };
81
82 public static int [][] BASE_COUNTS_WITH_3 = new int [][]
83 {{6, 2, 1},
84 {4, 2, 1},
85 {3, 2, 1},
86 {1, 1, 1},
87 {1, 1, 1},
88 };
89 public static int [][] MAX_EXTRA_WITH_3 = new int [][]
90 {{2, 0, 0},
91 {2, 1, 0},
92 {2, 2, 0},
93 {2, 2, 0},
94 {1, 1, 0},
95 };
96
97 public static Logger log = Global.getLogger(FleetFactoryV3.class);
98
99
100
101
102 public static float getShipQualityModForStability(float stability) {
103 return (stability - 5f) * 0.05f;
104 }
105 public static float getNumShipsMultForStability(float stability) {
106 return 1f + (stability - 5f) * 0.05f;
107 }
108
109
110 public static float getNumShipsMultForMarketSize(float marketSize) {
111 if (marketSize < 3) marketSize = 3;
112
113// switch ((int)marketSize) {
114// case 3: return 0.5f;
115// case 4: return 0.7f;
116// case 5: return 0.85f;
117// case 6: return 1f;
118// case 7: return 1.15f;
119// case 8: return 1.3f;
120// case 9: return 1.5f;
121// case 10: return 2f;
122// }
123// switch ((int)marketSize) {
124// case 3: return 1f;
125// case 4: return 1.25f;
126// case 5: return 1.5f;
127// case 6: return 1.75f;
128// case 7: return 2.0f;
129// case 8: return 2.25f;
130// case 9: return 2.5f;
131// case 10: return 3f;
132// }
133 switch ((int)marketSize) {
134 case 3: return 0.5f;
135 case 4: return 0.75f;
136 case 5: return 1f;
137 case 6: return 1.25f;
138 case 7: return 1.5f;
139 case 8: return 1.75f;
140 case 9: return 2f;
141 case 10: return 2.5f;
142 }
143
144 return marketSize / 6f;
145 }
146 public static float getDoctrineNumShipsMult(int doctrineNumShips) {
147 float max = Global.getSettings().getFloat("maxDoctrineNumShipsMult");
148
149 return 1f + (float) (doctrineNumShips - 1f) * (max - 1f) / 4f;
150 }
151
153
155 if (plugin != null) {
156 return plugin.createFleet(params);
157 }
158
159 Global.getSettings().profilerBegin("FleetFactoryV3.createFleet()");
160 try {
161
162 boolean fakeMarket = false;
163 MarketAPI market = pickMarket(params);
164 if (market == null) {
165 market = Global.getFactory().createMarket("fake", "fake", 5);
166 market.getStability().modifyFlat("fake", 10000);
167 market.setFactionId(params.factionId);
169 market.setPrimaryEntity(token);
170
172
174
175 if (params.factionOverride != null) {
176 market.setCachedFaction(params.factionOverride);
177 }
178// CommodityOnMarketAPI com = market.getCommodityData(Commodities.SHIPS);
179// com.setMaxSupply(6);
180// com.setMaxDemand(6);
181// com.getAvailableStat().setBaseValue(6);
182// com.setSupplier(new SupplierData(6, com, false));
183 fakeMarket = true;
184 }
185 boolean sourceWasNull = params.source == null;
186 params.source = market;
187 if (sourceWasNull && params.qualityOverride == null) { // we picked a nearby market based on location
189 }
190
191 //params.timestamp = Global.getSector().getClock().getTimestamp() - (long)(3600 * 24 * 1000);
192// params.timestamp = Global.getSector().getClock().getTimestamp();
193// if (params.forceNoTimestamp != null && params.forceNoTimestamp) {
194// params.timestamp = null;
195// }
196
197// if (market.getName().equals("Jangala")) {
198// System.out.println("wfwdfwef");
199// }
200
201// ShipPickMode mode = ShipPickMode.PRIORITY_THEN_OTHER;
202// if (params.producer != null && params.producer.getFaction() != market.getFaction()) {
203// mode = ShipPickMode.IMPORTED;
204// }
205// if (params.modeOverride != null) mode = params.modeOverride;
206
207 String factionId = params.factionId;
208 if (factionId == null) factionId = params.source.getFactionId();
209
210 ShipPickMode mode = Misc.getShipPickMode(market, factionId);
211 if (params.modeOverride != null) mode = params.modeOverride;
212
213 CampaignFleetAPI fleet = null;
214
215 if (params.factionOverride != null) {
216 fleet = Global.getFactory().createEmptyFleet(params.factionOverride, true);
218 } else {
219 fleet = createEmptyFleet(factionId, params.fleetType, market);
220 }
222
223 Misc.getSalvageSeed(fleet); // will set it
224
225// if (true) {
226// fleet.getFleetData().setOnlySyncMemberLists(false);
227// fleet.getFleetData().addFleetMember("atlas_Standard");
228// return fleet;
229// }
230
231 FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
232 if (params.doctrineOverride != null) {
233 doctrine = params.doctrineOverride;
234 }
235
236 float numShipsMult = 1f;
237 if (params.ignoreMarketFleetSizeMult == null || !params.ignoreMarketFleetSizeMult) {
239 }
240
241 float quality = params.quality + params.qualityMod;
242// if (mode == ShipPickMode.IMPORTED) { // factored in by FleetParamsV3 calculation of quality
243// quality -= IMPORTED_QUALITY_PENALTY;
244// }
245 if (params.qualityOverride != null) {
246 quality = params.qualityOverride;
247 }
248
249 Random random = new Random();
250 if (params.random != null) random = params.random;
251
252 //Misc.setSpawnFPMult(fleet, numShipsMult);
253
254 float combatPts = params.combatPts * numShipsMult;
255
257 numShipsMult = 1f;
258 }
259
260 float freighterPts = params.freighterPts * numShipsMult;
261 float tankerPts = params.tankerPts * numShipsMult;
262 float transportPts = params.transportPts * numShipsMult;
263 float linerPts = params.linerPts * numShipsMult;
264 float utilityPts = params.utilityPts * numShipsMult;
265
266
267
268 if (combatPts < 10 && combatPts > 0) {
269 combatPts = Math.max(combatPts, 5 + random.nextInt(6));
270 }
271
272 float dW = (float) doctrine.getWarships() + random.nextInt(3) - 2;
273 float dC = (float) doctrine.getCarriers() + random.nextInt(3) - 2;
274 float dP = (float) doctrine.getPhaseShips() + random.nextInt(3) - 2;
275
276 boolean strict = doctrine.isStrictComposition();
277 if (strict) {
278 dW = (float) doctrine.getWarships() - 1;
279 dC = (float) doctrine.getCarriers() - 1;
280 dP = (float) doctrine.getPhaseShips() -1;
281 }
282
283 if (!strict) {
284 float r1 = random.nextFloat();
285 float r2 = random.nextFloat();
286 float min = Math.min(r1, r2);
287 float max = Math.max(r1, r2);
288
289 float mag = 1f;
290 float v1 = min;
291 float v2 = max - min;
292 float v3 = 1f - max;
293
294 v1 *= mag;
295 v2 *= mag;
296 v3 *= mag;
297
298 v1 -= mag/3f;
299 v2 -= mag/3f;
300 v3 -= mag/3f;
301
302 //System.out.println(v1 + "," + v2 + "," + v3);
303 dW += v1;
304 dC += v2;
305 dP += v3;
306 }
307
308 if (doctrine.getWarships() <= 0) dW = 0;
309 if (doctrine.getCarriers() <= 0) dC = 0;
310 if (doctrine.getPhaseShips() <= 0) dP = 0;
311
312
313// float dW = (float) doctrine.getWarships() + random.nextInt(2) - 1;
314// float dC = (float) doctrine.getCarriers() + random.nextInt(2) - 1;
315// float dP = (float) doctrine.getPhaseShips() + random.nextInt(2) - 1;
316
317 boolean banPhaseShipsEtc = !fleet.getFaction().isPlayerFaction() &&
319 if (params.forceAllowPhaseShipsEtc != null && params.forceAllowPhaseShipsEtc) {
320 banPhaseShipsEtc = !params.forceAllowPhaseShipsEtc;
321 }
322
323 params.mode = mode;
324 params.banPhaseShipsEtc = banPhaseShipsEtc;
325
326 // with the phase AI changes: allow phase ships in smaller fleets
327 // but still ban the "etc" (i.e. hyperion, ships with damper field, etc -
328 // anything not in the "combatSmallForSmallFleet" role
329// if (banPhaseShipsEtc) {
330// dP = 0;
331// };
332
333 if (dW < 0) dW = 0;
334 if (dC < 0) dC = 0;
335 if (dP < 0) dP = 0;
336
337 float extra = 7 - (dC + dP + dW);
338 if (extra < 0) extra = 0f;
339 if (doctrine.getWarships() > doctrine.getCarriers() && doctrine.getWarships() > doctrine.getPhaseShips()) {
340 dW += extra;
341 } else if (doctrine.getCarriers() > doctrine.getWarships() && doctrine.getCarriers() > doctrine.getPhaseShips()) {
342 dC += extra;
343 } else if (doctrine.getPhaseShips() > doctrine.getWarships() && doctrine.getPhaseShips() > doctrine.getCarriers()) {
344 dP += extra;
345 }
346
347
348 float doctrineTotal = dW + dC + dP;
349
350 //System.out.println("DW: " + dW + ", DC: " + dC + " DP: " + dP);
351
352 combatPts = (int) combatPts;
353 int warships = (int) (combatPts * dW / doctrineTotal);
354 int carriers = (int) (combatPts * dC / doctrineTotal);
355 int phase = (int) (combatPts * dP / doctrineTotal);
356
357 warships += (combatPts - warships - carriers - phase);
358
359 if (params.addShips != null) {
360 for (String variantId : params.addShips) {
361 ShipRolePick pick = new ShipRolePick(variantId);
362 warships -= addToFleet(pick, fleet, random);
363 }
364 if (warships < 0) warships = 0;
365 }
366
367
369 float combatFreighters = (int) Math.min(freighterPts * 1.5f, warships * 1.5f) * doctrine.getCombatFreighterProbability();
370 float added = addCombatFreighterFleetPoints(fleet, random, combatFreighters, params);
371 freighterPts -= added * 0.5f;
372 warships -= added * 0.5f;
373 } else if (freighterPts > 0 && random.nextFloat() < doctrine.getCombatFreighterProbability()) {
374 float combatFreighters = (int) Math.min(freighterPts * 1.5f, warships * 1.5f);
375 float added = addCombatFreighterFleetPoints(fleet, random, combatFreighters, params);
376 freighterPts -= added * 0.5f;
377 warships -= added * 0.5f;
378 }
379
380 addCombatFleetPoints(fleet, random, warships, carriers, phase, params);
381
382
383 addFreighterFleetPoints(fleet, random, freighterPts, params);
384 addTankerFleetPoints(fleet, random, tankerPts, params);
385 addTransportFleetPoints(fleet, random, transportPts, params);
386 addLinerFleetPoints(fleet, random, linerPts, params);
387 addUtilityFleetPoints(fleet, random, utilityPts, params);
388
389
390 //System.out.println("FLEET POINTS: " + getFP(fleet));
391 int maxShips = Global.getSettings().getInt("maxShipsInAIFleet");
392 if (params.maxNumShips != null) {
393 maxShips = params.maxNumShips;
394 }
395 if (fleet.getFleetData().getNumMembers() > maxShips) {
396 if (params.doNotPrune == null || !params.doNotPrune) {
397 float targetFP = getFP(fleet);
398 if (params.doNotAddShipsBeforePruning == null || !params.doNotAddShipsBeforePruning) {
399 sizeOverride = 5;
400 addCombatFleetPoints(fleet, random, warships, carriers, phase, params);
401 addFreighterFleetPoints(fleet, random, freighterPts, params);
402 addTankerFleetPoints(fleet, random, tankerPts, params);
403 addTransportFleetPoints(fleet, random, transportPts, params);
404 addLinerFleetPoints(fleet, random, linerPts, params);
405 addUtilityFleetPoints(fleet, random, utilityPts, params);
406 sizeOverride = 0;
407 }
408
409 int size = doctrine.getShipSize();
410 pruneFleet(maxShips, size, fleet, targetFP, random);
411
412 float currFP = getFP(fleet);
413 //currFP = getFP(fleet);
414// if (currFP < targetFP) {
415// extraOfficers = (int) Math.round ((targetFP / Math.max(10f, currFP) - 1f) * 10f);
416// if (extraOfficers > 30) extraOfficers = 30;
417// if (extraOfficers < 0) extraOfficers = 0;
418// }
419 }
420
421 fleet.getFleetData().sort();
422
423 //System.out.println("FLEET POINTS: " + getFP(fleet));
424
425
426 } else {
427 fleet.getFleetData().sort();
428 }
429
430 fleet.getFleetData().sort();
431
432 if (params.withOfficers) {
433 addCommanderAndOfficers(fleet, params, random);
434 }
435
436 if (fleet.getFlagship() != null) {
437 if (params.flagshipVariantId != null) {
439 } else if (params.flagshipVariant != null) {
440 fleet.getFlagship().setVariant(params.flagshipVariant, false, true);
441 }
442 }
443
444 if (params.onlyRetainFlagship != null && params.onlyRetainFlagship) {
445 for (FleetMemberAPI curr : fleet.getFleetData().getMembersListCopy()) {
446 if (curr.isFlagship()) continue;
447 fleet.getFleetData().removeFleetMember(curr);
448 }
449 }
450 //fleet.getFlagship()
451 fleet.forceSync();
452
453 //FleetFactoryV2.doctrine = null;
454
455 if (fleet.getFleetData().getNumMembers() <= 0 ||
456 fleet.getFleetData().getNumMembers() == fleet.getNumFighters()) {
457// if (params.allowEmptyFleet == null || !params.allowEmptyFleet){
458// return null;
459// }
460 }
461
462 if (fakeMarket) {
463 params.source = null;
464 }
465
467 p.quality = quality;
468 if (params.averageSMods != null) {
469 p.averageSMods = params.averageSMods;
470 }
471 p.persistent = true;
472 p.seed = random.nextLong();
473 p.mode = mode;
474 p.timestamp = params.timestamp;
475 p.allWeapons = params.allWeapons;
476 if (params.doctrineOverride != null) {
478 }
479 if (params.factionId != null) {
480 p.factionId = params.factionId;
481 }
482
483 FleetInflater inflater = Misc.getInflater(fleet, p);
484 fleet.setInflater(inflater);
485
487 fleet.getFleetData().sort();
488
489 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
490 for (FleetMemberAPI member : members) {
491 member.getRepairTracker().setCR(member.getRepairTracker().getMaxCR());
492 }
493
494 float requestedPoints = params.getTotalPts();
495 float actualPoints = fleet.getFleetPoints();
496
497 Misc.setSpawnFPMult(fleet, actualPoints / Math.max(1f, requestedPoints));
498
499
500 return fleet;
501
502 } finally {
504 }
505 }
506
507 public static void pruneFleet(int maxShips, int doctrineSize, CampaignFleetAPI fleet, float targetFP, Random random) {
508 //int maxShips = Global.getSettings().getInt("maxShipsInAIFleet");
509
510 float combatFP = 0;
511 float civFP = 0;
512
513 List<FleetMemberAPI> copy = fleet.getFleetData().getMembersListCopy();
514 List<FleetMemberAPI> combat = new ArrayList<FleetMemberAPI>();
515 //List<FleetMemberAPI> civ = new ArrayList<FleetMemberAPI>();
516 List<FleetMemberAPI> tanker = new ArrayList<FleetMemberAPI>();
517 List<FleetMemberAPI> freighter = new ArrayList<FleetMemberAPI>();
518 List<FleetMemberAPI> liner = new ArrayList<FleetMemberAPI>();
519 List<FleetMemberAPI> other = new ArrayList<FleetMemberAPI>();
520
521 for (FleetMemberAPI member : copy) {
522 if (member.isCivilian()) {
523 civFP += member.getFleetPointCost();
524 //civ.add(member);
525
526 if (member.getHullSpec().getHints().contains(ShipTypeHints.FREIGHTER)) {
527 freighter.add(member);
528 } else if (member.getHullSpec().getHints().contains(ShipTypeHints.TANKER)) {
529 tanker.add(member);
530 } else if (member.getHullSpec().getHints().contains(ShipTypeHints.TRANSPORT) ||
531 member.getHullSpec().getHints().contains(ShipTypeHints.LINER)) {
532 liner.add(member);
533 } else {
534 other.add(member);
535 }
536
537 } else {
538 combatFP += member.getFleetPointCost();
539 combat.add(member);
540 }
541 }
542 if (civFP < 1) civFP = 1;
543 if (combatFP < 1) combatFP = 1;
544
545 int keepCombat = (int) ((float)maxShips * combatFP / (civFP + combatFP));
546 int keepCiv = maxShips - keepCombat;
547 if (civFP > 10 && keepCiv < 2) {
548 keepCiv = 2;
549 if (!freighter.isEmpty()) keepCiv++;
550 if (!tanker.isEmpty()) keepCiv++;
551 if (!liner.isEmpty()) keepCiv++;
552 if (!other.isEmpty()) keepCiv++;
553
554 keepCiv = maxShips - keepCiv;
555 }
556
557
558 float f = 0, t = 0, l = 0, o = 0;
559 float total = freighter.size() + tanker.size() + liner.size() + other.size();
560 if (total < 1) total = 1;
561
562 f = (float) freighter.size() / total;
563 t = (float) tanker.size() / total;
564 l = (float) liner.size() / total;
565 o = (float) other.size() / total;
566
567 f *= keepCiv;
568 t *= keepCiv;
569 l *= keepCiv;
570 o *= keepCiv;
571
572 if (f > 0) f = Math.round(f);
573 if (t > 0) t = Math.round(t);
574 if (l > 0) l = Math.round(l);
575 if (o > 0) o = Math.round(o);
576
577 if (freighter.size() > 0 && f < 1) f = 1;
578 if (tanker.size() > 0 && t < 1) t = 1;
579 if (liner.size() > 0 && l < 1) l = 1;
580 if (other.size() > 0 && o < 1) o = 1;
581
582 int extra = (int) ((f + t + l + o) - keepCiv);
583 //if (extra < 0) keepCombat += Math.abs(extra);
584 if (extra > 0 && o >= 2) {
585 extra--;
586 o--;
587 }
588 if (extra > 0 && l >= 2) {
589 extra--;
590 l--;
591 }
592 if (extra > 0 && t >= 2) {
593 extra--;
594 t--;
595 }
596 if (extra > 0 && f >= 2) {
597 extra--;
598 f--;
599 }
600
601
602 LinkedHashSet<FleetMemberAPI> keep = new LinkedHashSet<FleetMemberAPI>();
603
604 Comparator<FleetMemberAPI> c = new Comparator<FleetMemberAPI>() {
605 public int compare(FleetMemberAPI o1, FleetMemberAPI o2) {
606 return o2.getHullSpec().getHullSize().ordinal() - o1.getHullSpec().getHullSize().ordinal();
607 }
608 };
609 Collections.sort(combat, c);
610 Collections.sort(freighter, c);
611 Collections.sort(tanker, c);
612 Collections.sort(liner, c);
613 Collections.sort(other, c);
614
615 int [] ratio = new int [] { 4, 2, 1, 1 };
616 //int [] ratio = new int [] { 1, 2, 2, 1 };
617
618 //doctrineSize = 2;
619// if (doctrineSize == 4) {
620// ratio = new int [] { 3, 3, 1, 1 };
621// } else if (doctrineSize == 3) {
622// ratio = new int [] { 2, 3, 2, 1 };
623// } else if (doctrineSize <= 2) {
624// ratio = new int [] { 2, 3, 2, 1 };
625// }
626 //ratio[3] = 0;
627 //ratio = new int [] { 4, 0, 0, 0 };
628
629 addAll(ratio, combat, keep, keepCombat, random);
630 //addAll(ratio, civ, keep, keepCiv, random);
631
632 addAll(ratio, freighter, keep, (int)f, random);
633 addAll(ratio, tanker, keep, (int)t, random);
634 addAll(ratio, liner, keep, (int)l, random);
635 addAll(ratio, other, keep, (int)o, random); // adds a Hermes since that's "other" but we don't really care
636
637 for (FleetMemberAPI member : copy) {
638 if (!keep.contains(member)) {
639 fleet.getFleetData().removeFleetMember(member);
640 }
641 }
642
643 float currFP = getFP(fleet);
644 if (currFP > targetFP) {
645 fleet.getFleetData().sort();
646 copy = fleet.getFleetData().getMembersListCopy();
647 //Collections.reverse(copy);
648 //Collections.shuffle(copy, random);
649 for (int i = 0; i < copy.size()/2; i+=2) {
650 FleetMemberAPI f1 = copy.get(i);
651 FleetMemberAPI f2 = copy.get(copy.size() - 1 - i);
652 copy.set(i, f2);
653 copy.set(copy.size() - 1 - i, f1);
654 }
655//
656// float fpGoal = currFP - targetFP;
657// float fpDone = 0;
658// for (FleetMemberAPI curr : copy) {
659// if (curr.isCivilian()) continue;
660// for (FleetMemberAPI replace : combat) {
661// float fpCurr = curr.getFleetPointCost();
662// float fpReplace = replace.getFleetPointCost();
663// if (fpCurr > fpReplace) {
664// fpDone += fpCurr - fpReplace;
665// combat.remove(replace);
666// fleet.getFleetData().removeFleetMember(curr);
667// fleet.getFleetData().addFleetMember(replace);
668// break;
669// }
670// }
671// if (fpDone >= fpGoal) {
672// break;
673// }
674// }
675
676 float fpGoal = currFP - targetFP;
677 float fpDone = 0;
678 for (FleetMemberAPI curr : copy) {
679 if (curr.isCivilian()) continue;
680 FleetMemberAPI best = null;
681 float bestDiff = 0f;
682 for (FleetMemberAPI replace : combat) {
683 float fpCurr = curr.getFleetPointCost();
684 float fpReplace = replace.getFleetPointCost();
685 if (fpCurr > fpReplace) {
686 float fpDiff = fpCurr - fpReplace;
687 if (fpDone + fpDiff <= fpGoal) {
688 best = replace;
689 bestDiff = fpDiff;
690 break;
691 } else {
692 if (fpDiff < bestDiff) {
693 best = replace;
694 bestDiff = fpDiff;
695 }
696 }
697 }
698 }
699 if (best != null) {
700 fpDone += bestDiff;
701 combat.remove(best);
702 fleet.getFleetData().removeFleetMember(curr);
703 fleet.getFleetData().addFleetMember(best);
704 }
705 if (fpDone >= fpGoal) {
706 break;
707 }
708 }
709
710 }
711
712 }
713
714 public static void addAll(int [] ratio, List<FleetMemberAPI> from, LinkedHashSet<FleetMemberAPI> to, int num, Random random) {
715 int added = 0;
716 if (num <= 5) {
717 while (added < num && !from.isEmpty()) {
718 to.add(from.remove(0));
719 added++;
720 }
721 return;
722 }
723
724 WeightedRandomPicker<HullSize> picker = makePicker(ratio, random);
725 for (int i = 0; i < num; i++) {
726 if (picker.isEmpty()) picker = makePicker(ratio, random);
727 OUTER: while (!picker.isEmpty()) {
728 HullSize size = picker.pickAndRemove();
729 for (FleetMemberAPI member : from) {
730 if (member.getHullSpec().getHullSize() == size) {
731 to.add(member);
732 from.remove(member);
733 added++;
734 break OUTER;
735 }
736 }
737 }
738
739 }
740
741 // if we failed to add up to num, add the largest ships until we've got num
742 // assumes from list is sorted descending by size
743 while (added < num && !from.isEmpty()) {
744 to.add(from.remove(0));
745 added++;
746 }
747
748 }
749
750 public static WeightedRandomPicker<HullSize> makePicker(int [] ratio, Random random) {
752 for (int i = 0; i < ratio[0]; i++) {
753 picker.add(HullSize.CAPITAL_SHIP);
754 }
755 for (int i = 0; i < ratio[1]; i++) {
756 picker.add(HullSize.CRUISER);
757 }
758 for (int i = 0; i < ratio[2]; i++) {
759 picker.add(HullSize.DESTROYER);
760 }
761 for (int i = 0; i < ratio[3]; i++) {
762 picker.add(HullSize.FRIGATE);
763 }
764// picker.add(HullSize.CAPITAL_SHIP, ratio[0]);
765// picker.add(HullSize.CRUISER, ratio[1]);
766// picker.add(HullSize.DESTROYER, ratio[2]);
767// picker.add(HullSize.FRIGATE, ratio[3]);
768 return picker;
769 }
770
771
772 public static int getFP(CampaignFleetAPI fleet) {
773 int fp = 0;
774 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
775 fp += member.getFleetPointCost();
776 }
777 return fp;
778 }
779
780
781 public static List<FleetMemberAPI> getRemoveOrder(CampaignFleetAPI fleet) {
782 List<FleetMemberAPI> remove = new ArrayList<FleetMemberAPI>();
783 List<FleetMemberAPI> copy = fleet.getFleetData().getMembersListCopy();
784
785// Collections.sort(copy, new Comparator<FleetMemberAPI>() {
786// public int compare(FleetMemberAPI o1, FleetMemberAPI o2) {
787// int f1 = o1.getFleetPointCost();
788// int f2 = o2.getFleetPointCost();
789//
790// if (!o1.isCivilian()) f1 *=
791// return 0;
792// }
793// });
794
795 Collections.reverse(copy);
796
797 Iterator<FleetMemberAPI> iter;
798
799 iter = copy.iterator();
800 while (iter.hasNext()) {
801 FleetMemberAPI member = iter.next();
802 if (member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.FRIGATE.ordinal()) {
803 remove.add(member);
804 iter.remove();
805 }
806 }
807
808 iter = copy.iterator();
809 while (iter.hasNext()) {
810 FleetMemberAPI member = iter.next();
811 if (!member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.FRIGATE.ordinal()) {
812 remove.add(member);
813 iter.remove();
814 }
815 }
816
817 iter = copy.iterator();
818 while (iter.hasNext()) {
819 FleetMemberAPI member = iter.next();
820 if (member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.DESTROYER.ordinal()) {
821 remove.add(member);
822 iter.remove();
823 }
824 }
825
826 iter = copy.iterator();
827 while (iter.hasNext()) {
828 FleetMemberAPI member = iter.next();
829 if (!member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.DESTROYER.ordinal()) {
830 remove.add(member);
831 iter.remove();
832 }
833 }
834
835 iter = copy.iterator();
836 while (iter.hasNext()) {
837 FleetMemberAPI member = iter.next();
838 if (member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.CRUISER.ordinal()) {
839 remove.add(member);
840 iter.remove();
841 }
842 }
843
844 iter = copy.iterator();
845 while (iter.hasNext()) {
846 FleetMemberAPI member = iter.next();
847 if (!member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.CRUISER.ordinal()) {
848 remove.add(member);
849 iter.remove();
850 }
851 }
852
853 iter = copy.iterator();
854 while (iter.hasNext()) {
855 FleetMemberAPI member = iter.next();
856 if (member.isCivilian()) {
857 remove.add(member);
858 iter.remove();
859 }
860 }
861
862 iter = copy.iterator();
863 while (iter.hasNext()) {
864 FleetMemberAPI member = iter.next();
865 if (!member.isCivilian()) {
866 remove.add(member);
867 iter.remove();
868 }
869 }
870
871 return remove;
872 }
873
874 public static void addCommanderAndOfficers(CampaignFleetAPI fleet, FleetParamsV3 params, Random random) {
875 if (true) {
876 addCommanderAndOfficersV2(fleet, params, random);
877 return;
878 }
879 }
880
881
882 public static void addCommanderAndOfficersV2(CampaignFleetAPI fleet, FleetParamsV3 params, Random random) {
883 addCommanderAndOfficersV2(fleet, params, random, false, false);
884 }
885 public static void addCommanderAndOfficersV2(CampaignFleetAPI fleet, FleetParamsV3 params, Random random, boolean simFleet, boolean putOfficersOnCivShips) {
886
887 if (!simFleet) {
888 GenerateFleetOfficersPickData pickData = new GenerateFleetOfficersPickData(fleet, params);
890 if (genPlugin != null) {
891 genPlugin.addCommanderAndOfficers(fleet, params, random);
892 return;
893 }
894 }
895
896 FactionAPI faction = fleet.getFaction();
897 FactionDoctrineAPI doctrine = faction.getDoctrine();
898 if (params.doctrineOverride != null) {
899 doctrine = params.doctrineOverride;
900 }
901 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
902 if (members.isEmpty()) return;
903
904 float combatPoints = 0f;
905 float combatShips = 0f;
906 for (FleetMemberAPI member : members) {
907 if (member.isCivilian() && !putOfficersOnCivShips) continue;
908 if (member.isFighterWing()) continue;
909 combatPoints += member.getFleetPointCost();
910 combatShips++;
911 }
912 if (combatPoints < 1f) combatPoints = 1f;
913 if (combatShips < 1f) combatShips = 1f;
914
915 boolean debug = true;
916 debug = false;
917
918
919 int maxCommanderLevel = Global.getSettings().getInt("maxAIFleetCommanderLevel");
920 float mercMult = Global.getSettings().getFloat("officerAIMaxMercsMult");
921 //float mercFP = Global.getSettings().getFloat("officerAIMercsStartingFP");
922 int maxOfficers = Global.getSettings().getInt("officerAIMax");
923 int baseMaxOfficerLevel = Global.getSettings().getInt("officerMaxLevel");
925
926 float officerQualityMult = (doctrine.getOfficerQuality() - 1f) / 4f;
927 if (officerQualityMult > 1f) officerQualityMult = 1f;
928
929// float baseFPPerOfficer = Global.getSettings().getFloat("baseFPPerOfficer");
930// float fpPerBaseOfficer = baseFPPerOfficer - (baseFPPerOfficer * 0.5f * officerQualityMult);
931// float fpPerExtraOfficer = fpPerBaseOfficer * 1f;
932
933 float baseShipsForMaxOfficerLevel = Global.getSettings().getFloat("baseCombatShipsForMaxOfficerLevel");
934 float baseCombatShipsPerOfficer = Global.getSettings().getFloat("baseCombatShipsPerOfficer");
935 float combatShipsPerOfficer = baseCombatShipsPerOfficer * (1f - officerQualityMult * 0.5f);
936
937 //float fleetSizeOfficerQualityMult = combatPoints / (fpPerBaseOfficer * maxOfficers);
938 float fleetSizeOfficerQualityMult = combatShips / (baseShipsForMaxOfficerLevel * (1f - officerQualityMult * 0.5f));
939 if (fleetSizeOfficerQualityMult > 1) fleetSizeOfficerQualityMult = 1;
940
941 maxOfficers += (int)((float)doctrine.getOfficerQuality() * mercMult) + params.officerNumberBonus;
942
943 //int numOfficers = (int) (combatPoints / fpPerBaseOfficer) + params.officerNumberBonus;
944 int numOfficers = (int) Math.min(maxOfficers, combatShips / combatShipsPerOfficer);
945 //numOfficers += (int) Math.max(0, (combatPoints - mercFP) / fpPerExtraOfficer);
946 numOfficers += params.officerNumberBonus;
947 numOfficers = Math.round(numOfficers * params.officerNumberMult);
948
949 if (debug) System.out.println("numOfficers: " + numOfficers);
950
951
952// if (params.maxOfficers >= 0) maxOfficers = params.maxOfficers;
953// if (params.minOfficers >= 0 && numOfficers < params.minOfficers) numOfficers = params.minOfficers;
954
955 if (numOfficers > maxOfficers) numOfficers = maxOfficers;
956
957 if (params.commander != null && params.commander.isPlayer()) {
958 numOfficers = (int) params.commander.getStats().getOfficerNumber().getModifiedInt();
959 }
960 if (params.maxOfficersToAdd != null) {
961 numOfficers = Math.min(numOfficers, params.maxOfficersToAdd);
962 }
963
964 //int maxOfficerLevel = (int) Math.round((officerQualityMult * 0.75f + fleetSizeOfficerQualityMult * 1f) * (float) baseMaxOfficerLevel);
965 int maxOfficerLevel = (int)Math.round(((float)doctrine.getOfficerQuality() / 2f) +
966 (fleetSizeOfficerQualityMult * 1f) * (float) baseMaxOfficerLevel);
967 if (maxOfficerLevel < 1) maxOfficerLevel = 1;
968 maxOfficerLevel += params.officerLevelBonus;
969 if (maxOfficerLevel < 1) maxOfficerLevel = 1;
970
971 if (debug) System.out.println("maxOfficers: " + maxOfficers);
972 if (debug) System.out.println("maxOfficerLevel: " + maxOfficerLevel);
973
974
977
978 int maxSize = 0;
979 for (FleetMemberAPI member : members) {
980 if (member.isFighterWing()) continue;
981 if (member.isFlagship()) continue;
982 if (member.isCivilian() && !putOfficersOnCivShips) continue;
983 if (!member.getCaptain().isDefault()) continue;
984 int size = member.getHullSpec().getHullSize().ordinal();
985 if (size > maxSize) {
986 maxSize = size;
987 }
988 }
989 //maxSize = 2;
990 for (FleetMemberAPI member : members) {
991 if (member.isFighterWing()) continue;
992 if (member.isFlagship()) continue;
993 if (member.isCivilian() && !putOfficersOnCivShips) continue;
994 if (!member.getCaptain().isDefault()) continue;
995
996 float weight = (float) member.getFleetPointCost();
997 int size = member.getHullSpec().getHullSize().ordinal();
998 if (size >= maxSize) {
999 flagshipPicker.add(member, weight);
1000 }
1001
1002 picker.add(member, weight);
1003 }
1004
1005 if (picker.isEmpty()) {
1006 picker.add(members.get(0), 1f);
1007 }
1008 if (flagshipPicker.isEmpty()) {
1009 flagshipPicker.add(members.get(0), 1f);
1010 }
1011
1012
1013 FleetMemberAPI flagship = flagshipPicker.pickAndRemove();
1014 if (!simFleet) picker.remove(flagship);
1015 int commanderLevel = maxOfficerLevel;
1016 int commanderLevelLimit = maxCommanderLevel;
1017// if (simFleet) {
1018// commanderLevelLimit = maxOfficerLevel;
1019// }
1020// if (commanderLevelLimit > params.officerLevelLimit) commanderLevelLimit = params.officerLevelLimit;
1021// if (commanderLevelLimit > maxCommanderLevel) commanderLevelLimit = maxCommanderLevel;
1022 if (params.commanderLevelLimit != 0) {
1023 commanderLevelLimit = params.commanderLevelLimit;
1024 }
1025 if (commanderLevel > commanderLevelLimit) commanderLevel = commanderLevelLimit;
1026
1027 SkillPickPreference pref = getSkillPrefForShip(flagship);
1028 PersonAPI commander = params.commander;
1029 if (commander == null) {
1030 commander = OfficerManagerEvent.createOfficer(fleet.getFaction(), commanderLevel, pref, false, null, true, true, -1, random);
1031 if (commander.getPersonalityAPI().getId().equals(Personalities.TIMID)) {
1033 }
1034 addCommanderSkills(commander, fleet, params, random);
1035 }
1036 if (params.commander == null) {
1037 commander.setRankId(Ranks.SPACE_COMMANDER);
1039 }
1040 fleet.setCommander(commander);
1041 if (simFleet) {
1042 //numOfficers++;
1043 } else {
1044 fleet.getFleetData().setFlagship(flagship);
1045 }
1046
1047 int commanderOfficerLevelBonus = (int) commander.getStats().getDynamic().getMod(Stats.OFFICER_MAX_LEVEL_MOD).computeEffective(0);
1048 int officerLevelLimit = plugin.getMaxLevel(null) + commanderOfficerLevelBonus;
1049 //if (officerLevelLimit > params.officerLevelLimit) officerLevelLimit = params.officerLevelLimit;
1050 if (params.officerLevelLimit != 0) {
1051 officerLevelLimit = params.officerLevelLimit;
1052 }
1053
1054 if (debug) {
1055 System.out.println("Created level " + commander.getStats().getLevel() + " commander");
1056 System.out.println("Max officer level bonus: " + commanderOfficerLevelBonus + " (due to commander skill)");
1057 System.out.println("Adding up to " + numOfficers + " officers");
1058 }
1059
1060 int added = 0;
1061 for (int i = 0; i < numOfficers; i++) {
1062 FleetMemberAPI member = picker.pickAndRemove();
1063 if (member == null) {
1064 break; // out of ships that need officers
1065 }
1066
1067 int level = maxOfficerLevel - random.nextInt(3);
1068 if (Misc.isEasy()) {
1069 level = (int) Math.ceil((float) level * Global.getSettings().getFloat("easyOfficerLevelMult"));
1070 }
1071 if (level < 1) level = 1;
1072// if (level >= 7) {
1073// System.out.println("4fefewfwe");
1074// }
1075 if (level > officerLevelLimit) level = officerLevelLimit;
1076 if (params.commander != null && params.commander.isPlayer()) {
1078 }
1079
1080 pref = getSkillPrefForShip(member);
1081 PersonAPI person = OfficerManagerEvent.createOfficer(fleet.getFaction(), level, pref, false, fleet, true, true, -1, random);
1082 if (person.getPersonalityAPI().getId().equals(Personalities.TIMID)) {
1084 }
1085
1086// if (person.getStats().getLevel() >= 7) {
1087// System.out.println("4fefewfwe");
1088// }
1089
1090 if (debug) {
1091 System.out.println("Added level " + person.getStats().getLevel() + " officer");
1092 }
1093 added++;
1094 member.setCaptain(person);
1095
1096 if (params.commander != null && params.commander.isPlayer()) {
1097 fleet.getFleetData().addOfficer(person);
1098 }
1099 }
1100
1101 if (debug) {
1102 System.out.println("Added " + added + " officers total");
1103 }
1104
1105 }
1106
1107 public static SkillPickPreference getSkillPrefForShip(FleetMemberAPI member) {
1108 float energy = 0f;
1109 float ballistic = 0f;
1110 float missile = 0f;
1111 float total = 0f;
1112
1113 for (WeaponSlotAPI slot : member.getHullSpec().getAllWeaponSlotsCopy()) {
1114 float w = 1f;
1115 switch (slot.getSlotSize()) {
1116 case LARGE: w = 4f; break;
1117 case MEDIUM: w = 2f; break;
1118 case SMALL: w = 1f; break;
1119 }
1120 WeaponType type = slot.getWeaponType();
1121 if (type == WeaponType.BALLISTIC || type == WeaponType.HYBRID) {
1122 ballistic += w;
1123 total += w;
1124 } else if (type == WeaponType.ENERGY) {
1125 energy += w;
1126 total += w;
1127 } else if (type == WeaponType.MISSILE || type == WeaponType.SYNERGY || type == WeaponType.COMPOSITE) {
1128 missile += w;
1129 total += w;
1130 }
1131 }
1132
1133 if (total <= 0f) total = 1f;
1134
1135 boolean e = energy >= total * 0.33f;
1136 boolean b = ballistic >= total * 0.33f;
1137 if (b && e) {
1138 if (ballistic * 1.5f >= energy) {
1139 e = false;
1140 } else {
1141 b = false;
1142 }
1143 }
1144 boolean m = missile >= total * 0.17f;
1145
1146 boolean d = member.getHullSpec().getShieldType() == ShieldType.FRONT ||
1147 member.getHullSpec().getShieldType() == ShieldType.OMNI ||
1148 member.getHullSpec().isPhase();
1149
1150 // doing things in this, ah, "elegant" way to keep method signatures the same for now...
1151 String n1 = e ? "YES_ENERGY" : "NO_ENERGY";
1152 String n2 = b ? "YES_BALLISTIC" : "NO_BALLISTIC";
1153 String n3 = m ? "YES_MISSILE" : "NO_MISSILE";
1154 String n4 = d ? "YES_DEFENSE" : "NO_DEFENSE";
1155 SkillPickPreference pref = SkillPickPreference.valueOf(n1 + "_" + n2 + "_" + n3 + "_" + n4);
1156
1157 return pref;
1158 }
1159
1160
1161 public static void addCommanderSkills(PersonAPI commander, CampaignFleetAPI fleet, FleetParamsV3 params, Random random) {
1162 if (params != null && params.noCommanderSkills != null && params.noCommanderSkills) return;
1163
1164 if (random == null) random = new Random();
1165
1166 MutableCharacterStatsAPI stats = commander.getStats();
1167 int level = stats.getLevel();
1168
1169 int forOne = Global.getSettings().getInt("commanderLevelForOneSkill");
1170 int forTwo = Global.getSettings().getInt("commanderLevelForTwoSkills");
1171
1172 int numSkills = 0;
1173 if (level >= forTwo) {
1174 numSkills = 2;
1175 } else if (level >= forOne) {
1176 numSkills = 1;
1177 }
1178
1179 if (numSkills <= 0) return;
1180
1181 FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
1182 if (params != null && params.doctrineOverride != null) {
1183 doctrine = params.doctrineOverride;
1184 }
1185
1186 List<String> skills = new ArrayList<String>(doctrine.getCommanderSkills());
1187
1188 Iterator<String> iter = skills.iterator();
1189 while (iter.hasNext()) {
1190 String id = iter.next();
1192 if (spec != null && spec.hasTag(Skills.TAG_PLAYER_ONLY)) {
1193 iter.remove();
1194 }
1195 }
1196
1197
1198 if (skills.isEmpty()) return;
1199
1200 if (random.nextFloat() < doctrine.getCommanderSkillsShuffleProbability()) {
1201 Collections.shuffle(skills, random);
1202 }
1203
1204 stats.setSkipRefresh(true);
1205
1206 boolean debug = true;
1207 debug = false;
1208 if (debug) System.out.println("Generating commander skills, person level " + stats.getLevel() + ", skills: " + numSkills);
1209 int picks = 0;
1210 for (String skillId : skills) {
1211 if (debug) System.out.println("Selected skill: [" + skillId + "]");
1212 stats.setSkillLevel(skillId, 1);
1213 picks++;
1214 if (picks >= numSkills) {
1215 break;
1216 }
1217 }
1218 if (debug) System.out.println("Done generating commander skills\n");
1219
1220 stats.setSkipRefresh(false);
1222 }
1223
1224
1225 public static float getMemberWeight(FleetMemberAPI member) {
1226 boolean nonCombat = member.getVariant().isCivilian();
1227 float weight = 0;
1228 switch (member.getVariant().getHullSize()) {
1229 case CAPITAL_SHIP: weight += 8; break;
1230 case CRUISER: weight += 4; break;
1231 case DESTROYER: weight += 2; break;
1232 case FRIGATE: weight += 1; break;
1233 case FIGHTER: weight += 1; break;
1234 }
1235 if (nonCombat) weight *= 0.1f;
1236 return weight;
1237 }
1238
1239
1240
1241
1242 public static MarketAPI pickMarket(FleetParamsV3 params) {
1243 if (params.source != null) return params.source;
1244 if (params.locInHyper == null) return null;
1245
1246 List<MarketAPI> allMarkets = Global.getSector().getEconomy().getMarketsCopy();
1247
1248 int size = getMinPreferredMarketSize(params);
1249 float distToClosest = Float.MAX_VALUE;
1250 MarketAPI closest = null;
1251 float distToClosestMatchingSize = Float.MAX_VALUE;
1252 MarketAPI closestMatchingSize = null;
1253
1254
1255 FactionAPI creationFaction = Global.getSector().getFaction(params.factionId);
1256 boolean independent = Factions.INDEPENDENT.equals(params.factionId) ||
1257 Factions.SCAVENGERS.equals(params.factionId) ||
1259
1260 for (MarketAPI market : allMarkets) {
1261 if (market.getPrimaryEntity() == null) continue;
1262
1263 if (independent) {
1264 boolean hostileToIndependent = market.getFaction().isHostileTo(Factions.INDEPENDENT);
1265 if (hostileToIndependent) continue;
1266 } else {
1267 if (!market.getFactionId().equals(params.factionId)) continue;
1268 }
1269
1270 float currDist = Misc.getDistance(market.getPrimaryEntity().getLocationInHyperspace(),
1271 params.locInHyper);
1272 if (currDist < distToClosest) {
1273 distToClosest = currDist;
1274 closest = market;
1275 }
1276
1277 if (market.getSize() >= size && currDist < distToClosestMatchingSize) {
1278 distToClosestMatchingSize = currDist;
1279 closestMatchingSize = market;
1280 }
1281 }
1282
1283 if (closestMatchingSize != null) {
1284 return closestMatchingSize;
1285 }
1286
1287 if (closest != null) {
1288 return closest;
1289 }
1290
1291// MarketAPI temp = Global.getFactory().createMarket("temp", "Temp", size);
1292// temp.setFactionId(params.factionId);
1293// return temp;
1294 return null;
1295 }
1296
1297 public static int getMinPreferredMarketSize(FleetParamsV3 params) {
1298 float fp = params.getTotalPts();
1299
1300 if (fp <= 20) return 1;
1301 if (fp <= 50) return 3;
1302 if (fp <= 100) return 5;
1303 if (fp <= 150) return 7;
1304
1305 return 8;
1306 }
1307
1308
1309
1310
1311 private static List<String> startingAbilities = null;
1312 public static CampaignFleetAPI createEmptyFleet(String factionId, String fleetType, MarketAPI market) {
1313 FactionAPI faction = Global.getSector().getFaction(factionId);
1314 String fleetName = faction.getFleetTypeName(fleetType);
1315 CampaignFleetAPI fleet = Global.getFactory().createEmptyFleet(factionId, fleetName, true);
1317
1318 if (market != null && !market.getId().equals("fake")) {
1320 }
1321
1322 if (startingAbilities == null) {
1323 startingAbilities = new ArrayList<String>();
1324 for (String id : Global.getSettings().getSortedAbilityIds()) {
1326 if (spec.isAIDefault()) {
1327 startingAbilities.add(id);
1328 }
1329 }
1330 }
1331
1332 for (String id : startingAbilities) {
1333 fleet.addAbility(id);
1334 }
1335
1336 return fleet;
1337 }
1338
1339 public static class FPRemaining {
1340 public int fp;
1341
1342 public FPRemaining(int fp) {
1343 this.fp = fp;
1344 }
1345 public FPRemaining() {
1346 }
1347 }
1348
1349 public static float addToFleet(String role, MarketAPI market, Random random, CampaignFleetAPI fleet, int maxFP, FleetParamsV3 params) {
1350 float total = 0f;
1351 List<ShipRolePick> picks = market.pickShipsForRole(role, fleet.getFaction().getId(),
1352 new ShipPickParams(params.mode, maxFP, params.timestamp, params.blockFallback), random, null);
1353 for (ShipRolePick pick : picks) {
1354 total += addToFleet(pick, fleet, random);
1355 }
1356 return total;
1357 }
1358
1359 protected static float addToFleet(ShipRolePick pick, CampaignFleetAPI fleet, Random random) {
1361 String name = fleet.getFleetData().pickShipName(member, random);
1362 member.setShipName(name);
1363 fleet.getFleetData().addFleetMember(member);
1364 return member.getFleetPointCost();
1365 }
1366
1367// public static float addCombatFleetPoints(CampaignFleetAPI fleet, Random random,
1368// float fp, FleetParamsV3 params) {
1369// FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
1370// if (params.doctrineOverride != null) {
1371// doctrine = params.doctrineOverride;
1372// }
1373//
1374// int size = doctrine.getShipSize();
1375//
1376// boolean addedSomething = true;
1377// FPRemaining rem = new FPRemaining();
1378// rem.fp = (int) fp;
1379//
1380// String smallRole = ShipRoles.COMBAT_SMALL_FOR_SMALL_FLEET;
1381// if (!params.banPhaseShipsEtc) {
1382// smallRole = ShipRoles.COMBAT_SMALL;
1383// }
1384//
1385// while (addedSomething && rem.fp > 0) {
1386// int small = BASE_COUNTS_WITH_4[size - 1][0] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][0] + 1);
1387// int medium = BASE_COUNTS_WITH_4[size - 1][1] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][1] + 1);
1388// int large = BASE_COUNTS_WITH_4[size - 1][2] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][2] + 1);
1389// int capital = BASE_COUNTS_WITH_4[size - 1][3] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][3] + 1);
1390//
1393//
1394// if (params.maxShipSize <= 1) medium = 0;
1395// if (params.maxShipSize <= 2) large = 0;
1396// if (params.maxShipSize <= 3) capital = 0;
1397//
1398// int smallPre = small / 2;
1399// small -= smallPre;
1400//
1401// int mediumPre = medium / 2;
1402// medium -= mediumPre;
1403//
1404// addedSomething = false;
1405//
1406// addedSomething |= addShips(smallRole, smallPre, params.source, random, fleet, rem, params);
1407//
1408// addedSomething |= addShips(ShipRoles.COMBAT_MEDIUM, mediumPre, params.source, random, fleet, rem, params);
1409// addedSomething |= addShips(smallRole, small, params.source, random, fleet, rem, params);
1410//
1411// addedSomething |= addShips(ShipRoles.COMBAT_LARGE, large, params.source, random, fleet, rem, params);
1412// addedSomething |= addShips(ShipRoles.COMBAT_MEDIUM, medium, params.source, random, fleet, rem, params);
1413//
1414// addedSomething |= addShips(ShipRoles.COMBAT_CAPITAL, capital, params.source, random, fleet, rem, params);
1415// }
1416//
1417// return fp - rem.fp;
1418// }
1419
1420 public static boolean addShips(String role, int count, MarketAPI market, Random random, CampaignFleetAPI fleet, FPRemaining rem, FleetParamsV3 params) {
1421 boolean addedSomething = false;
1422 for (int i = 0; i < count; i++) {
1423 if (rem.fp <= 0) break;
1424 float added = addToFleet(role, market, random, fleet, rem.fp, params);
1425 if (added > 0) {
1426 rem.fp -= added;
1427 addedSomething = true;
1428 }
1429 }
1430 return addedSomething;
1431 }
1432
1433
1434 public static float addPhaseFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1435 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.SMALL_IS_FRIGATE,
1437// FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
1438// if (params.doctrineOverride != null) {
1439// doctrine = params.doctrineOverride;
1440// }
1441//
1442// int size = doctrine.getShipSize();
1443//
1444// boolean addedSomething = true;
1445// FPRemaining rem = new FPRemaining();
1446// rem.fp = (int) fp;
1447//
1448// while (addedSomething && rem.fp > 0) {
1449// int small = BASE_COUNTS_WITH_3[size - 1][0] + random.nextInt(MAX_EXTRA_WITH_3[size - 1][0] + 1);
1450// int medium = BASE_COUNTS_WITH_3[size - 1][1] + random.nextInt(MAX_EXTRA_WITH_3[size - 1][1] + 1);
1451// int large = BASE_COUNTS_WITH_3[size - 1][2] + random.nextInt(MAX_EXTRA_WITH_3[size - 1][2] + 1);
1452//
1453// //System.out.println(String.format("Small: %s Medium: %s Large: %s Capital: %s",
1454// //"" + small, "" + medium, "" + large, "" + capital));
1455//
1456// if (params.maxShipSize <= 1) medium = 0;
1457// if (params.maxShipSize <= 2) large = 0;
1458//
1459// int smallPre = small / 2;
1460// small -= smallPre;
1461//
1462// int mediumPre = medium / 2;
1463// medium -= mediumPre;
1464//
1465// addedSomething = false;
1466//
1467// addedSomething |= addShips(ShipRoles.PHASE_SMALL, smallPre, params.source, random, fleet, rem, params);
1468//
1469// addedSomething |= addShips(ShipRoles.PHASE_MEDIUM, mediumPre, params.source, random, fleet, rem, params);
1470// addedSomething |= addShips(ShipRoles.PHASE_SMALL, small, params.source, random, fleet, rem, params);
1471//
1472// addedSomething |= addShips(ShipRoles.PHASE_LARGE, large, params.source, random, fleet, rem, params);
1473// addedSomething |= addShips(ShipRoles.PHASE_MEDIUM, medium, params.source, random, fleet, rem, params);
1474// }
1475//
1476// return fp - rem.fp;
1477 }
1478
1479 public static enum SizeFilterMode {
1480 NONE,
1481 SMALL_IS_FRIGATE,
1482 SMALL_IS_DESTROYER,
1483 }
1484 public static float addCarrierFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1485 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.SMALL_IS_DESTROYER,
1487 }
1488 public static float addPriorityOnlyThenAll(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params,
1489 SizeFilterMode sizeFilterMode,
1490 String roleSmall, String roleMedium, String roleLarge) {
1491 if (fp <= 0) return 0f;
1492
1493 float added = 0f;
1494 if (params.mode == ShipPickMode.PRIORITY_THEN_ALL) {
1495 int numPriority = fleet.getFaction().getNumAvailableForRole(roleSmall, ShipPickMode.PRIORITY_ONLY) +
1496 fleet.getFaction().getNumAvailableForRole(roleMedium, ShipPickMode.PRIORITY_ONLY) +
1497 fleet.getFaction().getNumAvailableForRole(roleLarge, ShipPickMode.PRIORITY_ONLY);
1498
1499 if (numPriority > 0) {
1500 params.mode = ShipPickMode.PRIORITY_ONLY;
1501 added = addFleetPoints(fleet, random, fp, params, sizeFilterMode,
1502 roleSmall, roleMedium, roleLarge);
1503 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1504 } else {
1505 params.mode = ShipPickMode.ALL;
1506 added = addFleetPoints(fleet, random, fp, params, sizeFilterMode,
1507 roleSmall, roleMedium, roleLarge);
1508 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1509 }
1510 // if there ARE priority ships for a 3-type category (i.e. carriers/phases/various civs,
1511 // then ONLY use priority, and use nothing if a priority ship was not added (since that just means not enough FP
1512 // for likely a smaller fleet.)
1513// if (added <= 0) {
1514// added = addFleetPoints(fleet, random, fp, params, sizeFilterMode,
1515// roleSmall, roleMedium, roleLarge);
1516// }
1517 } else {
1518 added = addFleetPoints(fleet, random, fp, params, sizeFilterMode,
1519 roleSmall, roleMedium, roleLarge);
1520 }
1521 return added;
1522 }
1523
1524 public static float addTankerFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1525 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.SMALL_IS_DESTROYER,
1527 }
1528
1529 public static float addFreighterFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1530 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.NONE,
1532 }
1533
1534 public static float addLinerFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1535 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.NONE,
1537 }
1538
1539 public static float addCombatFreighterFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1540 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.SMALL_IS_FRIGATE,
1542 }
1543
1544 public static float addTransportFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1545 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.NONE,
1547 }
1548
1549 public static float addUtilityFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params) {
1550 return addPriorityOnlyThenAll(fleet, random, fp, params, SizeFilterMode.NONE,
1552 }
1553
1554
1555 protected static int sizeOverride = 0;
1556 // tend towards larger ships as fleets get more members, regardless of doctrine
1557 public static int getAdjustedDoctrineSize(int size, CampaignFleetAPI fleetSoFar) {
1558 if (sizeOverride > 0) return sizeOverride;
1559 else return size;
1560
1561// int num = fleetSoFar.getNumMembersFast();
1562// if (num > 8 && size <= 2) {
1563// size++;
1564// }
1565// if (num > 14 && size <= 3) {
1566// size++;
1567// }
1568// if (num > 20 && size <= 4) {
1569// size++;
1570// }
1571// if (size > 5) size = 5;
1572// return size;
1573 }
1574
1575
1576 public static float addFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params,
1577 SizeFilterMode sizeFilterMode,
1578 String ... roles) {
1579 FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
1580 if (params.doctrineOverride != null) {
1581 doctrine = params.doctrineOverride;
1582 }
1583
1584 int size = doctrine.getShipSize();
1585 //size = getAdjustedDoctrineSize(size, fleet);
1586
1587 boolean addedSomething = true;
1588 FPRemaining rem = new FPRemaining();
1589 rem.fp = (int) fp;
1590
1591 while (addedSomething && rem.fp > 0) {
1592 size = getAdjustedDoctrineSize(size, fleet);
1593
1594 int small = BASE_COUNTS_WITH_3[size - 1][0] + random.nextInt(MAX_EXTRA_WITH_3[size - 1][0] + 1);
1595 int medium = BASE_COUNTS_WITH_3[size - 1][1] + random.nextInt(MAX_EXTRA_WITH_3[size - 1][1] + 1);
1596 int large = BASE_COUNTS_WITH_3[size - 1][2] + random.nextInt(MAX_EXTRA_WITH_3[size - 1][2] + 1);
1597
1598// if (sizeOverride > 0) {
1599// small = 0;
1600// medium = 0;
1601// }
1602
1603 if (sizeFilterMode == SizeFilterMode.SMALL_IS_FRIGATE) {
1604 if (params.maxShipSize <= 1) medium = 0;
1605 if (params.maxShipSize <= 2) large = 0;
1606 } else if (sizeFilterMode == SizeFilterMode.SMALL_IS_DESTROYER) {
1607 if (params.maxShipSize <= 2) medium = 0;
1608 if (params.maxShipSize <= 3) large = 0;
1609 }
1610
1611 //System.out.println(String.format("Small: %s Medium: %s Large: %s Capital: %s",
1612 //"" + small, "" + medium, "" + large, "" + capital));
1613
1614 int smallPre = small / 2;
1615 small -= smallPre;
1616
1617 int mediumPre = medium / 2;
1618 medium -= mediumPre;
1619
1620 addedSomething = false;
1621
1622 addedSomething |= addShips(roles[0], smallPre, params.source, random, fleet, rem, params);
1623
1624 addedSomething |= addShips(roles[1], mediumPre, params.source, random, fleet, rem, params);
1625 addedSomething |= addShips(roles[0], small, params.source, random, fleet, rem, params);
1626
1627 addedSomething |= addShips(roles[2], large, params.source, random, fleet, rem, params);
1628 addedSomething |= addShips(roles[1], medium, params.source, random, fleet, rem, params);
1629 }
1630
1631 return fp - rem.fp;
1632 }
1633
1634
1635
1636
1637
1638 public static void addCombatFleetPoints(CampaignFleetAPI fleet, Random random,
1639 float warshipFP, float carrierFP, float phaseFP, FleetParamsV3 params) {
1640
1641 FactionAPI faction = fleet.getFaction();
1642 FactionDoctrineAPI doctrine = faction.getDoctrine();
1643 if (params.doctrineOverride != null) {
1644 doctrine = params.doctrineOverride;
1645 }
1646
1651 WeightedRandomPicker<String> priorityCapitalPicker = new WeightedRandomPicker<String>(random);
1652
1653 String smallRole = ShipRoles.COMBAT_SMALL_FOR_SMALL_FLEET;
1654 if (!params.banPhaseShipsEtc) {
1655 smallRole = ShipRoles.COMBAT_SMALL;
1656 }
1657
1658// if (warshipFP > 0) smallPicker.add(smallRole, 1);
1659// if (phaseFP > 0) smallPicker.add(ShipRoles.PHASE_SMALL, 1);
1660//
1661// if (warshipFP > 0) mediumPicker.add(ShipRoles.COMBAT_MEDIUM, 1);
1662// if (phaseFP > 0) mediumPicker.add(ShipRoles.PHASE_MEDIUM, 1);
1663// if (carrierFP > 0) mediumPicker.add(ShipRoles.CARRIER_SMALL, 1);
1664//
1665// if (warshipFP > 0) largePicker.add(ShipRoles.COMBAT_LARGE, 1);
1666// if (phaseFP > 0) largePicker.add(ShipRoles.PHASE_LARGE, 1);
1667// if (carrierFP > 0) largePicker.add(ShipRoles.CARRIER_MEDIUM, 1);
1668//
1669// if (warshipFP > 0) capitalPicker.add(ShipRoles.COMBAT_CAPITAL, 1);
1670// if (phaseFP > 0) capitalPicker.add(ShipRoles.PHASE_CAPITAL, 1);
1671// if (carrierFP > 0) capitalPicker.add(ShipRoles.CARRIER_LARGE, 1);
1672
1673 smallPicker.add(smallRole, warshipFP);
1674 smallPicker.add(ShipRoles.PHASE_SMALL, phaseFP);
1675
1676 mediumPicker.add(ShipRoles.COMBAT_MEDIUM, warshipFP);
1677 mediumPicker.add(ShipRoles.PHASE_MEDIUM, phaseFP);
1678 mediumPicker.add(ShipRoles.CARRIER_SMALL, carrierFP);
1679
1680 largePicker.add(ShipRoles.COMBAT_LARGE, warshipFP);
1681 largePicker.add(ShipRoles.PHASE_LARGE, phaseFP);
1682 largePicker.add(ShipRoles.CARRIER_MEDIUM, carrierFP);
1683
1684 capitalPicker.add(ShipRoles.COMBAT_CAPITAL, warshipFP);
1685 capitalPicker.add(ShipRoles.PHASE_CAPITAL, phaseFP);
1686 capitalPicker.add(ShipRoles.CARRIER_LARGE, carrierFP);
1687
1688
1689 Set<String> usePriorityOnly = new HashSet<String>();
1690
1691 if (params.mode == ShipPickMode.PRIORITY_THEN_ALL) {
1692 float num = faction.getVariantWeightForRole(ShipRoles.COMBAT_CAPITAL, ShipPickMode.PRIORITY_ONLY);
1693 if (num > 0) {
1694 //priorityCapitalPicker.add(ShipRoles.COMBAT_CAPITAL, doctrine.getWarships() + 1);
1695 priorityCapitalPicker.add(ShipRoles.COMBAT_CAPITAL, num);
1696 }
1697 num = faction.getVariantWeightForRole(ShipRoles.CARRIER_LARGE, ShipPickMode.PRIORITY_ONLY);
1698 if (num > 0) {
1699 //priorityCapitalPicker.add(ShipRoles.CARRIER_LARGE, doctrine.getCarriers() + 1);
1700 priorityCapitalPicker.add(ShipRoles.CARRIER_LARGE, num);
1701 }
1702 num = faction.getVariantWeightForRole(ShipRoles.PHASE_CAPITAL, ShipPickMode.PRIORITY_ONLY);
1703 if (num > 0) {
1704 //priorityCapitalPicker.add(ShipRoles.PHASE_CAPITAL, doctrine.getPhaseShips() + 1);
1705 priorityCapitalPicker.add(ShipRoles.PHASE_CAPITAL, num);
1706 }
1707
1708 if (params.mode == ShipPickMode.PRIORITY_THEN_ALL) {
1711 }
1712 }
1713
1714 Map<String, FPRemaining> remaining = new HashMap<String, FPRemaining>();
1715 FPRemaining remWarship = new FPRemaining((int)warshipFP);
1716 FPRemaining remCarrier = new FPRemaining((int)carrierFP);
1717 FPRemaining remPhase = new FPRemaining((int)phaseFP);
1718
1719 remaining.put(ShipRoles.COMBAT_SMALL_FOR_SMALL_FLEET, remWarship);
1720 remaining.put(ShipRoles.COMBAT_SMALL, remWarship);
1721 remaining.put(ShipRoles.COMBAT_MEDIUM, remWarship);
1722 remaining.put(ShipRoles.COMBAT_LARGE, remWarship);
1723 remaining.put(ShipRoles.COMBAT_CAPITAL, remWarship);
1724
1725 remaining.put(ShipRoles.CARRIER_SMALL, remCarrier);
1726 remaining.put(ShipRoles.CARRIER_MEDIUM, remCarrier);
1727 remaining.put(ShipRoles.CARRIER_LARGE, remCarrier);
1728
1729 remaining.put(ShipRoles.PHASE_SMALL, remPhase);
1730 remaining.put(ShipRoles.PHASE_MEDIUM, remPhase);
1731 remaining.put(ShipRoles.PHASE_LARGE, remPhase);
1732 remaining.put(ShipRoles.PHASE_CAPITAL, remPhase);
1733
1734
1735 if (params.maxShipSize <= 1) {
1736 mediumPicker.clear();
1737 }
1738 if (params.maxShipSize <= 2) {
1739 largePicker.clear();
1740 }
1741 if (params.maxShipSize <= 3) {
1742 capitalPicker.clear();
1743 }
1744
1745 if (params.minShipSize >= 2) {
1746 smallPicker.clear();
1747 }
1748 if (params.minShipSize >= 3) {
1749 mediumPicker.clear();
1750 }
1751 if (params.minShipSize >= 4) {
1752 largePicker.clear();
1753 }
1754
1755
1756 int size = doctrine.getShipSize();
1757 //size = getAdjustedDoctrineSize(size, fleet);
1758
1759 int numFails = 0;
1760 while (numFails < 2) {
1761 size = getAdjustedDoctrineSize(size, fleet);
1762
1763// if (size > 5) {
1764// System.out.println("wefwefe");
1765// }
1766
1767 int small = BASE_COUNTS_WITH_4[size - 1][0] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][0] + 1);
1768 int medium = BASE_COUNTS_WITH_4[size - 1][1] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][1] + 1);
1769 int large = BASE_COUNTS_WITH_4[size - 1][2] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][2] + 1);
1770 int capital = BASE_COUNTS_WITH_4[size - 1][3] + random.nextInt(MAX_EXTRA_WITH_4[size - 1][3] + 1);
1771
1772 if (size < 5 && capital > 1) {
1773 capital = 1;
1774 }
1775
1776 if (params.maxShipSize <= 1) medium = 0;
1777 if (params.maxShipSize <= 2) large = 0;
1778 if (params.maxShipSize <= 3) capital = 0;
1779
1780 if (params.minShipSize >= 2) small = 0;
1781 if (params.minShipSize >= 3) medium = 0;
1782 if (params.minShipSize >= 4) large = 0;
1783
1784 int smallPre = small / 2;
1785 small -= smallPre;
1786
1787 int mediumPre = medium / 2;
1788 medium -= mediumPre;
1789
1790 boolean addedSomething = false;
1791
1792 //System.out.println("Rem carrier pre: " + remCarrier.fp);
1793 addedSomething |= addShips(smallPicker, usePriorityOnly, remaining, null, smallPre, fleet, random, params);
1794 //System.out.println("Rem carrier after smallPre: " + remCarrier.fp);
1795 addedSomething |= addShips(mediumPicker, usePriorityOnly, remaining, null, mediumPre, fleet, random, params);
1796 //System.out.println("Rem carrier after mediumPre: " + remCarrier.fp);
1797 addedSomething |= addShips(smallPicker, usePriorityOnly, remaining, null, small, fleet, random, params);
1798 //System.out.println("Rem carrier after small: " + remCarrier.fp);
1799 addedSomething |= addShips(largePicker, usePriorityOnly, remaining, null, large, fleet, random, params);
1800 //System.out.println("Rem carrier after large: " + remCarrier.fp);
1801 addedSomething |= addShips(mediumPicker, usePriorityOnly, remaining, null, medium, fleet, random, params);
1802 //System.out.println("Rem carrier after medium: " + remCarrier.fp);
1803
1804
1805 if (!priorityCapitalPicker.isEmpty()) {
1806 params.mode = ShipPickMode.PRIORITY_ONLY;
1807 params.blockFallback = true;
1808 FPRemaining combined = new FPRemaining(remWarship.fp + remCarrier.fp + remPhase.fp);
1809 boolean addedCapital = addShips(priorityCapitalPicker, usePriorityOnly, remaining, combined, capital, fleet, random, params);
1810 addedSomething |= addedCapital;
1811 if (addedCapital) {
1812 redistributeFP(remWarship, remCarrier, remPhase, combined.fp);
1813 }
1814 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1815 params.blockFallback = null;
1816 //System.out.println("Rem carrier after capitals priority: " + remCarrier.fp);
1817 } else {
1818 addedSomething |= addShips(capitalPicker, usePriorityOnly, remaining, null, capital, fleet, random, params);
1819 //System.out.println("Rem carrier after capitals normal: " + remCarrier.fp);
1820 }
1821
1822 if (!addedSomething) {
1823 numFails++;
1824
1825 if (numFails == 2) {
1826 boolean goAgain = false;
1827 if (remPhase.fp > 0) {
1828 remWarship.fp += remPhase.fp;
1829 remPhase.fp = 0;
1830 goAgain = true;
1831 }
1832 if (remCarrier.fp > 0) {
1833 remWarship.fp += remCarrier.fp;
1834 remCarrier.fp = 0;
1835 goAgain = true;
1836 }
1837
1838 if (goAgain) {
1839 numFails = 0;
1840 smallPicker.add(smallRole, 1);
1841 mediumPicker.add(ShipRoles.COMBAT_MEDIUM, 1);
1842 largePicker.add(ShipRoles.COMBAT_LARGE, 1);
1843 capitalPicker.add(ShipRoles.COMBAT_CAPITAL, 1);
1844 }
1845 }
1846 }
1847 }
1848 }
1849
1850 protected static void addToPriorityOnlySet(CampaignFleetAPI fleet, Set<String> set, String small, String medium, String large) {
1851 int numPriority = fleet.getFaction().getNumAvailableForRole(small, ShipPickMode.PRIORITY_ONLY) +
1852 fleet.getFaction().getNumAvailableForRole(medium, ShipPickMode.PRIORITY_ONLY) +
1853 fleet.getFaction().getNumAvailableForRole(large, ShipPickMode.PRIORITY_ONLY);
1854 if (numPriority > 0) {
1855 set.add(small);
1856 set.add(medium);
1857 set.add(large);
1858 }
1859 }
1860
1861 protected static void redistributeFP(FPRemaining one, FPRemaining two, FPRemaining three, int newTotal) {
1862 float total = one.fp + two.fp + three.fp;
1863 if (total <= 0) return;
1864
1865 int f1 = (int) Math.round((float)one.fp / total * newTotal);
1866 int f2 = (int) Math.round((float)two.fp / total * newTotal);
1867 int f3 = (int) Math.round((float)three.fp / total * newTotal);
1868
1869 f1 += newTotal - f1 - f2 - f3;
1870
1871 one.fp = f1;
1872 two.fp = f2;
1873 three.fp = f3;
1874 }
1875
1876 public static boolean addShips(WeightedRandomPicker<String> rolePicker, Set<String> usePriorityOnly, Map<String, FPRemaining> remaining, FPRemaining remOverride, int count,
1877 CampaignFleetAPI fleet, Random random, FleetParamsV3 params) {
1878 if (rolePicker.isEmpty()) return false;
1879
1880 boolean addedSomething = false;
1881 for (int i = 0; i < count; i++) {
1882 String role = rolePicker.pick();
1883 if (role == null) break;
1884 FPRemaining rem = remaining.get(role);
1885 FPRemaining remForProperRole = rem;
1886 if (remOverride != null) rem = remOverride;
1887 if (usePriorityOnly.contains(role)) {
1888 params.mode = ShipPickMode.PRIORITY_ONLY;
1889 }
1890 int fpPrePick = rem.fp;
1891
1892 boolean added = addShips(role, 1, params.source, random, fleet, rem, params);
1893
1894 if (added && remOverride != null) {
1895 int fpSpent = fpPrePick - rem.fp;
1896 int maxToTakeFromProperRole = Math.min(remForProperRole.fp, fpSpent);
1897 remForProperRole.fp -= maxToTakeFromProperRole;
1898 }
1899
1900 if (usePriorityOnly.contains(role)) {
1901 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1902 }
1903 if (!added) {
1904 rolePicker.remove(role);
1905 i--;
1906 if (rolePicker.isEmpty()) {
1907 break;
1908 }
1909 }
1910 addedSomething |= added;
1911 }
1912 return addedSomething;
1913 }
1914
1915 public static float getShipDeficitFleetSizeMult(MarketAPI market) {
1916 float mult = 1f;
1918 float available = com.getAvailable();
1919 float demand = com.getMaxDemand();
1920 if (demand > 0) {
1921 float f = available / demand;
1923 mult *= f;
1924 }
1925 if (mult < 0) mult = 0;
1926 if (mult > 1) mult = 1;
1927 return mult;
1928 }
1929
1930
1931
1932 public static void addCommanderSkills(PersonAPI commander, CampaignFleetAPI fleet, Random random) {
1933 addCommanderSkills(commander, fleet, null, random);
1934 }
1935
1936
1937 public static void applyDamageToFleet(CampaignFleetAPI fleet, float damage,
1938 boolean damageRemainingShips, Random random) {
1939 if (random == null) random = Misc.random;
1941
1942 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
1943 for (FleetMemberAPI member : members) {
1944 float w = 1f;
1945 if (member.isCivilian()) w *= 0.25f;
1946
1947 picker.add(member, w);
1948 }
1949
1950 List<FleetMemberAPI> remove = new ArrayList<FleetMemberAPI>();
1951 float removedFP = 0f;
1952 float fpToRemove = fleet.getFleetPoints() * damage * 0.8f;
1953
1954 while (removedFP < fpToRemove && remove.size() < members.size() - 1 && !picker.isEmpty()) {
1955 FleetMemberAPI member = picker.pickAndRemove();
1956 removedFP += member.getFleetPointCost();
1957 remove.add(member);
1958 }
1959
1960 for (FleetMemberAPI member : remove) {
1961 fleet.getFleetData().removeFleetMember(member);
1962 }
1963
1964
1965 if (damageRemainingShips) {
1966 int numStrikes = (int) Math.round(picker.getItems().size() * damage);
1967
1968 for (int i = 0; i < numStrikes; i++) {
1969 FleetMemberAPI member = picker.pick();
1970 if (member == null) return;
1971
1972 if (random.nextFloat() > damage) continue;
1973
1974 float crPerDep = member.getDeployCost();
1975 //if (crPerDep <= 0) continue;
1976 float suppliesPerDep = member.getStats().getSuppliesToRecover().getModifiedValue();
1977 if (suppliesPerDep <= 0 || crPerDep <= 0) return;
1978 float suppliesPer100CR = suppliesPerDep * 1f / Math.max(0.01f, crPerDep);
1979
1980 float strikeSupplies = suppliesPer100CR * damage * (0.25f + 0.75f * random.nextFloat());
1981 float strikeDamage = strikeSupplies / suppliesPer100CR * (0.75f + (float) Math.random() * 0.5f);
1982
1985 }
1986
1987 if (strikeDamage > 0) {
1988 float currCR = member.getRepairTracker().getBaseCR();
1989 float crDamage = Math.min(currCR, strikeDamage);
1990
1991 member.getRepairTracker().setCR(currCR - crDamage);
1992
1993 float hitStrength = member.getStats().getArmorBonus().computeEffective(member.getHullSpec().getArmorRating());
1994 int numHits = (int) (strikeDamage / 0.1f);
1995 if (numHits < 1) numHits = 1;
1996 for (int j = 0; j < numHits; j++) {
1997 member.getStatus().applyDamage(hitStrength);
1998 }
1999
2000 if (member.getStatus().getHullFraction() < 0.01f) {
2001 member.getStatus().setHullFraction(0.01f);
2002 picker.remove(member);
2003 } else {
2004 float w = picker.getWeight(member);
2005 picker.setWeight(picker.getItems().indexOf(member), w * 0.5f);
2006 }
2007 }
2008 }
2009 }
2010 }
2011}
2012
2013
2014
2015
2016
2017
2018
2019
2020
static SettingsAPI getSettings()
Definition Global.java:57
static FactoryAPI getFactory()
Definition Global.java:41
static Logger getLogger(Class c)
Definition Global.java:32
static SectorAPI getSector()
Definition Global.java:65
void modifyFlat(String source, float value)
void modifyFlat(String source, float value)
float computeEffective(float baseValue)
AvailableOfficer createOfficer(boolean isMerc, MarketAPI market, Random random)
static void pruneFleet(int maxShips, int doctrineSize, CampaignFleetAPI fleet, float targetFP, Random random)
static float addFreighterFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static float addCarrierFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static void addCommanderSkills(PersonAPI commander, CampaignFleetAPI fleet, Random random)
static float addToFleet(String role, MarketAPI market, Random random, CampaignFleetAPI fleet, int maxFP, FleetParamsV3 params)
static void addCommanderAndOfficersV2(CampaignFleetAPI fleet, FleetParamsV3 params, Random random)
static List< FleetMemberAPI > getRemoveOrder(CampaignFleetAPI fleet)
static float addUtilityFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static float addTankerFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static void addCombatFleetPoints(CampaignFleetAPI fleet, Random random, float warshipFP, float carrierFP, float phaseFP, FleetParamsV3 params)
static void redistributeFP(FPRemaining one, FPRemaining two, FPRemaining three, int newTotal)
static void addCommanderAndOfficers(CampaignFleetAPI fleet, FleetParamsV3 params, Random random)
static void addCommanderAndOfficersV2(CampaignFleetAPI fleet, FleetParamsV3 params, Random random, boolean simFleet, boolean putOfficersOnCivShips)
static float getDoctrineNumShipsMult(int doctrineNumShips)
static SkillPickPreference getSkillPrefForShip(FleetMemberAPI member)
static int getAdjustedDoctrineSize(int size, CampaignFleetAPI fleetSoFar)
static void addToPriorityOnlySet(CampaignFleetAPI fleet, Set< String > set, String small, String medium, String large)
static CampaignFleetAPI createFleet(FleetParamsV3 params)
static float addPhaseFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static CampaignFleetAPI createEmptyFleet(String factionId, String fleetType, MarketAPI market)
static void applyDamageToFleet(CampaignFleetAPI fleet, float damage, boolean damageRemainingShips, Random random)
static float addLinerFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static void addAll(int[] ratio, List< FleetMemberAPI > from, LinkedHashSet< FleetMemberAPI > to, int num, Random random)
static float addFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params, SizeFilterMode sizeFilterMode, String ... roles)
static float addToFleet(ShipRolePick pick, CampaignFleetAPI fleet, Random random)
static boolean addShips(WeightedRandomPicker< String > rolePicker, Set< String > usePriorityOnly, Map< String, FPRemaining > remaining, FPRemaining remOverride, int count, CampaignFleetAPI fleet, Random random, FleetParamsV3 params)
static float addTransportFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static float addPriorityOnlyThenAll(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params, SizeFilterMode sizeFilterMode, String roleSmall, String roleMedium, String roleLarge)
static WeightedRandomPicker< HullSize > makePicker(int[] ratio, Random random)
static float addCombatFreighterFleetPoints(CampaignFleetAPI fleet, Random random, float fp, FleetParamsV3 params)
static void addCommanderSkills(PersonAPI commander, CampaignFleetAPI fleet, FleetParamsV3 params, Random random)
static boolean addShips(String role, int count, MarketAPI market, Random random, CampaignFleetAPI fleet, FPRemaining rem, FleetParamsV3 params)
static final String OFFICER_MAX_LEVEL_MOD
Definition Stats.java:9
static FleetInflater getInflater(CampaignFleetAPI fleet, Object params)
Definition Misc.java:4246
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static long getSalvageSeed(SectorEntityToken entity)
Definition Misc.java:4129
static void setSpawnFPMult(CampaignFleetAPI fleet, float mult)
Definition Misc.java:5797
static ShipPickMode getShipPickMode(MarketAPI market)
Definition Misc.java:4542
static boolean isEasy()
Definition Misc.java:2284
MarketAPI createMarket(String id, String name, int size)
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
FleetMemberAPI createFleetMember(FleetMemberType type, String variantOrWingId)
AbilitySpecAPI getAbilitySpec(String abilityId)
ShipVariantAPI getVariant(String variantId)
SkillSpecAPI getSkillSpec(String skillId)
List< String > getSortedAbilityIds()
void setInflater(FleetInflater inflater)
int getNumAvailableForRole(String roleId, ShipPickMode mode)
float getVariantWeightForRole(String roleId, ShipPickMode mode)
String pickShipName(FleetMemberAPI member, Random random)
void setOnlySyncMemberLists(boolean onlySyncMemberLists)
void setFlagship(FleetMemberAPI flagship)
void addFleetMember(FleetMemberAPI member)
void removeFleetMember(FleetMemberAPI member)
List< FleetMemberAPI > getMembersListCopy()
< T > T pickPlugin(Class< T > c, Object params)
SectorEntityToken createToken(float x, float y)
GenericPluginManagerAPI getGenericPlugins()
FactionAPI getFaction(String factionId)
List< ShipRolePick > pickShipsForRole(String role, ShipPickParams params, Random random, ShipFilter filter)
CommodityOnMarketAPI getCommodityData(String commodityId)
void setPrimaryEntity(SectorEntityToken primaryEntity)
void setCachedFaction(FactionAPI faction)
MutableStatWithTempMods getStability()
void set(String key, Object value)
MutableCharacterStatsAPI getStats()
void setPersonality(String personality)
List< WeaponSlotAPI > getAllWeaponSlotsCopy()
void setCaptain(PersonAPI commander)
void setVariant(ShipVariantAPI variant, boolean withRefit, boolean withStatsUpdate)
void addCommanderAndOfficers(CampaignFleetAPI fleet, FleetParamsV3 params, Random random)
CampaignFleetAPI createFleet(FleetParamsV3 params)