8000 Improvement: Converted Most Convoy Dialogs into Immersive Dialogs by IllianiBird · Pull Request #6855 · MegaMek/mekhq · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Improvement: Converted Most Convoy Dialogs into Immersive Dialogs #6855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 43 additions & 12 deletions MekHQ/resources/mekhq/resources/Resupply.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,47 @@ smugglerFee.text=Local Resupply

roleplayItems.prompt=Items in <i>italics</i> are roleplay items and are not tracked by MekHQ.
documentation.prompt=Full documentation can be found in ''MekHQ/docs/Stratcon and Against the Bot''
outOfCharacter.abandoned=All units and personnel have been killed or captured.\
<p>Full documentation can be found in ''MekHQ/docs/Stratcon and Against the Bot''</p>
outOfCharacter.contractStart.normal=Each month your employer will offer you spare supplies from their depot. The contents\
\ of these resupplies is tailored to your force and your warehouse. That means you will always be offered items you\
\ are using, but if your warehouse is particularly well stocked your employer will choose to direct those spares\
\ elsewhere.\
<p>The <b>Negotiation</b> skill of your senior-most <b>Admin/Logistics</b> character significantly influences the quality\
\ of resupplies.</p>\
<p>Resupplies are meant to ease the logistics demands of a contract, but they are not intended to replace\
\ normal procurement. While you are en route to the contract location considered checking the Parts in Use dialog and\
\ seeing if there is any supplies you're likely to deplete. You don't want to run out of left arms if you have to wait\
\ 3 months for a left arm to arrive.</p>\
<p>Full documentation can be found in ''MekHQ/docs/Stratcon and Against the Bot''</p>
outOfCharacter.contractStart.guerrilla=Each month you have a chance to receive a resupply offer from a local smuggler.The\
\ contents of these resupplies is tailored to your force and your warehouse. That means you will always be offered items\
\ you are using, but if your warehouse is particularly well stocked smuggler will choose to direct those spares elsewhere.\
<p>The <b>Negotiation</b> skill of your <b>campaign commander</b> significantly influences the quality of smuggler resupplies.</p>\
<p>Resupplies are meant to ease the logistics demands of a contract, but they are not intended to replace normal\
\ procurement. While you are en route to the contract location considered checking the Parts in Use dialog and\
\ seeing if there is any supplies you're likely to deplete. You don't want to run out of left arms if you have to wait\
\ 3 months for a left arm to arrive.</p>\
<p>Full documentation can be found in ''MekHQ/docs/Stratcon and Against the Bot''</p>
outOfCharacter.intercepted=Your convoy has been intercepted and a special <a href='GLOSSARY:CRISIS_SCENARIO'>Crisis</a>\
\ scenario has been generated. Refusing to fight this engagement will result in the loss of the convoy and its contents.
outOfCharacter.convoyPicker=If you have the cargo capacity it's generally a good idea to use your own convoys. However,\
\ this is a risk as it means placing your forces in the line of fire.\
<p>You should avoid sending out convoys while the enemy has high morale. You should also try to keep the total unit\
\ weight of your convoys below 200t as the heavier the convoy the easier it is to intercept.</p>
outOfCharacter.focus=Your employer will refuse to resupply parts you already have large quantities\
\ of. For those items your employer is willing to supply a Negotiation check must be made, if the\
\ check is failed the item will be unavailable. If all options are disabled you either have a well\
\ stocked warehouse, or your most senior Admin/Logistics character may not be up to the task.\
<p>Full documentation can be found in ''MekHQ/docs/Stratcon and Against the Bot''</p>
outOfCharacter.itinerary=If your resupply seems smaller than expected it's possible your warehouse is well stocked and\
\ your employer (or smuggler) withheld supplies. Alternatively your negotiator may have performed poorly when negotiating\
\ for resources.\
<p>You negotiatiator is normally your senior-most Admin/Logistics character, however interactions with smugglers use\
\ your campaign commander, instead.</p>\
<p>Full documentation can be found in ''MekHQ/docs/Stratcon and Against the Bot''</p>
outOfCharacter.roleplay=This is a roleplay event and has no mechanical impact <i>for now...</i>\
<p>Full documentation can be found in ''MekHQ/docs/Stratcon and Against the Bot''</p>

