Starsector API
Loading...
Searching...
No Matches
WarSimScript.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.command;
2
3import java.util.ArrayList;
4import java.util.HashSet;
5import java.util.LinkedHashSet;
6import java.util.List;
7import java.util.Set;
8
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;
35
36public class WarSimScript implements EveryFrameScript, ObjectiveEventListener {
37
38 public static enum LocationDanger {
39 NONE(0.01f),
40 MINIMAL(0.1f),
41 LOW(0.2f),
42 MEDIUM(0.3f),
43 HIGH(0.5f),
44 EXTREME(0.8f),
45 ;
46
47 public static LocationDanger [] vals = values();
48
49 public float enemyStrengthFraction;
50 private LocationDanger(float enemyStrengthFraction) {
51 this.enemyStrengthFraction = enemyStrengthFraction;
52 }
53
54 public LocationDanger next() {
55 int index = this.ordinal() + 1;
56 if (index >= vals.length) index = vals.length - 1;
57 return vals[index];
58 }
59 public LocationDanger prev() {
60 int index = this.ordinal() - 1;
61 if (index < 0) index = 0;
62 return vals[index];
63 }
64
65 }
66
67
68
69
70
71 public static final String KEY = "$core_warSimScript";
72
73 public static final float CHECK_DAYS = 10f;
74 public static final float CHECK_PROB = 0.5f;
75
76
77 public static WarSimScript getInstance() {
78 Object test = Global.getSector().getMemoryWithoutUpdate().get(KEY);
79 return (WarSimScript) test;
80 }
81
82 protected TimeoutTracker<String> timeouts = new TimeoutTracker<String>();
83
84 protected List<StarSystemAPI> queue = new ArrayList<StarSystemAPI>();
85
86 public WarSimScript() {
87 Global.getSector().getMemoryWithoutUpdate().set(KEY, this);
88 Global.getSector().getListenerManager().addListener(this);
89
90 for (StarSystemAPI system : Global.getSector().getEconomy().getStarSystemsWithMarkets()) {
91 String sid = getStarSystemTimeoutId(system);
92 timeouts.add(sid, 2f + (float) Math.random() * 3f);
93 }
94 }
95
96 protected Object readResolve() {
97 if (timeouts == null) {
98 timeouts = new TimeoutTracker<String>();
99 }
100 return this;
101 }
102
103 public void advance(float amount) {
104 //if (true) return;
105
106 if (TutorialMissionIntel.isTutorialInProgress()) {
107 return;
108 }
109
110 float days = Misc.getDays(amount);
111
112 timeouts.advance(days);
113
114 if (queue.isEmpty()) {
115 queue = Global.getSector().getEconomy().getStarSystemsWithMarkets();
116 }
117
118 if (!queue.isEmpty()) {
119 StarSystemAPI curr = queue.remove(0);
120 processStarSystem(curr);
121 }
122 }
123
124 public void processStarSystem(StarSystemAPI system) {
125 String sid = getStarSystemTimeoutId(system);
126 if (timeouts.contains(sid)) return;
127 timeouts.add(sid, 2f + (float) Math.random() * 3f);
128
129 CountingMap<FactionAPI> str = getFactionStrengths(system);
130
131 boolean inSpawnRange = RouteManager.isPlayerInSpawnRange(system.getCenter());
132
133 List<FactionAPI> factions = new ArrayList<FactionAPI>(str.keySet());
134
135// if (system.getName().toLowerCase().contains("old milix")) {
136// System.out.println("wefwefwe");
137// }
138
139// if (system.isCurrentLocation()) {
140// System.out.println("ff23f23f32");
141// }
142
143 for (SectorEntityToken obj : system.getEntitiesWithTag(Tags.OBJECTIVE)) {
144 List<FactionAPI> contenders = new ArrayList<FactionAPI>();
145
146 // figure out if anyone that doesn't own it thinks they should own it
147 for (FactionAPI faction : factions) {
148 if (wantsToOwnObjective(faction, str, obj)) {
149 contenders.add(faction);
150 String id = getControlTimeoutId(obj, faction);
151 if (!timeouts.contains(id)) {
152 addObjectiveActionResponse(obj, faction, obj.getFaction());
153 }
154 } else if (faction == obj.getFaction()) {
155 contenders.add(faction);
156 }
157 }
158
159 if (!inSpawnRange) {
160 String id = getControlSimTimeoutId(obj);
161 if (timeouts.contains(id)) continue;
162
163 timeouts.add(id, 10f + (float) Math.random() * 30f);
164
165 WeightedRandomPicker<FactionAPI> picker = new WeightedRandomPicker<FactionAPI>();
166 float max = 0f;
167 for (FactionAPI faction : contenders) {
168 float curr = str.getCount(faction) + getStationStrength(faction, system, obj);
169 if (curr > max) {
170 max = curr;
171 }
172 }
173 if (max <= 0) continue;
174
175 for (FactionAPI faction : contenders) {
176 float curr = str.getCount(faction) + getStationStrength(faction, system, obj);
177 float w = (curr / max) - 0.5f;
178 picker.add(faction, w);
179 }
180
181 FactionAPI winner = picker.pick();
182 if (winner != null && winner != obj.getFaction()) {
183 Objectives o = new Objectives(obj);
184 o.control(winner.getId());
185 }
186 }
187 }
188
189
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;
193 if (!inSpawnRange) {
194 String id = getBuildSimTimeoutId(sLoc);
195 if (timeouts.contains(id)) continue;
196
197 timeouts.add(id, 20f + (float) Math.random() * 20f);
198
199 WeightedRandomPicker<FactionAPI> picker = new WeightedRandomPicker<FactionAPI>();
200 float max = 0f;
201 for (FactionAPI faction : factions) {
202 float curr = str.getCount(faction) + getStationStrength(faction, system, sLoc);
203 if (curr > max) {
204 max = curr;
205 }
206 }
207 if (max <= 0) continue;
208
209 for (FactionAPI faction : factions) {
210 float curr = str.getCount(faction) + getStationStrength(faction, system, sLoc);
211 float w = (curr / max) - 0.5f;
212 picker.add(faction, w);
213 }
214
215 FactionAPI winner = picker.pick();
216 if (winner != null && winner != sLoc.getFaction()) {
217 BuildObjectiveParams params = new BuildObjectiveParams();
218 params.faction = winner;
219 params.fleet = null;
220 params.stableLoc = sLoc;
221 BuildObjectiveTypePicker pick = Global.getSector().getGenericPlugins().pickPlugin(BuildObjectiveTypePicker.class, params);
222 String type = null;
223 if (pick != null) {
224 type = pick.pickObjectiveToBuild(params);
225 }
226 if (type != null) {
227 Objectives o = new Objectives(sLoc);
228 o.build(type, winner.getId());
229 }
230 }
231 }
232 }
233 }
234
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()) {
248// for (MarketAPI curr : Misc.getMarketsInLocation(o.getContainingLocation())) {
249// if (curr.getFaction() == o.getFaction() &&
250// !curr.getFaction().isNeutralFaction() &&
251// !curr.getFaction().isPlayerFaction()) {
252// return false;
253// }
254// }
255// return true;
256
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;
262 break;
263 }
264 }
265 if (ownerHasColonyInSystem) return false;
266 return true;
267 }
268
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) {
275 minDist = dist;
276 closest = market;
277 }
278 if (faction == market.getFaction()) {
279 haveInSystemMarkets = true;
280 }
281 }
282
283 if (closest != null && closest.getFaction() == faction) {
284 return true;
285 }
286
287 // pirate-like factions will try to pick up objectives that are far away from any markets
288 if (faction.getCustomBoolean(Factions.CUSTOM_PIRATE_BEHAVIOR)) {
289 if (minDist > 8000) {
290 return true;
291 }
292 }
293
294 if (!haveInSystemMarkets && closest != null && !closest.getFaction().isHostileTo(faction)) {
295 return false;
296 }
297
298 int maxStr = 0;
299 FactionAPI strongest = null;
300 for (FactionAPI curr : str.keySet()) {
301 int s = str.getCount(curr);
302 if (s > maxStr) {
303 maxStr = s;
304 strongest = curr;
305 }
306 }
307
308 return strongest == faction;
309 }
310
311
312
313 public void reportObjectiveChangedHands(SectorEntityToken objective, FactionAPI from, FactionAPI to) {
314 addObjectiveActionResponse(objective, from, to);
315 }
316
317
318 public void reportObjectiveDestroyed(SectorEntityToken objective, SectorEntityToken stableLocation, FactionAPI enemy) {
319 String id = getBuildSimTimeoutId(stableLocation);
320 timeouts.add(id, 40f + (float) Math.random() * 20f, 100f);
321
322 addObjectiveActionResponse(objective, objective.getFaction(), null);
323 }
324
325
326 protected String getStarSystemTimeoutId(StarSystemAPI system) {
327 String id = "starsystem_" + system.getId();
328 return id;
329 }
330
331 protected String getBuildSimTimeoutId(SectorEntityToken objective) {
332 String id = "sim_build_" + objective.getId();
333 return id;
334 }
335
336 protected String getControlSimTimeoutId(SectorEntityToken objective) {
337 String id = "sim_changedhands_" + objective.getId();
338 return id;
339 }
340
341 protected String getControlTimeoutId(SectorEntityToken objective, FactionAPI faction) {
342 String id = faction.getId() + "_" + objective.getId();
343 return id;
344 }
345
346 protected void addObjectiveActionResponse(SectorEntityToken objective, FactionAPI faction, FactionAPI enemy) {
347 if (faction.isNeutralFaction()) return;
348 if (faction.getCustomBoolean(Factions.CUSTOM_NO_WAR_SIM)) return;
349
350 if (enemy != null && enemy.isNeutralFaction()) return;
351 if (enemy != null && !faction.isHostileTo(enemy)) return;
352
353 String id = getControlTimeoutId(objective, faction);
354 if (timeouts.contains(id)) return;
355
356 if (isAlreadyFightingFor(objective, faction)) { // an MRS from some other source, such as a raid
357 return;
358 }
359
360 MilitaryResponseParams params = new MilitaryResponseParams(ActionType.HOSTILE,
361 objective.getId(),
362 faction,
363 objective,
364 0.4f,
365 20f + (float) Math.random() * 20f);
367 objective.getContainingLocation().addScript(script);
368
369 timeouts.add(id, params.responseDuration * 2f);
370 }
371
372
373
374
375 public boolean isDone() {
376 return false;
377 }
378
379 public boolean runWhilePaused() {
380 return false;
381 }
382
383
384
385
386 public static CountingMap<FactionAPI> getFactionStrengths(StarSystemAPI system) {
387 CountingMap<FactionAPI> result = new CountingMap<FactionAPI>();
388
389 Set<FactionAPI> factions = new LinkedHashSet<FactionAPI>();
390// if (system.getName().startsWith("Askonia")) {
391// System.out.println("wefewfew");
392// }
393
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());
398 }
399
400 for (RouteData route : RouteManager.getInstance().getRoutesInLocation(system)) {
401 String id = route.getFactionId();
402 if (id == null) continue;
403 FactionAPI faction = Global.getSector().getFaction(id);
404 factions.add(faction);
405 }
406
407 for (FactionAPI faction : factions) {
408 if (faction.getCustomBoolean(Factions.CUSTOM_NO_WAR_SIM)) continue;
409
410 int strength = (int) getFactionStrength(faction, system);
411 if (strength > 0) {
412 result.add(faction, strength);
413 }
414 }
415 return result;
416 }
417
418
419
420 public static float getRelativeEnemyStrength(String factionId, StarSystemAPI system) {
421 float enemyStrength = getEnemyStrength(factionId, system);
422 float factionStrength = getFactionStrength(factionId, system);
423 float f = enemyStrength / Math.max(1f, factionStrength + enemyStrength);
424 return f;
425 }
426
427 public static float getRelativeFactionStrength(String factionId, StarSystemAPI system) {
428 float enemyStrength = getEnemyStrength(factionId, system);
429 float factionStrength = getFactionStrength(factionId, system);
430 float f = factionStrength / Math.max(1f, factionStrength + enemyStrength);
431 return f;
432 }
433
434 public static float getEnemyStrength(String factionId, StarSystemAPI system) {
435 return getEnemyStrength(Global.getSector().getFaction(factionId), system, false);
436 }
437 public static float getEnemyStrength(FactionAPI faction, StarSystemAPI system) {
438 return getEnemyStrength(faction, system, false);
439 }
440 public static float getEnemyStrength(String factionId, StarSystemAPI system, boolean assumeHostileToPlayer) {
441 return getEnemyStrength(Global.getSector().getFaction(factionId), system, assumeHostileToPlayer);
442 }
443 public static float getEnemyStrength(FactionAPI faction, StarSystemAPI system, boolean assumeHostileToPlayer) {
444 float enemyStr = 0;
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;
449 }
450
451 if (seen.contains(target.getFactionId())) continue;
452 seen.add(target.getFactionId());
453 enemyStr += WarSimScript.getFactionStrength(target.getFaction(), system);
454 }
455
456 if (faction.isPlayerFaction()) {
457 HostileActivityEventIntel intel = HostileActivityEventIntel.get();
458 //HostileActivityIntel intel = HostileActivityIntel.get(system);
459 if (intel != null) {
460 enemyStr += intel.getVeryApproximateFPStrength(system);
461 }
462 }
463
464 return enemyStr;
465 }
466
467 public static float getFactionStrength(String factionId, StarSystemAPI system) {
468 return getFactionStrength(Global.getSector().getFaction(factionId), system);
469 }
470 public static float getFactionStrength(FactionAPI faction, StarSystemAPI system) {
471 float strength = 0f;
472
473// if (system.getName().toLowerCase().contains("naraka") && Factions.PIRATES.equals(faction.getId())) {
474// System.out.println("wefwefwe");
475// }
476
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;
483
484 if (fleet.isPlayerFleet()) continue;
485
486 strength += fleet.getEffectiveStrength();
487
488 seenFleets.add(fleet);
489 }
490
491 for (RouteData route : RouteManager.getInstance().getRoutesInLocation(system)) {
492 if (route.getActiveFleet() != null && seenFleets.contains(route.getActiveFleet())) continue;
493
494 OptionalFleetData data = route.getExtra();
495 if (data == null) continue;
496 if (route.getFactionId() == null) continue;
497 if (!faction.getId().equals(route.getFactionId())) continue;
498
499 strength += data.getStrengthModifiedByDamage();
500 }
501
502 return strength;
503 }
504
505
506 public static float getStationStrength(FactionAPI faction, StarSystemAPI system, SectorEntityToken from) {
507 float strength = 0f;
508
509 for (CampaignFleetAPI fleet : system.getFleets()) {
510 if (!fleet.isStationMode()) continue;
511 if (fleet.getFaction() != faction) continue;
512
513 float maxDist = Misc.getBattleJoinRange() * 3f;
514
515 float dist = Misc.getDistance(from, fleet);
516 if (dist < maxDist) {
517 strength += fleet.getEffectiveStrength();
518 }
519 }
520
521 return strength;
522 }
523
524 public TimeoutTracker<String> getTimeouts() {
525 return timeouts;
526 }
527
528
529 public static void removeFightOrdersFor(SectorEntityToken target, FactionAPI faction) {
530 for (EveryFrameScript s : target.getContainingLocation().getScripts()) {
531 if (s instanceof MilitaryResponseScript) {
533 if (script.getParams() != null && script.getParams().target == target &&
534 script.getParams().faction == faction) {
535 script.forceDone();
536 }
537 }
538 }
539 }
540
541 public static void setNoFightingForObjective(SectorEntityToken objective, FactionAPI faction, float timeout) {
542 removeFightOrdersFor(objective, faction);
543 if (timeout > 0) {
545 String id = wss.getControlTimeoutId(objective, faction);
546 wss.timeouts.add(id, timeout);
547 }
548 }
549
550 public static void removeNoFightingTimeoutForObjective(SectorEntityToken objective, FactionAPI faction) {
552 String id = wss.getControlTimeoutId(objective, faction);
553 wss.timeouts.remove(id);
554 }
555
556 public static boolean isAlreadyFightingFor(SectorEntityToken objective, FactionAPI faction) {
557 for (EveryFrameScript s : objective.getContainingLocation().getScripts()) {
558 if (s instanceof MilitaryResponseScript) {
560 if (script.getParams() != null && script.getParams().target == objective &&
561 script.getParams().faction == faction) {
562 return true;
563 }
564 }
565 }
566 return false;
567
568 }
569
570 public static LocationDanger getDangerFor(FactionAPI faction, StarSystemAPI system) {
571 if (system == null) return LocationDanger.NONE;
572 return getDangerFor(getFactionStrength(faction, system), getEnemyStrength(faction, system));
573 }
574 public static LocationDanger getDangerFor(String factionId, StarSystemAPI system) {
575 if (system == null) return LocationDanger.NONE;
576 return getDangerFor(getFactionStrength(factionId, system), getEnemyStrength(factionId, system));
577 }
578 public static LocationDanger getDangerFor(float factionStrength, float enemyStrength) {
579 if (enemyStrength < 100) return LocationDanger.NONE;
580
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;
585 if (test >= f) {
586 return level;
587 }
588 }
589 return LocationDanger.EXTREME;
590 }
591}
592
593
594
595
596
597
static SectorAPI getSector()
Definition Global.java:59
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)
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)
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)
static CountingMap< FactionAPI > getFactionStrengths(StarSystemAPI system)
static void setNoFightingForObjective(SectorEntityToken objective, FactionAPI faction, float timeout)
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)
void reportObjectiveDestroyed(SectorEntityToken objective, SectorEntityToken stableLocation, FactionAPI enemy)
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)