From c2e3983181358479b136c30f758afcc3ab1c744c Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 15:11:14 -0600 Subject: [PATCH 1/8] Remove redundant logging statement in Procurement.java The info-level logging of `successfulParts` was removed as it was unnecessary and could lead to clutter in the logs. This change improves code clarity and ensures logs are more meaningful. --- MekHQ/src/mekhq/campaign/market/procurement/Procurement.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/market/procurement/Procurement.java b/MekHQ/src/mekhq/campaign/market/procurement/Procurement.java index 92533651e7..de97c58c16 100644 --- a/MekHQ/src/mekhq/campaign/market/procurement/Procurement.java +++ b/MekHQ/src/mekhq/campaign/market/procurement/Procurement.java @@ -112,8 +112,6 @@ public List makeProcurementChecks(List parts, boolean useHardExtinct } } - logger.info(successfulParts); - return successfulParts; } From a4f721d5ba8ebfd69b474d472ebe09e403715066 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 15:11:23 -0600 Subject: [PATCH 2/8] Adjust handling of ammo and armor weights in resupply logic Ensured ammo and armor are consistently treated as 5t batches across all resupply calculations, regardless of actual weight. Standardized logic to improve accuracy and prevent inconsistencies in cargo management. Updated related UI and utility methods to reflect this adjustment. --- MekHQ/src/mekhq/campaign/mission/Loot.java | 8 ++++++++ .../GenerateResupplyContents.java | 19 +++++++++++-------- .../resupplyAndCaches/PerformResupply.java | 13 ++++++++++--- .../resupplyAndCaches/ResupplyUtilities.java | 6 ++++-- .../src/mekhq/gui/view/MissionViewPanel.java | 2 +- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/mission/Loot.java b/MekHQ/src/mekhq/campaign/mission/Loot.java index 242025bcd9..d1c035bbf8 100644 --- a/MekHQ/src/mekhq/campaign/mission/Loot.java +++ b/MekHQ/src/mekhq/campaign/mission/Loot.java @@ -33,8 +33,10 @@ import mekhq.campaign.finances.Money; import mekhq.campaign.finances.enums.TransactionType; import mekhq.campaign.mission.enums.ScenarioType; +import mekhq.campaign.parts.Armor; import mekhq.campaign.parts.Part; import mekhq.campaign.parts.enums.PartQuality; +import mekhq.campaign.parts.equipment.AmmoBin; import mekhq.campaign.rating.IUnitRating; import mekhq.campaign.unit.Unit; import mekhq.utilities.MHQXMLUtility; @@ -214,6 +216,12 @@ public void getLoot(Campaign campaign, Scenario scenario, double partWeight = part.getTonnage(); partWeight = partWeight == 0 ? RESUPPLY_MINIMUM_PART_WEIGHT : partWeight; + if (part instanceof AmmoBin || part instanceof Armor) { + // Ammo and Armor are delivered in batches of 5t, + // so we need to make sure we're treating them as 5t no matter their actual weight. + partWeight = 5; + } + if (isResupply) { if (cargo - partWeight < 0) { abandonedParts.add("
- " + part.getName() + " (" + partWeight + " tons)"); diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/GenerateResupplyContents.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/GenerateResupplyContents.java index 26ba01902f..13b1cbab33 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/GenerateResupplyContents.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/GenerateResupplyContents.java @@ -76,10 +76,6 @@ public enum DropType { * @param usePlayerConvoys Indicates whether player convoy cargo capacity should be applied. */ static void getResupplyContents(Resupply resupply, DropType dropType, boolean usePlayerConvoys) { - // Ammo and Armor are delivered in batches of 5, so we need to make sure to multiply their - // weight by five when picking these items. - final int WEIGHT_MULTIPLIER = dropType == DropType.DROP_TYPE_PARTS ? 1 : 5; - double targetCargoTonnage = resupply.getTargetCargoTonnage(); if (usePlayerConvoys) { final int targetCargoTonnagePlayerConvoy = resupply.getTargetCargoTonnagePlayerConvoy(); @@ -112,7 +108,8 @@ static void getResupplyContents(Resupply resupply, DropType dropType, boolean us case DROP_TYPE_AMMO -> ammoBinPool; }; - while ((availableSpace > 0) && (!relevantPartsPool.isEmpty())) { + double currentLoad = 0; + while ((currentLoad < availableSpace) && (!relevantPartsPool.isEmpty())) { Part potentialPart = switch(dropType) { case DROP_TYPE_PARTS -> getRandomDrop(partsPool, negotiatorSkill); case DROP_TYPE_ARMOR -> getRandomDrop(armorPool, negotiatorSkill); @@ -155,10 +152,16 @@ static void getResupplyContents(Resupply resupply, DropType dropType, boolean us case DROP_TYPE_AMMO -> ammoBinPool.remove(potentialPart); } - double partWeight = potentialPart.getTonnage(); - partWeight = partWeight == 0 ? RESUPPLY_MINIMUM_PART_WEIGHT : partWeight; + // Ammo and Armor are delivered in batches of 5t, + // so we need to make sure we're treating them as 5t no matter their actual weight. + double partWeight = 5; + + if (dropType == DropType.DROP_TYPE_PARTS) { + partWeight = potentialPart.getTonnage(); + partWeight = partWeight == 0 ? RESUPPLY_MINIMUM_PART_WEIGHT : partWeight; + } - availableSpace -= partWeight * WEIGHT_MULTIPLIER; + currentLoad += partWeight; droppedItems.add(potentialPart); } } diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java index 2bcff6920f..8ff9d6950d 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java @@ -167,7 +167,13 @@ public static void performResupply(Resupply resupply, AtBContract contract, int double totalTonnage = 0; for (Part part : resupply.getConvoyContents()) { - totalTonnage += part.getTonnage() * (part instanceof Armor || part instanceof AmmoBin ? 5 : 1); + if (part instanceof AmmoBin || part instanceof Armor) { + // Ammo and Armor are delivered in batches of 5t, + // so we need to make sure we're treating them as 5t no matter their actual weight. + totalTonnage += 5; + } else { + totalTonnage += part.getTonnage(); + } } logger.info("totalTonnage: " + totalTonnage); @@ -255,7 +261,6 @@ public static void makeSmugglerDelivery(Resupply resupply) { public static void loadPlayerConvoys(Resupply resupply) { // Ammo and Armor are delivered in batches of 5, so we need to make sure to multiply their // weight by five when picking these items. - final int WEIGHT_MULTIPLIER = 5; final Campaign campaign = resupply.getCampaign(); final Map playerConvoys = resupply.getPlayerConvoys(); @@ -286,7 +291,9 @@ public static void loadPlayerConvoys(Resupply resupply) { tonnage = tonnage == 0 ? RESUPPLY_MINIMUM_PART_WEIGHT : tonnage; if (part instanceof AmmoBin || part instanceof Armor) { - tonnage *= WEIGHT_MULTIPLIER; + // Ammo and Armor are delivered in batches of 5t, + // so we need to make sure we're treating them as 5t no matter their actual weight. + tonnage = 5; } if (cargoCapacity - tonnage >= 0) { diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java index ca0150aede..e16d6f4114 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java @@ -32,8 +32,8 @@ import java.util.UUID; import java.util.Vector; -import static java.lang.Math.ceil; import static java.lang.Math.floor; +import static java.lang.Math.max; import static mekhq.campaign.mission.resupplyAndCaches.Resupply.CARGO_MULTIPLIER; import static mekhq.campaign.mission.resupplyAndCaches.Resupply.calculateTargetCargoTonnage; import static mekhq.campaign.personnel.enums.PersonnelStatus.KIA; @@ -143,7 +143,9 @@ private static void decideCrewMemberFate(Campaign campaign, Person person) { */ public static int estimateCargoRequirements(Campaign campaign, AtBContract contract) { double targetTonnage = calculateTargetCargoTonnage(campaign, contract) * CARGO_MULTIPLIER; - return (int) Math.ceil(targetTonnage); + + // Armor and ammo are always delivered in blocks of 5t, so cargo will never be less than 10t + return max(10, (int) Math.ceil(targetTonnage)); } /** diff --git a/MekHQ/src/mekhq/gui/view/MissionViewPanel.java b/MekHQ/src/mekhq/gui/view/MissionViewPanel.java index 9e980cae6d..b66854022c 100644 --- a/MekHQ/src/mekhq/gui/view/MissionViewPanel.java +++ b/MekHQ/src/mekhq/gui/view/MissionViewPanel.java @@ -994,7 +994,7 @@ public void mouseClicked(MouseEvent e) { pnlStats.add(lblCargoRequirement, gridBagConstraints); txtCargoRequirement.setName("txtCargoRequirement"); - txtCargoRequirement.setText(estimateCargoRequirements(campaign, contract) + "t"); + txtCargoRequirement.setText(estimateCargoRequirements(campaign, contract) + "t+"); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = y++; From 0be3c95731b5393586796ae200fbb3062bb082ae Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 15:55:10 -0600 Subject: [PATCH 3/8] Refactored resupply logic with enhanced part key handling Implemented a new method `getPartKey` to generate unique part keys for more consistent identification. Adjusted drop weight calculations and warehouse weight modifiers to use the new key system. Improved readability and accuracy of resupply adjustments. --- .../mission/resupplyAndCaches/Resupply.java | 88 +++++++++++++++---- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java index 0ab0c1dcd1..ebea48171f 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java @@ -21,6 +21,7 @@ import java.math.BigInteger; import java.util.*; +import static java.lang.Math.floor; import static java.lang.Math.min; import static java.lang.Math.round; import static megamek.common.MiscType.F_SPONSON_TURRET; @@ -545,9 +546,11 @@ private Map collectParts() { } int dropWeight = part instanceof MissingPart ? 10 : 1; + dropWeight = (int) floor(dropWeight * getPartMultiplier(part)); + PartDetails partDetails = new PartDetails(part, dropWeight); - processedParts.merge(part.toString(), partDetails, (oldValue, newValue) -> { + processedParts.merge(getPartKey(part), partDetails, (oldValue, newValue) -> { oldValue.setWeight(oldValue.getWeight() + newValue.getWeight()); return oldValue; }); @@ -563,6 +566,29 @@ private Map collectParts() { return processedParts; } + /** + * Generates a key for the given part based on its name and tonnage. + * + *

The key is a combination of the part's name and its tonnage, separated by a colon. + * For specific part types such as {@link AmmoBin} and {@link Armor}, the tonnage is + * always set to a value of 5, regardless of the actual tonnage.

+ * + * @param part The {@link Part} for which the key is generated. Must not be {@code null}. + * @return A unique key in the format {@code "partName:partTonnage"}, where + * {@code partName} is the name of the part and {@code partTonnage} is the + * tonnage of the part or a fixed value of 5 for {@link AmmoBin} and {@link Armor}. + */ + private static String getPartKey(Part part) { + String partName = part.getName(); + double partTonnage = part.getTonnage(); + + if (part instanceof AmmoBin || part instanceof Armor) { + partTonnage = 5; + } + + return partName + ':' + partTonnage; + } + /** * Checks if a part is ineligible for inclusion in the resupply process. Ineligibility is * determined based on exclusion lists, unit structure compatibility, and transporter checks. @@ -648,29 +674,55 @@ private boolean checkTransporter(Part part) { } /** - * Applies warehouse weight modifiers to the collected parts list by comparing the - * in-campaign warehouse spare parts with the current list. Removes parts from the pool - * if the warehouse already contains enough resources to offset demand. + * Adjusts the provided parts list by applying warehouse weight modifiers. * - * @param partsList A map of part names and their respective part details to modify. + *

This method compares the in-campaign warehouse's spare parts inventory with the given + * parts list and reduces the weight (quantity) of parts in the list based on the warehouse + * stock. If the warehouse contains enough resources to fully satisfy the demand for a part, + * the part is removed from the parts list.

+ * + *

The adjustments are performed as follows: + *

    + *
  • For each part in the warehouse: + *
      + *
    • The weight of the part in the part list is reduced by the quantity available + * in the warehouse.
    • + *
    • If the weight becomes zero or negative, the part is flagged for removal.
    • + *
    + *
  • + *
  • All flagged parts are then removed from the part list.
  • + *
+ *

+ * + * @param partsList A map containing part identifiers (keys) and their corresponding {@link PartDetails}. + * The map will be modified to reflect the warehouse adjustments. */ private void applyWarehouseWeightModifiers(Map partsList) { - // Because of how AmmoBins work, we're always considering the campaign to have 0 rounds - // of ammo in storage, we could avoid this, but I don't think it's necessary. + // Adjust based on the quantity in the warehouse for (Part part : campaign.getWarehouse().getSpareParts()) { - PartDetails targetPart = partsList.get(part.toString()); - if (targetPart != null) { - int spareCount = part.getQuantity(); - double multiplier = getPartMultiplier(part); - - double targetPartCount = targetPart.getWeight() * multiplier; - if ((targetPartCount - spareCount) < 1) { - partsList.remove(part.toString()); - } else { - targetPart.setWeight(min(1, targetPartCount - spareCount)); - } + int weight = part.getQuantity(); + PartDetails partDetails = new PartDetails(part, weight); + + partsList.merge(getPartKey(part), partDetails, (oldValue, newValue) -> { + oldValue.setWeight(oldValue.getWeight() - newValue.getWeight()); + return oldValue; + }); + } + + // Remove any items that now have 0 (or negative) tickets left in the pool + List removalList = new ArrayList<>(); + for (PartDetails partDetails : partsList.values()) { + Part part = partDetails.getPart(); + double weight = partDetails.getWeight(); + + if (weight <= 0) { + removalList.add(getPartKey(part)); } } + + for (String removalKey : removalList) { + partsList.remove(removalKey); + } } /** From 3d2dbe6b003edfbb0f736a5a18066531035af408 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 15:57:45 -0600 Subject: [PATCH 4/8] Refactored interception check for Routed morale level Removed redundant interception chance check for Routed morale. The code now directly exits early if the enemy is Routed, improving clarity and reducing duplication. This simplifies the logic without altering functionality. --- .../mission/resupplyAndCaches/PerformResupply.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java index 8ff9d6950d..e305bebb7a 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java @@ -45,7 +45,6 @@ import static mekhq.campaign.mission.enums.AtBMoraleLevel.CRITICAL; import static mekhq.campaign.mission.enums.AtBMoraleLevel.DOMINATING; -import static mekhq.campaign.mission.enums.AtBMoraleLevel.ROUTED; import static mekhq.campaign.mission.enums.AtBMoraleLevel.STALEMATE; import static mekhq.campaign.mission.resupplyAndCaches.GenerateResupplyContents.DropType.DROP_TYPE_AMMO; import static mekhq.campaign.mission.resupplyAndCaches.GenerateResupplyContents.DropType.DROP_TYPE_ARMOR; @@ -333,18 +332,14 @@ public static void processConvoy(Resupply resupply, List convoyContents, @ // First, we need to identify whether the convoy has been intercepted. AtBMoraleLevel morale = contract.getMoraleLevel(); + // There isn't any chance of an interception if the enemy is Routed, so early-exit if (morale.isRouted()) { completeSuccessfulDelivery(resupply, convoyContents); + return; } int interceptionChance = morale.ordinal(); - // There isn't any chance of an interception if the enemy is Routed, so early-exit - if (interceptionChance == ROUTED.ordinal()) { - completeSuccessfulDelivery(resupply, convoyContents); - return; - } - // This chance is modified by convoy weight, for player convoys this is easy - we just // calculate the weight of all units in the convoy. For NPC convoys, we need to get a bit // creative, as we have no way to determine their size prior to any interception scenario. From 1b9c425f855f6f34477b4b714a1f093a42653680 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 15:58:27 -0600 Subject: [PATCH 5/8] Fix typo in Resupply.properties descriptions Corrected "partially vehicles" to "partially crewed vehicles" in multiple instances to improve clarity and accuracy in convoy descriptions within the resupply properties file. --- MekHQ/resources/mekhq/resources/Resupply.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MekHQ/resources/mekhq/resources/Resupply.properties b/MekHQ/resources/mekhq/resources/Resupply.properties index 54119a3a15..16c58f407c 100644 --- a/MekHQ/resources/mekhq/resources/Resupply.properties +++ b/MekHQ/resources/mekhq/resources/Resupply.properties @@ -67,8 +67,8 @@ usePlayerConvoyOptional.text=%s, our employer has a delivery ready for us but is
\
This enhanced delivery requires an estimated %s tons of cargo space across all\ \ convoys. However, as this is an estimate final tonnage may vary. We currently have a total of\ - \ %s available space across %s convoy%s. Damaged or partially vehicles are not\ - \ considered available.\ + \ %s available space across %s convoy%s. Damaged or partially crewed vehicles are\ + \ not considered available.\
\
Be aware that this can be a risky job and if we fail to defend any intercepted convoys all\ \ units and personnel will be lost.\ @@ -81,7 +81,7 @@ usePlayerConvoyForced.text=%s, our employer has a delivery ready for us, but we
\
This delivery requires an estimated %s tons of cargo space across all convoys. However,\ \ as this is an estimate final tonnage may vary. We currently have a total of %s available\ - \ space across %s convoy%s. Damaged or partially vehicles are not considered available.\ + \ space across %s convoy%s. Damaged or partially crewed vehicles are not considered available.\
\
Be aware that this can be a risky job and if we fail to defend any intercepted convoys all\ \ units and personnel will be lost.\ From cbee6fa9f0f030e8ea5bfd68b61b487f476bd4be Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 16:04:01 -0600 Subject: [PATCH 6/8] Skip empty AmmoStorage in resupply weight calculation Adjusted resupply logic to skip empty AmmoStorage items when calculating part weighting. This prevents empty ammo from incorrectly affecting resupply prioritization, ensuring more accurate resource allocation. --- .../mekhq/campaign/mission/resupplyAndCaches/Resupply.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java index ebea48171f..cae811e70e 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java @@ -701,6 +701,12 @@ private void applyWarehouseWeightModifiers(Map partsList) { // Adjust based on the quantity in the warehouse for (Part part : campaign.getWarehouse().getSpareParts()) { int weight = part.getQuantity(); + + // We don't want empty AmmoStorage to reduce Resupply weighting + if (part instanceof AmmoStorage && (((AmmoStorage) part).getShots() == 0)) { + continue; + } + PartDetails partDetails = new PartDetails(part, weight); partsList.merge(getPartKey(part), partDetails, (oldValue, newValue) -> { From ead98a80ba3a4e228c60d96d052fb07774dca469 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 16:09:33 -0600 Subject: [PATCH 7/8] Refactored resupply tonnage handling for Ammo and Armor Replaced hardcoded tonnage values for Ammo and Armor with constants `RESUPPLY_AMMO_TONNAGE` and `RESUPPLY_ARMOR_TONNAGE`. This improves maintainability and consistency across resupply-related code. --- MekHQ/src/mekhq/campaign/mission/Loot.java | 10 +++++---- .../resupplyAndCaches/PerformResupply.java | 22 ++++++++++--------- .../mission/resupplyAndCaches/Resupply.java | 12 ++++++---- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/mission/Loot.java b/MekHQ/src/mekhq/campaign/mission/Loot.java index d1c035bbf8..8dd7a6efe7 100644 --- a/MekHQ/src/mekhq/campaign/mission/Loot.java +++ b/MekHQ/src/mekhq/campaign/mission/Loot.java @@ -47,6 +47,8 @@ import java.util.*; import static mekhq.campaign.mission.resupplyAndCaches.GenerateResupplyContents.RESUPPLY_MINIMUM_PART_WEIGHT; +import static mekhq.campaign.mission.resupplyAndCaches.Resupply.RESUPPLY_AMMO_TONNAGE; +import static mekhq.campaign.mission.resupplyAndCaches.Resupply.RESUPPLY_ARMOR_TONNAGE; import static mekhq.utilities.ReportingUtilities.CLOSING_SPAN_TAG; import static mekhq.utilities.ReportingUtilities.spanOpeningWithCustomColor; @@ -216,10 +218,10 @@ public void getLoot(Campaign campaign, Scenario scenario, double partWeight = part.getTonnage(); partWeight = partWeight == 0 ? RESUPPLY_MINIMUM_PART_WEIGHT : partWeight; - if (part instanceof AmmoBin || part instanceof Armor) { - // Ammo and Armor are delivered in batches of 5t, - // so we need to make sure we're treating them as 5t no matter their actual weight. - partWeight = 5; + if (part instanceof AmmoBin) { + partWeight = RESUPPLY_AMMO_TONNAGE; + } else if (part instanceof Armor) { + partWeight = RESUPPLY_ARMOR_TONNAGE; } if (isResupply) { diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java index e305bebb7a..6db3ff71f9 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/PerformResupply.java @@ -51,6 +51,8 @@ import static mekhq.campaign.mission.resupplyAndCaches.GenerateResupplyContents.DropType.DROP_TYPE_PARTS; import static mekhq.campaign.mission.resupplyAndCaches.GenerateResupplyContents.RESUPPLY_MINIMUM_PART_WEIGHT; import static mekhq.campaign.mission.resupplyAndCaches.GenerateResupplyContents.getResupplyContents; +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.ResupplyType.RESUPPLY_CONTRACT_END; import static mekhq.campaign.mission.resupplyAndCaches.Resupply.ResupplyType.RESUPPLY_LOOT; import static mekhq.campaign.mission.resupplyAndCaches.ResupplyUtilities.forceContainsMajorityVTOLForces; @@ -166,10 +168,10 @@ public static void performResupply(Resupply resupply, AtBContract contract, int double totalTonnage = 0; for (Part part : resupply.getConvoyContents()) { - if (part instanceof AmmoBin || part instanceof Armor) { - // Ammo and Armor are delivered in batches of 5t, - // so we need to make sure we're treating them as 5t no matter their actual weight. - totalTonnage += 5; + if (part instanceof AmmoBin) { + totalTonnage += RESUPPLY_AMMO_TONNAGE; + } else if (part instanceof Armor) { + totalTonnage += RESUPPLY_ARMOR_TONNAGE; } else { totalTonnage += part.getTonnage(); } @@ -212,9 +214,9 @@ public static void makeDelivery(Resupply resupply, @Nullable List contents for (Part part : contents) { if (part instanceof AmmoBin) { campaign.getQuartermaster().addAmmo(((AmmoBin) part).getType(), - ((AmmoBin) part).getFullShots() * 5); + ((AmmoBin) part).getFullShots() * RESUPPLY_AMMO_TONNAGE); } else if (part instanceof Armor) { - int quantity = (int) Math.ceil(((Armor) part).getArmorPointsPerTon() * 5); + int quantity = (int) Math.ceil(((Armor) part).getArmorPointsPerTon() * RESUPPLY_ARMOR_TONNAGE); ((Armor) part).setAmount(quantity); campaign.getWarehouse().addPart(part, true); } else { @@ -289,10 +291,10 @@ public static void loadPlayerConvoys(Resupply resupply) { double tonnage = part.getTonnage(); tonnage = tonnage == 0 ? RESUPPLY_MINIMUM_PART_WEIGHT : tonnage; - if (part instanceof AmmoBin || part instanceof Armor) { - // Ammo and Armor are delivered in batches of 5t, - // so we need to make sure we're treating them as 5t no matter their actual weight. - tonnage = 5; + if (part instanceof AmmoBin) { + tonnage = RESUPPLY_AMMO_TONNAGE; + } else if (part instanceof Armor) { + tonnage = RESUPPLY_ARMOR_TONNAGE; } if (cargoCapacity - tonnage >= 0) { diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java index cae811e70e..4e98dab774 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/Resupply.java @@ -66,6 +66,8 @@ public class Resupply { private Money convoyContentsValueCalculated; public static final int CARGO_MULTIPLIER = 4; + public static final int RESUPPLY_AMMO_TONNAGE = 1; + public static final int RESUPPLY_ARMOR_TONNAGE = 5; private static final MMLogger logger = MMLogger.create(Resupply.class); @@ -571,19 +573,21 @@ private Map collectParts() { * *

The key is a combination of the part's name and its tonnage, separated by a colon. * For specific part types such as {@link AmmoBin} and {@link Armor}, the tonnage is - * always set to a value of 5, regardless of the actual tonnage.

+ * always set to a set value, regardless of the actual tonnage.

* * @param part The {@link Part} for which the key is generated. Must not be {@code null}. * @return A unique key in the format {@code "partName:partTonnage"}, where * {@code partName} is the name of the part and {@code partTonnage} is the - * tonnage of the part or a fixed value of 5 for {@link AmmoBin} and {@link Armor}. + * tonnage of the part or a fixed value for {@link AmmoBin} and {@link Armor}. */ private static String getPartKey(Part part) { String partName = part.getName(); double partTonnage = part.getTonnage(); - if (part instanceof AmmoBin || part instanceof Armor) { - partTonnage = 5; + if (part instanceof AmmoBin) { + partTonnage = RESUPPLY_AMMO_TONNAGE; + } else if (part instanceof Armor) { + partTonnage = RESUPPLY_ARMOR_TONNAGE; } return partName + ':' + partTonnage; From 81076ea5af4a876965a3997b6087ade7227d6200 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Mon, 6 Jan 2025 16:39:24 -0600 Subject: [PATCH 8/8] Refactored cargo requirement calculation in ResupplyUtilities Updated the minimum cargo requirement logic to use constants for ammo and armor tonnage blocks. This ensures better readability and maintainability by centralizing the values. The change aligns the calculation with standardized tonnage sums. --- .../mission/resupplyAndCaches/ResupplyUtilities.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java index e16d6f4114..121e06313a 100644 --- a/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java +++ b/MekHQ/src/mekhq/campaign/mission/resupplyAndCaches/ResupplyUtilities.java @@ -35,6 +35,8 @@ import static java.lang.Math.floor; import static java.lang.Math.max; 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.EntityUtilities.getEntityFromUnitId; @@ -144,8 +146,9 @@ private static void decideCrewMemberFate(Campaign campaign, Person person) { public static int estimateCargoRequirements(Campaign campaign, AtBContract contract) { double targetTonnage = calculateTargetCargoTonnage(campaign, contract) * CARGO_MULTIPLIER; - // Armor and ammo are always delivered in blocks of 5t, so cargo will never be less than 10t - return max(10, (int) Math.ceil(targetTonnage)); + // Armor and ammo are always delivered in blocks, so cargo will never be less than the sum + // of those blocks + return max(RESUPPLY_AMMO_TONNAGE + RESUPPLY_ARMOR_TONNAGE, (int) Math.ceil(targetTonnage)); } /**