From be4bfb87f8495326b0a2a78fe699c29e6afae207 Mon Sep 17 00:00:00 2001 From: sleet01 Date: Mon, 5 Aug 2024 12:23:33 -0700 Subject: [PATCH 1/2] Tweak automatic munition selection for low-ammo-count Autocannons --- .../generator/TeamLoadoutGenerator.java | 70 +++++++++++++++++-- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java b/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java index ff3acb03d52..c0ff1858df5 100644 --- a/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java +++ b/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java @@ -113,7 +113,7 @@ public class TeamLoadoutGenerator { "Acid", "Laser Inhibiting", "Follow The Leader", "Heat-Seeking", "Tandem-Charge", "Thunder-Active", "Thunder-Augmented", "Thunder-Vibrabomb", "Thunder-Inferno", "AAAMissile Ammo", "ASMissile Ammo", "ASWEMissile Ammo", "ArrowIVMissile Ammo", - "AlamoMissile Ammo" + "AlamoMissile Ammo", "Precision", "Armor-Piercing" )); public static final ArrayList TYPE_LIST = new ArrayList(List.of( @@ -652,15 +652,62 @@ public static ReconfigurationParameters generateParameters( // region Imperative mutators private static void setACImperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { + setAC5Imperatives(e, mt, rp); + setAC10Imperatives(e, mt, rp); setAC20Imperatives(e, mt, rp); } + private static int getACWeaponCount(Entity e, String size) { + return (int) e.getWeaponList().stream() + .filter(w -> w.getName().toLowerCase().contains("ac") && w.getName().contains(size)).count(); + } + + private static int getACAmmoCount(Entity e, String size) { + return (int) e.getAmmo().stream() + .filter(w -> w.getName().toLowerCase().contains("ac") && w.getName().contains(size)).count(); + } + + // Set low-ammo-count AC5 carriers to use Caseless if ammo is <= 1/2 ton per tube + private static boolean setAC5Imperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { + int ac5Count = getACWeaponCount(e, "5"); + + // TODO: remove this block when implementing new anti-ground Aero errata + // Ignore Aeros, which can't use most alt munitions, and those without AC5s. + if (e.isAero() || ac5Count == 0) { + return false; + } + + // Always use Caseless if AC/5 ammo tons <= count of tubes + int ac5Ammo = getACAmmoCount(e, "5"); + if (ac5Ammo <= ac5Count/2.0) { + mt.insertImperative(e.getFullChassis(), e.getModel(), "any", "AC/5", "Caseless"); + return true; + } + return false; + } + + // Set low-ammo-count AC10 carriers to use Caseless if ammo is <= 1 ton per tube + private static boolean setAC10Imperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { + int ac10Count = getACWeaponCount(e, "10"); + + // TODO: remove this block when implementing new anti-ground Aero errata + // Ignore Aeros, which can't use most alt munitions, and those without AC10s. + if (e.isAero() || ac10Count == 0) { + return false; + } + + // Always use Caseless if AC/10 ammo tons <= count of tubes + int ac10Ammo = getACAmmoCount(e, "10"); + if (ac10Ammo <= ac10Count) { + mt.insertImperative(e.getFullChassis(), e.getModel(), "any", "AC/10", "Caseless"); + return true; + } + return false; + } + // Set low-ammo-count AC20 carriers to use Caseless exclusively. private static boolean setAC20Imperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { - int ac20Count = 0; - int ac20Ammo = 0; - ac20Count = (int) e.getWeaponList().stream() - .filter(w -> w.getName().toLowerCase().contains("ac") && w.getName().contains("20")).count(); + int ac20Count = getACWeaponCount(e, "20"); // TODO: remove this block when implementing new anti-ground Aero errata // Ignore Aeros, which can't use most alt munitions, and those without AC20s. @@ -669,8 +716,7 @@ private static boolean setAC20Imperatives(Entity e, MunitionTree mt, Reconfigura } // Always use Caseless if AC/20 ammo tons <= count of tubes - ac20Ammo = (int) e.getAmmo().stream() - .filter(w -> w.getName().toLowerCase().contains("ac") && w.getName().contains("20")).count(); + int ac20Ammo = getACAmmoCount(e, "20"); if (ac20Ammo <= ac20Count) { mt.insertImperative(e.getFullChassis(), e.getModel(), "any", "AC/20", "Caseless"); return true; @@ -2022,6 +2068,16 @@ public ArrayList getMunitionTypesInWeightOrder(Map weigh weightMap.entrySet().stream() .sorted((E1, E2) -> E2.getValue().compareTo(E1.getValue())) .forEach(k -> orderedTypes.add(String.valueOf(k))); + // Make Standard the first entry if tied with other highest-weight munitions + for (String munitionString: orderedTypes) { + if (munitionString.contains("Standard") && !orderedTypes.get(0).contains("Standard")) { + int idx = orderedTypes.indexOf(munitionString); + if (weightMap.get("Standard") == Double.parseDouble(orderedTypes.get(0).split("=")[1])) { + Collections.swap(orderedTypes, idx, 0); + break; + } + } + } return orderedTypes; } From 4a08954518e20636e0dda744d5dc21c0bf4f93e3 Mon Sep 17 00:00:00 2001 From: sleet01 Date: Fri, 9 Aug 2024 15:34:46 -0700 Subject: [PATCH 2/2] Refactored ac2/5/10/20 imperatives into one --- .../generator/TeamLoadoutGenerator.java | 110 ++++++++---------- 1 file changed, 49 insertions(+), 61 deletions(-) diff --git a/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java b/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java index c0ff1858df5..ec16d24e24f 100644 --- a/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java +++ b/megamek/src/megamek/client/generator/TeamLoadoutGenerator.java @@ -652,85 +652,73 @@ public static ReconfigurationParameters generateParameters( // region Imperative mutators private static void setACImperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { - setAC5Imperatives(e, mt, rp); - setAC10Imperatives(e, mt, rp); - setAC20Imperatives(e, mt, rp); + applyACCaselessImperative(e, mt, rp); } private static int getACWeaponCount(Entity e, String size) { + // Only applies to non-LB-X AC weapons return (int) e.getWeaponList().stream() - .filter(w -> w.getName().toLowerCase().contains("ac") && w.getName().contains(size)).count(); + .filter( + w -> w.getName().toLowerCase() + .contains("ac") + && !w.getName().toLowerCase() + .contains("lb") + && w.getName() + .contains(size) + ).count(); } private static int getACAmmoCount(Entity e, String size) { + // Only applies to non-LB-X AC weapons return (int) e.getAmmo().stream() - .filter(w -> w.getName().toLowerCase().contains("ac") && w.getName().contains(size)).count(); + .filter( + w -> w.getName().toLowerCase() + .contains("ac") + && !w.getName().toLowerCase() + .contains("lb") + && w.getName() + .contains(size) + ).count(); } - // Set low-ammo-count AC5 carriers to use Caseless if ammo is <= 1/2 ton per tube - private static boolean setAC5Imperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { - int ac5Count = getACWeaponCount(e, "5"); - - // TODO: remove this block when implementing new anti-ground Aero errata - // Ignore Aeros, which can't use most alt munitions, and those without AC5s. - if (e.isAero() || ac5Count == 0) { - return false; - } - - // Always use Caseless if AC/5 ammo tons <= count of tubes - int ac5Ammo = getACAmmoCount(e, "5"); - if (ac5Ammo <= ac5Count/2.0) { - mt.insertImperative(e.getFullChassis(), e.getModel(), "any", "AC/5", "Caseless"); - return true; - } - return false; - } - - // Set low-ammo-count AC10 carriers to use Caseless if ammo is <= 1 ton per tube - private static boolean setAC10Imperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { - int ac10Count = getACWeaponCount(e, "10"); - + private static boolean applyACCaselessImperative(Entity e, MunitionTree mt, ReconfigurationParameters rp) { // TODO: remove this block when implementing new anti-ground Aero errata - // Ignore Aeros, which can't use most alt munitions, and those without AC10s. - if (e.isAero() || ac10Count == 0) { + // Ignore Aeros, which can't use most alt munitions. + if (e.isAero()) { return false; } - // Always use Caseless if AC/10 ammo tons <= count of tubes - int ac10Ammo = getACAmmoCount(e, "10"); - if (ac10Ammo <= ac10Count) { - mt.insertImperative(e.getFullChassis(), e.getModel(), "any", "AC/10", "Caseless"); - return true; - } - return false; - } + boolean swapped = false; + Map caliburToRatioMap = Map.of( + "2", 0.25, // if 1 ton or less per 4 AC/2 barrels, + "5", 0.5, // if 1 ton or less per 2 AC/5 barrels, + "10", 1.0, // if 1 ton or less per AC/10 or AC/20 barrel + "20", 1.0 // Replace existing imperatives with Caseless only. + ); - // Set low-ammo-count AC20 carriers to use Caseless exclusively. - private static boolean setAC20Imperatives(Entity e, MunitionTree mt, ReconfigurationParameters rp) { - int ac20Count = getACWeaponCount(e, "20"); + // Iterate over any possible Autocannons and update their ammo imperatives if count of bins/barrel + // is at or below the relevant ratio. + for (String calibur: caliburToRatioMap.keySet()) { + int barrelCount = getACWeaponCount(e, calibur); + int binCount = getACAmmoCount(e, calibur); - // TODO: remove this block when implementing new anti-ground Aero errata - // Ignore Aeros, which can't use most alt munitions, and those without AC20s. - if (e.isAero() || ac20Count == 0) { - return false; - } - - // Always use Caseless if AC/20 ammo tons <= count of tubes - int ac20Ammo = getACAmmoCount(e, "20"); - if (ac20Ammo <= ac20Count) { - mt.insertImperative(e.getFullChassis(), e.getModel(), "any", "AC/20", "Caseless"); - return true; - } - - // Add one "Standard" to the start of the existing imperatives operating on this - // unit. - String[] imperatives = mt.getEffectiveImperative(e.getFullChassis(), e.getModel(), "any", "AC/20").split(":"); - if (!imperatives[0].contains("Standard")) { - mt.insertImperative(e.getFullChassis(), e.getModel(), "any", "AC/20", - "Standard:" + String.join(":", imperatives)); + if (barrelCount == 0) { + // Nothing to do + continue; + } else if (((double) binCount) / barrelCount <= caliburToRatioMap.get(calibur)) { + // Replace any existing imperatives with Caseless as default + mt.insertImperative( + e.getFullChassis(), + e.getModel(), + "any", + "AC/" + calibur, + "Caseless" + ); + swapped = true; + } } - return false; + return swapped; } // Set Artemis LRM carriers to use Artemis LRMs