convoySuccessful.text=A convoy has {0}<b>arrived</b>{1}, and its supplies have been distributed by\
\ your logistics personnel.
Expand Down Expand Up @@ -153,10 +194,6 @@ focusDescription.text={0}, we might be able to lean a little on our contact and
<br>\
<br>Would you like to pick a focus? I''ve already disabled any options our employer is refusing to\
\ fulfill.
focusDescription.ooc=Your employer will refuse to resupply parts you already have large quantities\
\ of. For those items your employer is willing to supply a Negotiation check must be made, if the\
\ check is failed the item will be unavailable. If all options are disabled you either have a well\
\ stocked warehouse, or your most senior Admin/Logistics character may not be up to the task.

supplyCostFull.text=<br><br>This resupply will cost {0}.\
<br><br><i>The value of these supplies is {1}.</i>
Expand Down Expand Up @@ -2203,7 +2240,7 @@ statusUpdateEnemyOverwhelming49.text={0}, we faced a series of well-timed strike
\ Current assessment indicates a high likelihood of additional attacks in this sector.

statusUpdateIntercepted.boilerplate={0}, hostile interception underway. Incoming contacts unrelenting.\
\ Reinforcements needed urgently. They''re closing in fast.{1}
\ Reinforcements needed urgently. They''re closing in fast.
statusUpdateIntercepted0.text={0}, rear assault underway. Hostile ''Meks penetrating our lines.\
\ Transports are fully exposed; formation in disarray. Incoming contacts on sensors.\
\ Reinforcements needed urgently. Attempting to fall back, but we''re in serious trouble. They''re closing in\
Expand Down Expand Up @@ -2257,12 +2294,6 @@ statusUpdateIntercepted18.text={0}, under relentless fire. Supplies compromised,
statusUpdateIntercepted19.text={0}, situation hopeless. Last line of defense lost. Convoy collapsing,\
\ all units breaking down. Reinforcements needed urgently.{1}

interceptionInstructions.text=<br><br><i>A special scenario has been generated. Failure to complete\
\ this scenario will result in the loss of all units, personnel, and cargo.</i>




statusUpdateAbandoned0.text={0}, we''re being overwhelmed! Enemy ''Meks are breaching our lines, and\
\ half the transports are lost! Supplies are about to be captured, and the crew\
\ is down. No reinforcements in sight! They''re breaking through the barricade -\
Expand Down Expand Up @@ -3510,4 +3541,4 @@ proposition99.text={0}, you''ve made significant progress in locating the Star L
\ offer is straightforward and beneficial for both parties. We recommend acting promptly.

propositionValue.text=We''re offering {0} for the depot''s location, sealed and unsullied.
senderUnknown.text=Sender Unknown
senderUnknown.text=Sender Unknown
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*/
package mekhq.campaign.mission.resupplyAndCaches;

