001package com.fs.starfarer.api.impl.campaign; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.List; 006import java.util.Map; 007import java.util.Random; 008 009import java.awt.Color; 010 011import org.lwjgl.input.Keyboard; 012 013import com.fs.starfarer.api.Global; 014import com.fs.starfarer.api.campaign.BattleAPI; 015import com.fs.starfarer.api.campaign.BattleAPI.BattleSide; 016import com.fs.starfarer.api.campaign.CampaignFleetAPI; 017import com.fs.starfarer.api.campaign.CargoAPI; 018import com.fs.starfarer.api.campaign.CoreInteractionListener; 019import com.fs.starfarer.api.campaign.EngagementResultForFleetAPI; 020import com.fs.starfarer.api.campaign.FactionAPI; 021import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.DataForEncounterSide; 022import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.DisengageHarryAvailability; 023import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.EngagementOutcome; 024import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.PursueAvailability; 025import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.Status; 026import com.fs.starfarer.api.campaign.FleetMemberPickerListener; 027import com.fs.starfarer.api.campaign.InteractionDialogAPI; 028import com.fs.starfarer.api.campaign.InteractionDialogPlugin; 029import com.fs.starfarer.api.campaign.OptionPanelAPI; 030import com.fs.starfarer.api.campaign.RuleBasedDialog; 031import com.fs.starfarer.api.campaign.SectorEntityToken; 032import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel; 033import com.fs.starfarer.api.campaign.TextPanelAPI; 034import com.fs.starfarer.api.campaign.VisualPanelAPI; 035import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI; 036import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.EncounterOption; 037import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.InitialBoardingResponse; 038import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.PursuitOption; 039import com.fs.starfarer.api.campaign.events.CampaignEventPlugin; 040import com.fs.starfarer.api.campaign.listeners.ListenerUtil; 041import com.fs.starfarer.api.campaign.rules.MemKeys; 042import com.fs.starfarer.api.campaign.rules.MemoryAPI; 043import com.fs.starfarer.api.campaign.rules.RuleAPI; 044import com.fs.starfarer.api.campaign.rules.RulesAPI; 045import com.fs.starfarer.api.characters.PersonAPI; 046import com.fs.starfarer.api.combat.BattleCreationContext; 047import com.fs.starfarer.api.combat.CombatReadinessPlugin; 048import com.fs.starfarer.api.combat.EngagementResultAPI; 049import com.fs.starfarer.api.fleet.CrewCompositionAPI; 050import com.fs.starfarer.api.fleet.FleetGoal; 051import com.fs.starfarer.api.fleet.FleetMemberAPI; 052import com.fs.starfarer.api.impl.campaign.FleetEncounterContext.BoardingResult; 053import com.fs.starfarer.api.impl.campaign.FleetEncounterContext.EngageBoardableOutcome; 054import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 055import com.fs.starfarer.api.impl.campaign.ids.Sounds; 056import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin; 057import com.fs.starfarer.api.impl.campaign.rulecmd.DumpMemory; 058import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest; 059import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption; 060import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.BaseOptionStoryPointActionDelegate; 061import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.StoryOptionParams; 062import com.fs.starfarer.api.impl.campaign.skills.BaseSkillEffectDescription; 063import com.fs.starfarer.api.impl.combat.CRPluginImpl; 064import com.fs.starfarer.api.ui.LabelAPI; 065import com.fs.starfarer.api.ui.TooltipMakerAPI; 066import com.fs.starfarer.api.util.Misc; 067import com.fs.starfarer.api.util.Pair; 068 069public class FleetInteractionDialogPluginImpl implements InteractionDialogPlugin, RuleBasedDialog { 070 071 public static float EMERGENCY_REPAIRS_MAX_DP = Global.getSettings().getFloat("emergencyRepairsMaxDPValue"); 072 073 public static String DO_NOT_AUTO_SHOW_FC_PORTRAIT = "$doNotAutoShowFleetCommanderPortrait"; 074 075 public static interface FIDConfigGen { 076 FIDConfig createConfig(); 077 } 078 079 public static class FIDConfig { 080 public boolean showCommLinkOption = true; 081 public boolean leaveAlwaysAvailable = false; 082 public boolean showWarningDialogWhenNotHostile = true; 083 public boolean showTransponderStatus = true; 084 public boolean showFleetAttitude = true; 085 public boolean showEngageText = true; 086 public boolean alwaysAttackVsAttack = false; 087 public boolean alwaysPursue = false; 088 public boolean alwaysHarry = false; 089 public boolean alwaysLetGo = false; 090 public boolean dismissOnLeave = true; 091 public boolean withSalvage = true; 092 public boolean lootCredits = true; 093 094 public boolean showCrRecoveryText = true; 095 096 public boolean showVictoryText = true; 097 098 //public boolean postLootLeaveHasShortcut = true; 099 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 210 protected InteractionDialogAPI dialog; 211 protected TextPanelAPI textPanel; 212 protected OptionPanelAPI options; 213 protected VisualPanelAPI visual; 214 215 protected CampaignFleetAPI playerFleet; 216 protected CampaignFleetAPI otherFleet; 217 218 protected FleetGoal playerGoal = FleetGoal.ATTACK; 219 protected FleetGoal otherGoal = FleetGoal.ATTACK; 220 221 protected VisualType currVisualType = VisualType.FLEET_INFO; 222 223 protected FleetEncounterContext context = new FleetEncounterContext(); 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 229 protected RuleBasedInteractionDialogPluginImpl conversationDelegate; 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 249 public FleetInteractionDialogPluginImpl() { 250 this(null); 251 } 252 public FleetInteractionDialogPluginImpl(FIDConfig params) { 253 this.config = params; 254 255 if (origFlagship == null) { 256 origFlagship = Global.getSector().getPlayerFleet().getFlagship(); 257 } 258 if (origCaptains.isEmpty()) { 259 for (FleetMemberAPI member : Global.getSector().getPlayerFleet().getFleetData().getMembersListCopy()) { 260 origCaptains.put(member, member.getCaptain()); 261 } 262 membersInOrderPreEncounter = new ArrayList<FleetMemberAPI>(Global.getSector().getPlayerFleet().getFleetData().getMembersListCopy()); 263 } 264 } 265 266 public Map<String, MemoryAPI> getMemoryMap() { 267 return conversationDelegate == null ? null : conversationDelegate.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) { 275 reinitPostContinue(); 276 } else { 277 options.clearOptions(); 278 options.addOption("Continue", OptionId.REINIT_CONTINUE, null); 279 if (Global.getSettings().isDevMode()) { 280 DevMenuOptions.addOptions(dialog); 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")) { 299 options.clearOptions(); 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 311 public void init(InteractionDialogAPI dialog) { 312 this.dialog = dialog; 313 314 if (this.config == null) { 315 MemoryAPI memory = dialog.getInteractionTarget().getMemoryWithoutUpdate(); 316// if (memory.contains(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE)) { 317// this.config = (FIDConfig) memory.get(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE); 318// } else 319 if (memory.contains(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN)) { 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 335 textPanel = dialog.getTextPanel(); 336 options = dialog.getOptionPanel(); 337 visual = dialog.getVisualPanel(); 338 339 playerFleet = Global.getSector().getPlayerFleet(); 340 if (playerFleet != null) { 341 playerFleet.getFleetData().ensureHasFlagship(); 342 } 343 otherFleet = (CampaignFleetAPI) (dialog.getInteractionTarget()); 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; 351 BattleAPI battle = Global.getFactory().createBattle(playerFleet, otherFleet); 352 context.setBattle(battle); 353 pullInNearbyFleets(); 354 } else { 355 ongoingBattle = true; 356 context.setBattle(otherFleet.getBattle()); 357 if (context.getBattle().canJoin(playerFleet)) { 358 //context.getBattle().join(playerFleet); 359 pullInNearbyFleets(); 360 } 361 } 362 } 363 364 for (CampaignFleetAPI fleet : context.getBattle().getBothSides()) { 365 fleet.inflateIfNeeded(); 366 } 367 context.getBattle().genCombined(); 368 369 visual.setVisualFade(0.25f, 0.25f); 370 if (!config.straightToEngage) { 371 if (ongoingBattle && !joinedBattle) { 372 BattleAPI b = context.getBattle(); 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"; 377 visual.showPreBattleJoinInfo(null, playerFleet, Misc.ucFirst(titleOne), Misc.ucFirst(titleTwo), context); 378 } else { 379 //visual.showFleetInfo((String)null, playerFleet, (String)null, otherFleet, context); 380 showFleetInfo(); 381 } 382 } 383 384 inConversation = false; 385 directToComms = false; 386 conversationDelegate = new RuleBasedInteractionDialogPluginImpl(); 387 conversationDelegate.setEmbeddedMode(true); 388 conversationDelegate.init(dialog); 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")) { 409 options.clearOptions(); 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 433 public void printOngoingBattleInfo() { 434 optionSelected(null, OptionId.PRINT_ONGOING_BATTLE_INFO); 435 } 436 437 438 protected List<CampaignFleetAPI> pulledIn = new ArrayList<CampaignFleetAPI>(); 439 protected void pullInNearbyFleets() { 440 BattleAPI b = context.getBattle(); 441 if (!ongoingBattle) { 442 b.join(Global.getSector().getPlayerFleet()); 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; 453 CampaignFleetAPI actualPlayer = Global.getSector().getPlayerFleet(); 454 CampaignFleetAPI actualOther = (CampaignFleetAPI) (dialog.getInteractionTarget()); 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; 463 Pair<SectorEntityToken, CampaignFleetAPI> p = Misc.getNearestStationInSupportRange(actualOther); 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)) { 494 textPanel.addParagraph( 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 } 503 textPanel.highlightFirstInLastPara(closest.getNameWithFactionKeepCase() + ":", closest.getFaction().getBaseUIColor()); 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 567 if (otherFleet != null) otherFleet.inflateIfNeeded(); 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(); 578 playerFleet = b.getPlayerCombined(); 579 otherFleet = b.getNonPlayerCombined(); 580 if (!config.straightToEngage) { 581 showFleetInfo(); 582 } 583 } 584 585 } 586 587 588 protected EngagementResultAPI lastResult = null; 589 public void backFromEngagement(EngagementResultAPI result) { 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()) { 596 playerGoal = FleetGoal.ATTACK; 597 otherGoal = FleetGoal.ATTACK; 598 } else { 599 playerGoal = FleetGoal.ATTACK; 600 otherGoal = FleetGoal.ATTACK; 601 } 602 player.setGoal(playerGoal); 603 other.setGoal(otherGoal); 604 } 605 606 if (!ongoingBattle) { 607 if (!otherFleet.getMemoryWithoutUpdate().contains(MemFlags.MEMORY_KEY_IGNORE_PLAYER_COMMS)) { 608 otherFleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_IGNORE_PLAYER_COMMS, true, 0); 609 } 610 } 611 612 result.setBattle(context.getBattle()); 613 614 context.processEngagementResults(result); 615 lastResult = result; 616 617 boolean startedWithAllies = false; 618 if (context.getBattle() != null) { 619 startedWithAllies = context.getBattle().getPlayerSideSnapshot().size() > 1; 620 } 621 if (!Global.getSector().getPlayerFleet().isValidPlayerFleet() && 622 startedWithAllies && context.getBattle().getPlayerSide().size() > 1) { 623 //!context.getBattle().getPlayerCombined().getFleetData().getMembersListCopy().isEmpty()) { 624 showFleetInfo(); 625 addText(getString("battleFleetLost")); 626 addText(getString("finalOutcomeNoShipsLeft")); 627 options.clearOptions(); 628 options.addOption("Leave", OptionId.LEAVE, null); 629 options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true); 630 return; 631 } 632 633 restoreOrigCaptains(); 634 if (origFlagship != null) { 635 if (selectedFlagship != null) { 636 PersonAPI captain = origFlagship.getCaptain(); 637 if (captain != null && !captain.isPlayer()) { 638 selectedFlagship.setCaptain(captain); 639 } 640 } 641 Global.getSector().getPlayerFleet().getFleetData().setFlagship(origFlagship); 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 677 switch (context.getLastEngagementOutcome()) { 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) { 787 if (context.didPlayerWinLastEngagement()) { 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); 798 showFleetInfo(); 799 } 800 801 addPostBattleAttitudeText(); 802 803 804 if (config.straightToEngage) { 805 //optionSelected(null, OptionId.LEAVE); 806 goToEncounterEndPath(); 807 } else { 808 if (ongoingBattle) { 809 options.clearOptions(); 810 updateEngagementChoice(true); 811 } else { 812 updateMainState(true); 813 } 814 } 815 816 if (isFightingOver()) { 817 if (context.isEngagedInHostilities()) { 818 context.getDataFor(playerFleet).setDisengaged(!context.didPlayerWinMostRecentBattleOfEncounter()); 819 context.getDataFor(otherFleet).setDisengaged(context.didPlayerWinMostRecentBattleOfEncounter()); 820 } 821 } 822 } 823 824 protected void addPostBattleAttitudeText() { 825 if (!config.showFleetAttitude) return; 826 827 if (!ongoingBattle) { 828 if (!context.wasLastEngagementEscape()) { 829 boolean otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage(); 830 if (!otherWantsToRun) { 831 if (context.didPlayerWinLastEngagement()) { 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 } 844 if (otherFleetWantsToFight()) { 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 { 853 if (otherFleetHoldingVsStrongerEnemy()) { 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>(); 864 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) { 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")); 908 dialog.addOptionSelectedText(option); 909 } 910 911 switch (option) { 912 case PRINT_ONGOING_BATTLE_INFO: 913 if (ongoingBattle) { 914 if (!config.straightToEngage) addText(getString("ongoingBattleEncounter")); 915 BattleAPI b = context.getBattle(); 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")); 935 BattleAPI b = context.getBattle(); 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; 966 for (CampaignFleetAPI curr : context.getBattle().getSideFor(otherFleet)) { 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 { 989 if (otherFleetHoldingVsStrongerEnemy()) { 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 } 1003 if (!otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_SKIP_TRANSPONDER_STATUS_INFO)) { 1004 //boolean knows = otherFleet.knowsWhoPlayerIs(); 1005 boolean knows = context.getBattle() != null && context.getBattle().getNonPlayerSide() != null && 1006 context.getBattle().knowsWhoPlayerIs(context.getBattle().getNonPlayerSide()); 1007 if (!knows) { 1008 addText(getString("initialDoesntKnow" + side)); 1009 } else { 1010 CampaignFleetAPI actualPlayer = Global.getSector().getPlayerFleet(); 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: 1028 reinitPostContinue(); 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: 1066 if (context.getBattle().canJoin(playerFleet)) { 1067 BattleAPI b = context.getBattle(); 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 1092 playerFleet = b.getPlayerCombined(); 1093 otherFleet = b.getNonPlayerCombined(); 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 1106 options.clearOptions(); 1107 updateEngagementChoice(true); 1108 if (!allyEngagementChoiceNoBattle) { 1109 updatePreCombat(); 1110 } 1111 } else { 1112 addText("Failed to join battle; shouldn't happen."); 1113 updateMainState(true); 1114 } 1115 break; 1116 case CONTINUE_ONGOING_BATTLE: 1117 updatePreCombat(); 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; 1126 if (otherFleetWantsToDisengage() && otherCanDisengage() && !forceEngage) { 1127 playerGoal = FleetGoal.ATTACK; 1128 otherGoal = FleetGoal.ESCAPE; 1129 if (config.showEngageText) { 1130 addText(getString("engagePursuit")); 1131 } 1132 } else { 1133 playerGoal = FleetGoal.ATTACK; 1134 otherGoal = FleetGoal.ATTACK; 1135 if (config.showEngageText) { 1136 addText(getString("engageMutual")); 1137 } 1138 } 1139 updatePreCombat(); 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 1151 BattleCreationContext bcc; 1152 if (config.alwaysAttackVsAttack){ 1153 playerGoal = FleetGoal.ATTACK; 1154 otherGoal = FleetGoal.ATTACK; 1155 } 1156 1157 if (context.getBattle() != null) { 1158 BattleAPI b = context.getBattle(); 1159 1160 if (b.isStationInvolved()) { 1161 boolean regen = false; 1162 if (b.isStationInvolvedOnPlayerSide()) { 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); 1184 bcc.setPlayerCommandPoints((int) Global.getSector().getPlayerFleet().getCommanderStats().getCommandPoints().getModifiedValue()); 1185 1186 if (b.isStationInvolved() && playerGoal != FleetGoal.ESCAPE && otherGoal != FleetGoal.ESCAPE) { 1187 bcc.objectivesAllowed = false; 1188 } 1189 if (config.delegate != null) { 1190 config.delegate.battleContextCreated(dialog, bcc); 1191 } 1192 1193 if (firstEngagement) { 1194 if (playerGoal != FleetGoal.ESCAPE && ongoingBattle) { 1195 bcc.setInitialStepSize(1.5f); 1196 bcc.setInitialNumSteps(10 + (float) Math.random() * 30); 1197 } 1198 firstEngagement = false; 1199 } else { 1200 if (playerGoal != FleetGoal.ESCAPE && ongoingBattle) { 1201 bcc.setInitialStepSize(1.5f); 1202 bcc.setInitialNumSteps(5 + (float) Math.random() * 5); 1203 } 1204 } 1205 } else { 1206 bcc = new BattleCreationContext(playerFleet, playerGoal, otherFleet, otherGoal); 1207 bcc.setPlayerCommandPoints((int) Global.getSector().getPlayerFleet().getCommanderStats().getCommandPoints().getModifiedValue()); 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); 1215 CampaignFleetAIAPI ai = playerFleet.getAI(); 1216 if (ai != null) { 1217 ai.performCrashMothballingPriorToEscape(context, otherFleet); 1218 } 1219 } else if (otherGoal == FleetGoal.ESCAPE) { 1220 //DataForEncounterSide data = context.getDataFor(playerFleet); 1221 CampaignFleetAIAPI ai = otherFleet.getAI(); 1222 if (ai != null) { 1223 ai.performCrashMothballingPriorToEscape(context, playerFleet); 1224 } 1225 } 1226 1227 visual.fadeVisualOut(); 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); 1235 if (otherFleetHoldingVsStrongerEnemy() || !otherFleetWantsToFight() || canDisengageCleanly(playerFleet)) { 1236 po = PursuitOption.LET_THEM_GO; 1237 } 1238 1239 context.applyPursuitOption(otherFleet, playerFleet, po); 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? 1249 context.setOtherFleetHarriedPlayer(true); 1250 context.getDataFor(playerFleet).setDisengaged(true); 1251 context.getDataFor(otherFleet).setDisengaged(false); 1252 break; 1253 case LET_THEM_GO: 1254 if (canDisengageCleanly(playerFleet)) { 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) { 1270 playerGoal = FleetGoal.ESCAPE; 1271 otherGoal = FleetGoal.ATTACK; 1272 addText(getString("enemyPursuit")); 1273 letGo = false; 1274 updatePreCombat(); 1275 } else if (pursuitOption == PursuitOption.HARRY) { 1276 context.applyPursuitOption(otherFleet, playerFleet, PursuitOption.HARRY); 1277 addText(getString("enemyHarass")); 1278 context.setEngagedInHostilities(true); 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); 1298 context.getDataFor(otherFleet).setDisengaged(!context.isEngagedInHostilities()); 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: 1316 reinitPostContinue(); 1317 break; 1318 case OPEN_COMM: 1319 CampaignFleetAPI actualOther = (CampaignFleetAPI) (dialog.getInteractionTarget()); 1320 dialog.showTextPanel(); 1321 dialog.flickerStatic(0.1f, 0.1f); 1322 1323 inConversation = true; 1324 conversationDelegate = new RuleBasedInteractionDialogPluginImpl(); 1325 conversationDelegate.setEmbeddedMode(true); 1326 conversationDelegate.init(dialog); 1327 1328 dialog.getInteractionTarget().setActivePerson(actualOther.getCommander()); 1329 conversationDelegate.notifyActivePersonChanged(); 1330 1331 boolean otherWantsToRun = otherFleetWantsToDisengage() && otherCanDisengage(); 1332 MemoryAPI mem = conversationDelegate.getMemoryMap().get(MemKeys.LOCAL); 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."); 1339 dialog.getInteractionTarget().setActivePerson(null); 1340 conversationDelegate.notifyActivePersonChanged(); 1341 inConversation = false; 1342 } 1343 if (inConversation && !visual.isShowingPersonInfo(actualOther.getCommander()) && 1344 !dialog.getInteractionTarget().getMemoryWithoutUpdate().getBoolean(DO_NOT_AUTO_SHOW_FC_PORTRAIT)) { 1345 visual.showPersonInfo(actualOther.getCommander()); 1346 } 1347 break; 1348 case CUT_COMM: 1349 dialog.showTextPanel(); 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: 1364 playerGoal = FleetGoal.ATTACK; 1365 otherGoal = FleetGoal.ESCAPE; 1366 addText(getString("pursue")); 1367 updatePreCombat(); 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, 1379 new FleetMemberPickerListener() { 1380 public void pickedFleetMembers(List<FleetMemberAPI> members) { 1381 if (members != null && !members.isEmpty()) { 1382 BattleAutoresolverPluginImpl resolver = new BattleAutoresolverPluginImpl(context.getBattle()); 1383 resolver.resolvePlayerPursuit(context, members); 1384 if (resolver.getResult() != null) { 1385 addText(getString("pursuitAutoresolve")); 1386 if (context.getBattle() != null) { 1387 CampaignFleetAPI player = Global.getSector().getPlayerFleet(); 1388 CampaignFleetAPI ally = null; 1389 float alliedFP = 0; 1390 for (CampaignFleetAPI curr : context.getBattle().getPlayerSide()) { 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; 1410 context.setPlayerFPHullDamageToEnemies(context.getPlayerFPHullDamageToEnemies() + damage * playerFP / total); 1411 if (ally != null && alliedFP > 0) { 1412 context.setAllyFPHullDamageToEnemies(context.getAllyFPHullDamageToEnemies() + damage * alliedFP / total); 1413 } 1414 } 1415 backFromEngagement(resolver.getResult()); 1416 } 1417 } 1418 } 1419 public void cancelledFleetMemberPicking() { 1420 1421 } 1422 }); 1423 break; 1424 case CRASH_MOTHBALL: 1425 List<FleetMemberAPI> choices = getCrashMothballable(playerFleet.getFleetData().getCombatReadyMembersListCopy()); 1426 dialog.showFleetMemberPickerDialog("Select craft to crash-mothball", "Ok", "Cancel", 1427 3, 7, 58f, false, true, choices, 1428 new FleetMemberPickerListener() { 1429 public void pickedFleetMembers(List<FleetMemberAPI> members) { 1430 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) { 1431 member.getRepairTracker().setCrashMothballed(false); 1432 } 1433 if (members != null && !members.isEmpty()) { 1434 for (FleetMemberAPI member : members) { 1435 member.getRepairTracker().setCrashMothballed(true); 1436 } 1437 1438 crashMothballList = createShipNameListString(members); 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: 1454 updateEngagementChoice(false); 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) { 1469 playerFleet = Global.getSector().getPlayerFleet(); 1470 otherFleet = (CampaignFleetAPI) (dialog.getInteractionTarget()); 1471 context.getBattle().leave(playerFleet, context.isEngagedInHostilities() || context.isOtherFleetHarriedPlayer()); 1472 BattleAPI b = context.getBattle(); 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"; 1477 visual.showPreBattleJoinInfo(null, playerFleet, Misc.ucFirst(titleOne), Misc.ucFirst(titleTwo), context); 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: 1499 visual.showCustomPanel(810, 400, new ExampleCustomUIPanel()); 1500 dialog.hideTextPanel(); 1501 break; 1502 case DEV_MODE_ESCAPE: 1503 context.applyAfterBattleEffectsIfThereWasABattle(); 1504 1505 BattleAPI b = context.getBattle(); 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)) { 1518 options.clearOptions(); 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 { 1537 if (context.isEngagedInHostilities()) { 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) { 1547 context.setTextPanelForXPGain(textPanel); 1548 textPanel.setFontSmallInsignia(); 1549 } 1550 context.applyAfterBattleEffectsIfThereWasABattle(); 1551 context.setTextPanelForXPGain(null); 1552 textPanel.setFontInsignia(); 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); 1578 context.setEngagedInHostilities(true); 1579 context.getDataFor(playerFleet).setDisengaged(false); 1580 context.getDataFor(otherFleet).setDisengaged(true); 1581 context.setEngagedInHostilities(true); 1582 goToEncounterEndPath(); 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); 1589 goToEncounterEndPath(); 1590 break; 1591 case RECOVERY_CONTINUE: 1592 goToEncounterEndPath(); 1593 break; 1594 case RECOVERY_SELECT: 1595 if (!recoverableShips.isEmpty() || !storyRecoverableShips.isEmpty()) { 1596 dialog.showFleetMemberRecoveryDialog("Select ships to recover", 1597 recoverableShips, storyRecoverableShips, 1598 new FleetMemberPickerListener() { 1599 public void pickedFleetMembers(List<FleetMemberAPI> members) { 1600 if (members != null && !members.isEmpty()) { 1601 recoveredShips.clear(); 1602 recoveredShips.addAll(members); 1603 FleetEncounterContext.recoverShips(members, context, playerFleet, otherFleet); 1604 1605 ListenerUtil.reportShipsRecovered(members, dialog); 1606 1607 CampaignFleetAPI player = Global.getSector().getPlayerFleet(); 1608 restoreOrigCaptains(); 1609 player.getFleetData().sortToMatchOrder(membersInOrderPreEncounter); 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); 1626 dialog.hideTextPanel(); 1627 dialog.hideVisualPanel(); 1628 1629 Global.getSector().reportEncounterLootGenerated(context, context.getLoot()); 1630 1631 visual.showLoot("Salvaged", context.getLoot(), true, new CoreInteractionListener() { 1632 public void coreUIDismissed() { 1633 if (config.printXPToDialog) { 1634 context.setTextPanelForXPGain(textPanel); 1635 textPanel.setFontSmallInsignia(); 1636 } 1637 context.applyAfterBattleEffectsIfThereWasABattle(); 1638 context.setTextPanelForXPGain(null); 1639 textPanel.setFontInsignia(); 1640// context.getBattle().uncombine(); 1641// context.getBattle().leave(Global.getSector().getPlayerFleet()); 1642 cleanUpBattle(); 1643 1644 if (config.dismissOnLeave) { 1645 dialog.dismiss(); 1646 dialog.hideTextPanel(); 1647 dialog.hideVisualPanel(); 1648 } else { 1649 dialog.showTextPanel(); 1650 dialog.showVisualPanel(); 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 }); 1660 options.clearOptions(); 1661 dialog.setPromptText(""); 1662 //options.addOption("Leave", OptionId.LEAVE, null); 1663 break; 1664 case CONTINUE_INTO_BOARDING: 1665 goToEncounterEndPath(); 1666 break; 1667 case BOARDING_ACTION: 1668 boardingPhase++; 1669 CampaignFleetAPI sourceFleet = context.getBattle().getSourceFleet(toBoard); 1670 boardingResult = context.boardShip(toBoard, Global.getSector().getPlayerFleet(), sourceFleet); 1671 //boardingResult = context.boardShip(toBoard, Global.getSector().getPlayerFleet(), otherFleet); 1672 goToEncounterEndPath(); 1673 break; 1674 case SELECT_FLAGSHIP: 1675 members = new ArrayList<FleetMemberAPI>(); 1676 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) { 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, 1685 new FleetMemberPickerListener() { 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()) { 1698 restoreOrigCaptains(); 1699 1700 selectedFlagship = members.get(0); 1701 PersonAPI captain = selectedFlagship.getCaptain(); 1702 Global.getSector().getPlayerFleet().getFleetData().setFlagship(selectedFlagship); 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; 1730 goToEncounterEndPath(); 1731 break; 1732 case LET_IT_GO: 1733 context.letBoardableGo(toBoard, otherFleet, playerFleet); 1734 addText(getString("letBoardableGo")); 1735 toBoard = null; 1736 goToEncounterEndPath(); 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 1766 for (CampaignFleetAPI other : context.getBattle().getNonPlayerSide()) { 1767 MemoryAPI mem = other.getMemoryWithoutUpdate(); 1768 if (!mem.getBoolean(MemFlags.MEMORY_KEY_RECENTLY_DEFEATED_BY_PLAYER)) { 1769 mem.set(MemFlags.MEMORY_KEY_RECENTLY_DEFEATED_BY_PLAYER, true, 0.5f); 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 1790 BattleAPI b = context.getBattle(); 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()) { 1795 rememberWasBeaten(); 1796 } 1797 1798 1799 b.leave(Global.getSector().getPlayerFleet(), context.isEngagedInHostilities() || context.isOtherFleetHarriedPlayer()); 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) { 1808 b.finish(winner, context.isEngagedInHostilities() || context.isOtherFleetHarriedPlayer()); 1809 Global.getSector().getPlayerFleet().getFleetData().setSyncNeeded(); 1810 Global.getSector().getPlayerFleet().getFleetData().syncIfNeeded(); 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 || 1827 harryEndedBattle || 1828 context.isOtherFleetHarriedPlayer() || 1829 allyEngagementChoiceNoBattle) { 1830 b.finish(winner, true); 1831 } else { 1832 for (CampaignFleetAPI curr : pulledIn) { 1833 b.leave(curr, context.isEngagedInHostilities() || context.isOtherFleetHarriedPlayer()); 1834 } 1835 } 1836 } 1837 } 1838 if (context.isEngagedInHostilities()) { 1839 b.applyVisibilityMod(Global.getSector().getPlayerFleet()); 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; 1858 protected CrewCompositionAPI maxBoardingParty = null; 1859 protected CrewCompositionAPI boardingParty = null; 1860 //protected BoardingAttackType boardingAttackType = null; 1861 protected BoardingResult boardingResult = null; 1862 protected FleetMemberAPI selectedFlagship = null; 1863 protected FleetMemberAPI origFlagship = 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(); 1878 if (context.didPlayerWinMostRecentBattleOfEncounter() || 1879 (config.straightToEngage && 1880 context.getLastEngagementOutcome() == EngagementOutcome.BATTLE_PLAYER_WIN)) { 1881 winningPath(); 1882 } else { 1883 losingPath(); 1884 } 1885 } 1886 1887 protected void losingPath() { 1888 options.clearOptions(); 1889 1890 context.getDataFor(playerFleet).setDisengaged(true); 1891 1892 if (!recoveredCrew) { 1893 recoveredCrew = true; 1894 context.recoverCrew(otherFleet); 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) { 1912 visual.showFleetMemberInfo(toBoard); 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 } 1923 aiBoardingResponse = otherFleet.getAI().pickBoardingResponse(context, toBoard, playerFleet); 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: 1965 context.letBoardableGo(toBoard, playerFleet, otherFleet); 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() { 2010 options.clearOptions(); 2011 DataForEncounterSide playerData = context.getDataFor(playerFleet); 2012 context.getDataFor(otherFleet).setDisengaged(true); 2013 2014 if (!firedVictoryTriggers && context.getBattle() != null && context.getBattle().getNonPlayerSideSnapshot() != null) { 2015 2016 SectorEntityToken prev = dialog.getInteractionTarget(); 2017 RuleBasedInteractionDialogPluginImpl plugin = new RuleBasedInteractionDialogPluginImpl(); 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()) { 2026 dialog.setInteractionTarget(other); 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 } 2062 Misc.clearDefeatTriggersIfNeeded(other); 2063 } 2064 2065 dialog.setInteractionTarget(prev); 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 2098 context.recoverCrew(playerFleet); 2099 } 2100 } 2101 2102 CampaignFleetAPI actualPlayer = Global.getSector().getPlayerFleet(); 2103 2104 boolean playerHasPersonnel = actualPlayer.getCargo().getMarines() > 0; 2105 boolean playerHasReadyShips = !actualPlayer.getFleetData().getCombatReadyMembersListCopy().isEmpty(); 2106 2107 2108 if (!didRecoveryCheck) { 2109 didRecoveryCheck = true; 2110 recoverableShips = context.getRecoverableShips(context.getBattle(), playerFleet, otherFleet); 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."; 2126 textPanel.addParagraph(pre); 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) { 2153 textPanel.setFontSmallInsignia(); 2154 textPanel.addParagraph( "Disabled ships from your fleet are available for recovery", Misc.getHighlightColor()); 2155 textPanel.setFontInsignia(); 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(); 2214 if (context.isEngagedInHostilities() && context.getLastEngagementOutcome() != null) { 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")); 2234 textPanel.highlightLastInLastPara(creditsLooted, HIGHLIGHT_COLOR); 2235 Global.getSector().getPlayerFleet().getCargo().getCredits().add(credits); 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>(); 2263 CombatReadinessPlugin crPlugin = Global.getSettings().getCRPlugin(); 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() { 2298 BattleAPI b = context.getBattle(); 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) { 2309 titleTwo = b.getPrimary(b.getNonPlayerSide()).getNameWithFactionKeepCase(); 2310 } 2311 if (b.getNonPlayerSide().size() > 1) titleTwo += ", with allies"; 2312 visual.showFleetInfo(titleOne, b.getPlayerCombined(), Misc.ucFirst(titleTwo), b.getNonPlayerCombined(), context); 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() { 2339 options.clearOptions(); 2340 options.addOption("Cut the comm link", OptionId.CUT_COMM, null); 2341 } 2342 2343 protected boolean isValidTransferCommandTarget(FleetMemberAPI member) { 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 2352 if (!context.isComputedDifficulty()) { 2353 context.computeBattleDifficulty(); 2354 } 2355 float diff = context.getDifficulty(); 2356 if (diff >= 1f) { 2357 String percent = "+" + (int) Math.round((diff - 1f) * 100f) + "%"; 2358 textPanel.setFontSmallInsignia(); 2359 textPanel.addPara("Additional XP due to overall battle difficulty: %s", 2360 Misc.getGrayColor(), Misc.getHighlightColor(), percent); 2361 textPanel.setFontInsignia(); 2362 } 2363 2364 2365 options.clearOptions(); 2366 2367 //playerFleet.updateCounts(); 2368 //int nonFighters = playerFleet.getFleetData().getMembersListCopy().size() - playerFleet.getNumFighters(); 2369 boolean canTransfer = false; 2370 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) { 2371// if (member.isFighterWing() || member.isAlly()) continue; 2372 if (member.isFlagship()) continue; 2373 if (!isValidTransferCommandTarget(member)) continue; 2374 canTransfer = true; 2375 break; 2376 } 2377 if (playerGoal == FleetGoal.ATTACK && otherGoal == FleetGoal.ESCAPE) { 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) { 2393 List<FleetMemberAPI> choices = getCrashMothballable(playerFleet.getFleetData().getCombatReadyMembersListCopy()); 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) { 2421//// options.addOption("Go back", OptionId.GO_TO_MAIN, null); 2422//// options.setShortcut(OptionId.GO_TO_MAIN, Keyboard.KEY_ESCAPE, false, false, false, true); 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// } 2427 DevMenuOptions.addOptions(dialog); 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) { 2485 options.clearOptions(); 2486 2487 if (isFightingOver()) { 2488 goToEncounterEndPath(); 2489 return; 2490 } 2491 2492 if (ongoingBattle) { 2493 BattleAPI battle = context.getBattle(); 2494 boolean playerHasReadyShips = false; 2495 for (FleetMemberAPI member : playerFleet.getFleetData().getCombatReadyMembersListCopy()) { 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()) { 2530 DevMenuOptions.addOptions(dialog); 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); 2536 otherFleet.getMemoryWithoutUpdate().unset("$hailing"); 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 2545 boolean smuggler = otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_SMUGGLER); 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) { 2563 allyEngagementChoiceNoBattle = false; 2564 //options.clearOptions(); 2565 if (isFightingOver()) { 2566 goToEncounterEndPath(); 2567 return; 2568 } 2569 //options.clearOptions(); 2570 2571 BattleAPI b = context.getBattle(); 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; 2595 for (FleetMemberAPI member : playerFleet.getFleetData().getCombatReadyMembersListCopy()) { 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// } 2617 goToEncounterEndPath(); 2618 } else if (otherWantsToRun) { 2619 String pursueTooltip = "tooltipPursue"; 2620 String harassTooltip = "tooltipHarassRetreat"; 2621 String letThemGoTooltip = "tooltipLetThemGo"; 2622 if (!context.isEngagedInHostilities()) { 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) { 2670 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) { 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")); 2699 playerGoal = FleetGoal.ATTACK; 2700 otherGoal = FleetGoal.ESCAPE; 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 2708 context.applyPursuitOption(playerFleet, otherFleet, po); 2709 2710 if (withText) addText(getString("ongoingBattleHarass")); 2711 context.setEngagedInHostilities(true); 2712 context.getDataFor(playerFleet).setDisengaged(false); 2713 context.getDataFor(otherFleet).setDisengaged(true); 2714 allyEngagementChoiceNoBattle = true; 2715 harryEndedBattle = true; 2716 //rememberWasBeaten(); 2717 break; 2718 case LET_THEM_GO: 2719 letGo = true; 2720 if (context.isEngagedInHostilities()) { 2721 context.getDataFor(playerFleet).setDisengaged(false); 2722 context.getDataFor(otherFleet).setDisengaged(true); 2723 } 2724 allyEngagementChoiceNoBattle = true; 2725 //rememberWasBeaten(); 2726 break; 2727 } 2728 //} 2729 if (letGo) { 2730 if (withText) addText(getString("ongoingBattleLetGo")); 2731 allyEngagementChoiceNoBattle = true; 2732 } 2733 2734 if (context.isEngagedInHostilities() && context.isBattleOver()) { 2735 goToEncounterEndPath(); 2736 } else { 2737 if (context.isEngagedInHostilities()) { 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 { 2746 CampaignFleetAIAPI ai = otherFleet.getAI(); 2747 boolean hostile = false; 2748 if (ai != null) { 2749 hostile = ai.isHostileTo(playerFleet) || context.isEngagedInHostilities(); 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 && 2757 context.getBattle().knowsWhoPlayerIs(context.getBattle().getNonPlayerSide()); 2758 boolean lowImpact = context.isLowRepImpact() || context.isNoRepImpact(); 2759 FactionAPI nonHostile = getNonHostileOtherFaction(); 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 && 2774 context.getBattle().knowsWhoPlayerIs(context.getBattle().getNonPlayerSide()); 2775 boolean lowImpact = context.isLowRepImpact() || context.isNoRepImpact(); 2776 FactionAPI nonHostile = getNonHostileOtherFaction(); 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")); 2803 playerGoal = FleetGoal.ESCAPE; 2804 otherGoal = FleetGoal.ATTACK; 2805 options.addOption("Join the disengage attempt", OptionId.CONTINUE_ONGOING_BATTLE, null); 2806 } else { 2807 boolean station = false; 2808 if (playerFleet != null) { 2809 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) { 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 } 2824 playerGoal = FleetGoal.ATTACK; 2825 otherGoal = FleetGoal.ATTACK; 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 && 2848 context.getBattle().knowsWhoPlayerIs(context.getBattle().getNonPlayerSide()); 2849 boolean lowImpact = context.isLowRepImpact() || context.isNoRepImpact(); 2850 FactionAPI nonHostile = getNonHostileOtherFaction(); 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 } 2860 CampaignFleetAIAPI ai = otherFleet.getAI(); 2861 boolean hostile = false; 2862 if (ai != null) { 2863 hostile = ai.isHostileTo(playerFleet) || context.isEngagedInHostilities(); 2864 } 2865 //if (!config.noLeaveOption) { 2866 boolean noLeave = !context.isEngagedInHostilities() && config.noLeaveOptionOnFirstEngagement; 2867 if (!noLeave) { 2868 if (!config.leaveAlwaysAvailable && 2869 (otherFleetWantsToFight() || (hostile && !otherFleetWantsToDisengage()))) { 2870 if (canDisengageCleanly(playerFleet)) { 2871 options.addOption("Disengage", OptionId.DISENGAGE, getString("tooltipCleanDisengage")); 2872 } else if (canDisengageWithoutPursuit(playerFleet) && !(!otherFleetWantsToFight() && !otherFleetWantsToDisengage())) { 2873 options.addOption("Disengage", OptionId.DISENGAGE, getString("tooltipHarrassableDisengage")); 2874 } else { 2875 if (otherFleetHoldingVsStrongerEnemy() || (!otherFleetWantsToFight() && !otherFleetWantsToDisengage())) { 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; 2890 for (CampaignFleetAPI curr : context.getBattle().getSideFor(otherFleet)) { 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) { 2904 shownTooLargeToRetreatMessage = true; 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")); 2909 label.setHighlightColors(Misc.getNegativeHighlightColor(), Misc.getHighlightColor()); 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 2920 addEmergencyRepairsOption(); 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()) { 2944 DevMenuOptions.addOptions(dialog); 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 2962 final CampaignFleetAPI fleet = Global.getSector().getPlayerFleet(); 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 3038 String str = BaseSkillEffectDescription.getValueLabelForMember(member); 3039 textPanel.setFontSmallInsignia(); 3040 textPanel.addPara(str + " performed emergency repairs", Misc.getPositiveHighlightColor()); 3041 textPanel.highlightFirstInLastPara(str, Misc.getHighlightColor()); 3042 textPanel.setFontInsignia(); 3043 3044 if (fraction < 1f) { 3045 break; 3046 } 3047 } 3048 didRepairs = true; 3049 playerFleet.getFleetData().setSyncNeeded(); 3050 playerFleet.getFleetData().syncIfNeeded(); 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); 3072 info.setBulletedListMode(BaseIntelPlugin.INDENT); 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 3086 String str = BaseSkillEffectDescription.getValueLabelForMember(member); 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 3104 protected PursuitOption pickPursuitOption(CampaignFleetAPI fleet, CampaignFleetAPI other, FleetEncounterContext context) { 3105 context.setNoHarryBecauseOfStation(false); 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) { 3135 context.setNoHarryBecauseOfStation(true); 3136 return PursuitOption.LET_THEM_GO; 3137 } 3138 return option; 3139 } 3140 3141 public FactionAPI getNonHostileOtherFaction() { 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) { 3152 FactionAPI player = Global.getSector().getPlayerFaction(); 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() { 3182 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 3183 float total = 0f; 3184 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) { 3185 if (member.canBeDeployedForCombat()) { 3186 total += member.getDeploymentPointsCost(); 3187 } 3188 } 3189 return total <= getDisengageSize(); 3190 } 3191 3192 protected boolean otherCanDisengage() { 3193 return fleetCanDisengage(otherFleet); 3194 } 3195 3196 protected boolean alliedCanDisengage() { 3197 return fleetCanDisengage(playerFleet); 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 } 3247 protected boolean canDisengageWithoutPursuit(CampaignFleetAPI fleet) { 3248 CampaignFleetAPI other = playerFleet; 3249 if (other == fleet) other = otherFleet; 3250 PursueAvailability pa = getPursuitAvailability(other); 3251 return pa != PursueAvailability.AVAILABLE; 3252 } 3253 3254 protected PursueAvailability getPursuitAvailability(CampaignFleetAPI fleet) { 3255 CampaignFleetAPI other = playerFleet; 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 3272 if (otherFleet.getFaction().isNeutralFaction()) { 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 3364 BattleAPI b = context.getBattle(); 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() { 3481 return fleetWantsToFight(playerFleet, otherFleet); 3482 } 3483 public boolean otherFleetWantsToFight() { 3484 return fleetWantsToFight(otherFleet, playerFleet); 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 } 3502 if (context.isEngagedInHostilities() && 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 3512 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_MAKE_ALLOW_DISENGAGE)) return false; 3513 3514 return (ai.isHostileTo(other) || context.isEngagedInHostilities() || assumeHostile || 3515 fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_MAKE_PREVENT_DISENGAGE) //|| 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 3524 protected boolean alliedFleetHoldingVsStrongerEnemy() { 3525 return fleetHoldingVsStrongerEnemy(playerFleet, otherFleet); 3526 } 3527 protected boolean otherFleetHoldingVsStrongerEnemy() { 3528// if (otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_MAKE_HOLD_VS_STRONGER_COMBAT_ONLY)) { 3529// return true; 3530// } 3531 return fleetHoldingVsStrongerEnemy(otherFleet, playerFleet); 3532 } 3533 protected boolean fleetHoldingVsStrongerEnemy(CampaignFleetAPI fleet, CampaignFleetAPI other) { 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 3544 protected boolean alliedFleetWantsToDisengage() { 3545 return fleetWantsToDisengage(playerFleet, otherFleet); 3546 } 3547 3548 protected boolean otherFleetWantsToDisengage() { 3549 return fleetWantsToDisengage(otherFleet, playerFleet); 3550 } 3551 protected boolean fleetWantsToDisengage(CampaignFleetAPI fleet, CampaignFleetAPI other) { 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 } 3561 if (context.isEngagedInHostilities() && 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) { 3578 conversationDelegate.updateMemory(); 3579 } 3580 } 3581 3582 public void notifyActivePersonChanged() { 3583 if (conversationDelegate != null) { 3584 conversationDelegate.notifyActivePersonChanged(); 3585 } 3586 } 3587 3588 public void setActiveMission(CampaignEventPlugin mission) { 3589 if (mission == null) { 3590 conversationDelegate.getMemoryMap().remove(MemKeys.MISSION); 3591 } else { 3592 MemoryAPI memory = mission.getMemory(); 3593 if (memory != null) { 3594 conversationDelegate.getMemoryMap().put(MemKeys.MISSION, memory); 3595 } else { 3596 conversationDelegate.getMemoryMap().remove(MemKeys.MISSION); 3597 } 3598 } 3599 } 3600 public void setPlayerFleet(CampaignFleetAPI playerFleet) { 3601 this.playerFleet = playerFleet; 3602 } 3603 3604 3605} 3606 3607 3608