1package com.fs.starfarer.api.impl.campaign.command;
3import java.util.ArrayList;
4import java.util.HashSet;
5import java.util.LinkedHashSet;
9import com.fs.starfarer.api.EveryFrameScript;
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.CampaignFleetAPI;
12import com.fs.starfarer.api.campaign.FactionAPI;
13import com.fs.starfarer.api.campaign.SectorEntityToken;
14import com.fs.starfarer.api.campaign.StarSystemAPI;
15import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.ActionType;
16import com.fs.starfarer.api.campaign.econ.MarketAPI;
17import com.fs.starfarer.api.campaign.listeners.ObjectiveEventListener;
18import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript;
19import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript.MilitaryResponseParams;
20import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
21import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.OptionalFleetData;
22import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
23import com.fs.starfarer.api.impl.campaign.ids.Factions;
24import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
25import com.fs.starfarer.api.impl.campaign.ids.Tags;
26import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel;
27import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.Objectives;
28import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
29import com.fs.starfarer.api.plugins.BuildObjectiveTypePicker;
30import com.fs.starfarer.api.plugins.BuildObjectiveTypePicker.BuildObjectiveParams;
31import com.fs.starfarer.api.util.CountingMap;
32import com.fs.starfarer.api.util.Misc;
33import com.fs.starfarer.api.util.TimeoutTracker;
34import com.fs.starfarer.api.util.WeightedRandomPicker;
38 public static enum LocationDanger {
47 public static LocationDanger [] vals = values();
49 public float enemyStrengthFraction;
50 private LocationDanger(
float enemyStrengthFraction) {
51 this.enemyStrengthFraction = enemyStrengthFraction;
54 public LocationDanger next() {
55 int index = this.ordinal() + 1;
56 if (index >= vals.length) index = vals.length - 1;
59 public LocationDanger prev() {
60 int index = this.ordinal() - 1;
61 if (index < 0) index = 0;
71 public static final String
KEY =
"$core_warSimScript";
82 protected TimeoutTracker<String>
timeouts =
new TimeoutTracker<String>();
84 protected List<StarSystemAPI>
queue =
new ArrayList<StarSystemAPI>();
90 for (StarSystemAPI system :
Global.
getSector().getEconomy().getStarSystemsWithMarkets()) {
92 timeouts.add(sid, 2f + (
float) Math.random() * 3f);
98 timeouts =
new TimeoutTracker<String>();
106 if (TutorialMissionIntel.isTutorialInProgress()) {
110 float days = Misc.getDays(amount);
114 if (
queue.isEmpty()) {
118 if (!
queue.isEmpty()) {
119 StarSystemAPI curr =
queue.remove(0);
127 timeouts.add(sid, 2f + (
float) Math.random() * 3f);
131 boolean inSpawnRange = RouteManager.isPlayerInSpawnRange(system.getCenter());
133 List<FactionAPI> factions =
new ArrayList<FactionAPI>(str.keySet());
143 for (SectorEntityToken obj : system.getEntitiesWithTag(Tags.OBJECTIVE)) {
144 List<FactionAPI> contenders =
new ArrayList<FactionAPI>();
147 for (FactionAPI faction : factions) {
149 contenders.add(faction);
154 }
else if (faction == obj.getFaction()) {
155 contenders.add(faction);
161 if (
timeouts.contains(
id))
continue;
163 timeouts.add(
id, 10f + (
float) Math.random() * 30f);
165 WeightedRandomPicker<FactionAPI> picker =
new WeightedRandomPicker<FactionAPI>();
167 for (FactionAPI faction : contenders) {
173 if (max <= 0)
continue;
175 for (FactionAPI faction : contenders) {
177 float w = (curr / max) - 0.5f;
178 picker.add(faction, w);
181 FactionAPI winner = picker.pick();
182 if (winner !=
null && winner != obj.getFaction()) {
183 Objectives o =
new Objectives(obj);
184 o.control(winner.getId());
190 for (SectorEntityToken sLoc : system.getEntitiesWithTag(Tags.STABLE_LOCATION)) {
191 if (sLoc.hasTag(Tags.NON_CLICKABLE))
continue;
192 if (sLoc.hasTag(Tags.FADING_OUT_AND_EXPIRING))
continue;
195 if (
timeouts.contains(
id))
continue;
197 timeouts.add(
id, 20f + (
float) Math.random() * 20f);
199 WeightedRandomPicker<FactionAPI> picker =
new WeightedRandomPicker<FactionAPI>();
201 for (FactionAPI faction : factions) {
207 if (max <= 0)
continue;
209 for (FactionAPI faction : factions) {
211 float w = (curr / max) - 0.5f;
212 picker.add(faction, w);
215 FactionAPI winner = picker.pick();
216 if (winner !=
null && winner != sLoc.getFaction()) {
217 BuildObjectiveParams params =
new BuildObjectiveParams();
218 params.faction = winner;
220 params.stableLoc = sLoc;
221 BuildObjectiveTypePicker pick =
Global.
getSector().getGenericPlugins().pickPlugin(BuildObjectiveTypePicker.class, params);
224 type = pick.pickObjectiveToBuild(params);
227 Objectives o =
new Objectives(sLoc);
228 o.build(type, winner.getId());
245 protected boolean wantsToOwnObjective(FactionAPI faction, CountingMap<FactionAPI> str, SectorEntityToken o) {
246 if (o.getFaction() == faction)
return false;
247 if (!o.getFaction().isHostileTo(faction) && !o.getFaction().isNeutralFaction()) {
257 boolean ownerHasColonyInSystem =
false;
258 for (MarketAPI curr : Misc.getMarketsInLocation(o.getContainingLocation())) {
259 if (curr.getFaction() == o.getFaction() &&
260 !curr.getFaction().isNeutralFaction()) {
261 ownerHasColonyInSystem =
true;
265 if (ownerHasColonyInSystem)
return false;
269 float minDist = Float.MAX_VALUE;
270 MarketAPI closest =
null;
271 boolean haveInSystemMarkets =
false;
272 for (MarketAPI market : Misc.getMarketsInLocation(o.getContainingLocation())) {
273 float dist = Misc.getDistance(market.getPrimaryEntity(), o);
274 if (dist < minDist) {
278 if (faction == market.getFaction()) {
279 haveInSystemMarkets =
true;
283 if (closest !=
null && closest.getFaction() == faction) {
288 if (faction.getCustomBoolean(Factions.CUSTOM_PIRATE_BEHAVIOR)) {
289 if (minDist > 8000) {
294 if (!haveInSystemMarkets && closest !=
null && !closest.getFaction().isHostileTo(faction)) {
299 FactionAPI strongest =
null;
300 for (FactionAPI curr : str.keySet()) {
301 int s = str.getCount(curr);
308 return strongest == faction;
320 timeouts.add(
id, 40f + (
float) Math.random() * 20f, 100f);
327 String
id =
"starsystem_" + system.getId();
332 String
id =
"sim_build_" + objective.getId();
337 String
id =
"sim_changedhands_" + objective.getId();
342 String
id = faction.getId() +
"_" + objective.getId();
347 if (faction.isNeutralFaction())
return;
348 if (faction.getCustomBoolean(Factions.CUSTOM_NO_WAR_SIM))
return;
350 if (enemy !=
null && enemy.isNeutralFaction())
return;
351 if (enemy !=
null && !faction.isHostileTo(enemy))
return;
360 MilitaryResponseParams params =
new MilitaryResponseParams(ActionType.HOSTILE,
365 20f + (
float) Math.random() * 20f);
367 objective.getContainingLocation().addScript(script);
369 timeouts.add(
id, params.responseDuration * 2f);
387 CountingMap<FactionAPI> result =
new CountingMap<FactionAPI>();
389 Set<FactionAPI> factions =
new LinkedHashSet<FactionAPI>();
394 for (CampaignFleetAPI fleet : system.getFleets()) {
395 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_TRADE_FLEET))
continue;
396 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_SMUGGLER))
continue;
397 factions.add(fleet.getFaction());
400 for (RouteData route : RouteManager.getInstance().getRoutesInLocation(system)) {
401 String
id = route.getFactionId();
402 if (
id ==
null)
continue;
404 factions.add(faction);
407 for (FactionAPI faction : factions) {
408 if (faction.getCustomBoolean(Factions.CUSTOM_NO_WAR_SIM))
continue;
412 result.add(faction, strength);
423 float f = enemyStrength / Math.max(1f, factionStrength + enemyStrength);
430 float f = factionStrength / Math.max(1f, factionStrength + enemyStrength);
440 public static float getEnemyStrength(String factionId, StarSystemAPI system,
boolean assumeHostileToPlayer) {
443 public static float getEnemyStrength(FactionAPI faction, StarSystemAPI system,
boolean assumeHostileToPlayer) {
445 Set<String> seen =
new HashSet<String>();
446 for (MarketAPI target : Misc.getMarketsInLocation(system)) {
447 if (!(assumeHostileToPlayer && target.getFaction().isPlayerFaction())) {
448 if (!target.getFaction().isHostileTo(faction))
continue;
451 if (seen.contains(target.getFactionId()))
continue;
452 seen.add(target.getFactionId());
456 if (faction.isPlayerFaction()) {
457 HostileActivityEventIntel intel = HostileActivityEventIntel.get();
460 enemyStr += intel.getVeryApproximateFPStrength(system);
477 Set<CampaignFleetAPI> seenFleets =
new HashSet<CampaignFleetAPI>();
478 for (CampaignFleetAPI fleet : system.getFleets()) {
479 if (fleet.getFaction() != faction)
continue;
480 if (fleet.isStationMode())
continue;
481 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_TRADE_FLEET))
continue;
482 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_SMUGGLER))
continue;
484 if (fleet.isPlayerFleet())
continue;
486 strength += fleet.getEffectiveStrength();
488 seenFleets.add(fleet);
491 for (RouteData route : RouteManager.getInstance().getRoutesInLocation(system)) {
492 if (route.getActiveFleet() !=
null && seenFleets.contains(route.getActiveFleet()))
continue;
494 OptionalFleetData data = route.getExtra();
495 if (data ==
null)
continue;
496 if (route.getFactionId() ==
null)
continue;
497 if (!faction.getId().equals(route.getFactionId()))
continue;
499 strength += data.getStrengthModifiedByDamage();
506 public static float getStationStrength(FactionAPI faction, StarSystemAPI system, SectorEntityToken from) {
509 for (CampaignFleetAPI fleet : system.getFleets()) {
510 if (!fleet.isStationMode())
continue;
511 if (fleet.getFaction() != faction)
continue;
513 float maxDist = Misc.getBattleJoinRange() * 3f;
515 float dist = Misc.getDistance(from, fleet);
516 if (dist < maxDist) {
517 strength += fleet.getEffectiveStrength();
570 public static LocationDanger
getDangerFor(FactionAPI faction, StarSystemAPI system) {
571 if (system ==
null)
return LocationDanger.NONE;
574 public static LocationDanger
getDangerFor(String factionId, StarSystemAPI system) {
575 if (system ==
null)
return LocationDanger.NONE;
578 public static LocationDanger
getDangerFor(
float factionStrength,
float enemyStrength) {
579 if (enemyStrength < 100)
return LocationDanger.NONE;
581 float f = enemyStrength / Math.max(1f, factionStrength + enemyStrength);
582 for (LocationDanger level : LocationDanger.vals) {
583 float test = level.enemyStrengthFraction + (level.next().enemyStrengthFraction - level.enemyStrengthFraction) * 0.5f;
584 if (level == LocationDanger.NONE) test = LocationDanger.NONE.enemyStrengthFraction;
589 return LocationDanger.EXTREME;
static SectorAPI getSector()
MilitaryResponseParams getParams()
static LocationDanger getDangerFor(FactionAPI faction, StarSystemAPI system)
static float getFactionStrength(String factionId, StarSystemAPI system)
static float getRelativeFactionStrength(String factionId, StarSystemAPI system)
String getControlSimTimeoutId(SectorEntityToken objective)
TimeoutTracker< String > getTimeouts()
void advance(float amount)
static float getEnemyStrength(FactionAPI faction, StarSystemAPI system)
static float getStationStrength(FactionAPI faction, StarSystemAPI system, SectorEntityToken from)
static float getFactionStrength(FactionAPI faction, StarSystemAPI system)
String getControlTimeoutId(SectorEntityToken objective, FactionAPI faction)
void addObjectiveActionResponse(SectorEntityToken objective, FactionAPI faction, FactionAPI enemy)
List< StarSystemAPI > queue
void reportObjectiveChangedHands(SectorEntityToken objective, FactionAPI from, FactionAPI to)
static void removeNoFightingTimeoutForObjective(SectorEntityToken objective, FactionAPI faction)
static float getEnemyStrength(String factionId, StarSystemAPI system, boolean assumeHostileToPlayer)
static float getEnemyStrength(FactionAPI faction, StarSystemAPI system, boolean assumeHostileToPlayer)
String getStarSystemTimeoutId(StarSystemAPI system)
void processStarSystem(StarSystemAPI system)
static CountingMap< FactionAPI > getFactionStrengths(StarSystemAPI system)
static WarSimScript getInstance()
static void setNoFightingForObjective(SectorEntityToken objective, FactionAPI faction, float timeout)
TimeoutTracker< String > timeouts
static LocationDanger getDangerFor(float factionStrength, float enemyStrength)
static float getRelativeEnemyStrength(String factionId, StarSystemAPI system)
static void removeFightOrdersFor(SectorEntityToken target, FactionAPI faction)
static boolean isAlreadyFightingFor(SectorEntityToken objective, FactionAPI faction)
static final float CHECK_PROB
void reportObjectiveDestroyed(SectorEntityToken objective, SectorEntityToken stableLocation, FactionAPI enemy)
static final float CHECK_DAYS
static LocationDanger getDangerFor(String factionId, StarSystemAPI system)
boolean wantsToOwnObjective(FactionAPI faction, CountingMap< FactionAPI > str, SectorEntityToken o)
String getBuildSimTimeoutId(SectorEntityToken objective)
static float getEnemyStrength(String factionId, StarSystemAPI system)