Starsector API
Loading...
Searching...
No Matches
FleetInteractionDialogPluginImpl.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.List;
6import java.util.Map;
7import java.util.Random;
8
9import java.awt.Color;
10
11import org.lwjgl.input.Keyboard;
12
13import com.fs.starfarer.api.Global;
14import com.fs.starfarer.api.campaign.BattleAPI;
15import com.fs.starfarer.api.campaign.BattleAPI.BattleSide;
16import com.fs.starfarer.api.campaign.CampaignFleetAPI;
17import com.fs.starfarer.api.campaign.CargoAPI;
18import com.fs.starfarer.api.campaign.CoreInteractionListener;
19import com.fs.starfarer.api.campaign.EngagementResultForFleetAPI;
20import com.fs.starfarer.api.campaign.FactionAPI;
21import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.DataForEncounterSide;
22import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.DisengageHarryAvailability;
23import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.EngagementOutcome;
24import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.PursueAvailability;
25import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.Status;
26import com.fs.starfarer.api.campaign.FleetMemberPickerListener;
27import com.fs.starfarer.api.campaign.InteractionDialogAPI;
28import com.fs.starfarer.api.campaign.InteractionDialogPlugin;
29import com.fs.starfarer.api.campaign.OptionPanelAPI;
30import com.fs.starfarer.api.campaign.RuleBasedDialog;
31import com.fs.starfarer.api.campaign.SectorEntityToken;
32import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel;
33import com.fs.starfarer.api.campaign.TextPanelAPI;
34import com.fs.starfarer.api.campaign.VisualPanelAPI;
35import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI;
36import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.EncounterOption;
37import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.InitialBoardingResponse;
38import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.PursuitOption;
39import com.fs.starfarer.api.campaign.events.CampaignEventPlugin;
40import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
41import com.fs.starfarer.api.campaign.rules.MemKeys;
42import com.fs.starfarer.api.campaign.rules.MemoryAPI;
43import com.fs.starfarer.api.campaign.rules.RuleAPI;
44import com.fs.starfarer.api.campaign.rules.RulesAPI;
45import com.fs.starfarer.api.characters.PersonAPI;
46import com.fs.starfarer.api.combat.BattleCreationContext;
47import com.fs.starfarer.api.combat.CombatReadinessPlugin;
48import com.fs.starfarer.api.combat.EngagementResultAPI;
49import com.fs.starfarer.api.fleet.CrewCompositionAPI;
50import com.fs.starfarer.api.fleet.FleetGoal;
51import com.fs.starfarer.api.fleet.FleetMemberAPI;
52import com.fs.starfarer.api.impl.campaign.FleetEncounterContext.BoardingResult;
53import com.fs.starfarer.api.impl.campaign.FleetEncounterContext.EngageBoardableOutcome;
54import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
55import com.fs.starfarer.api.impl.campaign.ids.Sounds;
56import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
57import com.fs.starfarer.api.impl.campaign.rulecmd.DumpMemory;
58import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
59import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption;
60import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.BaseOptionStoryPointActionDelegate;
61import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.StoryOptionParams;
62import com.fs.starfarer.api.impl.campaign.skills.BaseSkillEffectDescription;
63import com.fs.starfarer.api.impl.combat.CRPluginImpl;
64import com.fs.starfarer.api.ui.LabelAPI;
65import com.fs.starfarer.api.ui.TooltipMakerAPI;
66import com.fs.starfarer.api.util.Misc;
67import com.fs.starfarer.api.util.Pair;
68
70
71 public static float EMERGENCY_REPAIRS_MAX_DP = Global.getSettings().getFloat("emergencyRepairsMaxDPValue");
72
73 public static String DO_NOT_AUTO_SHOW_FC_PORTRAIT = "$doNotAutoShowFleetCommanderPortrait";
74
75 public static interface FIDConfigGen {
76 FIDConfig createConfig();
77 }
78
79 public static class FIDConfig {
80 public boolean showCommLinkOption = true;
81 public boolean leaveAlwaysAvailable = false;
82 public boolean showWarningDialogWhenNotHostile = true;
83 public boolean showTransponderStatus = true;
84 public boolean showFleetAttitude = true;
85 public boolean showEngageText = true;
86 public boolean alwaysAttackVsAttack = false;
87 public boolean alwaysPursue = false;
88 public boolean alwaysHarry = false;
89 public boolean alwaysLetGo = false;
90 public boolean dismissOnLeave = true;
91 public boolean withSalvage = true;
92 public boolean lootCredits = true;
93
94 public boolean showCrRecoveryText = true;
95
96 public boolean showVictoryText = true;
97
98 //public boolean postLootLeaveHasShortcut = true;
99
100 public boolean impactsEnemyReputation = true;
101 public boolean impactsAllyReputation = true;
102
103 public boolean pullInAllies = true;
104 public boolean pullInEnemies = true;
105 public boolean pullInStations = true;
106
107 //public String postLootLeaveOptionText = null;
108 public String noSalvageLeaveOptionText = null;
109 public String firstTimeEngageOptionText = null;
110 public String afterFirstTimeEngageOptionText = null;
111
112 public FIDDelegate delegate = null;
113 public boolean printXPToDialog = false;
114
115 public boolean justShowFleets = false;
116 public boolean showPullInText = true;
117
118 public boolean straightToEngage = false;
119 public boolean playerAttackingStation = false;
120 public boolean playerDefendingStation = false;
121
122
123// /**
124// * Note: this means that retreating won't work, either - the player will be forced to re-engage every time until
125// * one fleet is entirely destroyed.
126// * Also this gets broken completely by e.g. Phase Anchor
127// */
128// public boolean noLeaveOption = false;
129
130 public boolean noLeaveOptionOnFirstEngagement = false;
131
132
133 public Random salvageRandom = null;
134 }
135
136 public static interface FIDDelegate {
137 public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage);
138 public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc);
139 public void notifyLeave(InteractionDialogAPI dialog);
140 }
141
142 public static class BaseFIDDelegate implements FIDDelegate {
143 public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) {}
144 public void notifyLeave(InteractionDialogAPI dialog) {}
145 public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) {}
146 }
147
148
149
150
151 protected static enum VisualType {
152 FLEET_INFO,
153 OTHER,
154 }
155
156
157 public static enum OptionId {
158 INIT,
159 PRINT_ONGOING_BATTLE_INFO,
160 BEGIN_FLEET_ENCOUNTER_2,
161 OPEN_COMM,
162 CUT_COMM,
163 ENGAGE,
164 FORCE_ENGAGE,
165 ATTEMPT_TO_DISENGAGE,
166 DISENGAGE,
167 CLEAN_DISENGAGE,
168 SCUTTLE,
169 PURSUE,
170 AUTORESOLVE_PURSUE,
171 HARRY_PURSUE,
172 LET_THEM_GO,
173 LEAVE,
174 LOOT_THEN_LEAVE,
175 CONTINUE_LEAVE,
176 CONTINUE,
177 GO_TO_MAIN,
178 GO_TO_PRE_BATTLE,
179 RECOVERY_SELECT,
180 RECOVERY_CONTINUE,
181 CONTINUE_FROM_VICTORY_TRIGGERS,
182 CONTINUE_LOOT,
183 CONTINUE_INTO_BATTLE,
184
185 CONTINUE_INTO_BOARDING,
186 BOARDING_ACTION,
187 SELECT_FLAGSHIP,
188 CRASH_MOTHBALL,
189 ENGAGE_BOARDABLE,
190 ABORT_BOARDING_ACTION,
191 HARD_DOCK,
192 LAUNCH_ASSAULT_TEAMS,
193 LET_IT_GO,
194
195 SELECTOR_MARINES,
196 SELECTOR_CREW,
197
198 REINIT_CONTINUE,
199
200 INITIATE_BATTLE,
201 JOIN_ONGOING_BATTLE,
202 CONTINUE_ONGOING_BATTLE,
203
204 EMERGENCY_REPAIRS,
205
206 DEV_MODE_ESCAPE,
207 }
208
209
214
217
220
221 protected VisualType currVisualType = VisualType.FLEET_INFO;
222
224
225 protected static final Color HIGHLIGHT_COLOR = Global.getSettings().getColor("buttonShortcut");
226 protected static final Color FRIEND_COLOR = Global.getSettings().getColor("textFriendColor");
227 protected static final Color ENEMY_COLOR = Misc.getNegativeHighlightColor();
228
230 protected boolean ongoingBattle = false;
231 protected boolean firstEngagement = true;
232 protected boolean joinedBattle = false;
233
234 protected boolean forceEngage = false;
235
236 protected boolean shownTooLargeToRetreatMessage = false;
237
238 public static boolean inConversation = false;
239 public static boolean directToComms = false;
240
241 protected FIDConfig config;
242
243// public static class FleetMemberPreEncounterData {
244// public int indexInFleet;
245// public PersonAPI officer;
246// }
247 protected List<FleetMemberAPI> membersInOrderPreEncounter = new ArrayList<FleetMemberAPI>();
248
250 this(null);
251 }
252 public FleetInteractionDialogPluginImpl(FIDConfig params) {
253 this.config = params;
254
255 if (origFlagship == null) {
257 }
258 if (origCaptains.isEmpty()) {
260 origCaptains.put(member, member.getCaptain());
261 }
263 }
264 }
265
266 public Map<String, MemoryAPI> getMemoryMap() {
268 }
269
270 private boolean skipAttitudeOnInit = false;
271 public void reinit(boolean withContinueOnRuleFound) {
272 RulesAPI rules = Global.getSector().getRules();
273 RuleAPI rule = rules.getBestMatching(null, "BeginFleetEncounter", dialog, conversationDelegate.getMemoryMap());
274 if (rule == null || !withContinueOnRuleFound) {
276 } else {
278 options.addOption("Continue", OptionId.REINIT_CONTINUE, null);
279 if (Global.getSettings().isDevMode()) {
281 }
282 }
283 }
284
285 public void reinitPostContinue() {
286 //init(dialog);
287 inConversation = false;
288 directToComms = false;
289
290 boolean cont = conversationDelegate.getMemoryMap().get(MemKeys.LOCAL).getBoolean("$fidpi_addContinue");
291 conversationDelegate.getMemoryMap().get(MemKeys.LOCAL).unset("$fidpi_addContinue");
292
293 if (cont) {
294 conversationDelegate.fireBest("BeginFleetEncounter2");
295 } else {
296 conversationDelegate.fireBest("BeginFleetEncounter");
297 }
298 if (conversationDelegate.getMemoryMap().get(MemKeys.LOCAL).getBoolean("$fidpi_addContinue")) {
300 options.addOption("Continue", OptionId.BEGIN_FLEET_ENCOUNTER_2);
301 } else {
302 if (directToComms) {
303 optionSelected(null, OptionId.OPEN_COMM);
304 } else {
305 //skipAttitudeOnInit = true;
306 optionSelected(null, OptionId.INIT);
307 }
308 }
309 }
310
312 this.dialog = dialog;
313
314 if (this.config == null) {
316// if (memory.contains(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE)) {
317// this.config = (FIDConfig) memory.get(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE);
318// } else
320 this.config = ((FIDConfigGen) memory.get(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN)).createConfig();
321 } else {
322 this.config = new FIDConfig();
323 }
324 }
325
326
327
328// boolean sampling = true;
329// while (sampling) {
330 if (Global.getSettings().isDevMode()) {
331 dialog.setOptionOnEscape("dev mode exit", OptionId.DEV_MODE_ESCAPE);
332 dialog.setOptionOnConfirm("dev mode exit", OptionId.DEV_MODE_ESCAPE);
333 }
334
338
340 if (playerFleet != null) {
342 }
344
345// playerFleet.getFleetData().takeSnapshot();
346// otherFleet.getFleetData().takeSnapshot();
347
348 if (context.getBattle() == null) {
349 if (otherFleet.getBattle() == null || otherFleet.getBattle().isDone()) {
350 ongoingBattle = false;
352 context.setBattle(battle);
354 } else {
355 ongoingBattle = true;
358 //context.getBattle().join(playerFleet);
360 }
361 }
362 }
363
365 fleet.inflateIfNeeded();
366 }
368
369 visual.setVisualFade(0.25f, 0.25f);
370 if (!config.straightToEngage) {
371 if (ongoingBattle && !joinedBattle) {
373 String titleOne = b.getPrimary(b.getSideOne()).getNameWithFactionKeepCase();
374 if (b.getSideOne().size() > 1) titleOne += ", with allies";
375 String titleTwo = b.getPrimary(b.getSideTwo()).getNameWithFactionKeepCase();
376 if (b.getSideTwo().size() > 1) titleTwo += ", with allies";
378 } else {
379 //visual.showFleetInfo((String)null, playerFleet, (String)null, otherFleet, context);
381 }
382 }
383
384 inConversation = false;
385 directToComms = false;
389
390// }
391
392 if (!config.justShowFleets) {
393 // if (ongoingBattle) {
394 conversationDelegate.getMemoryMap().get(MemKeys.LOCAL).set("$ongoingBattle", ongoingBattle, 0);
395 boolean cont = conversationDelegate.getMemoryMap().get(MemKeys.LOCAL).getBoolean("$fidpi_addContinue");
396 conversationDelegate.getMemoryMap().get(MemKeys.LOCAL).unset("$fidpi_addContinue");
397 if (!ongoingBattle && !config.straightToEngage) {
398 if (cont) {
399 conversationDelegate.fireBest("BeginFleetEncounter2");
400 } else {
401 conversationDelegate.fireBest("BeginFleetEncounter");
402 }
403 }
404 // } else {
405 // conversationDelegate.fireBest("OngoingBattleEncounter");
406 // }
407
408 if (conversationDelegate.getMemoryMap().get(MemKeys.LOCAL).getBoolean("$fidpi_addContinue")) {
410 options.addOption("Continue", OptionId.BEGIN_FLEET_ENCOUNTER_2);
411 } else {
412 if (directToComms) {
413 optionSelected(null, OptionId.OPEN_COMM);
414 } else {
415 optionSelected(null, OptionId.INIT);
416 }
417 }
418
419 if (config.straightToEngage) {
420 if (ongoingBattle) {
421 optionSelected(null, OptionId.JOIN_ONGOING_BATTLE);
422 } else {
423 optionSelected(null, OptionId.ENGAGE);
424 }
425 }
426 } else {
427// if (config.showPullInText) {
428// optionSelected(null, OptionId.PRINT_ONGOING_BATTLE_INFO);
429// }
430 }
431 }
432
434 optionSelected(null, OptionId.PRINT_ONGOING_BATTLE_INFO);
435 }
436
437
438 protected List<CampaignFleetAPI> pulledIn = new ArrayList<CampaignFleetAPI>();
439 protected void pullInNearbyFleets() {
441 if (!ongoingBattle) {
443 }
444
445 BattleSide playerSide = b.pickSide(Global.getSector().getPlayerFleet());
446
447 boolean hostile = otherFleet.getAI() != null && otherFleet.getAI().isHostileTo(playerFleet);
448 if (ongoingBattle) hostile = true;
449
450 //canDecline = otherFleet.getAI() != null && other
451
452// boolean someJoined = false;
455
456 //textPanel.addParagraph("Projecting nearby fleet movements:");
457 //textPanel.addParagraph("You encounter a ");
458 pulledIn.clear();
459
460 if (config.pullInStations && !b.isStationInvolved()) {
461 SectorEntityToken closestEntity = null;
462 CampaignFleetAPI closest = null;
464 if (p != null) {
465 closestEntity = p.one;
466 closest = p.two;
467 }
468
469 if (closest != null) {
470 BattleSide joiningSide = b.pickSide(closest, true);
471 boolean canJoin = joiningSide != BattleSide.NO_JOIN;
472 if (!config.pullInAllies && joiningSide == playerSide) {
473 canJoin = false;
474 }
475 if (!config.pullInEnemies && joiningSide != playerSide) {
476 canJoin = false;
477 }
478 if (b == closest.getBattle()) {
479 canJoin = false;
480 }
481 if (closest.getBattle() != null) {
482 canJoin = false;
483 }
484
485 if (canJoin) {
486 if (closestEntity != null) {
487 closestEntity.getMarket().reapplyIndustries(); // need to pick up station CR value, in some cases
488 }
489 b.join(closest);
490 pulledIn.add(closest);
491
492 if (!config.straightToEngage && config.showPullInText) {
493 if (b.getSide(playerSide) == b.getSideFor(closest)) {
495 Misc.ucFirst(closest.getNameWithFactionKeepCase()) + ": supporting your forces.");//, FRIEND_COLOR);
496 } else {
497 if (hostile) {
498 textPanel.addParagraph(Misc.ucFirst(closest.getNameWithFactionKeepCase()) + ": supporting the enemy.");//, ENEMY_COLOR);
499 } else {
500 textPanel.addParagraph(Misc.ucFirst(closest.getNameWithFactionKeepCase()) + ": supporting the opposing side.");
501 }
502 }
504 }
505 }
506 }
507 }
508
509
510 for (CampaignFleetAPI fleet : actualPlayer.getContainingLocation().getFleets()) {
511 if (b == fleet.getBattle()) continue;
512 if (fleet.getBattle() != null) continue;
513
514 if (fleet.isStationMode()) continue;
515
516 float dist = Misc.getDistance(actualOther.getLocation(), fleet.getLocation());
517 dist -= actualOther.getRadius();
518 dist -= fleet.getRadius();
519// if (dist < Misc.getBattleJoinRange()) {
520// System.out.println("Checking: " + fleet.getNameWithFaction());
521// }
522
523 if (fleet.getFleetData().getNumMembers() <= 0) continue;
524
525 float baseSensorRange = playerFleet.getBaseSensorRangeToDetect(fleet.getSensorProfile());
526 boolean visible = fleet.isVisibleToPlayerFleet();
527 VisibilityLevel level = fleet.getVisibilityLevelToPlayerFleet();
528// if (dist < Misc.getBattleJoinRange() &&
529// (dist < baseSensorRange || (visible && level != VisibilityLevel.SENSOR_CONTACT))) {
530// System.out.println("2380dfwef");
531// }
532 float joinRange = Misc.getBattleJoinRange();
533 if (fleet.getFaction().isPlayerFaction() && !fleet.isStationMode()) {
534 joinRange += Global.getSettings().getFloat("battleJoinRangePlayerFactionBonus");
535 }
536 if (dist < joinRange &&
537 (dist < baseSensorRange || (visible && level != VisibilityLevel.SENSOR_CONTACT)) &&
538 ((fleet.getAI() != null && fleet.getAI().wantsToJoin(b, true)) || fleet.isStationMode())) {
539
540 boolean ignore = fleet.getMemoryWithoutUpdate() != null &&
541 fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.FLEET_IGNORES_OTHER_FLEETS);
542 if (ignore) continue;
543
544 BattleSide joiningSide = b.pickSide(fleet, true);
545 if (!config.pullInAllies && joiningSide == playerSide) continue;
546 if (!config.pullInEnemies && joiningSide != playerSide) continue;
547
548 b.join(fleet);
549 pulledIn.add(fleet);
550 //if (b.isPlayerSide(b.getSideFor(fleet))) {
551 if (!config.straightToEngage && config.showPullInText) {
552 if (b.getSide(playerSide) == b.getSideFor(fleet)) {
553 textPanel.addParagraph(Misc.ucFirst(fleet.getNameWithFactionKeepCase()) + ": supporting your forces.");//, FRIEND_COLOR);
554 } else {
555 if (hostile) {
556 textPanel.addParagraph(Misc.ucFirst(fleet.getNameWithFactionKeepCase()) + ": joining the enemy.");//, ENEMY_COLOR);
557 } else {
558 textPanel.addParagraph(Misc.ucFirst(fleet.getNameWithFactionKeepCase()) + ": supporting the opposing side.");
559 }
560 }
561 textPanel.highlightFirstInLastPara(fleet.getNameWithFactionKeepCase() + ":", fleet.getFaction().getBaseUIColor());
562 }
563// someJoined = true;
564 }
565 }
566
568 for (CampaignFleetAPI curr : pulledIn) {
569 curr.inflateIfNeeded();
570 }
571
572// if (!someJoined) {
573// addText("No nearby fleets will join the battle.");
574// }
575 if (!ongoingBattle) {
576 b.genCombined();
577 b.takeSnapshots();
580 if (!config.straightToEngage) {
582 }
583 }
584
585 }
586
587
590
591 // failsafe
592 if (playerGoal == null && otherGoal == null) {
593 EngagementResultForFleetAPI player = result.didPlayerWin() ? result.getWinnerResult() : result.getLoserResult();
594 EngagementResultForFleetAPI other = result.didPlayerWin() ? result.getLoserResult() : result.getWinnerResult();
595 if (player.getDeployed().isEmpty()) {
598 } else {
601 }
602 player.setGoal(playerGoal);
603 other.setGoal(otherGoal);
604 }
605
606 if (!ongoingBattle) {
609 }
610 }
611
612 result.setBattle(context.getBattle());
613
615 lastResult = result;
616
617 boolean startedWithAllies = false;
618 if (context.getBattle() != null) {
619 startedWithAllies = context.getBattle().getPlayerSideSnapshot().size() > 1;
620 }
622 startedWithAllies && context.getBattle().getPlayerSide().size() > 1) {
625 addText(getString("battleFleetLost"));
626 addText(getString("finalOutcomeNoShipsLeft"));
628 options.addOption("Leave", OptionId.LEAVE, null);
629 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
630 return;
631 }
632
634 if (origFlagship != null) {
635 if (selectedFlagship != null) {
637 if (captain != null && !captain.isPlayer()) {
639 }
640 }
642// origFlagship = null;
643// selectedFlagship = null;
644
645 }
646
647 if (context.getLastEngagementOutcome() == null) {
648 return; // failsafe
649 }
650
651 boolean totalDefeat = !playerFleet.isValidPlayerFleet();
652 boolean mutualDestruction = context.getLastEngagementOutcome() == EngagementOutcome.MUTUAL_DESTRUCTION;
653
654 DataForEncounterSide playerSide = context.getDataFor(playerFleet);
655 CrewCompositionAPI crewLosses = playerSide.getCrewLossesDuringLastEngagement();
656 if ((int)crewLosses.getCrewInt() + (int)crewLosses.getMarines() > 0 && !totalDefeat && !mutualDestruction) {
657 addText(getString("casualtyReport"));
658
659 DataForEncounterSide data = context.getDataFor(playerFleet);
660 int crewLost = (int) (data.getCrewLossesDuringLastEngagement().getCrewInt());
661 int marinesLost = (int) (data.getCrewLossesDuringLastEngagement().getMarines());
662 String crewLostStr = getApproximate(crewLost);
663 if (crewLostStr.equals("no")) crewLostStr = "";
664 if (crewLostStr.indexOf(" ") >= 0) {
665 crewLostStr = crewLostStr.substring(crewLostStr.indexOf(" ") + 1);
666 }
667 String marinesLostStr = getApproximate(marinesLost);
668 if (marinesLostStr.equals("no")) marinesLostStr = "";
669 if (marinesLostStr.indexOf(" ") >= 0) {
670 marinesLostStr = marinesLostStr.substring(marinesLostStr.indexOf(" ") + 1);
671 }
672 textPanel.highlightInLastPara(HIGHLIGHT_COLOR, crewLostStr, marinesLostStr);
673 }
674
675 boolean showFleetInfo = false;
676
678 case PURSUIT_PLAYER_OUT_FIRST_WIN:
679 addText(getString("playerOutFirstPursuitWin"));
680 showFleetInfo = true;
681 break;
682 case PURSUIT_PLAYER_OUT_FIRST_LOSS:
683 addText(getString("playerOutFirstPursuitLoss"));
684 showFleetInfo = true;
685 break;
686 case BATTLE_PLAYER_OUT_FIRST_WIN:
687 addText(getString("playerOutFirstEngageWin"));
688 showFleetInfo = true;
689 break;
690 case BATTLE_PLAYER_OUT_FIRST_LOSS:
691 addText(getString("playerOutFirstEngageLoss"));
692 showFleetInfo = true;
693 break;
694 case ESCAPE_PLAYER_OUT_FIRST_WIN:
695 addText(getString("playerOutFirstEscapeWin"));
696 showFleetInfo = true;
697 break;
698 case ESCAPE_PLAYER_OUT_FIRST_LOSS:
699 addText(getString("playerOutFirstEscapeLoss"));
700 showFleetInfo = true;
701 break;
702 case BATTLE_ENEMY_WIN:
703 addText(getString("battleDefeat"));
704 showFleetInfo = true;
705 //enemyHasPostCombatOptions = true;
706 break;
707 case BATTLE_ENEMY_WIN_TOTAL:
708 addText(getString("battleTotalDefeat"));
709 showFleetInfo = true;
710 break;
711 case BATTLE_PLAYER_WIN:
712 if (config.showVictoryText) {
713 addText(getString("battleVictory"));
714 }
715 showFleetInfo = true;
716 break;
717 case BATTLE_PLAYER_WIN_TOTAL:
718 if (config.showVictoryText) {
719 addText(getString("battleTotalVictory"));
720 }
721 showFleetInfo = true;
722 break;
723 case ESCAPE_ENEMY_LOSS_TOTAL:
724 if (config.showVictoryText) {
725 addText(getString("pursuitTotalVictory"));
726 }
727 showFleetInfo = true;
728 break;
729 case ESCAPE_ENEMY_SUCCESS:
730 if (result.getLoserResult().getDisabled().isEmpty() && result.getLoserResult().getDestroyed().isEmpty()) {
731 addText(getString("pursuitVictoryNoLosses"));
732 } else {
733 addText(getString("pursuitVictoryLosses"));
734 }
735 showFleetInfo = true;
736 break;
737 case ESCAPE_ENEMY_WIN:
738 addText(getString("pursuitDefeat"));
739 showFleetInfo = true;
740 break;
741 case ESCAPE_ENEMY_WIN_TOTAL:
742 addText(getString("pursuitTotalDefeat"));
743 showFleetInfo = true;
744 break;
745 case ESCAPE_PLAYER_LOSS_TOTAL:
746 addText(getString("escapeTotalDefeat"));
747 showFleetInfo = true;
748 break;
749 case ESCAPE_PLAYER_SUCCESS:
750 addText(getString("escapeDefeat"));
751 showFleetInfo = true;
752 break;
753 case ESCAPE_PLAYER_WIN:
754 addText(getString("escapeVictory"));
755 showFleetInfo = true;
756 break;
757 case ESCAPE_PLAYER_WIN_TOTAL:
758 addText(getString("escapeTotalVictory"));
759 showFleetInfo = true;
760 break;
761 case MUTUAL_DESTRUCTION:
762 addText(getString("engagementMutualDestruction"));
763 // bit of a hack. this'll make it so that the player's ships have a chance to be repaired
764 // in the event of mutual destruction by adding them to the enemy fleet side's "disabled enemy ships" list.
765 // it'll work by using the existing vs-player boarding path
766 if (mutualDestruction) {
767 DataForEncounterSide otherData = context.getDataFor(otherFleet);
768 for (FleetMemberAPI member : result.getLoserResult().getDisabled()) {
769 otherData.addEnemy(member, Status.DISABLED);
770 }
771 }
772 }
773
774 EngagementOutcome last = context.getLastEngagementOutcome();
775 if (last == EngagementOutcome.BATTLE_PLAYER_OUT_FIRST_LOSS ||
776 last == EngagementOutcome.BATTLE_PLAYER_OUT_FIRST_WIN) {
777 float recoveryFraction = context.performPostEngagementRecoveryBoth(result);
778 if (recoveryFraction > 0) {
779 if (config.showCrRecoveryText) {
780 addText(getString("bothRecovery"));
781 }
782 }
783 } else {
784 float recoveryFraction = context.performPostVictoryRecovery(result);
785 if (recoveryFraction > 0) {
786 if (config.showCrRecoveryText) {
788 addText(getString("playerRecovery"));
789 } else {
790 addText(getString("enemyRecovery"));
791 }
792 }
793 }
794 }
795
796 if (showFleetInfo) {
797 //visual.showFleetInfo((String)null, playerFleet, (String)null, otherFleet, context);
799 }
800
802
803
804 if (config.straightToEngage) {
805 //optionSelected(null, OptionId.LEAVE);
807 } else {
808 if (ongoingBattle) {
811 } else {
812 updateMainState(true);
813 }
814 }
815
816 if (isFightingOver()) {
820 }
821 }
822 }
823
824 protected void addPostBattleAttitudeText() {
825 if (!config.showFleetAttitude) return;
826
827 if (!ongoingBattle) {
829 boolean otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage();
830 if (!otherWantsToRun) {
832 addText(getString("cleanDisengageOpportunity"), getString("highlightCleanDisengage"), Misc.getPositiveHighlightColor());
833 } else if (didEnoughToDisengage(playerFleet)) {
834 addText(getString("playerDisruptedEnemy"), getString("highlghtDisruptedEnemy"), Misc.getPositiveHighlightColor());
835 }
836 }
837 }
838 }
839 if (!isFightingOver()) {
840 String side = "";
841 if (context.getBattle() != null && context.getBattle().getNonPlayerSide().size() > 1) {
842 side = "Side";
843 }
845 addText(getString("postBattleAggressive" + side));
846 } else if (otherFleetWantsToDisengage()) {
847 if (!otherCanDisengage()) {
848 addText(getString("postBattleAggressive" + side));
849 } else {
850 addText(getString("postBattleDisengage" + side));
851 }
852 } else {
854 addText(getString("postBattleHoldVsStrongerEnemy" + side));
855 } else {
856 addText(getString("postBattleNeutral" + side));
857 }
858 }
859 }
860 }
861
862 public List<FleetMemberAPI> getPursuitCapablePlayerShips() {
863 List<FleetMemberAPI> members = new ArrayList<FleetMemberAPI>();
865 if (member.isAlly()) continue;
866 if (member.isCivilian()) continue;
867 members.add(member);
868 }
869 return members;
870 }
871
872 public void optionSelected(String text, Object optionData) {
873 if (optionData == null) return;
874
875 // might not be a string if it's the dev-mode "escape to leave" option
876 if (inConversation && optionData instanceof String) {
877 conversationDelegate.optionSelected(text, optionData);
878 if (!inConversation) {
879 //optionSelected(null, OptionId.CUT_COMM);
880 //optionSelected(null, OptionId.INIT);
881 }
882 return;
883 }
884
885 if (optionData == DumpMemory.OPTION_ID) {
886 //new DumpMemory().execute(null, dialog, null, conversationDelegate.getMemoryMap());
887 new DumpMemory().execute(null, dialog, null, getMemoryMap());
888 return;
889 } else if (DevMenuOptions.isDevOption(optionData)) {
890 DevMenuOptions.execute(dialog, (String) optionData);
891 return;
892 }
893
894 if (optionData instanceof String) {
895 //??? failsafe
896 optionSelected(null, OptionId.CUT_COMM);
897 return;
898 }
899
900 OptionId option = (OptionId) optionData;
901
902// if (option == OptionId.OPEN_COMM) {
903// textPanel.clear();
904// }
905
906 if (text != null) {
907 //textPanel.addParagraph(text, Global.getSettings().getColor("buttonText"));
909 }
910
911 switch (option) {
912 case PRINT_ONGOING_BATTLE_INFO:
913 if (ongoingBattle) {
914 if (!config.straightToEngage) addText(getString("ongoingBattleEncounter"));
916 b.genCombined();
917
918 BattleSide side = b.pickSide(playerFleet);
919 BattleSide sideAssumingTransponderOn = b.pickSide(playerFleet, false);
920
921 if (!config.straightToEngage) {
922 if (side == sideAssumingTransponderOn && side == BattleSide.NO_JOIN) {
923 addText(getString("ongoingBattleNoJoin"));
924 } else if (side != sideAssumingTransponderOn && side == BattleSide.NO_JOIN) {
925 addText(getString("ongoingBattleNoJoinTransponder"));
926 } else {
927 addText(getString("ongoingBattleShareIFF"));
928 }
929 }
930 }
931 break;
932 case INIT:
933 if (ongoingBattle) {
934 if (!config.straightToEngage) addText(getString("ongoingBattleEncounter"));
936 b.genCombined();
937
938 BattleSide side = b.pickSide(playerFleet);
939 BattleSide sideAssumingTransponderOn = b.pickSide(playerFleet, false);
940
941 if (!config.straightToEngage) {
942 if (side == sideAssumingTransponderOn && side == BattleSide.NO_JOIN) {
943 addText(getString("ongoingBattleNoJoin"));
944 } else if (side != sideAssumingTransponderOn && side == BattleSide.NO_JOIN) {
945 addText(getString("ongoingBattleNoJoinTransponder"));
946 } else {
947 addText(getString("ongoingBattleShareIFF"));
948 }
949 }
950// if (context.getBattle().canJoin(playerFleet)) {
951// BattleSide playerSide = b.pickSide(playerFleet);
952// CampaignFleetAPI prePlayerAllies = b.getCombined(playerSide);
953// CampaignFleetAPI enemies = b.getOtherSideCombined(playerSide);
954// }
955 } else {
956 boolean hostile = otherFleet.getAI() != null && otherFleet.getAI().isHostileTo(playerFleet);
957 hostile |= context.isEngagedInHostilities();
958 if (!skipAttitudeOnInit) {
959 String side = "";
960 if (context.getBattle() != null && context.getBattle().getNonPlayerSide().size() > 1) {
961 side = "Side";
962 }
963 if (config.showFleetAttitude) {
964 boolean hasStation = false;
965 boolean allStation = true;
967 allStation &= curr.isStationMode();
968 hasStation |= curr.isStationMode();
969 }
970 if (otherFleetWantsToFight() && !canDisengage() && hasStation && !allStation) {
971 addText(getString("initialWithStationVsLargeFleet"));
972 } else if (otherFleetWantsToFight()) {
973 addText(getString("initialAggressive" + side));
974 } else if (otherFleetWantsToDisengage()) {
975 if (!otherCanDisengage()) {
976 if (hostile) {
977 addText(getString("initialNeutral" + side));
978 } else {
979 addText(getString("initialNeutral" + side));
980 }
981 } else {
982 if (hostile) {
983 addText(getString("initialDisengage" + side));
984 } else {
985 addText(getString("initialCareful" + side));
986 }
987 }
988 } else {
990 addText(getString("initialHoldVsStrongerEnemy" + side));
991 } else {
992 addText(getString("initialNeutral" + side));
993 }
994 }
995 }
996 }
997 if (!shownKnownStatus && config.showTransponderStatus && !otherFleet.getFaction().isNeutralFaction()) {
998 shownKnownStatus = true;
999 String side = "";
1000 if (context.getBattle() != null && context.getBattle().getNonPlayerSide().size() > 1) {
1001 side = "Side";
1002 }
1004 //boolean knows = otherFleet.knowsWhoPlayerIs();
1005 boolean knows = context.getBattle() != null && context.getBattle().getNonPlayerSide() != null &&
1007 if (!knows) {
1008 addText(getString("initialDoesntKnow" + side));
1009 } else {
1011 if (actualPlayer.isTransponderOn()) {
1012 addText(getString("initialKnows" + side));
1013 } else {
1014 if (actualPlayer.hasShipsWithUniqueSig()) {
1015 addText(getString("initialKnowsUnique" + side));
1016 } else {
1017 addText(getString("initialKnowsTOff" + side));
1018 }
1019 }
1020 }
1021 }
1022 }
1023 //textPanel.highlightFirstInLastPara("neutral posture", HIGHLIGHT_COLOR);
1024 }
1025 updateMainState(true);
1026 break;
1027 case REINIT_CONTINUE:
1029 break;
1030 case INITIATE_BATTLE:
1031 {
1032// BattleAPI b = context.getBattle();
1033// b.join(Global.getSector().getPlayerFleet());
1034//
1035// boolean someJoined = false;
1036// CampaignFleetAPI actualPlayer = Global.getSector().getPlayerFleet();
1037// for (CampaignFleetAPI fleet : actualPlayer.getContainingLocation().getFleets()) {
1038// if (b == fleet.getBattle()) continue;
1039//
1040// float dist = Misc.getDistance(actualPlayer.getLocation(), fleet.getLocation());
1041// dist -= actualPlayer.getRadius();
1042// dist -= fleet.getRadius();
1043// if (dist < 200 && fleet.getAI() != null && fleet.getAI().wantsToJoin(b)) {
1044// b.join(fleet);
1045// addText(Misc.ucFirst(fleet.getNameWithFaction()) + " will join the battle.");
1046// textPanel.highlightFirstInLastPara(fleet.getNameWithFaction(), fleet.getFaction().getBaseUIColor());
1047// someJoined = true;
1048// }
1049// }
1050// if (!someJoined) {
1051// addText("No nearby fleets will join the battle.");
1052// }
1053//
1054// b.genCombined();
1055//
1056// showFleetInfo();
1057//
1058// playerFleet = b.getPlayerCombined();
1059// otherFleet = b.getNonPlayerCombined();
1060
1061 //updateEngagementChoice(true);
1062 updateMainState(true);
1063 }
1064 break;
1065 case JOIN_ONGOING_BATTLE:
1068 for (CampaignFleetAPI fleet : b.getBothSides()) {
1069 fleet.inflateIfNeeded();
1070 }
1071 b.genCombined();
1072
1073 BattleSide playerSide = b.pickSide(playerFleet);
1074 CampaignFleetAPI prePlayerAllies = b.getCombined(playerSide);
1075 CampaignFleetAPI enemies = b.getOtherSideCombined(playerSide);
1076
1077 boolean alliedWantsToFightBefore = fleetWantsToFight(prePlayerAllies, enemies);
1078 boolean alliedWantsToDisengageBefore = fleetWantsToDisengage(prePlayerAllies, enemies) && fleetCanDisengage(prePlayerAllies);
1079 boolean alliedHoldingBefore = fleetHoldingVsStrongerEnemy(prePlayerAllies, enemies);
1080 boolean otherWantsToFightBefore = fleetWantsToFight(enemies, prePlayerAllies);
1081 boolean otherWantsToDisengageBefore = fleetWantsToDisengage(enemies, prePlayerAllies) && fleetCanDisengage(enemies);
1082 boolean otherHoldingBefore = fleetHoldingVsStrongerEnemy(enemies, prePlayerAllies);
1083
1084 //System.out.println("Ships before: " + prePlayerAllies.getFleetData().getMembersListCopy().size());
1085
1086 b.join(playerFleet);
1087 b.genCombined();
1088
1089 showFleetInfo();
1090 joinedBattle = true;
1091
1094
1095 //System.out.println("Ships after: " + playerFleet.getFleetData().getMembersListCopy().size());
1096 boolean alliedWantsToFight = alliedFleetWantsToFight();
1097 boolean alliedWantsToDisengage = alliedFleetWantsToDisengage() && alliedCanDisengage();
1098 boolean alliedHolding = alliedFleetHoldingVsStrongerEnemy();
1099
1100 boolean otherWantsToFight = otherFleetWantsToFight();
1101 boolean otherWantsToDisengage = otherFleetWantsToDisengage() && otherCanDisengage();
1102 boolean otherHolding = otherFleetHoldingVsStrongerEnemy();
1103
1104 b.takeSnapshots();
1105
1110 }
1111 } else {
1112 addText("Failed to join battle; shouldn't happen.");
1113 updateMainState(true);
1114 }
1115 break;
1116 case CONTINUE_ONGOING_BATTLE:
1118 break;
1119 case FORCE_ENGAGE:
1120 if (config.showEngageText) {
1121 addText(getString("engageForce"));
1122 }
1123 case ENGAGE:
1124 //visual.showImagePortion("illustrations", "hound_hangar", 350, 75, 800, 800, 0, 0, 400, 400);
1125 boolean forceEngage = option == OptionId.FORCE_ENGAGE;
1129 if (config.showEngageText) {
1130 addText(getString("engagePursuit"));
1131 }
1132 } else {
1135 if (config.showEngageText) {
1136 addText(getString("engageMutual"));
1137 }
1138 }
1140 break;
1141 case CONTINUE_INTO_BATTLE:
1142// if (context.getBattle() == null) {
1143// if (otherFleet.getBattle() != null) {
1144// context.setBattle(otherFleet.getBattle());
1145// } else {
1146// BattleAPI battle = Global.getFactory().createBattle(playerFleet, otherFleet);
1147// context.setBattle(battle);
1148// }
1149// }
1150
1152 if (config.alwaysAttackVsAttack){
1155 }
1156
1157 if (context.getBattle() != null) {
1159
1160 if (b.isStationInvolved()) {
1161 boolean regen = false;
1163 if (otherGoal == FleetGoal.ESCAPE) {
1164 regen = true;
1165 }
1166 } else {
1167 if (playerGoal == FleetGoal.ESCAPE) {
1168 regen = true;
1169 }
1170 }
1171
1172 if (regen) {
1173 b.genCombined(false);
1174 }
1175 }
1176
1177 CampaignFleetAPI combinedPlayer = b.getPlayerCombined();
1178 CampaignFleetAPI combinedEnemy = b.getNonPlayerCombined();
1179
1180// playerGoal = null;
1181// otherGoal = null;
1182
1183 bcc = new BattleCreationContext(combinedPlayer, playerGoal, combinedEnemy, otherGoal);
1185
1187 bcc.objectivesAllowed = false;
1188 }
1189 if (config.delegate != null) {
1190 config.delegate.battleContextCreated(dialog, bcc);
1191 }
1192
1193 if (firstEngagement) {
1195 bcc.setInitialStepSize(1.5f);
1196 bcc.setInitialNumSteps(10 + (float) Math.random() * 30);
1197 }
1198 firstEngagement = false;
1199 } else {
1201 bcc.setInitialStepSize(1.5f);
1202 bcc.setInitialNumSteps(5 + (float) Math.random() * 5);
1203 }
1204 }
1205 } else {
1208 if (config.delegate != null) {
1209 config.delegate.battleContextCreated(dialog, bcc);
1210 }
1211 }
1212
1213 if (playerGoal == FleetGoal.ESCAPE) {
1214 //DataForEncounterSide data = context.getDataFor(otherFleet);
1216 if (ai != null) {
1218 }
1219 } else if (otherGoal == FleetGoal.ESCAPE) {
1220 //DataForEncounterSide data = context.getDataFor(playerFleet);
1222 if (ai != null) {
1224 }
1225 }
1226
1228 dialog.startBattle(bcc);
1229 break;
1230 case CLEAN_DISENGAGE:
1231 case DISENGAGE:
1232// CampaignFleetAIAPI ai = otherFleet.getAI();
1233// PursuitOption po = otherFleet.getAI().pickPursuitOption(context, playerFleet);
1234 PursuitOption po = pickPursuitOption(otherFleet, playerFleet, context);
1236 po = PursuitOption.LET_THEM_GO;
1237 }
1238
1240 context.getDataFor(playerFleet).setDisengaged(true);
1241 context.getDataFor(otherFleet).setDisengaged(false);
1242 switch (po) {
1243 case PURSUE:
1244 // shouldn't happen here, or we'd be in ATTEMPT_TO_DISENGAGE
1245 case HARRY:
1246 context.applyPursuitOption(otherFleet, playerFleet, PursuitOption.HARRY);
1247 addText(getString("enemyHarass"));
1248 context.setEngagedInHostilities(true); // this was commented out, why?
1250 context.getDataFor(playerFleet).setDisengaged(true);
1251 context.getDataFor(otherFleet).setDisengaged(false);
1252 break;
1253 case LET_THEM_GO:
1255 context.setEngagedInHostilities(true); // so that other fleets stand down and don't insta-pursue
1256 addText(getString("enemyUnableToPursue"));
1257 } else {
1258 addText(getString("enemyDecidesNotToPursue"));
1259 }
1260 break;
1261 }
1262 updateMainState(true);
1263 break;
1264 case ATTEMPT_TO_DISENGAGE:
1265 boolean letGo = true;
1266 if (otherFleetWantsToFight()) {
1267 //PursuitOption pursuitOption = otherFleet.getAI().pickPursuitOption(context, playerFleet);
1268 PursuitOption pursuitOption = pickPursuitOption(otherFleet, playerFleet, context);
1269 if (pursuitOption == PursuitOption.PURSUE) {
1272 addText(getString("enemyPursuit"));
1273 letGo = false;
1275 } else if (pursuitOption == PursuitOption.HARRY) {
1276 context.applyPursuitOption(otherFleet, playerFleet, PursuitOption.HARRY);
1277 addText(getString("enemyHarass"));
1279 //context.getDataFor(playerFleet).setDisengaged(!context.isEngagedInHostilities());
1280 context.getDataFor(playerFleet).setDisengaged(true);
1281 context.getDataFor(otherFleet).setDisengaged(false);
1282 updateMainState(true);
1283 letGo = false;
1284 } else {
1285 letGo = true;
1286 }
1287 }
1288 if (letGo) {
1289 //PursueAvailability pa = context.getPursuitAvailability(otherFleet, playerFleet);
1290 PursueAvailability pa = getPursuitAvailability(otherFleet);
1291 DisengageHarryAvailability dha = context.getDisengageHarryAvailability(otherFleet, playerFleet);
1292 if (dha == DisengageHarryAvailability.AVAILABLE || pa == PursueAvailability.AVAILABLE) {
1293 addText(getString("enemyDecidesNotToPursue"));
1294 } else {
1295 addText(getString("enemyUnableToPursue"));
1296 }
1297 context.getDataFor(playerFleet).setDisengaged(true);
1299 updateMainState(true);
1300 }
1301
1302// String name = "Corvus III";
1303// SectorEntityToken planet = Global.getSector().getStarSystem("Corvus").getEntityByName(name);
1304// //planet = Global.getSector().getStarSystem("Corvus").getStar();
1305// if (planet != null) {
1306// addText("Incoming visual feed from " + name + ".");
1307// visual.showPlanetInfo(planet);
1308// } else {
1309// addText("Planet " + name + " not found in the Corvus system.");
1310// }
1311// dialog.showTextPanel();
1312 //dialog.hideTextPanel();
1313 //dialog.setXOffset(-200);
1314 break;
1315 case BEGIN_FLEET_ENCOUNTER_2:
1317 break;
1318 case OPEN_COMM:
1321 dialog.flickerStatic(0.1f, 0.1f);
1322
1323 inConversation = true;
1327
1330
1331 boolean otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage();
1333 if (otherWantsToRun) {
1334 mem.unset("$weakerThanPlayerButHolding");
1335 }
1336
1337 if (!conversationDelegate.fireBest("OpenCommLink")) {
1338 addText("You try to establish a comm link, but only get static.");
1341 inConversation = false;
1342 }
1343 if (inConversation && !visual.isShowingPersonInfo(actualOther.getCommander()) &&
1345 visual.showPersonInfo(actualOther.getCommander());
1346 }
1347 break;
1348 case CUT_COMM:
1350 dialog.flickerStatic(0.1f, 0.1f);
1351
1352// addText(getString("cutComm"));
1353// visual.showFleetInfo((String)null, playerFleet, (String)null, otherFleet, context);
1354// updateMainState();
1355
1356 inConversation = false;
1357// addText(getString("cutComm"));
1358 //visual.showFleetInfo((String)null, playerFleet, (String)null, otherFleet, context);
1359 showFleetInfo();
1360 optionSelected(null, OptionId.INIT);
1361
1362 break;
1363 case PURSUE:
1366 addText(getString("pursue"));
1368 break;
1369 case AUTORESOLVE_PURSUE:
1370 List<FleetMemberAPI> members = getPursuitCapablePlayerShips();
1371// List<FleetMemberAPI> members = new ArrayList<FleetMemberAPI>();
1372// for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) {
1373// if (member.isAlly()) continue;
1374// if (member.isCivilian()) continue;
1375// members.add(member);
1376// }
1377 dialog.showFleetMemberPickerDialog("Select craft to send in pursuit", "Ok", "Cancel",
1378 4, 8, 58f, false, true, members,
1380 public void pickedFleetMembers(List<FleetMemberAPI> members) {
1381 if (members != null && !members.isEmpty()) {
1383 resolver.resolvePlayerPursuit(context, members);
1384 if (resolver.getResult() != null) {
1385 addText(getString("pursuitAutoresolve"));
1386 if (context.getBattle() != null) {
1388 CampaignFleetAPI ally = null;
1389 float alliedFP = 0;
1391 if (!curr.isPlayerFleet() && !curr.getFleetData().getMembersListCopy().isEmpty() &&
1392 !curr.isStationMode()) {
1393 if (ally == null) ally = curr;
1394 alliedFP += ally.getFleetPoints();
1395 }
1396 }
1397 float playerFP = 0f;
1398 for (FleetMemberAPI member : members) {
1399 playerFP += member.getFleetPointCost();
1400 }
1401 float damage = 0f;
1402 for (FleetMemberAPI member : resolver.getResult().getLoserResult().getDisabled()) {
1403 damage += member.getFleetPointCost();
1404 }
1405 for (FleetMemberAPI member : resolver.getResult().getLoserResult().getDestroyed()) {
1406 damage += member.getFleetPointCost();
1407 }
1408 float total = playerFP + alliedFP;
1409 if (total < 1) total = 1;
1411 if (ally != null && alliedFP > 0) {
1413 }
1414 }
1415 backFromEngagement(resolver.getResult());
1416 }
1417 }
1418 }
1419 public void cancelledFleetMemberPicking() {
1420
1421 }
1422 });
1423 break;
1424 case CRASH_MOTHBALL:
1426 dialog.showFleetMemberPickerDialog("Select craft to crash-mothball", "Ok", "Cancel",
1427 3, 7, 58f, false, true, choices,
1429 public void pickedFleetMembers(List<FleetMemberAPI> members) {
1431 member.getRepairTracker().setCrashMothballed(false);
1432 }
1433 if (members != null && !members.isEmpty()) {
1434 for (FleetMemberAPI member : members) {
1435 member.getRepairTracker().setCrashMothballed(true);
1436 }
1437
1439 if (members.size() == 1) {
1440 addText(getString("crashMothballSelectedOneShip"));
1441 } else {
1442 addText(getString("crashMothballSelectedMultiple"));
1443 }
1444 }
1445 }
1446 public void cancelledFleetMemberPicking() {
1447
1448 }
1449 });
1450 break;
1451 case SCUTTLE:
1452 break;
1453 case GO_TO_PRE_BATTLE:
1455 break;
1456 case GO_TO_MAIN:
1457 if (config.straightToEngage) {
1458 optionSelected(null, OptionId.LEAVE);
1459 break;
1460 }
1461 List<CampaignFleetAPI> playerSide = context.getBattle().getPlayerSide();
1462 List<CampaignFleetAPI> otherSide = context.getBattle().getNonPlayerSide();
1463 //context.getBattle().leave(playerFleet);
1464 if (joinedBattle) {
1465 //context.getBattle().leave(otherFleet);
1466 joinedBattle = false;
1467 }
1468 if (ongoingBattle) {
1473 String titleOne = b.getPrimary(b.getSideOne()).getNameWithFactionKeepCase();
1474 if (b.getSideOne().size() > 1) titleOne += ", with allies";
1475 String titleTwo = b.getPrimary(b.getSideTwo()).getNameWithFactionKeepCase();
1476 if (b.getSideTwo().size() > 1) titleTwo += ", with allies";
1478 } else {
1479// context.getBattle().uncombine();
1480// if (playerSide != null) {
1481// for (CampaignFleetAPI curr : new ArrayList<CampaignFleetAPI>(playerSide)) {
1482// if (curr != playerFleet) {
1483// context.getBattle().leave(curr);
1484// }
1485// }
1486// }
1487// if (otherSide != null) {
1488// for (CampaignFleetAPI curr : new ArrayList<CampaignFleetAPI>(otherSide)) {
1489// if (curr != otherFleet) {
1490// context.getBattle().leave(curr);
1491// }
1492// }
1493// }
1494// showFleetInfo();
1495 }
1496 updateMainState(false);
1497 break;
1498 case CONTINUE:
1501 break;
1502 case DEV_MODE_ESCAPE:
1504
1506 if (b.isPlayerInvolved()) {
1507 cleanUpBattle();
1508 }
1509 case LOOT_THEN_LEAVE:
1510 //goToEncounterEndPath();
1511 winningPath();
1512 break;
1513 case LEAVE:
1514 case CONTINUE_LEAVE:
1515 if (option != OptionId.CONTINUE_LEAVE) {
1516 if (context.adjustPlayerReputation(dialog, getString("friendlyFireRepLoss"),
1517 config.impactsAllyReputation, config.impactsEnemyReputation)) {
1519 options.addOption("Continue", OptionId.CONTINUE_LEAVE, null);
1520 if (!config.straightToEngage) {
1521 options.setShortcut(OptionId.CONTINUE_LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
1522 }
1523 break;
1524 }
1525 }
1526 if (isFightingOver()) {
1527 if (!context.hasWinnerAndLoser()) {
1528 if (context.getDataFor(playerFleet).isWonLastEngagement()) {
1529 context.getDataFor(playerFleet).setDisengaged(false);
1530 context.getDataFor(otherFleet).setDisengaged(true);
1531 } else {
1532 context.getDataFor(playerFleet).setDisengaged(true);
1533 context.getDataFor(otherFleet).setDisengaged(false);
1534 }
1535 }
1536 } else {
1538 context.getDataFor(playerFleet).setDisengaged(true);
1539 context.getDataFor(otherFleet).setDisengaged(false);
1540 } else {
1541 context.getDataFor(playerFleet).setDisengaged(true);
1542 context.getDataFor(otherFleet).setDisengaged(true);
1543 }
1544 }
1545
1546 if (config.printXPToDialog) {
1549 }
1553
1554// if (config.dismissOnLeave) {
1555// Global.getSector().getCampaignUI().addMessage("Game paused");
1556// }
1557
1558 cleanUpBattle();
1559// context.getBattle().leave(Global.getSector().getPlayerFleet());
1560// if (!ongoingBattle) {
1561// context.getBattle().finish();
1562// }
1563
1564 if (config.dismissOnLeave) {
1565 dialog.dismiss();
1566 } else {
1567 //options.clearOptions();
1568 dialog.setOptionOnEscape("", null);
1569 dialog.setOptionOnConfirm("", null);
1570 }
1571 if (config.delegate != null) {
1572 config.delegate.notifyLeave(dialog);
1573 }
1574 break;
1575 case HARRY_PURSUE:
1576 addText(getString("playerHarass"));
1577 context.applyPursuitOption(playerFleet, otherFleet, PursuitOption.HARRY);
1579 context.getDataFor(playerFleet).setDisengaged(false);
1580 context.getDataFor(otherFleet).setDisengaged(true);
1583 break;
1584 case LET_THEM_GO:
1585 addText(getString("playerLetGo"));
1586 //context.getDataFor(playerFleet).setDisengaged(!context.isEngagedInHostilities());
1587 context.getDataFor(playerFleet).setDisengaged(false);
1588 context.getDataFor(otherFleet).setDisengaged(true);
1590 break;
1591 case RECOVERY_CONTINUE:
1593 break;
1594 case RECOVERY_SELECT:
1595 if (!recoverableShips.isEmpty() || !storyRecoverableShips.isEmpty()) {
1596 dialog.showFleetMemberRecoveryDialog("Select ships to recover",
1597 recoverableShips, storyRecoverableShips,
1599 public void pickedFleetMembers(List<FleetMemberAPI> members) {
1600 if (members != null && !members.isEmpty()) {
1601 recoveredShips.clear();
1602 recoveredShips.addAll(members);
1604
1606
1610
1611
1612 showFleetInfo();
1613 winningPath();
1614 }
1615 }
1616 public void cancelledFleetMemberPicking() {
1617 }
1618 });
1619 }
1620 break;
1621 case CONTINUE_FROM_VICTORY_TRIGGERS:
1622 winningPath();
1623 break;
1624 case CONTINUE_LOOT:
1625 visual.setVisualFade(0, 0);
1628
1630
1631 visual.showLoot("Salvaged", context.getLoot(), true, new CoreInteractionListener() {
1632 public void coreUIDismissed() {
1633 if (config.printXPToDialog) {
1636 }
1640// context.getBattle().uncombine();
1641// context.getBattle().leave(Global.getSector().getPlayerFleet());
1642 cleanUpBattle();
1643
1644 if (config.dismissOnLeave) {
1645 dialog.dismiss();
1648 } else {
1651 //options.clearOptions();
1652 dialog.setOptionOnEscape("", null);
1653 dialog.setOptionOnConfirm("", null);
1654 }
1655 if (config.delegate != null) {
1656 config.delegate.notifyLeave(dialog);
1657 }
1658 }
1659 });
1662 //options.addOption("Leave", OptionId.LEAVE, null);
1663 break;
1664 case CONTINUE_INTO_BOARDING:
1666 break;
1667 case BOARDING_ACTION:
1668 boardingPhase++;
1671 //boardingResult = context.boardShip(toBoard, Global.getSector().getPlayerFleet(), otherFleet);
1673 break;
1674 case SELECT_FLAGSHIP:
1675 members = new ArrayList<FleetMemberAPI>();
1677// if (member.isFighterWing()) continue;
1678// if (member.isAlly()) continue;
1679 if (!isValidTransferCommandTarget(member)) continue;
1680 members.add(member);
1681 }
1682 if (!members.isEmpty()) {
1683 dialog.showFleetMemberPickerDialog("Select flagship for this engagement", "Ok", "Cancel",
1684 3, 7, 58f, false, false, members,
1686 public void pickedFleetMembers(List<FleetMemberAPI> members) {
1687 if (members != null && !members.isEmpty()) {
1688// if (origFlagship == null) {
1689// origFlagship = Global.getSector().getPlayerFleet().getFlagship();
1690// if (origCaptains.isEmpty()) {
1691// //origCaptains.clear();
1692// for (FleetMemberAPI member : Global.getSector().getPlayerFleet().getFleetData().getMembersListCopy()) {
1693// origCaptains.put(member, member.getCaptain());
1694// }
1695// }
1696// }
1697 if (!members.get(0).isFlagship()) {
1699
1700 selectedFlagship = members.get(0);
1703 if (origFlagship != null && captain != null && !captain.isPlayer()) {
1704 origFlagship.setCaptain(captain);
1705 }
1706 addText(getString("selectedFlagship"));
1707 }
1708 }
1709 }
1710 public void cancelledFleetMemberPicking() {
1711
1712 }
1713 });
1714 }
1715 break;
1716 case ENGAGE_BOARDABLE:
1717 EngageBoardableOutcome outcome = context.engageBoardableShip(toBoard, otherFleet, playerFleet);
1718 switch (outcome) {
1719 case DESTROYED:
1720 addText(getString("engageBoardableDestroyed"));
1721 break;
1722 case DISABLED:
1723 addText(getString("engageBoardableDisabled"));
1724 break;
1725 case ESCAPED:
1726 addText(getString("engageBoardableEscaped"));
1727 break;
1728 }
1729 toBoard = null;
1731 break;
1732 case LET_IT_GO:
1734 addText(getString("letBoardableGo"));
1735 toBoard = null;
1737 break;
1738// case ABORT_BOARDING_ACTION:
1739// context.letBoardableGo(toBoard, otherFleet, playerFleet);
1740// addText(getString("letBoardableGo"));
1741// toBoard = null;
1742// goToEncounterEndPath();
1743// break;
1744// case HARD_DOCK:
1745// initBoardingParty();
1746// if (boardingParty != null) {
1747// boardingAttackType = BoardingAttackType.SHIP_TO_SHIP;
1748// boardingResult = context.boardShip(toBoard, boardingParty, boardingAttackType, boardingTaskForce, Global.getSector().getPlayerFleet(), otherFleet);
1749// goToEncounterEndPath();
1750// }
1751// break;
1752// case LAUNCH_ASSAULT_TEAMS:
1753// initBoardingParty();
1754// if (boardingParty != null) {
1755// boardingAttackType = BoardingAttackType.LAUNCH_FROM_DISTANCE;
1756// boardingResult = context.boardShip(toBoard, boardingParty, boardingAttackType, boardingTaskForce, Global.getSector().getPlayerFleet(), otherFleet);
1757// goToEncounterEndPath();
1758// }
1759// break;
1760 }
1761 }
1762
1763 protected void rememberWasBeaten() {
1764 if (context.getBattle() == null) return;
1765
1767 MemoryAPI mem = other.getMemoryWithoutUpdate();
1770 }
1771 }
1772 }
1773
1774 protected void restoreOrigCaptains() {
1775 if (origCaptains != null) {
1776 for (FleetMemberAPI member : origCaptains.keySet()) {
1777 PersonAPI captain = origCaptains.get(member);
1778 if (captain != null) {
1779 member.setCaptain(captain);
1780 }
1781 }
1782 }
1783 }
1784
1785 protected boolean cleanedUp = false;
1786 public void cleanUpBattle() {
1787 if (cleanedUp) return;
1788 cleanedUp = true;
1789
1791
1792 DataForEncounterSide enemyData = context.getDataFor(b.getNonPlayerCombined());
1793 DataForEncounterSide playerData = context.getDataFor(b.getPlayerCombined());
1794 if (enemyData != null && playerData != null && enemyData.disengaged() && !playerData.disengaged()) {
1796 }
1797
1798
1800
1801 BattleSide playerSide = b.getPlayerSide() == b.getSideOne() ? BattleSide.ONE : BattleSide.TWO;
1802 BattleSide otherSide = b.getPlayerSide() == b.getSideOne() ? BattleSide.TWO : BattleSide.ONE;
1803
1804 BattleSide winner = context.didPlayerWinMostRecentBattleOfEncounter() ? playerSide : otherSide;
1805 if (!context.isEngagedInHostilities() && !context.isOtherFleetHarriedPlayer()) winner = BattleSide.NO_JOIN;
1806
1807 if (!ongoingBattle) {
1811 } else if (ongoingBattle) {
1812 EngagementOutcome last = context.getLastEngagementOutcome();
1813 boolean finished = false;
1814 if (last == EngagementOutcome.BATTLE_PLAYER_WIN_TOTAL) {
1815 List<CampaignFleetAPI> other = b.getSide(otherSide);
1816 if (other != null && other.size() == 1) {
1817 CampaignFleetAPI f = other.get(0);
1818 if (f != null && f.isStationMode()) {
1819 b.finish(winner, true);
1820 finished = true;
1821 }
1822 }
1823 }
1824 if (!finished) {
1825 if (last == EngagementOutcome.ESCAPE_ENEMY_SUCCESS ||
1826 last == EngagementOutcome.ESCAPE_PLAYER_SUCCESS ||
1830 b.finish(winner, true);
1831 } else {
1832 for (CampaignFleetAPI curr : pulledIn) {
1834 }
1835 }
1836 }
1837 }
1840 }
1841
1842 }
1843
1844
1845 protected boolean okToLeave = false;
1846 protected boolean didRepairs = false;
1847 protected boolean didBoardingCheck = false;
1848 protected boolean didRecoveryCheck = false;
1849 protected boolean pickedMemberToBoard = false;
1850 protected FleetMemberAPI toBoard = null;
1851 protected String repairedShipList = null;
1852 //protected String boardingTaskForceList = null;
1853 //protected List<FleetMemberAPI> boardingTaskForce = null;
1854 protected int boardingPhase = 0;
1855 protected float boardingPercentSuccess = 0;
1856
1857 protected String crashMothballList = null;
1860 //protected BoardingAttackType boardingAttackType = null;
1861 protected BoardingResult boardingResult = null;
1864 protected Map<FleetMemberAPI, PersonAPI> origCaptains = new HashMap<FleetMemberAPI, PersonAPI>();
1865
1866 protected InitialBoardingResponse aiBoardingResponse = null;
1867
1868 protected boolean shownKnownStatus = false;
1869
1870 protected void goToEncounterEndPath() {
1871// boolean otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage();
1872// if (context.didPlayerWinEncounter() ||
1873// (config.straightToEngage &&
1874// context.getLastEngagementOutcome() == EngagementOutcome.BATTLE_PLAYER_WIN) ||
1875// (otherWantsToRun &&
1876// context.getLastEngagementOutcome() == EngagementOutcome.BATTLE_PLAYER_WIN)) {
1877// winningPath();
1879 (config.straightToEngage &&
1880 context.getLastEngagementOutcome() == EngagementOutcome.BATTLE_PLAYER_WIN)) {
1881 winningPath();
1882 } else {
1883 losingPath();
1884 }
1885 }
1886
1887 protected void losingPath() {
1889
1890 context.getDataFor(playerFleet).setDisengaged(true);
1891
1892 if (!recoveredCrew) {
1893 recoveredCrew = true;
1895 }
1896
1897 boolean playerHasReadyShips = !playerFleet.getFleetData().getCombatReadyMembersListCopy().isEmpty();
1898 boolean otherHasReadyShips = !otherFleet.getFleetData().getCombatReadyMembersListCopy().isEmpty();
1899 boolean totalDefeat = !playerFleet.isValidPlayerFleet();
1900 boolean mutualDestruction = context.getLastEngagementOutcome() == EngagementOutcome.MUTUAL_DESTRUCTION;
1901// if (!didBoardingCheck) {
1902// didBoardingCheck = true;
1903// toBoard = context.pickShipToBoard(otherFleet, playerFleet);
1904// if (toBoard != null) {
1905// pickedMemberToBoard = true;
1906// options.addOption("Continue", OptionId.CONTINUE_INTO_BOARDING, null);
1907// return;
1908// }
1909// }
1910
1911 if (toBoard != null && aiBoardingResponse == null) {
1913
1914 if (mutualDestruction) {
1915 addText(getString("mutualDestructionRepairs"));
1916 aiBoardingResponse = InitialBoardingResponse.LET_IT_GO;
1917 } else {
1918 if (totalDefeat) {
1919 addText(getString("lastFriendlyShipRepairs"));
1920 } else {
1921 addText(getString("friendlyShipBoardable"));
1922 }
1924 }
1925
1926 if (!otherHasReadyShips) {
1927 aiBoardingResponse = InitialBoardingResponse.LET_IT_GO;
1928 }
1929
1930 options.addOption("Continue", OptionId.CONTINUE_INTO_BOARDING, null);
1931 return;
1932 }
1933
1934 if (toBoard != null && aiBoardingResponse != null) {
1935 switch (aiBoardingResponse) {
1936 case BOARD:
1937 break;
1938 case ENGAGE:
1939 EngageBoardableOutcome outcome = context.engageBoardableShip(toBoard, playerFleet, otherFleet);
1940 switch (outcome) {
1941 case DESTROYED:
1942 if (totalDefeat) {
1943 addText(getString("lastFriendlyBoardableDestroyed"));
1944 } else {
1945 addText(getString("engageFriendlyBoardableDestroyed"));
1946 }
1947 break;
1948 case DISABLED:
1949 if (totalDefeat) {
1950 addText(getString("lastFriendlyBoardableDisabled"));
1951 } else {
1952 addText(getString("engageFriendlyBoardableDisabled"));
1953 }
1954 break;
1955 case ESCAPED:
1956 if (totalDefeat) {
1957 addText(getString("lastFriendlyBoardableEscaped"));
1958 } else {
1959 addText(getString("engageFriendlyBoardableEscaped"));
1960 }
1961 break;
1962 }
1963 break;
1964 case LET_IT_GO:
1966 if (!mutualDestruction) {
1967 if (totalDefeat) {
1968 addText(getString("engageFriendlyBoardableLetGo"));
1969 } else {
1970 addText(getString("lastFriendlyBoardableLetGo"));
1971 }
1972 }
1973 break;
1974 }
1975 }
1976
1977 totalDefeat = !playerFleet.isValidPlayerFleet();
1978 if (totalDefeat) {
1979 addText(getString("finalOutcomeNoShipsLeft"));
1980 }
1981
1982 if (pickedMemberToBoard) {
1983 //visual.showFleetInfo((String)null, playerFleet, (String)null, otherFleet, context);
1984 showFleetInfo();
1985 }
1986
1987 if (config.salvageRandom != null) {
1988 context.setSalvageRandom(config.salvageRandom);
1989 }
1990 context.generateLoot(null, config.lootCredits);
1991 context.autoLoot();
1992 //context.repairShips();
1993 String leave = "Leave";
1994 if (config.straightToEngage) {
1995 leave = "Continue";
1996 }
1997 options.addOption(leave, OptionId.LEAVE, null);
1998 if (!config.straightToEngage) {
1999 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2000 } else {
2001 optionSelected(null, OptionId.LEAVE);
2002 }
2003 }
2004
2005 protected boolean recoveredCrew = false;
2006 protected boolean lootedCredits = false;
2007 protected boolean firedVictoryTriggers = false;
2008 protected String creditsLooted = null;
2009 protected void winningPath() {
2011 DataForEncounterSide playerData = context.getDataFor(playerFleet);
2012 context.getDataFor(otherFleet).setDisengaged(true);
2013
2015
2018 plugin.setEmbeddedMode(true);
2019 //plugin.init(dialog);
2020 dialog.setPlugin(plugin);
2021 BattleAPI battle = context.getBattle();
2022 boolean firedAnyTriggers = false;
2023
2024 //for (CampaignFleetAPI other : battle.getNonPlayerSide()) {
2025 for (CampaignFleetAPI other : battle.getNonPlayerSideSnapshot()) {
2027 plugin.init(dialog);
2028
2029 MemoryAPI mem = other.getMemoryWithoutUpdate();
2030 List<FleetMemberAPI> losses = Misc.getSnapshotMembersLost(other);
2031 List<FleetMemberAPI> remaining = other.getFleetData().getMembersListCopy();
2032
2033 int fpTotal = 0;
2034 int fpLost = 0;
2035 int fpRemaining = 0;
2036 for (FleetMemberAPI curr : losses) {
2037 fpLost += curr.getFleetPointCost();
2038 fpTotal += curr.getFleetPointCost();
2039 }
2040 for (FleetMemberAPI curr : remaining) {
2041 fpRemaining += curr.getFleetPointCost();
2042 fpTotal += curr.getFleetPointCost();
2043 }
2044
2045 mem.set("$someShipsDestroyed", !losses.isEmpty(), 0);
2046 mem.set("$fpLost", fpLost, 0);
2047 mem.set("$fpRemaining", fpRemaining, 0);
2048 mem.set("$fpLostFraction", (float) fpLost / Math.max(1, fpTotal), 0);
2049 mem.set("$battle", battle, 0);
2050
2051 List<String> triggers = Misc.getDefeatTriggers(other, false);
2052 if (triggers != null) {
2053 //DebugFlags.PRINT_RULES_DEBUG_INFO = true;
2054 for (String trigger : new ArrayList<String>(triggers)) {
2055 boolean fired = FireBest.fire(null, dialog, plugin.getMemoryMap(), trigger);
2056 if (fired) {
2057 triggers.remove(trigger);
2058 firedAnyTriggers = true;
2059 }
2060 }
2061 }
2063 }
2064
2066 dialog.setPlugin(this);
2067 firedVictoryTriggers = true;
2068
2069 if (firedAnyTriggers) {
2070 options.addOption("Continue", OptionId.CONTINUE_FROM_VICTORY_TRIGGERS, null);
2071 return;
2072 }
2073 }
2074
2075 if (!recoveredCrew) {
2076 recoveredCrew = true;
2077 if ((int)playerData.getRecoverableCrewLosses().getCrewInt() + (int)playerData.getRecoverableCrewLosses().getMarines() > 0) {
2078 addText(getString("recoveryReport"));
2079 DataForEncounterSide data = context.getDataFor(playerFleet);
2080 int crewRecovered = (int) data.getRecoverableCrewLosses().getCrew();
2081 int marinesRecovered = (int) data.getRecoverableCrewLosses().getMarines();
2082 String crewRecStr = "" + crewRecovered;
2083 if (crewRecovered <= 0) {
2084 crewRecStr = "";
2085 }
2086 String marinesRecStr = "" + marinesRecovered;
2087 if (marinesRecovered <= 0) {
2088 marinesRecStr = "";
2089 }
2090 //if (crewRecStr != null && marinesRecStr != null) {
2091 textPanel.highlightInLastPara(HIGHLIGHT_COLOR, crewRecStr, marinesRecStr);
2092 //} else if (crewRecStr != null) {
2093 //textPanel.highlightInLastPara(HIGHLIGHT_COLOR, crewRecStr);
2094 //} else if (marinesRecStr != null) {
2095 //textPanel.highlightInLastPara(HIGHLIGHT_COLOR, marinesRecStr);
2096 //}
2097
2099 }
2100 }
2101
2103
2104 boolean playerHasPersonnel = actualPlayer.getCargo().getMarines() > 0;
2105 boolean playerHasReadyShips = !actualPlayer.getFleetData().getCombatReadyMembersListCopy().isEmpty();
2106
2107
2108 if (!didRecoveryCheck) {
2109 didRecoveryCheck = true;
2111 storyRecoverableShips = context.getStoryRecoverableShips();
2112
2113 if (recoverableShips == null) recoverableShips = new ArrayList<FleetMemberAPI>();
2114 if (storyRecoverableShips == null) storyRecoverableShips = new ArrayList<FleetMemberAPI>();
2115
2116 if (!recoverableShips.isEmpty() || !storyRecoverableShips.isEmpty()) {
2117 int crew = actualPlayer.getCargo().getCrew();
2118 int needed = (int)actualPlayer.getFleetData().getMinCrew();
2119
2120 int num = recoverableShips.size() + storyRecoverableShips.size();
2121 String numString = "several ships disabled or destroyed";
2122 if (num == 1) numString = "a ship disabled";
2123 String pre = "The salvage chief reports that " + numString + " during the battle " +
2124 "can be restored to basic functionalty. Recovering ships instead of breaking " +
2125 "them for salvage will greatly reduce the salvage gained from these ships.";
2127// if (extra > 0) {
2128// textPanel.addPara(pre +
2129// "You have %s extra crew available, beyond what's " +
2130// "already required to operate your current ships.", Misc.getHighlightColor(), "" + extra);
2131// } else {
2132// textPanel.addParagraph(pre +
2133// "You have no extra crew available for any recovered vessels, beyond what's " +
2134// "already required to operate your current ships.");
2135// }
2136
2137 boolean playerShipsRecoverable = false;
2138 for (FleetMemberAPI member : recoverableShips) {
2139 if (member.getOwner() == 0 && !member.isAlly()) {
2140 playerShipsRecoverable = true;
2141 break;
2142 }
2143 }
2144 for (FleetMemberAPI member : storyRecoverableShips) {
2145 if (member.getOwner() == 0 && !member.isAlly()) {
2146 playerShipsRecoverable = true;
2147 break;
2148 }
2149 }
2150
2151 boolean onlyDifficultRecovery = recoverableShips.isEmpty() && !storyRecoverableShips.isEmpty();
2152 if (playerShipsRecoverable) {
2154 textPanel.addParagraph( "Disabled ships from your fleet are available for recovery", Misc.getHighlightColor());
2156 options.addOption("Consider ship recovery", OptionId.RECOVERY_SELECT, Misc.getHighlightColor(),
2157 "Disabled ships from your fleet are available for recovery.");
2158 } else {
2159 Color color = Misc.getButtonTextColor();
2160 if (onlyDifficultRecovery) {
2161 color = Misc.getStoryOptionColor();
2162 }
2163 options.addOption("Consider ship recovery", OptionId.RECOVERY_SELECT, color, null);
2164 }
2165
2166 options.addOption("Continue", OptionId.RECOVERY_CONTINUE, null);
2167 if (playerShipsRecoverable) {
2168 options.addOptionConfirmation(OptionId.RECOVERY_CONTINUE,
2169 "Disabled ships from your fleet are available for recovery.\n\nIf you proceed without recovering them, "
2170 + "they will be lost permanently.", "Proceed", "Cancel");
2171 }
2172
2173 return;
2174 }
2175 }
2176
2177
2178
2179 context.adjustPlayerReputation(dialog, getString("friendlyFireRepLoss"),
2180 config.impactsAllyReputation, config.impactsEnemyReputation);
2181
2182
2183// "noSalvageReport":"There's no salvage to be had.",
2184// "noSalvageReportPlayerDidNothing":"Your $fleetOrShip does not participate in salvage operations due to its limited contributions throughout the encounter.",
2185// "salvageReportPlayer":"Your $fleetOrShip is able to participate in salvage operations due to its contributions throughout the encounter.",
2186 boolean validFleet = playerFleet.isValidPlayerFleet();
2187 BattleAPI battle = context.getBattle();
2188 boolean hasAllies = false;
2189 boolean startedWithAllies = false;
2190 if (battle != null) {
2191 hasAllies = context.getBattle().getPlayerSide().size() <= 1;
2192 startedWithAllies = context.getBattle().getPlayerSideSnapshot().size() > 1;
2193 }
2194
2195 if (!lootedCredits && config.withSalvage) {
2196 Random resetSalvageRandomTo = null;
2197
2198 if (config.salvageRandom != null) {
2199 context.setSalvageRandom(config.salvageRandom);
2200 resetSalvageRandomTo = Misc.getRandom(config.salvageRandom.nextLong(), 11);
2201 }
2202
2203 context.generateLoot(recoveredShips, config.lootCredits);
2204
2205 if (resetSalvageRandomTo != null) {
2206 config.salvageRandom = resetSalvageRandomTo;
2207 }
2208 if (config.delegate != null) {
2209 config.delegate.postPlayerSalvageGeneration(dialog, context, context.getLoot());
2210 }
2211 lootedCredits = true;
2212
2213 float credits = context.getCreditsLooted();
2215 if (validFleet) {
2216 if (credits <= 0 && context.getLoot().isEmpty()) {
2217 if (startedWithAllies) {
2218 addText(getString("noSalvageReportPlayerDidNothing"));
2219 } else {
2220 addText(getString("noSalvageReport"));
2221 }
2222 } else {
2223 if (startedWithAllies) {
2224 addText(getString("salvageReportPlayer"));
2225 }
2226 }
2227 }
2228 }
2229
2230 //creditsLooted = "" + (int) credits;
2231 creditsLooted = Misc.getWithDGS((int)credits);
2232 if (credits > 0 && validFleet) {
2233 addText(getString("creditsLootedReport"));
2236
2237// PromoteOfficerIntel intel = new PromoteOfficerIntel(textPanel);
2238// Global.getSector().getIntelManager().addIntel(intel, false, textPanel);
2239 }
2240 }
2241
2242 if (!context.getLoot().isEmpty() && validFleet) {
2243 options.addOption("Pick through the wreckage", OptionId.CONTINUE_LOOT, null);
2244 } else {
2245 if (!validFleet) {
2246 addText(getString("finalOutcomeNoShipsLeft"));
2247 }
2248 String leave = "Leave";
2249 boolean withEscape = true;
2250 if (config.noSalvageLeaveOptionText != null && validFleet && context.getLoot().isEmpty()) {
2251 leave = config.noSalvageLeaveOptionText;
2252 withEscape = false;
2253 }
2254 options.addOption(leave, OptionId.LEAVE, null);
2255 if (withEscape) {
2256 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2257 }
2258 }
2259 }
2260
2261 protected List<FleetMemberAPI> getCrashMothballable(List<FleetMemberAPI> all) {
2262 List<FleetMemberAPI> result = new ArrayList<FleetMemberAPI>();
2264 for (FleetMemberAPI member : all) {
2265 if (member.isAlly()) continue;
2266 if (!member.isFighterWing() && member.getRepairTracker().getCR() < crPlugin.getMalfunctionThreshold(member.getStats())) {
2267 result.add(member);
2268 }
2269 }
2270 return result;
2271 }
2272
2273
2274 protected OptionId lastOptionMousedOver = null;
2275 public void optionMousedOver(String optionText, Object optionData) {
2276
2277 if (inConversation) {
2278 conversationDelegate.optionMousedOver(optionText, optionData);
2279 return;
2280 }
2281
2282 if (optionData instanceof String) return;
2283
2284 if (optionData == null) {
2285 if (currVisualType != VisualType.FLEET_INFO) {
2286 showFleetInfo();
2287 currVisualType = VisualType.FLEET_INFO;
2288 }
2289 lastOptionMousedOver = null;
2290 return;
2291 }
2292 OptionId option = (OptionId) optionData;
2293 if (option == lastOptionMousedOver) return;
2294 lastOptionMousedOver = option;
2295 }
2296
2297 protected void showFleetInfo() {
2299 if (b != null && b.isPlayerInvolved()) {
2300 String titleOne = "Your forces";
2301 if (b.isPlayerInvolved() && b.getPlayerSide().size() > 1) {
2302 titleOne += ", with allies";
2303 }
2304 if (!Global.getSector().getPlayerFleet().isValidPlayerFleet() && b.getPlayerSide().size() > 1) {
2305 titleOne = "Allied forces";
2306 }
2307 String titleTwo = null;
2308 if (b.getPrimary(b.getNonPlayerSide()) != null) {
2310 }
2311 if (b.getNonPlayerSide().size() > 1) titleTwo += ", with allies";
2313 } else {
2314 visual.showFleetInfo((String)null, playerFleet, (String)null, otherFleet, context);
2315 }
2316 }
2317
2318 public void advance(float amount) {
2319
2320 }
2321
2322 protected void addText(String text) {
2323 textPanel.addParagraph(text);
2324 }
2325 protected void addText(String text, Color color) {
2326 textPanel.addParagraph(text, color);
2327 }
2328 protected void addText(String text, String hl, Color hlColor) {
2329 LabelAPI label = textPanel.addParagraph(text);
2330 label.setHighlight(hl);
2331 label.setHighlightColor(hlColor);
2332 }
2333
2334 protected void appendText(String text) {
2335 textPanel.appendToLastParagraph(" " + text);
2336 }
2337
2338 protected void updateDialogState() {
2340 options.addOption("Cut the comm link", OptionId.CUT_COMM, null);
2341 }
2342
2344 if (member.isFighterWing() || member.isAlly()) return false;
2345 if (Misc.isAutomated(member)) return false;
2346 if (Misc.isUnremovable(member.getCaptain())) return false;
2347 return true;
2348 }
2349
2350 protected void updatePreCombat() {
2351
2354 }
2355 float diff = context.getDifficulty();
2356 if (diff >= 1f) {
2357 String percent = "+" + (int) Math.round((diff - 1f) * 100f) + "%";
2359 textPanel.addPara("Additional XP due to overall battle difficulty: %s",
2360 Misc.getGrayColor(), Misc.getHighlightColor(), percent);
2362 }
2363
2364
2366
2367 //playerFleet.updateCounts();
2368 //int nonFighters = playerFleet.getFleetData().getMembersListCopy().size() - playerFleet.getNumFighters();
2369 boolean canTransfer = false;
2371// if (member.isFighterWing() || member.isAlly()) continue;
2372 if (member.isFlagship()) continue;
2373 if (!isValidTransferCommandTarget(member)) continue;
2374 canTransfer = true;
2375 break;
2376 }
2378 String tooltipText = getString("tooltipPursueAutoresolve");
2379 options.addOption("Order your second-in-command to handle it", OptionId.AUTORESOLVE_PURSUE, tooltipText);
2380 options.addOption("Transfer command for this engagement", OptionId.SELECT_FLAGSHIP, getString("tooltipSelectFlagship"));
2381 //if (nonFighters <= 1) {
2382 if (!canTransfer) {
2383 options.setEnabled(OptionId.SELECT_FLAGSHIP, false);
2384 }
2385 options.addOption("Take command of the action", OptionId.CONTINUE_INTO_BATTLE, null);
2386 } else {
2387 options.addOption("Transfer command for this engagement", OptionId.SELECT_FLAGSHIP, getString("tooltipSelectFlagship"));
2388 //if (nonFighters <= 1) {
2389 if (!canTransfer) {
2390 options.setEnabled(OptionId.SELECT_FLAGSHIP, false);
2391 }
2392 if (playerGoal == FleetGoal.ESCAPE) {
2394
2395 options.addOption("Crash-mothball some of your ships to prevent malfunctions", OptionId.CRASH_MOTHBALL, null);
2396 if (choices.isEmpty()) {
2397 options.setEnabled(OptionId.CRASH_MOTHBALL, false);
2398 options.setTooltip(OptionId.CRASH_MOTHBALL, getString("tooltipCrashMothballUnavailable"));
2399 } else {
2400 options.setTooltip(OptionId.CRASH_MOTHBALL, getString("tooltipCrashMothball"));
2401 }
2402 }
2403 if (config.straightToEngage) {
2404 options.addOption("Continue into battle", OptionId.CONTINUE_INTO_BATTLE, null);
2405 } else {
2406 options.addOption("Continue", OptionId.CONTINUE_INTO_BATTLE, null);
2407 }
2408 }
2409
2410 boolean canGoBack = ongoingBattle || otherGoal == FleetGoal.ESCAPE || Global.getSettings().isDevMode();
2411 if (canGoBack) {
2412 options.addOption("Go back", OptionId.GO_TO_MAIN, null);
2413 options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true);
2414 }
2415// if (ongoingBattle) {
2416// options.addOption("Go back", OptionId.GO_TO_MAIN, null);
2417// options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true);
2418// }
2419 if (Global.getSettings().isDevMode()) {
2420// if (ongoingBattle) {
2423// } else {
2424// options.addOption("Go back", OptionId.GO_TO_MAIN, null);
2425// options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true);
2426// }
2428 }
2429 }
2430
2431 protected String createShipNameListString(List<FleetMemberAPI> members) {
2432 String str = "";
2433 int fighters = 0;
2434 int ships = 0;
2435 for (FleetMemberAPI member : members) {
2436 boolean last = members.indexOf(member) == members.size() - 1;
2437 boolean secondToLast = members.indexOf(member) == members.size() - 2;
2438 boolean fighter = member.isFighterWing();
2439 if (fighter) {
2440 fighters++;
2441 } else {
2442 ships++;
2443 if (last && fighters == 0 && ships > 1) {
2444 if (members.size() > 2) {
2445 str += ", and the " + member.getShipName();
2446 } else {
2447 str += " and the " + member.getShipName();
2448 }
2449 } else {
2450 str += "the " + member.getShipName();
2451 }
2452 }
2453 if (!last && !secondToLast && !fighter) {
2454 str += ", ";
2455 }
2456
2457 if (last && fighters > 0) {
2458 if (fighters == 1) {
2459 if (ships == 0) {
2460 str += "a fighter wing";
2461 } else {
2462 if (ships > 1) {
2463 str += ", and a fighter wing";
2464 } else {
2465 str += " and a fighter wing";
2466 }
2467 }
2468 } else {
2469 if (ships == 0) {
2470 str += "several fighter wings";
2471 } else {
2472 if (ships > 1) {
2473 str += ", and several fighter wings";
2474 } else {
2475 str += " and several fighter wings";
2476 }
2477 }
2478 }
2479 }
2480 }
2481 return str;
2482 }
2483
2484 protected void updateMainState(boolean withText) {
2486
2487 if (isFightingOver()) {
2489 return;
2490 }
2491
2492 if (ongoingBattle) {
2493 BattleAPI battle = context.getBattle();
2494 boolean playerHasReadyShips = false;
2496 if (!member.isAlly()) {
2497 playerHasReadyShips = true;
2498 }
2499 }
2500 if (!joinedBattle && battle.canJoin(playerFleet)) {
2501 options.addOption("Join the battle", OptionId.JOIN_ONGOING_BATTLE, null);
2502
2503 BattleSide side = battle.pickSide(playerFleet);
2504 if (side != null) {
2505 List<CampaignFleetAPI> otherSide = battle.getOtherSide(side);
2506 if (otherSide != null) {
2507 boolean knows = battle.knowsWhoPlayerIs(otherSide);
2508 boolean lowImpact = false;
2509 CampaignFleetAPI otherPrimary = battle.getPrimary(otherSide);
2510 if (otherPrimary != null) {
2511 lowImpact |= otherPrimary.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_LOW_REP_IMPACT) == true;
2512 lowImpact |= otherPrimary.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_NO_REP_IMPACT) == true;
2513 }
2514 FactionAPI nonHostile = getNonHostileOtherFaction(otherSide);
2515 if (nonHostile != null && knows && !lowImpact && !context.isEngagedInHostilities() &&
2516 config.showWarningDialogWhenNotHostile) {
2517 options.addOptionConfirmation(OptionId.JOIN_ONGOING_BATTLE, "The " + nonHostile.getDisplayNameLong() + " " + nonHostile.getDisplayNameIsOrAre() + " not currently hostile, and you have been positively identified. Are you sure you want to engage in hostilities with one of their fleets?", "Yes", "Never mind");
2518 }
2519 }
2520 }
2521
2522 if (!playerHasReadyShips) {
2523 options.setEnabled(OptionId.JOIN_ONGOING_BATTLE, false);
2524 }
2525 }
2526
2527 options.addOption("Leave", OptionId.LEAVE, null);
2528 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2529 if (Global.getSettings().isDevMode()) {
2531 }
2532 } else {
2533 if (config.showCommLinkOption) {
2534 if (otherFleet.getMemoryWithoutUpdate().is("$hailing", true)) {
2535 options.addOption("Accept the comm request", OptionId.OPEN_COMM, Misc.getHighlightedOptionColor(), null);
2537 } else if (otherFleet.getMemoryWithoutUpdate().is("$highlightComms", true)) {
2538 options.addOption("Open a comm link", OptionId.OPEN_COMM, Misc.getHighlightedOptionColor(), null);
2539 otherFleet.getMemoryWithoutUpdate().unset("$highlightComms");
2540 } else {
2541 options.addOption("Open a comm link", OptionId.OPEN_COMM, null);
2542 }
2543 }
2544
2546 if (otherFleet.getFaction().isPlayerFaction() && !smuggler) {
2547 options.addOption("Leave", OptionId.LEAVE, null);
2548 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2549 } else {
2550 updateEngagementChoice(withText);
2551 }
2552 }
2553
2554 }
2555
2556
2557 protected boolean allyEngagementChoiceNoBattle = false;
2558 protected boolean harryEndedBattle = false;
2559 private List<FleetMemberAPI> recoverableShips;
2560 private List<FleetMemberAPI> storyRecoverableShips;
2561 private List<FleetMemberAPI> recoveredShips = new ArrayList<FleetMemberAPI>();
2562 protected void updateEngagementChoice(boolean withText) {
2564 //options.clearOptions();
2565 if (isFightingOver()) {
2567 return;
2568 }
2569 //options.clearOptions();
2570
2572
2573 if (ongoingBattle && b.getPlayerSide() != null && b.getPlayerSide().size() <= 1) {
2574 //if (ongoingBattle && b.getPlayerSide() != null && b.isPlayerPrimary()) {
2575 ongoingBattle = false;
2576 if (config.showCommLinkOption) {
2577 options.addOption("Open a comm link", OptionId.OPEN_COMM, null);
2578 }
2579 }
2580
2581 playerGoal = null;
2582 otherGoal = null;
2583
2584 boolean alliedWantsToFight = alliedFleetWantsToFight();
2585 boolean alliedWantsToRun = alliedFleetWantsToDisengage() && alliedCanDisengage();
2586 boolean alliedHolding = alliedFleetHoldingVsStrongerEnemy();
2587 boolean otherWantsToFight = otherFleetWantsToFight();
2588 boolean otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage();
2589 //otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage();
2590 boolean otherHolding = otherFleetHoldingVsStrongerEnemy();
2591
2592 //boolean otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage();
2593 boolean playerHasReadyShips = false;
2594 boolean allyHasReadyShips = false;
2596 if (member.isAlly() && !member.isStation()) {
2597 allyHasReadyShips = true;
2598 } else {
2599 playerHasReadyShips = true;
2600 }
2601 }
2602
2603 if (otherWantsToRun && canDisengageCleanly(otherFleet)) {
2604// if (didEnoughToDisengage(otherFleet)) {
2605// if (context.getBattle().getPlayerSide().size() > 1) {
2606// if (withText) addText(getString("enemyDisruptedPlayerSide"), Misc.getNegativeHighlightColor());
2607// } else {
2608// if (withText) addText(getString("enemyDisruptedPlayer"), Misc.getNegativeHighlightColor());
2609// }
2610// } else {
2611 if (context.getBattle().getPlayerSide().size() > 1) {
2612 if (withText) addText(getString("enemyCleanDisengageSide"));
2613 } else {
2614 if (withText) addText(getString("enemyCleanDisengage"));
2615 }
2616// }
2618 } else if (otherWantsToRun) {
2619 String pursueTooltip = "tooltipPursue";
2620 String harassTooltip = "tooltipHarassRetreat";
2621 String letThemGoTooltip = "tooltipLetThemGo";
2623 letThemGoTooltip = "tooltipLetThemGoNoPenalty";
2624 }
2625
2626 boolean canPursue = false;
2627 boolean canHasass = false;
2628 //PursueAvailability pa = context.getPursuitAvailability(playerFleet, otherFleet);
2629 PursueAvailability pa = getPursuitAvailability(playerFleet);
2630 //List<FleetMemberAPI> members = getPursuitCapablePlayerShips();
2631 //if (members.isEmpty()) pa = PursueAvailability.NO_READY_SHIPS;
2632
2633 DisengageHarryAvailability dha = context.getDisengageHarryAvailability(playerFleet, otherFleet);
2634
2635 switch (pa) {
2636 case AVAILABLE:
2637 canPursue = true;
2638 break;
2639 case LOST_LAST_ENGAGEMENT:
2640 pursueTooltip = "tooltipPursueLostLast";
2641 break;
2642 case NO_READY_SHIPS:
2643 pursueTooltip = "tooltipNoReadyShips";
2644 break;
2645 case TOOK_SERIOUS_LOSSES:
2646 if (context.getBattle().getPlayerSide().size() > 1) {
2647 if (withText) addText(getString("enemyDisruptedPlayerSide"), getString("highlightDisruptedPlayer"), Misc.getNegativeHighlightColor());
2648 } else {
2649 if (withText) addText(getString("enemyDisruptedPlayer"), getString("highlightDisruptedPlayer"), Misc.getNegativeHighlightColor());
2650 }
2651 pursueTooltip = "tooltipPursueSeriousLosses";
2652 break;
2653 case TOO_SLOW:
2654 pursueTooltip = "tooltipPursueTooSlow";
2655 break;
2656 }
2657
2658 switch (dha) {
2659 case AVAILABLE:
2660 canHasass = true;
2661 break;
2662 case NO_READY_SHIPS:
2663 harassTooltip = "tooltipNoReadyShips";
2664 break;
2665 }
2666
2667 if (ongoingBattle) {
2668 boolean station = false;
2669 if (playerFleet != null) {
2671 if (member.isStation()) {
2672 station = true;
2673 break;
2674 }
2675 }
2676 }
2677
2678 //boolean letGo = (!canPursue && !canHasass) || !allyHasReadyShips || station;
2679 boolean letGo = (!canPursue && !canHasass) || !allyHasReadyShips;// || station;
2680 if (station) { // make it so the player can decide to pursue
2681 letGo = false;
2682 alliedWantsToFight = true;
2683 }
2684 //if (!letGo) {
2685 //PursuitOption po = playerFleet.getAI().pickPursuitOption(context, otherFleet);
2686 PursuitOption po = pickPursuitOption(playerFleet, otherFleet, context);
2687 po = PursuitOption.PURSUE;
2688 if (alliedWantsToRun || alliedHolding || !alliedWantsToFight || letGo) {
2689 po = PursuitOption.LET_THEM_GO;
2690 }
2691 if (!canPursue && canHasass) {
2692 po = PursuitOption.HARRY;
2693 }
2694 //po = PursuitOption.LET_THEM_GO;
2695 //po = PursuitOption.HARRY;
2696 switch (po) {
2697 case PURSUE:
2698 if (withText) addText(getString("ongoingBattlePursue"));
2701 options.addOption("Join the pursuit", OptionId.CONTINUE_ONGOING_BATTLE, getString(pursueTooltip));
2702 if (!canPursue || !playerHasReadyShips) {
2703 options.setEnabled(OptionId.CONTINUE_ONGOING_BATTLE, false);
2704 }
2705 break;
2706 case HARRY:
2707 // CR loss from harrying
2709
2710 if (withText) addText(getString("ongoingBattleHarass"));
2712 context.getDataFor(playerFleet).setDisengaged(false);
2713 context.getDataFor(otherFleet).setDisengaged(true);
2715 harryEndedBattle = true;
2716 //rememberWasBeaten();
2717 break;
2718 case LET_THEM_GO:
2719 letGo = true;
2721 context.getDataFor(playerFleet).setDisengaged(false);
2722 context.getDataFor(otherFleet).setDisengaged(true);
2723 }
2725 //rememberWasBeaten();
2726 break;
2727 }
2728 //}
2729 if (letGo) {
2730 if (withText) addText(getString("ongoingBattleLetGo"));
2732 }
2733
2736 } else {
2738 options.addOption("Perform a salvage operation, then leave", OptionId.LOOT_THEN_LEAVE, null);
2739 options.setShortcut(OptionId.LOOT_THEN_LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2740 } else {
2741 options.addOption("Leave", OptionId.LEAVE, null);
2742 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2743 }
2744 }
2745 } else {
2747 boolean hostile = false;
2748 if (ai != null) {
2750 }
2751
2752 options.addOption("Pursue them", OptionId.PURSUE, getString(pursueTooltip));
2753
2754 if (playerHasReadyShips) {
2755 options.addOption("Maneuver to force a pitched battle", OptionId.FORCE_ENGAGE, "Outmaneuver the opposing fleet, forcing them to fight you head on.");
2756 boolean knows = context.getBattle() != null && context.getBattle().getNonPlayerSide() != null &&
2758 boolean lowImpact = context.isLowRepImpact() || context.isNoRepImpact();
2760 //if (!playerFleet.getFaction().isHostileTo(otherFleet.getFaction()) && knows && !context.isEngagedInHostilities()) {
2761 if (nonHostile != null && knows && !lowImpact && !context.isEngagedInHostilities() &&
2762 config.showWarningDialogWhenNotHostile) {
2763 options.addOptionConfirmation(OptionId.FORCE_ENGAGE, "The " + nonHostile.getDisplayNameLong() + " " + nonHostile.getDisplayNameIsOrAre() + " not currently hostile, and you have been positively identified. Are you sure you want to engage one of their fleets?", "Yes", "Never mind");
2764 }
2765 } else {
2766 options.addOption("Maneuver to force a pitched battle", OptionId.ENGAGE, getString("tooltipNoReadyShips"));
2767 options.setEnabled(OptionId.FORCE_ENGAGE, false);
2768 }
2769 SetStoryOption.set(dialog, 1, OptionId.FORCE_ENGAGE, "forceBattle", Sounds.STORY_POINT_SPEND_COMBAT,
2770 "Maneuvered to force pitched battle with " + otherFleet.getNameWithFactionKeepCase());
2771
2772 options.addOption("Harry their retreat", OptionId.HARRY_PURSUE, getString(harassTooltip));
2773 boolean knows = context.getBattle() != null && context.getBattle().getNonPlayerSide() != null &&
2775 boolean lowImpact = context.isLowRepImpact() || context.isNoRepImpact();
2777 //if (!playerFleet.getFaction().isHostileTo(otherFleet.getFaction()) && knows && !context.isEngagedInHostilities()) {
2778 if (nonHostile != null && knows && !lowImpact && !context.isEngagedInHostilities() &&
2779 config.showWarningDialogWhenNotHostile) {
2780 options.addOptionConfirmation(OptionId.HARRY_PURSUE, "The " + nonHostile.getDisplayNameLong() + " " + nonHostile.getDisplayNameIsOrAre() + " not currently hostile, and you have been positively identified. Are you sure you want to engage in hostilities with one of their fleets?", "Yes", "Never mind");
2781 options.addOptionConfirmation(OptionId.PURSUE, "The " + nonHostile.getDisplayNameLong() + " " + nonHostile.getDisplayNameIsOrAre() + " not currently hostile, and you have been positively identified. Are you sure you want to engage in hostilities with one of their fleets?", "Yes", "Never mind");
2782 }
2783 if (hostile) {
2784 options.addOption("Let them go", OptionId.LET_THEM_GO, getString(letThemGoTooltip));
2785 } else {
2786 options.addOption("Leave", OptionId.LEAVE, null);
2787 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2788// options.addOption("Go back", OptionId.GO_TO_MAIN, null);
2789// options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true);
2790 }
2791
2792 if (!canPursue || !playerHasReadyShips) {
2793 options.setEnabled(OptionId.PURSUE, false);
2794 }
2795 if (!canHasass || !playerHasReadyShips) {
2796 options.setEnabled(OptionId.HARRY_PURSUE, false);
2797 }
2798 }
2799 } else {
2800 if (ongoingBattle) {
2801 if (alliedWantsToRun) {
2802 if (withText && !config.straightToEngage) addText(getString("ongoingBattleDisengage"));
2805 options.addOption("Join the disengage attempt", OptionId.CONTINUE_ONGOING_BATTLE, null);
2806 } else {
2807 boolean station = false;
2808 if (playerFleet != null) {
2810 if (member.isStation()) {
2811 station = true;
2812 break;
2813 }
2814 }
2815 }
2816
2817 if (withText && !config.straightToEngage) {
2818 if (station) {
2819 addText(getString("ongoingBattleStation"));
2820 } else {
2821 addText(getString("ongoingBattleEngage"));
2822 }
2823 }
2826
2827 if (playerHasReadyShips) {
2828 options.addOption("Join the engagement", OptionId.CONTINUE_ONGOING_BATTLE, null);
2829 } else {
2830 options.addOption("Join the engagement", OptionId.CONTINUE_ONGOING_BATTLE, getString("tooltipNoReadyShips"));
2831 options.setEnabled(OptionId.CONTINUE_ONGOING_BATTLE, false);
2832 }
2833
2834 options.addOption("Leave", OptionId.LEAVE, null);
2835 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2836 }
2837 } else {
2838 String engageText = "Move in to engage";
2839 if (config.firstTimeEngageOptionText != null && !context.isEngagedInHostilities()) {
2840 engageText = config.firstTimeEngageOptionText;
2841 }
2842 if (config.afterFirstTimeEngageOptionText != null && context.isEngagedInHostilities()) {
2843 engageText = config.afterFirstTimeEngageOptionText;
2844 }
2845 if (playerHasReadyShips) {
2846 options.addOption(engageText, OptionId.ENGAGE, getString("tooltipEngage"));
2847 boolean knows = context.getBattle() != null && context.getBattle().getNonPlayerSide() != null &&
2849 boolean lowImpact = context.isLowRepImpact() || context.isNoRepImpact();
2851 //if (!playerFleet.getFaction().isHostileTo(otherFleet.getFaction()) && knows && !context.isEngagedInHostilities()) {
2852 if (nonHostile != null && knows && !lowImpact && !context.isEngagedInHostilities() &&
2853 config.showWarningDialogWhenNotHostile) {
2854 options.addOptionConfirmation(OptionId.ENGAGE, "The " + nonHostile.getDisplayNameLong() + " " + nonHostile.getDisplayNameIsOrAre() + " not currently hostile, and you have been positively identified. Are you sure you want to engage one of their fleets?", "Yes", "Never mind");
2855 }
2856 } else {
2857 options.addOption(engageText, OptionId.ENGAGE, getString("tooltipNoReadyShips"));
2858 options.setEnabled(OptionId.ENGAGE, false);
2859 }
2861 boolean hostile = false;
2862 if (ai != null) {
2864 }
2865 //if (!config.noLeaveOption) {
2866 boolean noLeave = !context.isEngagedInHostilities() && config.noLeaveOptionOnFirstEngagement;
2867 if (!noLeave) {
2868 if (!config.leaveAlwaysAvailable &&
2869 (otherFleetWantsToFight() || (hostile && !otherFleetWantsToDisengage()))) {
2871 options.addOption("Disengage", OptionId.DISENGAGE, getString("tooltipCleanDisengage"));
2873 options.addOption("Disengage", OptionId.DISENGAGE, getString("tooltipHarrassableDisengage"));
2874 } else {
2876 options.addOption("Leave", OptionId.LEAVE, null);
2877 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2878 // options.addOption("Go back", OptionId.GO_TO_MAIN, null);
2879 // options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true);
2880 } else {
2881 boolean addSPDisengage = true;
2882 if (canDisengage() || !playerHasReadyShips) {
2883 options.addOption("Attempt to disengage", OptionId.ATTEMPT_TO_DISENGAGE, getString("tootipAttemptToDisengage"));
2884
2885 addSPDisengage = true;
2886
2887 } else {
2888 boolean hasStation = false;
2889 boolean allStation = true;
2891 allStation &= curr.isStationMode();
2892 hasStation |= curr.isStationMode();
2893 }
2894
2895 if (hasStation) {
2896 if (allStation) {
2897 options.addOption("Disengage", OptionId.DISENGAGE, getString("tooltipCleanDisengage"));
2898 } else {
2899 options.addOption("Disengage", OptionId.DISENGAGE, getString("tooltipHarrassableDisengage"));
2900 }
2901 addSPDisengage = false;
2902 } else {
2903 if (withText && !shownTooLargeToRetreatMessage) {
2905 //addText(getString("playerTooLargeToDisengage"), getString("highlightTooLarge"), Misc.getNegativeHighlightColor());
2906 //addText(getString("playerTooLargeCanFightToDisengage"), getString("highlightCanFight"), Misc.getHighlightColor());
2907 LabelAPI label = textPanel.addParagraph(getString("playerTooLargeToDisengage"));
2908 label.setHighlight(getString("highlightTooLarge"), getString("highlightDisengage"));
2910 }
2911 }
2912 }
2913 if (addSPDisengage) {
2914 //options.addOption("Execute a series of special maneuvers, allowing you to disengage cleanly", OptionId.DISENGAGE);
2915 options.addOption("Disengage by executing a series of special maneuvers", OptionId.CLEAN_DISENGAGE,
2916 "Allows your fleet to disengage without being pursued.");
2917 SetStoryOption.set(dialog, 1, OptionId.CLEAN_DISENGAGE, "cleanDisengage", Sounds.STORY_POINT_SPEND_COMBAT,
2918 "Maneuvered to disengage from " + otherFleet.getNameWithFactionKeepCase());
2919
2921 }
2922 }
2923 }
2924 } else {
2925 options.addOption("Leave", OptionId.LEAVE, null);
2926 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2927 // options.addOption("Go back", OptionId.GO_TO_MAIN, null);
2928 // options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true);
2929 }
2930 }
2931 }
2932 }
2933
2934 if (playerOutBeforeAllies()) {
2935 if (!options.hasOption(OptionId.LEAVE) &&
2936 !options.hasOption(OptionId.LET_THEM_GO) &&
2937 !options.hasOption(OptionId.DISENGAGE)) {
2938 options.addOption("Leave", OptionId.LEAVE, null);
2939 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
2940 }
2941 }
2942
2943 if (Global.getSettings().isDevMode()) {
2945 }
2946
2947 // if it's an ongoing battle, this will all get cleared out by a subsequent call to updatePreCombat()
2948// if (!options.hasOption(OptionId.GO_TO_MAIN)) {
2949// options.addOption("Go back", OptionId.GO_TO_MAIN, null);
2950// options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true);
2951// }
2952
2953// if (Global.getSettings().isDevMode()) {
2954// DevMenuOptions.addOptions(dialog);
2955// }
2956 }
2957
2958 //addSPDisengage
2959 protected void addEmergencyRepairsOption() {
2960 if (didRepairs) return;
2961
2963 final List<FleetMemberAPI> members = new ArrayList<FleetMemberAPI>();
2964
2965 final float crThreshold = CRPluginImpl.MALFUNCTION_START;
2966 final float hullThreshold = 0.4f;
2967 final float bonusRepairAmount = 0.1f; // threshold + this = repair level
2968
2969 FleetMemberAPI flagship = fleet.getFlagship();
2970 if (flagship != null && !flagship.isMothballed()) {
2971 if (flagship.getStatus().getHullFraction() < hullThreshold ||
2972 flagship.getRepairTracker().getBaseCR() < crThreshold) {
2973 members.add(flagship);
2974 }
2975 }
2976
2977 for (FleetMemberAPI curr : fleet.getFleetData().getMembersListCopy()) {
2978 if (curr == flagship) continue;
2979 if (curr.isMothballed()) continue;
2980 if (!curr.getCaptain().isDefault()) {
2981 if (curr.getStatus().getHullFraction() < hullThreshold ||
2982 curr.getRepairTracker().getBaseCR() < crThreshold) {
2983 members.add(curr);
2984 }
2985 }
2986 if (members.size() > 12) break; // just in case, since these are listed in the dialog w/o a limit check
2987 }
2988
2989// for (FleetMemberAPI curr : fleet.getFleetData().getMembersListCopy()) {
2990// if (curr == flagship) continue;
2991// if (curr.isMothballed()) continue;
2992// if (!members.contains(curr)) {
2993// if (curr.getStatus().getHullFraction() < hullThreshold ||
2994// curr.getRepairTracker().getBaseCR() < crThreshold) {
2995// members.add(curr);
2996// }
2997// }
2998// if (members.size() > 12) break; // just in case, since these are listed in the dialog w/o a limit check
2999// }
3000//
3001 if (members.isEmpty()) return;
3002
3003 options.addOption("Perform limited emergency repairs", OptionId.EMERGENCY_REPAIRS,
3004 "Brings your flagship and a few officer-controlled ships back up to reasonable " +
3005 "combat readiness and repairs some hull damage.");
3006 StoryOptionParams params = new StoryOptionParams(OptionId.EMERGENCY_REPAIRS,
3007 1, "emergencyRepairs", Sounds.STORY_POINT_SPEND_COMBAT,
3008 "Performed emergency repairs when facing " + otherFleet.getNameWithFactionKeepCase());
3009
3010 SetStoryOption.set(dialog, params,
3011 new BaseOptionStoryPointActionDelegate(dialog, params) {
3012 @Override
3013 public void confirm() {
3014 float dpUsed = 0f;
3015 for (FleetMemberAPI member : members) {
3016 float dpRemaining = EMERGENCY_REPAIRS_MAX_DP - dpUsed;
3017 float shipDP = member.getDeploymentPointsCost();
3018 dpUsed += shipDP;
3019
3020 float fraction = dpRemaining / shipDP;
3021 if (fraction >= 0.99f) fraction = 1f;
3022
3023 float baseRepairCRLevel = crThreshold + bonusRepairAmount * (float) Math.random();
3024 float baseRepairHullLevel = hullThreshold + bonusRepairAmount * (float) Math.random();
3025
3026 float cr = member.getRepairTracker().getBaseCR();
3027 float repairedCR = cr + (baseRepairCRLevel - cr) * fraction;
3028 if (cr < repairedCR) {
3029 //member.getRepairTracker().setCR(cr + (repairedCR - cr) * fraction);
3030 member.getRepairTracker().applyCREvent(repairedCR - cr, "Emergency repairs");
3031 }
3032 float hull = member.getStatus().getHullFraction();
3033 float repairedHull = hull + (baseRepairHullLevel - hull) * fraction;
3034 if (hull < repairedHull) {
3035 member.getStatus().setHullFraction(repairedHull);
3036 }
3037
3040 textPanel.addPara(str + " performed emergency repairs", Misc.getPositiveHighlightColor());
3043
3044 if (fraction < 1f) {
3045 break;
3046 }
3047 }
3048 didRepairs = true;
3051 dialog.getOptionPanel().setEnabled(OptionId.EMERGENCY_REPAIRS, false);
3052 }
3053
3054 @Override
3055 public void createDescription(TooltipMakerAPI info) {
3056 super.createDescription(info);
3057 info.setParaFontDefault();
3058 float opad = 10f;
3059 float pad = 3f;
3060 info.addPara("Will bring up to %s deployment points worth of ships up " +
3061 "to approximately %s combat readiness and %s hull integrity. Starts with the " +
3062 "flagship and then goes on to officer-controlled ships, in the " +
3063 "order they are placed in the fleet. " +
3064 "Does not affect other ships.",
3065 0f, Misc.getHighlightColor(),
3066 "" + (int) EMERGENCY_REPAIRS_MAX_DP,
3067 "" + (int) Math.round((crThreshold + bonusRepairAmount) * 100f) + "%",
3068 "" + (int) Math.round((hullThreshold + bonusRepairAmount) * 100f) + "%"
3069 );
3070
3071 info.addPara("The repairs will affect:", opad);
3073 float initPad = 10f;
3074
3075 float dpUsed = 0f;
3076 for (FleetMemberAPI member : members) {
3077 float dpRemaining = EMERGENCY_REPAIRS_MAX_DP - dpUsed;
3078 float shipDP = member.getDeploymentPointsCost();
3079 dpUsed += shipDP;
3080
3081 dpUsed += shipDP;
3082
3083 float fraction = dpRemaining / shipDP;
3084 if (fraction >= 0.99f) fraction = 1f;
3085
3087
3088 String post = " (full effect)";
3089 if (fraction < 1) post = " (partial effect)";
3090
3091 info.addPara(str + post, initPad);
3092 initPad = 0f;
3093
3094 if (dpUsed >= EMERGENCY_REPAIRS_MAX_DP) break;
3095 }
3096 info.setBulletedListMode(null);
3097 info.addSpacer(20f);
3098 }
3099 });
3100// SetStoryOption.set(dialog, 1, OptionId.EMERGENCY_REPAIRS, "emergencyRepairs", Sounds.STORY_POINT_SPEND_COMBAT,
3101// "Performed emergency repairs when facing " + otherFleet.getNameWithFactionKeepCase());
3102 }
3103
3106
3107 if (fleet.getAI() == null) return PursuitOption.LET_THEM_GO;
3108
3109 if (config.alwaysPursue) {
3110 return PursuitOption.PURSUE;
3111 }
3112 if (config.alwaysHarry) {
3113 return PursuitOption.HARRY;
3114 }
3115 if (config.alwaysLetGo) {
3116 return PursuitOption.LET_THEM_GO;
3117 }
3118
3119 boolean allStation = false;
3120 boolean hasStation = false;
3121 if (context.getBattle() != null) {
3122 allStation = true;
3123 for (CampaignFleetAPI curr : context.getBattle().getSideFor(fleet)) {
3124// if (curr.isStationMode()) {
3125// return PursuitOption.HARRY;
3126// }
3127 allStation &= curr.isStationMode();
3128 hasStation |= curr.isStationMode();
3129 }
3130 //if (allStation) {
3131 }
3132
3133 PursuitOption option = fleet.getAI().pickPursuitOption(context, other);
3134 if (hasStation && option == PursuitOption.HARRY) {
3136 return PursuitOption.LET_THEM_GO;
3137 }
3138 return option;
3139 }
3140
3142 if (context.getBattle() == null) return null;
3143
3144 //BattleSide playerSide = context.getBattle().pickSide(Global.getSector().getPlayerFleet());
3145
3146 //List<CampaignFleetAPI> otherSide = context.getBattle().getSideFor(otherFleet);
3147 List<CampaignFleetAPI> otherSide = context.getBattle().getNonPlayerSide();
3148 return getNonHostileOtherFaction(otherSide);
3149 }
3150
3151 public FactionAPI getNonHostileOtherFaction(List<CampaignFleetAPI> otherSide) {
3153 int max = -1;
3154 CampaignFleetAPI result = null;
3155
3156 if (otherSide != null) {
3157 for (CampaignFleetAPI other : otherSide) {
3158 if (!player.isHostileTo(other.getFaction()) && other.getFleetPoints() > max) {
3159 result = other;
3160 max = other.getFleetPoints();
3161 }
3162 }
3163 }
3164 return result == null ? null : result.getFaction();
3165 }
3166
3167 protected boolean playerOutBeforeAllies() {
3168 EngagementOutcome last = context.getLastEngagementOutcome();
3169 if (last == EngagementOutcome.BATTLE_PLAYER_OUT_FIRST_WIN ||
3170 last == EngagementOutcome.BATTLE_PLAYER_OUT_FIRST_LOSS ||
3171 last == EngagementOutcome.PURSUIT_PLAYER_OUT_FIRST_WIN ||
3172 last == EngagementOutcome.PURSUIT_PLAYER_OUT_FIRST_LOSS ||
3173 last == EngagementOutcome.ESCAPE_PLAYER_OUT_FIRST_WIN ||
3174 last == EngagementOutcome.ESCAPE_PLAYER_OUT_FIRST_LOSS
3175 ) {
3176 return true;
3177 }
3178 return false;
3179 }
3180
3181 public static boolean canDisengage() {
3183 float total = 0f;
3185 if (member.canBeDeployedForCombat()) {
3186 total += member.getDeploymentPointsCost();
3187 }
3188 }
3189 return total <= getDisengageSize();
3190 }
3191
3192 protected boolean otherCanDisengage() {
3194 }
3195
3196 protected boolean alliedCanDisengage() {
3198 }
3199
3200 protected boolean fleetCanDisengage(CampaignFleetAPI fleet) {
3201 float total = 0f;
3202 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
3203 if (member.canBeDeployedForCombat()) {
3204 total += member.getDeploymentPointsCost();
3205 }
3206 }
3207 return total <= getDisengageSize();
3208 }
3209
3210 public static float getDisengageSize() {
3211 float abs = Global.getSettings().getFloat("maxDisengageSize");
3212 float fraction = Global.getSettings().getFloat("maxDisengageFraction") * Global.getSettings().getBattleSize();
3213 return Math.min(abs, fraction);
3214 }
3215
3216 protected boolean didEnoughToDisengage(CampaignFleetAPI fleet) {
3217 DataForEncounterSide data = context.getDataFor(fleet);
3218 return data.isDidEnoughToDisengage();
3219 }
3220
3221 protected boolean canDisengageCleanly(CampaignFleetAPI fleet) {
3222 //if (wasEnemyDisrupted(fleet)) return true;
3223 DataForEncounterSide data = context.getDataFor(fleet);
3224 if (data.isWonLastEngagement()) return true;
3225
3226 if (data.isDidEnoughToDisengage()) return true;
3227
3228 if (fleet == playerFleet) {
3229 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
3230 if (member.isStation()) return true;
3231 }
3232 }
3233
3234 EngagementOutcome last = context.getLastEngagementOutcome();
3235 if (fleet == playerFleet && !ongoingBattle &&
3236 (last == EngagementOutcome.BATTLE_PLAYER_OUT_FIRST_WIN ||
3237 last == EngagementOutcome.BATTLE_PLAYER_OUT_FIRST_LOSS ||
3238 last == EngagementOutcome.PURSUIT_PLAYER_OUT_FIRST_WIN ||
3239 last == EngagementOutcome.PURSUIT_PLAYER_OUT_FIRST_LOSS ||
3240 last == EngagementOutcome.ESCAPE_PLAYER_OUT_FIRST_WIN ||
3241 last == EngagementOutcome.ESCAPE_PLAYER_OUT_FIRST_LOSS)) {
3242 return true;
3243 }
3244
3245 return false;
3246 }
3249 if (other == fleet) other = otherFleet;
3250 PursueAvailability pa = getPursuitAvailability(other);
3251 return pa != PursueAvailability.AVAILABLE;
3252 }
3253
3254 protected PursueAvailability getPursuitAvailability(CampaignFleetAPI fleet) {
3256 if (other == fleet) other = otherFleet;
3257 PursueAvailability pa = context.getPursuitAvailability(fleet, other);
3258 if (pa == PursueAvailability.TOO_SLOW && fleet == playerFleet) {
3259 pa = PursueAvailability.AVAILABLE;
3260 }
3261 return pa;
3262 }
3263
3264 protected String getString(String id) {
3265 String str = Global.getSettings().getString("fleetInteractionDialog", id);
3266
3267 String faction = otherFleet.getFaction().getEntityNamePrefix();
3268 if (faction == null || faction.isEmpty()) {
3269 faction = otherFleet.getFaction().getDisplayName();
3270 }
3271
3273 faction = "opposing";
3274 }
3275
3276 String fleetName = otherFleet.getName();
3277 String firstName = otherFleet.getCommander().getName().getFirst();
3278 String lastName = otherFleet.getCommander().getName().getLast();
3279 String fleetOrShip = "fleet";
3280 if (otherFleet.getFleetData().getMembersListCopy().size() == 1) {
3281 fleetOrShip = "ship";
3282 if (otherFleet.getFleetData().getMembersListCopy().get(0).isFighterWing()) {
3283 fleetOrShip = "fighter wing";
3284 }
3285 }
3286 String playerFleetOrShip = "fleet";
3287 if (playerFleet.getFleetData().getMembersListCopy().size() == 1) {
3288 playerFleetOrShip = "ship";
3289 if (playerFleet.getFleetData().getMembersListCopy().get(0).isFighterWing()) {
3290 playerFleetOrShip = "fighter wing";
3291 }
3292 }
3293
3294 DataForEncounterSide data = context.getDataFor(playerFleet);
3295 if (data != null) {
3296 int crewLost = (int) (data.getCrewLossesDuringLastEngagement().getCrewInt());
3297 String crewLostStr = getApproximate(crewLost);
3298
3299 int marinesLost = (int) (data.getCrewLossesDuringLastEngagement().getMarines());
3300 String marinesLostStr = getApproximate(marinesLost);
3301
3302 int crewRecovered = (int) data.getRecoverableCrewLosses().getCrewInt();
3303 int marinesRecovered = (int) data.getRecoverableCrewLosses().getMarines();
3304
3305 String crewRecStr = "" + crewRecovered;
3306 if (crewRecovered <= 0) {
3307 crewRecStr = "no";
3308 }
3309 String marinesRecStr = "" + marinesRecovered;
3310 if (marinesRecovered <= 0) {
3311 marinesRecStr = "no";
3312 }
3313
3314 str = str.replaceAll("\\$crewLost", crewLostStr);
3315 str = str.replaceAll("\\$marinesLost", marinesLostStr);
3316 str = str.replaceAll("\\$crewLost", crewLostStr);
3317 str = str.replaceAll("\\$crewRecovered", crewRecStr);
3318 str = str.replaceAll("\\$marinesRecovered", marinesRecStr);
3319 }
3320
3321 if (toBoard != null) {
3322 int numLifeSigns = (int) (toBoard.getCrewComposition().getCrew() + toBoard.getCrewComposition().getMarines());
3323 str = str.replaceAll("\\$numLifeSigns", getApproximate(numLifeSigns));
3324
3325 str = str.replaceAll("\\$boardableShipName", toBoard.getShipName());
3326 }
3327
3328 str = str.replaceAll("\\$faction", faction);
3329 str = str.replaceAll("\\$fleetName", fleetName);
3330 str = str.replaceAll("\\$firstName", firstName);
3331 str = str.replaceAll("\\$lastName", lastName);
3332 str = str.replaceAll("\\$fleetOrShip", fleetOrShip);
3333 str = str.replaceAll("\\$playerFleetOrShip", playerFleetOrShip);
3334
3335 if (selectedFlagship != null) {
3336 str = str.replaceAll("\\$flagship", "the " + selectedFlagship.getShipName());
3337 }
3338
3339 str = str.replaceAll("\\$creditsLooted", creditsLooted);
3340
3341 if (crashMothballList != null) {
3342 str = str.replaceAll("\\$crashMothballList", crashMothballList);
3343 }
3344
3345 if (repairedShipList != null) {
3346 str = str.replaceAll("\\$repairedShipList", repairedShipList);
3347 }
3348
3349 int marines = Global.getSector().getPlayerFleet().getCargo().getMarines();
3350 str = str.replaceAll("\\$marines", "" + marines);
3351
3352 str = str.replaceAll("\\$boardingSuccessChance", "" + (int) boardingPercentSuccess + "%");
3353
3354 if (boardingResult != null) {
3355 str = str.replaceAll("\\$boardingCrewLost", getIntOrNo(boardingResult.getAttackerLosses().getCrew()));
3356 str = str.replaceAll("\\$boardingMarinesLost", getIntOrNo(boardingResult.getAttackerLosses().getMarines()));
3357 str = str.replaceAll("\\$boardingEnemyCrewLost", getIntOrNo(boardingResult.getDefenderLosses().getCrew()));
3358 str = str.replaceAll("\\$boardingEnemyMarinesLost", getIntOrNo(boardingResult.getDefenderLosses().getMarines()));
3359 }
3360
3361// # $alliedFactionAndTheirAllies "Hegemony forces and their allies"
3362// # $enemyFactionAndTheirAllies "Hegemony forces and their allies"
3363// # $yourForcesWereOrYourSideWas
3365 if (b != null) {
3366 BattleSide playerSide = b.pickSide(Global.getSector().getPlayerFleet());
3367 CampaignFleetAPI sideOnePrimary = b.getPrimary(b.getSideOne());
3368 CampaignFleetAPI sideTwoPrimary = b.getPrimary(b.getSideTwo());
3369 if (playerSide != BattleSide.NO_JOIN) {
3370 sideOnePrimary = b.getPrimary(b.getSide(playerSide));
3371 sideTwoPrimary = b.getPrimary(b.getOtherSide(playerSide));
3372 }
3373
3374 if (sideOnePrimary != null) {
3375 String strOne = sideOnePrimary.getFaction().getEntityNamePrefix() + " forces";
3376 if (strOne.startsWith(" ")) {
3377 strOne = sideOnePrimary.getFaction().getDisplayName() + " forces";
3378 }
3379// if (b.isStationInvolved(b.getSideFor(sideOnePrimary))) {
3380// strOne = strOne.replaceFirst(" forces", " station");
3381// }
3382 for (CampaignFleetAPI fleet : b.getSideFor(sideOnePrimary)) {
3383 if (fleet.getFaction() != sideOnePrimary.getFaction()) {
3384 if (fleet.isPlayerFleet()) continue;
3385 strOne += " and their allies";
3386 break;
3387 }
3388 }
3389 str = str.replaceAll("\\$alliedFactionAndTheirAllies", strOne);
3390 }
3391 if (sideTwoPrimary != null) {
3392 String strTwo = sideTwoPrimary.getFaction().getEntityNamePrefix() + " forces";
3393 if (strTwo.startsWith(" ")) {
3394 strTwo = sideTwoPrimary.getFaction().getDisplayName() + " forces";
3395 }
3396// if (b.isStationInvolved(b.getSideFor(sideTwoPrimary))) {
3397// strTwo = strTwo.replaceFirst(" forces", " station");
3398// }
3399 for (CampaignFleetAPI fleet : b.getSideFor(sideTwoPrimary)) {
3400 if (fleet.getFaction() != sideTwoPrimary.getFaction()) {
3401 if (fleet.isPlayerFleet()) continue;
3402 strTwo += " and their allies";
3403 break;
3404 }
3405 }
3406 str = str.replaceAll("\\$enemyFactionAndTheirAllies", strTwo);
3407 }
3408
3409 //$yourForcesWereOrYourSideWas
3410 String yourForcesWere = "Your forces were";
3411 if (b.getPlayerSide() != null && b.getPlayerSide().size() > 1) {
3412 yourForcesWere = "Your side was";
3413 }
3414 str = str.replaceAll("\\$yourForcesWereOrYourSideWas", yourForcesWere);
3415 }
3416
3417
3418// float recoveryFraction = context.getStandDownRecoveryFraction();
3419// str = str.replaceAll("\\$standDownRecovery", "" + (int) (recoveryFraction * 100f));
3420
3421 return str;
3422 }
3423
3424 protected String getIntOrNo(float value) {
3425 if (value < 1) {
3426 return "no";
3427 }
3428 return "" + (int) value;
3429 }
3430
3431 protected String getApproximate(float value) {
3432 int v = (int) value;
3433 String str = "multiple";
3434 if (v <= 0) {
3435 str = "no";
3436 } else if (v < 10) {
3437 str = "" + v;
3438 } else if (v < 100) {
3439 v = (int) Math.round((float) v/10f) * 10;
3440 str = "approximately " + v;
3441 } else if (v < 1000) {
3442 v = (int) Math.round((float) v/10f) * 10;
3443 str = "approximately " + v;
3444 } else {
3445 v = (int) Math.round((float) v/100f) * 100;
3446 str = "" + v;
3447 }
3448 return str;
3449 }
3450
3451 protected String getApproximateNumOnly(float value) {
3452 int v = (int) value;
3453 String str = "";
3454 if (v <= 0) {
3455 str = "asdasd";
3456 } else if (v < 10) {
3457 str = "" + v;
3458 } else if (v < 100) {
3459 v = (int) Math.round((float) v/10f) * 10;
3460 str = "" + v;
3461 } else if (v < 1000) {
3462 v = (int) Math.round((float) v/10f) * 10;
3463 str = "" + v;
3464 } else {
3465 v = (int) Math.round((float) v/100f) * 100;
3466 str = "" + v;
3467 }
3468 return str;
3469 }
3470
3471
3472 protected boolean isFightingOver() {
3473 return context.isBattleOver() ||
3474 (context.getDataFor(otherFleet).disengaged() && context.getDataFor(playerFleet).disengaged());
3475// return context.getDataFor(playerFleet).getLastGoal() == FleetGoal.ESCAPE ||
3476// context.getDataFor(otherFleet).getLastGoal() == FleetGoal.ESCAPE;
3477 //return context.getWinnerData().getLastGoal() == FleetGoal.ESCAPE || context.getLoserData().getLastGoal() == FleetGoal.ESCAPE;
3478 }
3479
3480 public boolean alliedFleetWantsToFight() {
3482 }
3483 public boolean otherFleetWantsToFight() {
3485 }
3486 public boolean otherFleetWantsToFight(boolean assumeHostile) {
3487 return fleetWantsToFight(otherFleet, playerFleet, assumeHostile);
3488 }
3489 protected boolean fleetWantsToFight(CampaignFleetAPI fleet, CampaignFleetAPI other) {
3490 return fleetWantsToFight(fleet, other, false);
3491 }
3492 protected boolean fleetWantsToFight(CampaignFleetAPI fleet, CampaignFleetAPI other, boolean assumeHostile) {
3493 if (config.alwaysAttackVsAttack) return true;
3494
3495 boolean hasNonCivReserves = false;
3496 for (FleetMemberAPI member : context.getDataFor(fleet).getInReserveDuringLastEngagement()) {
3497 if (!member.isCivilian()) {
3498 hasNonCivReserves = true;
3499 break;
3500 }
3501 }
3503 !context.getDataFor(fleet).isWonLastEngagement() &&
3504 !hasNonCivReserves) {
3505 return false;
3506 }
3507
3508 CampaignFleetAIAPI ai = fleet.getAI();
3509 if (ai == null) return false;
3510 EncounterOption option = ai.pickEncounterOption(context, other);
3511
3513
3514 return (ai.isHostileTo(other) || context.isEngagedInHostilities() || assumeHostile ||
3516 // "aggressive" just means "always engage IF already hostile"
3517 //fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE)
3518 ) &&
3519 (option == EncounterOption.ENGAGE || (option == EncounterOption.HOLD && ongoingBattle));
3520 }
3521
3522
3523
3528// if (otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_MAKE_HOLD_VS_STRONGER_COMBAT_ONLY)) {
3529// return true;
3530// }
3532 }
3534 CampaignFleetAIAPI ai = fleet.getAI();
3535 if (ai == null) return false;
3536 boolean hostile = ai.isHostileTo(other) || (other.getAI() != null && other.getAI().isHostileTo(fleet)) || context.isEngagedInHostilities();
3537 if (!hostile) return false;
3538
3539 if (ai.pickEncounterOption(context, other) == EncounterOption.HOLD_VS_STRONGER) return true;
3540
3541 return fleetWantsToDisengage(fleet, other) && !fleetCanDisengage(fleet);
3542 }
3543
3547
3548 protected boolean otherFleetWantsToDisengage() {
3550 }
3552 if (config.alwaysAttackVsAttack) return false;
3553
3554 boolean hasNonCivReserves = false;
3555 for (FleetMemberAPI member : context.getDataFor(fleet).getInReserveDuringLastEngagement()) {
3556 if (!member.isCivilian()) {
3557 hasNonCivReserves = true;
3558 break;
3559 }
3560 }
3562 !context.getDataFor(fleet).isWonLastEngagement() &&
3563 !hasNonCivReserves) {
3564 return true;
3565 }
3566
3567 CampaignFleetAIAPI ai = fleet.getAI();
3568 if (ai == null) return false;
3569 return ai.pickEncounterOption(context, other) == EncounterOption.DISENGAGE;
3570 }
3571
3572 public Object getContext() {
3573 return context;
3574 }
3575
3576 public void updateMemory() {
3577 if (conversationDelegate != null) {
3579 }
3580 }
3581
3587
3589 if (mission == null) {
3591 } else {
3592 MemoryAPI memory = mission.getMemory();
3593 if (memory != null) {
3595 } else {
3597 }
3598 }
3599 }
3601 this.playerFleet = playerFleet;
3602 }
3603
3604
3605}
3606
3607
3608
static SettingsAPI getSettings()
Definition Global.java:57
static FactoryAPI getFactory()
Definition Global.java:41
static SectorAPI getSector()
Definition Global.java:65
static void reportShipsRecovered(List< FleetMemberAPI > ships, InteractionDialogAPI dialog)
void resolvePlayerPursuit(FleetEncounterContext context, List< FleetMemberAPI > playerShipsToDeploy)
static void execute(InteractionDialogAPI dialog, String option)
static boolean isDevOption(Object optionData)
static void addOptions(InteractionDialogAPI dialog)
List< FleetMemberAPI > getRecoverableShips(BattleAPI battle, CampaignFleetAPI winningFleet, CampaignFleetAPI otherFleet)
void generateLoot(List< FleetMemberAPI > recoveredShips, boolean withCredits)
boolean adjustPlayerReputation(InteractionDialogAPI dialog, String ffText)
void applyPursuitOption(CampaignFleetAPI pursuingFleet, CampaignFleetAPI otherFleet, PursuitOption pursuitOption)
BoardingResult boardShip(FleetMemberAPI member, CampaignFleetAPI attacker, CampaignFleetAPI defender)
DataForEncounterSide getDataFor(CampaignFleetAPI participantOrCombined)
static void recoverShips(List< FleetMemberAPI > ships, FleetEncounterContext context, CampaignFleetAPI winningFleet, CampaignFleetAPI otherFleet)
PursueAvailability getPursuitAvailability(CampaignFleetAPI fleet, CampaignFleetAPI otherFleet)
EngageBoardableOutcome engageBoardableShip(FleetMemberAPI toBoard, CampaignFleetAPI fleetItBelongsTo, CampaignFleetAPI attackingFleet)
void setPlayerFPHullDamageToEnemies(float playerFPHullDamageToEnemies)
DisengageHarryAvailability getDisengageHarryAvailability(CampaignFleetAPI fleet, CampaignFleetAPI otherFleet)
void letBoardableGo(FleetMemberAPI toBoard, CampaignFleetAPI fleetItBelongsTo, CampaignFleetAPI attackingFleet)
boolean fleetHoldingVsStrongerEnemy(CampaignFleetAPI fleet, CampaignFleetAPI other)
boolean fleetWantsToFight(CampaignFleetAPI fleet, CampaignFleetAPI other, boolean assumeHostile)
PursuitOption pickPursuitOption(CampaignFleetAPI fleet, CampaignFleetAPI other, FleetEncounterContext context)
boolean fleetWantsToDisengage(CampaignFleetAPI fleet, CampaignFleetAPI other)
static final String FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN
static final String MEMORY_KEY_SKIP_TRANSPONDER_STATUS_INFO
static final String MEMORY_KEY_RECENTLY_DEFEATED_BY_PLAYER
boolean execute(String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
static boolean fire(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
Definition FireBest.java:56
static boolean set(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
static Color getStoryOptionColor()
Definition Misc.java:782
static String getWithDGS(float num)
Definition Misc.java:1381
static Color getButtonTextColor()
Definition Misc.java:842
static List< String > getDefeatTriggers(CampaignFleetAPI fleet, boolean createIfNecessary)
Definition Misc.java:5934
static List< FleetMemberAPI > getSnapshotMembersLost(CampaignFleetAPI fleet)
Definition Misc.java:748
static String ucFirst(String str)
Definition Misc.java:559
static Color getNegativeHighlightColor()
Definition Misc.java:802
static Random getRandom(long seed, int level)
Definition Misc.java:2973
static boolean isAutomated(MutableShipStatsAPI stats)
Definition Misc.java:5491
static Pair< SectorEntityToken, CampaignFleetAPI > getNearestStationInSupportRange(CampaignFleetAPI from)
Definition Misc.java:4789
static Color getGrayColor()
Definition Misc.java:826
static void clearDefeatTriggersIfNeeded(CampaignFleetAPI fleet)
Definition Misc.java:5947
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static Color getHighlightedOptionColor()
Definition Misc.java:788
static Color getHighlightColor()
Definition Misc.java:792
static boolean isUnremovable(PersonAPI person)
Definition Misc.java:5473
static float getBattleJoinRange()
Definition Misc.java:2227
static Color getPositiveHighlightColor()
Definition Misc.java:822
BattleAPI createBattle(CampaignFleetAPI one, CampaignFleetAPI two)
CombatReadinessPlugin getCRPlugin()
String getString(String category, String id)
List< CampaignFleetAPI > getPlayerSideSnapshot()
List< CampaignFleetAPI > getSideOne()
CampaignFleetAPI getPrimary(List< CampaignFleetAPI > side)
List< CampaignFleetAPI > getSideFor(CampaignFleetAPI participantOrCombined)
boolean join(CampaignFleetAPI fleet)
List< CampaignFleetAPI > getOtherSide(BattleSide side)
List< CampaignFleetAPI > getSideTwo()
List< CampaignFleetAPI > getSide(BattleSide side)
void leave(CampaignFleetAPI fleet, boolean engagedInHostilities)
BattleSide pickSide(CampaignFleetAPI fleet)
CampaignFleetAPI getOtherSideCombined(BattleSide side)
boolean canJoin(CampaignFleetAPI fleet)
CampaignFleetAPI getSourceFleet(FleetMemberAPI member)
List< CampaignFleetAPI > getNonPlayerSideSnapshot()
boolean knowsWhoPlayerIs(List< CampaignFleetAPI > side)
List< CampaignFleetAPI > getBothSides()
void applyVisibilityMod(CampaignFleetAPI fleet)
List< CampaignFleetAPI > getNonPlayerSide()
CampaignFleetAPI getCombined(BattleSide side)
List< CampaignFleetAPI > getPlayerSide()
float getBaseSensorRangeToDetect(float sensorProfile)
MutableCharacterStatsAPI getCommanderStats()
boolean isHostileTo(FactionAPI other)
void setFlagship(FleetMemberAPI flagship)
void sortToMatchOrder(List< FleetMemberAPI > originalOrder)
List< FleetMemberAPI > getCombatReadyMembersListCopy()
List< FleetMemberAPI > getMembersListCopy()
void setInteractionTarget(SectorEntityToken interactionTarget)
void setPlugin(InteractionDialogPlugin plugin)
void startBattle(BattleCreationContext context)
void setOptionOnConfirm(String text, Object optionId)
void showFleetMemberRecoveryDialog(String title, List< FleetMemberAPI > pool, FleetMemberPickerListener listener)
void showFleetMemberPickerDialog(String title, String okText, String cancelText, int rows, int cols, float iconSize, boolean canPickNotReady, boolean canPickMultiple, List< FleetMemberAPI > pool, FleetMemberPickerListener listener)
void setOptionOnEscape(String text, Object optionId)
List< CampaignFleetAPI > getFleets()
void setTooltip(Object data, String tooltipText)
void addOptionConfirmation(Object optionId, String text, String yes, String no)
void addOption(String text, Object data)
void setEnabled(Object data, boolean enabled)
void setShortcut(Object data, int code, boolean ctrl, boolean alt, boolean shift, boolean putLast)
void reportEncounterLootGenerated(FleetEncounterContextPlugin plugin, CargoAPI loot)
void setActivePerson(PersonAPI activePerson)
void highlightFirstInLastPara(String text, Color color)
void highlightInLastPara(Color color, String ...strings)
void highlightLastInLastPara(String text, Color color)
void setVisualFade(float in, float out)
boolean isShowingPersonInfo(PersonAPI person)
void showLoot(String title, CargoAPI otherCargo, boolean generatePods, CoreInteractionListener listener)
CustomPanelAPI showCustomPanel(float width, float height, CustomUIPanelPlugin plugin)
void showFleetMemberInfo(FleetMemberAPI member)
void showPreBattleJoinInfo(String playerTitle, CampaignFleetAPI playerFleet, String titleOne, String titleTwo, FleetEncounterContextPlugin context)
void showFleetInfo(String titleOne, CampaignFleetAPI one, String titleTwo, CampaignFleetAPI two)
EncounterOption pickEncounterOption(FleetEncounterContextPlugin context, CampaignFleetAPI otherFleet)
InitialBoardingResponse pickBoardingResponse(FleetEncounterContextPlugin context, FleetMemberAPI toBoard, CampaignFleetAPI otherFleet)
PursuitOption pickPursuitOption(FleetEncounterContextPlugin context, CampaignFleetAPI otherFleet)
boolean isHostileTo(CampaignFleetAPI other)
void performCrashMothballingPriorToEscape(FleetEncounterContextPlugin context, CampaignFleetAPI playerFleet)
void set(String key, Object value)
boolean is(String key, Object value)
RuleAPI getBestMatching(String currentRule, String trigger, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
float getMalfunctionThreshold(MutableShipStatsAPI stats)
EngagementResultForFleetAPI getLoserResult()
EngagementResultForFleetAPI getWinnerResult()
void setCaptain(PersonAPI commander)
void setHighlight(int start, int end)
void setHighlightColor(Color color)
void setHighlightColors(Color ... colors)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)
UIComponentAPI addSpacer(float height)
void setBulletedListMode(String itemPrefix)