Skip to content

Commit 5368f97

Browse files
authored
Merge pull request #6222 from Scoppio/feat/pacar-kill-convoys
Feat/pacar kill convoys
2 parents c07e034 + 1296930 commit 5368f97

File tree

8 files changed

+80
-17
lines changed

8 files changed

+80
-17
lines changed

MekHQ/data/scenariotemplates/Convoy Escort.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22
<ScenarioTemplate>
33
<name>Convoy Escort</name>
4+
<stratConScenarioType>CONVOY</stratConScenarioType>
45
<shortBriefing>Escort supply convoy or defeat attackers.</shortBriefing>
56
<detailedBriefing>An allied convoy carrying critical supplies is moving through hostile territory, and enemy forces are preparing to intercept. Your mission is to ensure that the convoy reaches its destination. At least 50% of the convoy must reach the far edge of the engagement area intact. These supplies are vital to sustaining our operations, and failure is not an option.
67

MekHQ/data/scenariotemplates/Convoy Interdiction.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22
<ScenarioTemplate>
33
<name>Convoy Interdiction</name>
4+
<stratConScenarioType>CONVOY</stratConScenarioType>
45
<shortBriefing>Intercept and neutralize enemy convoy.</shortBriefing>
56
<detailedBriefing>An enemy convoy is on the move, and your orders are simple—hit them hard and stop at least 50% of their forces from reaching the far edge of the engagement zone. This is a direct strike, not a prolonged engagement. Destroy or cripple the convoy units with no regard for salvage or escort interference. Speed and overwhelming firepower are your greatest assets.
67

MekHQ/data/scenariotemplates/Convoy Raid.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22
<ScenarioTemplate>
33
<name>Convoy Raid</name>
4+
<stratConScenarioType>CONVOY</stratConScenarioType>
45
<shortBriefing>Intercept and disrupt enemy convoy.</shortBriefing>
56
<detailedBriefing>An enemy supply convoy is on the move, and this is our chance to cripple their logistics. Your mission is to intercept and raid the convoy before it can escape the engagement zone. These supplies are vital to the enemy’s war effort, and every truck or transport we eliminate weakens their ability to fight. Speed and aggression will be key—hit them hard, hit them fast, and get out before their reinforcements arrive.
67

MekHQ/data/scenariotemplates/Critical Convoy Escort.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22
<ScenarioTemplate>
33
<name>Critical Convoy Escort</name>
4+
<stratConScenarioType>CONVOY</stratConScenarioType>
45
<shortBriefing>Escort critical convoy or defeat attackers.</shortBriefing>
56
<detailedBriefing>An allied convoy carrying critical supplies is moving through hostile territory, and a large, heavily armed enemy force is preparing to intercept. Your mission is to ensure that at least 50% of the convoy reaches the far edge of the engagement area intact. These supplies are essential to sustaining our war effort, and failure is not an option.
67

MekHQ/data/scenariotemplates/Irregular Force Suppression.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<ScenarioTemplate>
33
<name>Irregular Force Suppression</name>
44
<shortBriefing>Engage and defeat irregular-supported force.</shortBriefing>
5-
<detailedBriefing>ocal insurgent forces are receiving direct military support in this region, strengthening their ability to disrupt our operations. If they are not dealt with decisively, they will continue to erode our control and pose a long-term threat. Your mission is to engage and destroy at least 50% of the combined enemy force, cutting off their ability to operate effectively.
5+
<detailedBriefing>Local insurgent forces are receiving direct military support in this region, strengthening their ability to disrupt our operations. If they are not dealt with decisively, they will continue to erode our control and pose a long-term threat. Your mission is to engage and destroy at least 50% of the combined enemy force, cutting off their ability to operate effectively.
66

77
Expect a blend of unconventional tactics and structured military resistance. The insurgents will use ambushes, terrain familiarity, and hit-and-run attacks, while their military allies will bring firepower, coordination, and heavier assets into the fight. Dismantle their cohesion, eliminate key targets, and disrupt their ability to function as a fighting force.
88

