1package com.fs.starfarer.api.impl.combat.threat;
3import java.util.ArrayList;
6import org.lwjgl.util.vector.Vector2f;
8import com.fs.starfarer.api.Global;
9import com.fs.starfarer.api.combat.BoundsAPI.SegmentAPI;
10import com.fs.starfarer.api.combat.CombatEngineAPI;
11import com.fs.starfarer.api.combat.CombatFleetManagerAPI;
12import com.fs.starfarer.api.combat.DeployedFleetMemberAPI;
13import com.fs.starfarer.api.combat.MutableShipStatsAPI;
14import com.fs.starfarer.api.combat.ShipAPI;
15import com.fs.starfarer.api.combat.ShipAPI.HullSize;
16import com.fs.starfarer.api.combat.ShipSystemAPI;
17import com.fs.starfarer.api.combat.ShipSystemAPI.SystemState;
18import com.fs.starfarer.api.combat.ShipVariantAPI;
19import com.fs.starfarer.api.impl.campaign.ids.Tags;
20import com.fs.starfarer.api.impl.combat.BaseShipSystemScript;
21import com.fs.starfarer.api.loading.WeaponSlotAPI;
22import com.fs.starfarer.api.util.CountingMap;
23import com.fs.starfarer.api.util.Misc;
24import com.fs.starfarer.api.util.WeightedRandomPicker;
53 public static enum SwarmConstructableType {
59 public static class SwarmConstructableVariant {
60 public SwarmConstructableType type;
61 public String variantId;
67 public SwarmConstructableVariant(SwarmConstructableType type, String variantId) {
69 this.variantId = variantId;
82 }
else if (v.
getHullSize() == HullSize.CAPITAL_SHIP) {
86 if (type == SwarmConstructableType.HIVE) {
89 if (type == SwarmConstructableType.OVERSEER) {
96 public static List<SwarmConstructableVariant>
CONSTRUCTABLE =
new ArrayList<>();
98 protected static boolean inited =
false;
106 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.COMBAT_UNIT,
"skirmish_unit_Type100"));
107 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.COMBAT_UNIT,
"skirmish_unit_Type101"));
108 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.COMBAT_UNIT,
"assault_unit_Type200"));
109 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.COMBAT_UNIT,
"assault_unit_Type201"));
110 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.COMBAT_UNIT,
"standoff_unit_Type300"));
111 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.COMBAT_UNIT,
"standoff_unit_Type301"));
112 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.COMBAT_UNIT,
"standoff_unit_Type302"));
114 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.OVERSEER,
"overseer_unit_Type250"));
115 CONSTRUCTABLE.add(
new SwarmConstructableVariant(SwarmConstructableType.HIVE,
"hive_unit_Type350"));
132 public static class SwarmConstructionData {
133 public String variantId;
134 public float constructionTime = 10f;
135 public float preConstructionTravelTime = 3f;
144 if (
slots !=
null)
return;
147 if (slot.isSystemSlot()) {
165 if (state == State.IDLE || state == State.COOLDOWN || effectLevel <= 0f) {
208 if (sourceSwarm ==
null)
return;
217 SwarmConstructableVariant pick =
pickVariant(ship);
218 if (pick ==
null)
return;
220 String variantId = pick.variantId;
229 if (variant ==
null)
return;
235 int numFragments = pick.fragments;
236 float radiusMult = 1f;
237 float collisionMult = 2f;
239 float travelTime = 3f;
246 }
else if (variant.
getHullSize() == HullSize.CRUISER) {
251 }
else if (variant.
getHullSize() == HullSize.CAPITAL_SHIP) {
259 s.getP1().scale(collisionMult);
260 s.getP2().scale(collisionMult);
261 s.set(s.getP1().x, s.getP1().y, s.getP2().x, s.getP2().y);
268 swarm.params.maxOffset *= radiusMult;
272 swarm.params.initialMembers = numFragments;
273 swarm.params.baseMembersToMaintain = numFragments;
277 SwarmConstructionData data =
new SwarmConstructionData();
278 data.variantId = variantId;
283 data.preConstructionTravelTime = travelTime;
286 if (pick.size == HullSize.FRIGATE) {
288 data.constructionTime = 2f;
294 swarm.custom1 = data;
298 loc =
new Vector2f(takeoffVel);
304 int add = numFragments - transfer;
320 if (manager ==
null)
return null;
334 int wantOverseers = (int) (combatWeight / 8f);
335 if (wantOverseers < 1) wantOverseers = 1;
337 combatWeight += Math.max(0, fabricators - 1f) * 16f;
338 int wantHives = (int) (combatWeight / 16f);
340 if (wantHives < 1) wantHives = 1;
341 if (wantHives > 2) wantHives = 2;
343 wantOverseers -= overseers;
350 float large = cruisers + capitals;
358 if (curr.type == SwarmConstructableType.COMBAT_UNIT) {
359 numCombatVariants.
add(curr.size);
370 if (curr.dp > dpLeft)
continue;
371 if (curr.cr > cr)
continue;
372 if (curr.fragments > fragments)
continue;
374 if (curr.type == SwarmConstructableType.HIVE) {
375 hivePicker.
add(curr, 1f / curr.dp);
376 }
else if (curr.type == SwarmConstructableType.OVERSEER) {
377 overseerPicker.
add(curr, 1f / curr.dp);
379 float wMult = 1f / Math.max(1f, numCombatVariants.
getCount(curr.size));
380 if (curr.size == HullSize.FRIGATE) {
381 smallPicker.
add(curr, 1f / curr.dp * wMult);
382 }
else if (curr.size == HullSize.DESTROYER) {
383 mediumPicker.
add(curr, 1f / curr.dp * wMult);
385 largePicker.
add(curr, 1f / curr.dp * wMult);
390 if (frigates <= 1 && !smallPicker.
isEmpty()) {
391 return smallPicker.
pick();
394 if (wantOverseers > 0 || wantHives > 0) {
395 if (wantOverseers >= wantHives && !overseerPicker.
isEmpty()) {
396 return overseerPicker.
pick();
397 }
else if (!hivePicker.
isEmpty()) {
398 return hivePicker.
pick();
403 return largePicker.
pick();
407 return mediumPicker.
pick();
410 return smallPicker.
pick();
422 if (swarm.
custom1 instanceof SwarmConstructionData) {
423 SwarmConstructionData data = (SwarmConstructionData) swarm.
custom1;
437 if (ship ==
null)
continue;
451 if (ship ==
null)
continue;
472 if (ship ==
null)
continue;
492 if (ship ==
null)
continue;
496 if (swarm !=
null && swarm.
custom1 instanceof SwarmConstructionData) {
497 SwarmConstructionData data = (SwarmConstructionData) swarm.
custom1;
501 case CAPITAL_SHIP: weight += 8;
break;
502 case CRUISER: weight += 4;
break;
503 case DESTROYER: weight += 2;
break;
504 case FRIGATE: weight += 1;
break;
505 case FIGHTER: weight += 1;
break;
524 if (ship ==
null)
continue;
541 float numMult = 1f * dp / 5f;
542 if (size == HullSize.DESTROYER) {
543 numMult = 2f * dp / 20f;
544 }
else if (size == HullSize.CRUISER) {
545 numMult = 3f * dp / 20f;
546 }
else if (size == HullSize.CAPITAL_SHIP) {
547 numMult = 5f * dp / 40f;
557 if (system.
getState() != SystemState.IDLE)
return null;
560 return "LOW FRAGMENTS";
577 if (manager ==
null)
return true;
583 if (ship2 ==
null)
continue;
592 if (swarm.
custom1 instanceof SwarmConstructionData) {
593 SwarmConstructionData data = (SwarmConstructionData) swarm.
custom1;
605 return active >= required;
static SettingsAPI getSettings()
static CombatEngineAPI getCombatEngine()
void modifyMult(String source, float value)
static int getNumFabricatorsDeployed(CombatFleetManagerAPI manager)
void findSlots(ShipAPI ship)
static float CONSTRUCTION_TIME_OVERSEER_EXTRA
String getInfoText(ShipSystemAPI system, ShipAPI ship)
static int BASE_FRAGMENTS
static int getCombatDeployed(CombatFleetManagerAPI manager, HullSize size)
static float getCombatWeightDeployed(CombatFleetManagerAPI manager)
static List< SwarmConstructableVariant > CONSTRUCTABLE
static boolean constructionSwarmWillBuild(ShipAPI ship, String tag, HullSize size)
void launchSwarm(ShipAPI ship)
boolean enoughDP(ShipSystemAPI system, ShipAPI ship)
static int getNumOverseersDeployed(CombatFleetManagerAPI manager)
static float CONSTRUCTION_SWARM_SPEED_MULT
boolean enoughCR(ShipSystemAPI system, ShipAPI ship)
WeightedRandomPicker< WeaponSlotAPI > slots
SwarmConstructableVariant pickVariant(ShipAPI ship)
static float CONSTRUCTION_TIME_DP_MULT
static int getNumHivesDeployed(CombatFleetManagerAPI manager)
static int FAST_CONSTRUCTION_FRIGATES_MAX
static float NUM_DESTROYERS_AS_FRACTION_OF_FRIGATES
boolean isUsable(ShipSystemAPI system, ShipAPI ship)
static int getFragmentCost(float dp, HullSize size)
void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel)
static float BASE_CONSTRUCTION_TIME
boolean enoughFragments(ShipSystemAPI system, ShipAPI ship)
static float NUM_LARGE_AS_FRACTION_OF_DESTROYERS
static String CONSTRUCTION_SWARM_FLOCKING_CLASS
static RoilingSwarmEffect createSwarmFor(ShipAPI ship)
int getNumActiveMembers()
RoilingSwarmParams params
void transferMembersTo(RoilingSwarmEffect other, float fraction)
static RoilingSwarmEffect getSwarmFor(CombatEntityAPI entity)
static ListMap< RoilingSwarmEffect > getFlockingMap()
static float IMPACT_VOLUME_MULT
static String CONSTRUCTION_SWARM_WING
static String SWARM_CONSTRUCTING_SHIP
static Color EMP_FRINGE_COLOR
void add(K key, int quantity)
static float getShipWeight(ShipAPI ship)
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
ShipVariantAPI getVariant(String variantId)
List< SegmentAPI > getOrigSegments()
CombatFleetManagerAPI getFleetManager(FleetSide side)
float getCollisionRadius()
void setCollisionRadius(float radius)
BoundsAPI getExactBounds()
List< DeployedFleetMemberAPI > getDeployedCopyDFM()
ShipAPI spawnShipOrWing(String specId, Vector2f location, float facing)
void setSuppressDeploymentMessages(boolean suppressDeploymentMessages)
void setSourceShip(ShipAPI sourceShip)
MutableStat getMaxSpeed()
CombatEntityAPI getEntity()
ShipHullSpecAPI getHullSpec()
MutableShipStatsAPI getMutableStats()
void setMaxHitpoints(float maxArmor)
void setHitpoints(float value)
void setDoNotRender(boolean doNotRender)
void setImpactVolumeMult(float impactVolumeMult)
boolean hasTag(String tag)
void setCurrentCR(float cr)
ArmorGridAPI getArmorGrid()
void setExplosionScale(float explosionScale)
void setHulkChanceOverride(float hulkChanceOverride)
boolean hasTag(String tag)
List< WeaponSlotAPI > getAllWeaponSlotsCopy()
float getSuppliesToRecover()
ShipAPI.HullSize getHullSize()
ShipHullSpecAPI getHullSpec()
Vector2f computePosition(CombatEntityAPI ship)
float computeMidArcAngle(ShipAPI ship)