1package com.fs.starfarer.api.impl.campaign.intel.group;
4import java.util.ArrayList;
5import java.util.Collections;
6import java.util.Comparator;
9import org.lwjgl.util.vector.Vector2f;
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.campaign.CampaignFleetAPI;
13import com.fs.starfarer.api.campaign.FactionAPI;
14import com.fs.starfarer.api.campaign.SectorEntityToken;
15import com.fs.starfarer.api.campaign.StarSystemAPI;
16import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI;
17import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.ActionType;
18import com.fs.starfarer.api.campaign.econ.Industry;
19import com.fs.starfarer.api.campaign.econ.MarketAPI;
20import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript;
21import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript.MilitaryResponseParams;
22import com.fs.starfarer.api.impl.campaign.command.WarSimScript;
23import com.fs.starfarer.api.impl.campaign.econ.impl.OrbitalStation;
24import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
25import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
26import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.OptionalFleetData;
27import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
28import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
29import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
30import com.fs.starfarer.api.impl.campaign.ids.Tags;
31import com.fs.starfarer.api.impl.campaign.intel.group.GenericRaidFGI.GenericPayloadAction;
32import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseAssignmentAI.FleetActionDelegate;
33import com.fs.starfarer.api.impl.campaign.procgen.themes.WarfleetAssignmentAI;
34import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD;
35import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.BombardType;
36import com.fs.starfarer.api.util.CountingMap;
37import com.fs.starfarer.api.util.IntervalUtil;
38import com.fs.starfarer.api.util.Misc;
42 public static enum FGRaidType {
48 public static class FGRaidParams {
50 public FGRaidType type = FGRaidType.CONCURRENT;
51 public boolean doNotGetSidetracked =
true;
52 public boolean tryToCaptureObjectives =
true;
53 public boolean allowAnyHostileMarket =
false;
54 public float maxDurationIfSpawnedFleetsConcurrent = 90f;
55 public float maxDurationIfSpawnedFleetsPerSequentialStage = 45f;
56 public int maxStabilityLostPerRaid = 3;
57 public int raidsPerColony = 2;
59 public String raidApproachText =
null;
60 public String raidActionText =
null;
61 public String targetTravelText =
null;
62 public boolean appendTargetNameToTravelText =
true;
63 public String inSystemActionText =
null;
64 public BombardType bombardment =
null;
65 public List<String> disrupt =
new ArrayList<String>();
67 public boolean allowNonHostileTargets =
false;
68 public List<MarketAPI> allowedTargets =
new ArrayList<MarketAPI>();
70 public void setBombardment(BombardType type) {
71 this.bombardment = type;
72 raidApproachText =
"moving to bombard";
73 raidActionText =
"bombarding";
77 public void setDisrupt(String ... industries) {
78 for (String
id : industries) {
81 raidsPerColony = Math.min(disrupt.size(), 3);
82 if (raidsPerColony < 1) raidsPerColony = 1;
86 public static class RaidSubstage {
87 protected boolean started =
false;
88 public float maxDuration;
90 public List<SectorEntityToken> objectives =
new ArrayList<SectorEntityToken>();
91 public List<SectorEntityToken> markets =
new ArrayList<SectorEntityToken>();
92 public List<SectorEntityToken> finishedRaiding =
new ArrayList<SectorEntityToken>();
94 protected Object readResolve() {
95 if (objectives ==
null) {
96 objectives =
new ArrayList<SectorEntityToken>();
98 if (markets ==
null) {
99 markets =
new ArrayList<SectorEntityToken>();
101 if (finishedRaiding ==
null) {
102 finishedRaiding =
new ArrayList<SectorEntityToken>();
108 if (markets.isEmpty()) {
116 if (action.
raidCount.getCount(curr.getMarket()) < action.
params.raidsPerColony) {
134 protected List<MilitaryResponseScript>
scripts =
new ArrayList<MilitaryResponseScript>();
155 route.addSegment(segment);
161 super.notifyFleetsSpawnedMidSegment(segment);
166 super.notifySegmentFinished(segment);
173 if (fleets.isEmpty())
return;
189 fleet.addScript(script);
196 List<MarketAPI> sortedTargetMarkets =
new ArrayList<MarketAPI>();
198 if (!
params.allowAnyHostileMarket && !
params.allowedTargets.contains(market))
continue;
201 sortedTargetMarkets.add(market);
204 final Vector2f sortLoc =
new Vector2f(fleets.get(0).getLocation());
205 Collections.sort(sortedTargetMarkets,
new Comparator<MarketAPI>() {
209 return (
int) Math.signum(d1 - d2);
219 List<SectorEntityToken> objectives =
new ArrayList<SectorEntityToken>();
220 float minDist = Float.MAX_VALUE;
224 if (dist < minDist) {
229 if (closest !=
null) {
230 objectives.add(closest);
234 minDist = Float.MAX_VALUE;
238 if (dist < minDist) {
243 if (closest !=
null) {
244 objectives.add(closest);
247 if (!
params.tryToCaptureObjectives) {
251 if (
params.type == FGRaidType.CONCURRENT) {
252 RaidSubstage stage =
new RaidSubstage();
253 stage.maxDuration =
params.maxDurationIfSpawnedFleetsConcurrent;
254 stage.objectives.addAll(objectives);
255 for (
MarketAPI market : sortedTargetMarkets) {
256 stage.markets.add(market.getPrimaryEntity());
260 if (!objectives.isEmpty()) {
261 RaidSubstage stage =
new RaidSubstage();
262 stage.maxDuration =
params.maxDurationIfSpawnedFleetsPerSequentialStage;
263 stage.objectives.addAll(objectives);
267 for (
MarketAPI market : sortedTargetMarkets) {
268 RaidSubstage stage =
new RaidSubstage();
269 stage.maxDuration =
params.maxDurationIfSpawnedFleetsConcurrent;
270 stage.markets.add(market.getPrimaryEntity());
276 for (RaidSubstage stage :
stages) {
277 totalDur += stage.maxDuration;
283 float responseFraction = 1f / Math.max(1f, sortedTargetMarkets.size());
284 for (
MarketAPI market : sortedTargetMarkets) {
285 MilitaryResponseParams defParams =
new MilitaryResponseParams(ActionType.HOSTILE,
286 "defRaid_" + market.getId(),
288 market.getPrimaryEntity(),
300 if (clearAssignments) {
302 fleet.clearAssignments();
306 List<MilitaryResponseScript>
remove =
new ArrayList<MilitaryResponseScript>();
308 if (s.getParams() !=
null &&
309 s.getParams().responseReason !=
null && s.getParams().responseReason.startsWith(
"raid_")) {
343 super.directFleets(amount);
349 if (fleets.isEmpty()) {
365 RaidSubstage stage =
stages.get(0);
366 if (!stage.started) {
367 stage.started =
true;
371 List<SectorEntityToken> targets =
new ArrayList<SectorEntityToken>(stage.objectives);
372 targets.addAll(stage.markets);
378 stage.maxDuration -= days;
379 if (stage.maxDuration <= 0 || stage.allGoalsAchieved(
this)) {
385 if (!
interval.intervalElapsed())
return;
400 boolean someRaidsFinished =
false;
402 if (stage.finishedRaiding.contains(e))
continue;
404 someRaidsFinished =
true;
405 stage.finishedRaiding.add(e);
409 if (someRaidsFinished) {
413 List<SectorEntityToken> remaining =
new ArrayList<SectorEntityToken>();
414 remaining.addAll(stage.markets);
415 remaining.removeAll(stage.finishedRaiding);
419 if (!remaining.isEmpty()) {
427 if (
params.doNotGetSidetracked) {
428 boolean battleNear =
false;
430 if (other == fleet || other.getBattle() ==
null)
continue;
431 if (other.getContainingLocation() != fleet.getContainingLocation());
435 if (ai !=
null && ai.
wantsToJoin(other.getBattle(), other.getBattle().isPlayerInvolved())) {
450 float responseFraction = 1f / Math.max(1f, targets.size());
457 float rf = responseFraction;
458 MilitaryResponseParams aggroParams =
new MilitaryResponseParams(ActionType.HOSTILE,
459 "raid_" + target.getId(),
464 if (
params.appendTargetNameToTravelText) {
465 aggroParams.travelText =
466 (params.targetTravelText !=
null ? params.targetTravelText +
" " :
"traveling to ") + target.getName();
467 }
else if (
params.targetTravelText !=
null) {
468 aggroParams.travelText =
params.targetTravelText;
471 if (
params.inSystemActionText !=
null) {
472 aggroParams.actionText =
params.inSystemActionText;
474 aggroParams.actionText =
"raiding system";
489 if (market ==
null)
return false;
493 if (!
params.allowedTargets.contains(market) && !
params.allowedTargets.isEmpty() && !
params.allowAnyHostileMarket) {
504 if (
params.bombardment !=
null && fleet !=
null) {
507 if (other == fleet)
continue;
510 if (dist > 1000)
continue;
511 float otherFP = other.getFleetPoints();
512 if (otherFP > fp * 1.2f) {
538 if (
params.bombardment !=
null) {
546 if (cost <= bombardStr) {
561 int index =
raidCount.getCount(market) - 1;
562 if (index < 0) index = 0;
563 if (
params.disrupt !=
null && index <
params.disrupt.size()) {
565 for (String industryId :
params.disrupt) {
567 if (count >= index) {
581 faction.
getId(),
true, 30f);
583 }
else if (industry !=
null) {
588 raidStr,
params.maxStabilityLostPerRaid,
params.raidsPerColony > 1);
602 if (data !=
null) str += data.getStrengthModifiedByDamage();
605 boolean playerTargeted =
false;
614 if (!
params.allowAnyHostileMarket && !
params.allowedTargets.contains(target))
continue;
619 float damage = 0.5f * defensiveStr / Math.max(str, 1f);
620 if (damage > 0.75f) damage = 0.75f;
621 strMult *= (1f - damage);
623 if (defensiveStr >= str) {
628 if (station !=
null) {
633 for (
int i = 0; i <
params.raidsPerColony; i++) {
638 str = origStr * strMult;
650 if (extra.damage ==
null) {
653 extra.damage = 1f - (1f - extra.damage) * strMult;
655 if (extra.damage > 1f) extra.damage = 1f;
670 if (
params.raidApproachText !=
null) {
671 return params.raidApproachText +
" " + market.
getName();
677 if (
params.raidActionText !=
null) {
678 return params.raidActionText +
" " + market.
getName();
703 int totalGoal = params.raidsPerColony *
params.allowedTargets.size();
704 if (totalGoal < 1) totalGoal = 1;
707 if (
params.bombardment !=
null) {
711 return Math.max(0f, (
float)achieved / (
float)totalGoal);
717 boolean player =
false;
719 if (!
params.allowAnyHostileMarket && !
params.allowedTargets.contains(target))
continue;
722 int size = target.getSize();
727 if (target.isPlayerOwned()) {
732 if (largest !=
null) {
static SettingsAPI getSettings()
static SectorAPI getSector()
static float getFactionStrength(String factionId, StarSystemAPI system)
static float getStationStrength(FactionAPI faction, StarSystemAPI system, SectorEntityToken from)
static void removeNoFightingTimeoutForObjective(SectorEntityToken objective, FactionAPI faction)
static void setNoFightingForObjective(SectorEntityToken objective, FactionAPI faction, float timeout)
static void removeFightOrdersFor(SectorEntityToken target, FactionAPI faction)
static float getEnemyStrength(String factionId, StarSystemAPI system)
static void disrupt(Industry station)
static void applyDamageToFleet(CampaignFleetAPI fleet, float damage, boolean damageRemainingShips, Random random)
static boolean isPlayerInSpawnRange(SectorEntityToken from)
static final String MEMORY_KEY_FLEET_DO_NOT_GET_SIDETRACKED
static final String MEMORY_KEY_WAR_FLEET
static final String RECENTLY_RAIDED
static final String RECENTLY_BOMBARDED
static final String FLEET_BUSY
boolean isActionFinished()
void setDurDays(float waitDays)
void setActionFinished(boolean finished)
Color getSystemNameHighlightColor()
CountingMap< MarketAPI > raidCount
void addRouteSegment(RouteData route)
void orderFleetMovements(List< SectorEntityToken > targets)
boolean canRaid(CampaignFleetAPI fleet, MarketAPI market)
String getRaidInSystemText(CampaignFleetAPI fleet)
String getRaidApproachText(CampaignFleetAPI fleet, MarketAPI market)
boolean computedSubstages
float getSuccessFraction()
void notifySegmentFinished(RouteSegment segment)
void directFleets(float amount)
String getRaidActionText(CampaignFleetAPI fleet, MarketAPI market)
void notifyFleetsSpawnedMidSegment(RouteSegment segment)
List< RaidSubstage > stages
List< MilitaryResponseScript > scripts
String getRaidDefaultText(CampaignFleetAPI fleet)
void performRaid(CampaignFleetAPI fleet, MarketAPI market)
String getRaidPrepText(CampaignFleetAPI fleet, SectorEntityToken from)
FGRaidAction(FGRaidParams params, float raidDays)
CountingMap< MarketAPI > getRaidCount()
void removeAggroMilitaryScripts(boolean clearAssignments)
boolean isSpawnedFleets()
int getApproximateNumberOfFleets()
List< CampaignFleetAPI > getFleets()
void setDelegate(FleetActionDelegate delegate)
boolean doIndustryRaid(FactionAPI faction, float attackerStr, Industry industry, float durMult)
void doBombardment(FactionAPI faction, BombardType type)
void doGenericRaid(FactionAPI faction, float attackerStr)
static int getBombardmentCost(MarketAPI market, CampaignFleetAPI fleet)
static float getRaidStr(CampaignFleetAPI fleet)
void forceIntervalElapsed()
void advance(float amount)
static Color getTextColor()
static float FP_TO_GROUND_RAID_STR_APPROX_MULT
static List< MarketAPI > getMarketsInLocation(LocationAPI location, String factionId)
static Color getBasePlayerColor()
static boolean isFleetMadeHostileToFaction(CampaignFleetAPI fleet, FactionAPI faction)
static float getDistance(SectorEntityToken from, SectorEntityToken to)
static boolean setFlagWithReason(MemoryAPI memory, String flagKey, String reason, boolean value, float expire)
static Industry getStationIndustry(MarketAPI market)
static float FP_TO_BOMBARD_COST_APPROX_MULT
static void setRaidedTimestamp(MarketAPI market)
float getFloat(String key)
float convertToDays(float realSeconds)
LocationAPI getContainingLocation()
boolean isHostileTo(FactionAPI other)
List< SectorEntityToken > getEntitiesWithTag(String tag)
void addScript(EveryFrameScript script)
CampaignClockAPI getClock()
SectorEntityToken getCenter()
boolean wantsToJoin(BattleAPI battle, boolean playerInvolved)
MemoryAPI getMemoryWithoutUpdate()
boolean hasIndustry(String id)
Industry getIndustry(String id)
SectorEntityToken getPrimaryEntity()