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.HullModItemManager;
34import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflater;
35import com.fs.starfarer.api.impl.campaign.ids.Factions;
36import com.fs.starfarer.api.impl.campaign.ids.HullMods;
37import com.fs.starfarer.api.impl.campaign.ids.Skills;
38import com.fs.starfarer.api.impl.campaign.ids.Tags;
39import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
40import com.fs.starfarer.api.loading.FighterWingSpecAPI;
41import com.fs.starfarer.api.loading.HullModSpecAPI;
42import com.fs.starfarer.api.loading.VariantSource;
43import com.fs.starfarer.api.loading.WeaponGroupSpec;
44import com.fs.starfarer.api.loading.WeaponSlotAPI;
45import com.fs.starfarer.api.loading.WeaponSpecAPI;
46import com.fs.starfarer.api.util.Misc;
47import com.fs.starfarer.api.util.WeightedRandomPicker;
60 public static String
UPGRADE =
new String(
"upgrade");
63 public static String
STRIP =
new String(
"strip");
64 public static String
RANDOMIZE =
new String(
"randomize");
68 public static String
LR =
"LR";
69 public static String
SR =
"SR";
72 public static String
HE =
"he";
73 public static String
ENERGY =
"energy";
74 public static String
PD =
"pd";
75 public static String
BEAM =
"beam";
77 public static String
STRIKE =
"strike";
80 public static String
ROCKET =
"rocket";
83 public static String
BOMBER =
"bomber";
90 public static class Category {
92 public Set<String> tags =
new HashSet<String>();
94 public List<String> fallback =
new ArrayList<String>();
96 public Category(String base, Map<String, Category>
categories) {
100 for (
int i = 0; i < 100; i++) {
101 String
id = base + i;
107 public void addFallback(String ...
categories) {
114 protected List<AutofitOption>
options =
new ArrayList<AutofitOption>();
116 protected Map<String, Category>
categories =
new LinkedHashMap<String, Category>();
118 protected Map<WeaponSpecAPI, List<String>>
altWeaponCats =
new LinkedHashMap<WeaponSpecAPI, List<String>>();
119 protected Map<FighterWingSpecAPI, List<String>>
altFighterCats =
new LinkedHashMap<FighterWingSpecAPI, List<String>>();
140 for (AutofitOption option :
options) {
141 if (option.id.equals(
id))
return option.checked;
147 for (AutofitOption option :
options) {
148 if (option.id.equals(
id)) {
149 option.checked = checked;
159 "Use weapons and fighter LPCs from your fleet's cargo holds."));
161 "Use weapons and fighter LPCs from your local storage facilities."));
163 "Buy weapons and fighter LPCs from market, if docked at one.\n\n" +
164 "Ordnance from your cargo will be preferred if that option is checked and if the alternatives are of equal quality."));
166 "Buy weapons and fighter LPCs from the black market.\n\n" +
167 "Non-black-market options will be preferred if the alternatives are of equal quality."));
168 options.add(
new AutofitOption(
UPGRADE,
"Upgrade weapons using extra OP",
false,
169 "Use weapons better than the ones specified in the goal variant, if there are ordnance points left to mount them.\n\n" +
170 "Will add flux vents and capacitors up to the number specified in the goal variant first, " +
171 "then upgrade weapons, and then add more vents and some common hullmods.\n\n" +
172 "Leaving some unspent ordnance points in a goal variant can help take advantage of this option."));
173 options.add(
new AutofitOption(
STRIP,
"Strip before autofitting",
true,
174 "Remove everything possible prior to autofitting; generally results in a better fit.\n\n" +
175 "However, refitting outside of port reduces a ship's combat readiness, and this option tends to lead to more changes and more readiness lost."));
177 "Prioritizes installing the \"Reinforced Bulkheads\" hullmod, which increases hull integrity and " +
178 "makes a ship virtually certain to be recoverable if lost in battle.\n\n" +
179 "\"Reinforced Bulkheads\" may still be added if this option isn't checked, provided there are enough ordnance points."));
181 "Prioritizes installing the \"Blast Doors\" hullmod, which increases hull integrity and " +
182 "greatly reduces crew losses suffered due to hull damage.\n\n" +
183 "\"Blast Doors\" may still be added if this option isn't checked, provided there are enough ordnance points."));
184 options.add(
new AutofitOption(
RANDOMIZE,
"Randomize weapons and hullmods",
false,
185 "Makes the loadout only loosely based on the goal variant."));
230 for (
int i = 0; i < numBays; i++) {
239 protected Map<String, AvailableWeapon>
fittedWeapons =
new HashMap<String, AvailableWeapon>();
240 protected Map<String, AvailableFighter>
fittedFighters =
new HashMap<String, AvailableFighter>();
246 cost += w.getPrice();
249 cost += w.getPrice();
289 boolean forceClone =
false;
290 if (moduleCurrent ==
null) {
296 if (moduleCurrent ==
null) {
298 throw new RuntimeException(
"Module variant for slotId [" + slotId +
"] not found for " +
303 moduleCurrent = moduleCurrent.
clone();
314 if (moduleTarget ==
null)
continue;
317 doFit(moduleCurrent, moduleTarget, 0, delegate);
361 for (
int i = 0; i < 20; i++) {
363 if (wingId !=
null && !wingId.isEmpty()) {
375 if (reinforcedHull) {
382 List<String> targetMods =
new ArrayList<String>();
383 for (String
id : target.
getSMods()) {
391 if (!targetMods.isEmpty()) {
392 addHullmods(current, delegate, targetMods.toArray(
new String[0]));
395 int addedRandomHullmodPts = 0;
411 if (
randomize && addedRandomHullmodPts <= addedMax) {
415 float ventsCapsFraction = 1f;
418 ventsCapsFraction = 0.5f;
463 int remaining = maxSMods - added;
465 List<String> mods =
new ArrayList<String>();
476 Iterator<String> iter = mods.iterator();
477 while (iter.hasNext()) {
478 String modId = iter.next();
486 for (
int i = 0; i < remaining && !mods.isEmpty(); i++) {
489 String modId = mods.get(Math.min(i, mods.size() - 1));
508 int opLeft = opMax - opCost;
526 for (String slotId : group.getSlots()) {
552 if (num <= 0)
return 0;
554 List<HullModSpecAPI> mods =
new ArrayList<HullModSpecAPI>();
564 Collections.sort(mods,
new Comparator<HullModSpecAPI>() {
571 for (
int i = 0; i < num && i < mods.size(); i++) {
572 String
id = mods.get(i).getId();
582 int opLeft = opMax - opCost;
584 if (opLeft <= 0)
return;
587 float ventsFraction = 1f;
593 if (ventsFraction >= 0.5f) {
601 if (ventsFraction >= 0.5f) {
614 int opLeft = opMax - opCost;
616 if (opLeft <= 0)
return;
623 if (cost < opLeft + vents * 0.3f) {
624 int remove = cost - opLeft;
626 opLeft -=
addVents(-
remove, current, 1000);
635 int opLeft = opMax - opCost;
637 if (opLeft <= 0)
return;
644 if (cost < opLeft + caps * 0.3f) {
645 int remove = cost - opLeft;
656 int opLeft = opMax - opCost;
658 if (opLeft <= 0)
return;
665 if (cost <= opLeft + caps * 0.3f) {
666 int remove = cost - opLeft;
677 int opLeft = opMax - opCost;
679 if (opLeft <= 0)
return;
686 if (cost <= opLeft + vents * 0.3f) {
687 int remove = cost - opLeft;
689 opLeft -=
addVents(-
remove, current, 1000);
703 List<AvailableWeapon> weapons =
new ArrayList<AvailableWeapon>(delegate.
getAvailableWeapons());
705 Iterator<AvailableWeapon> iter = weapons.iterator();
706 while (iter.hasNext()) {
725 List<AvailableFighter> fighters =
new ArrayList<AvailableFighter>(delegate.
getAvailableFighters());
726 Iterator<AvailableFighter> iter = fighters.iterator();
727 while (iter.hasNext()) {
745 int opLeft = opMax - opCost;
748 for (String mod : mods) {
755 current.
getHullSize().ordinal() >= HullSize.CRUISER.ordinal()) {
817 if (mod ==
null)
return 0;
824 if (cost > opLeft)
return 0;
854 if (orig !=
null && ship !=
null) {
860 if (ship !=
null && mod.
getId() !=
null && mod.
getEffect() !=
null) {
872 if (fraction < 0)
return;
876 int opLeft = opMax - opCost;
882 if (add > opLeft) add = opLeft;
883 opLeft -=
addVents(add, current, maxVents);
886 if (add > opLeft) add = opLeft;
893 int opLeft = opMax - opCost;
897 opLeft -=
addVents((
int) opLeft, current, maxVents);
904 int opLeft = opMax - opCost;
915 int opLeft = opMax - opCost;
922 float ventsFraction = 1f;
927 int add = (int) (opLeft * ventsFraction);
928 opLeft -=
addVents(add, current, maxVents);
933 opLeft -=
addVents(add, current, maxVents);
936 if (target !=
null) {
940 if (targetVents > targetCaps || targetVents >= maxVents) {
943 float currTotal = currVents + currCaps;
945 int currVentsDesired = (int) (currVents + currCaps * 0.5f);
946 if (currVentsDesired > maxVents) currVentsDesired = maxVents;
947 int currCapsDesired = (int) (currTotal - currVentsDesired);
948 if (currCapsDesired > maxCapacitors) currCapsDesired = maxCapacitors;
984 return maxCapacitors;
990 case CAPITAL_SHIP: max = 50;
break;
991 case CRUISER: max = 30;
break;
992 case DESTROYER: max = 20;
break;
993 case FRIGATE: max = 10;
break;
1001 if (target > max) target = max;
1002 if (target < 0) target = 0;
1010 if (target > max) target = max;
1011 if (target < 0) target = 0;
1034 Set<String> alreadyUsed =
new HashSet<String>();
1044 float opLeft = opMax - opCost;
1046 float levelToBeat = -1;
1053 for (String tag : curr.
getTags()) {
1054 levelToBeat = Math.max(levelToBeat,
getLevel(tag));
1064 if (desired ==
null)
continue;
1066 List<AvailableWeapon> weapons =
getWeapons(delegate);
1067 List<AvailableWeapon> possible =
getPossibleWeapons(slot, desired, current, opLeft, weapons);
1068 if (possible.isEmpty())
continue;
1081 if (alternate ==
null) {
1082 alternate =
new ArrayList<String>();
1084 Category category = this.categories.get(cat);
1085 if (category ==
null) {
1089 if (!category.fallback.isEmpty()) {
1090 int index =
random.nextInt(category.fallback.size()/2) + 1;
1093 alternate.add(category.fallback.get(index));
1099 if (!alternate.isEmpty()) {
1109 pick =
getBestMatch(desired, upgradeMode, catId, alreadyUsed, possible, slot, delegate);
1113 if (upgradeMode)
break;
1116 if (pick ==
null && !upgradeMode) {
1118 Category cat = this.categories.get(catId);
1119 if (cat ==
null)
continue;
1121 for (String fallbackCatId : cat.fallback) {
1122 pick =
getBestMatch(desired,
true, fallbackCatId, alreadyUsed, possible, delegate);
1132 float pickLevel = -1;
1134 Category cat = this.categories.get(
categories.get(0));
1143 if (pickLevel <= levelToBeat)
continue;
1146 alreadyUsed.add(pick.
getId());
1167 Set<String> alreadyUsed =
new HashSet<String>();
1169 for (
int i = 0; i < numBays; i++) {
1174 float opLeft = opMax - opCost;
1176 float levelToBeat = -1;
1183 for (String tag : curr.
getTags()) {
1184 levelToBeat = Math.max(levelToBeat,
getLevel(tag));
1196 List<AvailableFighter> fighters =
getFighters(delegate);
1198 if (possible.isEmpty())
continue;
1200 String desiredWingId = target.
getWingId(i);
1201 if (desiredWingId ==
null || desiredWingId.isEmpty()) {
1210 if (desired ==
null)
continue;
1217 if (alternate ==
null) {
1218 alternate =
new ArrayList<String>();
1220 Category category = this.categories.get(cat);
1221 if (category ==
null) {
1225 if (!category.fallback.isEmpty()) {
1226 int index =
random.nextInt(category.fallback.size() - 1) + 1;
1228 alternate.add(category.fallback.get(index));
1234 if (!alternate.isEmpty()) {
1244 pick =
getBestMatch(desired, upgradeMode, catId, alreadyUsed, possible, delegate);
1248 if (upgradeMode)
break;
1251 if (pick ==
null && !upgradeMode) {
1253 Category cat = this.categories.get(catId);
1254 if (cat ==
null)
continue;
1256 for (String fallbackCatId : cat.fallback) {
1257 pick =
getBestMatch(desired,
true, fallbackCatId, alreadyUsed, possible, delegate);
1267 float pickLevel = -1;
1269 Category cat = this.categories.get(
categories.get(0));
1278 if (pickLevel <= levelToBeat)
continue;
1281 alreadyUsed.add(pick.
getId());
1295 String catId, Set<String> alreadyUsed, List<AvailableWeapon> possible,
1297 return getBestMatch(desired, useBetter, catId, alreadyUsed, possible,
null, delegate);
1301 String catId, Set<String> alreadyUsed, List<AvailableWeapon> possible,
1305 float bestScore = -1f;
1306 boolean bestIsPriority =
false;
1310 if (cat ==
null)
return null;
1313 float desiredLevel =
getLevel(desiredTag);
1315 if (desiredTag ==
null) {
1320 desiredLevel = 10000f;
1323 boolean longRange = desired.
hasTag(
LR);
1324 boolean shortRange = desired.
hasTag(
SR);
1325 boolean midRange = !longRange && !shortRange;
1326 boolean desiredPD = desired.
getAIHints().contains(AIHints.PD);
1344 if (catTag ==
null)
continue;
1350 boolean currLongRange = spec.
hasTag(
LR);
1351 boolean currShortRange = spec.
hasTag(
SR);
1352 boolean currMidRange = !currLongRange && !currShortRange;
1355 if (!desiredPD && currShortRange && (midRange || longRange))
continue;
1359 boolean currIsPriority = isPrimaryCategory && delegate.
isPriority(spec);
1360 int currSize = spec.
getSize().ordinal();
1361 boolean betterDueToPriority = currSize >= bestSize && currIsPriority && !bestIsPriority;
1362 boolean worseDueToPriority = currSize <= bestSize && !currIsPriority && bestIsPriority;
1364 if (worseDueToPriority)
continue;
1368 if (!
randomize && !useBetter && !betterDueToPriority && level > desiredLevel)
continue;
1379 boolean symmetric =
random.nextFloat() < 0.75f;
1380 if (slot !=
null && symmetric) {
1381 long seed = (Math.abs((
int)(slot.
getLocation().x/2f)) * 723489413945245311L) ^ 1181783497276652981L;
1383 level += r.nextInt(rMag);
1385 level +=
random.nextInt(rMag);
1390 float score = level;
1394 if ((score > bestScore || betterDueToPriority)) {
1399 bestSize = currSize;
1400 bestIsPriority = currIsPriority;
1401 }
else if (score == bestScore) {
1412 List<AvailableWeapon> allMatches =
new ArrayList<AvailableWeapon>();
1413 List<AvailableWeapon> freeMatches =
new ArrayList<AvailableWeapon>();
1417 if (w.getPrice() <= 0) {
1422 if (!freeMatches.isEmpty())
return freeMatches.get(0);
1423 if (!allMatches.isEmpty())
return allMatches.get(0);
1426 boolean hasFree =
false;
1427 boolean hasNonBlackMarket =
false;
1429 if (w.getPrice() <= 0) {
1432 if (w.getSubmarket() ==
null || !w.getSubmarket().getPlugin().isBlackMarket()) {
1433 hasNonBlackMarket =
true;
1438 if (w.getPrice() > 0) {
1442 }
else if (hasNonBlackMarket) {
1444 if (w.getSubmarket() !=
null && w.getSubmarket().getPlugin().isBlackMarket()) {
1451 if (!alreadyUsed.isEmpty()) {
1453 if (alreadyUsed.contains(w.getId()))
return w;
1457 if (best.
isEmpty())
return null;
1465 String catId, Set<String> alreadyUsed, List<AvailableFighter> possible,
1467 float bestScore = -1f;
1468 boolean bestIsPriority =
false;
1471 if (cat ==
null)
return null;
1474 float desiredLevel =
getLevel(desiredTag);
1481 if (catTag ==
null)
continue;
1484 boolean currIsPriority = isPrimaryCategory && delegate.
isPriority(spec);
1485 boolean betterDueToPriority = currIsPriority && !bestIsPriority;
1486 boolean worseDueToPriority = !currIsPriority && bestIsPriority;
1488 if (worseDueToPriority)
continue;
1491 if (!
randomize && !useBetter && !betterDueToPriority && level > desiredLevel)
continue;
1503 level +=
random.nextInt(rMag);
1506 float score = level;
1510 if (score > bestScore || betterDueToPriority) {
1515 bestIsPriority = currIsPriority;
1516 }
else if (score == bestScore) {
1523 List<AvailableFighter> allMatches =
new ArrayList<AvailableFighter>();
1524 List<AvailableFighter> freeMatches =
new ArrayList<AvailableFighter>();
1526 if (desired.
getId().equals(f.getId())) {
1528 if (f.getPrice() <= 0) {
1533 if (!freeMatches.isEmpty())
return freeMatches.get(0);
1534 if (!allMatches.isEmpty())
return allMatches.get(0);
1538 boolean hasFree =
false;
1539 boolean hasNonBlackMarket =
false;
1541 if (f.getPrice() <= 0) {
1544 if (f.getSubmarket() ==
null || !f.getSubmarket().getPlugin().isBlackMarket()) {
1545 hasNonBlackMarket =
true;
1550 if (f.getPrice() > 0) {
1554 }
else if (hasNonBlackMarket) {
1556 if (f.getSubmarket() !=
null && f.getSubmarket().getPlugin().isBlackMarket()) {
1564 if (!alreadyUsed.isEmpty()) {
1566 if (alreadyUsed.contains(f.getId()))
return f;
1570 if (best.
isEmpty())
return null;
1577 String catTag =
null;
1578 for (String tag : tags) {
1579 if (cat.tags.contains(tag)) {
1588 protected static transient Map<String, Integer>
tagLevels =
new HashMap<String, Integer>();
1593 if (result !=
null)
return result;
1600 result = (int) Float.parseFloat(tag.replaceAll(cat.base,
""));
1603 }
catch (Throwable t) {
1632 List<WeaponSlotAPI> result =
new ArrayList<WeaponSlotAPI>();
1635 if (slot.isBuiltIn() || slot.isDecorative())
continue;
1636 if (target.
getWeaponId(slot.getId()) ==
null)
continue;
1637 if (!upgradeMode && current.
getWeaponId(slot.getId()) !=
null)
continue;
1641 Collections.sort(result,
new Comparator<WeaponSlotAPI>() {
1645 return (
int) Math.signum(s2 - s1);
1656 case LARGE: score = 10000;
break;
1657 case MEDIUM: score = 5000;
break;
1658 case SMALL: score = 2500;
break;
1664 score += 180f - angleDiff;
1673 List<AvailableWeapon> result =
new ArrayList<AvailableWeapon>();
1676 if (w.getQuantity() <= 0)
continue;
1681 if (cost > opLeft)
continue;
1684 if (spec != desired &&
1685 (spec.
getType() == WeaponType.MISSILE || spec.
getAIHints().contains(AIHints.STRIKE))) {
1686 boolean guided = spec.
getAIHints().contains(AIHints.DO_NOT_AIM);
1688 boolean guidedPoor = spec.
getAIHints().contains(AIHints.GUIDED_POOR);
1690 if (angleDiff > 45 || (!guidedPoor && angleDiff > 20))
continue;
1699 int num = Math.max(1, result.size() / 3 * 2);
1701 List<AvailableWeapon> filtered =
new ArrayList<AvailableWeapon>();
1702 for (Integer pick : picks) {
1703 filtered.add(result.get(pick));
1710 List<AvailableWeapon>
remove =
new ArrayList<AvailableWeapon>();
1712 if (w.getId().equals(
"heatseeker")) {
1716 result.removeAll(
remove);
1723 List<AvailableFighter> result =
new ArrayList<AvailableFighter>();
1726 if (f.getQuantity() <= 0)
continue;
1730 if (cost > opLeft)
continue;
1737 int num = Math.max(1, result.size() / 3 * 2);
1739 List<AvailableFighter> filtered =
new ArrayList<AvailableFighter>();
1740 for (Integer pick : picks) {
1741 filtered.add(result.get(pick));
1806 return "Spend free OP";
1810 return "Spend any unused ordnance points on flux vents, capacitors, and essential hullmods.\n\n" +
1812 "Will not make any changes to weapon loadout, will not affect ship modules (if any), and will not spend any credits.";
1816 int unusedOpTotal = 0;
1819 if (moduleCurrent ==
null)
continue;
1823 return unusedOpTotal > 0;
1829 public static class AutoAssignScore {
1830 public float [] score;
1838 List<FleetMemberAPI> members =
new ArrayList<FleetMemberAPI>();
1840 if (member.isMothballed()) {
1843 if (!member.getCaptain().isDefault()) {
1847 members.add(member);
1850 List<OfficerDataAPI> officers =
new ArrayList<OfficerDataAPI>();
1858 if (count > max && !merc)
continue;
1860 boolean found =
false;
1862 if (member.getCaptain() == officer.getPerson()) {
1868 officers.add(officer);
1873 List<AutoAssignScore> shipScores =
new ArrayList<AutoAssignScore>();
1874 List<AutoAssignScore> officerScores =
new ArrayList<AutoAssignScore>();
1876 float maxMemberTotal = 1f;
1877 float maxOfficerTotal = 1f;
1880 AutoAssignScore score =
new AutoAssignScore();
1881 shipScores.add(score);
1882 score.member = member;
1885 maxMemberTotal = Math.max(maxMemberTotal, score.score[4]);
1889 AutoAssignScore score =
new AutoAssignScore();
1890 officerScores.add(score);
1891 score.officer = officer.getPerson();
1893 maxOfficerTotal = Math.max(maxOfficerTotal, score.score[4]);
1896 for (AutoAssignScore score : officerScores) {
1899 score.score[4] = maxMemberTotal + (maxOfficerTotal - score.score[4]);
1902 while (!shipScores.isEmpty() && !officerScores.isEmpty()) {
1903 float minDist = Float.MAX_VALUE;
1904 AutoAssignScore bestShip =
null;
1905 AutoAssignScore bestOfficer =
null;
1906 for (AutoAssignScore ship : shipScores) {
1910 for (AutoAssignScore officer : officerScores) {
1911 float dist = Math.abs(ship.score[0] - officer.score[0]) +
1912 Math.abs(ship.score[1] - officer.score[1]) +
1913 Math.abs(ship.score[2] - officer.score[2]) +
1914 Math.abs(ship.score[3] - officer.score[3]) +
1915 Math.abs(ship.score[4] - officer.score[4]);
1917 if (dist < minDist) {
1920 bestOfficer = officer;
1924 if (bestShip ==
null) {
1928 shipScores.remove(bestShip);
1929 officerScores.remove(bestOfficer);
1930 bestShip.member.setCaptain(bestOfficer.officer);
1936 float ballistic = 0f;
1942 if (!sl.getSkill().isCombatOfficerSkill())
continue;
1943 float w = sl.getLevel();
1944 if (w == 2) w = 1.33f;
1961 if (total < 1f) total = 1f;
1967 float [] result =
new float [5];
1969 result[1] = ballistic;
1970 result[2] = missile;
1971 result[3] = defense;
1978 float ballistic = 0f;
1991 case LARGE: w = 4f;
break;
1992 case MEDIUM: w = 2f;
break;
1993 case SMALL: w = 1f;
break;
1996 WeaponType type = weapon.
getType();
1997 if (type == WeaponType.BALLISTIC) {
2000 }
else if (type == WeaponType.ENERGY) {
2003 }
else if (type == WeaponType.MISSILE) {
2010 if (total < 1f) total = 1f;
2019 float [] result =
new float [5];
2021 result[1] = ballistic;
2022 result[2] = missile;
2050 float level = skill.getLevel();
2051 if (level <= 0)
continue;
2064 if (
random.nextFloat() > 0.5f){
2066 if (
random.nextFloat() > 0.75f) {
2071 if (num <= 0)
return 0;
2076 boolean shield = omni || front;
2085 if (omni && shieldArc < 270) {
2091 if (shield && shieldArc <= 300) {
2099 if (faction ==
null) {
2100 if (
random.nextFloat() < 0.2f) {
2112 if (!shield && !phase) {
2130 if (hull.
getHullSize().ordinal() >= HullSize.CRUISER.ordinal()) {
2176 float addedTotal = 0;
2178 for (
int i = 0; i < num; i++) {
2180 if (modId ==
null)
break;
2191 addedTotal =
addHullmods(current, delegate, modId);
2192 if (addedTotal >= addedMax)
break;
2195 return (
int) addedTotal;
2201 if (
random.nextFloat() > 0.5f){
2203 if (
random.nextFloat() > 0.75f) {
2208 if (num <= 0)
return 0;
2237 float addedTotal = 0;
2239 for (
int i = 0; i < num; i++) {
2241 if (modId ==
null)
break;
2247 addedTotal =
addHullmods(current, delegate, modId);
2248 if (addedTotal >= addedMax)
break;
2251 return (
int) addedTotal;
2278 int remaining = numSmods - added;
2279 if (remaining > 0) {
2280 List<String> mods =
new ArrayList<String>();
2291 Iterator<String> iter = mods.iterator();
2292 while (iter.hasNext()) {
2293 String modId = iter.next();
2301 for (
int i = 0; i < remaining && !mods.isEmpty(); i++) {
2304 String modId = mods.get(Math.min(i, mods.size() - 1));
static SettingsAPI getSettings()
float computeEffective(float baseValue)
static HullModSpecAPI getMod(String id)
static HullModItemManager getInstance()
boolean isRequiredItemAvailable(String modId, FleetMemberAPI member, ShipVariantAPI currentVariant, MarketAPI dockedAt)
static Set< Integer > makePicks(int num, int max, Random random)
static final String DERELICT
static final String TAG_NON_PHASE
static final String FLUX_COIL
static final String STABILIZEDSHIELDEMITTER
static final String MAKESHIFT_GENERATOR
static final String REINFORCEDHULL
static final String MISSLERACKS
static final String TAG_PHASE
static final String HARDENED_SHIELDS
static final String ARMOREDWEAPONS
static final String EXTENDED_SHIELDS
static final String FRAGILE_SUBSYSTEMS
static final String INSULATEDENGINE
static final String HEAVYARMOR
static final String DISTRIBUTED_FIRE_CONTROL
static final String UNSTABLE_INJECTOR
static final String BLAST_DOORS
static final String FLUXBREAKERS
static final String DEDICATED_TARGETING_CORE
static final String EXPANDED_DECK_CREW
static final String HARDENED_SUBSYSTEMS
static final String FRONT_SHIELD_CONVERSION
static final String ADVANCED_TARGETING_CORE
static final String FLUX_DISTRIBUTOR
static final String INTEGRATED_TARGETING_UNIT
static final String CONVERTED_HANGAR
static final String SAFETYOVERRIDES
static final String TAG_CARRIER
static final String TAG_BALLISTIC_WEAPONS
static final String TAG_MISSILE_WEAPONS
static final String TAG_ENERGY_WEAPONS
static final String TAG_ACTIVE_DEFENSES
static boolean isTutorialInProgress()
void setAutofireOnByDefault(boolean autofireOnByDefault)
List< String > getSlots()
void addSlot(String slotId)
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
void addSMods(FleetMemberAPI member, int numSmods, AutofitPluginDelegate delegate)
static Map< String, Category > reusableCategories
static String ALWAYS_REINFORCED_HULL
void setChecked(String id, boolean checked)
float getLevel(String tag)
static float getDistanceFromArc(float direction, float arc, float angle)
static boolean isMercenary(PersonAPI person)
static boolean isAutomated(MutableShipStatsAPI stats)
static HullModSpecAPI getMod(String id)
static float getAngleDiff(float from, float to)
static int getOPCost(HullModSpecAPI mod, HullSize size)
static boolean isInArc(float direction, float arc, Vector2f from, Vector2f to)
int computeNumFighterBays(ShipVariantAPI variant)
FighterWingSpecAPI getFighterWingSpec(String wingId)
FleetDataAPI getFleetData()
FactionDoctrineAPI getDoctrine()
List< OfficerDataAPI > getOfficersCopy()
List< FleetMemberAPI > getMembersListCopy()
SubmarketPlugin getPlugin()
List< SkillLevelAPI > getSkillsCopy()
StatBonus getMaxCapacitorsBonus()
StatBonus getMaxVentsBonus()
MutableStat getOfficerNumber()
MutableCharacterStatsAPI getStats()
boolean hasTag(String tag)
boolean isCombatOfficerSkill()
boolean isApplicableToShip(ShipAPI ship)
void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id)
void applyEffectsAfterShipCreation(ShipAPI ship, String id)
MutableShipStatsAPI getMutableStats()
ShipVariantAPI getVariant()
void setVariantForHullmodCheckOnly(ShipVariantAPI variant)
boolean hasTag(String tag)
List< WeaponSlotAPI > getAllWeaponSlotsCopy()
ShieldSpecAPI getShieldSpec()
ShieldType getShieldType()
int getOrdnancePoints(MutableCharacterStatsAPI stats)
List< String > getBuiltInMods()
void setVariantDisplayName(String variantName)
Collection< String > getHullMods()
String getWeaponId(String slotId)
MutableShipStatsAPI getStatsForOpCosts()
void setHullVariantId(String hullVariantId)
int computeOPCost(MutableCharacterStatsAPI stats)
LinkedHashSet< String > getSMods()
boolean hasUnassignedWeapons()
Map< String, String > getStationModules()
ShipAPI.HullSize getHullSize()
FighterWingSpecAPI getWing(int index)
void addMod(String modId)
String getHullVariantId()
ShipVariantAPI getModuleVariant(String slotId)
String getWingId(int index)
Collection< String > getFittedWeaponSlots()
Collection< String > getNonBuiltInHullmods()
boolean hasHullMod(String id)
ShipHullSpecAPI getHullSpec()
void setNumFluxVents(int vents)
void setModuleVariant(String slotId, ShipVariantAPI variant)
LinkedHashSet< String > getSModdedBuiltIns()
void setSource(VariantSource source)
void setNumFluxCapacitors(int capacitors)
void setMayAutoAssignWeapons(boolean mayAutoAssign)
void removeMod(String modId)
int getUnusedOP(MutableCharacterStatsAPI stats)
void addPermaMod(String modId)
WeaponSlotAPI getSlot(String slotId)
void autoGenerateWeaponGroups()
WeaponSpecAPI getWeaponSpec(String slotId)
List< WeaponGroupSpec > getWeaponGroups()
void addWeaponGroup(WeaponGroupSpec group)
Set< String > getPermaMods()
int getNumFluxCapacitors()
ShipVariantAPI getVariant()
ShipHullSpecAPI getHullSpec()
List< String > getAutofitCategoriesInPriorityOrder()
boolean hasTag(String tag)
String getAutofitCategory()
float getOpCost(MutableShipStatsAPI shipStats)
int getCostFor(HullSize size)
boolean hasTag(String tag)
HullModEffect getEffect()
boolean weaponFits(WeaponSpecAPI spec)
WeaponAPI.WeaponSize getSlotSize()
boolean isStationModule()
boolean hasTag(String tag)
String getAutofitCategory()
EnumSet< WeaponAPI.AIHints > getAIHints()
List< String > getAutofitCategoriesInPriorityOrder()
float getOrdnancePointCost(MutableCharacterStatsAPI stats)
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)
FleetMemberAPI getFleetMember()
boolean isAllowSlightRandomization()
void clearFighterSlot(int index, ShipVariantAPI variant)
boolean isPriority(WeaponSpecAPI weapon)
SubmarketAPI getSubmarket()
FighterWingSpecAPI getWingSpec()
SubmarketAPI getSubmarket()