1package com.fs.starfarer.api.impl.combat.threat;
3import java.util.ArrayList;
4import java.util.LinkedHashSet;
8import org.lwjgl.util.vector.Vector2f;
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.combat.AssignmentTargetAPI;
12import com.fs.starfarer.api.combat.BattleObjectiveAPI;
13import com.fs.starfarer.api.combat.CombatAssignmentType;
14import com.fs.starfarer.api.combat.CombatEngineAPI;
15import com.fs.starfarer.api.combat.CombatFleetManagerAPI;
16import com.fs.starfarer.api.combat.CombatFleetManagerAPI.AssignmentInfo;
17import com.fs.starfarer.api.combat.CombatTaskManagerAPI;
18import com.fs.starfarer.api.combat.DeployedFleetMemberAPI;
19import com.fs.starfarer.api.combat.ShipAIPlugin;
20import com.fs.starfarer.api.combat.ShipAPI;
21import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags;
22import com.fs.starfarer.api.fleet.FleetGoal;
23import com.fs.starfarer.api.impl.campaign.ids.HullMods;
24import com.fs.starfarer.api.impl.campaign.ids.Tags;
25import com.fs.starfarer.api.util.IntervalUtil;
26import com.fs.starfarer.api.util.Misc;
53 protected boolean abort =
false;
101 ShipAPI ship = member.getShip();
102 if (ship ==
null || ship.
getAI() ==
null)
continue;
136 if (deployed.isEmpty())
return;
138 boolean someMatching =
false;
140 if (!member.isFighterWing() && member.getShip() !=
null &&
145 }
else if (!member.isFighterWing() && member.getShip() !=
null &&
151 if (!someMatching)
return;
159 if (
owner == 0) sign = -1;
161 Vector2f fabricatorLoc =
new Vector2f(0, 0 +
mh * 0.33f * sign);
163 Vector2f perp =
new Vector2f(axis.y, -axis.x);
167 float hiveOffset = distToEnemyCom - 6000f;
168 if (Math.abs(hiveOffset) < 2000f) {
169 hiveOffset = Math.signum(hiveOffset) * 2000f;
171 if (hiveOffset > 2000) hiveOffset= 2000f;
172 Vector2f hiveLoc =
new Vector2f(axis);
173 hiveLoc.scale(hiveOffset);
174 Vector2f.add(hiveLoc, fabricatorLoc, hiveLoc);
177 owner, fabricatorLoc, 0f, 360f, 3000f,
null,
true,
true);
182 ShipAPI ship = member.getShip();
183 if (ship ==
null || ship.
getAI() ==
null)
continue;
192 float defDist = distToEnemyCom - 2000f;
193 if (enemyWeightNearFabricatorLoc >= 3f) {
194 defDist = Math.min(defDist, 3000f);
196 if (fabricators == 0 && hives == 0) {
205 }
else if (defDist < 2000f) {
227 ShipAPI ship = member.getShip();
228 if (ship ==
null || ship.
getAI() ==
null)
continue;
243 Vector2f defLoc =
new Vector2f(axis);
244 defLoc.scale(defDist);
245 Vector2f.add(defLoc, fabricatorLoc, defLoc);
247 Vector2f defLoc1 =
new Vector2f(perp);
248 defLoc1.scale(1000f);
249 Vector2f.add(defLoc1, defLoc, defLoc1);
251 Vector2f defLoc2 =
new Vector2f(perp);
252 defLoc2.scale(-1000f);
253 Vector2f.add(defLoc2, defLoc, defLoc2);
284 List<AssignmentTargetAPI> withCaptures =
new ArrayList<>();
286 if (info.getTarget() ==
null)
continue;
288 if ((fabricators == 0 && hives == 0) ||
289 !
wantsToControl(fabricatorLoc, axisAngle, distToEnemyCom, info.getTarget().getLocation())) {
292 withCaptures.add(info.getTarget());
297 if (fabricators > 0 || hives > 0) {
299 if (withCaptures.contains(curr))
continue;
300 if (
wantsToControl(fabricatorLoc, axisAngle, distToEnemyCom, curr.getLocation())) {
307 Set<DeployedFleetMemberAPI> escorted =
new LinkedHashSet<>();
310 ShipAPI ship = member.getShip();
311 if (ship ==
null || ship.
getAI() ==
null)
continue;
314 float enemyCheckRange = 3000f;
316 enemyCheckRange = 1000f;
322 boolean enemiesNear = enemyWeight >= shipWeight * 0.5f;
332 }
else if (
isHive(ship)) {
340 float minDist = Float.MAX_VALUE;
342 if (other == member || other.getShip() ==
null || escorted.contains(other))
continue;
344 float extraDistScore = 0f;
345 if (other.getShip().isCruiser() &&
isCombatUnit(other.getShip())) {
347 }
else if (other.getShip().isDestroyer() &&
isCombatUnit(other.getShip())) {
348 extraDistScore = 100000f;
349 }
else if (other.getShip().isFrigate() &&
isCombatUnit(other.getShip())) {
351 extraDistScore = 500000f;
353 extraDistScore = 1000000f;
355 }
else if (
isHive(other.getShip())) {
357 extraDistScore = 100000f;
359 extraDistScore = 10000000f;
364 float dist =
Misc.
getDistance(member.getLocation(), other.getLocation()) + extraDistScore;
365 if (dist < minDist) {
370 if (closest !=
null) {
371 member.getShip().getAIFlags().setFlag(AIFlags.TIMID_ESCORT, 2f);
372 member.getShip().getAIFlags().setFlag(AIFlags.ESCORT_RANGE_MODIFIER, 2f, 300f);
383 protected boolean wantsToControl(Vector2f fabricatorLoc,
float axisAngle,
float distToEnemyCom, Vector2f objectiveLoc) {
389 if (enemyWeight <= 0f && angleDiff > 30f)
return true;
391 return dist < 5000 || (dist < distToEnemyCom && angleDiff < 45f);
400 if (withSearchAndDestroy) {
406 if (member.
getShip() ==
null)
return;
423 if (dist < minDist) {
429 boolean needToLeash =
false;
430 needToLeash |= curr ==
null && dist > minDist;
431 needToLeash |= curr !=
null && dist > maxDist;
433 if (needToMakeAssignment && needToLeash) {
442 List<AssignmentInfo>
remove =
new ArrayList<>();
447 if (curr.getAssignedMembers().isEmpty()) {
459 Vector2f com =
new Vector2f();
462 if (member.isFighterWing())
continue;
463 if (member.getShip() ==
null)
continue;
466 Vector2f.add(member.getLocation(), com, com);
470 com.scale(1f / weight);
static CombatEngineAPI getCombatEngine()
void modifyFlat(String source, float value)
void setFlag(AIFlags flag)
static final String THREAT_HULLMOD
static boolean isCombatUnit(ShipAPI ship)
static float SND_FRACTION
Vector2f getEnemyCenterOfMass()
boolean wantsToControl(Vector2f fabricatorLoc, float axisAngle, float distToEnemyCom, Vector2f objectiveLoc)
static boolean isOverseer(ShipAPI ship)
void advance(float amount)
boolean gaveInitialOrders
void cancelOrders(DeployedFleetMemberAPI member, boolean withSearchAndDestroy)
CombatFleetManagerAPI fleetManager
AssignmentInfo mainDefend2
void giveMovementOrder(DeployedFleetMemberAPI member, Vector2f loc, float minDist, float maxDist)
float untilSNDOnSkirmishUnits
float captureAllTimeRemaining
CombatFleetManagerAPI enemyFleetManager
static boolean isFabricator(ShipAPI ship)
AssignmentInfo mainDefend1
ThreatCombatStrategyAI(int owner)
void cleanUpEmptyAssignments()
CombatTaskManagerAPI taskManager
void manageSND(float amount)
void escort(DeployedFleetMemberAPI member, DeployedFleetMemberAPI target)
static boolean isHive(ShipAPI ship)
static String SHIP_UNDER_CONSTRUCTION
void advance(float amount)
static float countEnemyWeightInArcAroundLocation(ShipAPI ship, Vector2f loc, float dir, float arc, float maxRange, ShipAPI ignore, boolean ignoreFightersAndModules)
static float getShipWeight(ShipAPI ship)
static float getAngleDiff(float from, float to)
static float getDistance(SectorEntityToken from, SectorEntityToken to)
static Vector2f getUnitVector(Vector2f from, Vector2f to)
static float getAngleInDegrees(Vector2f v)
default void setNoOrders(boolean noOrders)
boolean isAwareOf(int owner, CombatEntityAPI other)
CombatFleetManagerAPI getFleetManager(FleetSide side)
List< BattleObjectiveAPI > getObjectives()
AssignmentTargetAPI getTarget()
CombatAssignmentType getType()
AdmiralAIPlugin getAdmiralAI()
List< DeployedFleetMemberAPI > getDeployedCopyDFM()
CombatTaskManagerAPI getTaskManager(boolean ally)
AssignmentTargetAPI createWaypoint2(Vector2f loc, boolean ally)
List< AssignmentInfo > getAllAssignments()
void removeAssignment(AssignmentInfo info)
MutableStat getCommandPointsStat()
AssignmentInfo createAssignment(CombatAssignmentType type, AssignmentTargetAPI target, boolean useCommandPoint)
AssignmentInfo getAssignmentFor(ShipAPI ship)
void setAssignmentWeight(AssignmentInfo info, float weight)
AssignmentTargetAPI getAssignmentTargetFor(ShipAPI ship)
void giveAssignment(DeployedFleetMemberAPI member, AssignmentInfo assignment, boolean useCommandPointIfNeeded)
void orderSearchAndDestroy(DeployedFleetMemberAPI member, boolean useCommandPointIfNeeded)
void clearEmptyWaypoints()
ShipHullSpecAPI getHullSpec()
boolean hasTag(String tag)
ShipwideAIFlags getAIFlags()
boolean hasTag(String tag)