1package com.fs.starfarer.api.plugins.impl;
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.LinkedHashMap;
10import java.util.LinkedHashSet;
13import java.util.Random;
16import com.fs.starfarer.api.Global;
17import com.fs.starfarer.api.campaign.CampaignFleetAPI;
18import com.fs.starfarer.api.campaign.FactionAPI;
19import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
20import com.fs.starfarer.api.characters.MutableCharacterStatsAPI.SkillLevelAPI;
21import com.fs.starfarer.api.characters.OfficerDataAPI;
22import com.fs.starfarer.api.characters.PersonAPI;
23import com.fs.starfarer.api.characters.SkillSpecAPI;
24import com.fs.starfarer.api.combat.ShieldAPI.ShieldType;
25import com.fs.starfarer.api.combat.ShipAPI;
26import com.fs.starfarer.api.combat.ShipAPI.HullSize;
27import com.fs.starfarer.api.combat.ShipHullSpecAPI;
28import com.fs.starfarer.api.combat.ShipVariantAPI;
29import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
30import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
31import com.fs.starfarer.api.fleet.FleetMemberAPI;
32import com.fs.starfarer.api.impl.campaign.DModManager;
33import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflater;
34import com.fs.starfarer.api.impl.campaign.ids.Factions;
35import com.fs.starfarer.api.impl.campaign.ids.HullMods;
36import com.fs.starfarer.api.impl.campaign.ids.Skills;
37import com.fs.starfarer.api.impl.campaign.ids.Tags;
38import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
39import com.fs.starfarer.api.loading.FighterWingSpecAPI;
40import com.fs.starfarer.api.loading.HullModSpecAPI;
41import com.fs.starfarer.api.loading.VariantSource;
42import com.fs.starfarer.api.loading.WeaponGroupSpec;
43import com.fs.starfarer.api.loading.WeaponSlotAPI;
44import com.fs.starfarer.api.loading.WeaponSpecAPI;
45import com.fs.starfarer.api.util.Misc;
46import com.fs.starfarer.api.util.WeightedRandomPicker;
59 public static String
UPGRADE =
new String(
"upgrade");
62 public static String
STRIP =
new String(
"strip");
63 public static String
RANDOMIZE =
new String(
"randomize");
67 public static String
LR =
"LR";
68 public static String
SR =
"SR";
71 public static String
HE =
"he";
72 public static String
ENERGY =
"energy";
73 public static String
PD =
"pd";
74 public static String
BEAM =
"beam";
76 public static String
STRIKE =
"strike";
79 public static String
ROCKET =
"rocket";
82 public static String
BOMBER =
"bomber";
89 public static class Category {
91 public Set<String> tags =
new HashSet<String>();
93 public List<String> fallback =
new ArrayList<String>();
95 public Category(String base, Map<String, Category>
categories) {
99 for (
int i = 0; i < 100; i++) {
100 String
id = base + i;
106 public void addFallback(String ...
categories) {
113 protected List<AutofitOption>
options =
new ArrayList<AutofitOption>();
115 protected Map<String, Category>
categories =
new LinkedHashMap<String, Category>();
117 protected Map<WeaponSpecAPI, List<String>>
altWeaponCats =
new LinkedHashMap<WeaponSpecAPI, List<String>>();
118 protected Map<FighterWingSpecAPI, List<String>>
altFighterCats =
new LinkedHashMap<FighterWingSpecAPI, List<String>>();
122 protected MutableCharacterStatsAPI
stats;
139 for (AutofitOption option :
options) {
140 if (option.id.equals(
id))
return option.checked;
146 for (AutofitOption option :
options) {
147 if (option.id.equals(
id)) {
148 option.checked = checked;
158 "Use weapons and fighter LPCs from your fleet's cargo holds."));
160 "Use weapons and fighter LPCs from your local storage facilities."));
162 "Buy weapons and fighter LPCs from market, if docked at one.\n\n" +
163 "Ordnance from your cargo will be preferred if that option is checked and if the alternatives are of equal quality."));
165 "Buy weapons and fighter LPCs from the black market.\n\n" +
166 "Non-black-market options will be preferred if the alternatives are of equal quality."));
167 options.add(
new AutofitOption(
UPGRADE,
"Upgrade weapons using extra OP",
false,
168 "Use weapons better than the ones specified in the goal variant, if there are ordnance points left to mount them.\n\n" +
169 "Will add flux vents and capacitors up to the number specified in the goal variant first, " +
170 "then upgrade weapons, and then add more vents and some common hullmods.\n\n" +
171 "Leaving some unspent ordnance points in a goal variant can help take advantage of this option."));
172 options.add(
new AutofitOption(
STRIP,
"Strip before autofitting",
true,
173 "Remove everything possible prior to autofitting; generally results in a better fit.\n\n" +
174 "However, refitting outside of port reduces a ship's combat readiness, and this option tends to lead to more changes and more readiness lost."));
176 "Prioritizes installing the \"Reinforced Bulkheads\" hullmod, which increases hull integrity and " +
177 "makes a ship virtually certain to be recoverable if lost in battle.\n\n" +
178 "\"Reinforced Bulkheads\" may still be added if this option isn't checked, provided there are enough ordnance points."));
180 "Prioritizes installing the \"Blast Doors\" hullmod, which increases hull integrity and " +
181 "greatly reduces crew losses suffered due to hull damage.\n\n" +
182 "\"Blast Doors\" may still be added if this option isn't checked, provided there are enough ordnance points."));
183 options.add(
new AutofitOption(
RANDOMIZE,
"Randomize weapons and hullmods",
false,
184 "Makes the loadout only loosely based on the goal variant."));
219 for (String
id : current.getFittedWeaponSlots()) {
220 WeaponSlotAPI slot = current.getSlot(
id);
221 if (slot.isDecorative() || slot.isBuiltIn() || slot.isHidden() ||
222 slot.isSystemSlot() || slot.isStationModule())
continue;
229 for (
int i = 0; i < numBays; i++) {
230 if (current.getWingId(i) !=
null) {
238 protected Map<String, AvailableWeapon>
fittedWeapons =
new HashMap<String, AvailableWeapon>();
239 protected Map<String, AvailableFighter>
fittedFighters =
new HashMap<String, AvailableFighter>();
245 cost += w.getPrice();
248 cost += w.getPrice();
282 current.setMayAutoAssignWeapons(
false);
283 current.getStationModules().putAll(target.getStationModules());
286 for (String slotId : current.getStationModules().keySet()) {
287 ShipVariantAPI moduleCurrent = current.getModuleVariant(slotId);
288 boolean forceClone =
false;
289 if (moduleCurrent ==
null) {
292 moduleCurrent = target.getModuleVariant(slotId);
295 if (moduleCurrent ==
null) {
296 String variantId = current.getHullVariantId();
297 throw new RuntimeException(
"Module variant for slotId [" + slotId +
"] not found for " +
298 "variantId [" + variantId +
"] of hull [" + current.getHullSpec().getHullId() +
"]");
301 if (moduleCurrent.isStockVariant() || forceClone) {
302 moduleCurrent = moduleCurrent.clone();
303 moduleCurrent.setSource(VariantSource.REFIT);
305 moduleCurrent.setHullVariantId(moduleCurrent.getHullVariantId() +
"_" + index);
312 ShipVariantAPI moduleTarget = target.getModuleVariant(slotId);
313 if (moduleTarget ==
null)
continue;
316 doFit(moduleCurrent, moduleTarget, 0, delegate);
319 current.setModuleVariant(slotId, moduleCurrent);
321 current.setSource(VariantSource.REFIT);
343 current.setNumFluxCapacitors(0);
344 current.setNumFluxVents(0);
346 for (String modId : current.getNonBuiltInHullmods()) {
349 current.removeMod(modId);
353 current.clearHullMods();
359 slotsToSkip.addAll(current.getFittedWeaponSlots());
360 for (
int i = 0; i < 20; i++) {
361 String wingId = current.getWingId(i);
362 if (wingId !=
null && !wingId.isEmpty()) {
374 if (reinforcedHull) {
375 addHullmods(current, delegate, HullMods.REINFORCEDHULL);
378 addHullmods(current, delegate, HullMods.BLAST_DOORS);
381 List<String> targetMods =
new ArrayList<String>();
382 for (String
id : target.getNonBuiltInHullmods()) {
386 if (!targetMods.isEmpty()) {
387 addHullmods(current, delegate, targetMods.toArray(
new String[0]));
390 int addedRandomHullmodPts = 0;
399 if (current.hasHullMod(HullMods.FRAGILE_SUBSYSTEMS) &&
400 (current.getHullSize() == HullSize.FRIGATE || current.getHullSize() == HullSize.DESTROYER)) {
401 addHullmods(current, delegate, HullMods.HARDENED_SUBSYSTEMS);
405 float addedMax = current.getHullSpec().getOrdnancePoints(
stats) * 0.1f;
406 if (
randomize && addedRandomHullmodPts <= addedMax) {
410 float ventsCapsFraction = 1f;
413 ventsCapsFraction = 0.5f;
436 addHullmods(current, delegate, HullMods.REINFORCEDHULL, HullMods.BLAST_DOORS, HullMods.HARDENED_SUBSYSTEMS);
445 if (!current.hasHullMod(HullMods.FLUX_DISTRIBUTOR)) {
448 if (!current.hasHullMod(HullMods.FLUX_COIL)) {
453 if (current.getHullSize() == HullSize.FRIGATE || current.hasHullMod(HullMods.SAFETYOVERRIDES)) {
454 addHullmods(current, delegate, HullMods.HARDENED_SUBSYSTEMS, HullMods.REINFORCEDHULL, HullMods.BLAST_DOORS);
456 addHullmods(current, delegate, HullMods.REINFORCEDHULL, HullMods.BLAST_DOORS, HullMods.HARDENED_SUBSYSTEMS);
458 int remaining = maxSMods - added;
460 List<String> mods =
new ArrayList<String>();
461 mods.add(HullMods.FLUX_DISTRIBUTOR);
462 mods.add(HullMods.FLUX_COIL);
463 if (current.getHullSize() == HullSize.FRIGATE || current.hasHullMod(HullMods.SAFETYOVERRIDES)) {
464 mods.add(HullMods.HARDENED_SUBSYSTEMS);
465 mods.add(HullMods.REINFORCEDHULL);
467 mods.add(HullMods.REINFORCEDHULL);
468 mods.add(HullMods.HARDENED_SUBSYSTEMS);
470 mods.add(HullMods.BLAST_DOORS);
471 Iterator<String> iter = mods.iterator();
472 while (iter.hasNext()) {
473 String modId = iter.next();
474 if (current.getPermaMods().contains(modId)) {
481 for (
int i = 0; i < remaining && !mods.isEmpty(); i++) {
482 current.setNumFluxCapacitors(0);
483 current.setNumFluxVents(0);
484 String modId = mods.get(Math.min(i, mods.size() - 1));
494 if (current.getHullSpec().isPhase()) {
500 addHullmods(current, delegate, HullMods.ARMOREDWEAPONS);
501 int opCost = current.computeOPCost(
stats);
502 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
503 int opLeft = opMax - opCost;
508 if (current.getHullSpec().isPhase()) {
515 current.setVariantDisplayName(target.getDisplayName());
517 current.getWeaponGroups().clear();
518 for (WeaponGroupSpec group : target.getWeaponGroups()) {
519 WeaponGroupSpec copy =
new WeaponGroupSpec(group.getType());
520 copy.setAutofireOnByDefault(group.isAutofireOnByDefault());
521 for (String slotId : group.getSlots()) {
522 if (current.getWeaponId(slotId) !=
null) {
523 copy.addSlot(slotId);
526 if (!copy.getSlots().isEmpty()) {
527 current.addWeaponGroup(copy);
532 if (current.getWeaponGroups().isEmpty() ||
randomize || current.hasUnassignedWeapons()) {
533 current.setMayAutoAssignWeapons(
true);
534 current.autoGenerateWeaponGroups();
538 current.getWeaponGroups().clear();
547 if (num <= 0)
return 0;
549 List<HullModSpecAPI> mods =
new ArrayList<HullModSpecAPI>();
550 for (String
id : current.getHullMods()) {
551 if (current.getPermaMods().contains(
id))
continue;
552 if (current.getHullSpec().getBuiltInMods().contains(
id))
continue;
553 HullModSpecAPI mod = DModManager.getMod(
id);
554 if (mod.hasTag(Tags.HULLMOD_NO_BUILD_IN))
continue;
558 final HullSize size = current.getHullSize();
559 Collections.sort(mods,
new Comparator<HullModSpecAPI>() {
560 public int compare(HullModSpecAPI o1, HullModSpecAPI o2) {
561 return Misc.getOPCost(o2, size) - Misc.getOPCost(o1, size);
566 for (
int i = 0; i < num && i < mods.size(); i++) {
567 String
id = mods.get(i).getId();
568 current.addPermaMod(
id,
true);
575 int opCost = current.computeOPCost(
stats);
576 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
577 int opLeft = opMax - opCost;
579 if (opLeft <= 0)
return;
581 float total = target.getNumFluxVents() + target.getNumFluxCapacitors();
582 float ventsFraction = 1f;
584 ventsFraction = target.getNumFluxVents() / total;
588 if (ventsFraction >= 0.5f) {
596 if (ventsFraction >= 0.5f) {
607 int opCost = current.computeOPCost(
stats);
608 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
609 int opLeft = opMax - opCost;
611 if (opLeft <= 0)
return;
613 int vents = current.getNumFluxVents();
615 HullModSpecAPI coil = Misc.getMod(HullMods.FLUX_COIL);
616 int cost = coil.getCostFor(current.getHullSize());
618 if (cost < opLeft + vents * 0.3f) {
619 int remove = cost - opLeft;
621 opLeft -=
addVents(-
remove, current, 1000);
628 int opCost = current.computeOPCost(
stats);
629 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
630 int opLeft = opMax - opCost;
632 if (opLeft <= 0)
return;
634 int caps = current.getNumFluxCapacitors();
636 HullModSpecAPI coil = Misc.getMod(HullMods.FLUX_COIL);
637 int cost = coil.getCostFor(current.getHullSize());
639 if (cost < opLeft + caps * 0.3f) {
640 int remove = cost - opLeft;
649 int opCost = current.computeOPCost(
stats);
650 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
651 int opLeft = opMax - opCost;
653 if (opLeft <= 0)
return;
655 int caps = current.getNumFluxCapacitors();
657 HullModSpecAPI distributor = Misc.getMod(HullMods.FLUX_DISTRIBUTOR);
658 int cost = distributor.getCostFor(current.getHullSize());
660 if (cost <= opLeft + caps * 0.3f) {
661 int remove = cost - opLeft;
665 opLeft -=
addModIfPossible(HullMods.FLUX_DISTRIBUTOR, delegate, current, opLeft);
670 int opCost = current.computeOPCost(
stats);
671 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
672 int opLeft = opMax - opCost;
674 if (opLeft <= 0)
return;
676 int vents = current.getNumFluxVents();
678 HullModSpecAPI distributor = Misc.getMod(HullMods.FLUX_DISTRIBUTOR);
679 int cost = distributor.getCostFor(current.getHullSize());
681 if (cost <= opLeft + vents * 0.3f) {
682 int remove = cost - opLeft;
684 opLeft -=
addVents(-
remove, current, 1000);
686 opLeft -=
addModIfPossible(HullMods.FLUX_DISTRIBUTOR, delegate, current, opLeft);
698 List<AvailableWeapon> weapons =
new ArrayList<AvailableWeapon>(delegate.
getAvailableWeapons());
700 Iterator<AvailableWeapon> iter = weapons.iterator();
701 while (iter.hasNext()) {
719 boolean automated = Misc.isAutomated(delegate.
getShip());
720 List<AvailableFighter> fighters =
new ArrayList<AvailableFighter>(delegate.
getAvailableFighters());
721 Iterator<AvailableFighter> iter = fighters.iterator();
722 while (iter.hasNext()) {
725 (automated && !f.
getWingSpec().hasTag(Tags.AUTOMATED_FIGHTER)) ||
738 int opCost = current.computeOPCost(
stats);
739 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
740 int opLeft = opMax - opCost;
743 for (String mod : mods) {
744 if (current.hasHullMod(mod))
continue;
749 if (mod.equals(HullMods.INTEGRATED_TARGETING_UNIT) &&
750 current.getHullSize().ordinal() >= HullSize.CRUISER.ordinal()) {
751 mod = HullMods.DEDICATED_TARGETING_CORE;
757 if (mod.equals(HullMods.DEDICATED_TARGETING_CORE) &&
758 availableMods.contains(HullMods.INTEGRATED_TARGETING_UNIT)) {
759 mod = HullMods.INTEGRATED_TARGETING_UNIT;
762 HullModSpecAPI modSpec = Misc.getMod(mod);
764 if (mod.equals(HullMods.INTEGRATED_TARGETING_UNIT) &&
765 current.hasHullMod(HullMods.DEDICATED_TARGETING_CORE)) {
766 current.removeMod(HullMods.DEDICATED_TARGETING_CORE);
767 HullModSpecAPI dtc = Misc.getMod(HullMods.DEDICATED_TARGETING_CORE);
768 int cost = dtc.getCostFor(current.getHullSize());;
774 if (current.hasHullMod(HullMods.ADVANCED_TARGETING_CORE) || current.hasHullMod(HullMods.DISTRIBUTED_FIRE_CONTROL)) {
775 if (mod.equals(HullMods.INTEGRATED_TARGETING_UNIT)) {
778 if (mod.equals(HullMods.DEDICATED_TARGETING_CORE)) {
783 if (current.getHullSpec().isPhase()) {
784 if (modSpec.hasTag(HullMods.TAG_NON_PHASE)) {
788 if (!current.getHullSpec().isPhase()) {
789 if (modSpec.hasTag(HullMods.TAG_PHASE)) {
804 if (current.hasHullMod(
id))
return 0;
807 HullModSpecAPI mod = Misc.getMod(
id);
812 if (mod ==
null)
return 0;
814 if (current.hasHullMod(mod.getId()))
return 0;
818 int cost = mod.getCostFor(current.getHullSize());
819 if (cost > opLeft)
return 0;
821 ShipAPI ship = delegate.
getShip();
822 ShipVariantAPI orig =
null;
828 orig = ship.getVariant();
829 ship.setVariantForHullmodCheckOnly(current);
831 if (ship !=
null && mod.getEffect() !=
null && ship.getVariant() !=
null && !mod.getEffect().isApplicableToShip(ship)
832 && !ship.getVariant().hasHullMod(mod.getId())) {
834 ship.setVariantForHullmodCheckOnly(orig);
839 if (orig !=
null && ship !=
null) {
840 ship.setVariantForHullmodCheckOnly(orig);
843 current.addMod(mod.getId());
849 public void addVentsAndCaps(ShipVariantAPI current, ShipVariantAPI target,
float fraction) {
850 if (fraction < 0)
return;
852 int opCost = current.computeOPCost(
stats);
853 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
854 int opLeft = opMax - opCost;
857 int maxCapacitors =
getMaxCaps(current.getHullSize());
859 int add = Math.max((
int)Math.ceil(target.getNumFluxVents() * fraction) - current.getNumFluxVents(), 0);
860 if (add > opLeft) add = opLeft;
861 opLeft -=
addVents(add, current, maxVents);
863 add = Math.max((
int)Math.ceil(target.getNumFluxCapacitors() * fraction) - current.getNumFluxCapacitors(), 0);
864 if (add > opLeft) add = opLeft;
869 int opCost = current.computeOPCost(
stats);
870 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
871 int opLeft = opMax - opCost;
875 opLeft -=
addVents((
int) opLeft, current, maxVents);
880 int opCost = current.computeOPCost(
stats);
881 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
882 int opLeft = opMax - opCost;
885 int maxCaps =
getMaxCaps(current.getHullSize());
891 int opCost = current.computeOPCost(
stats);
892 int opMax = current.getHullSpec().getOrdnancePoints(
stats);
893 int opLeft = opMax - opCost;
896 int maxCapacitors =
getMaxCaps(current.getHullSize());
899 float total = current.getNumFluxVents() + current.getNumFluxCapacitors();
900 float ventsFraction = 1f;
902 ventsFraction = current.getNumFluxVents() / total;
905 int add = (int) (opLeft * ventsFraction);
906 opLeft -=
addVents(add, current, maxVents);
911 opLeft -=
addVents(add, current, maxVents);
914 if (target !=
null) {
915 float targetVents = target.getNumFluxVents();
916 float targetCaps = target.getNumFluxCapacitors();
918 if (targetVents > targetCaps || targetVents >= maxVents) {
919 float currVents = current.getNumFluxVents();
920 float currCaps = current.getNumFluxCapacitors();
921 float currTotal = currVents + currCaps;
923 int currVentsDesired = (int) (currVents + currCaps * 0.5f);
924 if (currVentsDesired > maxVents) currVentsDesired = maxVents;
925 int currCapsDesired = (int) (currTotal - currVentsDesired);
926 if (currCapsDesired > maxCapacitors) currCapsDesired = maxCapacitors;
927 current.setNumFluxVents(currVentsDesired);
928 current.setNumFluxCapacitors(currCapsDesired);
952 maxVents = (int)
stats.getMaxVentsBonus().computeEffective(maxVents);
960 maxCapacitors = (int)
stats.getMaxCapacitorsBonus().computeEffective(maxCapacitors);
962 return maxCapacitors;
968 case CAPITAL_SHIP: max = 50;
break;
969 case CRUISER: max = 30;
break;
970 case DESTROYER: max = 20;
break;
971 case FRIGATE: max = 10;
break;
977 public int addVents(
int add, ShipVariantAPI current,
int max) {
978 int target = current.getNumFluxVents() + add;
979 if (target > max) target = max;
980 if (target < 0) target = 0;
981 int actual = target - current.getNumFluxVents();
982 current.setNumFluxVents(target);
987 int target = current.getNumFluxCapacitors() + add;
988 if (target > max) target = max;
989 if (target < 0) target = 0;
990 int actual = target - current.getNumFluxCapacitors();
991 current.setNumFluxCapacitors(target);
996 fittedWeapons.remove(variant.getHullVariantId() +
"_" + slot.getId());
1012 Set<String> alreadyUsed =
new HashSet<String>();
1020 float opCost = current.computeOPCost(
stats);
1021 float opMax = current.getHullSpec().getOrdnancePoints(
stats);
1022 float opLeft = opMax - opCost;
1024 float levelToBeat = -1;
1026 WeaponSpecAPI curr = current.getWeaponSpec(slot.getId());
1028 float cost = curr.getOrdnancePointCost(
stats, current.getStatsForOpCosts());
1031 for (String tag : curr.getTags()) {
1032 levelToBeat = Math.max(levelToBeat,
getLevel(tag));
1040 WeaponSpecAPI desired = target.getWeaponSpec(slot.getId());
1042 if (desired ==
null)
continue;
1044 List<AvailableWeapon> weapons =
getWeapons(delegate);
1045 List<AvailableWeapon> possible =
getPossibleWeapons(slot, desired, current, opLeft, weapons);
1046 if (possible.isEmpty())
continue;
1055 List<String>
categories = desired.getAutofitCategoriesInPriorityOrder();
1059 if (alternate ==
null) {
1060 alternate =
new ArrayList<String>();
1062 Category category = this.categories.get(cat);
1063 if (category ==
null) {
1067 if (!category.fallback.isEmpty()) {
1068 int index =
random.nextInt(category.fallback.size()/2) + 1;
1071 alternate.add(category.fallback.get(index));
1077 if (!alternate.isEmpty()) {
1087 pick =
getBestMatch(desired, upgradeMode, catId, alreadyUsed, possible, slot, delegate);
1091 if (upgradeMode)
break;
1094 if (pick ==
null && !upgradeMode) {
1096 Category cat = this.categories.get(catId);
1097 if (cat ==
null)
continue;
1099 for (String fallbackCatId : cat.fallback) {
1100 pick =
getBestMatch(desired,
true, fallbackCatId, alreadyUsed, possible, delegate);
1110 float pickLevel = -1;
1112 Category cat = this.categories.get(
categories.get(0));
1121 if (pickLevel <= levelToBeat)
continue;
1124 alreadyUsed.add(pick.
getId());
1128 fittedWeapons.put(current.getHullVariantId() +
"_" + slot.getId(), pick);
1130 if (pick.
getSpec().getType() == WeaponType.MISSILE && pick.
getSpec().usesAmmo()) {
1145 Set<String> alreadyUsed =
new HashSet<String>();
1147 for (
int i = 0; i < numBays; i++) {
1150 float opCost = current.computeOPCost(
stats);
1151 float opMax = current.getHullSpec().getOrdnancePoints(
stats);
1152 float opLeft = opMax - opCost;
1154 float levelToBeat = -1;
1156 FighterWingSpecAPI curr = current.getWing(i);
1158 float cost = curr.getOpCost(current.getStatsForOpCosts());
1161 for (String tag : curr.getTags()) {
1162 levelToBeat = Math.max(levelToBeat,
getLevel(tag));
1169 if (current.getWingId(i) !=
null) {
1174 List<AvailableFighter> fighters =
getFighters(delegate);
1176 if (possible.isEmpty())
continue;
1178 String desiredWingId = target.getWingId(i);
1179 if (desiredWingId ==
null || desiredWingId.isEmpty()) {
1188 if (desired ==
null)
continue;
1191 List<String>
categories = desired.getAutofitCategoriesInPriorityOrder();
1195 if (alternate ==
null) {
1196 alternate =
new ArrayList<String>();
1198 Category category = this.categories.get(cat);
1199 if (category ==
null) {
1203 if (!category.fallback.isEmpty()) {
1204 int index =
random.nextInt(category.fallback.size() - 1) + 1;
1206 alternate.add(category.fallback.get(index));
1212 if (!alternate.isEmpty()) {
1222 pick =
getBestMatch(desired, upgradeMode, catId, alreadyUsed, possible, delegate);
1226 if (upgradeMode)
break;
1229 if (pick ==
null && !upgradeMode) {
1231 Category cat = this.categories.get(catId);
1232 if (cat ==
null)
continue;
1234 for (String fallbackCatId : cat.fallback) {
1235 pick =
getBestMatch(desired,
true, fallbackCatId, alreadyUsed, possible, delegate);
1245 float pickLevel = -1;
1247 Category cat = this.categories.get(
categories.get(0));
1256 if (pickLevel <= levelToBeat)
continue;
1259 alreadyUsed.add(pick.
getId());
1273 String catId, Set<String> alreadyUsed, List<AvailableWeapon> possible,
1275 return getBestMatch(desired, useBetter, catId, alreadyUsed, possible,
null, delegate);
1279 String catId, Set<String> alreadyUsed, List<AvailableWeapon> possible,
1283 float bestScore = -1f;
1284 boolean bestIsPriority =
false;
1288 if (cat ==
null)
return null;
1291 float desiredLevel =
getLevel(desiredTag);
1293 if (desiredTag ==
null) {
1298 desiredLevel = 10000f;
1301 boolean longRange = desired.hasTag(
LR);
1302 boolean shortRange = desired.hasTag(
SR);
1303 boolean midRange = !longRange && !shortRange;
1304 boolean desiredPD = desired.getAIHints().contains(AIHints.PD);
1306 WeightedRandomPicker<AvailableWeapon> best =
new WeightedRandomPicker<AvailableWeapon>(
random);
1320 WeaponSpecAPI spec = w.getSpec();
1322 if (catTag ==
null)
continue;
1328 boolean currLongRange = spec.hasTag(
LR);
1329 boolean currShortRange = spec.hasTag(
SR);
1330 boolean currMidRange = !currLongRange && !currShortRange;
1333 if (!desiredPD && currShortRange && (midRange || longRange))
continue;
1336 boolean isPrimaryCategory = cat.base.equals(spec.getAutofitCategory());
1337 boolean currIsPriority = isPrimaryCategory && delegate.
isPriority(spec);
1338 int currSize = spec.getSize().ordinal();
1339 boolean betterDueToPriority = currSize >= bestSize && currIsPriority && !bestIsPriority;
1340 boolean worseDueToPriority = currSize <= bestSize && !currIsPriority && bestIsPriority;
1342 if (worseDueToPriority)
continue;
1346 if (!
randomize && !useBetter && !betterDueToPriority && level > desiredLevel)
continue;
1348 if (
randomize && desired.getSize() == spec.getSize()) {
1350 }
else if (desired.getSize() == spec.getSize()) {
1357 boolean symmetric =
random.nextFloat() < 0.75f;
1358 if (slot !=
null && symmetric) {
1359 long seed = (Math.abs((
int)(slot.getLocation().x/2f)) * 723489413945245311L) ^ 1181783497276652981L;
1361 level += r.nextInt(rMag);
1363 level +=
random.nextInt(rMag);
1368 float score = level;
1372 if ((score > bestScore || betterDueToPriority)) {
1377 bestSize = currSize;
1378 bestIsPriority = currIsPriority;
1379 }
else if (score == bestScore) {
1390 List<AvailableWeapon> allMatches =
new ArrayList<AvailableWeapon>();
1391 List<AvailableWeapon> freeMatches =
new ArrayList<AvailableWeapon>();
1393 if (desired.getWeaponId().equals(w.getId())) {
1395 if (w.getPrice() <= 0) {
1400 if (!freeMatches.isEmpty())
return freeMatches.get(0);
1401 if (!allMatches.isEmpty())
return allMatches.get(0);
1404 boolean hasFree =
false;
1405 boolean hasNonBlackMarket =
false;
1407 if (w.getPrice() <= 0) {
1410 if (w.getSubmarket() ==
null || !w.getSubmarket().getPlugin().isBlackMarket()) {
1411 hasNonBlackMarket =
true;
1415 for (
AvailableWeapon w :
new ArrayList<AvailableWeapon>(best.getItems())) {
1416 if (w.getPrice() > 0) {
1420 }
else if (hasNonBlackMarket) {
1421 for (
AvailableWeapon w :
new ArrayList<AvailableWeapon>(best.getItems())) {
1422 if (w.getSubmarket() !=
null && w.getSubmarket().getPlugin().isBlackMarket()) {
1429 if (!alreadyUsed.isEmpty()) {
1431 if (alreadyUsed.contains(w.getId()))
return w;
1435 if (best.isEmpty())
return null;
1443 String catId, Set<String> alreadyUsed, List<AvailableFighter> possible,
1445 float bestScore = -1f;
1446 boolean bestIsPriority =
false;
1449 if (cat ==
null)
return null;
1452 float desiredLevel =
getLevel(desiredTag);
1454 WeightedRandomPicker<AvailableFighter> best =
new WeightedRandomPicker<AvailableFighter>(
random);
1457 FighterWingSpecAPI spec = f.getWingSpec();
1459 if (catTag ==
null)
continue;
1461 boolean isPrimaryCategory = cat.base.equals(spec.getAutofitCategory());
1462 boolean currIsPriority = isPrimaryCategory && delegate.
isPriority(spec);
1463 boolean betterDueToPriority = currIsPriority && !bestIsPriority;
1464 boolean worseDueToPriority = !currIsPriority && bestIsPriority;
1466 if (worseDueToPriority)
continue;
1469 if (!
randomize && !useBetter && !betterDueToPriority && level > desiredLevel)
continue;
1481 level +=
random.nextInt(rMag);
1484 float score = level;
1488 if (score > bestScore || betterDueToPriority) {
1493 bestIsPriority = currIsPriority;
1494 }
else if (score == bestScore) {
1501 List<AvailableFighter> allMatches =
new ArrayList<AvailableFighter>();
1502 List<AvailableFighter> freeMatches =
new ArrayList<AvailableFighter>();
1504 if (desired.getId().equals(f.getId())) {
1506 if (f.getPrice() <= 0) {
1511 if (!freeMatches.isEmpty())
return freeMatches.get(0);
1512 if (!allMatches.isEmpty())
return allMatches.get(0);
1516 boolean hasFree =
false;
1517 boolean hasNonBlackMarket =
false;
1519 if (f.getPrice() <= 0) {
1522 if (f.getSubmarket() ==
null || !f.getSubmarket().getPlugin().isBlackMarket()) {
1523 hasNonBlackMarket =
true;
1527 for (
AvailableFighter f :
new ArrayList<AvailableFighter>(best.getItems())) {
1528 if (f.getPrice() > 0) {
1532 }
else if (hasNonBlackMarket) {
1533 for (
AvailableFighter f :
new ArrayList<AvailableFighter>(best.getItems())) {
1534 if (f.getSubmarket() !=
null && f.getSubmarket().getPlugin().isBlackMarket()) {
1542 if (!alreadyUsed.isEmpty()) {
1544 if (alreadyUsed.contains(f.getId()))
return f;
1548 if (best.isEmpty())
return null;
1555 String catTag =
null;
1556 for (String tag : tags) {
1557 if (cat.tags.contains(tag)) {
1566 protected static transient Map<String, Integer>
tagLevels =
new HashMap<String, Integer>();
1571 if (result !=
null)
return result;
1578 result = (int) Float.parseFloat(tag.replaceAll(cat.base,
""));
1581 }
catch (Throwable t) {
1610 List<WeaponSlotAPI> result =
new ArrayList<WeaponSlotAPI>();
1612 for (WeaponSlotAPI slot : current.getHullSpec().getAllWeaponSlotsCopy()) {
1613 if (slot.isBuiltIn() || slot.isDecorative())
continue;
1614 if (target.getWeaponId(slot.getId()) ==
null)
continue;
1615 if (!upgradeMode && current.getWeaponId(slot.getId()) !=
null)
continue;
1619 Collections.sort(result,
new Comparator<WeaponSlotAPI>() {
1620 public int compare(WeaponSlotAPI w1, WeaponSlotAPI w2) {
1623 return (
int) Math.signum(s2 - s1);
1633 switch (slot.getSlotSize()) {
1634 case LARGE: score = 10000;
break;
1635 case MEDIUM: score = 5000;
break;
1636 case SMALL: score = 2500;
break;
1638 float angleDiff = Misc.getAngleDiff(slot.getAngle(), 0);
1639 boolean front = Misc.isInArc(slot.getAngle(), slot.getArc(), 0);
1642 score += 180f - angleDiff;
1650 public List<AvailableWeapon>
getPossibleWeapons(WeaponSlotAPI slot, WeaponSpecAPI desired, ShipVariantAPI current,
float opLeft, List<AvailableWeapon> weapons) {
1651 List<AvailableWeapon> result =
new ArrayList<AvailableWeapon>();
1654 if (w.getQuantity() <= 0)
continue;
1656 WeaponSpecAPI spec = w.getSpec();
1658 float cost = w.getOPCost(
stats, current.getStatsForOpCosts());
1659 if (cost > opLeft)
continue;
1660 if (!slot.weaponFits(spec))
continue;
1662 if (spec != desired &&
1663 (spec.getType() == WeaponType.MISSILE || spec.getAIHints().contains(AIHints.STRIKE))) {
1664 boolean guided = spec.getAIHints().contains(AIHints.DO_NOT_AIM);
1666 boolean guidedPoor = spec.getAIHints().contains(AIHints.GUIDED_POOR);
1667 float angleDiff = Misc.getDistanceFromArc(slot.getAngle(), slot.getArc(), 0);
1668 if (angleDiff > 45 || (!guidedPoor && angleDiff > 20))
continue;
1677 int num = Math.max(1, result.size() / 3 * 2);
1678 Set<Integer> picks = DefaultFleetInflater.makePicks(num, result.size(), filterRandom);
1679 List<AvailableWeapon> filtered =
new ArrayList<AvailableWeapon>();
1680 for (Integer pick : picks) {
1681 filtered.add(result.get(pick));
1686 if (TutorialMissionIntel.isTutorialInProgress() &&
1687 current.getHullSpec() !=
null && current.getHullSpec().hasTag(Factions.DERELICT)) {
1688 List<AvailableWeapon>
remove =
new ArrayList<AvailableWeapon>();
1690 if (w.getId().equals(
"heatseeker")) {
1694 result.removeAll(
remove);
1700 public List<AvailableFighter>
getPossibleFighters(ShipVariantAPI current,
float opLeft, List<AvailableFighter> fighters) {
1701 List<AvailableFighter> result =
new ArrayList<AvailableFighter>();
1704 if (f.getQuantity() <= 0)
continue;
1706 FighterWingSpecAPI spec = f.getWingSpec();
1707 float cost = spec.getOpCost(current.getStatsForOpCosts());
1708 if (cost > opLeft)
continue;
1715 int num = Math.max(1, result.size() / 3 * 2);
1716 Set<Integer> picks = DefaultFleetInflater.makePicks(num, result.size(), filterRandom);
1717 List<AvailableFighter> filtered =
new ArrayList<AvailableFighter>();
1718 for (Integer pick : picks) {
1719 filtered.add(result.get(pick));
1763 if (current.getHullSize().ordinal() >= HullSize.DESTROYER.ordinal() && !current.isCivilian()) {
1764 addHullmods(current, delegate, HullMods.INTEGRATED_TARGETING_UNIT);
1775 addHullmods(current, delegate, HullMods.REINFORCEDHULL, HullMods.BLAST_DOORS, HullMods.HARDENED_SUBSYSTEMS);
1784 return "Spend free OP";
1788 return "Spend any unused ordnance points on flux vents, capacitors, and essential hullmods.\n\n" +
1790 "Will not make any changes to weapon loadout, will not affect ship modules (if any), and will not spend any credits.";
1794 int unusedOpTotal = 0;
1795 for (String slotId : currentVariant.getStationModules().keySet()) {
1796 ShipVariantAPI moduleCurrent = currentVariant.getModuleVariant(slotId);
1797 if (moduleCurrent ==
null)
continue;
1798 unusedOpTotal += moduleCurrent.getUnusedOP(
stats);
1800 unusedOpTotal += currentVariant.getUnusedOP(
stats);
1801 return unusedOpTotal > 0;
1807 public static class AutoAssignScore {
1808 public float [] score;
1809 public FleetMemberAPI member;
1810 public PersonAPI officer;
1816 List<FleetMemberAPI> members =
new ArrayList<FleetMemberAPI>();
1817 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
1818 if (member.isMothballed()) {
1821 if (!member.getCaptain().isDefault()) {
1824 if (fleet.isPlayerFleet() && Misc.isAutomated(member))
continue;
1825 members.add(member);
1828 List<OfficerDataAPI> officers =
new ArrayList<OfficerDataAPI>();
1829 int max = (int) fleet.getCommander().getStats().getOfficerNumber().getModifiedValue();
1831 for (OfficerDataAPI officer : fleet.getFleetData().getOfficersCopy()) {
1832 boolean merc = Misc.isMercenary(officer.getPerson());
1836 if (count > max && !merc)
continue;
1838 boolean found =
false;
1839 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
1840 if (member.getCaptain() == officer.getPerson()) {
1846 officers.add(officer);
1851 List<AutoAssignScore> shipScores =
new ArrayList<AutoAssignScore>();
1852 List<AutoAssignScore> officerScores =
new ArrayList<AutoAssignScore>();
1854 float maxMemberTotal = 1f;
1855 float maxOfficerTotal = 1f;
1857 for (FleetMemberAPI member : members) {
1858 AutoAssignScore score =
new AutoAssignScore();
1859 shipScores.add(score);
1860 score.member = member;
1863 maxMemberTotal = Math.max(maxMemberTotal, score.score[4]);
1866 for (OfficerDataAPI officer : officers) {
1867 AutoAssignScore score =
new AutoAssignScore();
1868 officerScores.add(score);
1869 score.officer = officer.getPerson();
1871 maxOfficerTotal = Math.max(maxOfficerTotal, score.score[4]);
1874 for (AutoAssignScore score : officerScores) {
1877 score.score[4] = maxMemberTotal + (maxOfficerTotal - score.score[4]);
1880 while (!shipScores.isEmpty() && !officerScores.isEmpty()) {
1881 float minDist = Float.MAX_VALUE;
1882 AutoAssignScore bestShip =
null;
1883 AutoAssignScore bestOfficer =
null;
1884 for (AutoAssignScore ship : shipScores) {
1888 for (AutoAssignScore officer : officerScores) {
1889 float dist = Math.abs(ship.score[0] - officer.score[0]) +
1890 Math.abs(ship.score[1] - officer.score[1]) +
1891 Math.abs(ship.score[2] - officer.score[2]) +
1892 Math.abs(ship.score[3] - officer.score[3]) +
1893 Math.abs(ship.score[4] - officer.score[4]);
1895 if (dist < minDist) {
1898 bestOfficer = officer;
1902 if (bestShip ==
null) {
1906 shipScores.remove(bestShip);
1907 officerScores.remove(bestOfficer);
1908 bestShip.member.setCaptain(bestOfficer.officer);
1914 float ballistic = 0f;
1919 for (SkillLevelAPI sl : officer.getStats().getSkillsCopy()) {
1920 if (!sl.getSkill().isCombatOfficerSkill())
continue;
1921 float w = sl.getLevel();
1922 if (w == 2) w = 1.33f;
1927 if (sl.getSkill().hasTag(Skills.TAG_ENERGY_WEAPONS)) {
1929 }
else if (sl.getSkill().hasTag(Skills.TAG_BALLISTIC_WEAPONS)) {
1931 }
else if (sl.getSkill().hasTag(Skills.TAG_MISSILE_WEAPONS)) {
1933 }
else if (sl.getSkill().hasTag(Skills.TAG_ACTIVE_DEFENSES)) {
1939 if (total < 1f) total = 1f;
1945 float [] result =
new float [5];
1947 result[1] = ballistic;
1948 result[2] = missile;
1949 result[3] = defense;
1956 float ballistic = 0f;
1960 boolean civ = member.isCivilian();
1962 for (String slotId : member.getVariant().getFittedWeaponSlots()) {
1963 WeaponSlotAPI slot = member.getVariant().getSlot(slotId);
1964 if (slot.isDecorative() || slot.isSystemSlot())
continue;
1966 WeaponSpecAPI weapon = member.getVariant().getWeaponSpec(slotId);
1968 switch (weapon.getSize()) {
1969 case LARGE: w = 4f;
break;
1970 case MEDIUM: w = 2f;
break;
1971 case SMALL: w = 1f;
break;
1974 WeaponType type = weapon.getType();
1975 if (type == WeaponType.BALLISTIC) {
1978 }
else if (type == WeaponType.ENERGY) {
1981 }
else if (type == WeaponType.MISSILE) {
1988 if (total < 1f) total = 1f;
1993 boolean d = member.getHullSpec().getShieldType() == ShieldType.FRONT ||
1994 member.getHullSpec().getShieldType() == ShieldType.OMNI ||
1995 member.getHullSpec().isPhase();
1997 float [] result =
new float [5];
1999 result[1] = ballistic;
2000 result[2] = missile;
2015 float op = member.getVariant().getHullSpec().getOrdnancePoints(
stats);
2017 f = (op - member.getVariant().getUnusedOP(
stats)) / op;
2024 for (SkillLevelAPI skill : officer.getPerson().getStats().getSkillsCopy()) {
2025 SkillSpecAPI spec = skill.getSkill();
2026 if (!spec.isCombatOfficerSkill())
continue;
2028 float level = skill.getLevel();
2029 if (level <= 0)
continue;
2031 if (!carrier || spec.hasTag(Skills.TAG_CARRIER)) {
2042 if (
random.nextFloat() > 0.5f){
2044 if (
random.nextFloat() > 0.75f) {
2049 if (num <= 0)
return 0;
2051 ShipHullSpecAPI hull = current.getHullSpec();
2052 boolean omni = hull.getShieldType() == ShieldType.OMNI;
2053 boolean front = hull.getShieldType() == ShieldType.FRONT;
2054 boolean shield = omni || front;
2055 boolean phase = hull.getShieldType() == ShieldType.PHASE;
2056 int bays = hull.getFighterBays();
2057 float shieldArc = hull.getShieldSpec().getArc();
2060 WeightedRandomPicker<String> picker =
new WeightedRandomPicker<String>(
random);
2062 if (
availableMods.contains(HullMods.FRONT_SHIELD_CONVERSION)) {
2063 if (omni && shieldArc < 270) {
2064 picker.add(HullMods.FRONT_SHIELD_CONVERSION, 1f);
2069 if (shield && shieldArc <= 300) {
2070 picker.add(HullMods.EXTENDED_SHIELDS, 1f);
2074 if (
availableMods.contains(HullMods.CONVERTED_HANGAR) && hull.getHullSize() != HullSize.FRIGATE) {
2077 if (faction ==
null) {
2078 if (
random.nextFloat() < 0.2f) {
2079 picker.add(HullMods.CONVERTED_HANGAR, 1f);
2082 if (
random.nextFloat() < (
float) faction.getDoctrine().getCarriers() / 5f) {
2083 picker.add(HullMods.CONVERTED_HANGAR, 1f);
2090 if (!shield && !phase) {
2091 picker.add(HullMods.MAKESHIFT_GENERATOR, 1f);
2097 picker.add(HullMods.EXPANDED_DECK_CREW, 1f);
2102 picker.add(HullMods.ECM, 1f);
2105 if (
availableMods.contains(HullMods.INTEGRATED_TARGETING_UNIT)) {
2106 picker.add(HullMods.INTEGRATED_TARGETING_UNIT, 100f);
2107 }
else if (
availableMods.contains(HullMods.DEDICATED_TARGETING_CORE)) {
2108 if (hull.getHullSize().ordinal() >= HullSize.CRUISER.ordinal()) {
2109 picker.add(HullMods.DEDICATED_TARGETING_CORE, 100f);
2115 picker.add(HullMods.HARDENED_SHIELDS, 1f);
2119 if (
availableMods.contains(HullMods.STABILIZEDSHIELDEMITTER)) {
2121 picker.add(HullMods.STABILIZEDSHIELDEMITTER, 1f);
2126 picker.add(HullMods.HEAVYARMOR, 1f);
2131 picker.add(HullMods.INSULATEDENGINE, 1f);
2137 picker.add(HullMods.FLUXBREAKERS, 1f);
2139 picker.add(HullMods.FLUXBREAKERS, 10f);
2144 picker.add(HullMods.UNSTABLE_INJECTOR, 1f);
2154 float addedTotal = 0;
2155 float addedMax = current.getHullSpec().getOrdnancePoints(
stats) * 0.2f;
2156 for (
int i = 0; i < num; i++) {
2157 String modId = picker.pickAndRemove();
2158 if (modId ==
null)
break;
2159 if (current.hasHullMod(modId)) {
2164 if (modId.equals(HullMods.EXTENDED_SHIELDS)) {
2165 picker.remove(HullMods.FRONT_SHIELD_CONVERSION);
2166 }
else if (modId.equals(HullMods.FRONT_SHIELD_CONVERSION) && shieldArc >= 180) {
2167 picker.remove(HullMods.EXTENDED_SHIELDS);
2169 addedTotal =
addHullmods(current, delegate, modId);
2170 if (addedTotal >= addedMax)
break;
2173 return (
int) addedTotal;
2179 if (
random.nextFloat() > 0.5f){
2181 if (
random.nextFloat() > 0.75f) {
2186 if (num <= 0)
return 0;
2188 ShipHullSpecAPI hull = current.getHullSpec();
2189 boolean omni = hull.getShieldType() == ShieldType.OMNI;
2190 boolean front = hull.getShieldType() == ShieldType.FRONT;
2197 WeightedRandomPicker<String> picker =
new WeightedRandomPicker<String>(
random);
2200 picker.add(HullMods.ARMOREDWEAPONS, 1f);
2211 picker.add(HullMods.ECCM, 1f);
2215 float addedTotal = 0;
2216 float addedMax = current.getHullSpec().getOrdnancePoints(
stats) * 0.2f;
2217 for (
int i = 0; i < num; i++) {
2218 String modId = picker.pickAndRemove();
2219 if (modId ==
null)
break;
2220 if (current.hasHullMod(modId)) {
2225 addedTotal =
addHullmods(current, delegate, modId);
2226 if (addedTotal >= addedMax)
break;
2229 return (
int) addedTotal;
static SettingsAPI getSettings()
int getMaxVents(HullSize size)
static String BUY_FROM_BLACK_MARKET
CoreAutofitPlugin(PersonAPI fleetCommander)
Map< String, AvailableWeapon > fittedWeapons
Map< FighterWingSpecAPI, List< String > > altFighterCats
void clearFighterSlot(int index, AutofitPluginDelegate delegate, ShipVariantAPI variant)
List< AvailableWeapon > getWeapons(AutofitPluginDelegate delegate)
void addVentsAndCaps(ShipVariantAPI current, ShipVariantAPI target, float fraction)
String getQuickActionTooltip()
Set< Integer > baysToSkip
AvailableWeapon getBestMatch(WeaponSpecAPI desired, boolean useBetter, String catId, Set< String > alreadyUsed, List< AvailableWeapon > possible, WeaponSlotAPI slot, AutofitPluginDelegate delegate)
int addRandomizedHullmodsPre(ShipVariantAPI current, AutofitPluginDelegate delegate)
void addModsWithSpareOPIfAny(ShipVariantAPI current, ShipVariantAPI target, boolean sModMode, AutofitPluginDelegate delegate)
AvailableWeapon getBestMatch(WeaponSpecAPI desired, boolean useBetter, String catId, Set< String > alreadyUsed, List< AvailableWeapon > possible, AutofitPluginDelegate delegate)
static transient Map< String, Integer > tagLevels
void fitWeapons(ShipVariantAPI current, ShipVariantAPI target, boolean upgradeMode, AutofitPluginDelegate delegate)
void addCoil(ShipVariantAPI current, AutofitPluginDelegate delegate)
AvailableFighter getBestMatch(FighterWingSpecAPI desired, boolean useBetter, String catId, Set< String > alreadyUsed, List< AvailableFighter > possible, AutofitPluginDelegate delegate)
void doQuickAction(ShipVariantAPI current, AutofitPluginDelegate delegate)
int addModIfPossible(String id, AutofitPluginDelegate delegate, ShipVariantAPI current, int opLeft)
void addExtraCaps(ShipVariantAPI current)
boolean isChecked(String id)
int addHullmods(ShipVariantAPI current, AutofitPluginDelegate delegate, String ... mods)
static String USE_FROM_CARGO
static String ALWAYS_BLAST_DOORS
void addCoilRemoveCapsIfNeeded(ShipVariantAPI current, AutofitPluginDelegate delegate)
static int getBaseMax(HullSize size)
float[] computeMemberScore(FleetMemberAPI member)
Map< WeaponSpecAPI, List< String > > altWeaponCats
static String USE_FROM_STORAGE
int addCapacitors(int add, ShipVariantAPI current, int max)
static String INTERCEPTOR
List< WeaponSlotAPI > getWeaponSlotsInPriorityOrder(ShipVariantAPI current, ShipVariantAPI target, boolean upgradeMode)
float getVariantOPFraction(FleetMemberAPI member)
static String BUY_FROM_MARKET
int addVents(int add, ShipVariantAPI current, int max)
void fitFighters(ShipVariantAPI current, ShipVariantAPI target, boolean upgradeMode, AutofitPluginDelegate delegate)
List< AutofitOption > options
void addDistributor(ShipVariantAPI current, AutofitPluginDelegate delegate)
int addRandomizedHullmodsPost(ShipVariantAPI current, AutofitPluginDelegate delegate)
void setRandom(Random random)
void clearWeaponSlot(WeaponSlotAPI slot, AutofitPluginDelegate delegate, ShipVariantAPI variant)
void addDistributorRemoveVentsIfNeeded(ShipVariantAPI current, AutofitPluginDelegate delegate)
static float RANDOMIZE_CHANCE
void doFit(ShipVariantAPI current, ShipVariantAPI target, int maxSMods, AutofitPluginDelegate delegate)
String getCategoryTag(Category cat, Set< String > tags)
Map< String, Category > categories
void stripFighters(ShipVariantAPI current, AutofitPluginDelegate delegate)
List< AvailableFighter > getFighters(AutofitPluginDelegate delegate)
float getSlotPriorityScore(WeaponSlotAPI slot)
MutableCharacterStatsAPI stats
void addExtraVentsAndCaps(ShipVariantAPI current, ShipVariantAPI target)
List< AvailableWeapon > getPossibleWeapons(WeaponSlotAPI slot, WeaponSpecAPI desired, ShipVariantAPI current, float opLeft, List< AvailableWeapon > weapons)
Set< String > availableMods
int convertToSMods(ShipVariantAPI current, int num)
Set< String > slotsToSkip
List< AvailableFighter > getPossibleFighters(ShipVariantAPI current, float opLeft, List< AvailableFighter > fighters)
float getRating(ShipVariantAPI current, ShipVariantAPI target, AutofitPluginDelegate delegate)
Map< String, AvailableFighter > fittedFighters
boolean isQuickActionEnabled(ShipVariantAPI currentVariant)
List< AutofitOption > getOptions()
int getMaxCaps(HullSize size)
int addModIfPossible(HullModSpecAPI mod, AutofitPluginDelegate delegate, ShipVariantAPI current, int opLeft)
void addExtraVents(ShipVariantAPI current)
void autoAssignOfficers(CampaignFleetAPI fleet)
float[] computeOfficerScore(PersonAPI officer)
void stripWeapons(ShipVariantAPI current, AutofitPluginDelegate delegate)
float getSkillTotal(OfficerDataAPI officer, boolean carrier)
String getQuickActionText()
int missilesWithAmmoOnCurrent
static Map< String, Category > reusableCategories
static String ALWAYS_REINFORCED_HULL
void setChecked(String id, boolean checked)
float getLevel(String tag)
int computeNumFighterBays(ShipVariantAPI variant)
FighterWingSpecAPI getFighterWingSpec(String wingId)
List< AvailableFighter > getAvailableFighters()
boolean isPlayerCampaignRefit()
boolean canAddRemoveHullmodInPlayerCampaignRefit(String modId)
List< String > getAvailableHullmods()
void clearWeaponSlot(WeaponSlotAPI slot, ShipVariantAPI variant)
List< AvailableWeapon > getAvailableWeapons()
void fitWeaponInSlot(WeaponSlotAPI slot, AvailableWeapon weapon, ShipVariantAPI variant)
void fitFighterInSlot(int index, AvailableFighter fighter, ShipVariantAPI variant)
void syncUIWithVariant(ShipVariantAPI variant)
boolean isAllowSlightRandomization()
void clearFighterSlot(int index, ShipVariantAPI variant)
boolean isPriority(WeaponSpecAPI weapon)
SubmarketAPI getSubmarket()
FighterWingSpecAPI getWingSpec()
SubmarketAPI getSubmarket()