import static megamek.common.Compute.randomInt;
import static mekhq.campaign.mission.enums.AtBMoraleLevel.CRITICAL;
import static mekhq.campaign.mission.enums.AtBMoraleLevel.DOMINATING;
import static mekhq.campaign.mission.enums.AtBMoraleLevel.STALEMATE;
Expand All @@ -44,6 +45,7 @@
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.RESUPPLY_ARMOR_TONNAGE;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.ResupplyType.RESUPPLY_CONTRACT_END;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.ResupplyType.RESUPPLY_LOOT;
import static mekhq.campaign.personnel.enums.PersonnelRole.GROUND_VEHICLE_DRIVER;
import static mekhq.campaign.stratcon.StratconContractInitializer.getUnoccupiedCoords;
import static mekhq.campaign.stratcon.StratconRulesManager.generateExternalScenario;
import static mekhq.gui.dialog.resupplyAndCaches.DialogItinerary.itineraryDialog;
Expand All @@ -63,9 +65,11 @@
import megamek.common.Compute;
import megamek.common.Entity;
import megamek.common.annotations.Nullable;
import megamek.common.enums.Gender;
import megamek.logging.MMLogger;
import mekhq.MekHQ;
import mekhq.campaign.Campaign;
import mekhq.campaign.Hangar;
import mekhq.campaign.force.Force;
import mekhq.campaign.mission.AtBContract;
import mekhq.campaign.mission.AtBDynamicScenario;
Expand All @@ -76,14 +80,14 @@
import mekhq.campaign.parts.Armor;
import mekhq.campaign.parts.Part;
import mekhq.campaign.parts.equipment.AmmoBin;
import mekhq.campaign.personnel.Person;
import mekhq.campaign.stratcon.StratconCampaignState;
import mekhq.campaign.stratcon.StratconCoords;
import mekhq.campaign.stratcon.StratconScenario;
import mekhq.campaign.stratcon.StratconTrackState;
import mekhq.gui.dialog.resupplyAndCaches.DialogInterception;
import mekhq.gui.baseComponents.immersiveDialogs.ImmersiveDialogSimple;
import mekhq.gui.dialog.resupplyAndCaches.DialogPlayerConvoyOption;
import mekhq.gui.dialog.resupplyAndCaches.DialogResupplyFocus;
import mekhq.gui.dialog.resupplyAndCaches.DialogRoleplayEvent;
import mekhq.gui.dialog.resupplyAndCaches.DialogSwindled;

