1package com.fs.starfarer.api.impl.campaign.fleets;
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;
12import java.util.Random;
15import org.apache.log4j.Logger;
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;
103 return (stability - 5f) * 0.05f;
106 return 1f + (stability - 5f) * 0.05f;
111 if (marketSize < 3) marketSize = 3;
133 switch ((
int)marketSize) {
135 case 4:
return 0.75f;
137 case 6:
return 1.25f;
139 case 8:
return 1.75f;
141 case 10:
return 2.5f;
144 return marketSize / 6f;
149 return 1f + (float) (doctrineNumShips - 1f) * (max - 1f) / 4f;
154 CreateFleetPlugin plugin =
Global.
getSector().getGenericPlugins().pickPlugin(CreateFleetPlugin.class, params);
155 if (plugin !=
null) {
156 return plugin.createFleet(params);
162 boolean fakeMarket =
false;
164 if (market ==
null) {
166 market.getStability().modifyFlat(
"fake", 10000);
168 SectorEntityToken token =
Global.
getSector().getHyperspace().createToken(0, 0);
169 market.setPrimaryEntity(token);
173 market.getStats().getDynamic().getMod(Stats.COMBAT_FLEET_SIZE_MULT).modifyFlat(
"fake", 1f);
182 boolean sourceWasNull = params.source ==
null;
183 params.source = market;
205 if (factionId ==
null) factionId = params.
source.getFactionId();
207 ShipPickMode mode = Misc.getShipPickMode(market, factionId);
211 fleet.getFleetData().setOnlySyncMemberLists(
true);
213 Misc.getSalvageSeed(fleet);
221 FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
226 float numShipsMult = 1f;
228 numShipsMult = market.getStats().getDynamic().getMod(Stats.COMBAT_FLEET_SIZE_MULT).computeEffective(0f);
231 float quality = params.quality + params.
qualityMod;
239 Random random =
new Random();
244 float combatPts = params.combatPts * numShipsMult;
250 float freighterPts = params.freighterPts * numShipsMult;
251 float tankerPts = params.tankerPts * numShipsMult;
252 float transportPts = params.transportPts * numShipsMult;
253 float linerPts = params.linerPts * numShipsMult;
254 float utilityPts = params.utilityPts * numShipsMult;
258 if (combatPts < 10 && combatPts > 0) {
259 combatPts = Math.max(combatPts, 5 + random.nextInt(6));
262 float dW = (float) doctrine.getWarships() + random.nextInt(3) - 2;
263 float dC = (float) doctrine.getCarriers() + random.nextInt(3) - 2;
264 float dP = (float) doctrine.getPhaseShips() + random.nextInt(3) - 2;
266 boolean strict = doctrine.isStrictComposition();
268 dW = (float) doctrine.getWarships() - 1;
269 dC = (float) doctrine.getCarriers() - 1;
270 dP = (float) doctrine.getPhaseShips() -1;
274 float r1 = random.nextFloat();
275 float r2 = random.nextFloat();
276 float min = Math.min(r1, r2);
277 float max = Math.max(r1, r2);
281 float v2 = max - min;
298 if (doctrine.getWarships() <= 0) dW = 0;
299 if (doctrine.getCarriers() <= 0) dC = 0;
300 if (doctrine.getPhaseShips() <= 0) dP = 0;
307 boolean banPhaseShipsEtc = !fleet.getFaction().isPlayerFaction() &&
314 params.banPhaseShipsEtc = banPhaseShipsEtc;
327 float extra = 7 - (dC + dP + dW);
328 if (extra < 0) extra = 0f;
329 if (doctrine.getWarships() > doctrine.getCarriers() && doctrine.getWarships() > doctrine.getPhaseShips()) {
331 }
else if (doctrine.getCarriers() > doctrine.getWarships() && doctrine.getCarriers() > doctrine.getPhaseShips()) {
333 }
else if (doctrine.getPhaseShips() > doctrine.getWarships() && doctrine.getPhaseShips() > doctrine.getCarriers()) {
338 float doctrineTotal = dW + dC + dP;
342 combatPts = (int) combatPts;
343 int warships = (int) (combatPts * dW / doctrineTotal);
344 int carriers = (int) (combatPts * dC / doctrineTotal);
345 int phase = (int) (combatPts * dP / doctrineTotal);
347 warships += (combatPts - warships - carriers - phase);
350 for (String variantId : params.
addShips) {
351 ShipRolePick pick =
new ShipRolePick(variantId);
354 if (warships < 0) warships = 0;
359 float combatFreighters = (int) Math.min(freighterPts * 1.5f, warships * 1.5f) * doctrine.getCombatFreighterProbability();
361 freighterPts -= added * 0.5f;
362 warships -= added * 0.5f;
363 }
else if (freighterPts > 0 && random.nextFloat() < doctrine.getCombatFreighterProbability()) {
364 float combatFreighters = (int) Math.min(freighterPts * 1.5f, warships * 1.5f);
366 freighterPts -= added * 0.5f;
367 warships -= added * 0.5f;
385 if (fleet.getFleetData().getNumMembers() > maxShips) {
387 float targetFP =
getFP(fleet);
399 int size = doctrine.getShipSize();
400 pruneFleet(maxShips, size, fleet, targetFP, random);
402 float currFP =
getFP(fleet);
411 fleet.getFleetData().sort();
417 fleet.getFleetData().sort();
420 fleet.getFleetData().sort();
426 if (fleet.getFlagship() !=
null) {
435 for (FleetMemberAPI curr : fleet.getFleetData().getMembersListCopy()) {
436 if (curr.isFlagship())
continue;
437 fleet.getFleetData().removeFleetMember(curr);
445 if (fleet.getFleetData().getNumMembers() <= 0 ||
446 fleet.getFleetData().getNumMembers() == fleet.getNumFighters()) {
453 params.source =
null;
462 p.seed = random.nextLong();
473 FleetInflater inflater = Misc.getInflater(fleet, p);
474 fleet.setInflater(inflater);
476 fleet.getFleetData().setOnlySyncMemberLists(
false);
477 fleet.getFleetData().sort();
479 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
480 for (FleetMemberAPI member : members) {
481 member.getRepairTracker().setCR(member.getRepairTracker().getMaxCR());
485 float actualPoints = fleet.getFleetPoints();
487 Misc.setSpawnFPMult(fleet, actualPoints / Math.max(1f, requestedPoints));
497 public static void pruneFleet(
int maxShips,
int doctrineSize, CampaignFleetAPI fleet,
float targetFP, Random random) {
503 List<FleetMemberAPI> copy = fleet.getFleetData().getMembersListCopy();
504 List<FleetMemberAPI> combat =
new ArrayList<FleetMemberAPI>();
506 List<FleetMemberAPI> tanker =
new ArrayList<FleetMemberAPI>();
507 List<FleetMemberAPI> freighter =
new ArrayList<FleetMemberAPI>();
508 List<FleetMemberAPI> liner =
new ArrayList<FleetMemberAPI>();
509 List<FleetMemberAPI> other =
new ArrayList<FleetMemberAPI>();
511 for (FleetMemberAPI member : copy) {
512 if (member.isCivilian()) {
513 civFP += member.getFleetPointCost();
516 if (member.getHullSpec().getHints().contains(ShipTypeHints.FREIGHTER)) {
517 freighter.add(member);
518 }
else if (member.getHullSpec().getHints().contains(ShipTypeHints.TANKER)) {
520 }
else if (member.getHullSpec().getHints().contains(ShipTypeHints.TRANSPORT) ||
521 member.getHullSpec().getHints().contains(ShipTypeHints.LINER)) {
528 combatFP += member.getFleetPointCost();
532 if (civFP < 1) civFP = 1;
533 if (combatFP < 1) combatFP = 1;
535 int keepCombat = (int) ((
float)maxShips * combatFP / (civFP + combatFP));
536 int keepCiv = maxShips - keepCombat;
537 if (civFP > 10 && keepCiv < 2) {
539 if (!freighter.isEmpty()) keepCiv++;
540 if (!tanker.isEmpty()) keepCiv++;
541 if (!liner.isEmpty()) keepCiv++;
542 if (!other.isEmpty()) keepCiv++;
544 keepCiv = maxShips - keepCiv;
548 float f = 0, t = 0, l = 0, o = 0;
549 float total = freighter.size() + tanker.size() + liner.size() + other.size();
550 if (total < 1) total = 1;
552 f = (float) freighter.size() / total;
553 t = (float) tanker.size() / total;
554 l = (float) liner.size() / total;
555 o = (float) other.size() / total;
562 if (f > 0) f = Math.round(f);
563 if (t > 0) t = Math.round(t);
564 if (l > 0) l = Math.round(l);
565 if (o > 0) o = Math.round(o);
567 if (freighter.size() > 0 && f < 1) f = 1;
568 if (tanker.size() > 0 && t < 1) t = 1;
569 if (liner.size() > 0 && l < 1) l = 1;
570 if (other.size() > 0 && o < 1) o = 1;
572 int extra = (int) ((f + t + l + o) - keepCiv);
574 if (extra > 0 && o >= 2) {
578 if (extra > 0 && l >= 2) {
582 if (extra > 0 && t >= 2) {
586 if (extra > 0 && f >= 2) {
592 LinkedHashSet<FleetMemberAPI> keep =
new LinkedHashSet<FleetMemberAPI>();
594 Comparator<FleetMemberAPI> c =
new Comparator<FleetMemberAPI>() {
595 public int compare(FleetMemberAPI o1, FleetMemberAPI o2) {
596 return o2.getHullSpec().getHullSize().ordinal() - o1.getHullSpec().getHullSize().ordinal();
599 Collections.sort(combat, c);
600 Collections.sort(freighter, c);
601 Collections.sort(tanker, c);
602 Collections.sort(liner, c);
603 Collections.sort(other, c);
605 int [] ratio =
new int [] { 4, 2, 1, 1 };
619 addAll(ratio, combat, keep, keepCombat, random);
622 addAll(ratio, freighter, keep, (
int)f, random);
623 addAll(ratio, tanker, keep, (
int)t, random);
624 addAll(ratio, liner, keep, (
int)l, random);
625 addAll(ratio, other, keep, (
int)o, random);
627 for (FleetMemberAPI member : copy) {
628 if (!keep.contains(member)) {
629 fleet.getFleetData().removeFleetMember(member);
633 float currFP =
getFP(fleet);
634 if (currFP > targetFP) {
635 fleet.getFleetData().sort();
636 copy = fleet.getFleetData().getMembersListCopy();
639 for (
int i = 0; i < copy.size()/2; i+=2) {
640 FleetMemberAPI f1 = copy.get(i);
641 FleetMemberAPI f2 = copy.get(copy.size() - 1 - i);
643 copy.set(copy.size() - 1 - i, f1);
666 float fpGoal = currFP - targetFP;
668 for (FleetMemberAPI curr : copy) {
669 if (curr.isCivilian())
continue;
670 FleetMemberAPI best =
null;
672 for (FleetMemberAPI replace : combat) {
673 float fpCurr = curr.getFleetPointCost();
674 float fpReplace = replace.getFleetPointCost();
675 if (fpCurr > fpReplace) {
676 float fpDiff = fpCurr - fpReplace;
677 if (fpDone + fpDiff <= fpGoal) {
682 if (fpDiff < bestDiff) {
692 fleet.getFleetData().removeFleetMember(curr);
693 fleet.getFleetData().addFleetMember(best);
695 if (fpDone >= fpGoal) {
704 public static void addAll(
int [] ratio, List<FleetMemberAPI> from, LinkedHashSet<FleetMemberAPI> to,
int num, Random random) {
707 while (added < num && !from.isEmpty()) {
708 to.add(from.remove(0));
714 WeightedRandomPicker<HullSize> picker =
makePicker(ratio, random);
715 for (
int i = 0; i < num; i++) {
716 if (picker.isEmpty()) picker =
makePicker(ratio, random);
717 OUTER:
while (!picker.isEmpty()) {
718 HullSize size = picker.pickAndRemove();
719 for (FleetMemberAPI member : from) {
720 if (member.getHullSpec().getHullSize() == size) {
733 while (added < num && !from.isEmpty()) {
734 to.add(from.remove(0));
740 public static WeightedRandomPicker<HullSize>
makePicker(
int [] ratio, Random random) {
741 WeightedRandomPicker<HullSize> picker =
new WeightedRandomPicker<HullSize>(random);
742 for (
int i = 0; i < ratio[0]; i++) {
743 picker.add(HullSize.CAPITAL_SHIP);
745 for (
int i = 0; i < ratio[1]; i++) {
746 picker.add(HullSize.CRUISER);
748 for (
int i = 0; i < ratio[2]; i++) {
749 picker.add(HullSize.DESTROYER);
751 for (
int i = 0; i < ratio[3]; i++) {
752 picker.add(HullSize.FRIGATE);
762 public static int getFP(CampaignFleetAPI fleet) {
764 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
765 fp += member.getFleetPointCost();
772 List<FleetMemberAPI>
remove =
new ArrayList<FleetMemberAPI>();
773 List<FleetMemberAPI> copy = fleet.getFleetData().getMembersListCopy();
785 Collections.reverse(copy);
787 Iterator<FleetMemberAPI> iter;
789 iter = copy.iterator();
790 while (iter.hasNext()) {
791 FleetMemberAPI member = iter.next();
792 if (member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.FRIGATE.ordinal()) {
798 iter = copy.iterator();
799 while (iter.hasNext()) {
800 FleetMemberAPI member = iter.next();
801 if (!member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.FRIGATE.ordinal()) {
807 iter = copy.iterator();
808 while (iter.hasNext()) {
809 FleetMemberAPI member = iter.next();
810 if (member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.DESTROYER.ordinal()) {
816 iter = copy.iterator();
817 while (iter.hasNext()) {
818 FleetMemberAPI member = iter.next();
819 if (!member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.DESTROYER.ordinal()) {
825 iter = copy.iterator();
826 while (iter.hasNext()) {
827 FleetMemberAPI member = iter.next();
828 if (member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.CRUISER.ordinal()) {
834 iter = copy.iterator();
835 while (iter.hasNext()) {
836 FleetMemberAPI member = iter.next();
837 if (!member.isCivilian() && member.getHullSpec().getHullSize().ordinal() <= HullSize.CRUISER.ordinal()) {
843 iter = copy.iterator();
844 while (iter.hasNext()) {
845 FleetMemberAPI member = iter.next();
846 if (member.isCivilian()) {
852 iter = copy.iterator();
853 while (iter.hasNext()) {
854 FleetMemberAPI member = iter.next();
855 if (!member.isCivilian()) {
874 GenerateFleetOfficersPickData pickData =
new GenerateFleetOfficersPickData(fleet, params);
876 if (genPlugin !=
null) {
881 FactionAPI faction = fleet.getFaction();
882 FactionDoctrineAPI doctrine = faction.getDoctrine();
886 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
887 if (members.isEmpty())
return;
889 float combatPoints = 0f;
890 float combatShips = 0f;
891 for (FleetMemberAPI member : members) {
892 if (member.isCivilian())
continue;
893 if (member.isFighterWing())
continue;
894 combatPoints += member.getFleetPointCost();
897 if (combatPoints < 1f) combatPoints = 1f;
898 if (combatShips < 1f) combatShips = 1f;
900 boolean debug =
true;
911 float officerQualityMult = (doctrine.getOfficerQuality() - 1f) / 4f;
912 if (officerQualityMult > 1f) officerQualityMult = 1f;
920 float combatShipsPerOfficer = baseCombatShipsPerOfficer * (1f - officerQualityMult * 0.5f);
923 float fleetSizeOfficerQualityMult = combatShips / (baseShipsForMaxOfficerLevel * (1f - officerQualityMult * 0.5f));
924 if (fleetSizeOfficerQualityMult > 1) fleetSizeOfficerQualityMult = 1;
926 maxOfficers += (int)((
float)doctrine.getOfficerQuality() * mercMult) + params.
officerNumberBonus;
929 int numOfficers = (int) Math.min(maxOfficers, combatShips / combatShipsPerOfficer);
934 if (debug) System.out.println(
"numOfficers: " + numOfficers);
940 if (numOfficers > maxOfficers) numOfficers = maxOfficers;
943 numOfficers = (int) params.
commander.getStats().getOfficerNumber().getModifiedInt();
950 int maxOfficerLevel = (int)Math.round(((
float)doctrine.getOfficerQuality() / 2f) +
951 (fleetSizeOfficerQualityMult * 1f) * (float) baseMaxOfficerLevel);
952 if (maxOfficerLevel < 1) maxOfficerLevel = 1;
954 if (maxOfficerLevel < 1) maxOfficerLevel = 1;
956 if (debug) System.out.println(
"maxOfficers: " + maxOfficers);
957 if (debug) System.out.println(
"maxOfficerLevel: " + maxOfficerLevel);
960 WeightedRandomPicker<FleetMemberAPI> picker =
new WeightedRandomPicker<FleetMemberAPI>(random);
961 WeightedRandomPicker<FleetMemberAPI> flagshipPicker =
new WeightedRandomPicker<FleetMemberAPI>(random);
964 for (FleetMemberAPI member : members) {
965 if (member.isFighterWing())
continue;
966 if (member.isFlagship())
continue;
967 if (member.isCivilian())
continue;
968 if (!member.getCaptain().isDefault())
continue;
969 int size = member.getHullSpec().getHullSize().ordinal();
970 if (size > maxSize) {
975 for (FleetMemberAPI member : members) {
976 if (member.isFighterWing())
continue;
977 if (member.isFlagship())
continue;
978 if (member.isCivilian())
continue;
979 if (!member.getCaptain().isDefault())
continue;
981 float weight = (float) member.getFleetPointCost();
982 int size = member.getHullSpec().getHullSize().ordinal();
983 if (size >= maxSize) {
984 flagshipPicker.add(member, weight);
987 picker.add(member, weight);
990 if (picker.isEmpty()) {
991 picker.add(members.get(0), 1f);
993 if (flagshipPicker.isEmpty()) {
994 flagshipPicker.add(members.get(0), 1f);
998 FleetMemberAPI flagship = flagshipPicker.pickAndRemove();
999 picker.remove(flagship);
1000 int commanderLevel = maxOfficerLevel;
1001 int commanderLevelLimit = maxCommanderLevel;
1007 if (commanderLevel > commanderLevelLimit) commanderLevel = commanderLevelLimit;
1011 if (commander ==
null) {
1012 commander = OfficerManagerEvent.createOfficer(fleet.getFaction(), commanderLevel, pref,
false,
null,
true,
true, -1, random);
1013 if (commander.getPersonalityAPI().getId().equals(Personalities.TIMID)) {
1014 commander.setPersonality(Personalities.CAUTIOUS);
1019 commander.setRankId(Ranks.SPACE_COMMANDER);
1020 commander.setPostId(Ranks.POST_FLEET_COMMANDER);
1022 fleet.setCommander(commander);
1023 fleet.getFleetData().setFlagship(flagship);
1025 int commanderOfficerLevelBonus = (int) commander.getStats().getDynamic().getMod(Stats.OFFICER_MAX_LEVEL_MOD).computeEffective(0);
1026 int officerLevelLimit = plugin.getMaxLevel(
null) + commanderOfficerLevelBonus;
1033 System.out.println(
"Created level " + commander.getStats().getLevel() +
" commander");
1034 System.out.println(
"Max officer level bonus: " + commanderOfficerLevelBonus +
" (due to commander skill)");
1035 System.out.println(
"Adding up to " + numOfficers +
" officers");
1039 for (
int i = 0; i < numOfficers; i++) {
1040 FleetMemberAPI member = picker.pickAndRemove();
1041 if (member ==
null) {
1045 int level = maxOfficerLevel - random.nextInt(3);
1046 if (Misc.isEasy()) {
1049 if (level < 1) level = 1;
1050 if (level > officerLevelLimit) level = officerLevelLimit;
1052 level = (int) params.
commander.getStats().getDynamic().getMod(Stats.OFFICER_MAX_LEVEL_MOD).computeEffective(
Global.
getSettings().
getInt(
"officerMaxLevel"));
1056 PersonAPI person = OfficerManagerEvent.createOfficer(fleet.getFaction(), level, pref,
false, fleet,
true,
true, -1, random);
1057 if (person.getPersonalityAPI().getId().equals(Personalities.TIMID)) {
1058 person.setPersonality(Personalities.CAUTIOUS);
1062 System.out.println(
"Added level " + person.getStats().getLevel() +
" officer");
1065 member.setCaptain(person);
1068 fleet.getFleetData().addOfficer(person);
1073 System.out.println(
"Added " + added +
" officers total");
1080 float ballistic = 0f;
1084 for (WeaponSlotAPI slot : member.getHullSpec().getAllWeaponSlotsCopy()) {
1086 switch (slot.getSlotSize()) {
1087 case LARGE: w = 4f;
break;
1088 case MEDIUM: w = 2f;
break;
1089 case SMALL: w = 1f;
break;
1091 WeaponType type = slot.getWeaponType();
1092 if (type == WeaponType.BALLISTIC || type == WeaponType.HYBRID) {
1095 }
else if (type == WeaponType.ENERGY) {
1098 }
else if (type == WeaponType.MISSILE || type == WeaponType.SYNERGY || type == WeaponType.COMPOSITE) {
1104 if (total <= 0f) total = 1f;
1106 boolean e = energy >= total * 0.33f;
1107 boolean b = ballistic >= total * 0.33f;
1109 if (ballistic * 1.5f >= energy) {
1115 boolean m = missile >= total * 0.17f;
1117 boolean d = member.getHullSpec().getShieldType() == ShieldType.FRONT ||
1118 member.getHullSpec().getShieldType() == ShieldType.OMNI ||
1119 member.getHullSpec().isPhase();
1122 String n1 = e ?
"YES_ENERGY" :
"NO_ENERGY";
1123 String n2 = b ?
"YES_BALLISTIC" :
"NO_BALLISTIC";
1124 String n3 = m ?
"YES_MISSILE" :
"NO_MISSILE";
1125 String n4 = d ?
"YES_DEFENSE" :
"NO_DEFENSE";
1126 SkillPickPreference pref = SkillPickPreference.valueOf(n1 +
"_" + n2 +
"_" + n3 +
"_" + n4);
1135 if (random ==
null) random =
new Random();
1137 MutableCharacterStatsAPI stats = commander.getStats();
1138 int level = stats.getLevel();
1144 if (level >= forTwo) {
1146 }
else if (level >= forOne) {
1150 if (numSkills <= 0)
return;
1152 FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
1157 List<String> skills =
new ArrayList<String>(doctrine.getCommanderSkills());
1159 Iterator<String> iter = skills.iterator();
1160 while (iter.hasNext()) {
1161 String
id = iter.next();
1163 if (spec !=
null && spec.hasTag(Skills.TAG_PLAYER_ONLY)) {
1169 if (skills.isEmpty())
return;
1171 if (random.nextFloat() < doctrine.getCommanderSkillsShuffleProbability()) {
1172 Collections.shuffle(skills, random);
1175 stats.setSkipRefresh(
true);
1177 boolean debug =
true;
1179 if (debug) System.out.println(
"Generating commander skills, person level " + stats.getLevel() +
", skills: " + numSkills);
1181 for (String skillId : skills) {
1182 if (debug) System.out.println(
"Selected skill: [" + skillId +
"]");
1183 stats.setSkillLevel(skillId, 1);
1185 if (picks >= numSkills) {
1189 if (debug) System.out.println(
"Done generating commander skills\n");
1191 stats.setSkipRefresh(
false);
1192 stats.refreshCharacterStatsEffects();
1197 boolean nonCombat = member.getVariant().isCivilian();
1199 switch (member.getVariant().getHullSize()) {
1200 case CAPITAL_SHIP: weight += 8;
break;
1201 case CRUISER: weight += 4;
break;
1202 case DESTROYER: weight += 2;
break;
1203 case FRIGATE: weight += 1;
break;
1204 case FIGHTER: weight += 1;
break;
1206 if (nonCombat) weight *= 0.1f;
1217 List<MarketAPI> allMarkets =
Global.
getSector().getEconomy().getMarketsCopy();
1220 float distToClosest = Float.MAX_VALUE;
1221 MarketAPI closest =
null;
1222 float distToClosestMatchingSize = Float.MAX_VALUE;
1223 MarketAPI closestMatchingSize =
null;
1227 boolean independent = Factions.INDEPENDENT.equals(params.
factionId) ||
1228 Factions.SCAVENGERS.equals(params.
factionId) ||
1229 creationFaction.getCustomBoolean(Factions.CUSTOM_SPAWNS_AS_INDEPENDENT);
1231 for (MarketAPI market : allMarkets) {
1232 if (market.getPrimaryEntity() ==
null)
continue;
1235 boolean hostileToIndependent = market.getFaction().isHostileTo(Factions.INDEPENDENT);
1236 if (hostileToIndependent)
continue;
1238 if (!market.getFactionId().equals(params.
factionId))
continue;
1241 float currDist = Misc.getDistance(market.getPrimaryEntity().getLocationInHyperspace(),
1243 if (currDist < distToClosest) {
1244 distToClosest = currDist;
1248 if (market.getSize() >= size && currDist < distToClosestMatchingSize) {
1249 distToClosestMatchingSize = currDist;
1250 closestMatchingSize = market;
1254 if (closestMatchingSize !=
null) {
1255 return closestMatchingSize;
1258 if (closest !=
null) {
1271 if (fp <= 20)
return 1;
1272 if (fp <= 50)
return 3;
1273 if (fp <= 100)
return 5;
1274 if (fp <= 150)
return 7;
1282 private static List<String> startingAbilities =
null;
1283 public static CampaignFleetAPI
createEmptyFleet(String factionId, String fleetType, MarketAPI market) {
1285 String fleetName = faction.getFleetTypeName(fleetType);
1287 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_FLEET_TYPE, fleetType);
1289 if (market !=
null && !market.getId().equals(
"fake")) {
1290 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_SOURCE_MARKET, market.getId());
1293 if (startingAbilities ==
null) {
1294 startingAbilities =
new ArrayList<String>();
1297 if (spec.isAIDefault()) {
1298 startingAbilities.add(
id);
1303 for (String
id : startingAbilities) {
1304 fleet.addAbility(
id);
1310 public static class FPRemaining {
1313 public FPRemaining(
int fp) {
1316 public FPRemaining() {
1320 public static float addToFleet(String role, MarketAPI market, Random random, CampaignFleetAPI fleet,
int maxFP,
FleetParamsV3 params) {
1322 List<ShipRolePick> picks = market.pickShipsForRole(role, fleet.getFaction().getId(),
1324 for (ShipRolePick pick : picks) {
1330 protected static float addToFleet(ShipRolePick pick, CampaignFleetAPI fleet, Random random) {
1332 String name = fleet.getFleetData().pickShipName(member, random);
1333 member.setShipName(name);
1334 fleet.getFleetData().addFleetMember(member);
1335 return member.getFleetPointCost();
1391 public static boolean addShips(String role,
int count, MarketAPI market, Random random, CampaignFleetAPI fleet, FPRemaining rem,
FleetParamsV3 params) {
1392 boolean addedSomething =
false;
1393 for (
int i = 0; i < count; i++) {
1394 if (rem.fp <= 0)
break;
1395 float added =
addToFleet(role, market, random, fleet, rem.fp, params);
1398 addedSomething =
true;
1401 return addedSomething;
1407 ShipRoles.PHASE_SMALL, ShipRoles.PHASE_MEDIUM, ShipRoles.PHASE_LARGE);
1450 public static enum SizeFilterMode {
1457 ShipRoles.CARRIER_SMALL, ShipRoles.CARRIER_MEDIUM, ShipRoles.CARRIER_LARGE);
1460 SizeFilterMode sizeFilterMode,
1461 String roleSmall, String roleMedium, String roleLarge) {
1462 if (fp <= 0)
return 0f;
1465 if (params.
mode == ShipPickMode.PRIORITY_THEN_ALL) {
1466 int numPriority = fleet.getFaction().getNumAvailableForRole(roleSmall, ShipPickMode.PRIORITY_ONLY) +
1467 fleet.getFaction().getNumAvailableForRole(roleMedium, ShipPickMode.PRIORITY_ONLY) +
1468 fleet.getFaction().getNumAvailableForRole(roleLarge, ShipPickMode.PRIORITY_ONLY);
1470 if (numPriority > 0) {
1471 params.mode = ShipPickMode.PRIORITY_ONLY;
1472 added =
addFleetPoints(fleet, random, fp, params, sizeFilterMode,
1473 roleSmall, roleMedium, roleLarge);
1474 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1476 params.mode = ShipPickMode.ALL;
1477 added =
addFleetPoints(fleet, random, fp, params, sizeFilterMode,
1478 roleSmall, roleMedium, roleLarge);
1479 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1489 added =
addFleetPoints(fleet, random, fp, params, sizeFilterMode,
1490 roleSmall, roleMedium, roleLarge);
1497 ShipRoles.TANKER_SMALL, ShipRoles.TANKER_MEDIUM, ShipRoles.TANKER_LARGE);
1502 ShipRoles.FREIGHTER_SMALL, ShipRoles.FREIGHTER_MEDIUM, ShipRoles.FREIGHTER_LARGE);
1507 ShipRoles.LINER_SMALL, ShipRoles.LINER_MEDIUM, ShipRoles.LINER_LARGE);
1512 ShipRoles.COMBAT_FREIGHTER_SMALL, ShipRoles.COMBAT_FREIGHTER_MEDIUM, ShipRoles.COMBAT_FREIGHTER_LARGE);
1517 ShipRoles.PERSONNEL_SMALL, ShipRoles.PERSONNEL_MEDIUM, ShipRoles.PERSONNEL_LARGE);
1522 ShipRoles.UTILITY, ShipRoles.UTILITY, ShipRoles.UTILITY);
1548 SizeFilterMode sizeFilterMode,
1550 FactionDoctrineAPI doctrine = fleet.getFaction().getDoctrine();
1555 int size = doctrine.getShipSize();
1558 boolean addedSomething =
true;
1559 FPRemaining rem =
new FPRemaining();
1562 while (addedSomething && rem.fp > 0) {
1574 if (sizeFilterMode == SizeFilterMode.SMALL_IS_FRIGATE) {
1577 }
else if (sizeFilterMode == SizeFilterMode.SMALL_IS_DESTROYER) {
1585 int smallPre = small / 2;
1588 int mediumPre = medium / 2;
1589 medium -= mediumPre;
1591 addedSomething =
false;
1593 addedSomething |=
addShips(roles[0], smallPre, params.
source, random, fleet, rem, params);
1595 addedSomething |=
addShips(roles[1], mediumPre, params.
source, random, fleet, rem, params);
1596 addedSomething |=
addShips(roles[0], small, params.
source, random, fleet, rem, params);
1598 addedSomething |=
addShips(roles[2], large, params.
source, random, fleet, rem, params);
1599 addedSomething |=
addShips(roles[1], medium, params.
source, random, fleet, rem, params);
1610 float warshipFP,
float carrierFP,
float phaseFP,
FleetParamsV3 params) {
1612 FactionAPI faction = fleet.getFaction();
1613 FactionDoctrineAPI doctrine = faction.getDoctrine();
1618 WeightedRandomPicker<String> smallPicker =
new WeightedRandomPicker<String>(random);
1619 WeightedRandomPicker<String> mediumPicker =
new WeightedRandomPicker<String>(random);
1620 WeightedRandomPicker<String> largePicker =
new WeightedRandomPicker<String>(random);
1621 WeightedRandomPicker<String> capitalPicker =
new WeightedRandomPicker<String>(random);
1622 WeightedRandomPicker<String> priorityCapitalPicker =
new WeightedRandomPicker<String>(random);
1624 String smallRole = ShipRoles.COMBAT_SMALL_FOR_SMALL_FLEET;
1626 smallRole = ShipRoles.COMBAT_SMALL;
1644 smallPicker.add(smallRole, warshipFP);
1645 smallPicker.add(ShipRoles.PHASE_SMALL, phaseFP);
1647 mediumPicker.add(ShipRoles.COMBAT_MEDIUM, warshipFP);
1648 mediumPicker.add(ShipRoles.PHASE_MEDIUM, phaseFP);
1649 mediumPicker.add(ShipRoles.CARRIER_SMALL, carrierFP);
1651 largePicker.add(ShipRoles.COMBAT_LARGE, warshipFP);
1652 largePicker.add(ShipRoles.PHASE_LARGE, phaseFP);
1653 largePicker.add(ShipRoles.CARRIER_MEDIUM, carrierFP);
1655 capitalPicker.add(ShipRoles.COMBAT_CAPITAL, warshipFP);
1656 capitalPicker.add(ShipRoles.PHASE_CAPITAL, phaseFP);
1657 capitalPicker.add(ShipRoles.CARRIER_LARGE, carrierFP);
1660 Set<String> usePriorityOnly =
new HashSet<String>();
1662 if (params.
mode == ShipPickMode.PRIORITY_THEN_ALL) {
1663 float num = faction.getVariantWeightForRole(ShipRoles.COMBAT_CAPITAL, ShipPickMode.PRIORITY_ONLY);
1666 priorityCapitalPicker.add(ShipRoles.COMBAT_CAPITAL, num);
1668 num = faction.getVariantWeightForRole(ShipRoles.CARRIER_LARGE, ShipPickMode.PRIORITY_ONLY);
1671 priorityCapitalPicker.add(ShipRoles.CARRIER_LARGE, num);
1673 num = faction.getVariantWeightForRole(ShipRoles.PHASE_CAPITAL, ShipPickMode.PRIORITY_ONLY);
1676 priorityCapitalPicker.add(ShipRoles.PHASE_CAPITAL, num);
1679 if (params.
mode == ShipPickMode.PRIORITY_THEN_ALL) {
1680 addToPriorityOnlySet(fleet, usePriorityOnly, ShipRoles.PHASE_SMALL, ShipRoles.PHASE_MEDIUM, ShipRoles.PHASE_LARGE);
1681 addToPriorityOnlySet(fleet, usePriorityOnly, ShipRoles.CARRIER_SMALL, ShipRoles.CARRIER_MEDIUM, ShipRoles.CARRIER_LARGE);
1685 Map<String, FPRemaining> remaining =
new HashMap<String, FPRemaining>();
1686 FPRemaining remWarship =
new FPRemaining((
int)warshipFP);
1687 FPRemaining remCarrier =
new FPRemaining((
int)carrierFP);
1688 FPRemaining remPhase =
new FPRemaining((
int)phaseFP);
1690 remaining.put(ShipRoles.COMBAT_SMALL_FOR_SMALL_FLEET, remWarship);
1691 remaining.put(ShipRoles.COMBAT_SMALL, remWarship);
1692 remaining.put(ShipRoles.COMBAT_MEDIUM, remWarship);
1693 remaining.put(ShipRoles.COMBAT_LARGE, remWarship);
1694 remaining.put(ShipRoles.COMBAT_CAPITAL, remWarship);
1696 remaining.put(ShipRoles.CARRIER_SMALL, remCarrier);
1697 remaining.put(ShipRoles.CARRIER_MEDIUM, remCarrier);
1698 remaining.put(ShipRoles.CARRIER_LARGE, remCarrier);
1700 remaining.put(ShipRoles.PHASE_SMALL, remPhase);
1701 remaining.put(ShipRoles.PHASE_MEDIUM, remPhase);
1702 remaining.put(ShipRoles.PHASE_LARGE, remPhase);
1703 remaining.put(ShipRoles.PHASE_CAPITAL, remPhase);
1707 mediumPicker.clear();
1710 largePicker.clear();
1713 capitalPicker.clear();
1717 smallPicker.clear();
1720 mediumPicker.clear();
1723 largePicker.clear();
1727 int size = doctrine.getShipSize();
1731 while (numFails < 2) {
1743 if (size < 5 && capital > 1) {
1755 int smallPre = small / 2;
1758 int mediumPre = medium / 2;
1759 medium -= mediumPre;
1761 boolean addedSomething =
false;
1764 addedSomething |=
addShips(smallPicker, usePriorityOnly, remaining,
null, smallPre, fleet, random, params);
1766 addedSomething |=
addShips(mediumPicker, usePriorityOnly, remaining,
null, mediumPre, fleet, random, params);
1768 addedSomething |=
addShips(smallPicker, usePriorityOnly, remaining,
null, small, fleet, random, params);
1770 addedSomething |=
addShips(largePicker, usePriorityOnly, remaining,
null, large, fleet, random, params);
1772 addedSomething |=
addShips(mediumPicker, usePriorityOnly, remaining,
null, medium, fleet, random, params);
1776 if (!priorityCapitalPicker.isEmpty()) {
1777 params.mode = ShipPickMode.PRIORITY_ONLY;
1778 params.blockFallback =
true;
1779 FPRemaining combined =
new FPRemaining(remWarship.fp + remCarrier.fp + remPhase.fp);
1780 boolean addedCapital =
addShips(priorityCapitalPicker, usePriorityOnly, remaining, combined, capital, fleet, random, params);
1781 addedSomething |= addedCapital;
1785 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1786 params.blockFallback =
null;
1789 addedSomething |=
addShips(capitalPicker, usePriorityOnly, remaining,
null, capital, fleet, random, params);
1793 if (!addedSomething) {
1796 if (numFails == 2) {
1797 boolean goAgain =
false;
1798 if (remPhase.fp > 0) {
1799 remWarship.fp += remPhase.fp;
1803 if (remCarrier.fp > 0) {
1804 remWarship.fp += remCarrier.fp;
1811 smallPicker.add(smallRole, 1);
1812 mediumPicker.add(ShipRoles.COMBAT_MEDIUM, 1);
1813 largePicker.add(ShipRoles.COMBAT_LARGE, 1);
1814 capitalPicker.add(ShipRoles.COMBAT_CAPITAL, 1);
1821 protected static void addToPriorityOnlySet(CampaignFleetAPI fleet, Set<String>
set, String small, String medium, String large) {
1822 int numPriority = fleet.getFaction().getNumAvailableForRole(small, ShipPickMode.PRIORITY_ONLY) +
1823 fleet.getFaction().getNumAvailableForRole(medium, ShipPickMode.PRIORITY_ONLY) +
1824 fleet.getFaction().getNumAvailableForRole(large, ShipPickMode.PRIORITY_ONLY);
1825 if (numPriority > 0) {
1832 protected static void redistributeFP(FPRemaining one, FPRemaining two, FPRemaining three,
int newTotal) {
1833 float total = one.fp + two.fp + three.fp;
1834 if (total <= 0)
return;
1836 int f1 = (int) Math.round((
float)one.fp / total * newTotal);
1837 int f2 = (int) Math.round((
float)two.fp / total * newTotal);
1838 int f3 = (int) Math.round((
float)three.fp / total * newTotal);
1840 f1 += newTotal - f1 - f2 - f3;
1847 public static boolean addShips(WeightedRandomPicker<String> rolePicker, Set<String> usePriorityOnly, Map<String, FPRemaining> remaining, FPRemaining remOverride,
int count,
1848 CampaignFleetAPI fleet, Random random,
FleetParamsV3 params) {
1849 if (rolePicker.isEmpty())
return false;
1851 boolean addedSomething =
false;
1852 for (
int i = 0; i < count; i++) {
1853 String role = rolePicker.pick();
1854 if (role ==
null)
break;
1855 FPRemaining rem = remaining.get(role);
1856 FPRemaining remForProperRole = rem;
1857 if (remOverride !=
null) rem = remOverride;
1858 if (usePriorityOnly.contains(role)) {
1859 params.mode = ShipPickMode.PRIORITY_ONLY;
1861 int fpPrePick = rem.fp;
1863 boolean added =
addShips(role, 1, params.
source, random, fleet, rem, params);
1865 if (added && remOverride !=
null) {
1866 int fpSpent = fpPrePick - rem.fp;
1867 int maxToTakeFromProperRole = Math.min(remForProperRole.fp, fpSpent);
1868 remForProperRole.fp -= maxToTakeFromProperRole;
1871 if (usePriorityOnly.contains(role)) {
1872 params.mode = ShipPickMode.PRIORITY_THEN_ALL;
1875 rolePicker.remove(role);
1877 if (rolePicker.isEmpty()) {
1881 addedSomething |= added;
1883 return addedSomething;
1888 CommodityOnMarketAPI com = market.getCommodityData(Commodities.SHIPS);
1889 float available = com.getAvailable();
1890 float demand = com.getMaxDemand();
1892 float f = available / demand;
1896 if (mult < 0) mult = 0;
1897 if (mult > 1) mult = 1;
1909 boolean damageRemainingShips, Random random) {
1910 if (random ==
null) random = Misc.random;
1911 WeightedRandomPicker<FleetMemberAPI> picker =
new WeightedRandomPicker<FleetMemberAPI>();
1913 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
1914 for (FleetMemberAPI member : members) {
1916 if (member.isCivilian()) w *= 0.25f;
1918 picker.add(member, w);
1921 List<FleetMemberAPI>
remove =
new ArrayList<FleetMemberAPI>();
1922 float removedFP = 0f;
1923 float fpToRemove = fleet.getFleetPoints() * damage * 0.8f;
1925 while (removedFP < fpToRemove &&
remove.size() < members.size() - 1 && !picker.isEmpty()) {
1926 FleetMemberAPI member = picker.pickAndRemove();
1927 removedFP += member.getFleetPointCost();
1931 for (FleetMemberAPI member :
remove) {
1932 fleet.getFleetData().removeFleetMember(member);
1936 if (damageRemainingShips) {
1937 int numStrikes = (int) Math.round(picker.getItems().size() * damage);
1939 for (
int i = 0; i < numStrikes; i++) {
1940 FleetMemberAPI member = picker.pick();
1941 if (member ==
null)
return;
1943 if (random.nextFloat() > damage)
continue;
1945 float crPerDep = member.getDeployCost();
1947 float suppliesPerDep = member.getStats().getSuppliesToRecover().getModifiedValue();
1948 if (suppliesPerDep <= 0 || crPerDep <= 0)
return;
1949 float suppliesPer100CR = suppliesPerDep * 1f / Math.max(0.01f, crPerDep);
1951 float strikeSupplies = suppliesPer100CR * damage * (0.25f + 0.75f * random.nextFloat());
1952 float strikeDamage = strikeSupplies / suppliesPer100CR * (0.75f + (float) Math.random() * 0.5f);
1954 if (strikeDamage > HyperspaceTerrainPlugin.STORM_MAX_STRIKE_DAMAGE) {
1955 strikeDamage = HyperspaceTerrainPlugin.STORM_MAX_STRIKE_DAMAGE;
1958 if (strikeDamage > 0) {
1959 float currCR = member.getRepairTracker().getBaseCR();
1960 float crDamage = Math.min(currCR, strikeDamage);
1962 member.getRepairTracker().setCR(currCR - crDamage);
1964 float hitStrength = member.getStats().getArmorBonus().computeEffective(member.getHullSpec().getArmorRating());
1965 int numHits = (int) (strikeDamage / 0.1f);
1966 if (numHits < 1) numHits = 1;
1967 for (
int j = 0; j < numHits; j++) {
1968 member.getStatus().applyDamage(hitStrength);
1971 if (member.getStatus().getHullFraction() < 0.01f) {
1972 member.getStatus().setHullFraction(0.01f);
1973 picker.remove(member);
1975 float w = picker.getWeight(member);
1976 picker.setWeight(picker.getItems().indexOf(member), w * 0.5f);
static SettingsAPI getSettings()
static FactoryAPI getFactory()
static Logger getLogger(Class c)
static SectorAPI getSector()
static float BASE_QUALITY_WHEN_NO_MARKET
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 MIN_NUM_SHIPS_DEFICIT_MULT
static int getFP(CampaignFleetAPI fleet)
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 int[][] BASE_COUNTS_WITH_4
static float getShipDeficitFleetSizeMult(MarketAPI market)
static int[][] MAX_EXTRA_WITH_3
static float getNumShipsMultForMarketSize(float marketSize)
static float getShipQualityModForStability(float stability)
static int[][] MAX_EXTRA_WITH_4
static float getDoctrineNumShipsMult(int doctrineNumShips)
static SkillPickPreference getSkillPrefForShip(FleetMemberAPI member)
static float getNumShipsMultForStability(float stability)
static int FLEET_POINTS_THRESHOLD_FOR_ANNOYING_SHIPS
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 int[][] BASE_COUNTS_WITH_3
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 getMemberWeight(FleetMemberAPI member)
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 int getMinPreferredMarketSize(FleetParamsV3 params)
static MarketAPI pickMarket(FleetParamsV3 params)
static String KEY_SPAWN_FP_MULT
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)
transient Boolean blockFallback
ShipPickMode modeOverride
void updateQualityAndProducerFromSourceMarket()
Boolean noCommanderSkills
Boolean forceAllowPhaseShipsEtc
FactionDoctrineAPI doctrineOverride
transient boolean banPhaseShipsEtc
Boolean doNotAddShipsBeforePruning
Boolean ignoreMarketFleetSizeMult
transient ShipPickMode mode
Boolean onlyApplyFleetSizeToCombatShips
Boolean treatCombatFreighterSettingAsFraction
Boolean onlyRetainFlagship
ShipVariantAPI flagshipVariant
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)
Object getPlugin(String id)
List< String > getSortedAbilityIds()
float getFloat(String key)
void profilerBegin(String id)
void addCommanderAndOfficers(CampaignFleetAPI fleet, FleetParamsV3 params, Random random)