MekHQ/src/mekhq/MekHQ.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,16 @@
6161
import mekhq.campaign.autoresolve.AtBSetupForces;
6262
import mekhq.campaign.handler.PostScenarioDialogHandler;
6363
import mekhq.campaign.handler.XPHandler;
64+
import mekhq.campaign.mission.AtBContract;
6465
import mekhq.campaign.mission.AtBDynamicScenario;
6566
import mekhq.campaign.mission.AtBScenario;
6667
import mekhq.campaign.mission.Scenario;
6768
import mekhq.campaign.mission.ScenarioTemplate;
6869
import mekhq.campaign.mission.ScenarioTemplate.BattlefieldControlType;
6970
import mekhq.campaign.personnel.Person;
71+
import mekhq.campaign.stratcon.StratconCampaignState;
7072
import mekhq.campaign.stratcon.StratconRulesManager;
73+
import mekhq.campaign.stratcon.StratconScenario;
7174
import mekhq.campaign.unit.Unit;
7275
import mekhq.gui.CampaignGUI;
7376
import mekhq.gui.dialog.ChooseMulFilesDialog;
@@ -476,8 +479,8 @@ public void startHost(Scenario scenario, boolean loadSavegame, List<Unit> meks,
476479
currentScenario = scenario;
477480

478481
// Start the game thread - also refactor this into a factory
479-
if (getCampaign().getCampaignOptions().isUseAtB() && (scenario instanceof AtBScenario)) {
480-
gameThread = new AtBGameThread(playerName, password, client, this, meks, (AtBScenario) scenario, autoResolveBehaviorSettings, useExperimentalPacarGui, true);
482+
if (getCampaign().getCampaignOptions().isUseAtB() && (scenario instanceof AtBScenario atBScenario)) {
483+
gameThread = new AtBGameThread(playerName, password, client, this, meks, atBScenario, autoResolveBehaviorSettings, useExperimentalPacarGui, true);
481484
} else {
482485
gameThread = new GameThread(playerName, password, client, this, meks, scenario);
483486
}

MekHQ/src/mekhq/campaign/mission/enums/ScenarioType.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public enum ScenarioType {
5050
NONE,
5151
SPECIAL_LOSTECH,
5252
SPECIAL_RESUPPLY,
53-
SPECIAL_JAIL_BREAK;
53+
SPECIAL_JAIL_BREAK,
54+
CONVOY;
5455

5556
/**
5657
* @return {@code true} if the scenario is considered a LosTech scenario, {@code false} otherwise.
@@ -59,6 +60,14 @@ public boolean isLosTech() {
5960
return this == SPECIAL_LOSTECH;
6061
}
6162

63+
/**
64+
* @return {@code true} if the scenario is considered a convoy scenario, {@code false} otherwise. Convoy scenarios involve the
65+
* defense or interception of a convoys with supplies, VIPs, or resupplies.
66+
*/
67+
public boolean isConvoy() {
68+
return this == SPECIAL_RESUPPLY || this == CONVOY;
69+
}
70+
6271
/**
6372
* @return {@code true} if the scenario is considered a Resupply scenario, {@code false} otherwise.
6473
*/
@@ -110,7 +119,7 @@ public static ScenarioType parseFromString(final String text) {
110119
} catch (Exception ignored) {}
111120

112121
MMLogger.create(ScenarioType.class)
113-
.error("Unable to parse " + text + " into an ScenarioType. Returning NONE.");
122+
.warn("Unable to parse {} into an ScenarioType. Returning NONE.", text);
114123

115124
return NONE;
116125
}

MekHQ/src/mekhq/gui/BriefingTab.java

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
package mekhq.gui;
2929

3030
import megamek.client.bot.princess.BehaviorSettings;
31+
import megamek.client.bot.princess.PrincessException;
3132
import megamek.client.generator.ReconfigurationParameters;
3233
import megamek.client.generator.TeamLoadOutGenerator;
3334
import megamek.client.ui.baseComponents.MMComboBox;
@@ -830,10 +831,10 @@ private void startScenario(BehaviorSettings autoResolveBehaviorSettings) {
830831
}
831832
}
832833

833-
if (scenario instanceof AtBDynamicScenario) {
834-
AtBDynamicScenarioFactory.setPlayerDeploymentTurns((AtBDynamicScenario) scenario, getCampaign());
835-
AtBDynamicScenarioFactory.finalizeStaggeredDeploymentTurns((AtBDynamicScenario) scenario, getCampaign());
836-
AtBDynamicScenarioFactory.setPlayerDeploymentZones((AtBDynamicScenario) scenario, getCampaign());
834+
if (scenario instanceof AtBDynamicScenario atBDynamicScenario) {
835+
AtBDynamicScenarioFactory.setPlayerDeploymentTurns(atBDynamicScenario, getCampaign());
836+
AtBDynamicScenarioFactory.finalizeStaggeredDeploymentTurns(atBDynamicScenario, getCampaign());
837+
AtBDynamicScenarioFactory.setPlayerDeploymentZones(atBDynamicScenario, getCampaign());
837838
}
838839

839840
if (!undeployed.isEmpty()) {
@@ -847,10 +848,16 @@ private void startScenario(BehaviorSettings autoResolveBehaviorSettings) {
847848
}
848849
}
849850

851+
// Ensure that the MegaMek year GameOption matches the campaign year
852+
// this is being set early on so that when setting up the autoconfig munitions
853+
// the correct year is used
854+
getCampaign().getGameOptions().getOption(OptionsConstants.ALLOWED_YEAR)
855+
.setValue(getCampaign().getGameYear());
856+
850857
// code to support deployment of reinforcements for legacy ATB scenarios.
851-
if ((scenario instanceof AtBScenario) && !(scenario instanceof AtBDynamicScenario)) {
858+
if ((scenario instanceof AtBScenario atBScenario) && !(scenario instanceof AtBDynamicScenario)) {
852859

853-
CombatTeam combatTeam = ((AtBScenario) scenario).getCombatTeamById(getCampaign());
860+
CombatTeam combatTeam = atBScenario.getCombatTeamById(getCampaign());
854861
if (combatTeam != null) {
855862
int assignedForceId = combatTeam.getForceId();
856863
int cmdrStrategy = 0;
@@ -870,24 +877,64 @@ private void startScenario(BehaviorSettings autoResolveBehaviorSettings) {
870877
}
871878
}
872879

873-
if (getCampaign().getCampaignOptions().isUseAtB() && (scenario instanceof AtBScenario)) {
874-
((AtBScenario) scenario).refresh(getCampaign());
880+
if (getCampaign().getCampaignOptions().isUseAtB() && (scenario instanceof AtBScenario atBScenario)) {
881+
atBScenario.refresh(getCampaign());
875882

876883
// Autoconfigure munitions for all non-player forces once more, using finalized
877884
// forces
878885
if (getCampaign().getCampaignOptions().isAutoConfigMunitions()) {
879-
autoconfigureBotMunitions(((AtBScenario) scenario), chosen);
886+
autoconfigureBotMunitions(atBScenario, chosen);
887+
}
888+
configureBotAi(atBScenario);
889+
}
890+
891+
if (scenario.getStratConScenarioType().isConvoy() && (autoResolveBehaviorSettings != null)) {
892+
try {
893+
autoResolveBehaviorSettings = autoResolveBehaviorSettings.getCopy();
894+
autoResolveBehaviorSettings.setIAmAPirate(true);
895+
} catch (PrincessException e) {
896+
logger.error("Failed to copy autoResolveBehaviorSettings", e);
880897
}
881898
}
882899

883900
if (!chosen.isEmpty()) {
884-
// Ensure that the MegaMek year GameOption matches the campaign year
885-
getCampaign().getGameOptions().getOption(OptionsConstants.ALLOWED_YEAR)
886-
.setValue(getCampaign().getGameYear());
887901
getCampaignGui().getApplication()
888902
.startHost(scenario, false, chosen, autoResolveBehaviorSettings);
903+
}
904+
}
905+
906+
private void configureBotAi(AtBScenario scenario) {
907+
Faction opFor = getEnemyFactionFromScenario(scenario);
908+
boolean isPirate = opFor.isRebelOrPirate();
909+
for (var bf : scenario.getBotForces()) {
910+
bf.getBehaviorSettings().setIAmAPirate(isPirate);
911+
}
912+
}
889913

914+
/**
915+
* Get the enemy faction from the Mission from the scenario
916+
* @param scenario the scenario to get the enemy faction from
917+
* @return the enemy faction
918+
*/
919+
private Faction getEnemyFactionFromScenario(Scenario scenario) {
920+
Mission mission = null;
921+
if (scenario.getMissionId() != -1) {
922+
mission = getCampaign().getMission(scenario.getMissionId());
923+
}
924+
if (mission == null) {
925+
mission = comboMission.getSelectedItem();
926+
}
927+
String opforFactionCode = "IS";
928+
Faction enemy;
929+
if (mission instanceof AtBContract atBContract) {
930+
enemy = atBContract.getEnemy();
931+
if (enemy != null) {
932+
return atBContract.getEnemy();
933+
}
934+
opforFactionCode = atBContract.getEnemyCode().isBlank() ? opforFactionCode : atBContract.getEnemyCode();
890935
}
936+
enemy = Factions.getInstance().getFaction(opforFactionCode);
937+
return enemy;
891938
}
892939

893940
/**

0 commit comments

Comments
 (0)