/**
Expand Down Expand Up @@ -153,7 +157,6 @@ public static void performResupply(Resupply resupply, AtBContract contract, int
return;
}

final Campaign campaign = resupply.getCampaign();
final boolean isIndependent = contract.getCommandRights().isIndependent();
final boolean isGuerrilla = contract.getContractType().isGuerrillaWarfare();
final ResupplyType resupplyType = resupply.getResupplyType();
Expand Down Expand Up @@ -265,7 +268,7 @@ public static void makeSmugglerDelivery(Resupply resupply) {
final AtBContract contract = resupply.getContract();
int swindleChance = contract.getMoraleLevel().ordinal();

if (Compute.randomInt(10) < swindleChance) {
if (randomInt(10) < swindleChance) {
new DialogSwindled(resupply);
} else {
final Campaign campaign = resupply.getCampaign();
Expand Down Expand Up @@ -392,7 +395,7 @@ public static void processConvoy(Resupply resupply, List<Part> convoyContents, @
interceptionChance = Math.max(1, interceptionChance);

// With interception chance calculated, we check to see whether an interception or event has occurred.
if (Compute.randomInt(10) < interceptionChance) {
if (randomInt(10) < interceptionChance) {
generateInterceptionOrConvoyEvent(resupply, playerConvoy, convoyContents, interceptionChance);
} else {
completeSuccessfulDelivery(resupply, convoyContents);
Expand Down Expand Up @@ -421,7 +424,7 @@ private static void generateInterceptionOrConvoyEvent(Resupply resupply, @Nullab
final Campaign campaign = resupply.getCampaign();
final AtBContract contract = resupply.getContract();

if (Compute.randomInt(10) < interceptionChance) {
if (randomInt(10) < interceptionChance) {
processConvoyInterception(resupply, convoy, convoyContents);
} else {
// If it is an NPC convoy, we skip roleplay events
Expand Down Expand Up @@ -450,18 +453,21 @@ private static void generateInterceptionOrConvoyEvent(Resupply resupply, @Nullab
STATUS_FORWARD + Compute.randomInt(100) + STATUS_AFTERWARD,
commanderAddress);
} else {
int roll = Compute.randomInt(2);
int roll = randomInt(2);

if (morale.isAdvancing() || morale.isWeakened()) {
morale = roll == 0 ? (morale.isAdvancing() ? DOMINATING : CRITICAL) : STALEMATE;
}

eventText = getFormattedTextAt(RESOURCE_BUNDLE,
STATUS_FORWARD + "Enemy" + morale + Compute.randomInt(50) + STATUS_AFTERWARD,
STATUS_FORWARD + "Enemy" + morale + randomInt(50) + STATUS_AFTERWARD,
commanderAddress);
}

new DialogRoleplayEvent(campaign, convoy, eventText);
Person speaker = campaign.getPerson(convoy.getForceCommanderID());
String outOfCharacterMessage = getFormattedTextAt(RESOURCE_BUNDLE, "outOfCharacter.roleplay");
new ImmersiveDialogSimple(campaign, speaker, null, eventText, null, outOfCharacterMessage, null, false);

completeSuccessfulDelivery(resupply, convoyContents);
}
}
Expand Down Expand Up @@ -509,8 +515,8 @@ private static void processConvoyInterception(Resupply resupply, @Nullable Force
final Campaign campaign = resupply.getCampaign();
final AtBContract contract = resupply.getContract();

// Trigger a dialog to inform the user an interception has taken place
new DialogInterception(resupply, targetConvoy);
// Trigger a dialog to inform the user that an interception has taken place
displayDialog(targetConvoy, campaign, contract);

// Determine which scenario template to use based on convoy state
String templateAddress = GENERIC;
Expand Down Expand Up @@ -622,6 +628,43 @@ private static void processConvoyInterception(Resupply resupply, @Nullable Force
}
}

private static void displayDialog(Force targetConvoy, Campaign campaign, AtBContract contract) {
Person speaker;
String inCharacterMessage = "";
String commanderAddress = campaign.getCommanderAddress(false);
if (targetConvoy != null) {
speaker = campaign.getPerson(targetConvoy.getForceCommanderID());

Hangar hangar = campaign.getHangar();
if (targetConvoy.forceContainsOnlyVTOLForces(hangar, false) ||
targetConvoy.forceContainsOnlyAerialForces(hangar, false, false)) {
inCharacterMessage = getFormattedTextAt(RESOURCE_BUNDLE,
"statusUpdateIntercepted.boilerplate",
commanderAddress);
}
} else {
// We invent an NPC driver for NPC convoys
speaker = campaign.newPerson(GROUND_VEHICLE_DRIVER, contract.getEmployerCode(), Gender.RANDOMIZE);
}

if (inCharacterMessage.isBlank()) {
inCharacterMessage = getFormattedTextAt(RESOURCE_BUNDLE,
"statusUpdateIntercepted" + randomInt(20) + ".text",
campaign.getCommanderAddress(false));
}

String outOfCharacterMessage = getFormattedTextAt(RESOURCE_BUNDLE, "outOfCharacter.intercepted");

new ImmersiveDialogSimple(campaign,
speaker,
null,
inCharacterMessage,
null,
outOfCharacterMessage,
null,
false);
}

/**
* Handles the fallback scenario where a resupply convoy escapes.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,26 @@
*
* Catalyst Game Labs and the Catalyst Game Labs logo are trademarks of
* InMediaRes Productions, LLC.
*
* MechWarrior Copyright Microsoft Corporation. MekHQ was created under
* Microsoft's "Game Content Usage Rules"
* <https://www.xbox.com/en-US/developers/rules> and it is not endorsed by or
* affiliated with Microsoft.
*/
package mekhq.campaign.mission.resupplyAndCaches;

