diff --git a/megamek/src/megamek/client/bot/BotClient.java b/megamek/src/megamek/client/bot/BotClient.java index ae50574b39e..08588490d4b 100644 --- a/megamek/src/megamek/client/bot/BotClient.java +++ b/megamek/src/megamek/client/bot/BotClient.java @@ -22,6 +22,7 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.annotations.Nullable; import megamek.common.enums.GamePhase; +import megamek.common.equipment.WeaponMounted; import megamek.common.event.*; import megamek.common.net.packets.Packet; import megamek.common.options.OptionsConstants; @@ -1006,13 +1007,12 @@ private static float getDeployDamage(Game g, WeaponAttackAction waa, List vCounters = waa.getCounterEquipment(); + List vCounters = waa.getCounterEquipment(); if (wt.hasFlag(WeaponType.F_MISSILE) && vCounters != null) { - for (Mounted vCounter : vCounters) { - EquipmentType type = vCounter.getType(); - if ((type instanceof WeaponType) - && type.hasFlag(WeaponType.F_AMS)) { - float fAMS = 3.5f * ((WeaponType) type).getDamage(); + for (WeaponMounted vCounter : vCounters) { + WeaponType type = vCounter.getType(); + if (type.hasFlag(WeaponType.F_AMS)) { + float fAMS = 3.5f * type.getDamage(); fHits = Math.max(0.0f, fHits - fAMS); } } diff --git a/megamek/src/megamek/client/bot/princess/FireControl.java b/megamek/src/megamek/client/bot/princess/FireControl.java index 89f1647f9c1..e27cc3d7074 100644 --- a/megamek/src/megamek/client/bot/princess/FireControl.java +++ b/megamek/src/megamek/client/bot/princess/FireControl.java @@ -666,7 +666,7 @@ ToHitData guessToHitModifierForWeapon(final Entity shooter, // Make sure we have ammo. final WeaponType weaponType = (WeaponType) weapon.getType(); - final AmmoMounted firingAmmo; + final Mounted firingAmmo; if (AmmoType.T_NA != weaponType.getAmmoType()) { // Use ammo arg if provided, else use linked ammo. firingAmmo = (ammo == null) ? weapon.getLinkedAmmo() : ammo; @@ -704,7 +704,7 @@ ToHitData guessToHitModifierForWeapon(final Entity shooter, } // Bays compute arc differently final boolean inArc = (bayWeapon) - ? Compute.isInArc(game, shooter.getId(), (int) weapon.getBayWeapons().get(0), target) + ? Compute.isInArc(game, shooter.getId(), weapon.getBayWeapons().get(0).getEquipmentNum(), target) : isInArc(shooterState.getPosition(), shooterFacing, targetState.getPosition(), shooter.getWeaponArc(shooter.getEquipmentNum(weapon))); if (!inArc) { diff --git a/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java b/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java index 379b15aba5f..592031861d7 100644 --- a/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java +++ b/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java @@ -380,11 +380,10 @@ private WeaponAttackAction buildBombAttackAction(final HashMap bo // bay weapons require special consideration, by looping through all weapons and adding up the damage // A bay's weapons may have different ranges, most noticeable in laser bays, where the damage potential // varies with distance to target. - if ((null != weapon.getBayWeapons()) && !weapon.getBayWeapons().isEmpty()) { + if (!weapon.getBayWeapons().isEmpty()) { int bayDamage = 0; - for (int weaponID : weapon.getBayWeapons()) { - Mounted bayWeapon = weapon.getEntity().getEquipment(weaponID); - WeaponType weaponType = (WeaponType) bayWeapon.getType(); + for (WeaponMounted bayWeapon: weapon.getBayWeapons()) { + WeaponType weaponType = bayWeapon.getType(); int maxRange = game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_RANGE) ? weaponType.getExtremeRange() : weaponType.getLongRange(); int targetDistance = getShooter().getPosition().distance(getTarget().getPosition()); @@ -521,16 +520,14 @@ private WeaponAttackAction buildBombAttackAction(final HashMap bo * @param weapon The weapon to check. * @return Generated heat. */ - int computeHeat(Mounted weapon) { + int computeHeat(WeaponMounted weapon) { // bay weapons require special consideration, by looping through all weapons and adding up the damage // A bay's weapons may have different ranges, most noticeable in laser bays, where the damage potential // varies with distance to target. - if ((null != weapon.getBayWeapons()) && !weapon.getBayWeapons().isEmpty()) { + if (!weapon.getBayWeapons().isEmpty()) { int bayHeat = 0; - for (int weaponID : weapon.getBayWeapons()) { - Mounted bayWeapon = weapon.getEntity().getEquipment(weaponID); - WeaponType weaponType = (WeaponType) bayWeapon.getType(); - bayHeat += weaponType.getHeat(); + for (WeaponMounted bayWeapon : weapon.getBayWeapons()) { + bayHeat += bayWeapon.getType().getHeat(); } return bayHeat; diff --git a/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java b/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java index aba18054dfc..5e799678361 100644 --- a/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java +++ b/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java @@ -49,15 +49,12 @@ public BayMunitionsChoicePanel(Entity entity, Game game) { for (WeaponMounted bay : entity.getWeaponBayList()) { Map,List> ammoByType = new HashMap<>(); - for (Integer aNum : bay.getBayAmmo()) { - final AmmoMounted ammo = (AmmoMounted) entity.getEquipment(aNum); - if (null != ammo) { - List key = new ArrayList<>(2); - key.add(ammo.getType().getAmmoType()); - key.add(ammo.getType().getRackSize()); - ammoByType.putIfAbsent(key, new ArrayList<>()); - ammoByType.get(key).add(ammo); - } + for (AmmoMounted ammo : bay.getBayAmmo()) { + List key = new ArrayList<>(2); + key.add(ammo.getType().getAmmoType()); + key.add(ammo.getType().getRackSize()); + ammoByType.putIfAbsent(key, new ArrayList<>()); + ammoByType.get(key).add(ammo); } for (List key : ammoByType.keySet()) { AmmoRowPanel row = new AmmoRowPanel(bay, key.get(0), key.get(1), ammoByType.get(key)); @@ -148,8 +145,7 @@ class AmmoRowPanel extends JPanel implements ChangeListener { Dimension spinnerSize =new Dimension(55, 25); final Optional wtype = bay.getBayWeapons().stream() - .map(entity::getEquipment) - .map(m -> (WeaponType) m.getType()).findAny(); + .map(Mounted::getType).findAny(); // set the bay's tech base to that of any weapon in the bay // an assumption is made here that bays don't mix clan-only and IS-only tech base diff --git a/megamek/src/megamek/client/ui/swing/CustomMechDialog.java b/megamek/src/megamek/client/ui/swing/CustomMechDialog.java index 059e75d908c..d35d8b4415b 100644 --- a/megamek/src/megamek/client/ui/swing/CustomMechDialog.java +++ b/megamek/src/megamek/client/ui/swing/CustomMechDialog.java @@ -530,11 +530,9 @@ public void actionPerformed(ActionEvent actionEvent) { // Artillery bays can mix and match, so limit the bay // to the shortest range of the weapons in it int bayShortestRange = 150; // Cruise missile/120 - for (int wId : wep.getBayWeapons()) { - WeaponMounted bweap = (WeaponMounted) entity.getEquipment(wId); - WeaponType bwtype = bweap.getType(); + for (WeaponMounted bweap : wep.getBayWeapons()) { // Max TO range in mapsheets - 1 for the actual play area - int currentDistance = (bwtype.getLongRange() - 1); + int currentDistance = (bweap.getType().getLongRange() - 1); if (currentDistance < bayShortestRange) { bayShortestRange = currentDistance; } diff --git a/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java b/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java index 761009c6b1c..91ba050dddb 100644 --- a/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java +++ b/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java @@ -1151,8 +1151,8 @@ public void displayMech(Entity en) { if (entity.usesWeaponBays()) { // if using bay heat option then don't add total arc if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) { - for (int wId : mounted.getBayWeapons()) { - currentHeatBuildup += entity.getEquipment(wId).getCurrentHeat(); + for (WeaponMounted weapon : mounted.getBayWeapons()) { + currentHeatBuildup += weapon.getCurrentHeat(); } } else { // check whether arc has fired @@ -1909,12 +1909,7 @@ private void displaySelected() { m_chBayWeapon.setEnabled(false); } else { m_chBayWeapon.setEnabled(true); - for (int wId : mounted.getBayWeapons()) { - WeaponMounted curWeapon = (WeaponMounted) entity.getEquipment(wId); - if (null == curWeapon) { - continue; - } - + for (WeaponMounted curWeapon : mounted.getBayWeapons()) { m_chBayWeapon.addItem(formatBayWeapon(curWeapon)); } @@ -1933,7 +1928,7 @@ private void displaySelected() { if (n == -1) { n = 0; } - mounted = (WeaponMounted) entity.getEquipment(mounted.getBayWeapons().get(n)); + mounted = mounted.getBayWeapon(n); wtype = mounted.getType(); } @@ -2579,7 +2574,7 @@ else if ((atype.getAmmoType() == AmmoType.T_LRM) private void compileWeaponBay(WeaponMounted weapon, boolean isCapital) { - List bayWeapons = weapon.getBayWeapons(); + List bayWeapons = weapon.getBayWeapons(); WeaponType wtype = weapon.getType(); // set default values in case if statement stops @@ -2599,15 +2594,14 @@ private void compileWeaponBay(WeaponMounted weapon, boolean isCapital) { double avExt = 0; int maxr = WeaponType.RANGE_SHORT; - for (int wId : bayWeapons) { - WeaponMounted m = (WeaponMounted) entity.getEquipment(wId); + for (WeaponMounted m : bayWeapons) { if (!m.isBreached() && !m.isMissing() && !m.isDestroyed() && !m.isJammed() && ((m.getLinked() == null) || (m.getLinked() .getUsableShotsLeft() > 0))) { - WeaponType bayWType = ((WeaponType) m.getType()); + WeaponType bayWType = m.getType(); heat = heat + m.getCurrentHeat(); double mAVShort = bayWType.getShortAV(); double mAVMed = bayWType.getMedAV(); @@ -2617,8 +2611,7 @@ private void compileWeaponBay(WeaponMounted weapon, boolean isCapital) { // deal with any ammo adjustments if (null != m.getLinked()) { - double[] changes = changeAttackValues((AmmoType) m - .getLinked().getType(), mAVShort, mAVMed, + double[] changes = changeAttackValues((AmmoType) m.getLinked().getType(), mAVShort, mAVMed, mAVLong, mAVExt, mMaxR); mAVShort = changes[0]; mAVMed = changes[1]; @@ -2785,20 +2778,21 @@ public void actionPerformed(ActionEvent ev) { return; } // - Mounted sWeap = entity.getEquipment(mWeap.getBayWeapons().get(n)); + WeaponMounted sWeap = mWeap.getBayWeapon(n); // cycle through all weapons of the same type and load with // this ammo - for (int wid : mWeap.getBayWeapons()) { - WeaponMounted bWeap = (WeaponMounted) entity.getEquipment(wid); - // FIXME: Consider new AmmoType::equals / BombType::equals - if (bWeap.getType().equals(sWeap.getType())) { - entity.loadWeapon(bWeap, mAmmo); - // Alert the server of the update. - clientgui.getClient().sendAmmoChange( - entity.getId(), - entity.getEquipmentNum(bWeap), - entity.getEquipmentNum(mAmmo), - 0); + if (sWeap != null) { + for (WeaponMounted bWeap : mWeap.getBayWeapons()) { + // FIXME: Consider new AmmoType::equals / BombType::equals + if (bWeap.getType().equals(sWeap.getType())) { + entity.loadWeapon(bWeap, mAmmo); + // Alert the server of the update. + clientgui.getClient().sendAmmoChange( + entity.getId(), + entity.getEquipmentNum(bWeap), + entity.getEquipmentNum(mAmmo), + 0); + } } } } else { diff --git a/megamek/src/megamek/common/Aero.java b/megamek/src/megamek/common/Aero.java index d5276bd1179..a27d2b4880c 100644 --- a/megamek/src/megamek/common/Aero.java +++ b/megamek/src/megamek/common/Aero.java @@ -16,6 +16,7 @@ import megamek.client.ui.swing.calculationReport.CalculationReport; import megamek.common.cost.AeroCostCalculator; import megamek.common.enums.AimingMode; +import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.WeaponMounted; import megamek.common.options.OptionsConstants; import megamek.common.planetaryconditions.PlanetaryConditions; @@ -3021,14 +3022,13 @@ public List getActiveAMS() { } // Make sure ammo is loaded - for (int wId : weapon.getBayWeapons()) { - Mounted bayW = getEquipment(wId); - Mounted bayWAmmo = bayW.getLinked(); + for (WeaponMounted bayW : weapon.getBayWeapons()) { + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); if (!(weapon.getType().hasFlag(WeaponType.F_ENERGY)) && ((bayWAmmo == null) || (bayWAmmo.getUsableShotsLeft() == 0) || bayWAmmo.isDumping())) { loadWeapon(weapon); - bayWAmmo = weapon.getLinked(); + bayWAmmo = weapon.getLinkedAmmo(); } // try again diff --git a/megamek/src/megamek/common/Compute.java b/megamek/src/megamek/common/Compute.java index 4586e2fe8d8..e122f4d0308 100644 --- a/megamek/src/megamek/common/Compute.java +++ b/megamek/src/megamek/common/Compute.java @@ -254,6 +254,20 @@ public static float randomFloat() { return random.randomFloat(); } + /** + * Selects a random element from a list + * @param list The list of items to select from + * @return An element in the list + * @param The list type + */ + public static T randomListElement(List list) { + if (list.isEmpty()) { + throw new IllegalArgumentException("Tried to select random element from empty list"); + } else { + return list.get(randomInt(list.size())); + } + } + /** * Sets the RNG to the desired type */ @@ -3120,8 +3134,8 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa, int infShootingStrength = 0; double infDamagePerTrooper = 0; - Mounted weapon = attacker.getEquipment(waa.getWeaponId()); - Mounted lnk_guide; + WeaponMounted weapon = (WeaponMounted) attacker.getEquipment(waa.getWeaponId()); + Mounted lnk_guide; ToHitData hitData = waa.toHit(g, allECMInfo); @@ -3329,10 +3343,10 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa, // adjust for previous AMS if ((wt.getDamage() == WeaponType.DAMAGE_BY_CLUSTERTABLE) && wt.hasFlag(WeaponType.F_MISSILE)) { - ArrayList vCounters = waa.getCounterEquipment(); + List vCounters = waa.getCounterEquipment(); if (vCounters != null) { - for (int x = 0; x < vCounters.size(); x++) { - EquipmentType type = vCounters.get(x).getType(); + for (WeaponMounted vCounter : vCounters) { + EquipmentType type = vCounter.getType(); if ((type instanceof WeaponType) && type.hasFlag(WeaponType.F_AMS)) { fHits *= 0.6f; } @@ -3371,9 +3385,8 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa, if (attacker.usesWeaponBays()) { double av = 0; double threat = 1; - for (int wId : weapon.getBayWeapons()) { - Mounted bayW = attacker.getEquipment(wId); - WeaponType bayWType = ((WeaponType) bayW.getType()); + for (WeaponMounted bayW : weapon.getBayWeapons()) { + WeaponType bayWType = bayW.getType(); //Capital weapons have a different range scale if (wt.isCapital()) { // Capital missiles get higher priority than standard missiles: diff --git a/megamek/src/megamek/common/Entity.java b/megamek/src/megamek/common/Entity.java index e44bb4083b6..6817760e25e 100644 --- a/megamek/src/megamek/common/Entity.java +++ b/megamek/src/megamek/common/Entity.java @@ -4032,7 +4032,7 @@ public int getFirstWeapon() { * @return True if valid, else false */ public boolean isWeaponValidForPhase(int weapNum) { - return isWeaponValidForPhase(equipmentList.get(weapNum)); + return isWeaponValidForPhase((WeaponMounted) equipmentList.get(weapNum)); } /** @@ -4042,7 +4042,7 @@ public boolean isWeaponValidForPhase(int weapNum) { * @param mounted * @return True if valid, else false */ - public boolean isWeaponValidForPhase(Mounted mounted) { + public boolean isWeaponValidForPhase(WeaponMounted mounted) { // Start reached, now we can attempt to pick a weapon. if ((mounted != null) && (mounted.isReady()) @@ -11574,12 +11574,12 @@ public boolean isCommander() { return isCommander; } - public boolean hasLinkedMGA(Mounted mounted) { + public boolean hasLinkedMGA(WeaponMounted mounted) { for (WeaponMounted m : getWeaponList()) { if ((m.getLocation() == mounted.getLocation()) && m.getType().hasFlag(WeaponType.F_MGA) && !(m.isDestroyed() || m.isBreached()) - && m.getBayWeapons().contains(getEquipmentNum(mounted)) + && m.getBayWeapons().contains(mounted) && m.hasModes() && m.curMode().equals("Linked")) { return true; } @@ -11631,16 +11631,21 @@ public boolean usesWeaponBays() { } /** - * return the bay of the current weapon + * return the bay of the current weapon or ammo * - * @param bayID - * @return + * @param equipmentId The equipment index + * @return The bay mount, or null if the equipment is not in a bay */ - public WeaponMounted whichBay(int bayID) { + public WeaponMounted whichBay(int equipmentId) { for (WeaponMounted m : getWeaponBayList()) { - for (int wId : m.getBayWeapons()) { + for (WeaponMounted weapon : m.getBayWeapons()) { // find the weapon and determine if it is there - if (wId == bayID) { + if (weapon.getEquipmentNum() == equipmentId) { + return m; + } + } + for (AmmoMounted ammo : m.getBayAmmo()) { + if (ammo.getEquipmentNum() == equipmentId) { return m; } } @@ -12599,11 +12604,10 @@ public int getQuirkIniBonus() { * @param mammo * @return */ - public WeaponMounted getBayByAmmo(Mounted mammo) { + public WeaponMounted getBayByAmmo(AmmoMounted mammo) { for (WeaponMounted m : getWeaponBayList()) { - for (int bayAmmoId : m.getBayAmmo()) { - Mounted bayammo = getEquipment(bayAmmoId); + for (AmmoMounted bayammo : m.getBayAmmo()) { if (bayammo == mammo) { return m; } diff --git a/megamek/src/megamek/common/EntityListFile.java b/megamek/src/megamek/common/EntityListFile.java index 2ffc16efe03..3d6486fc75f 100644 --- a/megamek/src/megamek/common/EntityListFile.java +++ b/megamek/src/megamek/common/EntityListFile.java @@ -292,8 +292,8 @@ public static String getLocString(Entity entity, int indentLvl) { // if the "equipment" is a weapons bay, // then let's make a note of it - if (entity.usesWeaponBays() && (mount != null) - && !mount.getBayAmmo().isEmpty()) { + if (entity.usesWeaponBays() && (mount instanceof WeaponMounted) + && !((WeaponMounted) mount).getBayAmmo().isEmpty()) { baySlotMap.put((WeaponMounted) slot.getMount(), loop + 1); } diff --git a/megamek/src/megamek/common/MechFileParser.java b/megamek/src/megamek/common/MechFileParser.java index cdf159713bc..346c840723f 100644 --- a/megamek/src/megamek/common/MechFileParser.java +++ b/megamek/src/megamek/common/MechFileParser.java @@ -524,14 +524,13 @@ else if (m.getType().hasFlag(MiscType.F_APOLLO)) { && (m.getLinked() == null)) { // link up to a weapon in the same location - for (Mounted mWeapon : ent.getWeaponList()) { - WeaponType wtype = (WeaponType) mWeapon.getType(); + for (WeaponMounted mWeapon : ent.getWeaponList()) { + WeaponType wtype = mWeapon.getType(); //Handle weapon bays if (wtype.getBayType().equals(EquipmentType.get(EquipmentTypeLookup.PPC_BAY))) { - for (int wId : mWeapon.getBayWeapons()) { - Mounted bayMountedWeapon = ent.getEquipment(wId); - WeaponType bayWeapType = (WeaponType) bayMountedWeapon.getType(); + for (WeaponMounted bayMountedWeapon : mWeapon.getBayWeapons()) { + WeaponType bayWeapType = bayMountedWeapon.getType(); // Check for PPC that isn't crosslinked if (!bayWeapType.hasFlag(WeaponType.F_PPC) || @@ -808,7 +807,7 @@ static void linkMGAs(Entity entity) { if (mga.getType().hasFlag(WeaponType.F_MGA)) { // This may be called from MML after changing equipment location, so there // may be old data that needs to be cleared - mga.getBayWeapons().clear(); + mga.clearBayWeapons(); for (int i = 0; i < entity.getNumberOfCriticals(mga.getLocation()); i++) { CriticalSlot slot = entity.getCritical(mga.getLocation(), i); if ((slot != null) && (slot.getType() == CriticalSlot.TYPE_EQUIPMENT) diff --git a/megamek/src/megamek/common/MechView.java b/megamek/src/megamek/common/MechView.java index e473ce72d86..e73239e090f 100644 --- a/megamek/src/megamek/common/MechView.java +++ b/megamek/src/megamek/common/MechView.java @@ -18,7 +18,9 @@ import megamek.client.ui.swing.GUIPreferences; import megamek.client.ui.swing.util.UIUtil; import megamek.common.annotations.Nullable; +import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.ArmorType; +import megamek.common.equipment.WeaponMounted; import megamek.common.eras.Era; import megamek.common.eras.Eras; import megamek.common.options.*; @@ -857,10 +859,10 @@ private List getWeapons(boolean showDetail) { wpnTable.setColNames("Weapons ", " Loc ", " Heat ", entity.isOmni() ? " Omni " : ""); wpnTable.setJustification(TableElement.JUSTIFIED_LEFT, TableElement.JUSTIFIED_CENTER, TableElement.JUSTIFIED_CENTER, TableElement.JUSTIFIED_CENTER); - for (Mounted mounted : entity.getWeaponList()) { + for (WeaponMounted mounted : entity.getWeaponList()) { String[] row = { mounted.getDesc() + quirkMarker(mounted), entity.joinLocationAbbr(mounted.allLocations(), 3), "", "" }; - WeaponType wtype = (WeaponType) mounted.getType(); + WeaponType wtype = mounted.getType(); if (entity.isClan() && (mounted.getType().getTechBase() == ITechnology.TECH_BASE_IS)) { @@ -882,11 +884,7 @@ private List getWeapons(boolean showDetail) { if (wtype instanceof BayWeapon) { // loop through weapons in bay and add up heat heat = 0; - for (int wId : mounted.getBayWeapons()) { - Mounted m = entity.getEquipment(wId); - if (null == m) { - continue; - } + for (WeaponMounted m : mounted.getBayWeapons()) { heat = heat + m.getType().getHeat(); if (m.isDestroyed()) { bWeapDamaged++; @@ -913,12 +911,7 @@ private List getWeapons(boolean showDetail) { // if this is a weapon bay, then cycle through weapons and ammo if ((wtype instanceof BayWeapon) && showDetail) { - for (int wId : mounted.getBayWeapons()) { - Mounted m = entity.getEquipment(wId); - if (null == m) { - continue; - } - + for (WeaponMounted m : mounted.getBayWeapons()) { row = new String[] { m.getDesc(), "", "", "" }; if (entity.isClan() @@ -939,11 +932,7 @@ private List getWeapons(boolean showDetail) { wpnTable.addRow(row); } } - for (int aId : mounted.getBayAmmo()) { - Mounted m = entity.getEquipment(aId); - if (null == m) { - continue; - } + for (AmmoMounted m : mounted.getBayAmmo()) { // Ignore ammo for one-shot launchers if ((m.getLinkedBy() != null) && m.getLinkedBy().isOneShot()) { diff --git a/megamek/src/megamek/common/Mounted.java b/megamek/src/megamek/common/Mounted.java index 56b9262d65a..fc7ce2a9060 100644 --- a/megamek/src/megamek/common/Mounted.java +++ b/megamek/src/megamek/common/Mounted.java @@ -1227,12 +1227,12 @@ public boolean isCrippled() { return false; } - public List getBayWeapons() { - return Collections.emptyList(); - } - - public List getBayAmmo() { - return Collections.emptyList(); + /** + * + * @return The index of this mount in the entity's equipmentlist. + */ + public int getEquipmentNum() { + return getEntity().getEquipmentNum(this); } /** @@ -1629,54 +1629,6 @@ public String getMissingTrooperString() { } return missings.toString(); } - - /** - * Assign APDS systems to the most dangerous incoming missile attacks. This - * should only be called once per turn, or AMS will get extra attacks - */ - public WeaponAttackAction assignAPDS(List vAttacks) { - // Shouldn't have null entity, but if we do... - if (getEntity() == null) { - return null; - } - - // Ensure we only target attacks in our arc & range - List vAttacksInArc = new Vector<>(vAttacks.size()); - for (WeaponHandler wr : vAttacks) { - boolean isInArc = Compute.isInArc(getEntity().getGame(), - getEntity().getId(), getEntity().getEquipmentNum(this), - getEntity().getGame().getEntity(wr.waa.getEntityId())); - boolean isInRange = getEntity().getPosition().distance( - wr.getWaa().getTarget(getEntity().getGame()).getPosition()) <= 3; - if (isInArc && isInRange) { - vAttacksInArc.add(wr.waa); - } - } - // find the most dangerous salvo by expected damage - WeaponAttackAction waa = Compute.getHighestExpectedDamage(getEntity() - .getGame(), vAttacksInArc, true); - if (waa != null) { - waa.addCounterEquipment(this); - return waa; - } - return null; - } - - /** - * Returns true if this Mounted is an APDS. - * @return - */ - public boolean isAPDS() { - if ((getEntity() instanceof BattleArmor) - && getType().getInternalName().equals("ISBAAPDS")) { - return true; - } else if (getType() instanceof WeaponType) { - return ((WeaponType) getType()).getAmmoType() == AmmoType.T_APDS; - } else { - return false; - } - } - /** * Returns true if this Mounted is ammunition in homing mode. */ diff --git a/megamek/src/megamek/common/WeaponType.java b/megamek/src/megamek/common/WeaponType.java index 43a3393d72c..e5ac6b87485 100644 --- a/megamek/src/megamek/common/WeaponType.java +++ b/megamek/src/megamek/common/WeaponType.java @@ -19,14 +19,7 @@ import megamek.common.alphaStrike.AlphaStrikeElement; import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.WeaponMounted; -import megamek.common.weapons.AlamoMissileWeapon; -import megamek.common.weapons.AltitudeBombAttack; -import megamek.common.weapons.DiveBombAttack; -import megamek.common.weapons.LegAttack; -import megamek.common.weapons.SpaceBombAttack; -import megamek.common.weapons.StopSwarmAttack; -import megamek.common.weapons.SwarmAttack; -import megamek.common.weapons.SwarmWeaponAttack; +import megamek.common.weapons.*; import megamek.common.weapons.artillery.*; import megamek.common.weapons.autocannons.*; import megamek.common.weapons.battlearmor.*; @@ -641,7 +634,6 @@ public int getMaxRange(WeaponMounted weapon, AmmoMounted ammo) { } return maxRange; } - public int getInfantryDamageClass() { return infDamageClass; } diff --git a/megamek/src/megamek/common/actions/ArtilleryAttackAction.java b/megamek/src/megamek/common/actions/ArtilleryAttackAction.java index 7ab1633db47..2d31ba8e806 100644 --- a/megamek/src/megamek/common/actions/ArtilleryAttackAction.java +++ b/megamek/src/megamek/common/actions/ArtilleryAttackAction.java @@ -24,6 +24,7 @@ import megamek.common.Mounted; import megamek.common.RangeType; import megamek.common.WeaponType; +import megamek.common.equipment.WeaponMounted; import megamek.common.options.OptionsConstants; import megamek.common.weapons.bayweapons.CapitalMissileBayWeapon; import megamek.common.weapons.capitalweapons.CapitalMissileWeapon; @@ -51,11 +52,10 @@ public ArtilleryAttackAction(int entityId, int targetType, int targetId, distance = (int) Math.floor((double) distance / game.getPlanetaryConditions().getGravity()); EquipmentType eType = getEntity(game).getEquipment(weaponId).getType(); WeaponType wType = (WeaponType) eType; - Mounted mounted = getEntity(game).getEquipment(weaponId); + WeaponMounted mounted = (WeaponMounted) getEntity(game).getEquipment(weaponId); if (getEntity(game).usesWeaponBays() && wType.getAtClass() == WeaponType.CLASS_ARTILLERY) { - for (int wId : game.getEntity(entityId).getEquipment(weaponId).getBayWeapons()) { - Mounted bayW = game.getEntity(entityId).getEquipment(wId); - WeaponType bayWType = ((WeaponType) bayW.getType()); + for (WeaponMounted bayW : mounted.getBayWeapons()) { + WeaponType bayWType = bayW.getType(); if (bayWType.hasFlag(WeaponType.F_CRUISE_MISSILE)) { // See TO p181. Cruise missile flight time is (1 + (Mapsheets / 5, round down) turnsTilHit = 1 + (distance / Board.DEFAULT_BOARD_HEIGHT / 5); diff --git a/megamek/src/megamek/common/actions/TeleMissileAttackAction.java b/megamek/src/megamek/common/actions/TeleMissileAttackAction.java index c5d56872b66..857459571be 100644 --- a/megamek/src/megamek/common/actions/TeleMissileAttackAction.java +++ b/megamek/src/megamek/common/actions/TeleMissileAttackAction.java @@ -20,10 +20,13 @@ package megamek.common.actions; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; +import java.util.List; -import megamek.client.ui.Messages; import megamek.common.*; +import megamek.common.equipment.AmmoMounted; +import megamek.common.equipment.WeaponMounted; import megamek.common.options.OptionsConstants; import megamek.common.weapons.AttackHandler; @@ -35,7 +38,7 @@ public class TeleMissileAttackAction extends AbstractAttackAction { private static final long serialVersionUID = -1054613811287285482L; // only used server-side for manually guided Telemissile attacks - private transient ArrayList vCounterEquipment; + private transient List vCounterEquipment; // Large Craft Point Defense/AMS Bay Stuff public int CounterAVInt = 0; @@ -61,7 +64,10 @@ public boolean getPDOverheated() { * Returns the list of Counter Equipment used against this physical attack * This is for AMS assignment to manual tele-operated missiles */ - public ArrayList getCounterEquipment() { + public List getCounterEquipment() { + if (vCounterEquipment == null) { + vCounterEquipment = new ArrayList<>(); + } return vCounterEquipment; } @@ -69,7 +75,7 @@ public ArrayList getCounterEquipment() { * Adds 'm' to the list of Counter Equipment used against this physical attack * This is for AMS assignment to manual tele-operated missiles */ - public void addCounterEquipment(Mounted m) { + public void addCounterEquipment(WeaponMounted m) { if (vCounterEquipment == null) { vCounterEquipment = new ArrayList<>(); } @@ -106,9 +112,8 @@ protected int getLargeCraftHeat(Entity e) { AttackHandler ah = i.nextElement(); WeaponAttackAction prevAttack = ah.getWaa(); if (prevAttack.getEntityId() == e.getId()) { - Mounted prevWeapon = e.getEquipment(prevAttack.getWeaponId()); - for (int wId : prevWeapon.getBayWeapons()) { - Mounted bayW = e.getEquipment(wId); + WeaponMounted prevWeapon = (WeaponMounted) e.getEquipment(prevAttack.getWeaponId()); + for (WeaponMounted bayW : prevWeapon.getBayWeapons()) { totalheat += bayW.getCurrentHeat(); } } @@ -118,7 +123,7 @@ protected int getLargeCraftHeat(Entity e) { AttackHandler ah = i.nextElement(); WeaponAttackAction prevAttack = ah.getWaa(); if (prevAttack.getEntityId() == e.getId()) { - Mounted prevWeapon = e.getEquipment(prevAttack.getWeaponId()); + Mounted prevWeapon = e.getEquipment(prevAttack.getWeaponId()); totalheat += prevWeapon.getCurrentHeat(); } } @@ -131,7 +136,7 @@ protected int getLargeCraftHeat(Entity e) { * Checks to see if this point defense/AMS bay can engage a capital missile * This should return true. Only when handling capital missile attacks can this be false. */ - protected boolean canEngageCapitalMissile(Mounted counter) { + protected boolean canEngageCapitalMissile(WeaponMounted counter) { return counter.getBayWeapons().size() >= 2; } @@ -148,11 +153,11 @@ public int calcCounterAV(Game game, Targetable target) { double pdAV = 0; Entity entityTarget = (Entity) target; // any AMS bay attacks by the target? - ArrayList lCounters = getCounterEquipment(); + List lCounters = getCounterEquipment(); // We need to know how much heat has been assigned to offensive weapons fire by the defender this round int weaponHeat = getLargeCraftHeat(entityTarget) + entityTarget.heatBuildup; if (null != lCounters) { - for (Mounted counter : lCounters) { + for (WeaponMounted counter : lCounters) { // Point defenses only fire vs attacks against the arc they protect Entity pdEnt = counter.getEntity(); @@ -160,7 +165,7 @@ public int calcCounterAV(Game game, Targetable target) { // Telemissiles are entities. Other craft can just shoot at them. // Point defenses can't fire if they're not ready for any other reason - if (!(counter.getType() instanceof WeaponType) + if (counter.getType() == null || !counter.isReady() || counter.isMissing() // shutdown means no Point defenses || pdEnt.isShutDown()) { @@ -192,9 +197,8 @@ public int calcCounterAV(Game game, Targetable target) { // First, reset the temporary damage counters amsAV = 0; pdAV = 0; - for (int wId : counter.getBayWeapons()) { - Mounted bayW = pdEnt.getEquipment(wId); - Mounted bayWAmmo = bayW.getLinked(); + for (WeaponMounted bayW : counter.getBayWeapons()) { + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); WeaponType bayWType = ((WeaponType) bayW.getType()); // build up some heat diff --git a/megamek/src/megamek/common/actions/WeaponAttackAction.java b/megamek/src/megamek/common/actions/WeaponAttackAction.java index 578db1765f1..88798c4bd3d 100644 --- a/megamek/src/megamek/common/actions/WeaponAttackAction.java +++ b/megamek/src/megamek/common/actions/WeaponAttackAction.java @@ -90,7 +90,7 @@ public class WeaponAttackAction extends AbstractAttackAction implements Serializ // equipment that affects this attack (AMS, ECM?, etc) // only used server-side - private transient ArrayList vCounterEquipment; + private transient List vCounterEquipment; /** * Boolean flag that determines whether or not this attack is part of a @@ -157,7 +157,7 @@ public int getAimedLocation() { return aimedLocation; } - public ArrayList getCounterEquipment() { + public List getCounterEquipment() { return vCounterEquipment; } @@ -193,7 +193,7 @@ public void setAimingMode(AimingMode aimMode) { this.aimMode = aimMode; } - public void addCounterEquipment(Mounted m) { + public void addCounterEquipment(WeaponMounted m) { if (vCounterEquipment == null) { vCounterEquipment = new ArrayList<>(); } @@ -460,8 +460,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, && (munition.contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))); if (ae.usesWeaponBays()) { - for (int wId : weapon.getBayWeapons()) { - Mounted bayW = ae.getEquipment(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { Mounted bayWAmmo = bayW.getLinked(); if (bayWAmmo == null) { @@ -1394,9 +1393,8 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // first check to see if there are any usable weapons boolean usable = false; - for (int wId : weapon.getBayWeapons()) { - Mounted m = ae.getEquipment(wId); - WeaponType bayWType = ((WeaponType) m.getType()); + for (WeaponMounted m : weapon.getBayWeapons()) { + WeaponType bayWType = m.getType(); boolean bayWUsesAmmo = (bayWType.getAmmoType() != AmmoType.T_NA); if (m.canFire()) { if (bayWUsesAmmo) { @@ -1433,13 +1431,13 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta continue; } if ((prevAttack.getEntityId() == attackerId) && (weaponId != prevAttack.getWeaponId())) { - Mounted prevWeapon = ae.getEquipment(prevAttack.getWeaponId()); + WeaponMounted prevWeapon = (WeaponMounted) ae.getEquipment(prevAttack.getWeaponId()); if (prevWeapon != null) { int loc = prevWeapon.getLocation(); boolean rearMount = prevWeapon.isRearMounted(); if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) { - for (int bwId : prevWeapon.getBayWeapons()) { - totalHeat += ae.getEquipment(bwId).getCurrentHeat(); + for (WeaponMounted bWeapon : prevWeapon.getBayWeapons()) { + totalHeat += bWeapon.getCurrentHeat(); } } else { if (!rearMount) { @@ -1464,8 +1462,8 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta int currentHeat = ae.getHeatInArc(loc, rearMount); if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) { currentHeat = 0; - for (int bwId : weapon.getBayWeapons()) { - currentHeat += ae.getEquipment(bwId).getCurrentHeat(); + for (WeaponMounted bWeapon : weapon.getBayWeapons()) { + currentHeat += bWeapon.getCurrentHeat(); } } // check to see if this is currently the only arc being fired @@ -1782,11 +1780,10 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // and finally, can only use Arrow IV artillery if (ae.usesWeaponBays()) { //For Dropships - for (int wId : weapon.getBayWeapons()) { - Mounted bayW = ae.getEquipment(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the loaded ammo for the Arrow IV flag - Mounted bayWAmmo = bayW.getLinked(); - AmmoType bAType = (AmmoType) bayWAmmo.getType(); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); + AmmoType bAType = bayWAmmo.getType(); if (bAType.getAmmoType() != AmmoType.T_ARROW_IV) { return Messages.getString("WeaponAttackAction.OnlyArrowArty"); } @@ -3562,7 +3559,7 @@ private static ToHitData compileAttackerToHitMods(Game game, Entity ae, Targetab private static ToHitData compileAeroAttackerToHitMods(Game game, Entity ae, Targetable target, int ttype, ToHitData toHit, int aimingAt, AimingMode aimingMode, int eistatus, - WeaponType wtype, Mounted weapon, + WeaponType wtype, WeaponMounted weapon, AmmoType atype, EnumSet munition, boolean isArtilleryIndirect, boolean isFlakAttack, @@ -3817,9 +3814,8 @@ private static ToHitData compileAeroAttackerToHitMods(Game game, Entity ae, Targ // any heavy lasers if (wtype.getAtClass() == WeaponType.CLASS_LASER) { - for (int wId : weapon.getBayWeapons()) { - Mounted bweap = ae.getEquipment(wId); - WeaponType bwtype = (WeaponType) bweap.getType(); + for (WeaponMounted bweap : weapon.getBayWeapons()) { + WeaponType bwtype = bweap.getType(); if ((bwtype.getInternalName().contains("Heavy")) && (bwtype.getInternalName().contains("Laser"))) { toHit.addModifier(+1, Messages.getString("WeaponAttackAction.HeavyLaserInBay")); @@ -3830,11 +3826,10 @@ private static ToHitData compileAeroAttackerToHitMods(Game game, Entity ae, Targ // barracuda missiles else if (wtype.getAtClass() == WeaponType.CLASS_CAPITAL_MISSILE) { boolean onlyBarracuda = true; - for (int wId : weapon.getBayWeapons()) { - Mounted bweap = ae.getEquipment(wId); - Mounted bammo = bweap.getLinked(); + for (WeaponMounted bweap : weapon.getBayWeapons()) { + AmmoMounted bammo = bweap.getLinkedAmmo(); if (bammo != null) { - AmmoType batype = (AmmoType) bammo.getType(); + AmmoType batype = bammo.getType(); if (batype.getAmmoType() != AmmoType.T_BARRACUDA) { onlyBarracuda = false; } @@ -3848,11 +3843,10 @@ else if (wtype.getAtClass() == WeaponType.CLASS_CAPITAL_MISSILE) { // barracuda) else if (wtype.getAtClass() == WeaponType.CLASS_AR10) { boolean onlyBarracuda = true; - for (int wId : weapon.getBayWeapons()) { - Mounted bweap = ae.getEquipment(wId); - Mounted bammo = bweap.getLinked(); + for (WeaponMounted bweap : weapon.getBayWeapons()) { + AmmoMounted bammo = bweap.getLinkedAmmo(); if (bammo != null) { - AmmoType batype = (AmmoType) bammo.getType(); + AmmoType batype = bammo.getType(); if (!batype.hasFlag(AmmoType.F_AR10_BARRACUDA)) { onlyBarracuda = false; } @@ -3865,11 +3859,10 @@ else if (wtype.getAtClass() == WeaponType.CLASS_AR10) { // LBX cluster else if (wtype.getAtClass() == WeaponType.CLASS_LBX_AC) { boolean onlyCluster = true; - for (int wId : weapon.getBayWeapons()) { - Mounted bweap = ae.getEquipment(wId); - Mounted bammo = bweap.getLinked(); + for (WeaponMounted bweap : weapon.getBayWeapons()) { + AmmoMounted bammo = bweap.getLinkedAmmo(); if (bammo != null) { - AmmoType batype = (AmmoType) bammo.getType(); + AmmoType batype = bammo.getType(); if (!batype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { onlyCluster = false; break; @@ -5193,7 +5186,7 @@ public static ToHitData processAttackerSPAs(ToHitData toHit, Entity ae, Targetab } } - WeaponType wtype = ((weapon != null) && (weapon.getType() instanceof WeaponType)) ? (WeaponType) weapon.getType() : null; + WeaponType wtype = (weapon != null) ? weapon.getType() : null; if (wtype != null) { // Unofficial weapon class specialist - Does not have an unspecialized penalty @@ -5214,7 +5207,7 @@ public static ToHitData processAttackerSPAs(ToHitData toHit, Entity ae, Targetab // Is the pilot a weapon specialist? if (wtype instanceof BayWeapon - && weapon.getBayWeapons().stream().map(ae::getEquipment) + && weapon.getBayWeapons().stream() .allMatch(w -> ae.hasAbility(OptionsConstants.GUNNERY_WEAPON_SPECIALIST, w.getName()))) { // All weapons in a bay must match the specialization toHit.addModifier(-2, Messages.getString("WeaponAttackAction.WeaponSpec")); diff --git a/megamek/src/megamek/common/alphaStrike/conversion/ASArcedDamageConverter.java b/megamek/src/megamek/common/alphaStrike/conversion/ASArcedDamageConverter.java index 9a7f68892b9..f08bde422bd 100644 --- a/megamek/src/megamek/common/alphaStrike/conversion/ASArcedDamageConverter.java +++ b/megamek/src/megamek/common/alphaStrike/conversion/ASArcedDamageConverter.java @@ -23,6 +23,7 @@ import megamek.common.Mounted; import megamek.common.WeaponType; import megamek.common.alphaStrike.*; +import megamek.common.equipment.WeaponMounted; import megamek.common.weapons.bayweapons.BayWeapon; import java.util.*; @@ -42,10 +43,10 @@ protected ASArcedDamageConverter(Entity entity, AlphaStrikeElement element, Calc locations[index] = new ASArcSummary(); } // Flatten the weaponlist as weapon bays are not relevant for AS conversion - List flattenedWeaponList = new ArrayList<>(); - for (Mounted weapon : entity.getWeaponList()) { + List flattenedWeaponList = new ArrayList<>(); + for (WeaponMounted weapon : entity.getWeaponList()) { if (weapon.getType() instanceof BayWeapon) { - weapon.getBayWeapons().stream().map(entity::getEquipment).forEach(flattenedWeaponList::add); + flattenedWeaponList.addAll(weapon.getBayWeapons()); } else { flattenedWeaponList.add(weapon); } diff --git a/megamek/src/megamek/common/alphaStrike/conversion/ASDamageConverter.java b/megamek/src/megamek/common/alphaStrike/conversion/ASDamageConverter.java index 54bc6372e45..14663266f18 100644 --- a/megamek/src/megamek/common/alphaStrike/conversion/ASDamageConverter.java +++ b/megamek/src/megamek/common/alphaStrike/conversion/ASDamageConverter.java @@ -21,6 +21,7 @@ import megamek.client.ui.swing.calculationReport.CalculationReport; import megamek.common.*; import megamek.common.alphaStrike.*; +import megamek.common.equipment.WeaponMounted; import megamek.common.weapons.missiles.MissileWeapon; import megamek.common.weapons.other.CLFussilade; @@ -56,7 +57,7 @@ public class ASDamageConverter { private final Map ammoModifier = new HashMap<>(); protected final boolean hasTargetingComputer; - protected List weaponsList; + protected List weaponsList; protected double rawSDamage; protected boolean needsHeatAdjustment = false; protected double heatAdjustFactor = 1; diff --git a/megamek/src/megamek/common/alphaStrike/conversion/ASLargeAeroSpecialAbilityConverter.java b/megamek/src/megamek/common/alphaStrike/conversion/ASLargeAeroSpecialAbilityConverter.java index 28b9bb45b6b..8367f8f4d87 100644 --- a/megamek/src/megamek/common/alphaStrike/conversion/ASLargeAeroSpecialAbilityConverter.java +++ b/megamek/src/megamek/common/alphaStrike/conversion/ASLargeAeroSpecialAbilityConverter.java @@ -22,10 +22,12 @@ import megamek.common.*; import megamek.common.alphaStrike.ASArcs; import megamek.common.alphaStrike.AlphaStrikeElement; +import megamek.common.equipment.WeaponMounted; import megamek.common.weapons.bayweapons.BayWeapon; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import static megamek.common.alphaStrike.ASUnitType.*; import static megamek.common.alphaStrike.BattleForceSUA.*; @@ -52,10 +54,9 @@ protected void processENE() { for (Mounted equipment : entity.getEquipment()) { processArcENE(equipment); if (equipment.getType() instanceof BayWeapon) { - var bayEquipmentList = new ArrayList<>(equipment.getBayWeapons()); - bayEquipmentList.addAll(equipment.getBayAmmo()); - for (int index : bayEquipmentList) { - Mounted bayEquipment = entity.getEquipment(index); + List> bayEquipmentList = new ArrayList<>(((WeaponMounted) equipment).getBayWeapons()); + bayEquipmentList.addAll(((WeaponMounted) equipment).getBayAmmo()); + for (Mounted bayEquipment : bayEquipmentList) { processArcENE(bayEquipment); } } diff --git a/megamek/src/megamek/common/battlevalue/BVCalculator.java b/megamek/src/megamek/common/battlevalue/BVCalculator.java index 304c7e06f14..1747d7009c9 100644 --- a/megamek/src/megamek/common/battlevalue/BVCalculator.java +++ b/megamek/src/megamek/common/battlevalue/BVCalculator.java @@ -743,9 +743,8 @@ protected double processWeapon(Mounted weapon, boolean showInReport, // MG Arrays need to sum up their linked MGs if ((weapon.getType() instanceof WeaponType) && weapon.getType().hasFlag(WeaponType.F_MGA)) { double mgBV = 0; - for (int eqNum : ((WeaponMounted) weapon).getBayWeapons()) { - Mounted mg = entity.getEquipment(eqNum); - if ((mg != null) && (!mg.isDestroyed())) { + for (WeaponMounted mg : ((WeaponMounted) weapon).getBayWeapons()) { + if (!mg.isDestroyed()) { mgBV += mg.getType().getBV(entity); } } diff --git a/megamek/src/megamek/common/equipment/WeaponMounted.java b/megamek/src/megamek/common/equipment/WeaponMounted.java index a7afca97ec9..09ccdd0b017 100644 --- a/megamek/src/megamek/common/equipment/WeaponMounted.java +++ b/megamek/src/megamek/common/equipment/WeaponMounted.java @@ -20,11 +20,15 @@ package megamek.common.equipment; import megamek.common.*; +import megamek.common.actions.WeaponAttackAction; import megamek.common.options.OptionsConstants; +import megamek.common.weapons.WeaponHandler; import megamek.common.weapons.gaussrifles.GaussWeapon; import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.Vector; import java.util.stream.Collectors; public class WeaponMounted extends Mounted { @@ -33,8 +37,8 @@ public class WeaponMounted extends Mounted { // this bay (if the mounted is of the BayWeapon type) // I can also use this for weapons of the same type on a capital fighter // and now Machine Gun Arrays too! - private List bayWeapons = new ArrayList<>(); - private List bayAmmo = new ArrayList<>(); + private final List bayWeapons = new ArrayList<>(); + private final List bayAmmo = new ArrayList<>(); public WeaponMounted(Entity entity, WeaponType type) { super(entity, type); @@ -142,16 +146,11 @@ public AmmoMounted getLinkedAmmo() { * Returns how many shots the weapon is using */ public int getCurrentShots() { - WeaponType wtype = (WeaponType) getType(); - int nShots = getNumShots(wtype, curMode(), false); + int nShots = getNumShots(getType(), curMode(), false); // sets number of shots for MG arrays - if (wtype.hasFlag(WeaponType.F_MGA)) { + if (getType().hasFlag(WeaponType.F_MGA)) { nShots = 0; - for (int eqn : getBayWeapons()) { - Mounted m = getEntity().getEquipment(eqn); - if (null == m) { - continue; - } + for (WeaponMounted m : getBayWeapons()) { if ((m.getLocation() == getLocation()) && !m.isDestroyed() && !m.isBreached() @@ -170,22 +169,100 @@ public boolean isOneShot() { return getType().hasFlag(WeaponType.F_ONESHOT); } - public void addWeaponToBay(int w) { - bayWeapons.add(w); + /** + * Adds the weapon with the given equipment number to the bay. + * @param equipmentNum The equipment number of the weapon to add + * @see Entity#getEquipmentNum(Mounted) + */ + public void addWeaponToBay(int equipmentNum) { + bayWeapons.add(equipmentNum); } - @Override - public List getBayWeapons() { - return bayWeapons; + public void addWeaponToBay(WeaponMounted weapon) { + addWeaponToBay(weapon.getEquipmentNum()); } - public void addAmmoToBay(int a) { - bayAmmo.add(a); + /** + * Removes the weapon with the given equipment number from the bay. + * @param equipmentNum The equipment number of the weapon to remove. + * @see Entity#getEquipmentNum(Mounted) + */ + public void removeWeaponFromBay(int equipmentNum) { + bayWeapons.remove(Integer.valueOf(equipmentNum)); } - @Override - public List getBayAmmo() { - return bayAmmo; + /** + * Removes a weapon from the bay. + * @param weapon The weapon to remove. + */ + public void removeWeaponFromBay(WeaponMounted weapon) { + removeWeaponFromBay(weapon.getEquipmentNum()); + } + + /** + * Removes all weapons from the bay. + */ + public void clearBayWeapons() { + bayWeapons.clear(); + } + + /** + * @return All the weapon mounts in the bay. + */ + public List getBayWeapons() { + return bayWeapons.stream() + .map(i -> getEntity().getWeapon(i)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + /** + * Fetches the bay weapon at a given index in the bay weapons list. + * @param index The index + * @return The weapon mount at that + */ + public WeaponMounted getBayWeapon(int index) { + if ((index >= 0) && (index < bayWeapons.size())) { + return getEntity().getWeapon(index); + } else { + return null; + } + } + + /** + * Adds the ammo with the given equipment number to the bay. + * @param equipmentNum The equipment number of the ammo + * @see Entity#getEquipmentNum(Mounted) + */ + public void addAmmoToBay(int equipmentNum) { + bayAmmo.add(equipmentNum); + } + + public void addAmmoToBay(AmmoMounted ammo) { + bayAmmo.add(ammo.getEquipmentNum()); + } + + /** + * Removes the ammo with the given equipment number from the bay. + * @param equipmentNum The equipment number of the ammo. + * @see Entity#getEquipmentNum(Mounted) + */ + public void removeAmmoFromBay(int equipmentNum) { + bayAmmo.remove(Integer.valueOf(equipmentNum)); + } + + /** + * Clears all ammo from the bay. + */ + public void clearBayAmmo() { + bayAmmo.clear(); + } + + public List getBayAmmo() { + return bayWeapons.stream() + .map(i -> getEntity().getAmmo(i)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } /** @@ -194,12 +271,44 @@ public List getBayAmmo() { * @return whether the ammo is in this weapon's bay */ public boolean ammoInBay(int mAmmoId) { - for (int nextAmmoId : bayAmmo) { - if (nextAmmoId == mAmmoId) { - return true; - } - } - return false; + return bayAmmo.contains(mAmmoId); + } + + /** + * Removes the weapon or ammo with the given equipment number from the bay. + * @param equipmentNum The weapon or ammo equipment number + * @see Entity#getEquipmentNum(Mounted) + */ + public void removeFromBay(int equipmentNum) { + bayWeapons.remove(Integer.valueOf(equipmentNum)); + bayAmmo.remove(Integer.valueOf(equipmentNum)); + } + + /** + * Removes the weapon or ammo from the bay. + * @param mounted The weapon or ammo to remove. + */ + public void removeFromBay(Mounted mounted) { + removeFromBay(mounted.getEquipmentNum()); + } + + /** + * Checks whether the bay contains the given weapon or ammo. + * @param equipmentNum The equipment number of the weapon or ammo. + * @return Whether the bay contains the equipment. + * @see Entity#getEquipmentNum(Mounted) + */ + public boolean bayContains(int equipmentNum) { + return bayWeapons.contains(equipmentNum) || bayAmmo.contains(equipmentNum); + } + + /** + * Checks whether the bay contains the given weapon or ammo. + * @param mounted The weapon or ammo. + * @return Wehther the bay contains the equipment. + */ + public boolean bayContains(Mounted mounted) { + return bayContains(mounted.getEquipmentNum()); } @Override @@ -215,4 +324,49 @@ protected List bayComponentsToString() { } return list; } + + + /** + * Assign APDS systems to the most dangerous incoming missile attacks. This + * should only be called once per turn, or AMS will get extra attacks + */ + public WeaponAttackAction assignAPDS(List vAttacks) { + // Shouldn't have null entity, but if we do... + if (getEntity() == null) { + return null; + } + + // Ensure we only target attacks in our arc & range + List vAttacksInArc = new Vector<>(vAttacks.size()); + for (WeaponHandler wr : vAttacks) { + boolean isInArc = Compute.isInArc(getEntity().getGame(), + getEntity().getId(), getEntity().getEquipmentNum(this), + getEntity().getGame().getEntity(wr.waa.getEntityId())); + boolean isInRange = getEntity().getPosition().distance( + wr.getWaa().getTarget(getEntity().getGame()).getPosition()) <= 3; + if (isInArc && isInRange) { + vAttacksInArc.add(wr.waa); + } + } + // find the most dangerous salvo by expected damage + WeaponAttackAction waa = Compute.getHighestExpectedDamage(getEntity() + .getGame(), vAttacksInArc, true); + if (waa != null) { + waa.addCounterEquipment(this); + return waa; + } + return null; + } + + /** + * @return Whether this mount is an advanced point defense system. + */ + public boolean isAPDS() { + if ((getEntity() instanceof BattleArmor) + && getType().getInternalName().equals("ISBAAPDS")) { + return true; + } else { + return getType().getAmmoType() == AmmoType.T_APDS; + } + } } diff --git a/megamek/src/megamek/common/loaders/BLKFile.java b/megamek/src/megamek/common/loaders/BLKFile.java index ee27673e60f..e5fa3f8d7c9 100644 --- a/megamek/src/megamek/common/loaders/BLKFile.java +++ b/megamek/src/megamek/common/loaders/BLKFile.java @@ -20,7 +20,9 @@ import com.sun.mail.util.DecodingException; import megamek.common.*; import megamek.common.InfantryBay.PlatoonType; +import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.ArmorType; +import megamek.common.equipment.WeaponMounted; import megamek.common.options.IBasicOption; import megamek.common.options.IOption; import megamek.common.options.PilotOptions; @@ -889,9 +891,9 @@ public static BuildingBlock getBlock(Entity t) { continue; } boolean rear = m.isRearMounted(); - for (int i = 0; i < m.getBayWeapons().size(); i++) { - Mounted w = t.getEquipment(m.getBayWeapons().get(i)); - String name = w.getType().getInternalName(); + List bayWeapons = ((WeaponMounted) m).getBayWeapons(); + for (int i = 0; i < bayWeapons.size(); i++) { + String name = bayWeapons.get(i).getType().getInternalName(); if (i == 0) { name = "(B) " + name; } @@ -900,8 +902,7 @@ public static BuildingBlock getBlock(Entity t) { } eq.get(loc).add(name); } - for (Integer aNum : m.getBayAmmo()) { - Mounted a = t.getEquipment(aNum); + for (AmmoMounted a : ((WeaponMounted) m).getBayAmmo()) { String name = a.getType().getInternalName(); name += ":" + a.getBaseShotsLeft(); if (rear) { diff --git a/megamek/src/megamek/common/templates/AeroTROView.java b/megamek/src/megamek/common/templates/AeroTROView.java index aa062601330..9d67e8f8d71 100644 --- a/megamek/src/megamek/common/templates/AeroTROView.java +++ b/megamek/src/megamek/common/templates/AeroTROView.java @@ -15,9 +15,10 @@ package megamek.common.templates; import megamek.common.*; +import megamek.common.equipment.AmmoMounted; +import megamek.common.equipment.WeaponMounted; import megamek.common.verifier.EntityVerifier; import megamek.common.verifier.TestAero; -import org.apache.logging.log4j.LogManager; import java.text.NumberFormat; import java.util.ArrayList; @@ -130,17 +131,17 @@ private void addArmorAndStructure() { */ protected int addWeaponBays(String[][] arcSets) { int nameWidth = 1; - final Map> baysByLoc = aero.getWeaponBayList().stream() + final Map> baysByLoc = aero.getWeaponBayList().stream() .collect(Collectors.groupingBy(this::getArcAbbr)); final List bayArcs = new ArrayList<>(); final Map heatByLoc = new HashMap<>(); final Map>> bayDetails = new HashMap<>(); for (final String[] arcSet : arcSets) { - final List bayList = baysByLoc.get(arcSet[0]); + final List bayList = baysByLoc.get(arcSet[0]); if (null != bayList) { final List> rows = new ArrayList<>(); int heat = 0; - for (final Mounted bay : bayList) { + for (final WeaponMounted bay : bayList) { final Map row = createBayRow(bay); heat += ((Number) row.get("heat")).intValue(); rows.add(row); @@ -161,26 +162,21 @@ protected int addWeaponBays(String[][] arcSets) { return nameWidth; } - private Map createBayRow(Mounted bay) { + private Map createBayRow(WeaponMounted bay) { final Map weaponCount = new HashMap<>(); int heat = 0; int srv = 0; int mrv = 0; int lrv = 0; int erv = 0; - final int multiplier = ((WeaponType) bay.getType()).isCapital() ? 10 : 1; - Mounted linker = null; + final int multiplier = bay.getType().isCapital() ? 10 : 1; + Mounted linker = null; // FIXME: Consider new AmmoType::equals / BombType::equals - final Map shotsByAmmoType = bay.getBayAmmo().stream().map(aero::getEquipment) - .collect(Collectors.groupingBy(m -> (AmmoType) m.getType(), + final Map shotsByAmmoType = bay.getBayAmmo().stream() + .collect(Collectors.groupingBy(AmmoMounted::getType, Collectors.summingInt(Mounted::getBaseShotsLeft))); - for (final Integer eqNum : bay.getBayWeapons()) { - final Mounted wMount = aero.getEquipment(eqNum); - if (null == wMount) { - LogManager.getLogger().error("Bay " + bay.getName() + " has non-existent weapon"); - continue; - } - final WeaponType wtype = (WeaponType) wMount.getType(); + for (final WeaponMounted wMount : bay.getBayWeapons()) { + final WeaponType wtype = wMount.getType(); if ((wMount.getLinkedBy() != null) && (wMount.getLinkedBy().getType() instanceof MiscType)) { linker = wMount.getLinkedBy(); } @@ -221,7 +217,7 @@ private Map createBayRow(Mounted bay) { * The weapon mount * @return The arc abbreviation. */ - protected String getArcAbbr(Mounted m) { + protected String getArcAbbr(Mounted m) { return aero.getLocationAbbr(m.getLocation()); } @@ -229,10 +225,10 @@ protected String getArcAbbr(Mounted m) { * Adds ammo data used by large craft */ protected void addAmmo() { - final Map> ammoByType = aero.getAmmo().stream() + final Map> ammoByType = aero.getAmmo().stream() .collect(Collectors.groupingBy(Mounted::getName)); final List> ammo = new ArrayList<>(); - for (final List aList : ammoByType.values()) { + for (final List aList : ammoByType.values()) { final Map ammoEntry = new HashMap<>(); ammoEntry.put("name", aList.get(0).getName().replaceAll("\\s+Ammo", "")); ammoEntry.put("shots", aList.stream().mapToInt(Mounted::getUsableShotsLeft).sum()); diff --git a/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java b/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java index c5bc384ccd1..f9a45b07a25 100644 --- a/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java +++ b/megamek/src/megamek/common/verifier/TestAdvancedAerospace.java @@ -15,6 +15,7 @@ package megamek.common.verifier; import megamek.common.*; +import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.ArmorType; import megamek.common.equipment.WeaponMounted; import megamek.common.util.StringUtil; @@ -501,21 +502,19 @@ public StringBuffer printWeapon() { return super.printWeapon(); } StringBuffer buffer = new StringBuffer(); - for (Mounted m : getEntity().getWeaponBayList()) { + for (WeaponMounted m : getEntity().getWeaponBayList()) { buffer.append(m.getName()).append(" ") .append(getLocationAbbr(m.getLocation())); if (m.isRearMounted()) { buffer.append(" (R)"); } buffer.append("\n"); - for (Integer wNum : m.getBayWeapons()) { - final Mounted w = getEntity().getEquipment(wNum); + for (WeaponMounted w : m.getBayWeapons()) { buffer.append(" ").append(StringUtil.makeLength(w.getName(), getPrintSize() - 25)).append(w.getTonnage()) .append("\n"); } - for (Integer aNum : m.getBayAmmo()) { - final Mounted a = getEntity().getEquipment(aNum); + for (AmmoMounted a : m.getBayAmmo()) { double weight = ceil(a.getTonnage() * a.getBaseShotsLeft() / ((AmmoType) a.getType()).getShots(), Ceil.HALFTON); buffer.append(" ").append(StringUtil.makeLength(a.getName(), @@ -641,34 +640,21 @@ public boolean hasIllegalEquipmentCombinations(StringBuffer buff) { // Make sure all bays have at least one weapon and that there are at least // ten shots of ammo for each ammo-using weapon in the bay. - for (Mounted bay : vessel.getWeaponBayList()) { + for (WeaponMounted bay : vessel.getWeaponBayList()) { if (bay.getBayWeapons().isEmpty()) { buff.append("Bay ").append(bay.getName()).append(" has no weapons\n"); illegal = true; } Map ammoWeaponCount = new HashMap<>(); Map ammoTypeCount = new HashMap<>(); - for (Integer wNum : bay.getBayWeapons()) { - final Mounted w = vessel.getEquipment(wNum); + for (WeaponMounted w : bay.getBayWeapons()) { if (w.isOneShot()) { continue; } - if (w.getType() instanceof WeaponType) { - ammoWeaponCount.merge(((WeaponType) w.getType()).getAmmoType(), 1, Integer::sum); - } else { - buff.append(w.getName()).append(" in bay ").append(bay.getName()).append(" is not a weapon\n"); - illegal = true; - } + ammoWeaponCount.merge(w.getType().getAmmoType(), 1, Integer::sum); } - for (Integer aNum : bay.getBayAmmo()) { - final Mounted a = vessel.getEquipment(aNum); - if (a.getType() instanceof AmmoType) { - ammoTypeCount.merge(((AmmoType) a.getType()).getAmmoType(), a.getUsableShotsLeft(), - Integer::sum); - } else { - buff.append(a.getName()).append(" in bay ").append(bay.getName()).append(" is not ammo\n"); - illegal = true; - } + for (AmmoMounted a : bay.getBayAmmo()) { + ammoTypeCount.merge(a.getType().getAmmoType(), a.getUsableShotsLeft(), Integer::sum); } for (Integer at : ammoWeaponCount.keySet()) { if (at != AmmoType.T_NA) { diff --git a/megamek/src/megamek/common/verifier/TestSmallCraft.java b/megamek/src/megamek/common/verifier/TestSmallCraft.java index 5bc0ea8f958..f19c2b0b0ef 100644 --- a/megamek/src/megamek/common/verifier/TestSmallCraft.java +++ b/megamek/src/megamek/common/verifier/TestSmallCraft.java @@ -15,7 +15,9 @@ package megamek.common.verifier; import megamek.common.*; +import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.ArmorType; +import megamek.common.equipment.WeaponMounted; import megamek.common.util.StringUtil; import java.math.BigInteger; @@ -378,21 +380,19 @@ public StringBuffer printWeapon() { return super.printWeapon(); } StringBuffer buffer = new StringBuffer(); - for (Mounted m : getEntity().getWeaponBayList()) { + for (WeaponMounted m : getEntity().getWeaponBayList()) { buffer.append(m.getName()).append(" ") .append(getLocationAbbr(m.getLocation())); if (m.isRearMounted()) { buffer.append(" (R)"); } buffer.append("\n"); - for (Integer wNum : m.getBayWeapons()) { - final Mounted w = getEntity().getEquipment(wNum); + for (WeaponMounted w : m.getBayWeapons()) { buffer.append(" ").append(StringUtil.makeLength(w.getName(), getPrintSize() - 25)).append(w.getTonnage()) .append("\n"); } - for (Integer aNum : m.getBayAmmo()) { - final Mounted a = getEntity().getEquipment(aNum); + for (AmmoMounted a : m.getBayAmmo()) { double weight = a.getTonnage() * a.getBaseShotsLeft() / ((AmmoType) a.getType()).getShots(); buffer.append(" ").append(StringUtil.makeLength(a.getName(), getPrintSize() - 25)).append(weight).append("\n"); @@ -520,35 +520,22 @@ public boolean hasIllegalEquipmentCombinations(StringBuffer buff) { // For DropShips, make sure all bays have at least one weapon and that there are at least // ten shots of ammo for each ammo-using weapon in the bay. - for (Mounted bay : smallCraft.getWeaponBayList()) { + for (WeaponMounted bay : smallCraft.getWeaponBayList()) { if (bay.getBayWeapons().isEmpty()) { buff.append("Bay ").append(bay.getName()).append(" has no weapons\n"); illegal = true; } Map ammoWeaponCount = new HashMap<>(); Map ammoTypeCount = new HashMap<>(); - for (Integer wNum : bay.getBayWeapons()) { - final Mounted w = smallCraft.getEquipment(wNum); + for (WeaponMounted w : bay.getBayWeapons()) { if (w.isOneShot()) { continue; } - if (w.getType() instanceof WeaponType) { - ammoWeaponCount.merge(((WeaponType) w.getType()).getAmmoType(), 1, Integer::sum); - } else { - buff.append(w.getName()).append(" in bay ").append(bay.getName()).append(" is not a weapon\n"); - illegal = true; - } + ammoWeaponCount.merge(w.getType().getAmmoType(), 1, Integer::sum); } - for (Integer aNum : bay.getBayAmmo()) { - final Mounted a = smallCraft.getEquipment(aNum); - if (a.getType() instanceof AmmoType) { - ammoTypeCount.merge(((AmmoType) a.getType()).getAmmoType(), a.getUsableShotsLeft(), - Integer::sum); - } else { - buff.append(a.getName()).append(" in bay ").append(bay.getName()).append(" is not ammo\n"); - illegal = true; - } + for (AmmoMounted a : bay.getBayAmmo()) { + ammoTypeCount.merge(a.getType().getAmmoType(), a.getUsableShotsLeft(), Integer::sum); } for (Integer at : ammoWeaponCount.keySet()) { diff --git a/megamek/src/megamek/common/weapons/ACBayHandler.java b/megamek/src/megamek/common/weapons/ACBayHandler.java index c22fca9741b..1c2a0e5f49b 100644 --- a/megamek/src/megamek/common/weapons/ACBayHandler.java +++ b/megamek/src/megamek/common/weapons/ACBayHandler.java @@ -50,12 +50,7 @@ public ACBayHandler(ToHitData t, WeaponAttackAction w, Game g, GameManager m) { */ @Override protected boolean doChecks(Vector vPhaseReport) { - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = ae.getWeapon(wId); - if (bayW == null) { - LogManager.getLogger().error("Handler can't find the weapon!"); - return false; - } + for (WeaponMounted bayW : weapon.getBayWeapons()) { WeaponType bayWType = bayW.getType(); int ammoUsed = bayW.getCurrentShots(); if (bayWType.getAmmoType() == AmmoType.T_AC_ROTARY) { diff --git a/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java b/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java index 9832b6a04a2..b25f8726b1a 100644 --- a/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java @@ -15,7 +15,6 @@ import megamek.common.AmmoType; import megamek.common.Game; -import megamek.common.Mounted; import megamek.common.RangeType; import megamek.common.ToHitData; import megamek.common.WeaponType; @@ -23,8 +22,6 @@ import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.WeaponMounted; import megamek.server.GameManager; -import megamek.server.Server; -import org.apache.logging.log4j.LogManager; /** * @author Jay Lawson @@ -63,12 +60,7 @@ protected int calcAttackValue() { double av = 0; int range = RangeType.rangeBracket(nRange, wtype.getATRanges(), true, false); - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = ae.getWeapon(wId); - if (bayW == null) { - LogManager.getLogger().error("Handler can't find the weapon!"); - return 0; - } + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); if (null == bayWAmmo || bayWAmmo.getUsableShotsLeft() < 1) { @@ -96,7 +88,7 @@ protected int calcAttackValue() { current_av = bayWType.getExtAV(); } current_av = updateAVforAmmo(current_av, atype, bayWType, - range, wId); + range, bayW.getEquipmentNum()); av = av + current_av; // now use the ammo that we had loaded if (current_av > 0) { diff --git a/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java b/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java index 805fd7296c5..cc437ff303c 100644 --- a/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java +++ b/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java @@ -51,13 +51,7 @@ public boolean cares(final GamePhase phase) { @Override protected void useAmmo() { nweaponsHit = weapon.getBayWeapons().size(); - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = ae.getWeapon(wId); - if (bayW == null) { - LogManager.getLogger().error("Handler can't find the weapon!"); - return; - } - + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); diff --git a/megamek/src/megamek/common/weapons/BayWeaponHandler.java b/megamek/src/megamek/common/weapons/BayWeaponHandler.java index 23856cc7eb9..f020c53c87e 100644 --- a/megamek/src/megamek/common/weapons/BayWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/BayWeaponHandler.java @@ -16,6 +16,8 @@ import megamek.common.*; import megamek.common.actions.WeaponAttackAction; import megamek.common.enums.GamePhase; +import megamek.common.equipment.AmmoMounted; +import megamek.common.equipment.WeaponMounted; import megamek.common.options.OptionsConstants; import megamek.server.GameManager; import megamek.server.Server; @@ -28,7 +30,7 @@ */ public class BayWeaponHandler extends WeaponHandler { private static final long serialVersionUID = -1618484541772117621L; - Mounted ammo; + AmmoMounted ammo; protected BayWeaponHandler() { // deserialization only @@ -48,8 +50,7 @@ protected int calcAttackValue() { double av = 0; int range = RangeType.rangeBracket(nRange, wtype.getATRanges(), true, false); - for (int wId : weapon.getBayWeapons()) { - Mounted m = ae.getEquipment(wId); + for (WeaponMounted m : weapon.getBayWeapons()) { if (!m.isBreached() && !m.isDestroyed() && !m.isJammed()) { WeaponType bayWType = ((WeaponType) m.getType()); // need to cycle through weapons and add av @@ -81,8 +82,7 @@ protected void addHeat() { } if (!(toHit.getValue() == TargetRoll.IMPOSSIBLE)) { if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_HEAT_BY_BAY)) { - for (int wId : weapon.getBayWeapons()) { - Mounted m = ae.getEquipment(wId); + for (WeaponMounted m : weapon.getBayWeapons()) { ae.heatBuildup += m.getCurrentHeat(); } } else { @@ -266,9 +266,8 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { int range = RangeType.rangeBracket(nRange, wtype.getATRanges(), true, false); int hits = 1; int nCluster = 1; - for (int wId : weapon.getBayWeapons()) { + for (WeaponMounted m : weapon.getBayWeapons()) { double av = 0; - Mounted m = ae.getEquipment(wId); if (!m.isBreached() && !m.isDestroyed() && !m.isJammed()) { WeaponType bayWType = ((WeaponType) m.getType()); // need to cycle through weapons and add av @@ -541,13 +540,13 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { ToHitData autoHit = new ToHitData(); autoHit.addModifier(TargetRoll.AUTOMATIC_SUCCESS, "if the bay hits, all bay weapons hit"); int replaceReport; - for (int wId : weapon.getBayWeapons()) { - Mounted m = ae.getEquipment(wId); + for (WeaponMounted m : weapon.getBayWeapons()) { if (!m.isBreached() && !m.isDestroyed() && !m.isJammed()) { - WeaponType bayWType = ((WeaponType) m.getType()); + WeaponType bayWType = m.getType(); if (bayWType instanceof Weapon) { replaceReport = vPhaseReport.size(); - WeaponAttackAction bayWaa = new WeaponAttackAction(waa.getEntityId(), waa.getTargetType(), waa.getTargetId(), wId); + WeaponAttackAction bayWaa = new WeaponAttackAction(waa.getEntityId(), waa.getTargetType(), + waa.getTargetId(), m.getEquipmentNum()); AttackHandler bayWHandler = ((Weapon) bayWType).getCorrectHandler(autoHit, bayWaa, game, gameManager); bayWHandler.setAnnouncedEntityFiring(false); // This should always be true diff --git a/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java b/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java index 7ea6350085c..6ae4f0ccdda 100644 --- a/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java +++ b/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java @@ -269,12 +269,7 @@ protected int calcAttackValue() { int weaponarmor = 0; int range = RangeType.rangeBracket(nRange, wtype.getATRanges(), true, false); - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = ae.getWeapon(wId); - if (bayW == null) { - LogManager.getLogger().error("Handler can't find the weapon!"); - return 0; - } + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); if (null == bayWAmmo || bayWAmmo.getUsableShotsLeft() < 1) { @@ -321,7 +316,7 @@ protected int calcAttackValue() { } current_av = updateAVforAmmo(current_av, atype, bayWType, - range, wId); + range, bayW.getEquipmentNum()); av = av + current_av; armor = armor + weaponarmor; // now use the ammo that we had loaded @@ -376,13 +371,12 @@ protected int getCapMissileAMSMod() { @Override protected int initializeCapMissileArmor() { int armor = 0; - for (int wId : weapon.getBayWeapons()) { + for (WeaponMounted bayW : weapon.getBayWeapons()) { int curr_armor = 0; - Mounted bayW = ae.getEquipment(wId); // check the currently loaded ammo - Mounted bayWAmmo = bayW.getLinked(); - AmmoType atype = (AmmoType) bayWAmmo.getType(); - WeaponType bayWType = ((WeaponType) bayW.getType()); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); + AmmoType atype = bayWAmmo.getType(); + WeaponType bayWType = bayW.getType(); if (bayWType.getAtClass() == (WeaponType.CLASS_AR10) && (atype.hasFlag(AmmoType.F_AR10_KILLER_WHALE) || atype.hasFlag(AmmoType.F_PEACEMAKER))) { @@ -405,13 +399,11 @@ protected int initializeCapMissileArmor() { @Override protected int getCapMisMod() { int mod = 0; - for (int wId : weapon.getBayWeapons()) { + for (WeaponMounted bayW : weapon.getBayWeapons()) { int curr_mod = 0; - Mounted bayW = ae.getEquipment(wId); // check the currently loaded ammo - Mounted bayWAmmo = bayW.getLinked(); - AmmoType atype = (AmmoType) bayWAmmo.getType(); - curr_mod = getCritMod(atype); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); + curr_mod = getCritMod(bayWAmmo.getType()); if (curr_mod > mod) { mod = curr_mod; } @@ -509,7 +501,7 @@ protected void insertAttacks(GamePhase phase, Vector vPhaseReport) { * This should return true. Only when handling capital missile attacks can this be false. */ @Override - protected boolean canEngageCapitalMissile(Mounted counter) { + protected boolean canEngageCapitalMissile(WeaponMounted counter) { return counter.getBayWeapons().size() >= 2; } @@ -712,13 +704,13 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { ToHitData autoHit = new ToHitData(); autoHit.addModifier(TargetRoll.AUTOMATIC_SUCCESS, "if the bay hits, all bay weapons hit"); int replaceReport; - for (int wId : weapon.getBayWeapons()) { - Mounted m = ae.getEquipment(wId); + for (WeaponMounted m : weapon.getBayWeapons()) { if (!m.isBreached() && !m.isDestroyed() && !m.isJammed()) { WeaponType bayWType = ((WeaponType) m.getType()); if (bayWType instanceof Weapon) { replaceReport = vPhaseReport.size(); - WeaponAttackAction bayWaa = new WeaponAttackAction(waa.getEntityId(), waa.getTargetType(), waa.getTargetId(), wId); + WeaponAttackAction bayWaa = new WeaponAttackAction(waa.getEntityId(), waa.getTargetType(), + waa.getTargetId(), m.getEquipmentNum()); AttackHandler bayWHandler = ((Weapon) bayWType).getCorrectHandler(autoHit, bayWaa, game, gameManager); bayWHandler.setAnnouncedEntityFiring(false); // This should always be true. Maybe there's a better way to write this? diff --git a/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java b/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java index 0c384ed41ca..10da53def86 100644 --- a/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java +++ b/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java @@ -67,8 +67,7 @@ public boolean cares(GamePhase phase) { } protected void getMountedAmmo() { - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = ae.getWeapon(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo bayWAmmo = bayW.getLinkedAmmo(); @@ -284,13 +283,13 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { ToHitData autoHit = new ToHitData(); autoHit.addModifier(TargetRoll.AUTOMATIC_SUCCESS, "if the bay hits, all bay weapons hit"); int replaceReport; - for (int wId : weapon.getBayWeapons()) { - Mounted m = ae.getEquipment(wId); + for (WeaponMounted m : weapon.getBayWeapons()) { if (!m.isBreached() && !m.isDestroyed() && !m.isJammed()) { - WeaponType bayWType = ((WeaponType) m.getType()); + WeaponType bayWType = m.getType(); if (bayWType instanceof Weapon) { replaceReport = vPhaseReport.size(); - WeaponAttackAction bayWaa = new WeaponAttackAction(waa.getEntityId(), waa.getTargetType(), waa.getTargetId(), wId); + WeaponAttackAction bayWaa = new WeaponAttackAction(waa.getEntityId(), waa.getTargetType(), + waa.getTargetId(), bayWAmmo.getEquipmentNum()); AttackHandler bayWHandler = ((Weapon) bayWType).getCorrectHandler(autoHit, bayWaa, game, gameManager); bayWHandler.setAnnouncedEntityFiring(false); // This should always be true. Maybe there's a better way to write this? @@ -660,7 +659,7 @@ protected boolean handleSpecialMiss(Entity entityTarget, * This should return true. Only when handling capital missile attacks can this be false. */ @Override - protected boolean canEngageCapitalMissile(Mounted counter) { + protected boolean canEngageCapitalMissile(WeaponMounted counter) { return counter.getBayWeapons().size() >= 2; } @@ -689,8 +688,7 @@ protected int calcAttackValue() { // A bearings-only shot is, by definition, always going to be at extreme range... int range = RangeType.RANGE_EXTREME; - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = ae.getWeapon(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); if (null == bayWAmmo || bayWAmmo.getUsableShotsLeft() < 1) { @@ -737,7 +735,7 @@ protected int calcAttackValue() { } current_av = updateAVforAmmo(current_av, atype, bayWType, - range, wId); + range, bayW.getEquipmentNum()); av = av + current_av; armor = armor + weaponarmor; } @@ -816,13 +814,12 @@ protected int getCapMissileAMSMod() { @Override protected int initializeCapMissileArmor() { int armor = 0; - for (int wId : weapon.getBayWeapons()) { + for (WeaponMounted bayW : weapon.getBayWeapons()) { int curr_armor = 0; - Mounted bayW = ae.getEquipment(wId); // check the currently loaded ammo - Mounted bayWAmmo = bayW.getLinked(); - AmmoType atype = (AmmoType) bayWAmmo.getType(); - WeaponType bayWType = ((WeaponType) bayW.getType()); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); + AmmoType atype = bayWAmmo.getType(); + WeaponType bayWType = bayW.getType(); if (bayWType.getAtClass() == (WeaponType.CLASS_AR10) && (atype.hasFlag(AmmoType.F_AR10_KILLER_WHALE) || atype.hasFlag(AmmoType.F_PEACEMAKER))) { @@ -845,13 +842,11 @@ protected int initializeCapMissileArmor() { @Override protected int getCapMisMod() { int mod = 0; - for (int wId : weapon.getBayWeapons()) { + for (WeaponMounted bayW : weapon.getBayWeapons()) { int curr_mod = 0; - Mounted bayW = ae.getEquipment(wId); // check the currently loaded ammo - Mounted bayWAmmo = bayW.getLinked(); - AmmoType atype = (AmmoType) bayWAmmo.getType(); - curr_mod = getCritMod(atype); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); + curr_mod = getCritMod(bayWAmmo.getType()); if (curr_mod > mod) { mod = curr_mod; } diff --git a/megamek/src/megamek/common/weapons/CapitalMissileHandler.java b/megamek/src/megamek/common/weapons/CapitalMissileHandler.java index 019521cf4a1..0fbe252f8a2 100644 --- a/megamek/src/megamek/common/weapons/CapitalMissileHandler.java +++ b/megamek/src/megamek/common/weapons/CapitalMissileHandler.java @@ -34,6 +34,7 @@ import megamek.common.WeaponType; import megamek.common.actions.WeaponAttackAction; import megamek.common.enums.GamePhase; +import megamek.common.equipment.WeaponMounted; import megamek.common.options.OptionsConstants; import megamek.server.GameManager; import megamek.server.Server; @@ -495,12 +496,8 @@ protected int getCritMod(AmmoType atype) { * This should return true. Only when handling capital missile attacks can this be false. */ @Override - protected boolean canEngageCapitalMissile(Mounted counter) { - if (counter.getBayWeapons().size() < 2) { - return false; - } else { - return true; - } + protected boolean canEngageCapitalMissile(WeaponMounted counter) { + return counter.getBayWeapons().size() >= 2; } /** diff --git a/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java b/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java index 9e579ae46fc..2495bc707a4 100644 --- a/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java @@ -75,8 +75,7 @@ protected int calcAttackValue() { int weaponarmor = 0; int range = RangeType.rangeBracket(nRange, wtype.getATRanges(), true, false); - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = ae.getWeapon(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); if (null == bayWAmmo || bayWAmmo.getUsableShotsLeft() < 1) { @@ -105,7 +104,7 @@ protected int calcAttackValue() { current_av = bayWType.getExtAV(); } current_av = updateAVforAmmo(current_av, atype, bayWType, - range, wId); + range, bayW.getEquipmentNum()); av = av + current_av; //If these are thunderbolts, they'll have missile armor weaponarmor += bayWType.getMissileArmor(); @@ -187,12 +186,8 @@ protected boolean isTbolt() { @Override protected int initializeCapMissileArmor() { int armor = 0; - for (int wId : weapon.getBayWeapons()) { - int curr_armor = 0; - Mounted bayW = ae.getEquipment(wId); - WeaponType bayWType = ((WeaponType) bayW.getType()); - curr_armor = bayWType.getMissileArmor(); - armor = armor + curr_armor; + for (WeaponMounted bayW : weapon.getBayWeapons()) { + armor += bayW.getType().getMissileArmor(); } return armor; } @@ -441,9 +436,8 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { int range = RangeType.rangeBracket(nRange, wtype.getATRanges(), true, false); int hits = 1; int nCluster = 1; - for (int wId : weapon.getBayWeapons()) { + for (WeaponMounted m : weapon.getBayWeapons()) { double av = 0; - Mounted m = ae.getEquipment(wId); if (!m.isBreached() && !m.isDestroyed() && !m.isJammed()) { WeaponType bayWType = ((WeaponType) m.getType()); // need to cycle through weapons and add av diff --git a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java index 1d131c82d98..3a339dd954b 100644 --- a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java @@ -17,11 +17,14 @@ import megamek.common.*; import megamek.common.actions.WeaponAttackAction; import megamek.common.enums.GamePhase; +import megamek.common.equipment.AmmoMounted; +import megamek.common.equipment.WeaponMounted; import megamek.common.options.OptionsConstants; import megamek.server.GameManager; import java.util.ArrayList; import java.util.Enumeration; +import java.util.List; import java.util.Vector; /** @@ -448,10 +451,10 @@ protected int getAMSHitsMod(Vector vPhaseReport) { int amsMod = 0; Entity entityTarget = (Entity) target; // any AMS attacks by the target? - ArrayList lCounters = waa.getCounterEquipment(); + List lCounters = waa.getCounterEquipment(); if (null != lCounters) { // resolve AMS counter-fire - for (Mounted counter : lCounters) { + for (WeaponMounted counter : lCounters) { // Set up differences between different types of AMS boolean isAMS = counter.getType().hasFlag(WeaponType.F_AMS); boolean isAMSBay = counter.getType().hasFlag(WeaponType.F_AMSBAY); @@ -493,9 +496,8 @@ protected int getAMSHitsMod(Vector vPhaseReport) { // If we're an AMSBay, heat and ammo must be calculated differently if (isAMSBay) { - for (int wId : counter.getBayWeapons()) { - Mounted bayW = entityTarget.getEquipment(wId); - Mounted bayWAmmo = bayW.getLinked(); + for (WeaponMounted bayW : counter.getBayWeapons()) { + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); // For AMS bays, stop the loop if an AMS in the bay has engaged this attack if (amsEngaged) { break; diff --git a/megamek/src/megamek/common/weapons/PlasmaBayWeaponHandler.java b/megamek/src/megamek/common/weapons/PlasmaBayWeaponHandler.java index f255b41aec9..9cbde6b65e0 100644 --- a/megamek/src/megamek/common/weapons/PlasmaBayWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/PlasmaBayWeaponHandler.java @@ -31,6 +31,7 @@ import megamek.common.WeaponType; import megamek.common.actions.WeaponAttackAction; import megamek.common.equipment.ArmorType; +import megamek.common.equipment.WeaponMounted; import megamek.common.weapons.ppc.CLPlasmaCannon; import megamek.common.weapons.ppc.ISPlasmaRifle; import megamek.server.GameManager; @@ -64,8 +65,7 @@ protected void handleEntityDamage(Entity entityTarget, if (!missed && ((entityTarget instanceof Mech) || (entityTarget instanceof Aero))) { int extraHeat = 0; - for (int wId : weapon.getBayWeapons()) { - Mounted m = ae.getEquipment(wId); + for (WeaponMounted m : weapon.getBayWeapons()) { if (!m.isBreached() && !m.isDestroyed() && !m.isJammed()) { WeaponType bayWType = ((WeaponType) m.getType()); if (bayWType instanceof ISPlasmaRifle) { diff --git a/megamek/src/megamek/common/weapons/TeleMissileHandler.java b/megamek/src/megamek/common/weapons/TeleMissileHandler.java index d62348ba7ac..69a1640da21 100644 --- a/megamek/src/megamek/common/weapons/TeleMissileHandler.java +++ b/megamek/src/megamek/common/weapons/TeleMissileHandler.java @@ -49,17 +49,16 @@ public TeleMissileHandler(ToHitData t, WeaponAttackAction w, Game g, */ private AmmoType getBayAmmoType() { AmmoType at = null; - for (int wId : weapon.getBayWeapons()) { - Mounted bayW = ae.getEquipment(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo - Mounted bayWAmmo = bayW.getLinked(); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); if (bayWAmmo == null) { LogManager.getLogger().debug("Handler can't find any ammo! Oh no!"); continue; } //Once we have some ammo to send to the server, stop looking - at = (AmmoType) bayWAmmo.getType(); + at = bayWAmmo.getType(); break; } return at; @@ -67,9 +66,8 @@ private AmmoType getBayAmmoType() { private int calcBayDamageAndHeat() { int damage = 0; - for (int wId : weapon.getBayWeapons()) { - Mounted bayW = ae.getEquipment(wId); - WeaponType bayWType = ((WeaponType) bayW.getType()); + for (WeaponMounted bayW : weapon.getBayWeapons()) { + WeaponType bayWType = bayW.getType(); damage += (int) bayWType.getShortAV(); ae.heatBuildup += bayW.getCurrentHeat(); missileArmor = bayWType.getMissileArmor(); @@ -79,8 +77,7 @@ private int calcBayDamageAndHeat() { @Override protected void useAmmo() { - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = (WeaponMounted) ae.getEquipment(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { // check the currently loaded ammo AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); diff --git a/megamek/src/megamek/common/weapons/WeaponHandler.java b/megamek/src/megamek/common/weapons/WeaponHandler.java index 8e5373745e4..a270dac8ec1 100644 --- a/megamek/src/megamek/common/weapons/WeaponHandler.java +++ b/megamek/src/megamek/common/weapons/WeaponHandler.java @@ -20,6 +20,7 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.enums.AimingMode; import megamek.common.enums.GamePhase; +import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.WeaponMounted; import megamek.common.options.OptionsConstants; import megamek.common.planetaryconditions.PlanetaryConditions; @@ -34,6 +35,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Enumeration; +import java.util.List; import java.util.Vector; /** @@ -138,9 +140,8 @@ protected int getLargeCraftHeat(Entity e) { AttackHandler ah = i.nextElement(); WeaponAttackAction prevAttack = ah.getWaa(); if (prevAttack.getEntityId() == e.getId()) { - Mounted prevWeapon = e.getEquipment(prevAttack.getWeaponId()); - for (int wId : prevWeapon.getBayWeapons()) { - Mounted bayW = e.getEquipment(wId); + WeaponMounted prevWeapon = (WeaponMounted) e.getEquipment(prevAttack.getWeaponId()); + for (WeaponMounted bayW : prevWeapon.getBayWeapons()) { totalheat += bayW.getCurrentHeat(); } } @@ -150,7 +151,7 @@ protected int getLargeCraftHeat(Entity e) { AttackHandler ah = i.nextElement(); WeaponAttackAction prevAttack = ah.getWaa(); if (prevAttack.getEntityId() == e.getId()) { - Mounted prevWeapon = e.getEquipment(prevAttack.getWeaponId()); + Mounted prevWeapon = e.getEquipment(prevAttack.getWeaponId()); totalheat += prevWeapon.getCurrentHeat(); } } @@ -191,7 +192,7 @@ protected boolean checkPDConditions() { * See also TeleMissileAttackAction, which contains a modified version of this to work against * a TeleMissile entity in the physical phase */ - protected boolean canEngageCapitalMissile(Mounted counter) { + protected boolean canEngageCapitalMissile(WeaponMounted counter) { return true; } @@ -233,11 +234,11 @@ protected int calcCounterAV() { double pdAV = 0; Entity entityTarget = (Entity) target; // any AMS bay attacks by the target? - ArrayList lCounters = waa.getCounterEquipment(); + List lCounters = waa.getCounterEquipment(); // We need to know how much heat has been assigned to offensive weapons fire by the defender this round int weaponHeat = getLargeCraftHeat(entityTarget) + entityTarget.heatBuildup; if (null != lCounters) { - for (Mounted counter : lCounters) { + for (WeaponMounted counter : lCounters) { // Point defenses only fire vs attacks against the arc they protect Entity pdEnt = counter.getEntity(); boolean isInArc; @@ -255,8 +256,7 @@ protected int calcCounterAV() { continue; } // Point defenses can't fire if they're not ready for any other reason - if (!(counter.getType() instanceof WeaponType) - || !counter.isReady() || counter.isMissing() + if (!counter.isReady() || counter.isMissing() // shutdown means no Point defenses || pdEnt.isShutDown()) { continue; @@ -281,10 +281,9 @@ protected int calcCounterAV() { // First, reset the temporary damage counters amsAV = 0; pdAV = 0; - for (int wId : counter.getBayWeapons()) { - Mounted bayW = pdEnt.getEquipment(wId); - Mounted bayWAmmo = bayW.getLinked(); - WeaponType bayWType = ((WeaponType) bayW.getType()); + for (WeaponMounted bayW : counter.getBayWeapons()) { + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); + WeaponType bayWType = bayW.getType(); // build up some heat // First Check to see if we have enough heat capacity to fire diff --git a/megamek/src/megamek/common/weapons/bayweapons/AmmoBayWeapon.java b/megamek/src/megamek/common/weapons/bayweapons/AmmoBayWeapon.java index a7fbe4b22b8..10438cb939c 100644 --- a/megamek/src/megamek/common/weapons/bayweapons/AmmoBayWeapon.java +++ b/megamek/src/megamek/common/weapons/bayweapons/AmmoBayWeapon.java @@ -46,8 +46,7 @@ public AttackHandler fire(WeaponAttackAction waa, Game game, GameManager manager protected void checkAmmo(WeaponAttackAction waa, Game g) { Entity ae = waa.getEntity(g); WeaponMounted bay = ae.getWeapon(waa.getWeaponId()); - for (int wId : bay.getBayWeapons()) { - WeaponMounted weapon = ae.getWeapon(wId); + for (WeaponMounted weapon : bay.getBayWeapons()) { AmmoMounted ammo = weapon.getLinkedAmmo(); if (ammo == null || ammo.getUsableShotsLeft() < 1) { ae.loadWeaponWithSameAmmo(weapon); diff --git a/megamek/src/megamek/common/weapons/bayweapons/ArtilleryBayWeapon.java b/megamek/src/megamek/common/weapons/bayweapons/ArtilleryBayWeapon.java index 69c3ccb8e68..49cf85f8f39 100644 --- a/megamek/src/megamek/common/weapons/bayweapons/ArtilleryBayWeapon.java +++ b/megamek/src/megamek/common/weapons/bayweapons/ArtilleryBayWeapon.java @@ -15,6 +15,8 @@ import megamek.common.*; import megamek.common.actions.WeaponAttackAction; +import megamek.common.equipment.AmmoMounted; +import megamek.common.equipment.WeaponMounted; import megamek.common.weapons.*; import megamek.server.GameManager; @@ -56,10 +58,9 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { Entity ae = game.getEntity(waa.getEntityId()); boolean useHoming = false; - for (int wId : ((Mounted) ae.getEquipment(waa.getWeaponId())).getBayWeapons()) { - Mounted bayW = ae.getEquipment(wId); + for (WeaponMounted bayW : ((WeaponMounted) ae.getEquipment(waa.getWeaponId())).getBayWeapons()) { // check the currently loaded ammo - Mounted bayWAmmo = bayW.getLinked(); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); waa.setAmmoId(ae.getEquipmentNum(bayWAmmo)); waa.setAmmoMunitionType(((AmmoType) bayWAmmo.getType()).getMunitionType()); waa.setAmmoCarrier(ae.getId()); diff --git a/megamek/src/megamek/common/weapons/bayweapons/BayWeapon.java b/megamek/src/megamek/common/weapons/bayweapons/BayWeapon.java index 7805fe9f134..cd28a46f4ed 100644 --- a/megamek/src/megamek/common/weapons/bayweapons/BayWeapon.java +++ b/megamek/src/megamek/common/weapons/bayweapons/BayWeapon.java @@ -21,7 +21,6 @@ import megamek.common.weapons.BayWeaponHandler; import megamek.common.weapons.Weapon; import megamek.server.GameManager; -import megamek.server.Server; /** * This is my attempt to get weapon bays treated as normal weapons rather than the current hack in @@ -73,8 +72,7 @@ public int getMaxRange(WeaponMounted weapon, AmmoMounted ammo) { int mrange = RANGE_SHORT; Entity ae = weapon.getEntity(); if (null != ae) { - for (int wId : weapon.getBayWeapons()) { - WeaponMounted bayW = (WeaponMounted) ae.getEquipment(wId); + for (WeaponMounted bayW : weapon.getBayWeapons()) { WeaponType bayWType = bayW.getType(); if (bayWType.getMaxRange(bayW) > mrange) { mrange = bayWType.getMaxRange(bayW); diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index d266d125e25..46d21b54a31 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -15,6 +15,7 @@ import megamek.common.*; import megamek.common.actions.WeaponAttackAction; +import megamek.common.equipment.WeaponMounted; import megamek.common.equipment.AmmoMounted; import megamek.common.equipment.WeaponMounted; import megamek.common.options.GameOptions; diff --git a/megamek/src/megamek/server/GameManager.java b/megamek/src/megamek/server/GameManager.java index e87f7f4230c..1779cd62ab4 100644 --- a/megamek/src/megamek/server/GameManager.java +++ b/megamek/src/megamek/server/GameManager.java @@ -13465,11 +13465,11 @@ public void assignTeleMissileAMS(final TeleMissileAttackAction taa) { */ public void assignAMS() { // Get all of the coords that would be protected by APDS - Hashtable> apdsCoords = getAPDSProtectedCoords(); + Hashtable> apdsCoords = getAPDSProtectedCoords(); // Map target to a list of missile attacks directed at it Hashtable> htAttacks = new Hashtable<>(); // Keep track of each APDS, and which attacks it could affect - Hashtable> apdsTargets = new Hashtable<>(); + Hashtable> apdsTargets = new Hashtable<>(); for (AttackHandler ah : game.getAttacksVector()) { WeaponHandler wh = (WeaponHandler) ah; @@ -13536,7 +13536,7 @@ public void assignAMS() { v.addElement(wh); // Keep track of what weapon attacks could be affected by APDS if (apdsCoords.containsKey(target.getPosition())) { - for (Mounted apds : apdsCoords.get(target.getPosition())) { + for (WeaponMounted apds : apdsCoords.get(target.getPosition())) { // APDS only affects attacks against friendly units if (target.isEnemyOf(apds.getEntity())) { continue; @@ -13560,7 +13560,7 @@ public void assignAMS() { // Let each APDS assign itself to an attack Set targetedAttacks = new HashSet<>(); - for (Mounted apds : apdsTargets.keySet()) { + for (WeaponMounted apds : apdsTargets.keySet()) { List potentialTargets = apdsTargets.get(apds); // Ensure we only target each attack once List targetsToRemove = new ArrayList<>(); @@ -13593,7 +13593,7 @@ public void assignAMS() { * @param vAttacks * List of missile attacks directed at e */ - private WeaponAttackAction manuallyAssignAPDSTarget(Mounted apds, + private WeaponAttackAction manuallyAssignAPDSTarget(WeaponMounted apds, List vAttacks) { Entity e = apds.getEntity(); if (e == null) { @@ -13680,7 +13680,7 @@ private void manuallyAssignAMSTarget(Entity e, // Current AMS targets: each attack can only be targeted once HashSet amsTargets = new HashSet<>(); // Pick assignment for each active AMS - for (Mounted ams : e.getActiveAMS()) { + for (WeaponMounted ams : e.getActiveAMS()) { // Skip APDS if (ams.isAPDS()) { continue; @@ -13745,22 +13745,22 @@ private void manuallyAssignAMSTarget(Entity e, * * @return */ - private Hashtable> getAPDSProtectedCoords() { + private Hashtable> getAPDSProtectedCoords() { // Get all of the coords that would be protected by APDS - Hashtable> apdsCoords = new Hashtable<>(); + Hashtable> apdsCoords = new Hashtable<>(); for (Entity e : game.getEntitiesVector()) { // Ignore Entities without positions if (e.getPosition() == null) { continue; } Coords origPos = e.getPosition(); - for (Mounted ams : e.getActiveAMS()) { + for (WeaponMounted ams : e.getActiveAMS()) { // Ignore non-APDS AMS if (!ams.isAPDS()) { continue; } // Add the current hex as a defended location - List apdsList = apdsCoords.computeIfAbsent(origPos, k -> new ArrayList<>()); + List apdsList = apdsCoords.computeIfAbsent(origPos, k -> new ArrayList<>()); apdsList.add(ams); // Add each coords that is within arc/range as protected int maxDist = 3; @@ -25156,7 +25156,7 @@ private Vector applyAeroCritical(Aero aero, int loc, CriticalSlot cs, in cf.setWingsHit(true); } } - for (Mounted weapon : cf.getWeaponList()) { + for (WeaponMounted weapon : cf.getWeaponList()) { if (weapon.getLocation() == loc) { if (destroyAll) { weapon.setHit(true); @@ -25166,7 +25166,7 @@ private Vector applyAeroCritical(Aero aero, int loc, CriticalSlot cs, in } } // also destroy any ECM or BAP in the location hit - for (Mounted misc : cf.getMisc()) { + for (MiscMounted misc : cf.getMisc()) { if ((misc.getType().hasFlag(MiscType.F_ECM) || misc.getType().hasFlag(MiscType.F_ANGEL_ECM) || misc.getType().hasFlag(MiscType.F_BAP)) @@ -25197,40 +25197,39 @@ private Vector applyAeroCritical(Aero aero, int loc, CriticalSlot cs, in } r = new Report(9150); r.subject = aero.getId(); - List weapons = new ArrayList<>(); + List> hittable = new ArrayList<>(); // Ignore internal bomb bay-mounted weapons - for (Mounted weapon : aero.getWeaponList()) { + for (WeaponMounted weapon : aero.getWeaponList()) { if ((weapon.getLocation() == loc) && !weapon.isDestroyed() && !weapon.isInternalBomb() && weapon.getType().isHittable()) { - weapons.add(weapon); + hittable.add(weapon); } } // add in hittable misc equipment; internal bay munitions are handled separately. - for (Mounted misc : aero.getMisc()) { + for (MiscMounted misc : aero.getMisc()) { if (misc.getType().isHittable() && (misc.getLocation() == loc) && !misc.isDestroyed() && !misc.isInternalBomb()) { - weapons.add(misc); + hittable.add(misc); } } - if (!weapons.isEmpty()) { - Mounted weapon = weapons.get(Compute.randomInt(weapons.size())); + if (!hittable.isEmpty()) { + Mounted equipmentHit = hittable.get(Compute.randomInt(hittable.size())); // possibly check for an ammo explosion // don't allow ammo explosions on fighter squadrons if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_STRATOPS_AMMO_EXPLOSIONS) && !(aero instanceof FighterSquadron) - && (weapon.getType() instanceof WeaponType)) { + && (equipmentHit.getType() instanceof WeaponType)) { //Bay Weapons - if (aero.usesWeaponBays()) { + if ((equipmentHit instanceof WeaponMounted) && aero.usesWeaponBays()) { //Finish reporting(9150) a hit on the bay - r.add(weapon.getName()); + r.add(equipmentHit.getName()); reports.add(r); //Pick a random weapon in the bay and get the stats - int wId = weapon.getBayWeapons().get(Compute.randomInt(weapon.getBayWeapons().size())); - Mounted bayW = aero.getEquipment(wId); - Mounted bayWAmmo = bayW.getLinked(); + WeaponMounted bayW = Compute.randomListElement(((WeaponMounted) equipmentHit).getBayWeapons()); + AmmoMounted bayWAmmo = bayW.getLinkedAmmo(); if (bayWAmmo != null && bayWAmmo.getType().isExplosive(bayWAmmo)) { r = new Report(9156); r.subject = aero.getId(); @@ -25269,33 +25268,30 @@ private Vector applyAeroCritical(Aero aero, int loc, CriticalSlot cs, in } } // Hit the weapon then also hit all the other weapons in the bay - weapon.setHit(true); - for (int next : weapon.getBayWeapons()) { - Mounted bayWeap = aero.getEquipment(next); - if (null != bayWeap) { - bayWeap.setHit(true); - // Taharqa : We should also damage the critical slot, or MM and - // MHQ won't remember that this weapon is damaged on the MUL file - for (int i = 0; i < aero.getNumberOfCriticals(loc); i++) { - CriticalSlot slot1 = aero.getCritical(loc, i); - if ((slot1 == null) || - (slot1.getType() == CriticalSlot.TYPE_SYSTEM)) { - continue; - } - Mounted mounted = slot1.getMount(); - if (mounted.equals(bayWeap)) { - aero.hitAllCriticals(loc, i); - break; - } + equipmentHit.setHit(true); + for (WeaponMounted bayWeap : ((WeaponMounted) equipmentHit).getBayWeapons()) { + bayWeap.setHit(true); + // Taharqa : We should also damage the critical slot, or MM and + // MHQ won't remember that this weapon is damaged on the MUL file + for (int i = 0; i < aero.getNumberOfCriticals(loc); i++) { + CriticalSlot slot1 = aero.getCritical(loc, i); + if ((slot1 == null) || + (slot1.getType() == CriticalSlot.TYPE_SYSTEM)) { + continue; + } + Mounted mounted = slot1.getMount(); + if (mounted.equals(bayWeap)) { + aero.hitAllCriticals(loc, i); + break; } } } break; } // does it use Ammo? - WeaponType wtype = (WeaponType) weapon.getType(); + WeaponType wtype = (WeaponType) equipmentHit.getType(); if (wtype.getAmmoType() != AmmoType.T_NA) { - Mounted m = weapon.getLinked(); + Mounted m = equipmentHit.getLinked(); int ammoroll = Compute.d6(2); if (ammoroll >= 10) { // A chance to reroll an explosion with edge @@ -25330,24 +25326,24 @@ private Vector applyAeroCritical(Aero aero, int loc, CriticalSlot cs, in // If the weapon is explosive, use edge to roll up a new one if (aero.getCrew().hasEdgeRemaining() && aero.getCrew().getOptions().booleanOption(OptionsConstants.EDGE_WHEN_AERO_EXPLOSION) - && (weapon.getType().isExplosive(weapon) && !weapon.isHit() - && !weapon.isDestroyed())) { + && (equipmentHit.getType().isExplosive(equipmentHit) && !equipmentHit.isHit() + && !equipmentHit.isDestroyed())) { aero.getCrew().decreaseEdge(); // Try something new for an interrupting report. r is still 9150. Report r1 = new Report(6530); r1.subject = aero.getId(); r1.add(aero.getCrew().getOptions().intOption(OptionsConstants.EDGE)); reports.add(r1); - weapon = weapons.get(Compute.randomInt(weapons.size())); + equipmentHit = hittable.get(Compute.randomInt(hittable.size())); } - r.add(weapon.getName()); + r.add(equipmentHit.getName()); reports.add(r); // explosive weapons e.g. gauss now explode - if (weapon.getType().isExplosive(weapon) && !weapon.isHit() - && !weapon.isDestroyed()) { - reports.addAll(explodeEquipment(aero, loc, weapon)); + if (equipmentHit.getType().isExplosive(equipmentHit) && !equipmentHit.isHit() + && !equipmentHit.isDestroyed()) { + reports.addAll(explodeEquipment(aero, loc, equipmentHit)); } - weapon.setHit(true); + equipmentHit.setHit(true); // Taharqa : We should also damage the critical slot, or MM and MHQ won't // remember that this weapon is damaged on the MUL file for (int i = 0; i < aero.getNumberOfCriticals(loc); i++) { @@ -25355,30 +25351,27 @@ private Vector applyAeroCritical(Aero aero, int loc, CriticalSlot cs, in if ((slot1 == null) || (slot1.getType() == CriticalSlot.TYPE_SYSTEM)) { continue; } - Mounted mounted = slot1.getMount(); - if (mounted.equals(weapon)) { + Mounted mounted = slot1.getMount(); + if (mounted.equals(equipmentHit)) { aero.hitAllCriticals(loc, i); break; } } // if this is a weapons bay then also hit all the other weapons - for (int wId : weapon.getBayWeapons()) { - Mounted bayWeap = aero.getEquipment(wId); - if (null != bayWeap) { - bayWeap.setHit(true); - // Taharqa : We should also damage the critical slot, or MM and MHQ - // won't remember that this weapon is damaged on the MUL file - for (int i = 0; i < aero.getNumberOfCriticals(loc); i++) { - CriticalSlot slot1 = aero.getCritical(loc, i); - if ((slot1 == null) - || (slot1.getType() == CriticalSlot.TYPE_SYSTEM)) { - continue; - } - Mounted mounted = slot1.getMount(); - if (mounted.equals(bayWeap)) { - aero.hitAllCriticals(loc, i); - break; - } + for (WeaponMounted bayWeap : ((WeaponMounted) equipmentHit).getBayWeapons()) { + bayWeap.setHit(true); + // Taharqa : We should also damage the critical slot, or MM and MHQ + // won't remember that this weapon is damaged on the MUL file + for (int i = 0; i < aero.getNumberOfCriticals(loc); i++) { + CriticalSlot slot1 = aero.getCritical(loc, i); + if ((slot1 == null) + || (slot1.getType() == CriticalSlot.TYPE_SYSTEM)) { + continue; + } + Mounted mounted = slot1.getMount(); + if (mounted.equals(bayWeap)) { + aero.hitAllCriticals(loc, i); + break; } } } diff --git a/megamek/unittests/megamek/common/MechFileParserTest.java b/megamek/unittests/megamek/common/MechFileParserTest.java index 56c47681114..34b9dd87141 100644 --- a/megamek/unittests/megamek/common/MechFileParserTest.java +++ b/megamek/unittests/megamek/common/MechFileParserTest.java @@ -18,6 +18,7 @@ */ package megamek.common; +import megamek.common.equipment.WeaponMounted; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -28,10 +29,10 @@ public class MechFileParserTest { @Test public void splitMGsBetweenMGAs() throws LocationFullException { Mech mech = new BipedMech(); - Mounted mga1 = mech.addEquipment(EquipmentType.get("ISMGA"), Mech.LOC_LT); + WeaponMounted mga1 = (WeaponMounted) mech.addEquipment(EquipmentType.get("ISMGA"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); - Mounted mga2 = mech.addEquipment(EquipmentType.get("ISMGA"), Mech.LOC_LT); + WeaponMounted mga2 = (WeaponMounted) mech.addEquipment(EquipmentType.get("ISMGA"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); @@ -45,12 +46,12 @@ public void splitMGsBetweenMGAs() throws LocationFullException { @Test public void loadMGAsFromContiguousBlocks() throws LocationFullException { Mech mech = new BipedMech(); - Mounted mga1 = mech.addEquipment(EquipmentType.get("ISLMGA"), Mech.LOC_LT); - Mounted mga2 = mech.addEquipment(EquipmentType.get("ISMGA"), Mech.LOC_LT); + WeaponMounted mga1 = (WeaponMounted) mech.addEquipment(EquipmentType.get("ISLMGA"), Mech.LOC_LT); + WeaponMounted mga2 = (WeaponMounted) mech.addEquipment(EquipmentType.get("ISMGA"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISLightMG"), Mech.LOC_LT); mech.addEquipment(EquipmentType.get("ISLightMG"), Mech.LOC_LT); - Mounted lastMG = mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); + WeaponMounted lastMG = (WeaponMounted) mech.addEquipment(EquipmentType.get("ISMG"), Mech.LOC_LT); MechFileParser.linkMGAs(mech); diff --git a/megamek/unittests/megamek/common/WeaponTypeTest.java b/megamek/unittests/megamek/common/WeaponTypeTest.java index 4f7b7a6acab..bd03b8419a1 100644 --- a/megamek/unittests/megamek/common/WeaponTypeTest.java +++ b/megamek/unittests/megamek/common/WeaponTypeTest.java @@ -70,7 +70,7 @@ private WeaponMounted setupBayWeapon(String name){ WeaponMounted weapon = new WeaponMounted(mockEntity, (WeaponType) etype); WeaponMounted bWeapon = new WeaponMounted(mockEntity, (WeaponType) weapon.getType().getBayType()); bWeapon.addWeaponToBay(mockEntity.getEquipmentNum(weapon)); - when(mockEntity.getEquipment(anyInt())).thenReturn((Mounted) weapon); + when(mockEntity.getWeapon(anyInt())).thenReturn(weapon); return bWeapon; } @@ -78,23 +78,23 @@ private WeaponMounted setupBayWeapon(String name){ @Test public void testWeaponBaysGetCorrectMaxRanges() { WeaponMounted ppcbay = setupBayWeapon("ISERPPC"); - WeaponType wtype = (WeaponType) ppcbay.getType(); + WeaponType wtype = ppcbay.getType(); assertEquals(RangeType.RANGE_LONG, wtype.getMaxRange(ppcbay)); WeaponMounted erplasbay = setupBayWeapon("CLERLargePulseLaser"); - wtype = (WeaponType) erplasbay.getType(); + wtype = erplasbay.getType(); assertEquals(RangeType.RANGE_LONG, wtype.getMaxRange(erplasbay )); WeaponMounted islplasbay = setupBayWeapon("ISLargePulseLaser"); - wtype = (WeaponType) islplasbay.getType(); + wtype = islplasbay.getType(); assertEquals(RangeType.RANGE_MEDIUM, wtype.getMaxRange(islplasbay)); WeaponMounted ersmlasbay = setupBayWeapon("CLERSmallLaser"); - wtype = (WeaponType) ersmlasbay.getType(); + wtype = ersmlasbay.getType(); assertEquals(RangeType.RANGE_SHORT, wtype.getMaxRange(ersmlasbay)); WeaponMounted islgaussbay = setupBayWeapon("ISLightGaussRifle"); - wtype = (WeaponType) islgaussbay .getType(); + wtype = islgaussbay .getType(); assertEquals(RangeType.RANGE_EXTREME, wtype.getMaxRange(islgaussbay )); } } \ No newline at end of file