Starsector API
Loading...
Searching...
No Matches
FleetGroupIntel.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.intel.group;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.Random;
6import java.util.Set;
7
8import java.awt.Color;
9
10import org.lwjgl.util.vector.Vector2f;
11
12import com.fs.starfarer.api.Global;
13import com.fs.starfarer.api.campaign.CampaignFleetAPI;
14import com.fs.starfarer.api.campaign.FactionAPI;
15import com.fs.starfarer.api.campaign.LocationAPI;
16import com.fs.starfarer.api.campaign.SectorEntityToken;
17import com.fs.starfarer.api.campaign.StarSystemAPI;
18import com.fs.starfarer.api.campaign.econ.Industry;
19import com.fs.starfarer.api.campaign.econ.MarketAPI;
20import com.fs.starfarer.api.campaign.rules.MemoryAPI;
21import com.fs.starfarer.api.impl.campaign.command.WarSimScript;
22import com.fs.starfarer.api.impl.campaign.fleets.RouteLocationCalculator;
23import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
24import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.OptionalFleetData;
25import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
26import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteFleetSpawner;
27import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
28import com.fs.starfarer.api.impl.campaign.ids.Conditions;
29import com.fs.starfarer.api.impl.campaign.ids.Factions;
30import com.fs.starfarer.api.impl.campaign.ids.Industries;
31import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
32import com.fs.starfarer.api.impl.campaign.ids.Tags;
33import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
34import com.fs.starfarer.api.impl.campaign.intel.group.GenericRaidFGI.GenericRaidParams;
35import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission;
36import com.fs.starfarer.api.impl.campaign.procgen.themes.RouteFleetAssignmentAI.TravelState;
37import com.fs.starfarer.api.ui.LabelAPI;
38import com.fs.starfarer.api.ui.SectorMapAPI;
39import com.fs.starfarer.api.ui.TooltipMakerAPI;
40import com.fs.starfarer.api.util.CountingMap;
41import com.fs.starfarer.api.util.Misc;
42
57public abstract class FleetGroupIntel extends BaseIntelPlugin implements RouteFleetSpawner {
58
59 public static interface FGIEventListener {
60 public void reportFGIAborted(FleetGroupIntel intel);
61 }
62
63 public static String ABORT_UPDATE = "abort_update";
64 public static String FLEET_LAUNCH_UPDATE = "fleet_launch_update";
65
66 public static final String KEY_SPAWN_FP = "$core_fgiSpawnFP";
67
68 public static final String NEVER_STRAGGLER = "$core_fgiNeverStraggler";
69 public static final String KEY_POTENTIAL_STRAGGLER = "$core_fgiMaybeStraggler";
70 public static final String KEY_STRAGGLER_RETURN_COUNTDOWN = "$core_fgiStragglerReturnCountdown";
71
72
73 public static boolean DEBUG = false;
74
75
76 protected Random random = new Random();
77 protected List<FGAction> actions = new ArrayList<FGAction>();
78 protected RouteData route;
79 protected RouteSegment prevSegment;
80 protected List<CampaignFleetAPI> fleets = new ArrayList<CampaignFleetAPI>();
81 protected boolean spawnedFleets = false;
82
83 protected boolean doIncrementalSpawn = true;
84 protected List<CampaignFleetAPI> spawning = new ArrayList<CampaignFleetAPI>();
85 protected LocationAPI spawnLocation = null;
86 protected float spawnDelay = 0f;
87 protected float elapsed = 0f;
88
89 protected boolean aborted = false;
90 protected float totalFPSpawned = 0f;
91 protected float fleetAbortsMissionFPFraction = 0.33f;
92 protected float groupAbortsMissionFPFraction = 0.33f;
95 protected int approximateNumberOfFleets = 3;
96
97 protected FGIEventListener listener;
98
99 public FleetGroupIntel() {
100 Global.getSector().addScript(this);
101 }
102
103 protected Object readResolve() {
104 if (random == null) {
105 random = new Random();
106 }
107
108 //random = new Random(142343232L);
109 //System.out.println("RNG CHECK 1: " + random.nextLong());
110 return this;
111 }
112
113 public float getETAUntil(String actionId) {
114 return getETAUntil(actionId, false);
115 }
116 public float getETAUntil(String actionId, boolean untilEndOfAction) {
117 float eta = getDelayRemaining();
118 for (FGAction action : actions) {
119 if (action.getId() != null && action.getId().equals(actionId)) {
120 if (untilEndOfAction) {
121 eta += action.getEstimatedDaysToComplete();
122 }
123 return eta;
124 } else {
125 eta += action.getEstimatedDaysToComplete();
126 }
127 }
128 return 0f;
129 }
130
131 @Override
132 protected void notifyEnded() {
133 super.notifyEnded();
135 }
136
137
138 protected boolean sourceWasEverMilitaryMarket = false;
139 protected boolean sendFleetLaunchUpdate = false;
141 if (getSource() == null) return false;
142 MarketAPI market = getSource().getMarket();
143 if (market == null || market.isPlanetConditionMarketOnly()) return false;
144
145 if (market.hasCondition(Conditions.DECIVILIZED)) {
146 return false;
147 }
148
150 if (b == null) b = market.getIndustry(Industries.HIGHCOMMAND);
151 if (b == null || b.isDisrupted() || !b.isFunctional()) {
152 return false;
153 }
154 return true;
155 }
156
157 public boolean isInPreLaunchDelay() {
158 return route != null && route.getElapsed() <= 0f && route.getDelay() > 0;
159 }
160
165 public void setPreFleetDeploymentDelay(float delay) {
166 if (route != null) {
167 route.setDelay(delay);
168 }
169 }
170
171 public float getDelayRemaining() {
172 if (!isInPreLaunchDelay() || route == null) return 0f;
173 return route.getDelay();
174 }
175
176 public float getElapsed() {
177 return elapsed;
178 }
179
180 public void setElapsed(float elapsed) {
181 this.elapsed = elapsed;
182 }
183
184 @Override
185 public void advance(float amount) {
186 super.advance(amount);
187
188 elapsed += amount;
189
190 if (isEnded() || isEnding() || isAborted()) return;
191 if (route == null) return;
192
193 if (isInPreLaunchDelay()) {
195 boolean mil = isSourceFunctionalMilitaryMarket();
197 if (!mil && sourceWasEverMilitaryMarket) {
198 abort();
199 return;
200 }
201 return;
202 }
203
205 sendFleetLaunchUpdate = false;
207 }
208
209 if (!isSucceeded() && !isEnding() && !isAborted() && shouldAbort()) {
210 abort();
211 return;
212 }
213
214 if (!spawnedFleets) {
215 if (!isSucceeded() && route.getExtra() != null && route.getExtra().damage != null &&
216 1f - route.getExtra().damage < getGroupAbortsMissionFPFraction()) {
217 abort();
218 return;
219 }
220
221 RouteSegment curr = route.getCurrent();
222 if (curr != prevSegment || route.isExpired()) {
223 if (prevSegment != null && prevSegment.custom instanceof FGAction) {
224 FGAction action = (FGAction) prevSegment.custom;
226 actions.remove(action);
227 notifyActionFinished(action);
228
229 if (route.isExpired()) {
230 finish(false);
231 return;
232 }
233 }
234 }
235 prevSegment = curr;
236 } else {
239
240 if (actions.isEmpty()) {
241 finish(false);
242 return;
243 }
244
245 FGAction action = actions.get(0);
246 if (action.isActionFinished()) {
247 actions.remove(0);
248 notifyActionFinished(action);
249 return;
250 }
251
252 action.directFleets(amount);
253
254 //System.out.println(action + " " + action.isActionFinished());
255 if (action.isActionFinished()) {
256 actions.remove(0);
257 notifyActionFinished(action);
258 return;
259 }
260 }
261
262 }
263
264 protected boolean shouldAbort() {
265 return false;
266 }
267
269 // presumably, !isFailed() is correct here but not 100% sure why -am
270 if (action instanceof FGWaitAction && (isAborted() || !isFailed())) {
271 return false;
272 }
273
274 if (action instanceof FGWaitAction) {
275 FGWaitAction wait = (FGWaitAction) action;
276 if (wait.getOrigDurDays() <= 0f) return false;
277 }
278 return action != null && action.getId() != null;
279 }
280
281 protected void notifyActionFinished(FGAction action) {
282 if (action != null && shouldSendIntelUpdateWhenActionFinished(action)) {
284 }
285 }
286
287
289 if (isSucceeded()) {
290 List<CampaignFleetAPI> remove = new ArrayList<CampaignFleetAPI>();
291 for (CampaignFleetAPI fleet : fleets) {
292 if (!fleet.isAlive()) {
293 remove.add(fleet);
294 }
295 }
296 fleets.removeAll(remove);
297 return; // already returning at this point, still clean up destroyed fleets though
298 }
299
301
302 List<CampaignFleetAPI> remove = new ArrayList<CampaignFleetAPI>();
303 float totalFP = 0f;
304 for (CampaignFleetAPI fleet : fleets) {
305 float spawnFP = fleet.getMemoryWithoutUpdate().getFloat(KEY_SPAWN_FP);
306 if (!fleet.isAlive()) {
307 remove.add(fleet);
308 } else if (fleet.getFleetPoints() <= spawnFP * getFleetAbortsMissionFPFraction()) {
309 remove.add(fleet);
311 } else {
312 totalFP += fleet.getFleetPoints();
313 }
314 }
315
316 fleets.removeAll(remove);
317
319 abort();
320 return;
321 }
322
323 }
324
325 protected void checkStragglers() {
326 List<CampaignFleetAPI> remove = new ArrayList<CampaignFleetAPI>();
328
329 for (CampaignFleetAPI fleet : fleets) {
330 fleetLocs.add(fleet.getContainingLocation());
331 }
332
333 LocationAPI withMostFleets = null;
334 int maxCount = 0;
335 for (LocationAPI loc : fleetLocs.keySet()) {
336 int count = fleetLocs.getCount(loc);
337 if (count > maxCount) {
338 withMostFleets = loc;
339 maxCount = count;
340 }
341 }
342
343 if (withMostFleets == null) return;
344
345 Vector2f com = new Vector2f();
346 float weight = 0f;
347 for (CampaignFleetAPI fleet : fleets) {
348 if (fleet.getContainingLocation() != withMostFleets) continue;
349 float w = fleet.getFleetPoints();
350 Vector2f loc = new Vector2f(fleet.getLocation());
351 loc.scale(w);
352 Vector2f.add(com, loc, com);
353 weight += w;
354 }
355
356 if (weight < 1f) weight = 1f;
357 com.scale(1f / weight);
358
359 FGAction action = getCurrentAction();
360 boolean canBeStragglers = action != null &&
361 (action instanceof FGTravelAction || action instanceof FGWaitAction);
362
363 int maybeStragglers = 0;
364 for (CampaignFleetAPI fleet : fleets) {
365 boolean potentialStraggler = fleet.getContainingLocation() != withMostFleets;
366 if (!potentialStraggler) {
367 potentialStraggler |= Misc.getDistance(fleet.getLocation(), com) > 4000;
368 }
369 if (fleet.getMemoryWithoutUpdate().getBoolean(NEVER_STRAGGLER) || !canBeStragglers) {
370 potentialStraggler = false;
371 }
372
373 MemoryAPI mem = fleet.getMemoryWithoutUpdate();
375 maybeStragglers++;
376 }
377 if (!potentialStraggler && mem.contains(KEY_POTENTIAL_STRAGGLER)) {
381 remove.add(fleet);
382// if (fleet.getName().toLowerCase().contains("tactistar")) {
383// System.out.println("fewfwef23r23r23r");
384// }
386 } else if (potentialStraggler && !mem.contains(KEY_POTENTIAL_STRAGGLER)) {
387 mem.set(KEY_POTENTIAL_STRAGGLER, true);
389 }
390 }
391
392 fleets.removeAll(remove);
393
394 //System.out.println(getClass().getSimpleName() + " maybe stragglers: " + maybeStragglers + ", fleets: " + fleets.size());
395 }
396
398 //if (true) return 0.5f;
399 return 30f;
400 }
401
402 protected boolean failedButNotDefeated = false;
403 public boolean isFailedButNotDefeated() {
405 }
406
408 this.failedButNotDefeated = failedButNotDefeated;
409 }
410
411 public void abort() {
412 finish(true);
413 }
414 public void finish(boolean isAbort) {
415 boolean wasEnding = isEnding();
416 aborted = isAbort;
418
419 if (!isAbort) {
421 }
422
423 if (spawnedFleets && !actions.isEmpty()) {
424 if (!actions.get(0).isActionFinished()) {
425 actions.get(0).setActionFinished(true);
426 }
427 }
428
429 if (route != null) {
430 route.expire();
432 }
433
435
436 if (!wasEnding && isAbort) {
438
439 if (listener != null) {
440 listener.reportFGIAborted(this);
441 }
442 }
443 }
444
445 public boolean isSpawning() {
446 return spawning != null && !spawning.isEmpty();
447 }
448
449 public boolean isAborted() {
450 return aborted;
451 }
452
453
455 for (CampaignFleetAPI fleet : fleets) {
457 }
458 }
459
462 if (returnLocation != null) {
464 } else {
466 }
467 }
468
469
470 protected void createRoute(String factionId, int approximateTotalDifficultyPoints,
471 int approximateNumberOfFleets, Object custom) {
472 createRoute(factionId, approximateTotalDifficultyPoints, approximateNumberOfFleets, custom, null);
473 }
474 protected void createRoute(String factionId, int approximateTotalDifficultyPoints,
475 int approximateNumberOfFleets, Object custom, GenericRaidParams params) {
476 OptionalFleetData extra = new OptionalFleetData();
477 extra.strength = getApproximateStrengthForTotalDifficultyPoints(factionId, approximateTotalDifficultyPoints);
478 extra.factionId = faction.getId(); // needed for WarSimScript etc
479 if (params != null && params.source != null) {
480 extra.quality = Misc.getShipQuality(params.source, extra.factionId);
481 }
482 route = RouteManager.getInstance().addRoute("FGI_" + getClass().getSimpleName(), null,
483 Misc.genRandomSeed(), extra, this, custom);
484
485 for (FGAction action : actions) {
486 int before = route.getSegments().size();
487 action.addRouteSegment(route);
488 int after = route.getSegments().size();
489 for (int i = before; i < after; i++) {
490 route.getSegments().get(i).custom = action;
491 }
492 }
493
494 this.approximateNumberOfFleets = approximateNumberOfFleets;
495 }
496
497 public void setRoute(RouteData route) {
498 this.route = route;
499 }
500
502 //System.out.println("RNG CHECK 2: " + random.nextLong());
503
505
506 if (isSpawnedFleets()) return null;
507
508 if (isEnded() || isEnding()) return null;
509 if (route == null || route.getCurrent() == null) {
510 abort();
511 return null;
512 }
513
514 RouteSegment curr = route.getCurrent();
515
516 while (!actions.isEmpty()) {
517 FGAction action = actions.get(0);
518 if (action == curr.custom) {
519 break;
520 }
521 actions.remove(0);
522 }
523
524 if (actions.isEmpty()) {
525 abort();
526 return(null);
527 }
528
530 System.out.println(getClass().getSimpleName() + ": about to spawn fleets");
531 }
532
533 spawnFleets();
534 setSpawnedFleets(true);
535
536 if (doIncrementalSpawn && route.getElapsed() < 0.1f) {
537 spawning.addAll(fleets);
538 fleets.clear();
539 for (CampaignFleetAPI fleet : spawning) {
540 if (spawnLocation == null) {
541 spawnLocation = fleet.getContainingLocation();
542 }
543 fleet.getContainingLocation().removeEntity(fleet);
544 }
546 } else {
547 for (CampaignFleetAPI fleet : fleets) {
548 int fp = fleet.getFleetPoints();
549 fleet.getMemoryWithoutUpdate().set(KEY_SPAWN_FP, fp);
550 totalFPSpawned += fp;
551 }
552 }
553
554
555 actions.get(0).notifyFleetsSpawnedMidSegment(curr);
556
557 // don't return any created fleets - route is removed anyway and we're managing the fleets directly
558 return null;
559 }
560
562 if (fleet == null) return;
564 }
565
566 public void handleIncrementalSpawning(float amount) {
567 if (spawning == null || spawning.isEmpty() || spawnLocation == null) return;
568 float days = Misc.getDays(amount);
569 spawnDelay -= days;
570
571 if (spawnDelay <= 0) {
572 spawnDelay = 0.25f + (float) Math.random() * 0.25f;
573
574 CampaignFleetAPI fleet = spawning.remove(0);
576 if (getSource() != null) {
578 }
579 fleets.add(fleet);
580 int fp = fleet.getFleetPoints();
581 totalFPSpawned += fp;
582
583 if (spawning.isEmpty()) {
584 spawning = null;
585 spawnLocation = null;
586 }
587 }
588 }
589
590
591 public boolean isDoIncrementalSpawn() {
592 return doIncrementalSpawn;
593 }
594
596 this.doIncrementalSpawn = doIncrementalSpawn;
597 }
598
599 public float getTotalFPSpawned() {
600 return totalFPSpawned;
601 }
602
603
605 this.totalFPSpawned = totalFPSpawned;
606 }
607
608 public void setSpawnedFleets(boolean spawnedFleets) {
609 this.spawnedFleets = spawnedFleets;
610 }
611
612 public RouteSegment getSegmentForAction(FGAction action) {
613 for (RouteSegment seg : getRoute().getSegments()) {
614 if (seg.custom == action) return seg;
615 }
616 return null;
617 }
618
619 public void removeAction(String id) {
620 FGAction action = getAction(id);
621 if (action != null) {
622 actions.remove(action);
623 }
624 }
625 public FGAction getAction(String id) {
626 for (FGAction curr : actions) {
627 if (curr.getId() != null && curr.getId().equals(id)) {
628 return curr;
629 }
630 }
631 return null;
632 }
633
634 public boolean isCurrent(String id) {
635 FGAction action = getAction(id);
636 return action != null && action == getCurrentAction();
637 }
638
640 if (actions.isEmpty()) return null;
641 return actions.get(0);
642 }
643
644 public boolean isSpawnedFleets() {
645 return spawnedFleets;
646 }
647
651
653 this.approximateNumberOfFleets = approximateNumberOfFleets;
654 }
655
656 public List<CampaignFleetAPI> getFleets() {
657 return fleets;
658 }
659
660 public static TravelState getTravelState(RouteSegment segment) {
661 if (segment.isInSystem()) {
662 return TravelState.IN_SYSTEM;
663 }
664
665 if (segment.hasLeaveSystemPhase() && segment.getLeaveProgress() < 1f) {
666 return TravelState.LEAVING_SYSTEM;
667 }
668 if (segment.hasEnterSystemPhase() && segment.getEnterProgress() > 0f) {
669 return TravelState.ENTERING_SYSTEM;
670 }
671
672 return TravelState.IN_HYPER_TRANSIT;
673 }
674
675 public static LocationAPI getLocation(RouteSegment segment) {
676 return getLocationForState(segment, getTravelState(segment));
677 }
678
679 public static LocationAPI getLocationForState(RouteSegment segment, TravelState state) {
680 switch (state) {
681 case ENTERING_SYSTEM: {
682 if (segment.to != null) {
683 return segment.to.getContainingLocation();
684 }
685 return segment.from.getContainingLocation();
686 }
687 case IN_HYPER_TRANSIT: return Global.getSector().getHyperspace();
688 case IN_SYSTEM: return segment.from.getContainingLocation();
689 case LEAVING_SYSTEM: return segment.from.getContainingLocation();
690 }
691 return null;
692 }
693
694
695 public static void setLocationAndCoordinates(CampaignFleetAPI fleet, RouteSegment current) {
696 TravelState state = getTravelState(current);
697 if (state == TravelState.LEAVING_SYSTEM) {
698 float p = current.getLeaveProgress();
700 if (jp == null) jp = current.from;
701 RouteLocationCalculator.setLocation(fleet, p, current.from, jp);
702 }
703 else if (state == TravelState.ENTERING_SYSTEM) {
704 float p = current.getEnterProgress();
706 if (jp == null) jp = current.to;
707 RouteLocationCalculator.setLocation(fleet, p, jp, current.to);
708 }
709 else if (state == TravelState.IN_SYSTEM) {
710 float p = current.getTransitProgress();
712 current.from, current.to);
713 }
714 else if (state == TravelState.IN_HYPER_TRANSIT) {
715 float p = current.getTransitProgress();
717 current.from.getLocationInHyperspace().x,
718 current.from.getLocationInHyperspace().y);
720 current.to.getLocationInHyperspace().x,
721 current.to.getLocationInHyperspace().y);
722 RouteLocationCalculator.setLocation(fleet, p, t1, t2);
723 }
724 }
725
726
727 public List<FGAction> getActions() {
728 return actions;
729 }
730
731 public void addAction(FGAction action, String id) {
732 action.setId(id);
733 addAction(action);
734 }
735 public void addAction(FGAction action) {
736 action.setIntel(this);
737 actions.add(action);
738 }
739
740
741 public boolean shouldCancelRouteAfterDelayCheck(RouteData route) {
742 return false;
743 }
744
745 public boolean shouldRepeat(RouteData route) {
746 return false;
747 }
748
750 // should never happen since this class removes the route and never returns the created fleets to the manager
751 }
752
756
758 this.returnLocation = returnLocation;
759 }
760
761
765
767 this.fleetAbortsMissionFPFraction = fleetAbortsMissionFPFraction;
768 }
769
773
775 this.groupAbortsMissionFPFraction = groupAbortsMissionFPFraction;
776 }
777
778 @Override
780 //return super.getFactionForUIColors();
781 return faction;
782 }
783
784 public void setFaction(String factionId) {
785 faction = Global.getSector().getFaction(factionId);
786
787 }
789 this.faction = faction;
790 }
791
793 return faction;
794 }
795
796 public RouteData getRoute() {
797 return route;
798 }
799
800 public static float getApproximateStrengthForTotalDifficultyPoints(String factionId, int points) {
801 float mult = 50f;
802 if (factionId != null) {
804 if (faction.getCustomBoolean("pirateBehavior")) {
805 mult = 35f;
806 }
807 }
808 return points * mult;
809 }
810
817 public static void computeSampleFleetStrengths() {
818 String factionId = null;
819 factionId = Factions.LUDDIC_CHURCH;
820 factionId = Factions.LUDDIC_PATH;
821 factionId = Factions.TRITACHYON;
822 factionId = Factions.DIKTAT;
823 factionId = Factions.REMNANTS;
824 factionId = Factions.PIRATES;
825 factionId = Factions.PERSEAN;
826 factionId = Factions.HEGEMONY;
827 factionId = Factions.INDEPENDENT;
828
829 System.out.println("---------------------------------");
830 System.out.println("FACTION: " + factionId);
831
832 System.out.println("Difficulty\tStd\tQuality\tQuantity");
833 for (int j = 0; j < 1; j++) {
834 for (int i = 1; i <= 10; i++) {
835
836 Vector2f loc = new Vector2f();
837
838 float strStandard = 0;
839 float strQuality = 0;
840 float strQuantity = 0;
841
842 {
843 FleetCreatorMission m = new FleetCreatorMission(new Random());
844 m.beginFleet();
845 m.createStandardFleet(i, factionId, loc);
846 CampaignFleetAPI fleet = m.createFleet();
847 if (fleet != null) {
848 strStandard = fleet.getEffectiveStrength();
849 }
850 }
851
852 {
853 FleetCreatorMission m = new FleetCreatorMission(new Random());
854 m.beginFleet();
855 m.createQualityFleet(i, factionId, loc);
856 CampaignFleetAPI fleet = m.createFleet();
857 if (fleet != null) {
858 strQuality = fleet.getEffectiveStrength();
859 }
860 }
861
862 {
863 FleetCreatorMission m = new FleetCreatorMission(new Random());
864 m.beginFleet();
865 m.createQuantityFleet(i, factionId, loc);
866 CampaignFleetAPI fleet = m.createFleet();
867 if (fleet != null) {
868 strQuantity = fleet.getEffectiveStrength();
869 }
870 }
871
872
873 System.out.println("" + i + "\t\t" + (int)strStandard + "\t" + (int)strQuality + "\t" + (int)strQuantity);
874 }
875 System.out.println("---------------------------------");
876 }
877 }
878
879 protected abstract boolean isPlayerTargeted();
880 protected abstract void spawnFleets();
881 protected abstract SectorEntityToken getSource();
882 protected abstract SectorEntityToken getDestination();
883 protected abstract String getBaseName();
884
885 protected abstract void addNonUpdateBulletPoints(TooltipMakerAPI info, Color tc, Object param,
886 ListInfoMode mode, float initPad);
887 protected abstract void addUpdateBulletPoints(TooltipMakerAPI info, Color tc, Object param,
888 ListInfoMode mode, float initPad);
889
890 protected void addStatusSection(TooltipMakerAPI info, float width, float height, float opad) {
891
892 }
893 protected void addAssessmentSection(TooltipMakerAPI info, float width, float height, float opad) {
894
895 }
896 protected void addBasicDescription(TooltipMakerAPI info, float width, float height, float opad) {
897
898 }
899
900 @Override
901 public Set<String> getIntelTags(SectorMapAPI map) {
902 Set<String> tags = super.getIntelTags(map);
903 tags.add(Tags.INTEL_MILITARY);
904
907 if (system != null &&
908 !Misc.getMarketsInLocation(system, Factions.PLAYER).isEmpty()) {
909 tags.add(Tags.INTEL_COLONIES);
910 }
911 }
912
913 if (getDestination() != null &&
914 getDestination().getContainingLocation() != null &&
915 !Misc.getMarketsInLocation(getDestination().getContainingLocation(), Factions.PLAYER).isEmpty()) {
916 tags.add(Tags.INTEL_COLONIES);
917 }
918 tags.add(getFaction().getId());
919 return tags;
920 }
921
922 public String getSortString() {
923 return "Fleet Group Movement";
924 }
925
926 public String getSuccessPostfix() {
927 return " - Successful";
928 }
929
930 public String getFailurePostfix() {
931 if (isInPreLaunchDelay()) {
932 return " - Aborted";
933 }
935 return " - Failed";
936 }
937 return " - Defeated";
938 }
939
940 public String getName() {
941 String base = getBaseName();
942 if (isSucceeded()) {
943 return base + getSuccessPostfix();
944 } else if (isFailed() || isAborted()) {
945 return base + getFailurePostfix();
946 }
947 //return base + " - Over";
948 return base;
949 }
950
951 public boolean isSucceeded() {
952 return false;
953 }
954 public boolean isFailed() {
955 return isAborted();
956 }
957
958 @Override
959 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) {
960 Color c = getTitleColor(mode);
961
962 info.setParaFontDefault();
963
964 info.addPara(getName(), c, 0f);
965 info.setParaFontDefault();
966 addBulletPoints(info, mode);
967 }
968
969 @Override
970 public String getIcon() {
971 return getFaction().getCrest();
972 }
973
974 public String getSmallDescriptionTitle() {
975 return getName();
976 }
977
978 @Override
979 public IntelSortTier getSortTier() {
980// if (isPlayerTargeted() && false) {
981// return IntelSortTier.TIER_2;
982// }
983 return super.getSortTier();
984 }
985
986 @Override
990
991 public List<ArrowData> getArrowData(SectorMapAPI map) {
992
995
996 if (src == null || dest == null || src.getContainingLocation() == dest.getContainingLocation()) {
997 return null;
998 }
999
1000 List<ArrowData> result = new ArrayList<ArrowData>();
1001
1002 ArrowData arrow = new ArrowData(src, dest);
1003 arrow.color = getFactionForUIColors().getBaseUIColor();
1004 arrow.width = 20f;
1005 result.add(arrow);
1006
1007 return result;
1008 }
1009
1010 public Random getRandom() {
1011 return random;
1012 }
1013
1014 public void setRandom(Random random) {
1015 this.random = random;
1016 }
1017
1018 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) {
1019 float pad = 3f;
1020 float opad = 10f;
1021
1022 float initPad = pad;
1023 if (mode == ListInfoMode.IN_DESC) initPad = opad;
1024
1025 Color tc = getBulletColorForMode(mode);
1026
1027
1028 bullet(info);
1029 Object param = getListInfoParam();
1030 boolean isUpdate = param != null;
1031
1032 if (!isUpdate) {
1033 addNonUpdateBulletPoints(info, tc, param, mode, initPad);
1034 } else {
1035 addUpdateBulletPoints(info, tc, param, mode, initPad);
1036 }
1037 unindent(info);
1038 }
1039
1040 protected void addFactionBulletPoint(TooltipMakerAPI info, Color tc, float initPad) {
1041 info.addPara("Faction: " + faction.getDisplayName(), initPad, tc,
1043 }
1044
1045 protected void addArrivedBulletPoint(String destName, Color destHL, TooltipMakerAPI info, Color tc, float initPad) {
1046 LabelAPI label = info.addPara("Arrived at " + destName, tc, initPad);
1047
1048 if (destHL != null) {
1049 String hl = getNameWithNoType(destName);
1050 label.setHighlightColor(destHL);
1051 label.highlightLast(hl);
1052 }
1053 }
1054
1055 public String getNameWithNoType(String systemName) {
1056 String hl = systemName;
1057 if (hl != null) {
1058 if (hl.endsWith(" system")) {
1059 hl = hl.replaceAll(" system", "");
1060 }
1061 if (hl.endsWith(" nebula")) {
1062 hl = hl.replaceAll(" nebula", "");
1063 }
1064 if (hl.endsWith(" star system")) {
1065 hl = hl.replaceAll(" star system", "");
1066 }
1067 }
1068 return hl;
1069 }
1070
1071 public static enum ETAType {
1072 ARRIVING,
1073 RETURNING,
1074 DEPARTURE,
1075 DEPLOYMENT,
1076 }
1077
1078 protected void addETABulletPoints(String destName, Color destHL, boolean withDepartedText, float eta,
1079 ETAType type, TooltipMakerAPI info, Color tc, float initPad) {
1080 Color h = Misc.getHighlightColor();
1081
1082 String hl = getNameWithNoType(destName);
1083
1084 if (type == ETAType.DEPLOYMENT) {
1085 if ((int) eta <= 0) {
1086 info.addPara("Fleet deployment imminent", tc, initPad);
1087 } else {
1088 String days = (int)eta == 1 ? "day" : "days";
1089 info.addPara("Estimated %s " + days + " until fleet deployment",
1090 initPad, tc, h, "" + (int) eta);
1091 }
1092 return;
1093 }
1094
1095 if (type == ETAType.DEPARTURE) {
1096 if ((int) eta <= 0) {
1097 info.addPara("Departure imminent", tc, initPad);
1098 } else {
1099 String days = (int)eta == 1 ? "day" : "days";
1100 info.addPara("Estimated %s " + days + " until departure",
1101 initPad, tc, h, "" + (int) eta);
1102 }
1103 return;
1104 }
1105
1106 LabelAPI label = null;
1107 if (withDepartedText && eta <= 0) {
1108 // operations in same location as the "from"
1109 label = info.addPara("Operating in the " + destName, tc, initPad);
1110
1111 if (destHL != null && label != null) {
1112 label.setHighlightColor(destHL);
1113 label.highlightLast(hl);
1114 }
1115 } else {
1116 if (withDepartedText) {
1117 String pre = "Departed for ";
1118 if (type == ETAType.RETURNING) {
1119 pre = "Returning to ";
1120 }
1121 label = info.addPara(pre + destName, tc, initPad);
1122
1123 if (destHL != null && label != null) {
1124 label.setHighlightColor(destHL);
1125 label.setHighlight(hl);
1126 }
1127 initPad = 0f;
1128 }
1129 if ((int) eta > 0) {
1130 String days = (int)eta == 1 ? "day" : "days";
1131 String post = " until arrival";
1132 if (type == ETAType.RETURNING) {
1133 post = " until return";
1134 }
1135 if (!withDepartedText) {
1136 if (type == ETAType.RETURNING) post += " to " + destName;
1137 else if (type == ETAType.ARRIVING) post += " at " + destName;
1138 }
1139 label = info.addPara("Estimated %s " + days + post, initPad, tc, h, "" + (int) eta);
1140
1141 if (!withDepartedText && destHL != null && label != null) {
1142 label.setHighlightColors(h, destHL);
1143 label.setHighlight("" + (int) eta, hl);
1144 }
1145 } else {
1146 String pre = "Arrival at ";
1147 if (type == ETAType.RETURNING) {
1148 pre = "Return to ";
1149 }
1150 label = info.addPara(pre + destName + " is imminent", tc, initPad);
1151
1152 if (destHL != null && label != null) {
1153 label.setHighlightColor(destHL);
1154 label.highlightLast(hl);
1155 }
1156 }
1157 }
1158 }
1159
1160
1161 @Override
1162 public void createSmallDescription(TooltipMakerAPI info, float width, float height) {
1163 Color h = Misc.getHighlightColor();
1164 Color g = Misc.getGrayColor();
1165 Color tc = Misc.getTextColor();
1166 float pad = 3f;
1167 float opad = 10f;
1168
1169 addBasicDescription(info, width, height, opad);
1170
1171 addAssessmentSection(info, width, height, opad);
1172
1173 addStatusSection(info, width, height, opad);
1174
1175 addBulletPoints(info, ListInfoMode.IN_DESC);
1176 }
1177
1178 protected void showMarketsInDanger(TooltipMakerAPI info, float opad, float width, StarSystemAPI system,
1179 List<MarketAPI> targets, String safeStr, String riskStr, String riskStrHighlight) {
1180
1181 Color h = Misc.getHighlightColor();
1182 float raidStr = getRoute().getExtra().getStrengthModifiedByDamage();
1183 float defenderStr = WarSimScript.getEnemyStrength(getFaction(), system, isPlayerTargeted());
1184
1185 List<MarketAPI> safe = new ArrayList<MarketAPI>();
1186 List<MarketAPI> unsafe = new ArrayList<MarketAPI>();
1187 for (MarketAPI market : targets) {
1188 float defensiveStr = defenderStr + WarSimScript.getStationStrength(market.getFaction(), system, market.getPrimaryEntity());
1189 if (defensiveStr > raidStr * 1.25f) {
1190 safe.add(market);
1191 } else {
1192 unsafe.add(market);
1193 }
1194 }
1195
1196 if (safe.size() == targets.size()) {
1197 info.addPara("However, all colonies " + safeStr + ", " +
1198 "owing to their orbital defenses.", opad);
1199 } else {
1200 info.addPara("The following colonies " + riskStr, opad,
1201 Misc.getNegativeHighlightColor(), riskStrHighlight);
1202
1204 addMarketTable(info, f.getBaseUIColor(), f.getDarkUIColor(), f.getBrightUIColor(), unsafe, width, opad);
1205 }
1206 }
1207
1216 float raidStr = getRoute().getExtra().getStrengthModifiedByDamage();
1217 float defenderStr = 0f;
1218 if (target != null) defenderStr = WarSimScript.getEnemyStrength(getFaction(), target, isPlayerTargeted());
1219
1220 if (raidStr < defenderStr * 0.75f) {
1221 return -1;
1222 } else if (raidStr < defenderStr * 1.25f) {
1223 return 0;
1224 } else {
1225 return 1;
1226 }
1227 }
1228
1233 protected boolean addStrengthDesc(TooltipMakerAPI info, float opad, StarSystemAPI system,
1234 String forces, String outcomeFailure, String outcomeUncertain, String outcomeSuccess) {
1235 Color h = Misc.getHighlightColor();
1236
1237 float raidStr = getRoute().getExtra().getStrengthModifiedByDamage();
1238 float defenderStr = 0f;
1239 if (system != null) defenderStr = WarSimScript.getEnemyStrength(getFaction(), system, isPlayerTargeted());
1240
1241 String strDesc = Misc.getStrengthDesc(raidStr);
1242 int numFleets = (int) getApproximateNumberOfFleets();
1243 String fleets = "fleets";
1244 if (numFleets == 1) fleets = "fleet";
1245
1246 String defenderDesc = "";
1247 String defenderHighlight = "";
1248 Color defenderHighlightColor = h;
1249
1250 boolean potentialDanger = false;
1251 String outcome = null;
1252 if (raidStr < defenderStr * 0.75f) {
1253 defenderDesc = "The defending fleets are superior";
1254 defenderHighlightColor = Misc.getPositiveHighlightColor();
1255 defenderHighlight = "superior";
1256 outcome = outcomeFailure;
1257 } else if (raidStr < defenderStr * 1.25f) {
1258 defenderDesc = "The defending fleets are evenly matched";
1259 defenderHighlightColor = h;
1260 defenderHighlight = "evenly matched";
1261 outcome = outcomeUncertain;
1262 potentialDanger = true;
1263 } else {
1264 defenderDesc = "The defending fleets are outmatched";
1265 defenderHighlightColor = Misc.getNegativeHighlightColor();
1266 defenderHighlight = "outmatched";
1267 outcome = outcomeSuccess;
1268 potentialDanger = true;
1269 }
1270
1271 if (outcome != null) {
1272 defenderDesc += ", and " + outcome + ".";
1273 } else {
1274 defenderDesc += ".";
1275 }
1276
1277 defenderDesc = " " + defenderDesc;
1278
1279 if (system == null) defenderDesc = "";
1280
1281
1282 LabelAPI label = info.addPara("The " + forces + " are " +
1283 "projected to be %s and likely comprised of %s " + fleets + "." + defenderDesc,
1284 opad, h, strDesc, "" + numFleets);
1285 label.setHighlight(strDesc, "" + numFleets, defenderHighlight);
1286 label.setHighlightColors(h, h, defenderHighlightColor);
1287
1288 return potentialDanger;
1289 }
1290
1291
1296 protected boolean addStrengthDesc(TooltipMakerAPI info, float opad, MarketAPI target,
1297 String forces, String outcomeFailure, String outcomeUncertain, String outcomeSuccess) {
1298 Color h = Misc.getHighlightColor();
1299
1300 float raidStr = getRoute().getExtra().getStrengthModifiedByDamage();
1301 float defenderStr = 0f;
1302 StarSystemAPI system = target.getStarSystem();
1303 if (system != null) defenderStr = WarSimScript.getEnemyStrength(getFaction(), system, isPlayerTargeted());
1304
1305 defenderStr += WarSimScript.getStationStrength(target.getFaction(), system, target.getPrimaryEntity());
1306
1307 String strDesc = Misc.getStrengthDesc(raidStr);
1308 int numFleets = (int) getApproximateNumberOfFleets();
1309 String fleets = "fleets";
1310 if (numFleets == 1) fleets = "fleet";
1311
1312 String defenderDesc = "";
1313 String defenderHighlight = "";
1314 Color defenderHighlightColor = h;
1315
1316 boolean potentialDanger = false;
1317 String outcome = null;
1318 if (raidStr < defenderStr * 0.75f) {
1319 defenderDesc = "The defending forces are superior";
1320 defenderHighlightColor = Misc.getPositiveHighlightColor();
1321 defenderHighlight = "superior";
1322 outcome = outcomeFailure;
1323 } else if (raidStr < defenderStr * 1.25f) {
1324 defenderDesc = "The defending forces are evenly matched";
1325 defenderHighlightColor = h;
1326 defenderHighlight = "evenly matched";
1327 outcome = outcomeUncertain;
1328 potentialDanger = true;
1329 } else {
1330 defenderDesc = "The defending forces are outmatched";
1331 defenderHighlightColor = Misc.getNegativeHighlightColor();
1332 defenderHighlight = "outmatched";
1333 outcome = outcomeSuccess;
1334 potentialDanger = true;
1335 }
1336
1337 if (outcome != null) {
1338 defenderDesc += ", and " + outcome + ".";
1339 } else {
1340 defenderDesc += ".";
1341 }
1342
1343 defenderDesc = " " + defenderDesc;
1344
1345 if (system == null) defenderDesc = "";
1346
1347
1348 LabelAPI label = info.addPara("The " + forces + " are " +
1349 "projected to be %s and likely comprised of %s " + fleets + "." + defenderDesc,
1350 opad, h, strDesc, "" + numFleets);
1351 label.setHighlight(strDesc, "" + numFleets, defenderHighlight);
1352 label.setHighlightColors(h, h, defenderHighlightColor);
1353
1354 return potentialDanger;
1355 }
1356
1357
1358
1359 public FGIEventListener getListener() {
1360 return listener;
1361 }
1362
1363 public void setListener(FGIEventListener listener) {
1364 this.listener = listener;
1365 }
1366
1367 @Override
1368 public String getCommMessageSound() {
1369 if (isSendingUpdate()) {
1370 return getSoundStandardUpdate();
1371 }
1372 return getSoundMajorPosting();
1373 }
1374
1375
1376}
1377
1378
1379
1380
static SectorAPI getSector()
Definition Global.java:65
static float getStationStrength(FactionAPI faction, StarSystemAPI system, SectorEntityToken from)
static float getEnemyStrength(String factionId, StarSystemAPI system)
static int setLocation(CampaignFleetAPI fleet, float daysElapsed, float maxDays, int overflowIndex, boolean onlyAdjustIntervals, float[] intervals, SectorEntityToken ... sequence)
static JumpPointAPI findJumpPointToUse(CampaignFleetAPI fleet, SectorEntityToken from)
RouteData addRoute(String source, MarketAPI market, Long seed, OptionalFleetData extra, RouteFleetSpawner spawner)
static final String MEMORY_KEY_FLEET_DO_NOT_GET_SIDETRACKED
static void addMarketTable(TooltipMakerAPI info, Color base, Color dark, Color bright, List< MarketAPI > markets, float width, float pad)
void sendUpdateIfPlayerHasIntel(Object listInfoParam, TextPanelAPI textPanel)
float getETAUntil(String actionId, boolean untilEndOfAction)
void addArrivedBulletPoint(String destName, Color destHL, TooltipMakerAPI info, Color tc, float initPad)
void createRoute(String factionId, int approximateTotalDifficultyPoints, int approximateNumberOfFleets, Object custom)
void setFleetAbortsMissionFPFraction(float fleetAbortsMissionFPFraction)
void addETABulletPoints(String destName, Color destHL, boolean withDepartedText, float eta, ETAType type, TooltipMakerAPI info, Color tc, float initPad)
void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode)
void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode)
void createRoute(String factionId, int approximateTotalDifficultyPoints, int approximateNumberOfFleets, Object custom, GenericRaidParams params)
abstract void addUpdateBulletPoints(TooltipMakerAPI info, Color tc, Object param, ListInfoMode mode, float initPad)
void showMarketsInDanger(TooltipMakerAPI info, float opad, float width, StarSystemAPI system, List< MarketAPI > targets, String safeStr, String riskStr, String riskStrHighlight)
static LocationAPI getLocationForState(RouteSegment segment, TravelState state)
boolean addStrengthDesc(TooltipMakerAPI info, float opad, StarSystemAPI system, String forces, String outcomeFailure, String outcomeUncertain, String outcomeSuccess)
void setGroupAbortsMissionFPFraction(float groupAbortsMissionFPFraction)
void addFactionBulletPoint(TooltipMakerAPI info, Color tc, float initPad)
static void setLocationAndCoordinates(CampaignFleetAPI fleet, RouteSegment current)
abstract void addNonUpdateBulletPoints(TooltipMakerAPI info, Color tc, Object param, ListInfoMode mode, float initPad)
void addAssessmentSection(TooltipMakerAPI info, float width, float height, float opad)
void addStatusSection(TooltipMakerAPI info, float width, float height, float opad)
void createSmallDescription(TooltipMakerAPI info, float width, float height)
static float getApproximateStrengthForTotalDifficultyPoints(String factionId, int points)
void addBasicDescription(TooltipMakerAPI info, float width, float height, float opad)
boolean addStrengthDesc(TooltipMakerAPI info, float opad, MarketAPI target, String forces, String outcomeFailure, String outcomeUncertain, String outcomeSuccess)
void createQualityFleet(int difficulty, String factionId, Vector2f locInHyper)
void createStandardFleet(int difficulty, String factionId, Vector2f locInHyper)
void createQuantityFleet(int difficulty, String factionId, Vector2f locInHyper)
void add(K key, int quantity)
static Color getTextColor()
Definition Misc.java:839
static List< MarketAPI > getMarketsInLocation(LocationAPI location, String factionId)
Definition Misc.java:936
static Color getNegativeHighlightColor()
Definition Misc.java:802
static void giveStandardReturnToSourceAssignments(CampaignFleetAPI fleet)
Definition Misc.java:3836
static Color getGrayColor()
Definition Misc.java:826
static String getStrengthDesc(float strAdjustedFP)
Definition Misc.java:5027
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static float getDays(float amount)
Definition Misc.java:4663
static boolean isHyperspaceAnchor(SectorEntityToken entity)
Definition Misc.java:4675
static Color getHighlightColor()
Definition Misc.java:792
static float getShipQuality(MarketAPI market)
Definition Misc.java:4505
static void giveStandardReturnAssignments(CampaignFleetAPI fleet, SectorEntityToken where, String text, boolean withClear)
Definition Misc.java:3869
static StarSystemAPI getStarSystemForAnchor(SectorEntityToken anchor)
Definition Misc.java:4679
static Color getPositiveHighlightColor()
Definition Misc.java:822
void addEntity(SectorEntityToken entity)
SectorEntityToken createToken(float x, float y)
void addScript(EveryFrameScript script)
void removeScript(EveryFrameScript script)
FactionAPI getFaction(String factionId)
void set(String key, Object value)
void setHighlight(int start, int end)
void setHighlightColor(Color color)
void highlightLast(String substring)
void setHighlightColors(Color ... colors)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)