import static java.lang.Math.max;
import static megamek.common.Compute.randomInt;
import static mekhq.campaign.force.ForceType.CONVOY;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.CARGO_MULTIPLIER;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.RESUPPLY_AMMO_TONNAGE;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.RESUPPLY_ARMOR_TONNAGE;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.calculateTargetCargoTonnage;
import static mekhq.campaign.personnel.enums.PersonnelStatus.KIA;
import static mekhq.utilities.MHQInternationalization.getFormattedTextAt;

import java.util.UUID;

import megamek.common.Compute;
import mekhq.campaign.Campaign;
import mekhq.campaign.force.Force;
Expand All @@ -35,17 +52,7 @@
import mekhq.campaign.personnel.Person;
import mekhq.campaign.personnel.enums.PersonnelStatus;
import mekhq.campaign.unit.Unit;
import mekhq.gui.dialog.resupplyAndCaches.DialogAbandonedConvoy;

import java.util.UUID;

import static java.lang.Math.max;
import static mekhq.campaign.force.ForceType.CONVOY;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.CARGO_MULTIPLIER;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.RESUPPLY_AMMO_TONNAGE;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.RESUPPLY_ARMOR_TONNAGE;
import static mekhq.campaign.mission.resupplyAndCaches.Resupply.calculateTargetCargoTonnage;
import static mekhq.campaign.personnel.enums.PersonnelStatus.KIA;
import mekhq.gui.baseComponents.immersiveDialogs.ImmersiveDialogSimple;

/**
* Utility class for managing resupply operations and events in MekHQ campaigns.
Expand All @@ -65,6 +72,8 @@
* <p>This utility is central to the logistics and event-handling systems present in MekHQ's resupply mechanics.</p>
*/
public class ResupplyUtilities {
private static final String RESOURCE_BUNDLE = "mekhq.resources.Resupply";

/**
* Processes an abandoned convoy, managing the removal of units and determining the fate of the
* convoy's crew members.
Expand Down Expand Up @@ -94,7 +103,22 @@ public static void processAbandonedConvoy(Campaign campaign, AtBContract contrac
}

if (force.isForceType(CONVOY) && force.getScenarioId() == scenarioId) {
new DialogAbandonedConvoy(campaign, contract, force);
Person speaker = campaign.getPerson(force.getForceCommanderID());

String commanderAddress = campaign.getCommanderAddress(false);
String inCharacterMessage = getFormattedTextAt(RESOURCE_BUNDLE,
"statusUpdateAbandoned" + randomInt(20) + ".text",
commanderAddress);
String outOfCharacterMessage = getFormattedTextAt(RESOURCE_BUNDLE, "outOfCharacter.abandoned");

new ImmersiveDialogSimple(campaign,
speaker,
null,
inCharacterMessage,
null,
outOfCharacterMessage,
null,
false);

for (UUID unitID : force.getAllUnits(false)) {
Unit unit = campaign.getUnit(unitID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
*
* Catalyst Game Labs and the Catalyst Game Labs logo are trademarks of
* InMediaRes Productions, LLC.
*
* MechWarrior Copyright Microsoft Corporation. MekHQ was created under
* Microsoft's "Game Content Usage Rules"
* <https://www.xbox.com/en-US/developers/rules> and it is not endorsed by or
* affiliated with Microsoft.
*/
package mekhq.gui.dialog.resupplyAndCaches;

Expand Down Expand Up @@ -57,10 +62,9 @@
import mekhq.campaign.personnel.Person;

/**
* This class provides a utility method to display a custom dialog related to abandoned convoys in the MekHQ game. The
* dialog includes detailed information and visuals, like the convoy commander or speaker, a status update message, and
* employer details.
* @deprecated Unused
*/
@Deprecated(since = "0.05.06", forRemoval = true)
public class DialogAbandonedConvoy extends JDialog {
final int LEFT_WIDTH = UIUtil.scaleForGUI(200);
final int RIGHT_WIDTH = UIUtil.scaleForGUI(400);
Expand Down
Loading
Loading
0