From 7fa2472d1310a7cf2a356ed86e10596124cc57cc Mon Sep 17 00:00:00 2001 From: cwspain Date: Tue, 31 Oct 2023 20:16:08 -0500 Subject: [PATCH 01/12] Include inferno, plasma, and incendiary infantry weapons with flamers in having heat mode. --- .../weapons/infantry/InfantryWeapon.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index 0d8e66c7105..0cf8dd67b49 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -15,10 +15,11 @@ import megamek.common.*; import megamek.common.actions.WeaponAttackAction; +import megamek.common.options.GameOptions; +import megamek.common.options.OptionsConstants; import megamek.common.weapons.AttackHandler; import megamek.common.weapons.Weapon; import megamek.server.GameManager; -import megamek.server.Server; /** * @author Sebastian Brocks @@ -248,11 +249,25 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa Mounted m = game.getEntity(waa.getEntityId()).getEquipment(waa.getWeaponId()); if (((null != m) && (m.curMode().equals(Weapon.MODE_FLAMER_HEAT) || (waa.getEntity(game).isSupportVehicle() - && m.getLinked() != null - && m.getLinked().getType() != null - && (((AmmoType) m.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)))))) { + && m.getLinked() != null + && m.getLinked().getType() != null + && (((AmmoType) m.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)))))) { return new InfantryHeatWeaponHandler(toHit, waa, game, manager); } return new InfantryWeaponHandler(toHit, waa, game, manager); } + + public void adaptToGameOptions(GameOptions gOp) { + super.adaptToGameOptions(gOp); + // Additional flags that are treated like flamers for infantry weapons + if (hasFlag(WeaponType.F_INFERNO) || hasFlag(WeaponType.F_PLASMA) || hasFlag(F_INCENDIARY_NEEDLES)) { + if (!gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + addMode(MODE_FLAMER_DAMAGE); + addMode(MODE_FLAMER_HEAT); + } else { + removeMode(MODE_FLAMER_DAMAGE); + removeMode(MODE_FLAMER_HEAT); + } + } + } } From 51dc21577b06c94c44381d853b2068f8f1cc547c Mon Sep 17 00:00:00 2001 From: cwspain Date: Tue, 31 Oct 2023 21:52:32 -0500 Subject: [PATCH 02/12] Added subclass of Mounted to manage modes for two weapons. --- megamek/src/megamek/common/Entity.java | 12 +- .../megamek/common/InfantryWeaponMounted.java | 111 ++++++++++++++++++ megamek/src/megamek/common/Mounted.java | 43 +++++-- .../common/loaders/BLKInfantryFile.java | 32 ++--- 4 files changed, 160 insertions(+), 38 deletions(-) create mode 100644 megamek/src/megamek/common/InfantryWeaponMounted.java diff --git a/megamek/src/megamek/common/Entity.java b/megamek/src/megamek/common/Entity.java index 737709aa033..b593d9f366c 100644 --- a/megamek/src/megamek/common/Entity.java +++ b/megamek/src/megamek/common/Entity.java @@ -3953,7 +3953,7 @@ public boolean isWeaponValidForPhase(Mounted mounted) { && (!(mounted.getType().hasFlag(WeaponType.F_AMS) && mounted.curMode().equals(Weapon.MODE_AMS_ON))) && (!(mounted.getType().hasFlag(WeaponType.F_AMS) && mounted.curMode().equals(Weapon.MODE_AMS_OFF))) && (!mounted.getType().hasFlag(WeaponType.F_AMSBAY)) - && (!(mounted.getType().hasModes() && mounted.curMode().equals("Point Defense"))) + && (!(mounted.hasModes() && mounted.curMode().equals("Point Defense"))) && ((mounted.getLinked() == null) || mounted.getLinked().getType().hasFlag(MiscType.F_AP_MOUNT) || (mounted.getLinked().getUsableShotsLeft() > 0))) { @@ -4375,7 +4375,7 @@ public int countWorkingMisc(BigInteger flag, int location) { OUTER: for (Mounted m : getMisc()) { if (!m.isInoperable() && m.getType().hasFlag(flag) && ((location == -1) || (m.getLocation() == location))) { - if (m.getType().hasModes()) { + if (m.hasModes()) { for (Enumeration e = m.getType().getModes(); e.hasMoreElements();) { if (e.nextElement().equals("On") && !m.curMode().equals("On")) { continue OUTER; @@ -4393,7 +4393,7 @@ public int countWorkingMisc(String internalName, int location) { OUTER: for (Mounted m : getMisc()) { if (!m.isInoperable() && m.getType().getInternalName().equalsIgnoreCase(internalName) && ((location == -1) || (m.getLocation() == location))) { - if (m.getType().hasModes()) { + if (m.hasModes()) { for (Enumeration e = m.getType().getModes(); e.hasMoreElements();) { if (e.nextElement().equals("On") && !m.curMode().equals("On")) { continue OUTER; @@ -11433,7 +11433,7 @@ public boolean hasLinkedMGA(Mounted mounted) { && m.getType().hasFlag(WeaponType.F_MGA) && !(m.isDestroyed() || m.isBreached()) && m.getBayWeapons().contains(getEquipmentNum(mounted)) - && m.getType().hasModes() && m.curMode().equals("Linked")) { + && m.hasModes() && m.curMode().equals("Linked")) { return true; } } @@ -11887,9 +11887,7 @@ public void setGameOptions() { } for (Mounted mounted : getWeaponList()) { - if (mounted.getType() instanceof Weapon) { - ((Weapon) mounted.getType()).adaptToGameOptions(game.getOptions()); - } + mounted.adaptToGameOptions(game.getOptions()); mounted.setModesForMapType(); } diff --git a/megamek/src/megamek/common/InfantryWeaponMounted.java b/megamek/src/megamek/common/InfantryWeaponMounted.java new file mode 100644 index 00000000000..ff7da7d23cf --- /dev/null +++ b/megamek/src/megamek/common/InfantryWeaponMounted.java @@ -0,0 +1,111 @@ +/* + * MegaMek - Copyright (C) 2023 - The MegaMek Team + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +package megamek.common; + +import megamek.common.options.GameOptions; +import megamek.common.weapons.Weapon; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * Specialized mount used for infantry units with primary and secondary weapons. + * This handles special features of both weapons. Infantry units that only have + * a single weapon should use {@link Mounted}. + */ +public class InfantryWeaponMounted extends Mounted { + + transient private EquipmentType otherWeapon; + private final String typeName; + + transient private List modes; + + /** + * Creates a Mounted that deals with combined feature of a primary and a secondary weapon. + * Infantry units with a single type of weapon should use {@link Mounted} + * + * @param entity The infantry unit + * @param rangeWeapon The weapon used to calculate range. + * @param otherWeapon The other weapon + */ + public InfantryWeaponMounted(Entity entity, EquipmentType rangeWeapon, EquipmentType otherWeapon) { + super(entity, rangeWeapon); + this.typeName = otherWeapon.getInternalName(); + this.otherWeapon = otherWeapon; + rebuildModeList(); + } + + public EquipmentType getOtherWeapon() { + if (otherWeapon == null) { + otherWeapon = EquipmentType.get(typeName); + } + return otherWeapon; + } + + public void rebuildModeList() { + modes = new ArrayList<>(); + for (Enumeration e = getType().getModes(); e.hasMoreElements(); ) { + modes.add(e.nextElement()); + } + for (Enumeration e = getOtherWeapon().getModes(); e.hasMoreElements(); ) { + EquipmentMode mode = e.nextElement(); + if (!modes.contains(mode)) { + modes.add(mode); + } + } + } + + private List getModes() { + if (modes == null) { + rebuildModeList(); + } + return modes; + } + + @Override + public int getModesCount() { + return getModes().size(); + } + + @Override + protected EquipmentMode getMode(int mode) { + return getModes().get(mode); + } + + @Override + public boolean hasModes() { + return !getModes().isEmpty(); + } + + public boolean canInstantSwitch(int newMode) { + if (getType().hasModes() && (getType().getMode(newMode) != null)) { + return super.canInstantSwitch(newMode); + } else { + String newModeName = getOtherWeapon().getMode(newMode).getName(); + String curModeName = curMode().getName(); + return getType().hasInstantModeSwitch() + && !getOtherWeapon().isNextTurnModeSwitch(newModeName) + && !getOtherWeapon().isNextTurnModeSwitch(curModeName); + } + } + + @Override + public void adaptToGameOptions(GameOptions options) { + ((Weapon) getOtherWeapon()).adaptToGameOptions(options); + super.adaptToGameOptions(options); + rebuildModeList(); + } +} diff --git a/megamek/src/megamek/common/Mounted.java b/megamek/src/megamek/common/Mounted.java index 9e04dd0eebb..63aff9268c4 100644 --- a/megamek/src/megamek/common/Mounted.java +++ b/megamek/src/megamek/common/Mounted.java @@ -16,6 +16,7 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.enums.GamePhase; +import megamek.common.options.GameOptions; import megamek.common.options.OptionsConstants; import megamek.common.options.WeaponQuirks; import megamek.common.weapons.AmmoWeapon; @@ -254,13 +255,31 @@ public EquipmentType getType() { return (null != type) ? type : (type = EquipmentType.get(typeName)); } + public int getModesCount() { + return type.getModesCount(); + } + + protected EquipmentMode getMode(int mode) { + return type.getMode(mode); + } + + public boolean hasModes() { + return type.hasModes(); + } + + public void adaptToGameOptions(GameOptions options) { + if (getType() instanceof Weapon) { + ((Weapon) getType()).adaptToGameOptions(options); + } + } + /** * @return the current mode of the equipment, or null if it's * not available. */ public EquipmentMode curMode() { - if ((mode >= 0) && (mode < type.getModesCount())) { - return type.getMode(mode); + if ((mode >= 0) && (mode < getModesCount())) { + return getMode(mode); } return EquipmentMode.getMode("None"); } @@ -269,7 +288,7 @@ public EquipmentMode curMode() { * @return the pending mode of the equipment. */ public EquipmentMode pendingMode() { - if ((pendingMode < 0) || (pendingMode >= type.getModesCount())) { + if ((pendingMode < 0) || (pendingMode >= getModesCount())) { return EquipmentMode.getMode("None"); } return type.getMode(pendingMode); @@ -284,24 +303,24 @@ public EquipmentMode pendingMode() { * @return new mode number, or -1 if it's not available. */ public int switchMode(boolean forward) { - if (type.hasModes()) { + if (hasModes()) { int nMode = 0; if (pendingMode > -1) { if (forward) { - nMode = (pendingMode + 1) % type.getModesCount(); + nMode = (pendingMode + 1) % getModesCount(); } else { nMode = (pendingMode - 1); if (nMode < 0) { - nMode = type.getModesCount() - 1; + nMode = getModesCount() - 1; } } } else { if (forward) { - nMode = (mode + 1) % type.getModesCount(); + nMode = (mode + 1) % getModesCount(); } else { nMode = (mode - 1); if (nMode < 0) { - nMode = type.getModesCount() - 1; + nMode = getModesCount() - 1; } } } @@ -318,8 +337,8 @@ public int switchMode(boolean forward) { * @return new mode number on success, -1 otherwise. */ public int setMode(String newMode) { - for (int x = 0, e = type.getModesCount(); x < e; x++) { - if (type.getMode(x).equals(newMode)) { + for (int x = 0, e = getModesCount(); x < e; x++) { + if (getMode(x).equals(newMode)) { setMode(x); return x; } @@ -334,9 +353,9 @@ public int setMode(String newMode) { * the number of the desired new mode */ public boolean setMode(int newMode) { - if (type.hasModes()) { + if (hasModes()) { - if (newMode >= type.getModesCount()) { + if (newMode >= getModesCount()) { return false; } diff --git a/megamek/src/megamek/common/loaders/BLKInfantryFile.java b/megamek/src/megamek/common/loaders/BLKInfantryFile.java index 9db1a166463..81d96e6e34b 100644 --- a/megamek/src/megamek/common/loaders/BLKInfantryFile.java +++ b/megamek/src/megamek/common/loaders/BLKInfantryFile.java @@ -13,13 +13,7 @@ */ package megamek.common.loaders; -import megamek.common.Entity; -import megamek.common.EntityMovementMode; -import megamek.common.EquipmentType; -import megamek.common.Infantry; -import megamek.common.LocationFullException; -import megamek.common.MiscType; -import megamek.common.WeaponType; +import megamek.common.*; import megamek.common.util.BuildingBlock; import megamek.common.weapons.infantry.InfantryWeapon; @@ -102,7 +96,7 @@ public Entity getEntity() throws EntityLoadingException { } String primaryName = dataFile.getDataAsString("Primary")[0]; EquipmentType ptype = EquipmentType.get(primaryName); - if ((null == ptype) || !(ptype instanceof InfantryWeapon)) { + if (!(ptype instanceof InfantryWeapon)) { throw new EntityLoadingException("primary weapon is not an infantry weapon"); } t.setPrimaryWeapon((InfantryWeapon) ptype); @@ -120,18 +114,18 @@ public Entity getEntity() throws EntityLoadingException { // if there is more than one secondary weapon per squad, then add that // to the unit // otherwise add the primary weapon - if ((t.getSecondaryWeaponsPerSquad() > 1) && (null != stype)) { - try { - t.addEquipment(stype, Infantry.LOC_INFANTRY); - } catch (LocationFullException ex) { - throw new EntityLoadingException(ex.getMessage()); - } + Mounted m; + if ((t.getSecondaryWeaponsPerSquad() > 1)) { + m = new InfantryWeaponMounted(t, stype, ptype); + } else if (t.getSecondaryWeaponsPerSquad() == 1) { + m = new InfantryWeaponMounted(t, ptype, stype); } else { - try { - t.addEquipment(ptype, Infantry.LOC_INFANTRY); - } catch (LocationFullException ex) { - throw new EntityLoadingException(ex.getMessage()); - } + m = new Mounted(t, ptype); + } + try { + t.addEquipment(m, Infantry.LOC_INFANTRY, false); + } catch (LocationFullException ex) { + throw new EntityLoadingException(ex.getMessage()); } //TAG infantry have separate attacks for primary and secondary weapons. if (null != stype && stype.hasFlag(WeaponType.F_TAG)) { From 58bcd22136e3ffb528332f99222d760767dd0144 Mon Sep 17 00:00:00 2001 From: cwspain Date: Tue, 31 Oct 2023 21:53:09 -0500 Subject: [PATCH 03/12] Use Mounted::hasModes instead of EquipmentType::hasModes. --- .../megamek/client/commands/FireCommand.java | 2 +- .../client/ui/swing/FiringDisplay.java | 6 ++--- .../src/megamek/client/ui/swing/MapMenu.java | 4 +-- .../ui/swing/TargetingPhaseDisplay.java | 2 +- .../ui/swing/unitDisplay/SystemPanel.java | 6 ++--- .../ui/swing/unitDisplay/WeaponPanel.java | 14 +++++----- megamek/src/megamek/common/Compute.java | 4 +-- megamek/src/megamek/common/WeaponType.java | 2 +- .../common/actions/WeaponAttackAction.java | 26 +++++++++---------- .../common/weapons/EnergyWeaponHandler.java | 2 +- .../common/weapons/HyperLaserHandler.java | 2 +- .../common/weapons/MissileWeaponHandler.java | 2 +- .../megamek/common/weapons/PPCHandler.java | 4 +-- .../weapons/PulseLaserWeaponHandler.java | 2 +- .../VariableSpeedPulseLaserWeaponHandler.java | 2 +- .../megamek/common/weapons/WeaponHandler.java | 8 +++--- 16 files changed, 44 insertions(+), 44 deletions(-) diff --git a/megamek/src/megamek/client/commands/FireCommand.java b/megamek/src/megamek/client/commands/FireCommand.java index 438bf840b77..77f545e9d31 100644 --- a/megamek/src/megamek/client/commands/FireCommand.java +++ b/megamek/src/megamek/client/commands/FireCommand.java @@ -274,7 +274,7 @@ private String calculateToHit(int weaponId, Targetable target) { str += " Can't shoot: " + Messages.getString("FiringDisplay.alreadyFired"); } else if ((m.getType().hasFlag(WeaponType.F_AUTO_TARGET) && !m.curMode().equals(Weapon.MODE_AMS_MANUAL)) - || (m.getType().hasModes() && m.curMode().equals("Point Defense"))) { + || (m.hasModes() && m.curMode().equals("Point Defense"))) { str += " Can't shoot: " + Messages.getString("FiringDisplay.autoFiringWeapon"); } else if (getClient().getGame().getPhase().isFiring() && m.isInBearingsOnlyMode()) { diff --git a/megamek/src/megamek/client/ui/swing/FiringDisplay.java b/megamek/src/megamek/client/ui/swing/FiringDisplay.java index 3bc36060e02..a29b2b26c76 100644 --- a/megamek/src/megamek/client/ui/swing/FiringDisplay.java +++ b/megamek/src/megamek/client/ui/swing/FiringDisplay.java @@ -1006,7 +1006,7 @@ protected void changeMode(boolean forward) { // If the weapon does not have modes, just exit. Mounted m = ce().getEquipment(wn); - if ((m == null) || !m.getType().hasModes()) { + if ((m == null) || !m.hasModes()) { return; } @@ -1960,7 +1960,7 @@ public void updateTarget() { setFireEnabled(false); } else if ((m.getType().hasFlag(WeaponType.F_AUTO_TARGET) && !m.curMode().equals(Weapon.MODE_AMS_MANUAL)) - || (m.getType().hasModes() && m.curMode().equals("Point Defense"))) { + || (m.hasModes() && m.curMode().equals("Point Defense"))) { clientgui.getUnitDisplay().wPan.setToHit(Messages.getString("FiringDisplay.autoFiringWeapon")); setFireEnabled(false); } else if (m.isInBearingsOnlyMode()) { @@ -2395,7 +2395,7 @@ protected void setFireModeEnabled(boolean enabled) { * @param m The active weapon */ protected void adaptFireModeEnabled(Mounted m) { - setFireModeEnabled(m.isModeSwitchable() & m.getType().hasModes()); + setFireModeEnabled(m.isModeSwitchable() & m.hasModes()); } protected void setFireCalledEnabled(boolean enabled) { diff --git a/megamek/src/megamek/client/ui/swing/MapMenu.java b/megamek/src/megamek/client/ui/swing/MapMenu.java index 134b9652497..74b3f4658f4 100644 --- a/megamek/src/megamek/client/ui/swing/MapMenu.java +++ b/megamek/src/megamek/client/ui/swing/MapMenu.java @@ -1405,8 +1405,8 @@ private JMenu createModeMenu() { int weaponNum = gui.getUnitDisplay().wPan.getSelectedWeaponNum(); Mounted mounted = myEntity.getEquipment(weaponNum); - if ((mounted != null) && mounted.getType().hasModes()) { - for (int pos = 0; pos < mounted.getType().getModesCount(); pos++) { + if ((mounted != null) && mounted.hasModes()) { + for (int pos = 0; pos < mounted.getModesCount(); pos++) { menu.add(createModeJMenuItem(mounted, pos)); } } diff --git a/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java b/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java index e495921c105..10bb3af3842 100644 --- a/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java +++ b/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java @@ -716,7 +716,7 @@ private void changeMode(boolean forward) { // If the weapon does not have modes, just exit. Mounted m = ce().getEquipment(wn); - if ((m == null) || !m.getType().hasModes()) { + if ((m == null) || !m.hasModes()) { return; } diff --git a/megamek/src/megamek/client/ui/swing/unitDisplay/SystemPanel.java b/megamek/src/megamek/client/ui/swing/unitDisplay/SystemPanel.java index c7f45c26708..c9c892c6114 100644 --- a/megamek/src/megamek/client/ui/swing/unitDisplay/SystemPanel.java +++ b/megamek/src/megamek/client/ui/swing/unitDisplay/SystemPanel.java @@ -415,7 +415,7 @@ private String getMountedDisplay(Mounted m, int loc, CriticalSlot cs) { sb.append(hotLoaded); } - if (m.getType().hasModes()) { + if (m.hasModes()) { if (!m.curMode().getDisplayableName().isEmpty()) { sb.append(" ("); sb.append(m.curMode().getDisplayableName()); @@ -451,7 +451,7 @@ public void itemStateChanged(ItemEvent ev) { && (ev.getStateChange() == ItemEvent.SELECTED)) { Mounted m = getSelectedEquipment(); CriticalSlot cs = getSelectedCritical(); - if ((m != null) && m.getType().hasModes()) { + if ((m != null) && m.hasModes()) { int nMode = m_chMode.getSelectedIndex(); if (nMode >= 0) { @@ -760,7 +760,7 @@ public void valueChanged(ListSelectionEvent event) { int round = client.getGame().getRoundCount(); boolean inSquadron = ((en instanceof Aero) && ((Aero) en) .isInASquadron()); - if ((m != null) && bOwner && m.getType().hasModes()) { + if ((m != null) && bOwner && m.hasModes()) { if (!m.isInoperable() && !m.isDumping() && (en.isActive() || en.isActive(round) || inSquadron) && m.isModeSwitchable()) { diff --git a/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java b/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java index 7d6b5feb9a6..36bb651529b 100644 --- a/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java +++ b/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java @@ -249,7 +249,7 @@ public String getElementAt(int index) { } // Fire Mode - lots of things have variable modes - if (wtype.hasModes()) { + if (mounted.hasModes()) { wn.append(' '); wn.append(mounted.curMode().getDisplayableName()); @@ -1749,7 +1749,7 @@ private void displaySelected() { } wDamR.setText(damage.toString()); } else if (wtype.hasFlag(WeaponType.F_ENERGY) - && wtype.hasModes() + && mounted.hasModes() && (unitDisplay.getClientGUI() != null) && unitDisplay.getClientGUI().getClient().getGame().getOptions().booleanOption( OptionsConstants.ADVCOMBAT_TACOPS_ENERGY_WEAPONS)) { if (mounted.hasChargedCapacitor() != 0) { @@ -1786,7 +1786,7 @@ private void displaySelected() { extremeR = wtype.getWExtremeRange(); } else if (wtype.hasFlag(WeaponType.F_PDBAY)) { //Point Defense bays have a variable range, depending on the mode they're in - if (wtype.hasModes() && mounted.curMode().equals("Point Defense")) { + if (mounted.hasModes() && mounted.curMode().equals("Point Defense")) { shortR = 1; wShortR.setText("1"); } else { @@ -2369,7 +2369,7 @@ private void updateAttackValues(Mounted weapon, Mounted ammo) { wShortR.setText("1-12"); } else if (wtype.hasFlag(WeaponType.F_PDBAY)) { //Point Defense bays have a variable range too, depending on the mode they're in - if (wtype.hasModes() && weapon.curMode().equals("Point Defense")) { + if (weapon.hasModes() && weapon.curMode().equals("Point Defense")) { wShortR.setText("1"); } else { wShortR.setText("1-6"); @@ -2594,13 +2594,13 @@ private void compileWeaponBay(Mounted weapon, boolean isCapital) { } // check for bracketing double mult = 1.0; - if (wtype.hasModes() && weapon.curMode().equals("Bracket 80%")) { + if (weapon.hasModes() && weapon.curMode().equals("Bracket 80%")) { mult = 0.8; } - if (wtype.hasModes() && weapon.curMode().equals("Bracket 60%")) { + if (weapon.hasModes() && weapon.curMode().equals("Bracket 60%")) { mult = 0.6; } - if (wtype.hasModes() && weapon.curMode().equals("Bracket 40%")) { + if (weapon.hasModes() && weapon.curMode().equals("Bracket 40%")) { mult = 0.4; } avShort = mult * avShort; diff --git a/megamek/src/megamek/common/Compute.java b/megamek/src/megamek/common/Compute.java index b0ae48d0fa3..24224f7f801 100644 --- a/megamek/src/megamek/common/Compute.java +++ b/megamek/src/megamek/common/Compute.java @@ -6593,7 +6593,7 @@ public static int dialDownDamage(Mounted weapon, WeaponType wtype) { public static int dialDownDamage(Mounted weapon, WeaponType wtype, int range) { int toReturn = wtype.getDamage(range); - if (!wtype.hasModes()) { + if (!weapon.hasModes()) { return toReturn; } @@ -6632,7 +6632,7 @@ public static int dialDownHeat(Mounted weapon, WeaponType wtype) { public static int dialDownHeat(Mounted weapon, WeaponType wtype, int range) { int toReturn = wtype.getHeat(); - if (!wtype.hasModes()) { + if (!weapon.hasModes()) { return toReturn; } diff --git a/megamek/src/megamek/common/WeaponType.java b/megamek/src/megamek/common/WeaponType.java index 4b37d4d680d..b8585228f0a 100644 --- a/megamek/src/megamek/common/WeaponType.java +++ b/megamek/src/megamek/common/WeaponType.java @@ -482,7 +482,7 @@ public int[] getRanges(Mounted weapon) { } } if (hasFlag(WeaponType.F_PDBAY)) { - if (hasModes() && weapon.curMode().equals("Point Defense")) { + if (weapon.hasModes() && weapon.curMode().equals("Point Defense")) { sRange = 1; } else { sRange = 6; diff --git a/megamek/src/megamek/common/actions/WeaponAttackAction.java b/megamek/src/megamek/common/actions/WeaponAttackAction.java index 2f67648ec58..6880918e047 100644 --- a/megamek/src/megamek/common/actions/WeaponAttackAction.java +++ b/megamek/src/megamek/common/actions/WeaponAttackAction.java @@ -366,7 +366,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, || atype.countsAsFlak() ); - boolean isIndirect = (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT)); + boolean isIndirect = (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT)); // BMM p. 31, semi-guided indirect missile attacks vs tagged targets ignore terrain modifiers boolean semiGuidedIndirectVsTaggedTarget = isIndirect && @@ -2236,7 +2236,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // Gauss weapons using the TacOps powered down rule can't fire if ((wtype instanceof GaussWeapon) - && wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_GAUSS_POWERED_DOWN)) { + && weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_GAUSS_POWERED_DOWN)) { return Messages.getString("WeaponAttackAction.WeaponNotReady"); } @@ -2397,7 +2397,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta return Messages.getString("WeaponAttackAction.NoWorkingMGs"); } // Or if the array is off - if (wtype.hasFlag(WeaponType.F_MGA) && wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_AMS_OFF)) { + if (wtype.hasFlag(WeaponType.F_MGA) && weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_AMS_OFF)) { return Messages.getString("WeaponAttackAction.MGArrayOff"); } else if (wtype.hasFlag(WeaponType.F_MG)) { // and you can't fire an individual MG if it's in an array @@ -2518,7 +2518,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // Weapon Bays // Large Craft weapon bays cannot bracket small craft at short range - if (wtype.hasModes() + if (weapon.hasModes() && (weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_80) || weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_60) || weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_40)) && target.isAero() && te!= null && !te.isLargeCraft() @@ -2528,20 +2528,20 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta } // you must have enough weapons in your bay to be able to use bracketing - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_80) && (weapon.getBayWeapons().size() < 2)) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_80) && (weapon.getBayWeapons().size() < 2)) { return Messages.getString("WeaponAttackAction.BayTooSmallForBracket"); } - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_60) && (weapon.getBayWeapons().size() < 3)) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_60) && (weapon.getBayWeapons().size() < 3)) { return Messages.getString("WeaponAttackAction.BayTooSmallForBracket"); } - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_40) && (weapon.getBayWeapons().size() < 4)) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_40) && (weapon.getBayWeapons().size() < 4)) { return Messages.getString("WeaponAttackAction.BayTooSmallForBracket"); } // If you're an aero, can't fire an AMS Bay at all or a Point Defense bay that's in PD Mode if (wtype.hasFlag(WeaponType.F_AMSBAY)) { return Messages.getString("WeaponAttackAction.AutoWeapon"); - } else if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_POINT_DEFENSE)) { + } else if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_POINT_DEFENSE)) { return Messages.getString("WeaponAttackAction.PDWeapon"); } @@ -2943,7 +2943,7 @@ private static ToHitData compileWeaponToHitMods(Game game, Entity ae, Entity spo } // AAA mode makes targeting large craft more difficult - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAP_LASER_AAA) && te != null && te.isLargeCraft()) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAP_LASER_AAA) && te != null && te.isLargeCraft()) { toHit.addModifier(+1, Messages.getString("WeaponAttackAction.AAALaserAtShip")); } @@ -2958,13 +2958,13 @@ private static ToHitData compileWeaponToHitMods(Game game, Entity ae, Entity spo } // Bracketing modes - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_80)) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_80)) { toHit.addModifier(-1, Messages.getString("WeaponAttackAction.Bracket80")); } - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_60)) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_60)) { toHit.addModifier(-2, Messages.getString("WeaponAttackAction.Bracket60")); } - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_40)) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAPITAL_BRACKET_40)) { toHit.addModifier(-3, Messages.getString("WeaponAttackAction.Bracket40")); } @@ -2983,7 +2983,7 @@ private static ToHitData compileWeaponToHitMods(Game game, Entity ae, Entity spo && (wtype.getAtClass() != WeaponType.CLASS_AR10) && te != null && !te.isLargeCraft()) { // Capital Lasers have an AAA mode for shooting at small targets int aaaMod = 0; - if (wtype.hasModes() && weapon.curMode().equals(Weapon.MODE_CAP_LASER_AAA)) { + if (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_CAP_LASER_AAA)) { aaaMod = 2; } if (wtype.isSubCapital()) { diff --git a/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java b/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java index 0cbc6d58be4..f663f889c63 100644 --- a/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java @@ -54,7 +54,7 @@ protected int calcDamagePerHit() { double toReturn = wtype.getDamage(nRange); if ((game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_ENERGY_WEAPONS) - && wtype.hasModes()) || wtype.hasFlag(WeaponType.F_BOMBAST_LASER)) { + && weapon.hasModes()) || wtype.hasFlag(WeaponType.F_BOMBAST_LASER)) { toReturn = Compute.dialDownDamage(weapon, wtype, nRange); } // during a swarm, all damage gets applied as one block to one location diff --git a/megamek/src/megamek/common/weapons/HyperLaserHandler.java b/megamek/src/megamek/common/weapons/HyperLaserHandler.java index ec906e4b1f9..b32c156bbad 100644 --- a/megamek/src/megamek/common/weapons/HyperLaserHandler.java +++ b/megamek/src/megamek/common/weapons/HyperLaserHandler.java @@ -87,7 +87,7 @@ protected int calcDamagePerHit() { double toReturn = wtype.getDamage(nRange); if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_ENERGY_WEAPONS) - && wtype.hasModes()) { + && weapon.hasModes()) { toReturn = Compute.dialDownDamage(weapon, wtype, nRange); } diff --git a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java index 1fcc79bad04..b97d96fb899 100644 --- a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java @@ -1005,7 +1005,7 @@ protected boolean isNemesisConfusable() { MiscType.F_ARTEMIS) || mLinker.getType().hasFlag( MiscType.F_ARTEMIS_V) || mLinker.getType().hasFlag( MiscType.F_ARTEMIS_PROTO)))) { - if ((!weapon.getType().hasModes() || !weapon.curMode().equals("Indirect")) + if ((!weapon.hasModes() || !weapon.curMode().equals("Indirect")) && (((atype.getAmmoType() == AmmoType.T_ATM) && ((atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) || (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) diff --git a/megamek/src/megamek/common/weapons/PPCHandler.java b/megamek/src/megamek/common/weapons/PPCHandler.java index a3795293a6f..9353d7ad9f2 100644 --- a/megamek/src/megamek/common/weapons/PPCHandler.java +++ b/megamek/src/megamek/common/weapons/PPCHandler.java @@ -71,7 +71,7 @@ protected int calcDamagePerHit() { double toReturn = wtype.getDamage(nRange); if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_ENERGY_WEAPONS) - && wtype.hasModes()) { + && weapon.hasModes()) { toReturn = Compute.dialDownDamage(weapon, wtype, nRange); } @@ -136,7 +136,7 @@ protected int calcDamagePerHit() { protected boolean doChecks(Vector vPhaseReport) { // Resolve roll for disengaged field inhibitors on PPCs, if needed if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_PPC_INHIBITORS) - && wtype.hasModes() + && weapon.hasModes() && weapon.curMode().equals("Field Inhibitor OFF")) { int rollTarget = 0; int dieRoll = Compute.d6(2); diff --git a/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java b/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java index 940070dc0d1..a0fbdbcdabe 100644 --- a/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java @@ -41,7 +41,7 @@ protected int calcDamagePerHit() { double toReturn = wtype.getDamage(); if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_ENERGY_WEAPONS) - && wtype.hasModes()) { + && weapon.hasModes()) { toReturn = Compute.dialDownDamage(weapon, wtype, nRange); } diff --git a/megamek/src/megamek/common/weapons/VariableSpeedPulseLaserWeaponHandler.java b/megamek/src/megamek/common/weapons/VariableSpeedPulseLaserWeaponHandler.java index c82f05d5032..a69ea1c9fad 100644 --- a/megamek/src/megamek/common/weapons/VariableSpeedPulseLaserWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/VariableSpeedPulseLaserWeaponHandler.java @@ -48,7 +48,7 @@ protected int calcDamagePerHit() { double toReturn = wtype.getDamage(nRange); if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_ENERGY_WEAPONS) - && wtype.hasModes()) { + && weapon.hasModes()) { toReturn = Compute.dialDownDamage(weapon, wtype, nRange); } diff --git a/megamek/src/megamek/common/weapons/WeaponHandler.java b/megamek/src/megamek/common/weapons/WeaponHandler.java index a41fe90bbe1..75ec984d0c3 100644 --- a/megamek/src/megamek/common/weapons/WeaponHandler.java +++ b/megamek/src/megamek/common/weapons/WeaponHandler.java @@ -1269,13 +1269,13 @@ protected int calcAttackValue() { */ protected double getBracketingMultiplier() { double mult = 1.0; - if (wtype.hasModes() && weapon.curMode().equals("Bracket 80%")) { + if (weapon.hasModes() && weapon.curMode().equals("Bracket 80%")) { mult = 0.8; } - if (wtype.hasModes() && weapon.curMode().equals("Bracket 60%")) { + if (weapon.hasModes() && weapon.curMode().equals("Bracket 60%")) { mult = 0.6; } - if (wtype.hasModes() && weapon.curMode().equals("Bracket 40%")) { + if (weapon.hasModes() && weapon.curMode().equals("Bracket 40%")) { mult = 0.4; } return mult; @@ -1441,7 +1441,7 @@ protected void handleEntityDamage(Entity entityTarget, initHit(entityTarget); - boolean isIndirect = wtype.hasModes() && weapon.curMode().equals("Indirect"); + boolean isIndirect = weapon.hasModes() && weapon.curMode().equals("Indirect"); Hex targetHex = game.getBoard().getHex(target.getPosition()); boolean mechPokingOutOfShallowWater = unitGainsPartialCoverFromWater(targetHex, entityTarget); From 4d8e069821a4491952984ce9b1043e4479eb14f1 Mon Sep 17 00:00:00 2001 From: cwspain Date: Wed, 1 Nov 2023 10:43:42 -0500 Subject: [PATCH 04/12] Access hasModeType() through Mounted instead of the EquipmentType. --- megamek/src/megamek/client/bot/princess/FireControl.java | 4 ++-- megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java | 2 +- megamek/src/megamek/common/InfantryWeaponMounted.java | 5 +++++ megamek/src/megamek/common/Mounted.java | 4 ++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/megamek/src/megamek/client/bot/princess/FireControl.java b/megamek/src/megamek/client/bot/princess/FireControl.java index 1a25ec3c0c4..00211303157 100644 --- a/megamek/src/megamek/client/bot/princess/FireControl.java +++ b/megamek/src/megamek/client/bot/princess/FireControl.java @@ -2166,7 +2166,7 @@ public boolean entityCanIndirectFireMissile(FireControlState fireControlState, E } for (Mounted weapon : shooter.getWeaponList()) { - if (weapon.getType().hasModeType(Weapon.MODE_MISSILE_INDIRECT)) { + if (weapon.hasModeType(Weapon.MODE_MISSILE_INDIRECT)) { fireControlState.getEntityIDFStates().put(shooter.getId(), true); return true; } @@ -3244,7 +3244,7 @@ private int switchMissileMode(Mounted weapon) { // check that we're operating a missile weapon that can switch direct/indirect modes // don't bother checking non-missile weapons if (weapon.getType().hasFlag(Weapon.F_MISSILE) && - weapon.getType().hasModeType(Weapon.MODE_MISSILE_INDIRECT)) { + weapon.hasModeType(Weapon.MODE_MISSILE_INDIRECT)) { // if we are able to switch the weapon to indirect fire mode, do so and try again if (!weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT)) { diff --git a/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java b/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java index e9244471438..d1771161181 100644 --- a/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java +++ b/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java @@ -569,7 +569,7 @@ void toggleHotLoad(Collection entities, boolean hotLoadOn) { // TODO: The following should ideally be part of setHotLoad in Mounted if (hotLoadOn) { m.setMode("HotLoad"); - } else if (m.getType().hasModeType("HotLoad")) { + } else if (m.hasModeType("HotLoad")) { m.setMode(""); } updateCandidates.add(entity); diff --git a/megamek/src/megamek/common/InfantryWeaponMounted.java b/megamek/src/megamek/common/InfantryWeaponMounted.java index ff7da7d23cf..f72507f6024 100644 --- a/megamek/src/megamek/common/InfantryWeaponMounted.java +++ b/megamek/src/megamek/common/InfantryWeaponMounted.java @@ -90,6 +90,11 @@ public boolean hasModes() { return !getModes().isEmpty(); } + @Override + public boolean hasModeType(String mode) { + return modes.contains(EquipmentMode.getMode(mode)); + } + public boolean canInstantSwitch(int newMode) { if (getType().hasModes() && (getType().getMode(newMode) != null)) { return super.canInstantSwitch(newMode); diff --git a/megamek/src/megamek/common/Mounted.java b/megamek/src/megamek/common/Mounted.java index 63aff9268c4..cf33cefc28d 100644 --- a/megamek/src/megamek/common/Mounted.java +++ b/megamek/src/megamek/common/Mounted.java @@ -267,6 +267,10 @@ public boolean hasModes() { return type.hasModes(); } + public boolean hasModeType(String mode) { + return getType().hasModeType(mode); + } + public void adaptToGameOptions(GameOptions options) { if (getType() instanceof Weapon) { ((Weapon) getType()).adaptToGameOptions(options); From b239208e2a06476fd5b95dcc3cc9ccea7caa9371 Mon Sep 17 00:00:00 2001 From: cwspain Date: Wed, 1 Nov 2023 16:54:27 -0500 Subject: [PATCH 05/12] Add mode for indirect fire flame-based infantry weapons. --- .../megamek/client/bot/princess/FireControl.java | 4 ++-- .../common/actions/WeaponAttackAction.java | 3 ++- megamek/src/megamek/common/weapons/Weapon.java | 1 + .../InfantrySupportLRMInfernoWeapon.java | 8 ++++---- .../InfantrySupportMortarHeavyInfernoWeapon.java | 16 ++++++++++++++++ .../InfantrySupportMortarHeavyWeapon.java | 16 ++++++++++++++++ .../InfantrySupportMortarLightInfernoWeapon.java | 16 ++++++++++++++++ .../InfantrySupportMortarLightWeapon.java | 16 ++++++++++++++++ .../common/weapons/infantry/InfantryWeapon.java | 2 +- 9 files changed, 74 insertions(+), 8 deletions(-) diff --git a/megamek/src/megamek/client/bot/princess/FireControl.java b/megamek/src/megamek/client/bot/princess/FireControl.java index 00211303157..2a22d5c578d 100644 --- a/megamek/src/megamek/client/bot/princess/FireControl.java +++ b/megamek/src/megamek/client/bot/princess/FireControl.java @@ -2166,7 +2166,7 @@ public boolean entityCanIndirectFireMissile(FireControlState fireControlState, E } for (Mounted weapon : shooter.getWeaponList()) { - if (weapon.hasModeType(Weapon.MODE_MISSILE_INDIRECT)) { + if (weapon.hasModeType(Weapon.MODE_MISSILE_INDIRECT) || weapon.hasModeType(Weapon.MODE_INDIRECT_HEAT)) { fireControlState.getEntityIDFStates().put(shooter.getId(), true); return true; } @@ -3244,7 +3244,7 @@ private int switchMissileMode(Mounted weapon) { // check that we're operating a missile weapon that can switch direct/indirect modes // don't bother checking non-missile weapons if (weapon.getType().hasFlag(Weapon.F_MISSILE) && - weapon.hasModeType(Weapon.MODE_MISSILE_INDIRECT)) { + (weapon.hasModeType(Weapon.MODE_MISSILE_INDIRECT) || weapon.hasModeType(Weapon.MODE_INDIRECT_HEAT))) { // if we are able to switch the weapon to indirect fire mode, do so and try again if (!weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT)) { diff --git a/megamek/src/megamek/common/actions/WeaponAttackAction.java b/megamek/src/megamek/common/actions/WeaponAttackAction.java index 6880918e047..0b316923a62 100644 --- a/megamek/src/megamek/common/actions/WeaponAttackAction.java +++ b/megamek/src/megamek/common/actions/WeaponAttackAction.java @@ -366,7 +366,8 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, || atype.countsAsFlak() ); - boolean isIndirect = (weapon.hasModes() && weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT)); + boolean isIndirect = (weapon.hasModes() && (weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT) + ||weapon.curMode().equals(Weapon.MODE_INDIRECT_HEAT))); // BMM p. 31, semi-guided indirect missile attacks vs tagged targets ignore terrain modifiers boolean semiGuidedIndirectVsTaggedTarget = isIndirect && diff --git a/megamek/src/megamek/common/weapons/Weapon.java b/megamek/src/megamek/common/weapons/Weapon.java index e76dfe1ecda..8b4ecb4d7c2 100644 --- a/megamek/src/megamek/common/weapons/Weapon.java +++ b/megamek/src/megamek/common/weapons/Weapon.java @@ -76,6 +76,7 @@ public Weapon() { public static final String MODE_GAUSS_POWERED_DOWN = "Powered Down"; public static final String MODE_MISSILE_INDIRECT = "Indirect"; + public static final String MODE_INDIRECT_HEAT = "Indirect/Heat"; public static final String MODE_PPC_CHARGE = "Charge"; diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java index 349e08e0d14..aee42adb3bc 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java @@ -65,11 +65,11 @@ public void adaptToGameOptions(GameOptions gOp) { // Indirect Fire if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { - addMode(""); - addMode("Indirect"); + addMode(MODE_MISSILE_INDIRECT); + addMode(MODE_INDIRECT_HEAT); } else { - removeMode(""); - removeMode("Indirect"); + removeMode(MODE_MISSILE_INDIRECT); + removeMode(MODE_INDIRECT_HEAT); } } } diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java index 3da30721c40..8fbf8d3538c 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java @@ -18,6 +18,8 @@ package megamek.common.weapons.infantry; import megamek.common.AmmoType; +import megamek.common.options.GameOptions; +import megamek.common.options.OptionsConstants; /** * @author Ben Grills @@ -57,4 +59,18 @@ public InfantrySupportMortarHeavyInfernoWeapon() { .setAvailability(RATING_C, RATING_C, RATING_C, RATING_C); } + + @Override + public void adaptToGameOptions(GameOptions gOp) { + super.adaptToGameOptions(gOp); + + // Indirect Fire + if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { + addMode(MODE_MISSILE_INDIRECT); + addMode(MODE_INDIRECT_HEAT); + } else { + removeMode(MODE_MISSILE_INDIRECT); + removeMode(MODE_INDIRECT_HEAT); + } + } } diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyWeapon.java index a3777499baf..6527461bca3 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyWeapon.java @@ -18,6 +18,8 @@ package megamek.common.weapons.infantry; import megamek.common.AmmoType; +import megamek.common.options.GameOptions; +import megamek.common.options.OptionsConstants; /** * @author Ben Grills @@ -55,4 +57,18 @@ public InfantrySupportMortarHeavyWeapon() { .setAvailability(RATING_C, RATING_C, RATING_C, RATING_C); } + + @Override + public void adaptToGameOptions(GameOptions gOp) { + super.adaptToGameOptions(gOp); + + // Indirect Fire + if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { + addMode(""); + addMode("Indirect"); + } else { + removeMode(""); + removeMode("Indirect"); + } + } } diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightInfernoWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightInfernoWeapon.java index b2eea6b6a3c..b79118ae59a 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightInfernoWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightInfernoWeapon.java @@ -18,6 +18,8 @@ package megamek.common.weapons.infantry; import megamek.common.AmmoType; +import megamek.common.options.GameOptions; +import megamek.common.options.OptionsConstants; /** * @author Ben Grills @@ -57,4 +59,18 @@ public InfantrySupportMortarLightInfernoWeapon() { .setAvailability(RATING_C, RATING_C, RATING_C, RATING_C); } + + @Override + public void adaptToGameOptions(GameOptions gOp) { + super.adaptToGameOptions(gOp); + + // Indirect Fire + if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { + addMode(MODE_MISSILE_INDIRECT); + addMode(MODE_INDIRECT_HEAT); + } else { + removeMode(MODE_MISSILE_INDIRECT); + removeMode(MODE_INDIRECT_HEAT); + } + } } diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightWeapon.java index 50f23e6acc3..685c46ad40d 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarLightWeapon.java @@ -18,6 +18,8 @@ package megamek.common.weapons.infantry; import megamek.common.AmmoType; +import megamek.common.options.GameOptions; +import megamek.common.options.OptionsConstants; /** * @author Ben Grills @@ -55,4 +57,18 @@ public InfantrySupportMortarLightWeapon() { .setAvailability(RATING_C, RATING_C, RATING_C, RATING_C); } + + @Override + public void adaptToGameOptions(GameOptions gOp) { + super.adaptToGameOptions(gOp); + + // Indirect Fire + if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { + addMode(""); + addMode("Indirect"); + } else { + removeMode(""); + removeMode("Indirect"); + } + } } diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index 0cf8dd67b49..39f979c8d1c 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -247,7 +247,7 @@ public int getSupportVeeSlots(Entity entity) { @Override protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { Mounted m = game.getEntity(waa.getEntityId()).getEquipment(waa.getWeaponId()); - if (((null != m) && (m.curMode().equals(Weapon.MODE_FLAMER_HEAT) + if (((null != m) && (m.curMode().equals(Weapon.MODE_FLAMER_HEAT) || m.curMode().equals(Weapon.MODE_INDIRECT_HEAT) || (waa.getEntity(game).isSupportVehicle() && m.getLinked() != null && m.getLinked().getType() != null From 9334548b8b10510c80b8f47cf06f326cfd0eaeb3 Mon Sep 17 00:00:00 2001 From: cwspain Date: Wed, 1 Nov 2023 16:55:12 -0500 Subject: [PATCH 06/12] Fix heat application in InfantryHeatWeaponHandler. --- .../infantry/InfantryHeatWeaponHandler.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java b/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java index f82e8c22d20..3868bbabdfc 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java @@ -48,8 +48,7 @@ public InfantryHeatWeaponHandler(ToHitData t, WeaponAttackAction w, Game g, protected void handleEntityDamage(Entity entityTarget, Vector vPhaseReport, Building bldg, int hits, int nCluster, int bldgAbsorbs) { - if ((entityTarget instanceof Mech) - && game.getOptions().booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + if (entityTarget.tracksHeat()) { // heat hit = entityTarget.rollHitLocation(toHit.getHitTable(), toHit.getSideTable(), waa.getAimedLocation(), waa @@ -66,22 +65,25 @@ protected void handleEntityDamage(Entity entityTarget, Report r = new Report(3400); r.subject = subjectId; r.indent(2); + int nDamage = nDamPerHit * Math.min(nCluster, hits); if (entityTarget.getArmor(hit) > 0 && (entityTarget.getArmorType(hit.getLocation()) == EquipmentType.T_ARMOR_HEAT_DISSIPATING)) { - entityTarget.heatFromExternal += nDamPerHit / 2; - r.add(nDamPerHit / 2); + entityTarget.heatFromExternal += nDamage / 2; + r.add(nDamage / 2); r.choose(true); r.messageId=3406; r.add(EquipmentType.armorNames [entityTarget.getArmorType(hit.getLocation())]); } else { - entityTarget.heatFromExternal += nDamPerHit; - r.add(nDamPerHit); + entityTarget.heatFromExternal += nDamage; + r.add(nDamage); r.choose(true); } vPhaseReport.addElement(r); - } else { + } + // Do damage to non-heat-tracking unit or if using the BMM heat option + if (!entityTarget.tracksHeat() || game.getOptions().booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { super.handleEntityDamage(entityTarget, vPhaseReport, bldg, hits, nCluster, bldgAbsorbs); } From 1a17a9a3717274ae32fa0a0ed0d330306e3a194a Mon Sep 17 00:00:00 2001 From: cwspain Date: Thu, 2 Nov 2023 10:37:38 -0500 Subject: [PATCH 07/12] Fix damage+heat for BMM flamer option. --- .../megamek/common/InfantryWeaponMounted.java | 9 ++--- .../common/loaders/BLKInfantryFile.java | 16 +++++---- .../megamek/common/weapons/WeaponHandler.java | 2 +- .../infantry/InfantryHeatWeaponHandler.java | 35 ++++++++++++++++--- .../weapons/infantry/InfantryWeapon.java | 15 ++++++-- 5 files changed, 58 insertions(+), 19 deletions(-) diff --git a/megamek/src/megamek/common/InfantryWeaponMounted.java b/megamek/src/megamek/common/InfantryWeaponMounted.java index f72507f6024..3be332610b8 100644 --- a/megamek/src/megamek/common/InfantryWeaponMounted.java +++ b/megamek/src/megamek/common/InfantryWeaponMounted.java @@ -16,6 +16,7 @@ import megamek.common.options.GameOptions; import megamek.common.weapons.Weapon; +import megamek.common.weapons.infantry.InfantryWeapon; import java.util.ArrayList; import java.util.Enumeration; @@ -28,7 +29,7 @@ */ public class InfantryWeaponMounted extends Mounted { - transient private EquipmentType otherWeapon; + transient private InfantryWeapon otherWeapon; private final String typeName; transient private List modes; @@ -41,16 +42,16 @@ public class InfantryWeaponMounted extends Mounted { * @param rangeWeapon The weapon used to calculate range. * @param otherWeapon The other weapon */ - public InfantryWeaponMounted(Entity entity, EquipmentType rangeWeapon, EquipmentType otherWeapon) { + public InfantryWeaponMounted(Entity entity, EquipmentType rangeWeapon, InfantryWeapon otherWeapon) { super(entity, rangeWeapon); this.typeName = otherWeapon.getInternalName(); this.otherWeapon = otherWeapon; rebuildModeList(); } - public EquipmentType getOtherWeapon() { + public InfantryWeapon getOtherWeapon() { if (otherWeapon == null) { - otherWeapon = EquipmentType.get(typeName); + otherWeapon = (InfantryWeapon) EquipmentType.get(typeName); } return otherWeapon; } diff --git a/megamek/src/megamek/common/loaders/BLKInfantryFile.java b/megamek/src/megamek/common/loaders/BLKInfantryFile.java index 81d96e6e34b..dbedcd20bab 100644 --- a/megamek/src/megamek/common/loaders/BLKInfantryFile.java +++ b/megamek/src/megamek/common/loaders/BLKInfantryFile.java @@ -115,12 +115,16 @@ public Entity getEntity() throws EntityLoadingException { // to the unit // otherwise add the primary weapon Mounted m; - if ((t.getSecondaryWeaponsPerSquad() > 1)) { - m = new InfantryWeaponMounted(t, stype, ptype); - } else if (t.getSecondaryWeaponsPerSquad() == 1) { - m = new InfantryWeaponMounted(t, ptype, stype); - } else { - m = new Mounted(t, ptype); + try { + if ((t.getSecondaryWeaponsPerSquad() > 1)) { + m = new InfantryWeaponMounted(t, stype, (InfantryWeapon) ptype); + } else if (stype != null) { + m = new InfantryWeaponMounted(t, ptype, (InfantryWeapon) stype); + } else { + m = new Mounted(t, ptype); + } + } catch (ClassCastException ex) { + throw new EntityLoadingException(ex.getMessage()); } try { t.addEquipment(m, Infantry.LOC_INFANTRY, false); diff --git a/megamek/src/megamek/common/weapons/WeaponHandler.java b/megamek/src/megamek/common/weapons/WeaponHandler.java index 75ec984d0c3..f1bdcac6766 100644 --- a/megamek/src/megamek/common/weapons/WeaponHandler.java +++ b/megamek/src/megamek/common/weapons/WeaponHandler.java @@ -1468,7 +1468,7 @@ protected void handleEntityDamage(Entity entityTarget, } if (!bSalvo) { - // Each hit in the salvo get's its own hit location. + // Each hit in the salvo gets its own hit location. Report r = new Report(3405); r.subject = subjectId; r.add(toHit.getTableDesc()); diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java b/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java index 3868bbabdfc..1012dae5b40 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java @@ -19,6 +19,8 @@ import megamek.common.*; import megamek.common.actions.WeaponAttackAction; import megamek.common.options.OptionsConstants; +import megamek.common.weapons.DamageType; +import megamek.common.weapons.Weapon; import megamek.server.GameManager; import megamek.server.Server; @@ -49,24 +51,49 @@ protected void handleEntityDamage(Entity entityTarget, Vector vPhaseReport, Building bldg, int hits, int nCluster, int bldgAbsorbs) { if (entityTarget.tracksHeat()) { + Report.addNewline(vPhaseReport); // heat hit = entityTarget.rollHitLocation(toHit.getHitTable(), toHit.getSideTable(), waa.getAimedLocation(), waa .getAimingMode(), toHit.getCover()); hit.setAttackerId(getAttackerId()); - if (entityTarget.removePartialCoverHits(hit.getLocation(), toHit + Hex targetHex = game.getBoard().getHex(target.getPosition()); + boolean indirect = weapon.hasModes() && weapon.curMode().getName().equals(Weapon.MODE_INDIRECT_HEAT); + boolean partialCoverForIndirectFire = indirect && + (unitGainsPartialCoverFromWater(targetHex, entityTarget) + || (WeaponAttackAction.targetInShortCoverBuilding(target) && entityTarget.locationIsLeg(hit.getLocation()))); + + if ((!indirect || partialCoverForIndirectFire) + && entityTarget.removePartialCoverHits(hit.getLocation(), toHit .getCover(), Compute.targetSideTable(ae, entityTarget, weapon.getCalledShot().getCall()))) { // Weapon strikes Partial Cover. handlePartialCoverHit(entityTarget, vPhaseReport, hit, bldg, hits, nCluster, bldgAbsorbs); return; } + Report r = new Report(3400); r.subject = subjectId; r.indent(2); int nDamage = nDamPerHit * Math.min(nCluster, hits); - if (entityTarget.getArmor(hit) > 0 && + // Building may absorb some damage. + boolean targetStickingOutOfBuilding = unitStickingOutOfBuilding(targetHex, entityTarget); + nDamage = absorbBuildingDamage(nDamage, entityTarget, bldgAbsorbs, + vPhaseReport, bldg, targetStickingOutOfBuilding); + nDamage = checkTerrain(nDamage, entityTarget, vPhaseReport); + nDamage = checkLI(nDamage, entityTarget, vPhaseReport); + if ((bldg != null) && !targetStickingOutOfBuilding) { + nDamage = (int) Math.floor(bldg.getDamageToScale() * nDamage); + } + + // If using BMM heat option, do damage as well as heat + if (game.getOptions().booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + vPhaseReport.addAll(gameManager.damageEntity(entityTarget, hit, nDamage, false, + ae.getSwarmTargetId() == entityTarget.getId() ? DamageType.IGNORE_PASSENGER : damageType, + false, false, throughFront, underWater, nukeS2S)); + } + if (entityTarget.getArmor(hit) > 0 && (entityTarget.getArmorType(hit.getLocation()) == EquipmentType.T_ARMOR_HEAT_DISSIPATING)) { entityTarget.heatFromExternal += nDamage / 2; @@ -81,9 +108,7 @@ protected void handleEntityDamage(Entity entityTarget, r.choose(true); } vPhaseReport.addElement(r); - } - // Do damage to non-heat-tracking unit or if using the BMM heat option - if (!entityTarget.tracksHeat() || game.getOptions().booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + } else { super.handleEntityDamage(entityTarget, vPhaseReport, bldg, hits, nCluster, bldgAbsorbs); } diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index 39f979c8d1c..b4223987182 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -253,14 +253,16 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa && m.getLinked().getType() != null && (((AmmoType) m.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)))))) { return new InfantryHeatWeaponHandler(toHit, waa, game, manager); + } else if (game.getOptions().booleanOption(OptionsConstants.BASE_FLAMER_HEAT) + && (isFlameBased() || (m instanceof InfantryWeaponMounted) + && ((InfantryWeaponMounted) m).getOtherWeapon().isFlameBased())) { + return new InfantryHeatWeaponHandler(toHit, waa, game, manager); } return new InfantryWeaponHandler(toHit, waa, game, manager); } public void adaptToGameOptions(GameOptions gOp) { - super.adaptToGameOptions(gOp); - // Additional flags that are treated like flamers for infantry weapons - if (hasFlag(WeaponType.F_INFERNO) || hasFlag(WeaponType.F_PLASMA) || hasFlag(F_INCENDIARY_NEEDLES)) { + if (isFlameBased()) { if (!gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { addMode(MODE_FLAMER_DAMAGE); addMode(MODE_FLAMER_HEAT); @@ -270,4 +272,11 @@ public void adaptToGameOptions(GameOptions gOp) { } } } + + public boolean isFlameBased() { + return hasFlag(WeaponType.F_FLAMER) + || hasFlag(WeaponType.F_INFERNO) + || hasFlag(WeaponType.F_INCENDIARY_NEEDLES) + || hasFlag(WeaponType.F_PLASMA); + } } From dbb5fca27ed56a56fa535a010d5cff72031e5772 Mon Sep 17 00:00:00 2001 From: cwspain Date: Thu, 2 Nov 2023 11:01:40 -0500 Subject: [PATCH 08/12] Fix interaction between game options and indirect heat modes. --- .../InfantrySupportLRMInfernoWeapon.java | 16 +++++++++++----- .../InfantrySupportMortarHeavyInfernoWeapon.java | 16 +++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java index aee42adb3bc..a6dec97b0c5 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java @@ -61,15 +61,21 @@ public InfantrySupportLRMInfernoWeapon() { @Override public void adaptToGameOptions(GameOptions gOp) { + removeMode(""); + removeMode(MODE_MISSILE_INDIRECT); + removeMode(MODE_INDIRECT_HEAT); + // add heat options super.adaptToGameOptions(gOp); // Indirect Fire if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { - addMode(MODE_MISSILE_INDIRECT); - addMode(MODE_INDIRECT_HEAT); - } else { - removeMode(MODE_MISSILE_INDIRECT); - removeMode(MODE_INDIRECT_HEAT); + if (gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + addMode(""); + addMode(MODE_MISSILE_INDIRECT); + } else { + addMode(MODE_MISSILE_INDIRECT); + addMode(MODE_INDIRECT_HEAT); + } } } } diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java index 8fbf8d3538c..d2a5effd88b 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java @@ -62,15 +62,21 @@ public InfantrySupportMortarHeavyInfernoWeapon() { @Override public void adaptToGameOptions(GameOptions gOp) { + removeMode(""); + removeMode(MODE_MISSILE_INDIRECT); + removeMode(MODE_INDIRECT_HEAT); + // add heat options super.adaptToGameOptions(gOp); // Indirect Fire if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { - addMode(MODE_MISSILE_INDIRECT); - addMode(MODE_INDIRECT_HEAT); - } else { - removeMode(MODE_MISSILE_INDIRECT); - removeMode(MODE_INDIRECT_HEAT); + if (gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + addMode(""); + addMode(MODE_MISSILE_INDIRECT); + } else { + addMode(MODE_MISSILE_INDIRECT); + addMode(MODE_INDIRECT_HEAT); + } } } } From dfe12ea26f168d25f102de9a3879149c72eba7e7 Mon Sep 17 00:00:00 2001 From: cwspain Date: Sat, 4 Nov 2023 17:47:46 -0500 Subject: [PATCH 09/12] Added missing overrides and fixed non-short-circuit operator. --- megamek/src/megamek/client/ui/swing/FiringDisplay.java | 2 +- megamek/src/megamek/common/InfantryWeaponMounted.java | 1 + megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/megamek/src/megamek/client/ui/swing/FiringDisplay.java b/megamek/src/megamek/client/ui/swing/FiringDisplay.java index a29b2b26c76..5e9e943fd3e 100644 --- a/megamek/src/megamek/client/ui/swing/FiringDisplay.java +++ b/megamek/src/megamek/client/ui/swing/FiringDisplay.java @@ -2395,7 +2395,7 @@ protected void setFireModeEnabled(boolean enabled) { * @param m The active weapon */ protected void adaptFireModeEnabled(Mounted m) { - setFireModeEnabled(m.isModeSwitchable() & m.hasModes()); + setFireModeEnabled(m.isModeSwitchable() && m.hasModes()); } protected void setFireCalledEnabled(boolean enabled) { diff --git a/megamek/src/megamek/common/InfantryWeaponMounted.java b/megamek/src/megamek/common/InfantryWeaponMounted.java index 3be332610b8..263c9f05941 100644 --- a/megamek/src/megamek/common/InfantryWeaponMounted.java +++ b/megamek/src/megamek/common/InfantryWeaponMounted.java @@ -96,6 +96,7 @@ public boolean hasModeType(String mode) { return modes.contains(EquipmentMode.getMode(mode)); } + @Override public boolean canInstantSwitch(int newMode) { if (getType().hasModes() && (getType().getMode(newMode) != null)) { return super.canInstantSwitch(newMode); diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index b4223987182..d620d493dd0 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -261,6 +261,7 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa return new InfantryWeaponHandler(toHit, waa, game, manager); } + @Override public void adaptToGameOptions(GameOptions gOp) { if (isFlameBased()) { if (!gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { From 4ee330546aff639810ad081f95db93ee98ff91db Mon Sep 17 00:00:00 2001 From: cwspain Date: Sat, 4 Nov 2023 17:59:32 -0500 Subject: [PATCH 10/12] Use safe access to Mounted::type --- megamek/src/megamek/common/Mounted.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/megamek/src/megamek/common/Mounted.java b/megamek/src/megamek/common/Mounted.java index cf33cefc28d..57a8271eda1 100644 --- a/megamek/src/megamek/common/Mounted.java +++ b/megamek/src/megamek/common/Mounted.java @@ -256,15 +256,15 @@ public EquipmentType getType() { } public int getModesCount() { - return type.getModesCount(); + return getType().getModesCount(); } protected EquipmentMode getMode(int mode) { - return type.getMode(mode); + return getType().getMode(mode); } public boolean hasModes() { - return type.hasModes(); + return getType().hasModes(); } public boolean hasModeType(String mode) { From f261dce4ab0eec20ecbc6aa761c47edbd8382dd8 Mon Sep 17 00:00:00 2001 From: cwspain Date: Sat, 4 Nov 2023 17:59:53 -0500 Subject: [PATCH 11/12] Consolidated indirect mode code. --- megamek/src/megamek/common/EquipmentMode.java | 6 ++++++ megamek/src/megamek/common/actions/WeaponAttackAction.java | 3 +-- .../src/megamek/common/weapons/infantry/InfantryWeapon.java | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/megamek/src/megamek/common/EquipmentMode.java b/megamek/src/megamek/common/EquipmentMode.java index 156a8bb45f4..9bec2924012 100644 --- a/megamek/src/megamek/common/EquipmentMode.java +++ b/megamek/src/megamek/common/EquipmentMode.java @@ -14,6 +14,8 @@ package megamek.common; +import megamek.common.weapons.Weapon; + import java.util.Hashtable; import java.util.Objects; @@ -115,4 +117,8 @@ public boolean equals(String modeName) { public String toString() { return getName(); } + + public boolean isIndirect() { + return name.equals(Weapon.MODE_MISSILE_INDIRECT) || name.equals(Weapon.MODE_INDIRECT_HEAT); + } } diff --git a/megamek/src/megamek/common/actions/WeaponAttackAction.java b/megamek/src/megamek/common/actions/WeaponAttackAction.java index 0b316923a62..3df46383cea 100644 --- a/megamek/src/megamek/common/actions/WeaponAttackAction.java +++ b/megamek/src/megamek/common/actions/WeaponAttackAction.java @@ -366,8 +366,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, || atype.countsAsFlak() ); - boolean isIndirect = (weapon.hasModes() && (weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT) - ||weapon.curMode().equals(Weapon.MODE_INDIRECT_HEAT))); + boolean isIndirect = weapon.hasModes() && (weapon.curMode().isIndirect()); // BMM p. 31, semi-guided indirect missile attacks vs tagged targets ignore terrain modifiers boolean semiGuidedIndirectVsTaggedTarget = isIndirect && diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index d620d493dd0..2a7cd50e067 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -247,7 +247,7 @@ public int getSupportVeeSlots(Entity entity) { @Override protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { Mounted m = game.getEntity(waa.getEntityId()).getEquipment(waa.getWeaponId()); - if (((null != m) && (m.curMode().equals(Weapon.MODE_FLAMER_HEAT) || m.curMode().equals(Weapon.MODE_INDIRECT_HEAT) + if (((null != m) && ((m.hasModes() && m.curMode().isIndirect()) || (waa.getEntity(game).isSupportVehicle() && m.getLinked() != null && m.getLinked().getType() != null From ca22a279b7fd3200c70be54d1be0f1a2267e6834 Mon Sep 17 00:00:00 2001 From: cwspain Date: Sat, 4 Nov 2023 21:49:50 -0500 Subject: [PATCH 12/12] Moved infantry heat+damage to unofficial option. --- megamek/i18n/megamek/common/options/messages.properties | 2 ++ megamek/src/megamek/common/EquipmentMode.java | 4 ++++ megamek/src/megamek/common/options/GameOptions.java | 3 ++- megamek/src/megamek/common/options/OptionsConstants.java | 1 + .../common/weapons/infantry/InfantryHeatWeaponHandler.java | 2 +- .../weapons/infantry/InfantrySupportLRMInfernoWeapon.java | 2 +- .../infantry/InfantrySupportMortarHeavyInfernoWeapon.java | 2 +- .../src/megamek/common/weapons/infantry/InfantryWeapon.java | 6 +++--- 8 files changed, 15 insertions(+), 7 deletions(-) diff --git a/megamek/i18n/megamek/common/options/messages.properties b/megamek/i18n/megamek/common/options/messages.properties index ced77889abd..03bc0c34138 100644 --- a/megamek/i18n/megamek/common/options/messages.properties +++ b/megamek/i18n/megamek/common/options/messages.properties @@ -47,6 +47,8 @@ GameOptionsInfo.option.rng_log.displayableName=RNG Log GameOptionsInfo.option.rng_log.description=Whether or not to log the Random Number Generator. GameOptionsInfo.option.flamer_heat.displayableName=Flamers per Battlemech Manual GameOptionsInfo.option.flamer_heat.description=If checked, flamers deal both heat and damage. (BMM pg. 99) Otherwise, you have the option to choose heat or damage. +GameOptionsInfo.option.infantry_damage_heat.displayableName=(Unofficial) Infantry weapons like BMM flamers +GameOptionsInfo.option.infantry_damage_heat.description=If checked, flame-based infantry weapons will deal damage and heat like flamers. GameOptionsInfo.option.indirect_fire.displayableName=Indirect fire GameOptionsInfo.option.indirect_fire.description=If checked, LRMs may be fire indirectly, and players may choose to spot for indirect fire instead of attacking.\nChecked by default. GameOptionsInfo.option.breeze.displayableName=Smoke Drift diff --git a/megamek/src/megamek/common/EquipmentMode.java b/megamek/src/megamek/common/EquipmentMode.java index 9bec2924012..94d9c1ad5be 100644 --- a/megamek/src/megamek/common/EquipmentMode.java +++ b/megamek/src/megamek/common/EquipmentMode.java @@ -118,6 +118,10 @@ public String toString() { return getName(); } + public boolean isHeat() { + return name.equals(Weapon.MODE_FLAMER_HEAT) || name.equals(Weapon.MODE_INDIRECT_HEAT); + } + public boolean isIndirect() { return name.equals(Weapon.MODE_MISSILE_INDIRECT) || name.equals(Weapon.MODE_INDIRECT_HEAT); } diff --git a/megamek/src/megamek/common/options/GameOptions.java b/megamek/src/megamek/common/options/GameOptions.java index de4a71012fb..7c9d5e9d97b 100755 --- a/megamek/src/megamek/common/options/GameOptions.java +++ b/megamek/src/megamek/common/options/GameOptions.java @@ -68,7 +68,8 @@ public synchronized void initialize() { addOption(base, OptionsConstants.BASE_SHOW_BAY_DETAIL, false); addOption(base, OptionsConstants.BASE_RNG_TYPE, 1); addOption(base, OptionsConstants.BASE_RNG_LOG, false); - addOption(base, OptionsConstants.BASE_FLAMER_HEAT, false); + addOption(base, OptionsConstants.BASE_FLAMER_HEAT, false); + addOption(base, OptionsConstants.BASE_INFANTRY_DAMAGE_HEAT, false); addOption(base, OptionsConstants.BASE_INDIRECT_FIRE, true); addOption(base, OptionsConstants.BASE_BREEZE, false); addOption(base, OptionsConstants.BASE_RANDOM_BASEMENTS, true); diff --git a/megamek/src/megamek/common/options/OptionsConstants.java b/megamek/src/megamek/common/options/OptionsConstants.java index d5dbeea8f63..02d11bd3fce 100644 --- a/megamek/src/megamek/common/options/OptionsConstants.java +++ b/megamek/src/megamek/common/options/OptionsConstants.java @@ -288,6 +288,7 @@ public class OptionsConstants { public static final String BASE_RNG_TYPE = "rng_type"; public static final String BASE_RNG_LOG = "rng_log"; public static final String BASE_FLAMER_HEAT = "flamer_heat"; + public static final String BASE_INFANTRY_DAMAGE_HEAT = "infantry_damage_heat"; public static final String BASE_INDIRECT_FIRE = "indirect_fire"; public static final String BASE_BREEZE = "breeze"; public static final String BASE_RANDOM_BASEMENTS = "random_basements"; diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java b/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java index 1012dae5b40..fa7f5b28886 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryHeatWeaponHandler.java @@ -88,7 +88,7 @@ protected void handleEntityDamage(Entity entityTarget, } // If using BMM heat option, do damage as well as heat - if (game.getOptions().booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + if (game.getOptions().booleanOption(OptionsConstants.BASE_INFANTRY_DAMAGE_HEAT)) { vPhaseReport.addAll(gameManager.damageEntity(entityTarget, hit, nDamage, false, ae.getSwarmTargetId() == entityTarget.getId() ? DamageType.IGNORE_PASSENGER : damageType, false, false, throughFront, underWater, nukeS2S)); diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java index a6dec97b0c5..288a39c1ad5 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportLRMInfernoWeapon.java @@ -69,7 +69,7 @@ public void adaptToGameOptions(GameOptions gOp) { // Indirect Fire if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { - if (gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + if (gOp.booleanOption(OptionsConstants.BASE_INFANTRY_DAMAGE_HEAT)) { addMode(""); addMode(MODE_MISSILE_INDIRECT); } else { diff --git a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java index d2a5effd88b..b3c1bd72ec2 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantrySupportMortarHeavyInfernoWeapon.java @@ -70,7 +70,7 @@ public void adaptToGameOptions(GameOptions gOp) { // Indirect Fire if (gOp.booleanOption(OptionsConstants.BASE_INDIRECT_FIRE)) { - if (gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + if (gOp.booleanOption(OptionsConstants.BASE_INFANTRY_DAMAGE_HEAT)) { addMode(""); addMode(MODE_MISSILE_INDIRECT); } else { diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index 2a7cd50e067..0fa6fa76826 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -247,13 +247,13 @@ public int getSupportVeeSlots(Entity entity) { @Override protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { Mounted m = game.getEntity(waa.getEntityId()).getEquipment(waa.getWeaponId()); - if (((null != m) && ((m.hasModes() && m.curMode().isIndirect()) + if (((null != m) && ((m.hasModes() && m.curMode().isHeat()) || (waa.getEntity(game).isSupportVehicle() && m.getLinked() != null && m.getLinked().getType() != null && (((AmmoType) m.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)))))) { return new InfantryHeatWeaponHandler(toHit, waa, game, manager); - } else if (game.getOptions().booleanOption(OptionsConstants.BASE_FLAMER_HEAT) + } else if (game.getOptions().booleanOption(OptionsConstants.BASE_INFANTRY_DAMAGE_HEAT) && (isFlameBased() || (m instanceof InfantryWeaponMounted) && ((InfantryWeaponMounted) m).getOtherWeapon().isFlameBased())) { return new InfantryHeatWeaponHandler(toHit, waa, game, manager); @@ -264,7 +264,7 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa @Override public void adaptToGameOptions(GameOptions gOp) { if (isFlameBased()) { - if (!gOp.booleanOption(OptionsConstants.BASE_FLAMER_HEAT)) { + if (!gOp.booleanOption(OptionsConstants.BASE_INFANTRY_DAMAGE_HEAT)) { addMode(MODE_FLAMER_DAMAGE); addMode(MODE_FLAMER_HEAT); } else {