diff --git a/megamek/data/mechfiles/infantry/Field Gunners/Clan Field Artillery (ArrowIV).blk b/megamek/data/mechfiles/infantry/Field Gunners/Clan Field Artillery (ArrowIV).blk index dfc9f4f1e84..031c6b55df6 100644 --- a/megamek/data/mechfiles/infantry/Field Gunners/Clan Field Artillery (ArrowIV).blk +++ b/megamek/data/mechfiles/infantry/Field Gunners/Clan Field Artillery (ArrowIV).blk @@ -27,8 +27,6 @@ Auto Rifle CLArrowIV CLArrowIV Ammo -CLArrowIV -CLArrowIV Ammo Clan Level 3 @@ -46,4 +44,4 @@ Intro date is based on when the weapon becomes an Advanced weapon. Since MM can' GenericKit - \ No newline at end of file + diff --git a/megamek/i18n/megamek/client/messages.properties b/megamek/i18n/megamek/client/messages.properties index fb5f8bad7a5..ef67faeabd7 100644 --- a/megamek/i18n/megamek/client/messages.properties +++ b/megamek/i18n/megamek/client/messages.properties @@ -3924,6 +3924,7 @@ WeaponAttackAction.LegBlockedByTerrain=Nearby terrain blocks leg weapons. WeaponAttackAction.MinimumAlt1=attacker must be at least at elevation 1 WeaponAttackAction.NoAeroDirectArty=Airborne aerospace units cannot make direct-fire artillery attacks. WeaponAttackAction.FlakOnGroundedAero=Grounded aerospace/vtol units are not valid Flak targets. +WeaponAttackAction.ADARangeBracket=ADA range brackets (+0/+2/+4) WeaponAttackAction.NoAttacker=Invalid Attacker! WeaponAttackAction.NoBombInMechMode=Cannot launch bomb in mech mode. WeaponAttackAction.NoFiringSolution=no firing solution to target. diff --git a/megamek/mmconf/serialkiller.xml b/megamek/mmconf/serialkiller.xml index b34d7294188..92147c4184c 100644 --- a/megamek/mmconf/serialkiller.xml +++ b/megamek/mmconf/serialkiller.xml @@ -10,6 +10,7 @@ \[C$ \[I$ + \[Ljava\.lang.Enum;$ java\.io\.File$ java\.lang\.Boolean$ java\.lang\.Enum$ @@ -31,6 +32,7 @@ java\.util\.concurrent\.locks\.ReentrantLock\$Sync$ java\.util\.UUID$ java\.util\.EnumMap$ + java\.util\.EnumSet.* java\.util\.HashMap$ java\.util\.HashSet$ java\.util\.Hashtable$ diff --git a/megamek/src/megamek/client/bot/BotClient.java b/megamek/src/megamek/client/bot/BotClient.java index efd54c9578e..e6e7d38a625 100644 --- a/megamek/src/megamek/client/bot/BotClient.java +++ b/megamek/src/megamek/client/bot/BotClient.java @@ -676,10 +676,10 @@ protected List getStartingCoordsArray(Entity deployed_ent) { if (atype.getAmmoType() == AmmoType.T_ATM) { weapon_count++; av_range += 15.0; - if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { av_range -= 6; } - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { av_range += 12.0; } } else if (atype.getAmmoType() == AmmoType.T_MML) { diff --git a/megamek/src/megamek/client/bot/princess/ArtilleryTargetingControl.java b/megamek/src/megamek/client/bot/princess/ArtilleryTargetingControl.java index e0f720bda8e..c78d2f23f27 100644 --- a/megamek/src/megamek/client/bot/princess/ArtilleryTargetingControl.java +++ b/megamek/src/megamek/client/bot/princess/ArtilleryTargetingControl.java @@ -1,27 +1,20 @@ -/* -* MegaMek - Copyright (C) 2018 - The MegaMek Team -* -* This program is free software; you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation; either version 2 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -* details. -*/ +/* +* MegaMek - Copyright (C) 2018 - The MegaMek Team +* +* This program is free software; you can redistribute it and/or modify it under +* the terms of the GNU General Public License as published by the Free Software +* Foundation; either version 2 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +* details. +*/ package megamek.client.bot.princess; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import megamek.common.*; import megamek.common.actions.ArtilleryAttackAction; @@ -37,31 +30,31 @@ public class ArtilleryTargetingControl { private static final int NO_AMMO = -1; // biggest known kaboom is the 120 cruise missile with a 4-hex radius, but it's not very common // and greatly increases the number of spaces we need to check - private static final int MAX_ARTILLERY_BLAST_RADIUS = 2; - + private static final int MAX_ARTILLERY_BLAST_RADIUS = 2; + // per TacOps, this is the to-hit modifier for indirect artillery attacks. private static final int ARTILLERY_ATTACK_MODIFIER = 7; - + // The main principle here isn't to try to anticipate enemy movement: that's unlikely, especially for faster or jump-capable units. // The main principle instead is to put down fire that a) may land on enemy units // b) is less likely to land on my units - + // Each potential hex is evaluated as follows: // (summed over all units within blast radius of hex) (1/unit run speed + 1) * odds of hitting hex * unit friendliness factor (1 for enemy, -1 for ally) // repeat and sum over all hexes within scatter pattern - + // this is a data structure that maps artillery damage value (which directly correlates with blast radius) // to a dictionary containing sets of coordinates and the damage value if one of those coordinates were hit by a shell // does not take into account hit odds or anything like that private Map> damageValues = new HashMap<>(); - + private Set targetSet; - + /** * Worker function that calculates the total damage that would be done if a shot with the given damage value * would hit the target coordinates. - * - * Caches computation results to avoid repeat + * + * Caches computation results to avoid repeat * @param damage * @param coords * @param shooter @@ -73,14 +66,14 @@ public double calculateDamageValue(int damage, Coords coords, Entity shooter, Ga if (getDamageValue(damage, coords) != null) { return getDamageValue(damage, coords); } - + // calculate blast radius = ceiling(damage / 10) - 1 - // for each hex in blast radius, value is + // for each hex in blast radius, value is // (damage - (distance from center * 10)) * [over all units] 1/(unit run MP + 1) * +/-1 (depending on if unit is friendly or not // it's not correct for cruise missiles, but I don't think the bot will be using those. - int blastRadius = (int) Math.ceil(damage / 10.0) - 1; + int blastRadius = (int) Math.ceil(damage / 10.0) - 1; double totalDamage = calculateDamageValueForHex(damage, coords, shooter, game, owner); - + // loop around each concentric hex centered on the given coords for (int distanceFromCenter = 1; distanceFromCenter <= blastRadius; distanceFromCenter++) { // the damage done is actual damage - 10 * # hexes from center @@ -90,15 +83,15 @@ public double calculateDamageValue(int damage, Coords coords, Entity shooter, Ga totalDamage += calculateDamageValueForHex(currentDamage, currentCoords, shooter, game, owner); } } - + cacheDamageValue(damage, coords, totalDamage); return totalDamage; } - + /** * Worker function that calculates the "damage value" of a single hex. - * The formula is (summed over all units in target hex) - * [incoming damage] * [1 / (unit run mp + 1)] * [-1 if friendly, +1 if enemy] + * The formula is (summed over all units in target hex) + * [incoming damage] * [1 / (unit run mp + 1)] * [-1 if friendly, +1 if enemy] * @param damage How much damage will we do * @param coords Coordinates to hit * @param shooter Entity doing the shooting @@ -106,38 +99,38 @@ public double calculateDamageValue(int damage, Coords coords, Entity shooter, Ga */ private double calculateDamageValueForHex(int damage, Coords coords, Entity shooter, Game game, Princess owner) { double value = 0; - + for (Entity entity : game.getEntitiesVector(coords, true)) { // ignore aircraft for now, and also transported entities if (entity.isAirborne() || entity.isAirborneVTOLorWIGE() || entity.getTransportId() != Entity.NONE) { continue; } - + int friendlyMultiplier = -1; - + // try to avoid shooting at friendlies // ignore routed enemies who haven't resumed fire if (entity.isEnemyOf(shooter)) { - boolean enemyUnitBroken = owner.getHonorUtil().isEnemyBroken(entity.getId(), - shooter.getOwnerId(), + boolean enemyUnitBroken = owner.getHonorUtil().isEnemyBroken(entity.getId(), + shooter.getOwnerId(), owner.getBehaviorSettings().isForcedWithdrawal()); - + boolean enemyDishonored = owner.getHonorUtil().isEnemyDishonored(entity.getOwnerId()); - + if (!enemyUnitBroken || enemyDishonored) { friendlyMultiplier = 1; } else { friendlyMultiplier = 0; } } - + double speedMultiplier = (double) 1 / (entity.getRunMP() + 1); value += damage * speedMultiplier * friendlyMultiplier; } - + return value; } - + /** * Cache a calculated damage value for the given damage/coordinates combo * @param damage @@ -148,10 +141,10 @@ private void cacheDamageValue(int damage, Coords coords, Double value) { if (!damageValues.containsKey(damage)) { damageValues.put(damage, new HashMap<>()); } - + damageValues.get(damage).put(coords, value); } - + /** * Retrieve a calculated damage value for the given damage/coords combo * @param damage @@ -162,10 +155,10 @@ private Double getDamageValue(int damage, Coords coords) { if (damageValues.containsKey(damage)) { return damageValues.get(damage).get(coords); } - + return null; } - + /** * Clears out all cached elements in preparation for a new targeting phase. */ @@ -173,7 +166,19 @@ public void initializeForTargetingPhase() { damageValues = new HashMap<>(); targetSet = null; } - + + private boolean getADAAvailable(Entity shooter){ + boolean available = false; + for (Mounted weapon: shooter.getWeaponList()){ + if(((AmmoType) weapon.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_ADA) + && !weapon.isFired() && weapon.getLinked().getUsableShotsLeft() > 0){ + available = true; + break; + } + } + + return available; + } /** * Builds a list of eligible targets for artillery strikes. * This includes hexes on and within the max radius of all non-airborne enemy entities @@ -184,10 +189,20 @@ public void initializeForTargetingPhase() { */ private void buildTargetList(Entity shooter, Game game, Princess owner) { targetSet = new HashSet<>(); - + boolean adaAvailable = getADAAvailable(shooter); + for (Iterator enemies = game.getAllEnemyEntities(shooter); enemies.hasNext();) { Entity e = enemies.next(); - + + // Given how accurate and long-ranged ADA missiles are, prioritize airborne targets if ADA is available + // Short-circuit Indirect fire artillery targeting to leave tubes available for ADA direct fire. + if(adaAvailable){ + if (e.isAirborne() || e.isAirborneVTOLorWIGE() || e.isAirborneAeroOnGroundMap()){ + // Forget about indirect fire for now. + targetSet = new HashSet<>(); + return; + } + } // skip airborne entities, and those off board - we'll handle them later and don't target ignored units if (!e.isAirborne() && !e.isAirborneVTOLorWIGE() @@ -195,38 +210,38 @@ private void buildTargetList(Entity shooter, Game game, Princess owner) { && !owner.getBehaviorSettings().getIgnoredUnitTargets().contains(e.getId())) { targetSet.add(new HexTarget(e.getPosition(), Targetable.TYPE_HEX_ARTILLERY)); - + // while we're here, consider shooting at hexes within "MAX_BLAST_RADIUS" - // of the entity. + // of the entity. addHexDonuts(e.getPosition(), targetSet, game); } } - + for (Entity enemy : game.getAllOffboardEnemyEntities(shooter.getOwner())) { if (enemy.isOffBoardObserved(shooter.getOwner().getTeam())) { targetSet.add(enemy); } } - + for (Coords coords : owner.getStrategicBuildingTargets()) { targetSet.add(new HexTarget(coords, Targetable.TYPE_HEX_ARTILLERY)); - + // while we're here, consider shooting at hexes within "MAX_BLAST_RADIUS" // of the strategic targets. addHexDonuts(coords, targetSet, game); } } - + /** * Adds on-board HexTargets within the MAX_ARTILLERY_BLAST_RADIUS of the given coordinates - * to the given HexTarget set. + * to the given HexTarget set. * @param coords Center coordinates * @param targetList List of target hexes * @param game The current {@link Game} */ private void addHexDonuts(Coords coords, Set targetList, Game game) { // while we're here, consider shooting at hexes within "MAX_BLAST_RADIUS" - // of the designated coordinates + // of the designated coordinates for (int radius = 1; radius <= MAX_ARTILLERY_BLAST_RADIUS; radius++) { for (Coords donutHex : coords.allAtDistance(radius)) { // don't bother adding off-board donuts. @@ -236,7 +251,7 @@ private void addHexDonuts(Coords coords, Set targetList, Game game) } } } - + /** * Calculate an indirect artillery "fire plan", taking into account the possibility of rotating the turret. * @param shooter Entity doing the shooting @@ -246,10 +261,10 @@ private void addHexDonuts(Coords coords, Set targetList, Game game) */ public FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Princess owner) { FiringPlan bestPlan = calculateIndirectArtilleryPlan(shooter, game, owner, 0); - + return bestPlan; } - + /** * Put together an indirect artillery "fire plan". * @param shooter Entity doing the shooting @@ -259,25 +274,25 @@ public FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Prin */ private FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Princess owner, int facingChange) { FiringPlan retval = new FiringPlan(); - + // if we're fleeing and haven't been shot at, then try not to agitate guys that may pursue us. if (owner.isFallingBack(shooter) && !owner.canShootWhileFallingBack(shooter)) { return retval; } - + // set the plan's torso twist/turret rotation - // also set the + // also set the // make sure to remember the entity's original rotation as we're manipulating it directly retval.setTwist(facingChange); int originalFacing = shooter.getSecondaryFacing(); shooter.setSecondaryFacing(FireControl.correctFacing(originalFacing + facingChange)); - + // if we haven't built a target list yet, do so now. // potential target list is the same regardless of the entity doing the shooting if (targetSet == null) { buildTargetList(shooter, game, owner); } - + // loop through all weapons on entity // each indirect artillery piece randomly picks a target from the priority list // by the end of this loop, we either have 0 max damage/0 top valued coordinates, which indicates there's nothing worth shooting at @@ -286,10 +301,10 @@ private FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Pri if (currentWeapon.getType().hasFlag(WeaponType.F_ARTILLERY)) { WeaponType wType = (WeaponType) currentWeapon.getType(); int damage = wType.getRackSize(); // crazy, but rack size appears to correspond to given damage values for arty pieces in tacops - + List topValuedFireInfos = new ArrayList<>(); double maxDamage = 0; - + // for each enemy unit, evaluate damage value of firing at its hex. // keep track of top target hexes with the same value and fire at them for (Targetable hexTarget : targetSet) { @@ -299,15 +314,15 @@ private FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Pri } else { damageValue = calculateDamageValue(damage, hexTarget.getPosition(), shooter, game, owner); } - + WeaponFireInfo wfi = new WeaponFireInfo(shooter, hexTarget, currentWeapon, game, false, owner); - + // factor the chance to hit when picking a target - if we've got a spotted hex or an auto-hit hex // we should prefer to hit that over something that may scatter to who knows where if (wfi.getProbabilityToHit() > 0) { damageValue *= wfi.getProbabilityToHit(); - + if (damageValue > maxDamage) { topValuedFireInfos.clear(); maxDamage = damageValue; @@ -317,7 +332,7 @@ private FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Pri } } } - + // this section is long and obnoxious: // Pick a random fire info out of the ones with the top damage level // Use that to create an artillery attack action, set the action's ammo @@ -341,19 +356,19 @@ private FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Pri } } else if (currentWeapon.getType().hasFlag(WeaponType.F_TAG)) { WeaponFireInfo tagInfo = getTAGInfo(currentWeapon, shooter, game, owner); - + if (tagInfo != null) { retval.add(tagInfo); retval.setUtility(retval.getUtility() + tagInfo.getProbabilityToHit()); } } } - + shooter.setSecondaryFacing(originalFacing); - + return retval; } - + /** * Worker function that calculates the shooter's "best" actions that result in a TAG being fired. * @param shooter @@ -364,7 +379,7 @@ private FiringPlan calculateIndirectArtilleryPlan(Entity shooter, Game game, Pri private WeaponFireInfo getTAGInfo(Mounted weapon, Entity shooter, Game game, Princess owner) { WeaponFireInfo retval = null; double hitOdds = 0.0; - + // pretty simple logic here: take the best shot that you have for (Targetable target : FireControl.getAllTargetableEnemyEntities(owner.getLocalPlayer(), game, owner.getFireControlState())) { WeaponFireInfo wfi = new WeaponFireInfo(shooter, target, weapon, game, false, owner); @@ -373,15 +388,15 @@ private WeaponFireInfo getTAGInfo(Mounted weapon, Entity shooter, Game game, Pri retval = wfi; } } - + return retval; } private static class HelperAmmo { public int equipmentNum; - public long munitionType; + public EnumSet munitionType = EnumSet.noneOf(AmmoType.Munitions.class); - public HelperAmmo(int equipmentNum, long munitionType) { + public HelperAmmo(int equipmentNum, EnumSet munitionType) { this.equipmentNum = equipmentNum; this.munitionType = munitionType; } @@ -395,38 +410,38 @@ public HelperAmmo(int equipmentNum, long munitionType) { */ private HelperAmmo findAmmo(Entity shooter, Mounted currentWeapon) { int ammoEquipmentNum = NO_AMMO; - long ammoMunitionType = -1; - + EnumSet ammoMunitionType = EnumSet.noneOf(AmmoType.Munitions.class); + // simply grab the first valid ammo and let 'er rip. for (Mounted ammo : shooter.getAmmo()) { if (!ammo.isAmmoUsable() || !AmmoType.isAmmoValid(ammo, (WeaponType) currentWeapon.getType())) { continue; } - + ammoEquipmentNum = shooter.getEquipmentNum(ammo); ammoMunitionType = ((AmmoType) ammo.getType()).getMunitionType(); break; - - // TODO: Attempt to select homing ammo if the target is tagged. - // To do so, check ammoType.getMunitionType() == AmmoType.M_HOMING + + // TODO: Attempt to select homing ammo if the target is tagged. + // To do so, check ammoType.getMunitionType().contains(AmmoType.Munitions.M_HOMING } - + return new HelperAmmo(ammoEquipmentNum, ammoMunitionType); } /** * Function that calculates the potential damage if an artillery attack - * were to land on target. + * were to land on target. * @param coords * @param operator * @return */ public static double evaluateIncomingArtilleryDamage(Coords coords, Princess operator) { double sum = 0; - + for (Enumeration attackEnum = operator.getGame().getArtilleryAttacks(); attackEnum.hasMoreElements();) { ArtilleryAttackAction aaa = attackEnum.nextElement(); - + // calculate damage: damage - (10 * distance to me), floored at 0 // we only say that it will actually be damage if the attack coming in is landing right after the movement phase double actualDamage = 0.0; @@ -435,18 +450,18 @@ public static double evaluateIncomingArtilleryDamage(Coords coords, Princess ope // damage for artillery weapons is, for some reason, derived from the weapon type's rack size Mounted weapon = aaa.getEntity(operator.getGame()).getEquipment(aaa.getWeaponId()); int damage = ((WeaponType) weapon.getType()).getRackSize(); - + // distance from given coordinates reduces damage Coords attackDestination = aaa.getTarget(operator.getGame()).getPosition(); int distance = coords.distance(attackDestination); - + // calculate odds of attack actually hitting // artillery skill may be gunnery or artillery depending on game options int artySkill = aaa.getEntity(operator.getGame()).getCrew().getGunnery(); if (operator.getGame().getOptions().booleanOption(OptionsConstants.RPG_ARTILLERY_SKILL)) { artySkill = aaa.getEntity(operator.getGame()).getCrew().getArtillery(); } - + double hitOdds = 0.0; if (operator.getArtilleryAutoHit() != null && operator.getArtilleryAutoHit().contains(coords)) { @@ -454,13 +469,13 @@ public static double evaluateIncomingArtilleryDamage(Coords coords, Princess ope } else { hitOdds = Compute.oddsAbove(artySkill + ARTILLERY_ATTACK_MODIFIER); } - + actualDamage = Math.max(damage - (10 * distance), 0) * hitOdds; } - + sum += actualDamage; } - + return sum; } } diff --git a/megamek/src/megamek/client/bot/princess/FireControl.java b/megamek/src/megamek/client/bot/princess/FireControl.java index 30c268d155c..1a25ec3c0c4 100644 --- a/megamek/src/megamek/client/bot/princess/FireControl.java +++ b/megamek/src/megamek/client/bot/princess/FireControl.java @@ -111,6 +111,8 @@ public class FireControl { static final TargetRollModifier TH_WEAP_PRONE_ARMLESS = new TargetRollModifier(TargetRoll.IMPOSSIBLE, "prone and missing an arm"); static final TargetRollModifier TH_WEAP_ARM_PROP = new TargetRollModifier(TargetRoll.IMPOSSIBLE, "using arm as prop"); static final TargetRollModifier TH_WEAP_PRONE_LEG = new TargetRollModifier(TargetRoll.IMPOSSIBLE, "prone leg weapon"); + static final TargetRollModifier TH_WEAP_ADA = new TargetRollModifier(-2, "Air-Defense Arrow IV vs airborne target"); + static final TargetRollModifier TH_WEAP_FLAK = new TargetRollModifier(-1, "Flak vs airborne target"); static final TargetRollModifier TH_WEAPON_NO_ARC = new TargetRollModifier(TargetRoll.IMPOSSIBLE, "not in arc"); static final TargetRollModifier TH_INF_ZERO_RNG = new TargetRollModifier(TargetRoll.AUTOMATIC_FAIL, "non-infantry shooting with zero range"); static final TargetRollModifier TH_STOP_SWARM_INVALID = new TargetRollModifier(TargetRoll.IMPOSSIBLE, "not swarming a Mek"); @@ -144,11 +146,11 @@ public class FireControl { * If you're adding a new one, add it here then make sure to add it to Princess.InitializeFireControls */ public enum FireControlType { - Basic, + Basic, Infantry, MultiTarget } - + protected final Princess owner; /** @@ -177,7 +179,7 @@ protected ToHitData getAttackerMovementModifier(final Game game, } /** - * Returns the {@link Coords} computed by + * Returns the {@link Coords} computed by * {@link Compute#getClosestFlightPath(int, Coords, Entity)}. * * @param shooterPosition The shooter's position. @@ -836,8 +838,37 @@ ToHitData guessToHitModifierForWeapon(final Entity shooter, && (null != weapon.getLinked()) && (weapon.getLinked().getType() instanceof AmmoType)) { final AmmoType ammoType = (AmmoType) weapon.getLinked().getType(); - if ((null != ammoType) && (0 != ammoType.getToHitModifier())) { - toHit.addModifier(ammoType.getToHitModifier(), TH_AMMO_MOD); + if (null != ammoType){ + // Set of munitions we'll consider for Flak targeting + EnumSet aaMunitions = EnumSet.of( + AmmoType.Munitions.M_CLUSTER, + AmmoType.Munitions.M_FLAK + ); + EnumSet ArtyOnlyMunitions = EnumSet.of( + AmmoType.Munitions.M_FLECHETTE, + AmmoType.Munitions.M_FAE + ); + if (0 != ammoType.getToHitModifier()) { + toHit.addModifier(ammoType.getToHitModifier(), TH_AMMO_MOD); + } + // Air-defense Arrow IV handling; can only fire at airborne targets + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_ADA)){ + if(target.isAirborne() || target.isAirborneVTOLorWIGE()){ + toHit.addModifier(TH_WEAP_ADA); + } + else{ + toHit.addModifier(TH_WEAP_CANNOT_FIRE); + } + } + // Handle cluster, flak, AAA vs Airborne, Arty-only vs Airborne + if (target.isAirborne() || target.isAirborneVTOLorWIGE()){ + if (ammoType.getMunitionType().stream().anyMatch(aaMunitions::contains) + || ammoType.countsAsFlak()){ + toHit.addModifier(TH_WEAP_FLAK); + } else if (ammoType.getMunitionType().stream().anyMatch(ArtyOnlyMunitions::contains)){ + toHit.addModifier(TH_WEAP_CANNOT_FIRE); + } + } } } @@ -1227,12 +1258,12 @@ protected double calcCommandUtility(final Targetable target) { protected boolean isCommander(final Entity entity) { if (owner.getFireControlState().commanderCached(entity)) { return owner.getFireControlState().isCommander(entity); - } + } - owner.getFireControlState().setCommander(entity, + owner.getFireControlState().setCommander(entity, entity.isCommander() || entity.hasC3M() || entity.hasC3i() || entity.hasC3MM() || (owner.getHighestEnemyInitiativeId() == entity.getId())); - + return owner.getFireControlState().isCommander(entity); } @@ -1242,12 +1273,12 @@ protected boolean isSubCommander(final Entity entity) { } final int initBonus = entity.getHQIniBonus() + entity.getQuirkIniBonus(); - owner.getFireControlState().setSubCommander(entity, + owner.getFireControlState().setSubCommander(entity, entity.hasC3() || entity.hasTAG() || entity.hasBoostedC3() || entity.hasNovaCEWS() || entity.isUsingSearchlight() || entity.hasBAP() || entity.hasActiveECM() || entity.hasActiveECCM() || entity.hasQuirk(OptionsConstants.QUIRK_POS_IMPROVED_SENSORS) || entity.hasEiCockpit() || (0 < initBonus)); - + return owner.getFireControlState().isSubCommander(entity); } @@ -1277,7 +1308,7 @@ protected boolean isSubCommander(final Entity entity) { // Do not shoot at units we already expect to deal more than their total HP of damage to! if (1.0 <= previousDamageFraction) { - return 100; + return 100; // In cases that are not generally overkill (less than 50% of the target's total HP in // damage), target as normal (don't want to spread damage in these cases). @@ -1328,7 +1359,7 @@ protected double calcTargetPotentialDamageMultiplier(final Targetable target) { final double preservation_scaling_factor = max_self_preservation / self_preservation; // Because the variance in log value for large numbers is smaller, we need to make a big self-preservation value become a small multiplicative factor, and vice versa. return Math.log10(TARGET_POTENTIAL_DAMAGE_UTILITY * preservation_scaling_factor * target_damage + 10); // Add 10 to make the multiplier scale from 1 upwards(1 being a target that does 0 damage)). } - + /** * calculates the 'utility' of a physical action. * @@ -1410,7 +1441,7 @@ WeaponFireInfo buildWeaponFireInfo(final Entity shooter, return new WeaponFireInfo(shooter, flightPath, target, targetState, weapon, game, assumeUnderFlightPath, guessToHit, owner, new int[0]); } - + /** * Creates a new {@link WeaponFireInfo} object containing data about firing the given weapon at the given target. * @@ -1521,18 +1552,18 @@ FiringPlan guessFullFiringPlan(final Entity shooter, // Rank how useful this plan is. calculateUtility(myPlan, calcHeatTolerance(shooter, null), shooterState.isAero()); - + // if we're in a position to drop bombs because we're an aircraft on a ground map, then // the "alpha strike" may be a bombing plan. if (shooter.isAirborneAeroOnGroundMap()) { final FiringPlan bombingPlan = this.getDiveBombPlan(shooter, null, target, game, shooter.passedOver(target), true); calculateUtility(bombingPlan, Entity.DOES_NOT_TRACK_HEAT, true); // bomb drops never cause heat - + if (bombingPlan.getUtility() > myPlan.getUtility()) { return bombingPlan; } } - + return myPlan; } @@ -1576,7 +1607,7 @@ FiringPlan guessFullAirToGroundPlan(final Entity shooter, LogManager.getLogger().error("Target's position is NULL/Off Board!"); return myPlan; } - + // if we have no bombs on board, we can't attack from down here if (AeroGroundPathFinder.NAP_OF_THE_EARTH >= flightPath.getFinalAltitude() && shooter.getBombs(BombType.F_GROUND_BOMB).isEmpty()) { @@ -1612,21 +1643,21 @@ FiringPlan guessFullAirToGroundPlan(final Entity shooter, myPlan.add(shoot); } } - + // if we are here, we have already confirmed the target is under the flight path and are guessing final FiringPlan bombPlan = getDiveBombPlan(shooter, flightPath, target, game, true, true); calculateUtility(bombPlan, Entity.DOES_NOT_TRACK_HEAT, shooter.isAero()); // bombs don't generate heat so don't bother with this calculation - + // Rank how useful this plan is. calculateUtility(myPlan, calcHeatTolerance(shooter, null), shooter.isAero()); - + if (myPlan.getUtility() >= bombPlan.getUtility()) { return myPlan; } else { return bombPlan; } } - + /** * Creates a firing plan that fires dive bombs, dropping all bombs on the given target * @@ -1635,7 +1666,7 @@ FiringPlan guessFullAirToGroundPlan(final Entity shooter, * @param game The current {@link Game} * @param passedOverTarget Set TRUE to automatically assume the target will be under the flight path rather * than going through the full calculation. - * @param guess Whether we're just thinking about this firing plan or about to + * @param guess Whether we're just thinking about this firing plan or about to * @return The {@link FiringPlan} containing all bombs on target, if the shooter is capable of dropping bombs. */ private FiringPlan getDiveBombPlan(final Entity shooter, @@ -1645,7 +1676,7 @@ private FiringPlan getDiveBombPlan(final Entity shooter, final boolean passedOverTarget, final boolean guess) { final FiringPlan diveBombPlan = new FiringPlan(target); - final HexTarget hexToBomb = new HexTarget(target.getPosition(), + final HexTarget hexToBomb = new HexTarget(target.getPosition(), shooter.isAero() ? Targetable.TYPE_HEX_AERO_BOMB : Targetable.TYPE_HEX_BOMB); // things that cause us to avoid calculating a bomb plan: @@ -1654,7 +1685,7 @@ private FiringPlan getDiveBombPlan(final Entity shooter, if (null == weaponIter) { return diveBombPlan; } - + // not having any bombs (due to expenditure/damage) if (shooter.getBombs(BombType.F_GROUND_BOMB).isEmpty()) { return diveBombPlan; @@ -1682,7 +1713,7 @@ private FiringPlan getDiveBombPlan(final Entity shooter, diveBombPlan.add(diveBomb); } } - + return diveBombPlan; } @@ -1724,18 +1755,18 @@ FiringPlan getFullFiringPlan(final Entity shooter, final double toHitThreshold = ammoConservation.get(weapon); WeaponFireInfo shoot = buildWeaponFireInfo(shooter, target, weapon, game, false); - + // if we're below the threshold, try switching missile modes if (shoot.getProbabilityToHit() <= toHitThreshold) { - + int updatedMissileMode = switchMissileMode(weapon); - + if (updatedMissileMode > -1) { shoot = buildWeaponFireInfo(shooter, target, weapon, game, false); shoot.setUpdatedFiringMode(updatedMissileMode); } } - + if ((shoot.getProbabilityToHit() > toHitThreshold)) { myPlan.add(shoot); continue; @@ -1748,21 +1779,21 @@ FiringPlan getFullFiringPlan(final Entity shooter, // Rank how useful this plan is. calculateUtility(myPlan, calcHeatTolerance(shooter, null), shooter.isAero()); - + if (shooter.isAero()) { final FiringPlan bombingPlan = this.getDiveBombPlan(shooter, null, target, game, shooter.passedOver(target), false); calculateUtility(bombingPlan, Entity.DOES_NOT_TRACK_HEAT, true); // bomb drops never cause heat - + // if the bombing plan actually involves doing something if (!bombingPlan.isEmpty() && (bombingPlan.getUtility() > myPlan.getUtility())) { return bombingPlan; } } - + return myPlan; } - + protected int calcHeatTolerance(final Entity entity, @Nullable Boolean isAero) { @@ -1777,7 +1808,7 @@ protected int calcHeatTolerance(final Entity entity, if (entity.hasQuirk(OptionsConstants.QUIRK_POS_COMBAT_COMPUTER)) { baseTolerance += 4; } - + if (null == isAero) { isAero = entity.isAero(); } @@ -1786,7 +1817,7 @@ protected int calcHeatTolerance(final Entity entity, if (isAero) { return baseTolerance; } - + return baseTolerance + 5; // todo add Heat Tolerance to Behavior Settings. } @@ -1859,10 +1890,10 @@ FiringPlan[] calcFiringPlansUnderHeat(final Entity shooter, } } calculateUtility(bestPlans[0], heatTolerance, isAero); - + if (shooter instanceof Infantry) { calculateUtility(swarmAttack, heatTolerance, isAero); - calculateUtility(legAttack, heatTolerance, isAero); + calculateUtility(legAttack, heatTolerance, isAero); calculateUtility(fieldGuns, heatTolerance, isAero); // Add these plans to the end of the list. bestPlans[maxHeat + 1] = swarmAttack; @@ -1899,7 +1930,7 @@ FiringPlan[] calcFiringPlansUnderHeat(final Entity shooter, } } } - + // if we are an aero blasting away at ground targets, another good option for a heatless plan is to bomb the crap out of the enemy // bombs cannot be mixed with other attack types, so we calculate it separately and overwrite the 0-heat plan if it's better // currently, this will probably result in the aero blowing its bomb load as soon as it passes over an enemy @@ -1907,20 +1938,20 @@ FiringPlan[] calcFiringPlansUnderHeat(final Entity shooter, if (shooter.isAirborne() && !shooter.getBombs(BombType.F_GROUND_BOMB).isEmpty()) { final FiringPlan diveBombPlan = this.getDiveBombPlan(shooter, null, target, shooter.getGame(), shooter.passedOver(target), false); - + calculateUtility(diveBombPlan, Entity.DOES_NOT_TRACK_HEAT, true); if (diveBombPlan.getUtility() > bestPlans[0].getUtility()) { bestPlans[0] = diveBombPlan; } } - + return bestPlans; } /** * Gets the 'best' firing plan, using heat as a disutility. No twisting is * done - * + * * @param shooter The unit doing the shooting. * @param target The unit being shot at. * @param game The current {@link Game} @@ -1934,7 +1965,7 @@ FiringPlan getBestFiringPlan(final Entity shooter, // Start with an alpha strike. FiringPlan alphaStrike = getFullFiringPlan(shooter, target, ammoConservation, game); - + if (shooter.canFlipArms()) { shooter.setArmsFlipped(true, false); FiringPlan betaStrike = getFullFiringPlan(shooter, target, ammoConservation, game); @@ -1942,15 +1973,15 @@ FiringPlan getBestFiringPlan(final Entity shooter, if (betaStrike.getUtility() > alphaStrike.getUtility()) { alphaStrike = betaStrike; } - + shooter.setArmsFlipped(false, false); } - + // Although they don't track heat, infantry/BA do need to make tradeoffs // between firing different weapons, because swarm/leg attacks are // mutually exclusive with normal firing, so we treat them similarly to // heat-tracking units. - + // conventional fighters can drop bombs if (Entity.DOES_NOT_TRACK_HEAT == shooter.getHeatCapacity() && ((shooter.getEntityType() & Entity.ETYPE_INFANTRY) == 0)) { @@ -1995,7 +2026,7 @@ protected FiringPlan guessBestFiringPlanUnderHeat(final Entity shooter, // Start with an alpha strike. If it falls under our heat limit, use it. FiringPlan alphaStrike = guessFullFiringPlan(shooter, shooterState, target, targetState, game); - + if (shooter.canFlipArms()) { shooter.setArmsFlipped(true, false); FiringPlan betaStrike = guessFullFiringPlan(shooter, shooterState, @@ -2004,10 +2035,10 @@ protected FiringPlan guessBestFiringPlanUnderHeat(final Entity shooter, if (betaStrike.getUtility() > alphaStrike.getUtility()) { alphaStrike = betaStrike; } - + shooter.setArmsFlipped(false, false); } - + // Infantry and BA may have alternative options, so we need to consider // different firing options. if (alphaStrike.getHeat() <= maxHeat && !(shooter instanceof Infantry)) { @@ -2018,7 +2049,7 @@ protected FiringPlan guessBestFiringPlanUnderHeat(final Entity shooter, // Now emulates the logic from getBestFiringPlanUnderHeat, rather than sorting the firing plans low to high then picking the lowest one final FiringPlan[] heatPlans = calcFiringPlansUnderHeat(shooter, alphaStrike); FiringPlan bestPlan = new FiringPlan(target); - + for (final FiringPlan firingPlan : heatPlans) { if ((bestPlan.getUtility() < firingPlan.getUtility())) { bestPlan = firingPlan; @@ -2062,7 +2093,7 @@ FiringPlan determineBestFiringPlan(final FiringPlanCalculationParameters params) // Get the best plan without any twists. FiringPlan noTwistPlan = null; - + switch (params.getCalculationType()) { case GET: noTwistPlan = getBestFiringPlan(shooter, target, owner.getGame(), ammoConservation); @@ -2076,7 +2107,7 @@ FiringPlan determineBestFiringPlan(final FiringPlanCalculationParameters params) owner.getGame()); break; } - + // If we can't change facing, we're done. if (!params.getShooter().canChangeSecondaryFacing()) { return noTwistPlan; @@ -2086,8 +2117,8 @@ FiringPlan determineBestFiringPlan(final FiringPlanCalculationParameters params) final int originalFacing = shooter.getSecondaryFacing(); final List validFacingChanges = getValidFacingChanges(shooter); - - // Now, we loop through all possible facings. If one facing produces a better plan + + // Now, we loop through all possible facings. If one facing produces a better plan // than what we currently have as the best plan then use that. Start with "no twist" as default. FiringPlan bestFiringPlan = noTwistPlan; for (final int currentTwist : validFacingChanges) { @@ -2140,11 +2171,11 @@ public boolean entityCanIndirectFireMissile(FireControlState fireControlState, E return true; } } - + fireControlState.getEntityIDFStates().put(shooter.getId(), false); return false; } - + /** * Determines if the given entity (potentially employing a given firing plan) * can/should spot. If yes, then return a spot action. @@ -2182,7 +2213,7 @@ public SpotAction getSpotAction(FiringPlan plan, Entity spotter, FireControlStat } LosEffects effects = LosEffects.calculateLOS(spotter.getGame(), spotter, target); - + // if we're in LOS if (effects.canSee()) { int targetDistance = spotter.getPosition().distance(target.getPosition()); @@ -2205,7 +2236,7 @@ public SpotAction getSpotAction(FiringPlan plan, Entity spotter, FireControlStat return null; } - + /** * Gets all the entities that are potential targets * @@ -2219,14 +2250,14 @@ protected List getTargetableEnemyEntities(final Entity shooter, final List targetableEnemyList = new ArrayList<>(); boolean shooterHasIDF = entityCanIndirectFireMissile(fireControlState, shooter); - - // Go through every enemy unit + + // Go through every enemy unit for (final Entity entity : owner.getEnemyEntities()) { // If they are my enemy and we can either see them or have IDF capability if (entity.isTargetable()) { final LosEffects effects = LosEffects.calculateLOS(game, shooter, entity); - + // if we're in LOS or we have IDF capability if (effects.canSee() || shooterHasIDF) { targetableEnemyList.add(entity); @@ -2293,7 +2324,7 @@ FiringPlan getBestFiringPlan(final Entity shooter, LogManager.getLogger().info(enemy.getDisplayName() + " is being explicitly ignored"); continue; } - + final boolean priorityTarget = owner.getPriorityUnitTargets().contains(enemy.getId()); // Skip retreating enemies so long as they haven't fired on me while retreating. @@ -2316,7 +2347,7 @@ FiringPlan getBestFiringPlan(final Entity shooter, bestPlan = plan; } } - + // Return the best overall plan. return bestPlan; } @@ -2347,17 +2378,17 @@ public static double getMaxDamageAtRange(final Entity shooter, if (weapon.isCrippled()) { continue; } - + int weaponDamage = weaponType.getDamage(); - + // just a ball park estimate of missile and/or other cluster damage // only a little over half of a cluster will generally hit // but some cluster munitions do more than 1 point of damage per individual hit // still better than just discounting them completely. - if (weaponDamage == WeaponType.DAMAGE_BY_CLUSTERTABLE) { + if (weaponDamage == WeaponType.DAMAGE_BY_CLUSTERTABLE || weaponType.hasFlag(WeaponType.F_ARTILLERY)) { weaponDamage = weaponType.getRackSize(); } - + if ((RangeType.RANGE_OUT != bracket) && (0 < weaponDamage)) { maxDamage += weaponDamage; } @@ -2393,7 +2424,7 @@ void loadAmmo(final Entity shooter, if (null == plan) { return; } - + // Loading ammo for all my weapons. for (final WeaponFireInfo info : plan) { final Mounted currentWeapon = info.getWeapon(); @@ -2437,7 +2468,7 @@ Mounted getClusterAmmo(final List ammoList, for (final Mounted ammo : ammoList) { final AmmoType ammoType = (AmmoType) ammo.getType(); - if (AmmoType.M_CLUSTER == ammoType.getMunitionType()) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { // MMLs have additional considerations. // There are no "cluster" missile munitions at this point in time. Code is included in case // they are added to the game at some later date. @@ -2537,7 +2568,7 @@ Mounted getPreferredAmmo(final Entity shooter, // Entity targets. } else if (null != targetEntity) { // Airborne targets - if (targetEntity.isAirborne() || (targetEntity instanceof VTOL)) { + if (targetEntity.isAirborne() || (targetEntity.isAirborneVTOLorWIGE())) { msg.append("\n\tTarget is airborne... "); preferredAmmo = getAntiAirAmmo(validAmmo, weaponType, range); if (null != preferredAmmo) { @@ -2657,13 +2688,13 @@ Mounted getAtmAmmo(final List ammoList, Mounted infernoAmmo = null; for (final Mounted ammo : ammoList) { final AmmoType type = (AmmoType) ammo.getType(); - if ((null == heAmmo) && (AmmoType.M_HIGH_EXPLOSIVE == type.getMunitionType())) { + if ((null == heAmmo) && (type.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE))) { heAmmo = ammo; - } else if ((null == erAmmo) && (AmmoType.M_EXTENDED_RANGE == type.getMunitionType())) { + } else if ((null == erAmmo) && (type.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE))) { erAmmo = ammo; - } else if ((null == stAmmo) && (AmmoType.M_STANDARD == type.getMunitionType())) { + } else if ((null == stAmmo) && (type.getMunitionType().contains(AmmoType.Munitions.M_STANDARD))) { stAmmo = ammo; - } else if ((null == infernoAmmo) && (AmmoType.M_IATM_IIW == type.getMunitionType())) { + } else if ((null == infernoAmmo) && (type.getMunitionType().contains(AmmoType.Munitions.M_IATM_IIW))) { infernoAmmo = ammo; } else if ((null != heAmmo) && (null != erAmmo) && (null != stAmmo) && (null != infernoAmmo)) { break; @@ -2733,9 +2764,9 @@ Mounted getAntiVeeAmmo(final List ammoList, for (final Mounted ammo : ammoList) { final AmmoType ammoType = (AmmoType) ammo.getType(); - if (AmmoType.M_CLUSTER == ammoType.getMunitionType() - || (AmmoType.M_INFERNO == ammoType.getMunitionType() && !fireResistant) - || (AmmoType.M_INFERNO_IV == ammoType.getMunitionType() && !fireResistant)) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER) + || (ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO) && !fireResistant) + || (ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO_IV) && !fireResistant)) { // MMLs have additional considerations. if (!(weaponType instanceof MMLWeapon)) { @@ -2775,11 +2806,11 @@ Mounted getAntiInfantryAmmo(final List ammoList, for (final Mounted ammo : ammoList) { final AmmoType ammoType = (AmmoType) ammo.getType(); - if (AmmoType.M_FLECHETTE == ammoType.getMunitionType() - || AmmoType.M_FRAGMENTATION == ammoType.getMunitionType() - || AmmoType.M_CLUSTER == ammoType.getMunitionType() - || AmmoType.M_INFERNO == ammoType.getMunitionType() - || AmmoType.M_INFERNO_IV == ammoType.getMunitionType()) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_FLECHETTE) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_FRAGMENTATION) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO_IV)) { // MMLs have additional considerations. if (!(weaponType instanceof MMLWeapon)) { @@ -2819,8 +2850,8 @@ private Mounted getHeatAmmo(final List ammoList, for (final Mounted ammo : ammoList) { final AmmoType ammoType = (AmmoType) ammo.getType(); - if (AmmoType.M_INFERNO == ammoType.getMunitionType() - || AmmoType.M_INFERNO_IV == ammoType.getMunitionType()) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO_IV)) { // MMLs have additional considerations. if (!(weaponType instanceof MMLWeapon)) { @@ -2860,11 +2891,11 @@ Mounted getIncendiaryAmmo(final List ammoList, for (final Mounted ammo : ammoList) { final AmmoType ammoType = (AmmoType) ammo.getType(); - if (AmmoType.M_INCENDIARY == ammoType.getMunitionType() - || AmmoType.M_INCENDIARY_LRM == ammoType.getMunitionType() - || AmmoType.M_INCENDIARY_AC == ammoType.getMunitionType() - || AmmoType.M_INFERNO == ammoType.getMunitionType() - || AmmoType.M_INFERNO_IV == ammoType.getMunitionType()) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY_LRM) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY_AC) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO_IV)) { // MMLs have additional considerations. if (!(weaponType instanceof MMLWeapon)) { @@ -2904,38 +2935,38 @@ Mounted getHardTargetAmmo(final List ammoList, for (final Mounted ammo : ammoList) { final AmmoType ammoType = (AmmoType) ammo.getType(); - if (AmmoType.M_CLUSTER == ammoType.getMunitionType() - || AmmoType.M_ANTI_FLAME_FOAM == ammoType.getMunitionType() - || AmmoType.M_CHAFF == ammoType.getMunitionType() - || AmmoType.M_COOLANT == ammoType.getMunitionType() - || AmmoType.M_ECM == ammoType.getMunitionType() - || AmmoType.M_FASCAM == ammoType.getMunitionType() - || AmmoType.M_FLAK == ammoType.getMunitionType() - || AmmoType.M_FLARE == ammoType.getMunitionType() - || AmmoType.M_FLECHETTE == ammoType.getMunitionType() - || AmmoType.M_FRAGMENTATION == ammoType.getMunitionType() - || AmmoType.M_HAYWIRE == ammoType.getMunitionType() - || AmmoType.M_INCENDIARY == ammoType.getMunitionType() - || AmmoType.M_INCENDIARY_AC == ammoType.getMunitionType() - || AmmoType.M_INCENDIARY_LRM == ammoType.getMunitionType() - || AmmoType.M_INFERNO == ammoType.getMunitionType() - || AmmoType.M_INFERNO_IV == ammoType.getMunitionType() - || AmmoType.M_LASER_INHIB == ammoType.getMunitionType() - || AmmoType.M_OIL_SLICK == ammoType.getMunitionType() - || AmmoType.M_NEMESIS == ammoType.getMunitionType() - || AmmoType.M_PAINT_OBSCURANT == ammoType.getMunitionType() - || AmmoType.M_SMOKE == ammoType.getMunitionType() - || AmmoType.M_SMOKE_WARHEAD == ammoType.getMunitionType() - || AmmoType.M_THUNDER == ammoType.getMunitionType() - || AmmoType.M_THUNDER_ACTIVE == ammoType.getMunitionType() - || AmmoType.M_THUNDER_AUGMENTED == ammoType.getMunitionType() - || AmmoType.M_THUNDER_INFERNO == ammoType.getMunitionType() - || AmmoType.M_THUNDER_VIBRABOMB == ammoType.getMunitionType() - || AmmoType.M_TORPEDO == ammoType.getMunitionType() - || AmmoType.M_VIBRABOMB_IV == ammoType.getMunitionType() - || AmmoType.M_WATER == ammoType.getMunitionType() - || AmmoType.M_ANTI_TSM == ammoType.getMunitionType() - || AmmoType.M_CORROSIVE == ammoType.getMunitionType()) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_ANTI_FLAME_FOAM) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_CHAFF) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_COOLANT) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_ECM) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_FASCAM) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_FLAK) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_FLARE) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_FLECHETTE) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_FRAGMENTATION) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_HAYWIRE) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY_AC) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY_LRM) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_INFERNO_IV) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_LASER_INHIB) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_OIL_SLICK) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_NEMESIS) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_PAINT_OBSCURANT) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_SMOKE) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_THUNDER) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_ACTIVE) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_AUGMENTED) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_INFERNO) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_TORPEDO) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_VIBRABOMB_IV) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_WATER) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_ANTI_TSM) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_CORROSIVE)) { continue; } // MMLs have additional considerations. @@ -2975,15 +3006,26 @@ Mounted getAntiAirAmmo(final List ammoList, for (final Mounted ammo : ammoList) { final AmmoType ammoType = (AmmoType) ammo.getType(); - if (AmmoType.M_CLUSTER == ammoType.getMunitionType() - || AmmoType.M_FLAK == ammoType.getMunitionType()) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_ADA)){ + // Air-Defense Arrow IVs are the premiere long-range AA munition. + returnAmmo = ammo; + break; + } else if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_FLAK) + || ammoType.countsAsFlak()) { // MMLs have additional considerations. // There are no "flak" or "cluster" missile munitions at this point in time. Code is included in case // they are added to the game at some later date. if (!(weaponType instanceof MMLWeapon)) { - returnAmmo = ammo; - break; + // Naively assume that easier-hitting is better + if (returnAmmo != null) { + AmmoType returnAmmoType = (AmmoType)(returnAmmo.getType()); + returnAmmo = ((ammoType.getToHitModifier() > returnAmmoType.getToHitModifier())? ammo : returnAmmo); + } else { + // Any Cluster/Flak ammo is usually a good bet for AAA. + returnAmmo = ammo; + } } if ((null == mmlLrm) && ammoType.hasFlag(AmmoType.F_MML_LRM)) { mmlLrm = ammo; @@ -3035,10 +3077,10 @@ public static List getValidFacingChanges(final Entity shooter) { validFacingChanges.add(-2); validFacingChanges.add(3); } - + return validFacingChanges; } - + /** * This function evaluates whether or not a unit should spend its time * unjamming weapons instead of firing, and returns the appropriate firing plan if that's the case. @@ -3049,46 +3091,46 @@ public Vector getUnjamWeaponPlan(Entity shooter) { int maxJammedDamage = 0; int maxDamageWeaponID = -1; Vector unjamVector = new Vector<>(); - + // apparently, only tank type units can unjam weapons/clear turrets // unconscious crews can't do this if (!shooter.hasETypeFlag(Entity.ETYPE_TANK) || !shooter.getCrew().isActive()) { return unjamVector; } - + Tank tankShooter = (Tank) shooter; - - // can't unjam if crew is stunned. Skip the rest of the logic to save time. + + // can't unjam if crew is stunned. Skip the rest of the logic to save time. if (tankShooter.getStunnedTurns() > 0) { return unjamVector; } - + // step 1: loop through all the unit's jammed weapons to determine the biggest one for (Mounted mounted : tankShooter.getJammedWeapons()) { int weaponDamage = ((WeaponType) mounted.getType()).getDamage(); if (weaponDamage == WeaponType.DAMAGE_BY_CLUSTERTABLE) { weaponDamage = ((WeaponType) mounted.getType()).getRackSize(); } - + if (weaponDamage > maxJammedDamage) { maxDamageWeaponID = shooter.getEquipmentNum(mounted); maxJammedDamage = weaponDamage; } } - + // if any of the unit's weapons are jammed, unjam the biggest one. // we can only unjam one per turn. if (maxDamageWeaponID >= 0) { RepairWeaponMalfunctionAction rwma = new RepairWeaponMalfunctionAction( shooter.getId(), maxDamageWeaponID); - + unjamVector.add(rwma); // if the unit has a jammed turret, attempt to clear it } else if (tankShooter.canClearTurret()) { UnjamTurretAction uta = new UnjamTurretAction(shooter.getId()); unjamVector.add(uta); } - + return unjamVector; } @@ -3101,10 +3143,10 @@ public FindClubAction getFindClubAction(Entity shooter) { FindClubAction findClubAction = new FindClubAction(shooter.getId()); return findClubAction; } - + return null; } - + /** * Given a firing plan, calculate the best target to light up with a searchlight */ @@ -3115,7 +3157,7 @@ public SearchlightAttackAction getSearchLightAction(Entity shooter, FiringPlan p || !shooter.getCrew().isActive()) { return null; } - + // assemble set of targets we're planning on shooting Set planTargets = new HashSet<>(); if (plan != null) { @@ -3123,14 +3165,14 @@ public SearchlightAttackAction getSearchLightAction(Entity shooter, FiringPlan p planTargets.add(wfi.getTarget().getPosition()); } } - + List searchlights = new ArrayList<>(); for (EntityAction action : shooter.getGame().getActionsVector()) { if (action instanceof SearchlightAttackAction) { searchlights.add((SearchlightAttackAction) action); } } - + // for each potential target on the board, draw a line between "shooter" and target // and assign it a score. Score is determined by: // # hostiles lit up - # friendlies lit up + # targets lit up @@ -3139,13 +3181,13 @@ public SearchlightAttackAction getSearchLightAction(Entity shooter, FiringPlan p for (Targetable target : getTargetableEnemyEntities(shooter, shooter.getGame(), owner.getFireControlState())) { int score = 0; - + for (Coords intervening : Coords.intervening(shooter.getPosition(), target.getPosition())) { - // if it's already lit up, don't count it + // if it's already lit up, don't count it if (!IlluminationLevel.determineIlluminationLevel(shooter.getGame(), intervening).isNone()) { continue; } - + for (Entity ent : shooter.getGame().getEntitiesVector(intervening, true)) { // don't count ourselves, or the target if it's already lit itself up // or the target if it will be lit up by a previously declared search light @@ -3153,46 +3195,46 @@ public SearchlightAttackAction getSearchLightAction(Entity shooter, FiringPlan p continue; } else { boolean willbeIlluminated = false; - + for (SearchlightAttackAction searchlight : searchlights) { if (searchlight.willIlluminate(shooter.getGame(), ent)) { willbeIlluminated = true; break; } } - + if (willbeIlluminated) { continue; } } - + if (ent.isEnemyOf(shooter)) { score++; } else { score--; } - + if (planTargets.contains(intervening)) { score++; } } } - + // don't bother considering impossible searchlight actions if (score > bestTargetScore && SearchlightAttackAction.isPossible(shooter.getGame(), shooter.getId(), target, null)) { bestTargetScore = score; bestTarget = target; } } - + if (bestTarget != null) { SearchlightAttackAction slaa = new SearchlightAttackAction(shooter.getId(), bestTarget.getTargetType(), bestTarget.getId()); return slaa; } - + return null; } - + /** * Attempts to switch the current weapon's firing mode between direct and indirect * or vice versa. Returns -1 if the mode switch fails, or the weapon mode index if it succeeds. @@ -3203,15 +3245,15 @@ private int switchMissileMode(Mounted weapon) { // don't bother checking non-missile weapons if (weapon.getType().hasFlag(Weapon.F_MISSILE) && weapon.getType().hasModeType(Weapon.MODE_MISSILE_INDIRECT)) { - + // if we are able to switch the weapon to indirect fire mode, do so and try again if (!weapon.curMode().equals(Weapon.MODE_MISSILE_INDIRECT)) { return weapon.setMode(Weapon.MODE_MISSILE_INDIRECT); } else { return weapon.setMode(""); } - } - + } + return -1; } } diff --git a/megamek/src/megamek/client/bot/princess/FiringPlan.java b/megamek/src/megamek/client/bot/princess/FiringPlan.java index 65b1a24bd06..07e9bbd4b79 100644 --- a/megamek/src/megamek/client/bot/princess/FiringPlan.java +++ b/megamek/src/megamek/client/bot/princess/FiringPlan.java @@ -38,17 +38,17 @@ public class FiringPlan extends ArrayList implements Comparable< private Targetable target; private int twist; private boolean flipArms; - + FiringPlan() { setTwist(0); setUtility(0); } - + FiringPlan(Targetable target) { this(); this.target = target; } - + FiringPlan(Targetable target, boolean flipArms) { this(target); this.flipArms = flipArms; @@ -92,15 +92,15 @@ synchronized double getExpectedCriticals() { * Models the probability of each individual weapon getting a kill shot. * We treat each weapon shot as a Bernoulli trial and compute the probability * of the target surviving each shot. We can then take 1 - surviveChance to - * get the chance of getting a kill. This model doesn't take into - * consideration multiple weapons hitting the same location. - * - * @return The odds of getting a kill based on the odds of each individual + * get the chance of getting a kill. This model doesn't take into + * consideration multiple weapons hitting the same location. + * + * @return The odds of getting a kill based on the odds of each individual * weapon getting a kill. The result will be between 0 and 1. */ synchronized double getKillProbability() { double surviveProbability = 1; - + for (WeaponFireInfo weaponFireInfo : this) { surviveProbability *= 1 - weaponFireInfo.getKillProbability(); } @@ -132,16 +132,16 @@ synchronized Vector getEntityActionVector() { if (size() == 0) { return actionVector; } - + if (getTwist() != 0) { actionVector.add(new TorsoTwistAction(get(0).getShooter().getId(), FireControl.correctFacing(get(0).getShooter().getFacing() + getTwist()))); } - + if (flipArms) { actionVector.addElement(new FlipArmsAction(get(0).getShooter().getId(), flipArms)); } - + for (WeaponFireInfo weaponFireInfo : this) { actionVector.add(weaponFireInfo.getWeaponAttackAction()); } @@ -155,7 +155,7 @@ String getDebugDescription(boolean detailed) { if (size() == 0) { return "Empty FiringPlan!"; } - + StringBuilder description = new StringBuilder("Firing Plan for ").append(get(0).getShooter().getChassis()) .append(" at "); Set targets = new HashSet<>(); @@ -166,13 +166,13 @@ String getDebugDescription(boolean detailed) { targets.add(weaponFireInfo.getTarget().getId()); } } - + // chop off the last ", " description.deleteCharAt(description.length() - 1); description.deleteCharAt(description.length() - 1); - + description.append("; ").append(size()).append(" weapons fired "); - + if (detailed) { for (WeaponFireInfo weaponFireInfo : this) { description.append("\n\t\t").append(weaponFireInfo.getDebugDescription()); @@ -201,11 +201,11 @@ public int getTwist() { public void setTwist(int twist) { this.twist = twist; } - + public boolean getFlipArms() { return flipArms; } - + public void setFlipArms(boolean flipArms) { this.flipArms = flipArms; } @@ -248,7 +248,7 @@ public boolean equals(Object o) { return true; } } - + @Override public String toString() { String desc = "Utility: " + utility + " "; @@ -300,7 +300,7 @@ void sortPlan() { if ((ammo1 != null) && (ammo1.getType() instanceof AmmoType)) { AmmoType ammoType = (AmmoType) ammo1.getType(); if ((WeaponType.DAMAGE_BY_CLUSTERTABLE == weaponType1.getDamage()) - || (AmmoType.M_CLUSTER == ammoType.getMunitionType())) { + || (ammoType.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER))) { dmg1 = ammoType.getDamagePerShot(); } } @@ -312,7 +312,7 @@ void sortPlan() { if ((ammo2 != null) && (ammo2.getType() instanceof AmmoType)) { AmmoType ammoType = (AmmoType) ammo2.getType(); if ((WeaponType.DAMAGE_BY_CLUSTERTABLE == weaponType2.getDamage()) - || (AmmoType.M_CLUSTER == ammoType.getMunitionType())) { + || (ammoType.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER))) { dmg2 = ammoType.getDamagePerShot(); } } diff --git a/megamek/src/megamek/client/bot/princess/InfantryFireControl.java b/megamek/src/megamek/client/bot/princess/InfantryFireControl.java index 5f17f9f9b6a..89b1d6b57b7 100644 --- a/megamek/src/megamek/client/bot/princess/InfantryFireControl.java +++ b/megamek/src/megamek/client/bot/princess/InfantryFireControl.java @@ -1,15 +1,15 @@ -/* -* MegaMek - Copyright (C) 2019 - The MegaMek Team -* -* This program is free software; you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation; either version 2 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -* details. +/* +* MegaMek - Copyright (C) 2019 - The MegaMek Team +* +* This program is free software; you can redistribute it and/or modify it under +* the terms of the GNU General Public License as published by the Free Software +* Foundation; either version 2 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +* details. */ package megamek.client.bot.princess; @@ -22,10 +22,12 @@ import java.util.ArrayList; import java.util.List; +import static megamek.common.WeaponType.F_ARTILLERY; + /** * This class is intended to help the bot calculate firing plans for infantry * units. - * + * * @author NickAragua */ public class InfantryFireControl extends FireControl { @@ -36,7 +38,7 @@ private enum InfantryFiringPlanType { Swarm, Leg } - + public InfantryFireControl(Princess owner) { super(owner); } @@ -85,7 +87,7 @@ public double getMaxDamageAtRange(final MovePath shooterPath, final MovePath tar continue; } - // there are three ways this can go: + // there are N ways this can go, currently we handle these: // 1. Shooter is infantry using infantry weapon, target is infantry. // Use infantry damage. Track damage separately. // 2. Shooter is non-infantry, target is infantry in open. Use @@ -100,13 +102,13 @@ public double getMaxDamageAtRange(final MovePath shooterPath, final MovePath tar // case 1 if (weaponType.hasFlag(WeaponType.F_INFANTRY)) { int infantryCount = 1; - + if (shooter.isConventionalInfantry()) { infantryCount = shooter.getInternal(Infantry.LOC_INFANTRY); } else if (shooter instanceof BattleArmor) { infantryCount = ((BattleArmor) shooter).getNumberActiverTroopers(); } - + maxInfantryWeaponDamage += ((InfantryWeapon) weaponType).getInfantryDamage() * infantryCount; // field guns can't fire if the infantry unit has done anything @@ -134,8 +136,13 @@ public double getMaxDamageAtRange(final MovePath shooterPath, final MovePath tar maxFGDamage += damage; // field guns can't fire if the infantry unit has done anything // other than turning + // case 5 } else if (fieldGunsDoDamage) { - maxFGDamage += weaponType.getDamage(); + // Some FGs are artillery, so check both damage/shot * shot num _and_ rack size. + AmmoType ammoType = (AmmoType) weapon.getLinked().getType(); + int wDamage = (weaponType.hasFlag(F_ARTILLERY) ? weaponType.rackSize : weaponType.getDamage()); + int ammoDamage = ammoType.getDamagePerShot()*ammoType.getShots(); + maxFGDamage += Math.max(wDamage, ammoDamage); } } @@ -162,7 +169,7 @@ public double getMaxDamageAtRange(final MovePath shooterPath, final MovePath tar protected FiringPlan guessBestFiringPlanUnderHeat(final Entity shooter, @Nullable EntityState shooterState, final Targetable target, @Nullable EntityState targetState, int maxHeat, final Game game) { FiringPlan bestPlan = new FiringPlan(target); - + // Shooting isn't possible if one of us isn't on the board. if ((null == shooter.getPosition()) || shooter.isOffBoard() || !game.getBoard().contains(shooter.getPosition())) { @@ -173,19 +180,19 @@ protected FiringPlan guessBestFiringPlanUnderHeat(final Entity shooter, @Nullabl LogManager.getLogger().error("Target's position is NULL/Off Board!"); return bestPlan; } - + // if it's not infantry, then we shouldn't be here, let's redirect to the base method. if (!(shooter instanceof Infantry)) { return super.guessBestFiringPlanUnderHeat(shooter, shooterState, target, targetState, maxHeat, game); } - + if (null == shooterState) { shooterState = new EntityState(shooter); } if (null == targetState) { targetState = new EntityState(target); } - + // Infantry can do the following things, which are mutually exclusive: // 1. Fire standard infantry weapons, including "need to stay still" support weapons // 2. Fire field guns - the unit needs to remain still to fire these @@ -203,11 +210,11 @@ protected FiringPlan guessBestFiringPlanUnderHeat(final Entity shooter, @Nullabl FiringPlan fieldGunPlan = guessFiringPlan(shooter, shooterState, target, targetState, game, InfantryFiringPlanType.FieldGuns); firingPlans.add(fieldGunPlan); } - + // case 3: leg attack FiringPlan legPlan = guessFiringPlan(shooter, shooterState, target, targetState, game, InfantryFiringPlanType.Leg); firingPlans.add(legPlan); - + // case 4: swarm attack FiringPlan swarmPlan = guessFiringPlan(shooter, shooterState, target, targetState, game, InfantryFiringPlanType.Swarm); firingPlans.add(swarmPlan); @@ -239,7 +246,7 @@ protected FiringPlan guessBestFiringPlanUnderHeat(final Entity shooter, @Nullabl */ private FiringPlan guessFiringPlan(final Entity shooter, @Nullable EntityState shooterState, final Targetable target, @Nullable EntityState targetState, final Game game, InfantryFiringPlanType firingPlanType) { - + final FiringPlan myPlan = new FiringPlan(target); // cycle through my field guns @@ -259,16 +266,16 @@ private FiringPlan guessFiringPlan(final Entity shooter, @Nullable EntityState s return myPlan; } - + /** - * Helper method that determines whether a weapon type is appropriate for a given firing plan type, + * Helper method that determines whether a weapon type is appropriate for a given firing plan type, * e.g. field guns cannot be fired when we're going to do a swarm attack, etc. */ private boolean weaponIsAppropriate(Mounted weapon, InfantryFiringPlanType firingPlanType) { boolean weaponIsSwarm = (weapon.getType()).getInternalName().equals(Infantry.SWARM_MEK); boolean weaponIsLegAttack = (weapon.getType()).getInternalName().equals(Infantry.LEG_ATTACK); boolean weaponIsFieldGuns = weapon.getLocation() == Infantry.LOC_FIELD_GUNS; - + switch (firingPlanType) { case FieldGuns: return weaponIsFieldGuns; diff --git a/megamek/src/megamek/client/commands/FireCommand.java b/megamek/src/megamek/client/commands/FireCommand.java index c59bcaca136..438bf840b77 100644 --- a/megamek/src/megamek/client/commands/FireCommand.java +++ b/megamek/src/megamek/client/commands/FireCommand.java @@ -1,7 +1,7 @@ /* * MegaMek - * Copyright (C) 2007 Ben Mazur (bmazur@sev.org) - * + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) @@ -23,6 +23,7 @@ import megamek.common.options.OptionsConstants; import megamek.common.weapons.Weapon; +import java.util.EnumSet; import java.util.Enumeration; import java.util.Vector; @@ -44,7 +45,7 @@ public FireCommand(Client client) { /* * (non-Javadoc) - * + * * @see megamek.client.commands.ClientCommand#run(java.lang.String[]) */ @Override @@ -212,14 +213,14 @@ private void fire(int weaponNum, Targetable target) { Mounted ammoMount = mounted.getLinked(); AmmoType ammoType = (AmmoType) ammoMount.getType(); waa.setAmmoId(ammoMount.getEntity().getEquipmentNum(ammoMount)); - long ammoMunitionType = ammoType.getMunitionType(); + EnumSet ammoMunitionType = ammoType.getMunitionType(); waa.setAmmoMunitionType(ammoMunitionType); waa.setAmmoCarrier(ammoMount.getEntity().getId()); - if (((ammoMunitionType == AmmoType.M_THUNDER_VIBRABOMB) - && (ammoType.getAmmoType() == AmmoType.T_LRM + if (((ammoMunitionType.contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) + && (ammoType.getAmmoType() == AmmoType.T_LRM || ammoType.getAmmoType() == AmmoType.T_MML || ammoType.getAmmoType() == AmmoType.T_LRM_IMP)) - || ammoType.getMunitionType() == AmmoType.M_VIBRABOMB_IV) { + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_VIBRABOMB_IV)) { waa.setOtherAttackInfo(50); // /hardcode vibrobomb setting for // now. diff --git a/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java b/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java index 7ae9eb835bc..9d40f83e309 100644 --- a/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java +++ b/megamek/src/megamek/client/ui/swing/BayMunitionsChoicePanel.java @@ -31,15 +31,15 @@ */ public class BayMunitionsChoicePanel extends JPanel { private static final long serialVersionUID = -7741380967676720496L; - + private final Entity entity; private final Game game; private final List rows = new ArrayList<>(); - + public BayMunitionsChoicePanel(Entity entity, Game game) { this.entity = entity; this.game = game; - + setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; @@ -66,7 +66,7 @@ public BayMunitionsChoicePanel(Entity entity, Game game) { } } } - + /** * Change the munition types of the bay ammo mounts to the selected values. If there are more * munition types than there were originally, additional ammo bin mounts will be added. If fewer, @@ -119,26 +119,26 @@ public void apply() { } } } - + class AmmoRowPanel extends JPanel implements ChangeListener { /** - * + * */ private static final long serialVersionUID = 7251618728823971065L; - + private final JLabel lblTonnage = new JLabel(); - + private final Mounted bay; private final int at; private final int rackSize; private final int techBase; private final List ammoMounts; - + private final List spinners; private final List munitions; - + private double tonnage; - + AmmoRowPanel(Mounted bay, int at, int rackSize, List ammoMounts) { this.bay = bay; this.at = at; @@ -146,15 +146,15 @@ class AmmoRowPanel extends JPanel implements ChangeListener { this.ammoMounts = new ArrayList<>(ammoMounts); this.spinners = new ArrayList<>(); Dimension spinnerSize =new Dimension(55, 25); - + final Optional wtype = bay.getBayWeapons().stream() .map(entity::getEquipment) .map(m -> (WeaponType) m.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 this.techBase = wtype.map(EquipmentType::getTechBase).orElse(WeaponType.TECH_BASE_ALL); - + munitions = AmmoType.getMunitionsFor(at).stream() .filter(this::includeMunition).collect(Collectors.toList()); tonnage = ammoMounts.stream().mapToDouble(Mounted::getSize).sum(); @@ -175,7 +175,7 @@ class AmmoRowPanel extends JPanel implements ChangeListener { } spinners.add(spn); } - + setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; @@ -206,7 +206,7 @@ class AmmoRowPanel extends JPanel implements ChangeListener { } recalcMaxValues(); } - + private boolean includeMunition(AmmoType atype) { if (!atype.canAeroUse(game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_ARTILLERY_MUNITIONS)) || (atype.getAmmoType() != at) @@ -215,8 +215,8 @@ private boolean includeMunition(AmmoType atype) { && (atype.getTechBase() != AmmoType.TECH_BASE_ALL) && (techBase != AmmoType.TECH_BASE_ALL)) || !atype.isLegal(game.getOptions().intOption(OptionsConstants.ALLOWED_YEAR), - SimpleTechLevel.getGameTechLevel(game), - techBase == AmmoType.TECH_BASE_CLAN, + SimpleTechLevel.getGameTechLevel(game), + techBase == AmmoType.TECH_BASE_CLAN, techBase == AmmoType.TECH_BASE_ALL, game.getOptions().booleanOption(OptionsConstants.ALLOWED_SHOW_EXTINCT))) { return false; @@ -226,20 +226,23 @@ private boolean includeMunition(AmmoType atype) { OptionsConstants.ADVAERORULES_AT2_NUKES)) { return false; } - if ((atype.getMunitionType() & AmmoType.M_ARTEMIS_CAPABLE) != 0) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE)) { return entity.hasWorkingMisc(MiscType.F_ARTEMIS) || entity.hasWorkingMisc(MiscType.F_ARTEMIS_PROTO); } - if ((atype.getMunitionType() & AmmoType.M_ARTEMIS_V_CAPABLE) != 0) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE)) { return entity.hasWorkingMisc(MiscType.F_ARTEMIS_V); } return true; } - + private String createMunitionLabel(AmmoType atype) { if (atype.getAmmoType() == AmmoType.T_MML) { - if ((atype.getMunitionType() & (AmmoType.M_ARTEMIS_CAPABLE | AmmoType.M_ARTEMIS_V_CAPABLE)) - == 0) { + EnumSet artemisCapable = EnumSet.of( + AmmoType.Munitions.M_ARTEMIS_CAPABLE, + AmmoType.Munitions.M_ARTEMIS_V_CAPABLE + ); + if (atype.getMunitionType().stream().noneMatch(artemisCapable::contains)) { return Messages.getString(atype.hasFlag(AmmoType.F_MML_LRM) ? "CustomMechDialog.LRM" : "CustomMechDialog.SRM"); } else { @@ -247,7 +250,7 @@ private String createMunitionLabel(AmmoType atype) { ? "CustomMechDialog.LRMArtemis" : "CustomMechDialog.SRMArtemis"); } } - + if (atype.hasFlag(AmmoType.F_CAP_MISSILE)) { String tele = atype.hasFlag(AmmoType.F_TELE_MISSILE) ? "-T" : ""; if (atype.hasFlag(AmmoType.F_PEACEMAKER)) { @@ -262,25 +265,25 @@ private String createMunitionLabel(AmmoType atype) { return Messages.getString("CustomMechDialog.Barracuda") + tele; } } - - if ((atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE) - || (atype.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)) { + + if ((atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))) { return Messages.getString("CustomMechDialog.Artemis"); } - + // ATM munitions - if ((atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) - || (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE)) { + if ((atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE))) { return atype.getDesc(); } - + if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_ARTILLERY_MUNITIONS)) { if (atype.getAmmoType() == AmmoType.T_ARROW_IV || atype.getAmmoType() == AmmoType.T_LONG_TOM || atype.getAmmoType() == AmmoType.T_SNIPER || atype.getAmmoType() == AmmoType.T_THUMPER || atype.getAmmoType() == AmmoType.T_CRUISE_MISSILE) { - if (atype.getMunitionType() == AmmoType.M_STANDARD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) { return Messages.getString("CustomMechDialog.StandardMunition"); } return atype.getShortName(); @@ -288,7 +291,7 @@ private String createMunitionLabel(AmmoType atype) { } return Messages.getString("CustomMechDialog.StandardMunition"); } - + private void recalcMaxValues() { double[] currentWeight = new double[spinners.size()]; double remaining = tonnage; diff --git a/megamek/src/megamek/client/ui/swing/EquipChoicePanel.java b/megamek/src/megamek/client/ui/swing/EquipChoicePanel.java index 366736ec9a7..d6a514da2da 100644 --- a/megamek/src/megamek/client/ui/swing/EquipChoicePanel.java +++ b/megamek/src/megamek/client/ui/swing/EquipChoicePanel.java @@ -48,24 +48,24 @@ public class EquipChoicePanel extends JPanel { private List m_vMunitions = new ArrayList<>(); private List m_vWeaponAmmoChoice = new ArrayList<>(); - + /** - * An ArrayList to keep track of all of the - * APWeaponChoicePanels that were added, so we can apply + * An ArrayList to keep track of all of the + * APWeaponChoicePanels that were added, so we can apply * their choices when the dialog is closed. */ private ArrayList m_vAPMounts = new ArrayList<>(); - + /** - * An ArrayList to keep track of all of the - * MEAChoicePanels that were added, so we can apply + * An ArrayList to keep track of all of the + * MEAChoicePanels that were added, so we can apply * their choices when the dialog is closed. */ private ArrayList m_vMEAdaptors = new ArrayList<>(); - + /** * Panel for adding components related to selecting which anti-personnel - * weapons are mounted in an AP Mount (armored gloves are also considered + * weapons are mounted in an AP Mount (armored gloves are also considered * AP mounts) **/ private JPanel panAPMounts = new JPanel(); @@ -103,7 +103,7 @@ public class EquipChoicePanel extends JPanel { private JLabel labCondEjectHeadshot = new JLabel( Messages.getString("CustomMechDialog.labConditional_Ejection_Headshot"), SwingConstants.RIGHT); private JCheckBox chCondEjectHeadshot = new JCheckBox(); - + private JLabel labCondEjectFuel = new JLabel( Messages.getString("CustomMechDialog.labConditional_Ejection_Fuel"), SwingConstants.RIGHT); private JCheckBox chCondEjectFuel = new JCheckBox(); @@ -188,17 +188,17 @@ public EquipChoicePanel(Entity entity, ClientGUI clientgui, Client client) { add(choC3, GBC.eol()); refreshC3(); } - + // Setup AP mounts if ((entity instanceof BattleArmor) && entity.hasWorkingMisc(MiscType.F_AP_MOUNT)) { setupAPMounts(); panAPMounts.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), Messages.getString("CustomMechDialog.APMountPanelTitle"), TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); - + add(panAPMounts,GBC.eop().anchor(GridBagConstraints.CENTER)); } - + if ((entity instanceof BattleArmor) && entity.hasWorkingMisc(MiscType.F_BA_MEA)) { panMEAdaptors.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), Messages.getString("CustomMechDialog.MEAPanelTitle"), @@ -209,7 +209,7 @@ public EquipChoicePanel(Entity entity, ClientGUI clientgui, Client client) { EntityVerifier verifier = EntityVerifier.getInstance( new MegaMekFile(Configuration.unitsDir(), EntityVerifier.CONFIG_FILENAME).getFile()); - TestBattleArmor testBA = new TestBattleArmor(ba, + TestBattleArmor testBA = new TestBattleArmor(ba, verifier.baOption, null); double maxTrooperWeight = 0; for (int i = 1; i < ba.getTroopers(); i++) { @@ -220,11 +220,11 @@ public EquipChoicePanel(Entity entity, ClientGUI clientgui, Client client) { } String freeWeight = Messages.getString("CustomMechDialog.freeWeight") + String.format(": %1$.3f/%2$.3f", maxTrooperWeight, ba.getTrooperWeight()); - + setupMEAdaptors(freeWeight); add(panMEAdaptors,GBC.eop().anchor(GridBagConstraints.CENTER)); } - + // Can't set up munitions on infantry. if (!((entity instanceof Infantry) && !((Infantry) entity) .hasFieldWeapon()) || (entity instanceof BattleArmor)) { @@ -234,7 +234,7 @@ public EquipChoicePanel(Entity entity, ClientGUI clientgui, Client client) { TitledBorder.TOP, TitledBorder.DEFAULT_POSITION)); add(panMunitions, GBC.eop().anchor(GridBagConstraints.CENTER)); - + setupWeaponAmmoChoice(); panWeaponAmmoSelector.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), Messages.getString("CustomMechDialog.WeaponSelectionTitle"), @@ -436,18 +436,18 @@ private void setupMines() { /** * Setup the layout of panMEAdaptors, which contains components - * for selecting which manipulators are mounted in a modular equipment + * for selecting which manipulators are mounted in a modular equipment * adaptor */ private void setupMEAdaptors(String freeWeight) { GridBagLayout gbl = new GridBagLayout(); panMEAdaptors.setLayout(gbl); - + JLabel lblFreeWeight = new JLabel(freeWeight); panMEAdaptors.add(lblFreeWeight, GBC.eol().anchor(GridBagConstraints.CENTER)); ArrayList manipTypes = new ArrayList<>(); - + for (String manipTypeName : BattleArmor.MANIPULATOR_TYPE_STRINGS) { // Ignore the "None" option if (manipTypeName.equals(BattleArmor.MANIPULATOR_TYPE_STRINGS[0])) { @@ -456,7 +456,7 @@ private void setupMEAdaptors(String freeWeight) { MiscType mType = (MiscType) EquipmentType.get(manipTypeName); manipTypes.add(mType); } - + for (Mounted m : entity.getMisc()) { if (!m.getType().hasFlag(MiscType.F_BA_MEA)) { continue; @@ -472,20 +472,20 @@ private void setupMEAdaptors(String freeWeight) { } MEAChoicePanel meacp; meacp = new MEAChoicePanel(entity, m.getBaMountLoc(), currentManip, manipTypes); - + panMEAdaptors.add(meacp, GBC.eol()); m_vMEAdaptors.add(meacp); } } - + /** * Setup the layout of panAPMounts, which contains components - * for selecting which anti-personnel weapons are mounted in an AP mount. + * for selecting which anti-personnel weapons are mounted in an AP mount. */ private void setupAPMounts() { GridBagLayout gbl = new GridBagLayout(); panAPMounts.setLayout(gbl); - + // Weapons that can be used in an AP Mount ArrayList apWeapTypes = new ArrayList<>(100); // Weapons that can be used in an Armored Glove @@ -495,18 +495,18 @@ private void setupAPMounts() { SimpleTechLevel legalLevel = SimpleTechLevel.getGameTechLevel(clientgui.getClient().getGame()); while (allTypes.hasMoreElements()) { EquipmentType eq = allTypes.nextElement(); - + // If it's not an infantry weapon, we don't care if (!(eq instanceof InfantryWeapon)) { continue; } - + // Check to see if the tech level of the equipment is legal if (!eq.isLegal(gameYear, legalLevel, entity.isClan(), entity.isMixedTech(), entity.getGame().getOptions().booleanOption(OptionsConstants.ALLOWED_SHOW_EXTINCT))) { continue; } - + // Check to see if we've got a valid infantry weapon InfantryWeapon infWeap = (InfantryWeapon) eq; if (infWeap.hasFlag(WeaponType.F_INFANTRY) @@ -534,7 +534,7 @@ private void setupAPMounts() { // Armored gloves need to be treated slightly differently, since // 1 or 2 armored gloves allow 1 additional AP weapon if (m.getType().hasFlag(MiscType.F_ARMORED_GLOVE)) { - armoredGloves.add(m); + armoredGloves.add(m); } else { apcp = new APWeaponChoicePanel(entity, m, apWeapTypes); } @@ -543,7 +543,7 @@ private void setupAPMounts() { m_vAPMounts.add(apcp); } } - + // If there is an armored glove with a weapon already mounted, we need // to ensure that that glove is displayed, and not the empty glove Mounted aGlove = null; @@ -552,7 +552,7 @@ private void setupAPMounts() { aGlove = ag; } else if ((aGlove.getLinked() == null) && (ag.getLinked() != null)) { aGlove = ag; - } + } // If both are linked, TestBattleArmor will mark unit as invalid } if (aGlove != null) { @@ -619,33 +619,32 @@ private void setupMunitions() { // If clan_ignore_eq_limits is unchecked, // do NOT allow Clans to use IS-only ammo. - // N.B. play bit-shifting games to allow "incendiary" - // to be combined to other munition types. - long muniType = atCheck.getMunitionType(); - muniType &= ~AmmoType.M_INCENDIARY_LRM; + // "Incendiary" munition type gets removed here for reasons unknown. + EnumSet muniType = atCheck.getMunitionType(); + muniType.remove(AmmoType.Munitions.M_INCENDIARY_LRM); if (!gameOpts.booleanOption(OptionsConstants.ALLOWED_CLAN_IGNORE_EQ_LIMITS) && entity.isClan() - && ((muniType == AmmoType.M_SEMIGUIDED) - || (muniType == AmmoType.M_SWARM_I) - || (muniType == AmmoType.M_THUNDER_AUGMENTED) - || (muniType == AmmoType.M_THUNDER_INFERNO) - || (muniType == AmmoType.M_THUNDER_VIBRABOMB) - || (muniType == AmmoType.M_THUNDER_ACTIVE) - || (muniType == AmmoType.M_INFERNO_IV) - || (muniType == AmmoType.M_VIBRABOMB_IV) - || (muniType == AmmoType.M_LISTEN_KILL) - || (muniType == AmmoType.M_ANTI_TSM) - || (muniType == AmmoType.M_DEAD_FIRE) - || (muniType == AmmoType.M_MINE_CLEARANCE))) { + && ((muniType.contains(AmmoType.Munitions.M_SEMIGUIDED)) + || (muniType.contains(AmmoType.Munitions.M_SWARM_I)) + || (muniType.contains(AmmoType.Munitions.M_THUNDER_AUGMENTED)) + || (muniType.contains(AmmoType.Munitions.M_THUNDER_INFERNO)) + || (muniType.contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) + || (muniType.contains(AmmoType.Munitions.M_THUNDER_ACTIVE)) + || (muniType.contains(AmmoType.Munitions.M_INFERNO_IV)) + || (muniType.contains(AmmoType.Munitions.M_VIBRABOMB_IV)) + || (muniType.contains(AmmoType.Munitions.M_LISTEN_KILL)) + || (muniType.contains(AmmoType.Munitions.M_ANTI_TSM)) + || (muniType.contains(AmmoType.Munitions.M_DEAD_FIRE)) + || (muniType.contains(AmmoType.Munitions.M_MINE_CLEARANCE)))) { bTechMatch = false; } - - if ((muniType == AmmoType.M_ARTEMIS_CAPABLE) + + if ((muniType.contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE)) && !entity.hasWorkingMisc(MiscType.F_ARTEMIS) && !entity.hasWorkingMisc(MiscType.F_ARTEMIS_PROTO)) { continue; } - if ((muniType == AmmoType.M_ARTEMIS_V_CAPABLE) + if ((muniType.contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE)) && !entity.hasWorkingMisc(MiscType.F_ARTEMIS_V) && !entity.hasWorkingMisc(MiscType.F_ARTEMIS_PROTO)) { continue; @@ -695,27 +694,27 @@ private void setupMunitions() { } /** - * Worker function that creates a series of weapon ammo choice panels that allow the user to pick a particular ammo bin for an + * Worker function that creates a series of weapon ammo choice panels that allow the user to pick a particular ammo bin for an * ammo-using weapon with matching ammo. */ private void setupWeaponAmmoChoice() { GridBagLayout gbl = new GridBagLayout(); panWeaponAmmoSelector.setLayout(gbl); - + for (Mounted weapon : entity.getWeaponList()) { WeaponType weaponType = weapon.getType() instanceof WeaponType ? (WeaponType) weapon.getType() : null; - - // don't deal with bay or grouped weapons for now + + // don't deal with bay or grouped weapons for now if (weaponType == null || weaponType.getAmmoType() == AmmoType.T_NA) { continue; } - + WeaponAmmoChoicePanel ammoChoicePanel = new WeaponAmmoChoicePanel(weapon); panWeaponAmmoSelector.add(ammoChoicePanel, GBC.eol()); m_vWeaponAmmoChoice.add(ammoChoicePanel); } } - + class MineChoicePanel extends JPanel { private static final long serialVersionUID = -1868675102440527538L; @@ -748,18 +747,18 @@ public void setEnabled(boolean enabled) { m_choice.setEnabled(enabled); } } - + /** * A panel that houses a label and a combo box that allows for selecting * which anti-personnel weapon is mounted in an AP mount. - * + * * @author arlith */ class APWeaponChoicePanel extends JPanel { private static final long serialVersionUID = 6189888202192403704L; private Entity entity; - + private ArrayList m_APWeaps; private JComboBox m_choice; @@ -798,7 +797,7 @@ class APWeaponChoicePanel extends JPanel { setLayout(g); add(lLoc, GBC.std()); add(m_choice, GBC.std()); - + } public void applyChoice() { @@ -812,9 +811,9 @@ public void applyChoice() { // Need to account for the "None" selection apType = m_APWeaps.get(n - 1); } - + // Remove any currently mounted AP weapon - if (m_APmounted.getLinked() != null + if (m_APmounted.getLinked() != null && m_APmounted.getLinked().getType() != apType) { Mounted apWeapon = m_APmounted.getLinked(); entity.getEquipment().remove(apWeapon); @@ -823,24 +822,24 @@ public void applyChoice() { // We need to make sure that the weapon has been removed // from the criticals, otherwise it can cause issues for (int loc = 0; loc < entity.locations(); loc++) { - for (int c = 0; + for (int c = 0; c < entity.getNumberOfCriticals(loc); c++) { CriticalSlot crit = entity.getCritical(loc, c); - if (crit != null && crit.getMount() != null + if (crit != null && crit.getMount() != null && crit.getMount().equals(apWeapon)) { entity.setCritical(loc, c, null); } } } } - + // Did the selection not change, or no weapon was selected - if ((m_APmounted.getLinked() != null + if ((m_APmounted.getLinked() != null && m_APmounted.getLinked().getType() == apType) || n == 0) { return; } - + // Add the newly mounted weapon try { Mounted newWeap = entity.addEquipment(apType, m_APmounted.getLocation()); @@ -858,18 +857,18 @@ public void setEnabled(boolean enabled) { m_choice.setEnabled(enabled); } } - + /** * A panel that houses a label and a combo box that allows for selecting * which manipulator is mounted in a modular equipment adaptor. - * + * * @author arlith */ class MEAChoicePanel extends JPanel { private static final long serialVersionUID = 6189888202192403704L; private Entity entity; - + private ArrayList m_Manipulators; private JComboBox m_choice; @@ -878,13 +877,13 @@ class MEAChoicePanel extends JPanel { * The manipulator currently mounted by a modular equipment adaptor. */ private Mounted m_Manipmounted; - + /** * The BattleArmor mount location of the modular equipment adaptor. */ private int baMountLoc; - MEAChoicePanel(Entity e, int mountLoc, Mounted m, + MEAChoicePanel(Entity e, int mountLoc, Mounted m, ArrayList manips) { entity = e; m_Manipulators = manips; @@ -903,8 +902,8 @@ class MEAChoicePanel extends JPanel { String manipName = manip.getName() + " (" + manip.getTonnage(entity) + "kg)"; m_choice.addItem(manipName); - if (curType != null && - manip.getInternalName() == + if (curType != null && + manip.getInternalName() == curType.getInternalName()) { m_choice.setSelectedIndex(x); } @@ -912,8 +911,8 @@ class MEAChoicePanel extends JPanel { String sDesc = ""; if (baMountLoc != BattleArmor.MOUNT_LOC_NONE) { - sDesc += " (" - + BattleArmor.MOUNT_LOC_NAMES[baMountLoc] + sDesc += " (" + + BattleArmor.MOUNT_LOC_NAMES[baMountLoc] + ')'; } else { sDesc = "None"; @@ -923,7 +922,7 @@ class MEAChoicePanel extends JPanel { setLayout(g); add(lLoc, GBC.std()); add(m_choice, GBC.std()); - + } public void applyChoice() { @@ -941,13 +940,13 @@ public void applyChoice() { if (m_Manipmounted != null) { entity.getEquipment().remove(m_Manipmounted); entity.getMisc().remove(m_Manipmounted); - } - + } + // Was no manipulator selected? if (n == 0) { return; } - + // Add the newly mounted manipulator try { m_Manipmounted = entity.addEquipment(manipType, m_Manipmounted.getLocation()); @@ -970,11 +969,11 @@ class MunitionChoicePanel extends JPanel { private List m_vTypes; private JComboBox m_choice; - + @SuppressWarnings("rawtypes") private JComboBox m_num_shots; private ItemListener numShotsListener; - + boolean numShotsChanged = false; private Mounted m_mounted; @@ -986,12 +985,12 @@ class MunitionChoicePanel extends JPanel { JLabel labHotLoad = new JLabel(Messages.getString("CustomMechDialog.switchToHotLoading")); JCheckBox chHotLoad = new JCheckBox(); - + @SuppressWarnings("unchecked") MunitionChoicePanel(Mounted m, ArrayList vTypes, List weaponAmmoChoicePanels) { m_vTypes = vTypes; m_mounted = m; - + AmmoType curType = (AmmoType) m.getType(); m_choice = new JComboBox<>(); Iterator e = m_vTypes.iterator(); @@ -1027,7 +1026,7 @@ class MunitionChoicePanel extends JPanel { int currShots = (Integer) m_num_shots.getSelectedItem(); m_num_shots.removeAllItems(); int numberOfShotsPerTon = m_vTypes.get(m_choice.getSelectedIndex()).getShots(); - + // ProtoMeks are limited to number of shots added during construction if ((entity instanceof BattleArmor) || (entity instanceof Protomech)) { numberOfShotsPerTon = m.getOriginalShots(); @@ -1041,11 +1040,11 @@ class MunitionChoicePanel extends JPanel { } else { m_num_shots.setSelectedItem(numberOfShotsPerTon); } - + for (WeaponAmmoChoicePanel weaponAmmoChoicePanel : weaponAmmoChoicePanels) { weaponAmmoChoicePanel.refreshAmmoBinName(m_mounted, m_vTypes.get(m_choice.getSelectedIndex())); } - + m_num_shots.addItemListener(numShotsListener); }); @@ -1100,12 +1099,12 @@ public void applyChoice() { } AmmoType at = m_vTypes.get(n); m_mounted.changeAmmoType(at); - + // set # shots only for non-one shot weapons if (m_mounted.getLocation() != Entity.LOC_NONE) { m_mounted.setShotsLeft((Integer) m_num_shots.getSelectedItem()); } - + if (chDump.isSelected()) { m_mounted.setShotsLeft(0); } @@ -1149,7 +1148,7 @@ void setShotsLeft(int shots) { m_mounted.setShotsLeft(shots); } } - + /** * A panel representing the option to choose a particular ammo bin for an individual weapon. * @author NickAragua @@ -1159,9 +1158,9 @@ class WeaponAmmoChoicePanel extends JPanel { // the weapon being displayed in this row private Mounted m_mounted; private ArrayList matchingAmmoBins; - + private JComboBox ammoBins; - + /** * Constructor * @param weapon The mounted weapon. Assumes that the weapon uses ammo. @@ -1171,14 +1170,14 @@ public WeaponAmmoChoicePanel(Mounted weapon) { if (!(weapon.getType() instanceof WeaponType)) { return; } - + m_mounted = weapon; - + this.setLayout(new GridBagLayout()); - + ammoBins = new JComboBox<>(); matchingAmmoBins = new ArrayList<>(); - + if (m_mounted.isOneShot() || (entity.isSupportVehicle() && (m_mounted.getType() instanceof InfantryWeapon))) { // One-shot weapons can only access their own bin @@ -1198,16 +1197,16 @@ public WeaponAmmoChoicePanel(Mounted weapon) { } } } - + // don't bother displaying the row if there's no ammo to be swapped if (matchingAmmoBins.isEmpty()) { return; } - + JLabel weaponName = new JLabel(); weaponName.setText("(" + weapon.getEntity().getLocationAbbr(weapon.getLocation()) + ") " + weapon.getName()); add(weaponName, GBC.std()); - + add(ammoBins, GBC.eol()); refreshAmmoBinNames(); } @@ -1218,24 +1217,24 @@ public WeaponAmmoChoicePanel(Mounted weapon) { public void refreshAmmoBinNames() { int selectedIndex = ammoBins.getSelectedIndex(); ammoBins.removeAllItems(); - + int currentIndex = 0; for (Mounted ammoBin : matchingAmmoBins) { ammoBins.addItem("(" + ammoBin.getEntity().getLocationAbbr(ammoBin.getLocation()) + ") " + ammoBin.getName()); if (m_mounted.getLinked() == ammoBin) { selectedIndex = currentIndex; } - + currentIndex++; } - + if (selectedIndex >= 0) { ammoBins.setSelectedIndex(selectedIndex); } - + validate(); } - + /** * Refreshes a single item in the ammo type combo box to display the correct ammo type name. * Because the underlying ammo bin hasn't been updated yet, we carry out the name swap "in-place". @@ -1245,28 +1244,28 @@ public void refreshAmmoBinNames() { public void refreshAmmoBinName(Mounted ammoBin, AmmoType selectedAmmoType) { int index = 0; boolean matchFound = false; - + for (index = 0; index < matchingAmmoBins.size(); index++) { if (matchingAmmoBins.get(index) == ammoBin) { matchFound = true; break; } } - + if (matchFound) { int currentBinIndex = ammoBins.getSelectedIndex(); - + ammoBins.removeItemAt(index); ammoBins.insertItemAt("(" + ammoBin.getEntity().getLocationAbbr(ammoBin.getLocation()) + ") " + selectedAmmoType.getName(), index); - + if (currentBinIndex == index) { ammoBins.setSelectedIndex(index); } - + validate(); } } - + /** * Common functionality that applies the panel's current ammo bin choice to the panel's weapon. */ @@ -1331,7 +1330,7 @@ class InfantryArmorPanel extends JPanel { JCheckBox chSneakIR = new JCheckBox(); JCheckBox chSneakECM = new JCheckBox(); List chSpecs = new ArrayList<>(Infantry.NUM_SPECIALIZATIONS); - + List armorKits = new ArrayList<>(); InfantryArmorPanel() { @@ -1342,7 +1341,7 @@ class InfantryArmorPanel extends JPanel { newSpec.setToolTipText(Infantry.getSpecializationTooltip(spec)); chSpecs.add(newSpec); } - + GridBagLayout g = new GridBagLayout(); setLayout(g); add(labArmor, GBC.std()); @@ -1370,7 +1369,7 @@ class InfantryArmorPanel extends JPanel { public void initialize() { inf = (Infantry) entity; - + SimpleTechLevel gameTechLevel = SimpleTechLevel.getGameTechLevel(client.getGame()); int year = client.getGame().getOptions().intOption("year"); for (Enumeration e = MiscType.getAllTypes(); e.hasMoreElements();) { @@ -1410,7 +1409,7 @@ public void initialize() { chSpecs.get(i).setSelected(inf.hasSpecialization(spec)); } } - + public void armorStateChanged() { fldDivisor.setEnabled(cbArmorKit.getSelectedIndex() == 0); chEncumber.setEnabled(cbArmorKit.getSelectedIndex() == 0); @@ -1486,13 +1485,13 @@ private void disableMunitionEditing() { m_vMunitions.get(i).setEnabled(false); } } - + private void disableAPMEditing() { for (int i = 0; i < m_vAPMounts.size(); i++) { m_vAPMounts.get(i).setEnabled(false); } } - + private void disableMEAEditing() { for (int i = 0; i < m_vMEAdaptors.size(); i++) { m_vMEAdaptors.get(i).setEnabled(false); diff --git a/megamek/src/megamek/client/ui/swing/FiringDisplay.java b/megamek/src/megamek/client/ui/swing/FiringDisplay.java index c78424ed73c..3bc36060e02 100644 --- a/megamek/src/megamek/client/ui/swing/FiringDisplay.java +++ b/megamek/src/megamek/client/ui/swing/FiringDisplay.java @@ -1638,14 +1638,14 @@ void fire() { Mounted ammoMount = mounted.getLinked(); AmmoType ammoType = (AmmoType) ammoMount.getType(); waa.setAmmoId(ammoMount.getEntity().getEquipmentNum(ammoMount)); - long ammoMunitionType = ammoType.getMunitionType(); + EnumSet ammoMunitionType = ammoType.getMunitionType(); waa.setAmmoMunitionType(ammoMunitionType); waa.setAmmoCarrier(ammoMount.getEntity().getId()); - if (((ammoMunitionType == AmmoType.M_THUNDER_VIBRABOMB) && + if (((ammoMunitionType.contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) && ((ammoType.getAmmoType() == AmmoType.T_LRM) || (ammoType.getAmmoType() == AmmoType.T_LRM_IMP) || (ammoType.getAmmoType() == AmmoType.T_MML))) - || (ammoType.getMunitionType() == AmmoType.M_VIBRABOMB_IV)) { + || (ammoType.getMunitionType().contains(AmmoType.Munitions.M_VIBRABOMB_IV))) { VibrabombSettingDialog vsd = new VibrabombSettingDialog( clientgui.frame); vsd.setVisible(true); @@ -2537,19 +2537,19 @@ private Targetable chooseTarget(Coords pos) { if ((weap != null) && (weap.getLinked() != null) && (weap.getLinked().getType() instanceof AmmoType)) { AmmoType aType = (AmmoType) weap.getLinked().getType(); - long munitionType = aType.getMunitionType(); + EnumSet munitionType = aType.getMunitionType(); // Mek mortar flares should default to deliver flare if ((aType.getAmmoType() == AmmoType.T_MEK_MORTAR) - && (munitionType == AmmoType.M_FLARE)) { + && (munitionType.contains(AmmoType.Munitions.M_FLARE))) { return new HexTarget(pos, Targetable.TYPE_FLARE_DELIVER); // Certain mek mortar types and LRMs should target hexes } else if (((aType.getAmmoType() == AmmoType.T_MEK_MORTAR) || (aType.getAmmoType() == AmmoType.T_LRM) || (aType.getAmmoType() == AmmoType.T_LRM_IMP)) - && ((munitionType == AmmoType.M_AIRBURST) - || (munitionType == AmmoType.M_SMOKE_WARHEAD))) { + && ((munitionType.contains(AmmoType.Munitions.M_AIRBURST)) + || (munitionType.contains(AmmoType.Munitions.M_SMOKE_WARHEAD)))) { return new HexTarget(pos, Targetable.TYPE_HEX_CLEAR); - } else if (munitionType == AmmoType.M_MINE_CLEARANCE) { + } else if (munitionType.contains(AmmoType.Munitions.M_MINE_CLEARANCE)) { return new HexTarget(pos, Targetable.TYPE_HEX_CLEAR); } } diff --git a/megamek/src/megamek/client/ui/swing/MapMenu.java b/megamek/src/megamek/client/ui/swing/MapMenu.java index a5fa11b74c4..134b9652497 100644 --- a/megamek/src/megamek/client/ui/swing/MapMenu.java +++ b/megamek/src/megamek/client/ui/swing/MapMenu.java @@ -442,7 +442,7 @@ JMenuItem createUnitEditorMenuItem(Entity entity) { }); return item; } - + private JMenu createSelectMenu() { JMenu menu = new JMenu("Select"); // add select options @@ -1105,16 +1105,16 @@ private JMenu createTargetMenu() { if ((hasAmmoType(AmmoType.T_LRM) || hasAmmoType(AmmoType.T_LRM_IMP) || hasAmmoType(AmmoType.T_MML)) - && (hasMunitionType(AmmoType.M_FASCAM) - || hasMunitionType(AmmoType.M_THUNDER) - || hasMunitionType(AmmoType.M_THUNDER_ACTIVE) - || hasMunitionType(AmmoType.M_THUNDER_AUGMENTED) - || hasMunitionType(AmmoType.M_THUNDER_INFERNO) - || hasMunitionType(AmmoType.M_THUNDER_VIBRABOMB))) { + && (hasMunitionType(AmmoType.Munitions.M_FASCAM) + || hasMunitionType(AmmoType.Munitions.M_THUNDER) + || hasMunitionType(AmmoType.Munitions.M_THUNDER_ACTIVE) + || hasMunitionType(AmmoType.Munitions.M_THUNDER_AUGMENTED) + || hasMunitionType(AmmoType.Munitions.M_THUNDER_INFERNO) + || hasMunitionType(AmmoType.Munitions.M_THUNDER_VIBRABOMB))) { menu.add(TargetMenuItem(new HexTarget(coords, Targetable.TYPE_MINEFIELD_DELIVER))); } - if (hasMunitionType(AmmoType.M_FLARE)) { + if (hasMunitionType(AmmoType.Munitions.M_FLARE)) { menu.add(TargetMenuItem(new HexTarget(coords, Targetable.TYPE_FLARE_DELIVER))); } @@ -1234,13 +1234,13 @@ private boolean hasWeaponFlag(BigInteger weaponFlag) { return false; } - private boolean hasMunitionType(long munition) { + private boolean hasMunitionType(AmmoType.Munitions munition) { if (myEntity.getAmmo().isEmpty()) { return false; } for (Mounted ammo : myEntity.getAmmo()) { - if (((AmmoType) ammo.getType()).getMunitionType() == munition) { + if (((AmmoType) ammo.getType()).getMunitionType().contains(munition)) { return true; } } diff --git a/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java b/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java index c6b22fbb08d..7cfd329c342 100644 --- a/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java +++ b/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java @@ -744,18 +744,18 @@ && ce().isUsingSearchlight()) { Mounted ammoMount = mounted.getLinked(); AmmoType ammoType = (AmmoType) ammoMount.getType(); waa.setAmmoId(ammoMount.getEntity().getEquipmentNum(ammoMount)); - long ammoMunitionType = ammoType.getMunitionType(); + EnumSet ammoMunitionType = ammoType.getMunitionType(); waa.setAmmoMunitionType(ammoMunitionType); waa.setAmmoCarrier(ammoMount.getEntity().getId()); - if (((ammoMunitionType == AmmoType.M_THUNDER_VIBRABOMB) + if (((ammoMunitionType.contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) && ((ammoType.getAmmoType() == AmmoType.T_LRM) || (ammoType.getAmmoType() == AmmoType.T_LRM_IMP) || (ammoType.getAmmoType() == AmmoType.T_MML))) - || (ammoType.getMunitionType() == AmmoType.M_VIBRABOMB_IV)) { + || (ammoType.getMunitionType().contains(AmmoType.Munitions.M_VIBRABOMB_IV))) { VibrabombSettingDialog vsd = new VibrabombSettingDialog(clientgui.frame); vsd.setVisible(true); waa.setOtherAttackInfo(vsd.getSetting()); - waa.setHomingShot(ammoType.getMunitionType() == AmmoType.M_HOMING && ammoMount.curMode().equals("Homing")); + waa.setHomingShot(ammoType.getMunitionType().contains(AmmoType.Munitions.M_HOMING) && ammoMount.curMode().equals("Homing")); } } diff --git a/megamek/src/megamek/client/ui/swing/StatusBarPhaseDisplay.java b/megamek/src/megamek/client/ui/swing/StatusBarPhaseDisplay.java index 40fee9be54a..235e6e3dfc5 100644 --- a/megamek/src/megamek/client/ui/swing/StatusBarPhaseDisplay.java +++ b/megamek/src/megamek/client/ui/swing/StatusBarPhaseDisplay.java @@ -44,7 +44,7 @@ /** * This is a parent class for the button display for each phase. Every phase * has a panel of control buttons along with a Done button. Each button - * correspondes to a command that can be carried out in the current phase. + * corresponds to a command that can be carried out in the current phase. * This class formats the button panel, the done button, and a status display area. * Control buttons are grouped and the groups can be cycled through. */ diff --git a/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java b/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java index 7409807d6dc..e495921c105 100644 --- a/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java +++ b/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java @@ -859,10 +859,10 @@ public void updateDisplayForPendingAttack(Mounted mounted, WeaponAttackAction wa && (((WeaponType) mounted.getType()).getAmmoType() != AmmoType.T_NA)) { Mounted ammoMount = mounted.getLinked(); waa.setAmmoId(ammoMount.getEntity().getEquipmentNum(ammoMount)); - long ammoMunitionType = ((AmmoType) ammoMount.getType()).getMunitionType(); + EnumSet ammoMunitionType = ((AmmoType) ammoMount.getType()).getMunitionType(); waa.setAmmoMunitionType(ammoMunitionType); waa.setAmmoCarrier(ammoMount.getEntity().getId()); - if (ammoMunitionType == AmmoType.M_VIBRABOMB_IV) { + if (ammoMunitionType.contains(AmmoType.Munitions.M_VIBRABOMB_IV)) { VibrabombSettingDialog vsd = new VibrabombSettingDialog(clientgui.frame); vsd.setVisible(true); waa.setOtherAttackInfo(vsd.getSetting()); diff --git a/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java b/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java index 3e3b0be4086..aa3033e350f 100644 --- a/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java +++ b/megamek/src/megamek/client/ui/swing/unitDisplay/WeaponPanel.java @@ -227,7 +227,7 @@ public String getElementAt(int index) { || (en.isSupportVehicle() && (wtype.getAmmoType() == AmmoType.T_INFANTRY))) { int shotsLeft = 0; int totalShots = 0; - long munition = ((AmmoType) mounted.getLinked().getType()).getMunitionType(); + EnumSet munition = ((AmmoType) mounted.getLinked().getType()).getMunitionType(); for (Mounted current = mounted.getLinked(); current != null; current = current.getLinked()) { if (((AmmoType) current.getType()).getMunitionType() == munition) { shotsLeft += current.getUsableShotsLeft(); @@ -1731,15 +1731,21 @@ private void displaySelected() { int artyDamage = wtype.getRackSize(); damage.append(artyDamage); int falloff = 10; + boolean specialArrowIV = false; if ((mounted.getLinked() != null) && (mounted.getLinked().getType() instanceof AmmoType)) { AmmoType ammoType = (AmmoType) mounted.getLinked().getType(); + specialArrowIV = (ammoType.is(AmmoType.T_ARROW_IV) + && (ammoType.getMunitionType().contains(AmmoType.Munitions.M_ADA) + || ammoType.getMunitionType().contains(AmmoType.Munitions.M_HOMING))); int attackingBA = (entity instanceof BattleArmor) ? ((BattleArmor) entity).getShootingStrength() : -1; falloff = AreaEffectHelper.calculateDamageFallOff(ammoType, attackingBA, false).falloff; } - artyDamage -= falloff; - while ((artyDamage > 0) && (falloff > 0)) { - damage.append('/').append(artyDamage); + if (!specialArrowIV) { artyDamage -= falloff; + while ((artyDamage > 0) && (falloff > 0)) { + damage.append('/').append(artyDamage); + artyDamage -= falloff; + } } wDamR.setText(damage.toString()); } else if (wtype.hasFlag(WeaponType.F_ENERGY) @@ -2015,9 +2021,9 @@ private void setFieldOfFire(Mounted mounted) { || (wtype.getAmmoType() == AmmoType.T_LRM) || (wtype.getAmmoType() == AmmoType.T_LRM_IMP) || (wtype.getAmmoType() == AmmoType.T_MML)) { - if (atype.getMunitionType() == AmmoType.M_TORPEDO) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_TORPEDO)) { ranges[1] = wtype.getRanges(mounted); - } else if (atype.getMunitionType() == AmmoType.M_MULTI_PURPOSE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_MULTI_PURPOSE)) { ranges[1] = wtype.getRanges(mounted); } } @@ -2039,10 +2045,12 @@ private void setFieldOfFire(Mounted mounted) { // 6 to 17 in the other phases as it will be // direct fire then if (wtype.hasFlag(WeaponType.F_ARTILLERY)) { + boolean isADA = (mounted.getLinked() != null + && ((AmmoType) mounted.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_ADA)); if (gui.getCurrentPanel() instanceof TargetingPhaseDisplay) { - ranges[0] = new int[] { 0, 0, 0, 100, 0 }; + ranges[0] = (!isADA? new int[] { 0, 0, 0, 100, 0 } : new int[] { 0, 0, 0, 51, 0 }); } else { - ranges[0] = new int[] { 6, 0, 0, 17, 0 }; + ranges[0] = (!isADA? new int[] { 6, 0, 0, 17, 0 } : wtype.getRanges(mounted)); } ranges[1] = new int[] { 0, 0, 0, 0, 0 }; } @@ -2050,33 +2058,33 @@ private void setFieldOfFire(Mounted mounted) { // Override for the various ATM and MML ammos if (atype != null) { if (atype.getAmmoType() == AmmoType.T_ATM) { - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { ranges[0] = new int[] { 4, 9, 18, 27, 36 }; - } else if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { ranges[0] = new int[] { 0, 3, 6, 9, 12 }; } else { ranges[0] = new int[] { 4, 5, 10, 15, 20 }; } } else if (atype.getAmmoType() == AmmoType.T_MML) { if (atype.hasFlag(AmmoType.F_MML_LRM)) { - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { ranges[0] = new int[] { 4, 5, 10, 15, 20 }; } else { ranges[0] = new int[] { 6, 7, 14, 21, 28 }; } } else { - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { ranges[0] = new int[] { 0, 2, 4, 6, 8 }; } else { ranges[0] = new int[] { 0, 3, 6, 9, 12 }; } } } else if (atype.getAmmoType() == AmmoType.T_IATM) { - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { ranges[0] = new int[] { 4, 9, 18, 27, 36 }; - } else if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { ranges[0] = new int[] { 0, 3, 6, 9, 12 }; - } else if (atype.getMunitionType() == AmmoType.M_IATM_IMP) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IMP)) { ranges[0] = new int[] { 0, 3, 6, 9, 12 }; } else { ranges[0] = new int[] { 4, 5, 10, 15, 20 }; @@ -2109,9 +2117,9 @@ private void setFieldOfFire(Mounted mounted) { if (atype != null) { if (atype.getAmmoType() == AmmoType.T_ATM) { - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { maxr = WeaponType.RANGE_EXT; - } else if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { maxr = WeaponType.RANGE_SHORT; } } else if (atype.getAmmoType() == AmmoType.T_MML) { @@ -2205,13 +2213,13 @@ private void updateRangeDisplayForAmmo(Mounted mAmmo) { AmmoType atype = (AmmoType) mAmmo.getType(); // Only override the display for the various ATM and MML ammos if (atype.getAmmoType() == AmmoType.T_ATM) { - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { wMinR.setText("4"); wShortR.setText("1 - 9"); wMedR.setText("10 - 18"); wLongR.setText("19 - 27"); wExtR.setText("28 - 36"); - } else if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { wMinR.setText("---"); wShortR.setText("1 - 3"); wMedR.setText("4 - 6"); @@ -2226,7 +2234,7 @@ private void updateRangeDisplayForAmmo(Mounted mAmmo) { } } else if (atype.getAmmoType() == AmmoType.T_MML) { if (atype.hasFlag(AmmoType.F_MML_LRM)) { - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { wMinR.setText("4"); wShortR.setText("1 - 5"); wMedR.setText("6 - 10"); @@ -2240,7 +2248,7 @@ private void updateRangeDisplayForAmmo(Mounted mAmmo) { wExtR.setText("21 - 28"); } } else { - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { wMinR.setText("---"); wShortR.setText("1 - 2"); wMedR.setText("3 - 4"); @@ -2255,25 +2263,25 @@ private void updateRangeDisplayForAmmo(Mounted mAmmo) { } } } else if (atype.getAmmoType() == AmmoType.T_IATM) { - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { wMinR.setText("4"); wShortR.setText("1 - 9"); wMedR.setText("10 - 18"); wLongR.setText("19 - 27"); wExtR.setText("28 - 36"); - } else if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { wMinR.setText("---"); wShortR.setText("1 - 3"); wMedR.setText("4 - 6"); wLongR.setText("7 - 9"); wExtR.setText("10 - 12"); - } else if (atype.getMunitionType() == AmmoType.M_IATM_IIW) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IIW)) { wMinR.setText("4"); wShortR.setText("1 - 5"); wMedR.setText("6 - 10"); wLongR.setText("11 - 15"); wExtR.setText("16 - 20"); - } else if (atype.getMunitionType() == AmmoType.M_IATM_IMP) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IMP)) { wMinR.setText("---"); wShortR.setText("1 - 3"); wMedR.setText("4 - 6"); @@ -2286,18 +2294,28 @@ private void updateRangeDisplayForAmmo(Mounted mAmmo) { wLongR.setText("11 - 15"); wExtR.setText("16 - 20"); } - } else if ((atype.getAmmoType() == AmmoType.T_LRM) && (atype.getMunitionType() == AmmoType.M_DEAD_FIRE)) { + } else if ((atype.getAmmoType() == AmmoType.T_LRM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE))) { wMinR.setText("4"); wShortR.setText("1 - 5"); wMedR.setText("6 - 10"); wLongR.setText("11 - 15"); wExtR.setText("16 - 20"); - } else if ((atype.getAmmoType() == AmmoType.T_SRM) && (atype.getMunitionType() == AmmoType.M_DEAD_FIRE)) { + } else if ((atype.getAmmoType() == AmmoType.T_SRM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE))) { wMinR.setText("---"); wShortR.setText("1 - 2"); wMedR.setText("3 - 4"); wLongR.setText("5 - 6"); wExtR.setText("7 - 8"); + } else if (atype.getAmmoType() == AmmoType.T_ARROW_IV) { + // Special casing for ADA ranges + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ADA)) { + wMinR.setText("---"); + wShortR.setText("1 - 17 [0]"); + wMedR.setText("18 - 34 [1]"); + wLongR.setText("35 - 51 [2]"); + wExtR.setText("---"); + } + } // Min range 0 for hotload @@ -2391,13 +2409,13 @@ private double[] changeAttackValues(AmmoType atype, double avShort, double avMed, double avLong, double avExt, int maxr) { if (AmmoType.T_ATM == atype.getAmmoType()) { - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { maxr = WeaponType.RANGE_EXT; avShort = avShort / 2; avMed = avMed / 2; avLong = avMed; avExt = avMed; - } else if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { maxr = WeaponType.RANGE_SHORT; avShort = avShort + (avShort / 2); avMed = 0; @@ -2408,7 +2426,7 @@ private double[] changeAttackValues(AmmoType atype, double avShort, else if (atype.getAmmoType() == AmmoType.T_MML) { // first check for artemis int bonus = 0; - if (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE)) { int rack = atype.getRackSize(); if (rack == 5) { bonus += 1; @@ -2432,7 +2450,7 @@ else if ((atype.getAmmoType() == AmmoType.T_LRM) || (atype.getAmmoType() == AmmoType.T_SRM) || (atype.getAmmoType() == AmmoType.T_SRM_IMP)) { - if (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE)) { if ((atype.getAmmoType() == AmmoType.T_LRM) || (atype.getAmmoType() == AmmoType.T_LRM_IMP)) { int bonus = (int) Math.ceil(atype.getRackSize() / 5.0); avShort = avShort + bonus; @@ -2444,7 +2462,7 @@ else if ((atype.getAmmoType() == AmmoType.T_LRM) } } } else if (atype.getAmmoType() == AmmoType.T_AC_LBX) { - if (atype.getMunitionType() == AmmoType.M_CLUSTER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { int newAV = (int) Math.floor(0.6 * atype.getRackSize()); avShort = newAV; if (avMed > 0) { diff --git a/megamek/src/megamek/common/Aero.java b/megamek/src/megamek/common/Aero.java index 6a96d60d14d..6828e5c60eb 100644 --- a/megamek/src/megamek/common/Aero.java +++ b/megamek/src/megamek/common/Aero.java @@ -302,6 +302,11 @@ public void setDesignType(int design) { designType = design; } + @Override + public void setDestroyed(boolean destroyed) { + this.destroyed = destroyed; + land(); + } /** * Returns the unit's design type */ diff --git a/megamek/src/megamek/common/AmmoType.java b/megamek/src/megamek/common/AmmoType.java index a755b50b52e..f1a657e8d2f 100644 --- a/megamek/src/megamek/common/AmmoType.java +++ b/megamek/src/megamek/common/AmmoType.java @@ -191,124 +191,124 @@ public class AmmoType extends EquipmentType { public static final BigInteger F_SCREEN = BigInteger.valueOf(1).shiftLeft(18); // ammo munitions, used for custom loadouts - // N.B. we play bit-shifting games to allow "incendiary" + // N.B. We use EnumSet allow "incendiary" // to be combined to other munition types. - - // M_STANDARD can be used for anything. - public static final long M_STANDARD = 0; - - // AC Munition Types - public static final long M_CLUSTER = 1L << 0; - public static final long M_ARMOR_PIERCING = 1L << 1; - public static final long M_FLECHETTE = 1L << 2; - public static final long M_INCENDIARY_AC = 1L << 3; - public static final long M_PRECISION = 1L << 4; - public static final long M_TRACER = 1L << 5; - public static final long M_FLAK = 1L << 6; - public static final long M_CASELESS = 1L << 62; - - // ATM Munition Types - public static final long M_EXTENDED_RANGE = 1L << 7; - public static final long M_HIGH_EXPLOSIVE = 1L << 8; - public static final long M_IATM_IMP = 1L << 57; - public static final long M_IATM_IIW = 1L << 58; - - // LRM & SRM Munition Types - public static final long M_FRAGMENTATION = 1L << 9; - public static final long M_LISTEN_KILL = 1L << 10; - public static final long M_ANTI_TSM = 1L << 11; - public static final long M_NARC_CAPABLE = 1L << 12; - public static final long M_ARTEMIS_CAPABLE = 1L << 13; - public static final long M_DEAD_FIRE = 1L << 14; - public static final long M_HEAT_SEEKING = 1L << 15; - public static final long M_TANDEM_CHARGE = 1L << 16; - public static final long M_ARTEMIS_V_CAPABLE = 1L << 17; - public static final long M_SMOKE_WARHEAD = 1L << 18; - // Mine Clearance munition type defined later, to maintain order - - // LRM Munition Types - // Incendiary is special, though... - // FIXME - I'm not implemented!!! - public static final long M_INCENDIARY_LRM = 1L << 19; - public static final long M_FLARE = 1L << 20; - public static final long M_SEMIGUIDED = 1L << 21; - public static final long M_SWARM = 1L << 22; - public static final long M_SWARM_I = 1L << 23; - public static final long M_THUNDER = 1L << 24; - public static final long M_THUNDER_AUGMENTED = 1L << 25; - public static final long M_THUNDER_INFERNO = 1L << 26; - public static final long M_THUNDER_VIBRABOMB = 1L << 27; - public static final long M_THUNDER_ACTIVE = 1L << 28; - public static final long M_FOLLOW_THE_LEADER = 1L << 29; - public static final long M_MULTI_PURPOSE = 1L << 30; - // SRM Munition Types - // TODO: Inferno should be available to fluid guns and vehicle flamers - // TO page 362 - public static final long M_INFERNO = 1L << 31; - public static final long M_AX_HEAD = 1L << 32; - // HARPOON - - // SRM, MRM and LRM - public static final long M_TORPEDO = 1L << 33; - - // iNarc Munition Types - public static final long M_NARC_EX = 1L << 34; - public static final long M_ECM = 1L << 35; - public static final long M_HAYWIRE = 1L << 36; - public static final long M_NEMESIS = 1L << 37; - - public static final long M_EXPLOSIVE = 1L << 38; - - // Arrow IV Munition Types - public static final long M_HOMING = 1L << 39; - public static final long M_FASCAM = 1L << 40; - public static final long M_INFERNO_IV = 1L << 41; - public static final long M_VIBRABOMB_IV = 1L << 42; -// public static final long M_ACTIVE_IV - public static final long M_SMOKE = 1L << 43; - public static final long M_LASER_INHIB = 1L << 44; - - // Nuclear Munitions - public static final long M_DAVY_CROCKETT_M = 1L << 45; -// public static final long M_SANTA_ANNA = 1L << 46; - - // fluid gun - // TODO: implement all of these except coolant - // water should also be used for vehicle flamers - // TO page 361-363 - public static final long M_WATER = 1L << 48; - public static final long M_PAINT_OBSCURANT = 1L << 49; - public static final long M_OIL_SLICK = 1L << 50; - public static final long M_ANTI_FLAME_FOAM = 1L << 51; - public static final long M_CORROSIVE = 1L << 52; - public static final long M_COOLANT = 1L << 53; - - // vehicular grenade launcher - public static final long M_CHAFF = 1L << 54; - public static final long M_INCENDIARY = 1L << 55; - // Number 56 was M_SMOKEGRENADE, but that has now been merged with M_SMOKE - - // Number 57 is used for iATMs IMP ammo in the ATM section above. - // and 58 for IIW - - // Mek mortar munitions - public static final long M_AIRBURST = 1L << 59; - public static final long M_ANTI_PERSONNEL = 1L << 60; - // The rest were already defined - // Flare - // Semi-guided - // Smoke - - // More SRM+LRM Munitions types - public static final long M_MINE_CLEARANCE = 1L << 61; - - // note that 62 is in use above - // this area is a primary target for the introduction of an enum or some other - // kind of refactoring - public static final long M_FAE = 1L << 63; - - // If you want to add another munition type, tough luck: longs can only be - // bit-shifted 63 times. + public enum Munitions{ + M_STANDARD, + + // AC Munition Types + M_CLUSTER, + M_ARMOR_PIERCING, + M_FLECHETTE, + M_INCENDIARY_AC, + M_PRECISION, + M_TRACER, + M_FLAK, + M_CASELESS, + + // ATM Munition Types + M_EXTENDED_RANGE, + M_HIGH_EXPLOSIVE, + M_IATM_IMP, + M_IATM_IIW, + + // LRM & SRM Munition Types + M_FRAGMENTATION, + M_LISTEN_KILL, + M_ANTI_TSM, + M_NARC_CAPABLE, + M_ARTEMIS_CAPABLE, + M_DEAD_FIRE, + M_HEAT_SEEKING, + M_TANDEM_CHARGE, + M_ARTEMIS_V_CAPABLE, + M_SMOKE_WARHEAD, + // Mine Clearance munition type defined later, to maintain order + + // LRM Munition Types + // Incendiary is special, though... + // FIXME - I'm not implemented!!! + M_INCENDIARY_LRM, + M_FLARE, + M_SEMIGUIDED, + M_SWARM, + M_SWARM_I, + M_THUNDER, + M_THUNDER_AUGMENTED, + M_THUNDER_INFERNO, + M_THUNDER_VIBRABOMB, + M_THUNDER_ACTIVE, + M_FOLLOW_THE_LEADER, + M_MULTI_PURPOSE, + + // SRM Munition Types + // TODO: Inferno should be available to fluid guns and vehicle flamers + // TO page 362 + M_INFERNO, + M_AX_HEAD, + // HARPOON + + // SRM, MRM and LRM + M_TORPEDO, + + // iNarc Munition Types + M_NARC_EX, + M_ECM, + M_HAYWIRE, + M_NEMESIS, + + M_EXPLOSIVE, + + // Arrow IV Munition Types + M_HOMING, + M_FASCAM, + M_INFERNO_IV, + M_VIBRABOMB_IV, + M_ADA, + + // M_ACTIVE_IV + M_SMOKE, + M_LASER_INHIB, + + // Nuclear Munitions + M_DAVY_CROCKETT_M, + // M_SANTA_ANNA, + + // fluid gun + // TODO: implement all of these except coolant + // water should also be used for vehicle flamers + // TO page 361-363 + M_WATER, + M_PAINT_OBSCURANT, + M_OIL_SLICK, + M_ANTI_FLAME_FOAM, + M_CORROSIVE, + M_COOLANT, + + // vehicular grenade launcher + M_CHAFF, + M_INCENDIARY, + // Number 56 was M_SMOKEGRENADE, but that has now been merged with M_SMOKE + + // Number 57 is used for iATMs IMP ammo in the ATM section above. + // and 58 for IIW + + // Mek mortar munitions + M_AIRBURST, + M_ANTI_PERSONNEL, + // The rest were already defined + // Flare + // Semi-guided + // Smoke + + // More SRM+LRM Munitions types + M_MINE_CLEARANCE, + + // note that 62 is in use above + // this area is a primary target for the introduction of an enum or some other + // kind of refactoring + M_FAE + } private static Vector[] m_vaMunitions = new Vector[NUM_TYPES]; @@ -319,7 +319,7 @@ public static Vector getMunitionsFor(int nAmmoType) { protected int damagePerShot; protected int rackSize; protected int ammoType; - protected long munitionType; + protected EnumSet munitionType = EnumSet.of(Munitions.M_STANDARD); protected int shots; private double kgPerShot = -1; @@ -335,7 +335,7 @@ public static Vector getMunitionsFor(int nAmmoType) { // Add ADA here when implemented private int[] ARTILLERY_TYPES = {T_LONG_TOM, T_SNIPER, T_THUMPER, T_ARROW_IV}; private int[] ARTILLERY_CANNON_TYPES = {T_LONG_TOM_CANNON, T_SNIPER_CANNON, T_THUMPER_CANNON}; - private long[] ARTILLERY_FLAK_MUNITIONS = {M_CLUSTER, M_STANDARD}; + private EnumSet ARTILLERY_FLAK_MUNITIONS = EnumSet.of(Munitions.M_CLUSTER, Munitions.M_STANDARD); public AmmoType() { criticals = 1; @@ -448,20 +448,23 @@ public boolean is(int ammoType) { * We need a way to quickly determine if a given ammo type / munition counts as "Flak" * Note, not _is_ Flak (as in the case of M_FLAK) but can be considered Flak by TW/TO/IO * rules. + * Arrow IV missiles with M_CLUSTER, M_ADA, or M_STANDARD (not M_HOMING) count as Flak (TO:AU&E pp166-167, 224) * @return counts true if this ammo can be considered Flak in some situations */ public boolean countsAsFlak() { boolean counts = false; if(ArrayUtils.contains(ARTILLERY_TYPES, this.getAmmoType())){ - counts = ArrayUtils.contains(ARTILLERY_FLAK_MUNITIONS, this.getMunitionType()); + // Air-Defense Arrow IV _is_ Flak, but is _not_ Artillery + counts = ARTILLERY_FLAK_MUNITIONS.containsAll(this.getMunitionType()) + || this.getMunitionType().contains(Munitions.M_ADA); } else if(ArrayUtils.contains(ARTILLERY_CANNON_TYPES, this.getAmmoType())){ - counts = this.getMunitionType() == AmmoType.M_STANDARD; + counts = this.getMunitionType().contains(Munitions.M_STANDARD); } return counts; } - public long getMunitionType() { + public EnumSet getMunitionType() { return munitionType; } @@ -519,16 +522,16 @@ public boolean canAeroUse() { switch (ammoType) { case T_AC_LBX: case T_SBGAUSS: - return munitionType == M_CLUSTER; + return munitionType.contains(Munitions.M_CLUSTER); case T_ATM: case T_IATM: - return (munitionType == M_STANDARD) || (munitionType == M_HIGH_EXPLOSIVE) - || (munitionType == M_EXTENDED_RANGE); + return (munitionType.contains(Munitions.M_STANDARD)) || (munitionType.contains(Munitions.M_HIGH_EXPLOSIVE)) + || (munitionType.contains(Munitions.M_EXTENDED_RANGE)); case T_AR10: return true; default: - return (munitionType == M_STANDARD) || (munitionType == M_ARTEMIS_CAPABLE) - || (munitionType == M_ARTEMIS_V_CAPABLE); + return (munitionType.contains(Munitions.M_STANDARD)) || (munitionType.contains(Munitions.M_ARTEMIS_CAPABLE)) + || (munitionType.contains(Munitions.M_ARTEMIS_V_CAPABLE)); } } @@ -548,31 +551,31 @@ public boolean canAeroUse(boolean option) { switch (ammoType) { case T_AC_LBX: case T_SBGAUSS: - return munitionType == M_CLUSTER; + return munitionType.contains(Munitions.M_CLUSTER); case T_ATM: case T_IATM: - return (munitionType == M_STANDARD) || (munitionType == M_HIGH_EXPLOSIVE) - || (munitionType == M_EXTENDED_RANGE); + return (munitionType.contains(Munitions.M_STANDARD)) || (munitionType.contains(Munitions.M_HIGH_EXPLOSIVE)) + || (munitionType.contains(Munitions.M_EXTENDED_RANGE)); case T_AR10: return true; case T_ARROW_IV: - return (munitionType == M_FLARE) || (munitionType == M_CLUSTER) || (munitionType == M_HOMING) - || (munitionType == M_INFERNO_IV) || (munitionType == M_LASER_INHIB) - || (munitionType == M_SMOKE) || (munitionType == M_FASCAM) - || (munitionType == M_DAVY_CROCKETT_M) || (munitionType == M_VIBRABOMB_IV) - || (munitionType == M_STANDARD); + return (munitionType.contains(Munitions.M_FLARE)) || (munitionType.contains(Munitions.M_CLUSTER)) || (munitionType.contains(Munitions.M_HOMING)) + || (munitionType.contains(Munitions.M_INFERNO_IV)) || (munitionType.contains(Munitions.M_LASER_INHIB)) + || (munitionType.contains(Munitions.M_SMOKE)) || (munitionType.contains(Munitions.M_FASCAM)) + || (munitionType.contains(Munitions.M_DAVY_CROCKETT_M)) || (munitionType.contains(Munitions.M_VIBRABOMB_IV)) + || (munitionType.contains(Munitions.M_STANDARD)); case T_LONG_TOM: - return (munitionType == M_FLARE) || (munitionType == M_CLUSTER) || (munitionType == M_HOMING) - || (munitionType == M_FLECHETTE) || (munitionType == M_SMOKE) || (munitionType == M_FASCAM) - || (munitionType == M_DAVY_CROCKETT_M) || (munitionType == M_STANDARD); + return (munitionType.contains(Munitions.M_FLARE)) || (munitionType.contains(Munitions.M_CLUSTER)) || (munitionType.contains(Munitions.M_HOMING)) + || (munitionType.contains(Munitions.M_FLECHETTE)) || (munitionType.contains(Munitions.M_SMOKE)) || (munitionType.contains(Munitions.M_FASCAM)) + || (munitionType.contains(Munitions.M_DAVY_CROCKETT_M)) || (munitionType.contains(Munitions.M_STANDARD)); case T_SNIPER: case T_THUMPER: - return (munitionType == M_FLARE) || (munitionType == M_CLUSTER) || (munitionType == M_HOMING) - || (munitionType == M_FLECHETTE) || (munitionType == M_SMOKE) || (munitionType == M_FASCAM) - || (munitionType == M_STANDARD); + return (munitionType.contains(Munitions.M_FLARE)) || (munitionType.contains(Munitions.M_CLUSTER)) || (munitionType.contains(Munitions.M_HOMING)) + || (munitionType.contains(Munitions.M_FLECHETTE)) || (munitionType.contains(Munitions.M_SMOKE)) || (munitionType.contains(Munitions.M_FASCAM)) + || (munitionType.contains(Munitions.M_STANDARD)); default: - return (munitionType == M_STANDARD) || (munitionType == M_ARTEMIS_CAPABLE) - || (munitionType == M_ARTEMIS_V_CAPABLE); + return (munitionType.contains(Munitions.M_STANDARD)) || (munitionType.contains(Munitions.M_ARTEMIS_CAPABLE)) + || (munitionType.contains(Munitions.M_ARTEMIS_V_CAPABLE)); } } else { return canAeroUse(); @@ -1311,7 +1314,7 @@ public static void initializeTypes() { clanMortarAmmos.add(base); // Create the munition types for IS Mek mortars - munitions.add(new MunitionMutator("Airburst", 1, M_AIRBURST, + munitions.add(new MunitionMutator("Airburst", 1, Munitions.M_AIRBURST, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_B, RATING_D, RATING_C, RATING_D) .setISAdvancement(2540, 2544, DATE_NONE, 2819, 3043) @@ -1319,7 +1322,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("Anti-personnel", 1, M_ANTI_PERSONNEL, + munitions.add(new MunitionMutator("Anti-personnel", 1, Munitions.M_ANTI_PERSONNEL, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setISAdvancement(2526, 2531, 3052, 2819, 3043) @@ -1330,13 +1333,13 @@ public static void initializeTypes() { // Armor Piercing is the base ammo type see further down. - munitions.add(new MunitionMutator("Flare", 1, M_FLARE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) + munitions.add(new MunitionMutator("Flare", 1, Munitions.M_FLARE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_B).setAvailability(RATING_A, RATING_A, RATING_A, RATING_A) .setISAdvancement(2533, 2536, DATE_NONE, 2819, 3043).setISApproximate(true, false, false, false, false) .setPrototypeFactions(F_TH).setProductionFactions(F_TH).setReintroductionFactions(F_FS, F_LC) .setStaticTechLevel(SimpleTechLevel.ADVANCED), "374, TO")); - munitions.add(new MunitionMutator("Semi-Guided", 1, M_SEMIGUIDED, + munitions.add(new MunitionMutator("Semi-Guided", 1, Munitions.M_SEMIGUIDED, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setISAdvancement(3055, 3064, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1344,7 +1347,7 @@ public static void initializeTypes() { .setProductionFactions(F_FW).setStaticTechLevel(SimpleTechLevel.ADVANCED), "374, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE_WARHEAD, + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE_WARHEAD, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_A, RATING_A, RATING_A, RATING_A) .setISAdvancement(2526, 2531, DATE_NONE, 2819, 3043) @@ -1359,7 +1362,7 @@ public static void initializeTypes() { // Create the munition types for Clan Mek mortars munitions.clear(); - munitions.add(new MunitionMutator("Airburst", 1, M_AIRBURST, + munitions.add(new MunitionMutator("Airburst", 1, Munitions.M_AIRBURST, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_B, RATING_D, RATING_C, RATING_D) .setClanAdvancement(2540, 2544, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1367,7 +1370,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("Anti-personnel", 1, M_ANTI_PERSONNEL, + munitions.add(new MunitionMutator("Anti-personnel", 1, Munitions.M_ANTI_PERSONNEL, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setClanAdvancement(2540, 2544, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1377,7 +1380,7 @@ public static void initializeTypes() { // Armor Piercing is the base ammo type see further down. - munitions.add(new MunitionMutator("Flare", 1, M_FLARE, + munitions.add(new MunitionMutator("Flare", 1, Munitions.M_FLARE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_A, RATING_A, RATING_A, RATING_A) .setClanAdvancement(2533, 2536, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1385,7 +1388,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "374, TO")); - munitions.add(new MunitionMutator("Semi-Guided", 1, M_SEMIGUIDED, + munitions.add(new MunitionMutator("Semi-Guided", 1, Munitions.M_SEMIGUIDED, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setClanAdvancement(3055, 3064, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1393,7 +1396,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "374, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE_WARHEAD, + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE_WARHEAD, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_A, RATING_A, RATING_A, RATING_A) .setClanAdvancement(2526, 2531, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1483,14 +1486,14 @@ public static void initializeTypes() { // Create the munition types for IS SRM launchers. munitions.clear(); - munitions.add(new MunitionMutator("Acid", 2, M_AX_HEAD, + munitions.add(new MunitionMutator("Acid", 2, Munitions.M_AX_HEAD, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F).setISAdvancement(3053) .setPrototypeFactions(F_FS, F_LC).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "367, TO")); /* - * munitions.add(new MunitionMutator("Harpoon", 2, M_HARPOON, new + * munitions.add(new MunitionMutator("Harpoon", 2, Munitions.M_HARPOON, new * TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false). * setTechRating(RATING_C) .setAvailability(RATING_C, RATING_C, RATING_C, * RATING_C) .setISAdvancement(2395, 2400, 2415, DATE_NONE, DATE_NONE) @@ -1498,7 +1501,7 @@ public static void initializeTypes() { * false).setPrototypeFactions(F_LC) .setProductionFactions(F_LC), "369, TO")); */ - munitions.add(new MunitionMutator("Heat-Seeking", 2, M_HEAT_SEEKING, + munitions.add(new MunitionMutator("Heat-Seeking", 2, Munitions.M_HEAT_SEEKING, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_E, RATING_E, RATING_F) .setISAdvancement(2365, 2370, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1506,7 +1509,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "369, TO")); - munitions.add(new MunitionMutator("Inferno", 1, M_INFERNO, + munitions.add(new MunitionMutator("Inferno", 1, Munitions.M_INFERNO, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setISAdvancement(2370, 2380, 2400, DATE_NONE, DATE_NONE) @@ -1514,7 +1517,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.STANDARD), "231, TM")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE_WARHEAD, + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE_WARHEAD, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setISAdvancement(2333, 2370, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1522,7 +1525,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "371, TO")); - munitions.add(new MunitionMutator("Tandem-Charge", 2, M_TANDEM_CHARGE, + munitions.add(new MunitionMutator("Tandem-Charge", 2, Munitions.M_TANDEM_CHARGE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(2757, 3062, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1535,7 +1538,7 @@ public static void initializeTypes() { // TODO Retro-Streak IO pg 132 - munitions.add(new MunitionMutator("Anti-TSM", 1, M_ANTI_TSM, + munitions.add(new MunitionMutator("Anti-TSM", 1, Munitions.M_ANTI_TSM, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) .setISAdvancement(3026, 3027, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1543,7 +1546,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "104, IO")); - munitions.add(new MunitionMutator("Artemis-capable", 1, M_ARTEMIS_CAPABLE, + munitions.add(new MunitionMutator("Artemis-capable", 1, Munitions.M_ARTEMIS_CAPABLE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setISAdvancement(2592, 2598, 3045, 2855, 3035) @@ -1551,13 +1554,13 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.STANDARD), "230, TM")); - munitions.add(new MunitionMutator("Dead-Fire", 1, M_DEAD_FIRE, + munitions.add(new MunitionMutator("Dead-Fire", 1, Munitions.M_DEAD_FIRE, new TechAdvancement(TECH_BASE_IS).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E).setISAdvancement(3052) .setPrototypeFactions(F_DC).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "131, IO")); - munitions.add(new MunitionMutator("Fragmentation", 1, M_FRAGMENTATION, + munitions.add(new MunitionMutator("Fragmentation", 1, Munitions.M_FRAGMENTATION, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(2375, 2377, 3058, 2790, 3054) @@ -1565,7 +1568,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "230, TM")); - munitions.add(new MunitionMutator("Listen-Kill", 1, M_LISTEN_KILL, + munitions.add(new MunitionMutator("Listen-Kill", 1, Munitions.M_LISTEN_KILL, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_F, RATING_X, RATING_X) .setISAdvancement(3037, DATE_NONE, DATE_NONE, 3040, DATE_NONE) @@ -1575,7 +1578,7 @@ public static void initializeTypes() { // TODO Mag Pulse see IO pg 62 - munitions.add(new MunitionMutator("Mine Clearance", 1, M_MINE_CLEARANCE, + munitions.add(new MunitionMutator("Mine Clearance", 1, Munitions.M_MINE_CLEARANCE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setISAdvancement(3065, 3069, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1583,7 +1586,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.ADVANCED), "370, TO")); - munitions.add(new MunitionMutator("Narc-capable", 1, M_NARC_CAPABLE, + munitions.add(new MunitionMutator("Narc-capable", 1, Munitions.M_NARC_CAPABLE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setISAdvancement(2520, 2587, 3049, 2795, 3035) @@ -1603,14 +1606,14 @@ public static void initializeTypes() { // Create the munition types for Clan SRM launchers. munitions.clear(); - munitions.add(new MunitionMutator("(Clan) Acid", 2, M_AX_HEAD, + munitions.add(new MunitionMutator("(Clan) Acid", 2, Munitions.M_AX_HEAD, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F).setClanAdvancement(3053) .setPrototypeFactions(F_FS, F_LC).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "367, TO")); /* - * munitions.add(new MunitionMutator("Harpoon", 2, M_HARPOON, new + * munitions.add(new MunitionMutator("Harpoon", 2, Munitions.M_HARPOON, new * TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false). * setTechRating(RATING_C) .setAvailability(RATING_C, RATING_C, RATING_C, * RATING_C) .setClanAdvancement(2395, 2400, 2415, DATE_NONE, DATE_NONE) @@ -1618,7 +1621,7 @@ public static void initializeTypes() { * false).setPrototypeFactions(F_LC) .setProductionFactions(F_LC), "369, TO")); */ - munitions.add(new MunitionMutator("(Clan) Heat-Seeking", 2, M_HEAT_SEEKING, + munitions.add(new MunitionMutator("(Clan) Heat-Seeking", 2, Munitions.M_HEAT_SEEKING, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_E, RATING_E, RATING_F) .setClanAdvancement(2365, 2370, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1626,7 +1629,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "369, TO")); - munitions.add(new MunitionMutator("(Clan) Inferno", 1, M_INFERNO, + munitions.add(new MunitionMutator("(Clan) Inferno", 1, Munitions.M_INFERNO, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setClanAdvancement(2370, 2380, 2400, DATE_NONE, DATE_NONE) @@ -1634,7 +1637,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.STANDARD), "231, TM")); - munitions.add(new MunitionMutator("(Clan) Smoke", 1, M_SMOKE_WARHEAD, + munitions.add(new MunitionMutator("(Clan) Smoke", 1, Munitions.M_SMOKE_WARHEAD, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) @@ -1643,7 +1646,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "371, TO")); - munitions.add(new MunitionMutator("(Clan) Tandem-Charge", 2, M_TANDEM_CHARGE, + munitions.add(new MunitionMutator("(Clan) Tandem-Charge", 2, Munitions.M_TANDEM_CHARGE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(2757, DATE_NONE, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1653,7 +1656,7 @@ public static void initializeTypes() { // TODO Tear Gas See IO pg 372 - munitions.add(new MunitionMutator("(Clan) Anti-TSM", 1, M_ANTI_TSM, + munitions.add(new MunitionMutator("(Clan) Anti-TSM", 1, Munitions.M_ANTI_TSM, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) .setClanAdvancement(3026, 3027, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1661,7 +1664,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "104, IO")); - munitions.add(new MunitionMutator("(Clan) Artemis-capable", 1, M_ARTEMIS_CAPABLE, + munitions.add(new MunitionMutator("(Clan) Artemis-capable", 1, Munitions.M_ARTEMIS_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setClanAdvancement(DATE_NONE, DATE_NONE, 2818, DATE_NONE, DATE_NONE) @@ -1670,7 +1673,7 @@ public static void initializeTypes() { "207, TM")); //Tech Progression tweaked to combine IntOps with TRO Prototypes/3145 NTNU RS - munitions.add(new MunitionMutator("(Clan) Artemis V-capable", 1, M_ARTEMIS_V_CAPABLE, + munitions.add(new MunitionMutator("(Clan) Artemis V-capable", 1, Munitions.M_ARTEMIS_V_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_E) .setClanAdvancement(DATE_NONE, 3061, 3085, DATE_NONE, DATE_NONE) @@ -1678,13 +1681,13 @@ public static void initializeTypes() { .setProductionFactions(F_CSF, F_RD).setStaticTechLevel(SimpleTechLevel.ADVANCED), "283, TO")); - munitions.add(new MunitionMutator("(Clan) Dead-Fire", 1, M_DEAD_FIRE, + munitions.add(new MunitionMutator("(Clan) Dead-Fire", 1, Munitions.M_DEAD_FIRE, new TechAdvancement(TECH_BASE_CLAN).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E).setClanAdvancement(3052) .setPrototypeFactions(F_DC).setStaticTechLevel(SimpleTechLevel.UNOFFICIAL), "131, IO")); - munitions.add(new MunitionMutator("(Clan) Fragmentation", 1, M_FRAGMENTATION, + munitions.add(new MunitionMutator("(Clan) Fragmentation", 1, Munitions.M_FRAGMENTATION, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setClanAdvancement(2375, 2377, 3058, DATE_NONE, DATE_NONE) @@ -1692,7 +1695,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "230, TM")); - munitions.add(new MunitionMutator("(Clan) Listen-Kill", 1, M_LISTEN_KILL, + munitions.add(new MunitionMutator("(Clan) Listen-Kill", 1, Munitions.M_LISTEN_KILL, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_X) .setClanAdvancement(3037, DATE_NONE, DATE_NONE, 3040, DATE_NONE) @@ -1702,7 +1705,7 @@ public static void initializeTypes() { // TODO Mag Pulse See IO pg 62 - munitions.add(new MunitionMutator("(Clan) Mine Clearance", 1, M_MINE_CLEARANCE, + munitions.add(new MunitionMutator("(Clan) Mine Clearance", 1, Munitions.M_MINE_CLEARANCE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setClanAdvancement(3065, 3069, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1710,7 +1713,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.ADVANCED), "370, TO")); - munitions.add(new MunitionMutator("(Clan) Narc-capable", 1, M_NARC_CAPABLE, + munitions.add(new MunitionMutator("(Clan) Narc-capable", 1, Munitions.M_NARC_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setClanAdvancement(DATE_NONE, DATE_NONE, 2828, DATE_NONE, DATE_NONE) @@ -1730,7 +1733,7 @@ public static void initializeTypes() { // Create the munition types for CLAN BA SRM launchers. munitions.clear(); - munitions.add(new MunitionMutator("(Clan) Torpedo", 1, M_TORPEDO, + munitions.add(new MunitionMutator("(Clan) Torpedo", 1, Munitions.M_TORPEDO, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setClanAdvancement(DATE_NONE, DATE_NONE, 2828, DATE_NONE, DATE_NONE) @@ -1738,7 +1741,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.STANDARD), "230, TM")); - munitions.add(new MunitionMutator("(Clan) Multi-Purpose", 1, M_MULTI_PURPOSE, + munitions.add(new MunitionMutator("(Clan) Multi-Purpose", 1, Munitions.M_MULTI_PURPOSE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3055, 3060, 3065, DATE_NONE, DATE_NONE) @@ -1752,7 +1755,7 @@ public static void initializeTypes() { // Create the munition types for IS BA LRM launchers. munitions.clear(); - munitions.add(new MunitionMutator("Torpedo", 1, M_TORPEDO, + munitions.add(new MunitionMutator("Torpedo", 1, Munitions.M_TORPEDO, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setISAdvancement(DATE_NONE, DATE_NONE, 3052, DATE_NONE, DATE_NONE) @@ -1767,7 +1770,7 @@ public static void initializeTypes() { // Create the munition types for clan BA LRM launchers. munitions.clear(); - munitions.add(new MunitionMutator("Multi-Purpose", 1, M_MULTI_PURPOSE, + munitions.add(new MunitionMutator("Multi-Purpose", 1, Munitions.M_MULTI_PURPOSE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3055, 3060, 3065, DATE_NONE, DATE_NONE) @@ -1775,7 +1778,7 @@ public static void initializeTypes() { .setProductionFactions(F_CGS).setStaticTechLevel(SimpleTechLevel.STANDARD), "229, TW")); - munitions.add(new MunitionMutator("Torpedo", 1, M_TORPEDO, + munitions.add(new MunitionMutator("Torpedo", 1, Munitions.M_TORPEDO, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setClanAdvancement(DATE_NONE, DATE_NONE, 2828, DATE_NONE, DATE_NONE) @@ -1792,7 +1795,7 @@ public static void initializeTypes() { // TODO Flare LRMs IO pg 230 - munitions.add(new MunitionMutator("Follow The Leader", 2, M_FOLLOW_THE_LEADER, + munitions.add(new MunitionMutator("Follow The Leader", 2, Munitions.M_FOLLOW_THE_LEADER, new TechAdvancement(TECH_BASE_IS).setTechRating(RATING_E) .setAvailability(RATING_F, RATING_X, RATING_E, RATING_X) .setISAdvancement(2750, DATE_NONE, DATE_NONE, 2770, 3046) @@ -1800,7 +1803,7 @@ public static void initializeTypes() { .setReintroductionFactions(F_FS, F_LC).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "368, TO")); - munitions.add(new MunitionMutator("Heat-Seeking", 2, M_HEAT_SEEKING, + munitions.add(new MunitionMutator("Heat-Seeking", 2, Munitions.M_HEAT_SEEKING, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_E, RATING_E, RATING_F) .setISAdvancement(2365, 2370, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1811,7 +1814,7 @@ public static void initializeTypes() { // TODO Incendiary LRMs - IO pg 61, TO pg 369 /* - * munitions.add(new MunitionMutator("Incendiary", 2, M_INCENDIARY_LRM, new + * munitions.add(new MunitionMutator("Incendiary", 2, Munitions.M_INCENDIARY_LRM, new * TechAdvancement(TECH_BASE_IS) .setIntroLevel(false) .setUnofficial(false) * .setTechRating(RATING_C) .setAvailability(RATING_E, RATING_E, RATING_E, * RATING_E) .setClanAdvancement(2341, 2342, 2352, DATE_NONE, DATE_NONE) @@ -1819,7 +1822,7 @@ public static void initializeTypes() { * .setPrototypeFactions(F_TH) .setProductionFactions(F_TH),"369, TO")); */ - munitions.add(new MunitionMutator("Semi-guided", 1, M_SEMIGUIDED, + munitions.add(new MunitionMutator("Semi-guided", 1, Munitions.M_SEMIGUIDED, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_D, RATING_D) .setISAdvancement(3053, 3057, 3065, DATE_NONE, DATE_NONE) @@ -1827,7 +1830,7 @@ public static void initializeTypes() { .setProductionFactions(F_FW).setStaticTechLevel(SimpleTechLevel.STANDARD), "231, TM")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE_WARHEAD, + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE_WARHEAD, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setISAdvancement(2333, 2370, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1837,13 +1840,13 @@ public static void initializeTypes() { //Note of Swarms the intro dates in IntOps are off and it allows Swarm-I to appear before Swarm during the //Clan Invasion. Proposed errata makes 3052 for Swarm-I a hard date, and 3053 for Swarm re-iintroduction a flexible date. - munitions.add(new MunitionMutator("Swarm", 1, M_SWARM, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) + munitions.add(new MunitionMutator("Swarm", 1, Munitions.M_SWARM, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_E).setAvailability(RATING_E, RATING_X, RATING_D, RATING_D) .setISAdvancement(2615, 2621, 3058, 2833, 3053).setISApproximate(true, false, false, false, true) .setPrototypeFactions(F_TH).setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "371, TO")); - munitions.add(new MunitionMutator("Swarm-I", 1, M_SWARM_I, + munitions.add(new MunitionMutator("Swarm-I", 1, Munitions.M_SWARM_I, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_X, RATING_D, RATING_D) .setISAdvancement(3052, 3057, 3066, DATE_NONE, DATE_NONE) @@ -1851,7 +1854,7 @@ public static void initializeTypes() { .setProductionFactions(F_FW).setStaticTechLevel(SimpleTechLevel.ADVANCED), "371, TO")); - munitions.add(new MunitionMutator("Thunder", 1, M_THUNDER, + munitions.add(new MunitionMutator("Thunder", 1, Munitions.M_THUNDER, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_D, RATING_X, RATING_D, RATING_D) .setISAdvancement(2618, 2620, 2650, 2840, 3052) @@ -1860,7 +1863,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("Thunder-Active", 2, M_THUNDER_ACTIVE, + munitions.add(new MunitionMutator("Thunder-Active", 2, Munitions.M_THUNDER_ACTIVE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3054, 3058, 3064, DATE_NONE, DATE_NONE) @@ -1868,7 +1871,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("Thunder-Augmented", 2, M_THUNDER_AUGMENTED, + munitions.add(new MunitionMutator("Thunder-Augmented", 2, Munitions.M_THUNDER_AUGMENTED, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3054, 3057, 3064, DATE_NONE, DATE_NONE) @@ -1876,7 +1879,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("Thunder-Vibrabomb", 2, M_THUNDER_VIBRABOMB, + munitions.add(new MunitionMutator("Thunder-Vibrabomb", 2, Munitions.M_THUNDER_VIBRABOMB, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3054, 3056, 3064, DATE_NONE, DATE_NONE) @@ -1884,7 +1887,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("Thunder-Inferno", 2, M_THUNDER_INFERNO, + munitions.add(new MunitionMutator("Thunder-Inferno", 2, Munitions.M_THUNDER_INFERNO, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3054, 3056, 3062, DATE_NONE, DATE_NONE) @@ -1892,7 +1895,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("Anti-TSM", 1, M_ANTI_TSM, + munitions.add(new MunitionMutator("Anti-TSM", 1, Munitions.M_ANTI_TSM, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) .setISAdvancement(3026, 3027, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1900,7 +1903,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "104, IO")); - munitions.add(new MunitionMutator("Artemis-capable", 1, M_ARTEMIS_CAPABLE, + munitions.add(new MunitionMutator("Artemis-capable", 1, Munitions.M_ARTEMIS_CAPABLE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setISAdvancement(2592, 2598, 3045, 2855, 3035) @@ -1908,13 +1911,13 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.STANDARD), "230, TM")); - munitions.add(new MunitionMutator("Dead-Fire", 1, M_DEAD_FIRE, + munitions.add(new MunitionMutator("Dead-Fire", 1, Munitions.M_DEAD_FIRE, new TechAdvancement(TECH_BASE_IS).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E).setISAdvancement(3052) .setPrototypeFactions(F_DC).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "131, IO")); - munitions.add(new MunitionMutator("Fragmentation", 1, M_FRAGMENTATION, + munitions.add(new MunitionMutator("Fragmentation", 1, Munitions.M_FRAGMENTATION, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(2375, 2377, 3058, 2790, 3054) @@ -1923,7 +1926,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.STANDARD), "230, TM")); - munitions.add(new MunitionMutator("Listen-Kill", 1, M_LISTEN_KILL, + munitions.add(new MunitionMutator("Listen-Kill", 1, Munitions.M_LISTEN_KILL, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_F, RATING_X, RATING_X) .setISAdvancement(3037, DATE_NONE, DATE_NONE, 3040, DATE_NONE) @@ -1933,7 +1936,7 @@ public static void initializeTypes() { // TODO Mag Pulse see IO pg 62 - munitions.add(new MunitionMutator("Mine Clearance", 1, M_MINE_CLEARANCE, + munitions.add(new MunitionMutator("Mine Clearance", 1, Munitions.M_MINE_CLEARANCE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setISAdvancement(3065, 3069, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1941,7 +1944,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "370, TO")); - munitions.add(new MunitionMutator("Narc-capable", 1, M_NARC_CAPABLE, + munitions.add(new MunitionMutator("Narc-capable", 1, Munitions.M_NARC_CAPABLE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setISAdvancement(2520, 2587, 3049, 2795, 3035) @@ -1957,7 +1960,7 @@ public static void initializeTypes() { // Create the munition types for Clan LRM launchers. munitions.clear(); - munitions.add(new MunitionMutator("(Clan) Follow The Leader", 2, M_FOLLOW_THE_LEADER, + munitions.add(new MunitionMutator("(Clan) Follow The Leader", 2, Munitions.M_FOLLOW_THE_LEADER, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_F, RATING_X, RATING_E, RATING_X) .setClanAdvancement(2750, DATE_NONE, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1965,7 +1968,7 @@ public static void initializeTypes() { .setReintroductionFactions(F_FS, F_LC).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "368, TO")); - munitions.add(new MunitionMutator("(Clan) Heat-Seeking", 2, M_HEAT_SEEKING, + munitions.add(new MunitionMutator("(Clan) Heat-Seeking", 2, Munitions.M_HEAT_SEEKING, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_E, RATING_E, RATING_F) .setClanAdvancement(2365, 2370, DATE_NONE, DATE_NONE, DATE_NONE) @@ -1976,7 +1979,7 @@ public static void initializeTypes() { // TODO Incendiary LRMs - IO pg 61, TO pg 369 /* - * munitions.add(new MunitionMutator("(Clan) Incendiary", 2, M_INCENDIARY_LRM, + * munitions.add(new MunitionMutator("(Clan) Incendiary", 2, Munitions.M_INCENDIARY_LRM, * new TechAdvancement(TECH_BASE_CLAN) .setIntroLevel(false) * .setUnofficial(false) .setTechRating(RATING_C) .setAvailability(RATING_E, * RATING_E, RATING_E, RATING_E) .setClanAdvancement(2341, 2342, 2352, @@ -1984,7 +1987,7 @@ public static void initializeTypes() { * .setPrototypeFactions(F_TH) .setProductionFactions(F_TH),"369, TO")); */ - munitions.add(new MunitionMutator("(Clan) Semi-guided", 1, M_SEMIGUIDED, + munitions.add(new MunitionMutator("(Clan) Semi-guided", 1, Munitions.M_SEMIGUIDED, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_D, RATING_D) .setClanAdvancement(3053, 3057, 3065, DATE_NONE, DATE_NONE) @@ -1992,7 +1995,7 @@ public static void initializeTypes() { .setProductionFactions(F_FW).setStaticTechLevel(SimpleTechLevel.STANDARD), "231, TM")); - munitions.add(new MunitionMutator("(Clan) Smoke", 1, M_SMOKE_WARHEAD, + munitions.add(new MunitionMutator("(Clan) Smoke", 1, Munitions.M_SMOKE_WARHEAD, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setClanAdvancement(2333, 2370, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2000,7 +2003,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.STANDARD), "371, TO")); - munitions.add(new MunitionMutator("(Clan) Swarm", 1, M_SWARM, + munitions.add(new MunitionMutator("(Clan) Swarm", 1, Munitions.M_SWARM, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_X, RATING_D, RATING_D) .setClanAdvancement(2615, 2621, 3058, DATE_NONE, DATE_NONE) @@ -2008,7 +2011,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "371, TO")); - munitions.add(new MunitionMutator("(Clan) Swarm-I", 1, M_SWARM_I, + munitions.add(new MunitionMutator("(Clan) Swarm-I", 1, Munitions.M_SWARM_I, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_X, RATING_D, RATING_D) .setClanAdvancement(3052, 3057, 3066, DATE_NONE, DATE_NONE) @@ -2016,7 +2019,7 @@ public static void initializeTypes() { .setProductionFactions(F_FW).setStaticTechLevel(SimpleTechLevel.ADVANCED), "371, TO")); - munitions.add(new MunitionMutator("(Clan) Thunder", 1, M_THUNDER, + munitions.add(new MunitionMutator("(Clan) Thunder", 1, Munitions.M_THUNDER, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_D, RATING_D) .setClanAdvancement(2618, 2620, 2650, DATE_NONE, DATE_NONE) @@ -2025,7 +2028,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("(Clan) Thunder-Active", 2, M_THUNDER_ACTIVE, + munitions.add(new MunitionMutator("(Clan) Thunder-Active", 2, Munitions.M_THUNDER_ACTIVE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3054, 3058, 3064, DATE_NONE, DATE_NONE) @@ -2033,7 +2036,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("(Clan) Thunder-Augmented", 2, M_THUNDER_AUGMENTED, + munitions.add(new MunitionMutator("(Clan) Thunder-Augmented", 2, Munitions.M_THUNDER_AUGMENTED, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3054, 3057, 3064, DATE_NONE, DATE_NONE) @@ -2041,7 +2044,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("(Clan) Thunder-Vibrabomb", 2, M_THUNDER_VIBRABOMB, + munitions.add(new MunitionMutator("(Clan) Thunder-Vibrabomb", 2, Munitions.M_THUNDER_VIBRABOMB, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3054, 3056, 3064, DATE_NONE, DATE_NONE) @@ -2049,7 +2052,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("(Clan) Thunder-Inferno", 2, M_THUNDER_INFERNO, + munitions.add(new MunitionMutator("(Clan) Thunder-Inferno", 2, Munitions.M_THUNDER_INFERNO, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3054, 3056, 3062, DATE_NONE, DATE_NONE) @@ -2057,7 +2060,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "373, TO")); - munitions.add(new MunitionMutator("(Clan) Anti-TSM", 1, M_ANTI_TSM, + munitions.add(new MunitionMutator("(Clan) Anti-TSM", 1, Munitions.M_ANTI_TSM, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) .setClanAdvancement(3026, 3027, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2065,7 +2068,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "104, IO")); - munitions.add(new MunitionMutator("(Clan) Artemis-capable", 1, M_ARTEMIS_CAPABLE, + munitions.add(new MunitionMutator("(Clan) Artemis-capable", 1, Munitions.M_ARTEMIS_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setClanAdvancement(2592, 2598, 3045, DATE_NONE, DATE_NONE) @@ -2074,7 +2077,7 @@ public static void initializeTypes() { "207, TM")); //Tech Progression tweaked to combine IntOps with TRO Prototypes/3145 NTNU RS - munitions.add(new MunitionMutator("(Clan) Artemis V-capable", 1, M_ARTEMIS_V_CAPABLE, + munitions.add(new MunitionMutator("(Clan) Artemis V-capable", 1, Munitions.M_ARTEMIS_V_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_E) .setClanAdvancement(DATE_NONE, 3061, 3085, DATE_NONE, DATE_NONE) @@ -2082,7 +2085,7 @@ public static void initializeTypes() { .setProductionFactions(F_CSF, F_RD).setStaticTechLevel(SimpleTechLevel.ADVANCED), "283, TO")); - munitions.add(new MunitionMutator("(Clan) Dead-Fire", 1, M_DEAD_FIRE, + munitions.add(new MunitionMutator("(Clan) Dead-Fire", 1, Munitions.M_DEAD_FIRE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3052, DATE_NONE, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2090,7 +2093,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "131, IO")); - munitions.add(new MunitionMutator("(Clan) Fragmentation", 1, M_FRAGMENTATION, + munitions.add(new MunitionMutator("(Clan) Fragmentation", 1, Munitions.M_FRAGMENTATION, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setClanAdvancement(2375, 2377, 3058, DATE_NONE, DATE_NONE) @@ -2098,7 +2101,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "230, TM")); - munitions.add(new MunitionMutator("(Clan) Listen-Kill", 1, M_LISTEN_KILL, + munitions.add(new MunitionMutator("(Clan) Listen-Kill", 1, Munitions.M_LISTEN_KILL, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_X) .setClanAdvancement(3037, DATE_NONE, DATE_NONE, 3040, DATE_NONE) @@ -2108,7 +2111,7 @@ public static void initializeTypes() { // TODO Mag Pulse see IO pg 62 - munitions.add(new MunitionMutator("(Clan) Mine Clearance", 1, M_MINE_CLEARANCE, + munitions.add(new MunitionMutator("(Clan) Mine Clearance", 1, Munitions.M_MINE_CLEARANCE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setClanAdvancement(3065, 3069, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2116,7 +2119,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "370, TO")); - munitions.add(new MunitionMutator("(Clan) Multi-Purpose", 1, M_MULTI_PURPOSE, + munitions.add(new MunitionMutator("(Clan) Multi-Purpose", 1, Munitions.M_MULTI_PURPOSE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3055, 3060, 3065, DATE_NONE, DATE_NONE) @@ -2124,7 +2127,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.STANDARD), "229, TW")); - munitions.add(new MunitionMutator("(Clan) Narc-capable", 1, M_NARC_CAPABLE, + munitions.add(new MunitionMutator("(Clan) Narc-capable", 1, Munitions.M_NARC_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setClanAdvancement(2520, 2587, 3049, DATE_NONE, DATE_NONE) @@ -2140,7 +2143,7 @@ public static void initializeTypes() { // Create the munition types for AC rounds. munitions.clear(); - munitions.add(new MunitionMutator("Armor-Piercing", 2, M_ARMOR_PIERCING, + munitions.add(new MunitionMutator("Armor-Piercing", 2, Munitions.M_ARMOR_PIERCING, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3055, 3059, 3063, DATE_NONE, DATE_NONE) @@ -2148,7 +2151,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); - munitions.add(new MunitionMutator("Caseless", 1, M_CASELESS, + munitions.add(new MunitionMutator("Caseless", 1, Munitions.M_CASELESS, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setISAdvancement(DATE_NONE, 3056, 3079, DATE_NONE, DATE_NONE) @@ -2159,7 +2162,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "352, TO")); - munitions.add(new MunitionMutator("Flak", 1, M_FLAK, + munitions.add(new MunitionMutator("Flak", 1, Munitions.M_FLAK, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_E, RATING_F, RATING_F, RATING_E) .setAdvancement(DATE_ES, 2310, 3070, DATE_NONE, DATE_NONE) @@ -2167,7 +2170,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.STANDARD), "352, TO")); - munitions.add(new MunitionMutator("Flechette", 1, M_FLECHETTE, + munitions.add(new MunitionMutator("Flechette", 1, Munitions.M_FLECHETTE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3053, 3055, 3058, DATE_NONE, DATE_NONE) @@ -2175,7 +2178,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); - munitions.add(new MunitionMutator("Precision", 2, M_PRECISION, + munitions.add(new MunitionMutator("Precision", 2, Munitions.M_PRECISION, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3058, 3062, 3066, DATE_NONE, DATE_NONE) @@ -2183,7 +2186,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); - munitions.add(new MunitionMutator("Tracer", 1, M_TRACER, + munitions.add(new MunitionMutator("Tracer", 1, Munitions.M_TRACER, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_D, RATING_E, RATING_F, RATING_E) .setISAdvancement(DATE_ES, 2300, 3060, DATE_NONE, DATE_NONE) @@ -2198,7 +2201,7 @@ public static void initializeTypes() { // Create the munition types for Clan Improved AC rounds. Since Improved AC go // extinct the ammo will as well. munitions.clear(); - munitions.add(new MunitionMutator("Armor-Piercing", 2, M_ARMOR_PIERCING, + munitions.add(new MunitionMutator("Armor-Piercing", 2, Munitions.M_ARMOR_PIERCING, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(DATE_NONE, DATE_NONE, 3109, DATE_NONE, DATE_NONE) @@ -2206,7 +2209,7 @@ public static void initializeTypes() { .setProductionFactions(F_CLAN).setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); - munitions.add(new MunitionMutator("Caseless", 1, M_CASELESS, + munitions.add(new MunitionMutator("Caseless", 1, Munitions.M_CASELESS, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setISAdvancement(DATE_NONE, 3056, 3079, DATE_NONE, DATE_NONE) @@ -2217,7 +2220,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "352, TO")); - munitions.add(new MunitionMutator("Flak", 1, M_FLAK, + munitions.add(new MunitionMutator("Flak", 1, Munitions.M_FLAK, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_E, RATING_F, RATING_F, RATING_E) .setAdvancement(DATE_ES, 2310, 3070, DATE_NONE, DATE_NONE) @@ -2226,7 +2229,7 @@ public static void initializeTypes() { "352, TO")); - munitions.add(new MunitionMutator("Flechette", 1, M_FLECHETTE, + munitions.add(new MunitionMutator("Flechette", 1, Munitions.M_FLECHETTE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(DATE_NONE, DATE_NONE, 3105, DATE_NONE, DATE_NONE) @@ -2234,7 +2237,7 @@ public static void initializeTypes() { .setProductionFactions(F_CLAN).setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); - munitions.add(new MunitionMutator("Precision", 2, M_PRECISION, + munitions.add(new MunitionMutator("Precision", 2, Munitions.M_PRECISION, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3053, 3055, 3058, DATE_NONE, DATE_NONE) @@ -2242,7 +2245,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.UNOFFICIAL), "208, TM")); - munitions.add(new MunitionMutator("Tracer", 1, M_TRACER, + munitions.add(new MunitionMutator("Tracer", 1, Munitions.M_TRACER, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_D, RATING_E, RATING_F, RATING_E) .setClanAdvancement(DATE_NONE, 2815, 2818, 2833, 3080) @@ -2257,7 +2260,7 @@ public static void initializeTypes() { // Create the munition types for Clan Protomek AC rounds. Ammo Tech Ratings // based off the weapon itself munitions.clear(); - munitions.add(new MunitionMutator("Armor-Piercing", 2, M_ARMOR_PIERCING, + munitions.add(new MunitionMutator("Armor-Piercing", 2, Munitions.M_ARMOR_PIERCING, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_X, RATING_E) .setClanAdvancement(DATE_NONE, 3095, 3105, DATE_NONE, DATE_NONE) @@ -2265,7 +2268,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); //Tech Progression tweaked to combine IntOps with TRO Prototypes/3145 NTNU RS - munitions.add(new MunitionMutator("Caseless", 1, M_CASELESS, + munitions.add(new MunitionMutator("Caseless", 1, Munitions.M_CASELESS, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_D) .setISAdvancement(DATE_NONE, 3056, 3079, DATE_NONE, DATE_NONE) @@ -2276,7 +2279,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS).setStaticTechLevel(SimpleTechLevel.STANDARD), "352, TO")); - munitions.add(new MunitionMutator("Flak", 1, M_FLAK, + munitions.add(new MunitionMutator("Flak", 1, Munitions.M_FLAK, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_E, RATING_F, RATING_F, RATING_E) .setAdvancement(DATE_ES, 2310, 3070, DATE_NONE, DATE_NONE) @@ -2285,7 +2288,7 @@ public static void initializeTypes() { "352, TO")); //Tech Progression tweaked to combine IntOps with TRO Prototypes/3145 NTNU RS - munitions.add(new MunitionMutator("Flechette", 1, M_FLECHETTE, + munitions.add(new MunitionMutator("Flechette", 1, Munitions.M_FLECHETTE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_X, RATING_E) .setClanAdvancement(DATE_NONE, 3095, 3105, DATE_NONE, DATE_NONE) @@ -2293,7 +2296,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); - munitions.add(new MunitionMutator("Precision", 2, M_PRECISION, + munitions.add(new MunitionMutator("Precision", 2, Munitions.M_PRECISION, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_F) .setClanAdvancement(3070, 3073, 3145, DATE_NONE, DATE_NONE) .setClanApproximate(true, false, false, false, false) @@ -2301,7 +2304,7 @@ public static void initializeTypes() { .setProductionFactions(F_CBS).setStaticTechLevel(SimpleTechLevel.STANDARD), "208, TM")); - munitions.add(new MunitionMutator("Tracer", 1, M_TRACER, + munitions.add(new MunitionMutator("Tracer", 1, Munitions.M_TRACER, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_E) .setClanAdvancement(3070, 3073, 3145, DATE_NONE, DATE_NONE) @@ -2315,20 +2318,16 @@ public static void initializeTypes() { // Create the munition types for IS Arrow IV launchers. munitions.clear(); - // TODO - /* - * munitions.add(new MunitionMutator("Air-Defense Arrow (ADA) Missiles", 1, - * M_XXXXXXX, new - * TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false) - * .setISAdvancement(3068, 3080, DATE_NONE, DATE_NONE, DATE_NONE) - * .setApproximate(false, false, false, false, false).setTechRating(RATING_E) - * .setAvailability(RATING_X, RATING_X, RATING_F, - * RATING_E).setPrototypeFactions(F_CC) - * .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED) - * , "353, TO")); - */ - - munitions.add(new MunitionMutator("Cluster", 1, M_CLUSTER, + munitions.add(new MunitionMutator("Air-Defense Arrow (ADA) Missiles", 1, Munitions.M_ADA, + new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false) + .setAvailability(RATING_X, RATING_X, RATING_F, RATING_E) + .setPrototypeFactions(F_CC) + .setISAdvancement(3068, 3080, DATE_NONE, DATE_NONE, DATE_NONE) + .setApproximate(false, false, false, false, false).setTechRating(RATING_E) + .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED) + , "165, TO:AU&E")); + + munitions.add(new MunitionMutator("Cluster", 1, Munitions.M_CLUSTER, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(2594, 2600, DATE_NONE, 2830, 3047) @@ -2337,13 +2336,13 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "354, TO")); - munitions.add(new MunitionMutator("Homing", 1, M_HOMING, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) + munitions.add(new MunitionMutator("Homing", 1, Munitions.M_HOMING, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_E).setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(2593, 2600, DATE_NONE, 2830, 3045).setISApproximate(false, false, false, false, false) .setPrototypeFactions(F_TH).setProductionFactions(F_TH).setReintroductionFactions(F_CC) .setStaticTechLevel(SimpleTechLevel.ADVANCED), "354, TO")); - munitions.add(new MunitionMutator("Illumination", 1, M_FLARE, + munitions.add(new MunitionMutator("Illumination", 1, Munitions.M_FLARE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setISAdvancement(2615, 2621, DATE_NONE, 2800, 3047) @@ -2352,7 +2351,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Inferno-IV", 1, M_INFERNO_IV, + munitions.add(new MunitionMutator("Inferno-IV", 1, Munitions.M_INFERNO_IV, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_D, RATING_D) .setISAdvancement(3053, 3083, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2360,7 +2359,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Laser Inhibiting", 1, M_LASER_INHIB, + munitions.add(new MunitionMutator("Laser Inhibiting", 1, Munitions.M_LASER_INHIB, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) .setISAdvancement(3053, 3083, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2368,13 +2367,13 @@ public static void initializeTypes() { .setProductionFactions(F_FS, F_LC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_E).setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(2595, 2600, DATE_NONE, 2840, 3044).setISApproximate(false, false, false, false, false) .setPrototypeFactions(F_TH).setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "356, TO")); - munitions.add(new MunitionMutator("Thunder (FASCAM)", 1, M_FASCAM, + munitions.add(new MunitionMutator("Thunder (FASCAM)", 1, Munitions.M_FASCAM, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_D) .setISAdvancement(2621, 2844, DATE_NONE, 2770, 3051) @@ -2385,7 +2384,7 @@ public static void initializeTypes() { // TODO - Implement them. /* - * munitions.add(new MunitionMutator("Thunder-Active-IV", 1, M_ACTIVE_IV, new + * munitions.add(new MunitionMutator("Thunder-Active-IV", 1, Munitions.M_ACTIVE_IV, new * TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false). * setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_E, * RATING_E) .setISAdvancement(3056, 3065, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2393,7 +2392,7 @@ public static void initializeTypes() { * .setProductionFactions(F_CCC), "356, TO")); */ - munitions.add(new MunitionMutator("Thunder Vibrabomb-IV", 1, M_VIBRABOMB_IV, + munitions.add(new MunitionMutator("Thunder Vibrabomb-IV", 1, Munitions.M_VIBRABOMB_IV, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setISAdvancement(3056, 3065, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2401,14 +2400,14 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "357, TO")); - munitions.add(new MunitionMutator("Davy Crocket-M", 5, M_DAVY_CROCKETT_M, + munitions.add(new MunitionMutator("Davy Crocket-M", 5, Munitions.M_DAVY_CROCKETT_M, new TechAdvancement(TECH_BASE_IS).setTechRating(RATING_D) .setAvailability(RATING_F, RATING_F, RATING_F, RATING_F) .setISAdvancement(2412, DATE_NONE, DATE_NONE, 2830, 3044) .setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "174, IO")); - munitions.add(new MunitionMutator("Fuel-Air", 1, M_FAE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) + munitions.add(new MunitionMutator("Fuel-Air", 1, Munitions.M_FAE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_C).setAvailability(RATING_E, RATING_F, RATING_E, RATING_E) .setISAdvancement(DATE_PS, DATE_PS, DATE_NONE, DATE_NONE, DATE_NONE) .setISApproximate(false, false, false, false, false).setStaticTechLevel(SimpleTechLevel.ADVANCED), @@ -2416,8 +2415,7 @@ public static void initializeTypes() { // TODO: /* - * Arrow IV [Air-Defense Arrow (ADA) Missiles] - (TO 353), Arrow IV [Thunder - * Active-IV] - TO (357) + * Arrow IV [Thunder Active-IV] - TO (357) */ // Walk through both the base types and the @@ -2427,19 +2425,17 @@ public static void initializeTypes() { // Create the munition types for Clan Arrow IV launchers. munitions.clear(); - // TODO - /* - * munitions.add(new MunitionMutator("Air-Defense Arrow (ADA) Missiles", 1, - * M_XXXXXXX, new - * TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false) - * .setISAdvancement(3068, 3080, DATE_NONE, DATE_NONE, DATE_NONE) - * .setApproximate(false, false, false, false, false).setTechRating(RATING_E) - * .setAvailability(RATING_X, RATING_X, RATING_F, - * RATING_E).setPrototypeFactions(F_CC) .setProductionFactions(F_CC), - * "353, TO")); - */ - munitions.add(new MunitionMutator("Cluster", 1, M_CLUSTER, + munitions.add(new MunitionMutator("Air-Defense Arrow (ADA) Missiles", 1, Munitions.M_ADA, + new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) + .setAvailability(RATING_X, RATING_X, RATING_F, RATING_E) + .setClanAdvancement(3068, 3080, DATE_NONE, DATE_NONE, DATE_NONE) + .setClanApproximate(false, false, false, false, false).setPrototypeFactions(F_CC) + .setProductionFactions(F_CC) + .setStaticTechLevel(SimpleTechLevel.ADVANCED), + "165, TO:AU&E")); + + munitions.add(new MunitionMutator("Cluster", 1, Munitions.M_CLUSTER, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setClanAdvancement(2594, 2600, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2448,7 +2444,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "354, TO")); - munitions.add(new MunitionMutator("Homing", 1, M_HOMING, + munitions.add(new MunitionMutator("Homing", 1, Munitions.M_HOMING, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setClanAdvancement(2593, 2600, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2457,7 +2453,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "354, TO")); - munitions.add(new MunitionMutator("Illumination", 1, M_FLARE, + munitions.add(new MunitionMutator("Illumination", 1, Munitions.M_FLARE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setClanAdvancement(2615, 2621, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2466,7 +2462,7 @@ public static void initializeTypes() { .setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Inferno-IV", 1, M_INFERNO_IV, + munitions.add(new MunitionMutator("Inferno-IV", 1, Munitions.M_INFERNO_IV, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_C) .setAvailability(RATING_X, RATING_X, RATING_D, RATING_D) .setClanAdvancement(3053, 3083, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2474,7 +2470,7 @@ public static void initializeTypes() { .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Laser Inhibiting", 1, M_LASER_INHIB, + munitions.add(new MunitionMutator("Laser Inhibiting", 1, Munitions.M_LASER_INHIB, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_F) .setClanAdvancement(3053, 3083, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2482,7 +2478,7 @@ public static void initializeTypes() { .setProductionFactions(F_FS, F_LC).setStaticTechLevel(SimpleTechLevel.EXPERIMENTAL), "355, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE, + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setClanAdvancement(2595, 2600, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2490,7 +2486,7 @@ public static void initializeTypes() { .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "356, TO")); - munitions.add(new MunitionMutator("Thunder (FASCAM)", 1, M_FASCAM, + munitions.add(new MunitionMutator("Thunder (FASCAM)", 1, Munitions.M_FASCAM, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_D) .setClanAdvancement(2621, 2844, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2501,7 +2497,7 @@ public static void initializeTypes() { // TODO - Implement them. /* - * munitions.add(new MunitionMutator("Thunder-Active-IV", 1, M_ACTIVE_IV, new + * munitions.add(new MunitionMutator("Thunder-Active-IV", 1, Munitions.M_ACTIVE_IV, new * TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false). * setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_E, * RATING_E) .setISAdvancement(3056, 3065, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2509,7 +2505,7 @@ public static void initializeTypes() { * .setProductionFactions(F_CCC), "356, TO")); */ - munitions.add(new MunitionMutator("Thunder Vibrabomb-IV", 1, M_VIBRABOMB_IV, + munitions.add(new MunitionMutator("Thunder Vibrabomb-IV", 1, Munitions.M_VIBRABOMB_IV, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_D) .setAvailability(RATING_X, RATING_X, RATING_E, RATING_E) .setClanAdvancement(3056, 3065, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2526,7 +2522,7 @@ public static void initializeTypes() { // create the munition types for clan vehicular grenade launchers munitions.clear(); - munitions.add(new MunitionMutator("Chaff", 1, M_CHAFF, + munitions.add(new MunitionMutator("Chaff", 1, Munitions.M_CHAFF, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_D, RATING_E, RATING_E, RATING_E) .setClanAdvancement(DATE_NONE, DATE_PS, 3080, DATE_NONE, DATE_NONE) @@ -2534,7 +2530,7 @@ public static void initializeTypes() { .setPrototypeFactions(F_CLAN) .setProductionFactions(F_CLAN).setStaticTechLevel(SimpleTechLevel.STANDARD), "363, TO")); - munitions.add(new MunitionMutator("Incendiary", 1, M_INCENDIARY, + munitions.add(new MunitionMutator("Incendiary", 1, Munitions.M_INCENDIARY, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setClanAdvancement(DATE_NONE, DATE_PS, 3080, DATE_NONE, DATE_NONE) @@ -2542,7 +2538,7 @@ public static void initializeTypes() { .setPrototypeFactions(F_CLAN) .setProductionFactions(F_CLAN).setStaticTechLevel(SimpleTechLevel.STANDARD), "364, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false) + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_B).setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setClanAdvancement(DATE_NONE, DATE_PS, 3080, DATE_NONE, DATE_NONE) .setClanApproximate(false, false, true, false, false) @@ -2553,20 +2549,20 @@ public static void initializeTypes() { // create the munition types for IS vehicular grenade launchers munitions.clear(); - munitions.add(new MunitionMutator("Chaff", 1, M_CHAFF, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) + munitions.add(new MunitionMutator("Chaff", 1, Munitions.M_CHAFF, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_B).setAvailability(RATING_X, RATING_E, RATING_E, RATING_E) .setISAdvancement(DATE_NONE, DATE_PS, 3080, DATE_NONE, DATE_NONE) .setISApproximate(false, false, true, false, false) .setStaticTechLevel(SimpleTechLevel.STANDARD), "363, TO")); - munitions.add(new MunitionMutator("Incendiary", 1, M_INCENDIARY, + munitions.add(new MunitionMutator("Incendiary", 1, Munitions.M_INCENDIARY, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_B) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setISAdvancement(DATE_NONE, DATE_PS, 3080, DATE_NONE, DATE_NONE) .setISApproximate(false, false, true, false, false) .setStaticTechLevel(SimpleTechLevel.STANDARD), "363, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_B).setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setISAdvancement(DATE_NONE, DATE_PS, 3080, DATE_NONE, DATE_NONE) .setISApproximate(false, false, true, false, false) @@ -2576,49 +2572,49 @@ public static void initializeTypes() { // Create the munition types for Artillery launchers. munitions.clear(); - munitions.add(new MunitionMutator("Cluster", 1, M_CLUSTER, + munitions.add(new MunitionMutator("Cluster", 1, Munitions.M_CLUSTER, new TechAdvancement(TECH_BASE_ALL).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(DATE_PS, DATE_PS, DATE_NONE, DATE_NONE, DATE_NONE) .setStaticTechLevel(SimpleTechLevel.ADVANCED), "354, TO")); - munitions.add(new MunitionMutator("Copperhead", 1, M_HOMING, + munitions.add(new MunitionMutator("Copperhead", 1, Munitions.M_HOMING, new TechAdvancement(TECH_BASE_ALL).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(2640, 2645, DATE_NONE, 2800, 3051).setPrototypeFactions(F_TH) .setProductionFactions(F_TH).setStaticTechLevel(SimpleTechLevel.ADVANCED), "354, TO")); - munitions.add(new MunitionMutator("FASCAM", 1, M_FASCAM, + munitions.add(new MunitionMutator("FASCAM", 1, Munitions.M_FASCAM, new TechAdvancement(TECH_BASE_ALL).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_D) .setISAdvancement(2621, 2844, DATE_NONE, 2770, 3051).setPrototypeFactions(F_TH) .setProductionFactions(F_CC).setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Flechette", 1, M_FLECHETTE, + munitions.add(new MunitionMutator("Flechette", 1, Munitions.M_FLECHETTE, new TechAdvancement(TECH_BASE_ALL).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_D) .setISAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) .setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Illumination", 1, M_FLARE, + munitions.add(new MunitionMutator("Illumination", 1, Munitions.M_FLARE, new TechAdvancement(TECH_BASE_ALL).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setISAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) .setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE, + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE, new TechAdvancement(TECH_BASE_ALL).setTechRating(RATING_B) .setAvailability(RATING_A, RATING_A, RATING_A, RATING_A) .setISAdvancement(DATE_PS, DATE_PS, DATE_NONE, DATE_NONE, DATE_NONE) .setStaticTechLevel(SimpleTechLevel.ADVANCED), "355, TO")); - munitions.add(new MunitionMutator("Fuel-Air", 1, M_FAE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) + munitions.add(new MunitionMutator("Fuel-Air", 1, Munitions.M_FAE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_C).setAvailability(RATING_E, RATING_F, RATING_E, RATING_E) .setISAdvancement(DATE_PS, DATE_PS, DATE_NONE, DATE_NONE, DATE_NONE) .setISApproximate(false, false, false, false, false).setStaticTechLevel(SimpleTechLevel.ADVANCED), @@ -2630,7 +2626,7 @@ public static void initializeTypes() { AmmoType.createMunitions(thumperAmmos, munitions); // Make Davy Crockett-Ms for Long Toms, but not Thumper or Sniper. - munitions.add(new MunitionMutator("Davy Crocket-M", 5, M_DAVY_CROCKETT_M, + munitions.add(new MunitionMutator("Davy Crocket-M", 5, Munitions.M_DAVY_CROCKETT_M, new TechAdvancement(TECH_BASE_IS).setTechRating(RATING_D) .setAvailability(RATING_F, RATING_F, RATING_F, RATING_F) .setISAdvancement(2412, DATE_NONE, DATE_NONE, 2830, 3044) @@ -2641,7 +2637,7 @@ public static void initializeTypes() { // Create the munition types for Artillery Cannons. // These were taken out in TacOps errata, so are unofficial. munitions.clear(); - munitions.add(new MunitionMutator("Cluster", 1, M_CLUSTER, + munitions.add(new MunitionMutator("Cluster", 1, Munitions.M_CLUSTER, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(DATE_PS, DATE_PS, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2650,7 +2646,7 @@ public static void initializeTypes() { .setClanApproximate(false, false, false, false, false), "354, TO")); - munitions.add(new MunitionMutator("Copperhead", 1, M_HOMING, + munitions.add(new MunitionMutator("Copperhead", 1, Munitions.M_HOMING, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) .setISAdvancement(2640, 2645, DATE_NONE, 2800, 3051) @@ -2660,14 +2656,14 @@ public static void initializeTypes() { .setProductionFactions(F_TH), "354, TO")); - munitions.add(new MunitionMutator("FASCAM", 1, M_FASCAM, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) + munitions.add(new MunitionMutator("FASCAM", 1, Munitions.M_FASCAM, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) .setUnofficial(true).setTechRating(RATING_C).setAvailability(RATING_E, RATING_F, RATING_D, RATING_D) .setISAdvancement(2621, 2844, DATE_NONE, 2770, 3051).setISApproximate(false, false, false, false, false) .setClanAdvancement(2621, 2844, DATE_NONE, DATE_NONE, DATE_NONE) .setClanApproximate(false, false, false, false, false).setPrototypeFactions(F_TH) .setProductionFactions(F_CHH), "355, TO")); - munitions.add(new MunitionMutator("Flechette", 1, M_FLECHETTE, + munitions.add(new MunitionMutator("Flechette", 1, Munitions.M_FLECHETTE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_C) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_D) .setISAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2676,7 +2672,7 @@ public static void initializeTypes() { .setClanApproximate(false, false, false, false, false), "355, TO")); - munitions.add(new MunitionMutator("Illumination", 1, M_FLARE, + munitions.add(new MunitionMutator("Illumination", 1, Munitions.M_FLARE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false).setUnofficial(true).setTechRating(RATING_C) .setAvailability(RATING_D, RATING_D, RATING_D, RATING_D) .setISAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2685,7 +2681,7 @@ public static void initializeTypes() { .setClanApproximate(false, false, false, false, false), "355, TO")); - munitions.add(new MunitionMutator("Smoke", 1, M_SMOKE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) + munitions.add(new MunitionMutator("Smoke", 1, Munitions.M_SMOKE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) .setUnofficial(true).setTechRating(RATING_B).setAvailability(RATING_A, RATING_A, RATING_A, RATING_A) .setISAdvancement(DATE_PS, DATE_PS, DATE_NONE, DATE_NONE, DATE_NONE) .setISApproximate(false, false, false, false, false) @@ -2693,7 +2689,7 @@ public static void initializeTypes() { .setClanApproximate(false, false, false, false, false).setStaticTechLevel(SimpleTechLevel.ADVANCED), "356, TO")); - munitions.add(new MunitionMutator("Fuel-Air", 1, M_FAE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) + munitions.add(new MunitionMutator("Fuel-Air", 1, Munitions.M_FAE, new TechAdvancement(TECH_BASE_ALL).setIntroLevel(false) .setUnofficial(false).setTechRating(RATING_C).setAvailability(RATING_E, RATING_F, RATING_E, RATING_E) .setISAdvancement(DATE_PS, DATE_PS, DATE_NONE, DATE_NONE, DATE_NONE) .setISApproximate(false, false, false, false, false).setStaticTechLevel(SimpleTechLevel.ADVANCED), @@ -2705,7 +2701,7 @@ public static void initializeTypes() { AmmoType.createMunitions(thumperCannonAmmos, munitions); // Make Davy Crockett-Ms for Long Toms, but not Thumper or Sniper. - munitions.add(new MunitionMutator("Davy Crocket-M", 5, M_DAVY_CROCKETT_M, + munitions.add(new MunitionMutator("Davy Crocket-M", 5, Munitions.M_DAVY_CROCKETT_M, new TechAdvancement(TECH_BASE_IS).setTechRating(RATING_D) .setAvailability(RATING_F, RATING_F, RATING_F, RATING_F) .setISAdvancement(2412, DATE_NONE, DATE_NONE, 2830, 3044) @@ -2715,7 +2711,7 @@ public static void initializeTypes() { // Create the munition types for SRT launchers. munitions.clear(); - munitions.add(new MunitionMutator("Artemis-capable", 1, M_ARTEMIS_CAPABLE, + munitions.add(new MunitionMutator("Artemis-capable", 1, Munitions.M_ARTEMIS_CAPABLE, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setISAdvancement(2592, 2598, 3045, 2855, 3035) @@ -2731,14 +2727,14 @@ public static void initializeTypes() { // Create the munition types for Clan SRT launchers. munitions.clear(); // Tech Progression tweaked to combine IntOps with TRO Prototypes/3145 NTNU RS - munitions.add(new MunitionMutator("(Clan) Artemis V-capable", 1, M_ARTEMIS_V_CAPABLE, + munitions.add(new MunitionMutator("(Clan) Artemis V-capable", 1, Munitions.M_ARTEMIS_V_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_F) .setAvailability(RATING_X, RATING_X, RATING_F, RATING_E) .setClanAdvancement(DATE_NONE, 3061, 3085, DATE_NONE, DATE_NONE) .setClanApproximate(false, false, true, false, false).setPrototypeFactions(F_CGS) .setProductionFactions(F_CSF, F_RD).setStaticTechLevel(SimpleTechLevel.ADVANCED), "283, TO")); - munitions.add(new MunitionMutator("Artemis-capable", 1, M_ARTEMIS_CAPABLE, + munitions.add(new MunitionMutator("Artemis-capable", 1, Munitions.M_ARTEMIS_CAPABLE, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_D, RATING_C) .setClanAdvancement(2592, 2598, 3045, DATE_NONE, DATE_NONE) @@ -2757,7 +2753,7 @@ public static void initializeTypes() { // Tech Progression tweaked to combine IntOps with TRO Prototypes/3145 NTNU RS // December 2021 - CGL requested we move this to Advanced for all fluid gun ammos. munitions.clear(); - munitions.add(new MunitionMutator("Coolant", 1, M_COOLANT, + munitions.add(new MunitionMutator("Coolant", 1, Munitions.M_COOLANT, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setISAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2770,7 +2766,7 @@ public static void initializeTypes() { AmmoType.createMunitions(vehicleFlamerAmmos, munitions); munitions.clear(); - munitions.add(new MunitionMutator("(Clan) Coolant", 1, M_COOLANT, + munitions.add(new MunitionMutator("(Clan) Coolant", 1, Munitions.M_COOLANT, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setClanAdvancement(DATE_ES, DATE_ES, DATE_NONE, DATE_NONE, DATE_NONE) @@ -2784,7 +2780,7 @@ public static void initializeTypes() { // Create the munition types for heavy flamers munitions.clear(); - munitions.add(new MunitionMutator("Coolant", 1, M_COOLANT, + munitions.add(new MunitionMutator("Coolant", 1, Munitions.M_COOLANT, new TechAdvancement(TECH_BASE_IS).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setISAdvancement(DATE_ES, DATE_ES, DATE_ES, DATE_NONE, DATE_NONE) @@ -2796,7 +2792,7 @@ public static void initializeTypes() { AmmoType.createMunitions(heavyFlamerAmmos, munitions); munitions.clear(); - munitions.add(new MunitionMutator("(Clan) Coolant", 1, M_COOLANT, + munitions.add(new MunitionMutator("(Clan) Coolant", 1, Munitions.M_COOLANT, new TechAdvancement(TECH_BASE_CLAN).setIntroLevel(false).setUnofficial(false).setTechRating(RATING_C) .setAvailability(RATING_B, RATING_B, RATING_B, RATING_B) .setClanAdvancement(DATE_ES, DATE_ES, DATE_ES, DATE_NONE, DATE_NONE) @@ -3628,7 +3624,7 @@ private static AmmoType createCLLB2XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 2; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 45; ammo.bv = 6; ammo.cost = 3300; @@ -3655,7 +3651,7 @@ private static AmmoType createCLLB5XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 5; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 20; ammo.bv = 12; ammo.cost = 15000; @@ -3682,7 +3678,7 @@ private static AmmoType createCLLB10XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 10; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 10; ammo.bv = 19; ammo.cost = 20000; @@ -3710,7 +3706,7 @@ private static AmmoType createCLLB20XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 20; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 5; ammo.bv = 30; ammo.cost = 34000; @@ -3737,7 +3733,7 @@ private static AmmoType createISLB2XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 2; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 45; ammo.bv = 5; ammo.cost = 3300; @@ -3764,7 +3760,7 @@ private static AmmoType createISLB5XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 5; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 20; ammo.bv = 10; ammo.cost = 15000; @@ -3791,7 +3787,7 @@ private static AmmoType createISLB10XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 10; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 10; ammo.bv = 19; ammo.cost = 20000; @@ -3817,7 +3813,7 @@ private static AmmoType createISLB20XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 20; ammo.ammoType = AmmoType.T_AC_LBX; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 5; ammo.bv = 30; ammo.cost = 34000; @@ -4833,7 +4829,7 @@ private static AmmoType createISSBGaussRifleAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 15; ammo.ammoType = AmmoType.T_SBGAUSS; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 8; ammo.bv = 25; ammo.cost = 25000; @@ -4862,7 +4858,7 @@ private static AmmoType createISVGLAmmo() { ammo.damagePerShot = 0; ammo.rackSize = 1; ammo.ammoType = AmmoType.T_VGL; - ammo.munitionType = AmmoType.M_STANDARD; + ammo.munitionType = EnumSet.of(Munitions.M_STANDARD); ammo.shots = 1; ammo.bv = 0; ammo.cost = 0; @@ -4887,8 +4883,7 @@ private static AmmoType createCLVGLAmmo() { ammo.damagePerShot = 0; ammo.rackSize = 1; ammo.ammoType = AmmoType.T_VGL; - ammo.munitionType = - AmmoType.M_STANDARD; + ammo.munitionType = EnumSet.of(Munitions.M_STANDARD); ammo.shots = 1; ammo.bv = 0; ammo.cost = 0; @@ -5335,7 +5330,7 @@ private static AmmoType createCLATM3ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 3; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 20; ammo.bv = 14; ammo.cost = 75000; @@ -5361,7 +5356,7 @@ private static AmmoType createCLATM6ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 6; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 10; ammo.bv = 26; ammo.cost = 75000; @@ -5387,7 +5382,7 @@ private static AmmoType createCLATM9ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 9; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 7; ammo.bv = 36; ammo.cost = 75000; @@ -5413,7 +5408,7 @@ private static AmmoType createCLATM12ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 12; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 5; ammo.bv = 52; ammo.cost = 75000; @@ -5440,7 +5435,7 @@ private static AmmoType createCLATM3HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 3; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 20; ammo.bv = 14; ammo.cost = 75000; @@ -5464,7 +5459,7 @@ private static AmmoType createCLATM6HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 6; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 10; ammo.bv = 26; ammo.cost = 75000; @@ -5488,7 +5483,7 @@ private static AmmoType createCLATM9HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 9; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 7; ammo.bv = 36; ammo.cost = 75000; @@ -5512,7 +5507,7 @@ private static AmmoType createCLATM12HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 12; ammo.ammoType = AmmoType.T_ATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 5; ammo.bv = 52; ammo.cost = 75000; @@ -5640,7 +5635,7 @@ private static AmmoType createCLIATM3ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 3; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 20; ammo.bv = 21; ammo.cost = 75000; @@ -5666,7 +5661,7 @@ private static AmmoType createCLIATM6ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 6; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 10; ammo.bv = 39; ammo.cost = 75000; @@ -5691,7 +5686,7 @@ private static AmmoType createCLIATM9ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 9; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 7; ammo.bv = 54; ammo.cost = 75000; @@ -5717,7 +5712,7 @@ private static AmmoType createCLIATM12ERAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 12; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_EXTENDED_RANGE; + ammo.munitionType = EnumSet.of(Munitions.M_EXTENDED_RANGE); ammo.shots = 5; ammo.bv = 78; ammo.cost = 75000; @@ -5744,7 +5739,7 @@ private static AmmoType createCLIATM3HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 3; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 20; ammo.bv = 21; ammo.cost = 75000; @@ -5770,7 +5765,7 @@ private static AmmoType createCLIATM6HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 6; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 10; ammo.bv = 39; ammo.cost = 75000; @@ -5796,7 +5791,7 @@ private static AmmoType createCLIATM9HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 9; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 7; ammo.bv = 54; ammo.cost = 75000; @@ -5822,7 +5817,7 @@ private static AmmoType createCLIATM12HEAmmo() { ammo.damagePerShot = 3; ammo.rackSize = 12; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_HIGH_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_HIGH_EXPLOSIVE); ammo.shots = 5; ammo.bv = 78; ammo.cost = 75000; @@ -5850,7 +5845,7 @@ private static AmmoType createCLIATM3IIWAmmo() { ammo.damagePerShot = 2; ammo.rackSize = 3; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IIW; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IIW); ammo.shots = 20; ammo.bv = 27; // 21 * 1.3 = 27.3, round down (?) ammo.cost = 75000; @@ -5879,7 +5874,7 @@ private static AmmoType createCLIATM6IIWAmmo() { ammo.damagePerShot = 2; ammo.rackSize = 6; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IIW; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IIW); ammo.shots = 10; ammo.bv = 51; // 50.7 round up (?) ammo.cost = 75000; @@ -5908,7 +5903,7 @@ private static AmmoType createCLIATM9IIWAmmo() { ammo.damagePerShot = 2; ammo.rackSize = 9; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IIW; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IIW); ammo.shots = 7; ammo.bv = 70; // 54 * 1.3 = 70.2, round down (?) ammo.cost = 75000; @@ -5937,7 +5932,7 @@ private static AmmoType createCLIATM12IIWAmmo() { ammo.damagePerShot = 2; ammo.rackSize = 12; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IIW; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IIW); ammo.shots = 5; ammo.bv = 101; // 78 * 1.3 = 101.4, round down (?) ammo.cost = 75000; @@ -5967,7 +5962,7 @@ private static AmmoType createCLIATM3IMPAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 3; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IMP; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IMP); ammo.shots = 20; ammo.bv = 42; // 21 * 2 = 42 ammo.cost = 75000; @@ -5994,7 +5989,7 @@ private static AmmoType createCLIATM6IMPAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 6; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IMP; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IMP); ammo.shots = 10; ammo.bv = 78; // 39 * 2 = 78 ammo.cost = 75000; @@ -6021,7 +6016,7 @@ private static AmmoType createCLIATM9IMPAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 9; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IMP; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IMP); ammo.shots = 7; ammo.bv = 108; // 54 * 2 = 108 ammo.cost = 75000; @@ -6048,7 +6043,7 @@ private static AmmoType createCLIATM12IMPAmmo() { ammo.damagePerShot = 1; ammo.rackSize = 12; ammo.ammoType = AmmoType.T_IATM; - ammo.munitionType = M_IATM_IMP; + ammo.munitionType = EnumSet.of(Munitions.M_IATM_IMP); ammo.shots = 5; ammo.bv = 156; // 78 * 2 = 156 ammo.cost = 75000; @@ -8288,7 +8283,7 @@ private static AmmoType createISNarcExplosiveAmmo() { ammo.damagePerShot = 4; ammo.rackSize = 1; ammo.ammoType = AmmoType.T_NARC; - ammo.munitionType = M_NARC_EX; + ammo.munitionType = EnumSet.of(Munitions.M_NARC_EX); ammo.shots = 6; ammo.bv = 0; ammo.cost = 1500; @@ -8310,7 +8305,7 @@ private static AmmoType createCLNarcExplosiveAmmo() { ammo.damagePerShot = 4; ammo.rackSize = 1; ammo.ammoType = AmmoType.T_NARC; - ammo.munitionType = AmmoType.M_NARC_EX; + ammo.munitionType = EnumSet.of(Munitions.M_NARC_EX); ammo.shots = 6; ammo.bv = 0; ammo.cost = 1500; @@ -8360,7 +8355,7 @@ private static AmmoType createISiNarcECMAmmo() { ammo.damagePerShot = 3; // only used for ammo crits ammo.rackSize = 1; ammo.ammoType = AmmoType.T_INARC; - ammo.munitionType = AmmoType.M_ECM; + ammo.munitionType = EnumSet.of(Munitions.M_ECM); ammo.shots = 4; ammo.bv = 0; ammo.cost = 15000; @@ -8383,7 +8378,7 @@ private static AmmoType createISiNarcExplosiveAmmo() { ammo.damagePerShot = 6; // only used for ammo crits ammo.rackSize = 1; ammo.ammoType = AmmoType.T_INARC; - ammo.munitionType = AmmoType.M_EXPLOSIVE; + ammo.munitionType = EnumSet.of(Munitions.M_EXPLOSIVE); ammo.shots = 4; ammo.bv = 0; ammo.cost = 1500; @@ -8406,7 +8401,7 @@ private static AmmoType createISiNarcHaywireAmmo() { ammo.damagePerShot = 3; // only used for ammo crits ammo.rackSize = 1; ammo.ammoType = AmmoType.T_INARC; - ammo.munitionType = AmmoType.M_HAYWIRE; + ammo.munitionType = EnumSet.of(Munitions.M_HAYWIRE); ammo.shots = 4; ammo.bv = 0; ammo.cost = 20000; @@ -8429,7 +8424,7 @@ private static AmmoType createISiNarcNemesisAmmo() { ammo.damagePerShot = 3; // only used for ammo crits ammo.rackSize = 1; ammo.ammoType = AmmoType.T_INARC; - ammo.munitionType = AmmoType.M_NEMESIS; + ammo.munitionType = EnumSet.of(Munitions.M_NEMESIS); ammo.shots = 4; ammo.bv = 0; ammo.cost = 10000; @@ -12335,7 +12330,7 @@ private static AmmoType createISMPodAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 15; ammo.ammoType = AmmoType.T_MPOD; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 1; ammo.bv = 0; ammo.cost = 0; @@ -12360,7 +12355,7 @@ private static AmmoType createCLMPodAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 15; ammo.ammoType = AmmoType.T_MPOD; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 1; ammo.bv = 0; ammo.cost = 0; @@ -12510,7 +12505,7 @@ private static AmmoType createISTHBLB2XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 2; ammo.ammoType = AmmoType.T_AC_LBX_THB; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 40; ammo.bv = 5; ammo.cost = 4950; @@ -12537,7 +12532,7 @@ private static AmmoType createISTHBLB5XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 5; ammo.ammoType = AmmoType.T_AC_LBX_THB; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 16; ammo.bv = 11; ammo.cost = 25000; @@ -12564,7 +12559,7 @@ private static AmmoType createISTHBLB20XClusterAmmo() { ammo.toHitModifier = -1; ammo.rackSize = 20; ammo.ammoType = AmmoType.T_AC_LBX_THB; - ammo.munitionType = M_CLUSTER; + ammo.munitionType = EnumSet.of(Munitions.M_CLUSTER); ammo.shots = 4; ammo.bv = 26; ammo.cost = 51000; @@ -13053,7 +13048,7 @@ private static AmmoType createInfantryInfernoAmmo() { ammo.name = "Inferno Ammo"; ammo.setInternalName(EquipmentTypeLookup.INFANTRY_INFERNO_AMMO); ammo.ammoType = AmmoType.T_INFANTRY; - ammo.munitionType = M_INFERNO; + ammo.munitionType = EnumSet.of(Munitions.M_INFERNO); ammo.techAdvancement.setTechBase(TECH_BASE_ALL).setTechRating(RATING_A) .setAdvancement(DATE_PS, DATE_PS, DATE_PS).setAvailability(RATING_A, RATING_A, RATING_A, RATING_A) .setStaticTechLevel(SimpleTechLevel.STANDARD); @@ -13073,19 +13068,19 @@ public static boolean canClearMinefield(AmmoType at) { || (at.getAmmoType() == T_EXLRM) || (at.getAmmoType() == T_MRM) || (at.getAmmoType() == T_ROCKET_LAUNCHER)) && (at.getRackSize() >= 20) - && ((at.getMunitionType() == M_STANDARD) || (at.getMunitionType() == M_ARTEMIS_CAPABLE) - || (at.getMunitionType() == M_ARTEMIS_V_CAPABLE) - || (at.getMunitionType() == M_NARC_CAPABLE))) { + && ((at.getMunitionType().contains(Munitions.M_STANDARD)) || (at.getMunitionType().contains(Munitions.M_ARTEMIS_CAPABLE)) + || (at.getMunitionType().contains(Munitions.M_ARTEMIS_V_CAPABLE)) + || (at.getMunitionType().contains(Munitions.M_NARC_CAPABLE)))) { return true; } // ATMs - if ((at.getAmmoType() == T_ATM) && ((at.getRackSize() >= 12 && at.getMunitionType() != M_EXTENDED_RANGE) - || (at.getRackSize() >= 9 && at.getMunitionType() == M_HIGH_EXPLOSIVE))) { + if ((at.getAmmoType() == T_ATM) && ((at.getRackSize() >= 12 && !(at.getMunitionType().contains(Munitions.M_EXTENDED_RANGE)) + || (at.getRackSize() >= 9 && at.getMunitionType().contains(Munitions.M_HIGH_EXPLOSIVE))))) { return true; } // Artillery if (((at.getAmmoType() == T_ARROW_IV) || (at.getAmmoType() == T_LONG_TOM) || (at.getAmmoType() == T_SNIPER) - || (at.getAmmoType() == T_THUMPER)) && (at.getMunitionType() == M_STANDARD)) { + || (at.getAmmoType() == T_THUMPER)) && (at.getMunitionType().contains(Munitions.M_STANDARD))) { return true; } } @@ -13098,10 +13093,10 @@ public static boolean canDeliverMinefield(AmmoType at) { return (at != null) && ((at.getAmmoType() == T_LRM) || (at.getAmmoType() == AmmoType.T_LRM_IMP) || (at.getAmmoType() == AmmoType.T_MML)) - && ((at.getMunitionType() == M_THUNDER) || (at.getMunitionType() == M_THUNDER_INFERNO) - || (at.getMunitionType() == M_THUNDER_AUGMENTED) - || (at.getMunitionType() == M_THUNDER_VIBRABOMB) - || (at.getMunitionType() == M_THUNDER_ACTIVE)); + && ((at.getMunitionType().contains(Munitions.M_THUNDER)) || (at.getMunitionType().contains(Munitions.M_THUNDER_INFERNO)) + || (at.getMunitionType().contains(Munitions.M_THUNDER_AUGMENTED)) + || (at.getMunitionType().contains(Munitions.M_THUNDER_VIBRABOMB)) + || (at.getMunitionType().contains(Munitions.M_THUNDER_ACTIVE))); } private void addToEnd(AmmoType base, String modifier) { @@ -13139,17 +13134,17 @@ static private class MunitionMutator { /** * The munition flag(s) for this type. */ - private long type; + private EnumSet type; protected String rulesRefs; private TechAdvancement techAdvancement; - public MunitionMutator(String munitionName, int weightRatio, long munitionType, + public MunitionMutator(String munitionName, int weightRatio, Munitions munitionType, TechAdvancement techAdvancement, String rulesRefs) { name = munitionName; weight = weightRatio; - type = munitionType; + type = EnumSet.of(munitionType); this.techAdvancement = new TechAdvancement(techAdvancement); this.rulesRefs = rulesRefs; } @@ -13271,15 +13266,15 @@ public AmmoType createMunitionType(AmmoType base) { // Replace "Shaped Charge" with the submunition name munition.name = base.name.replace("Shaped Charge", name); String abr = "SC"; - if (type == AmmoType.M_AIRBURST) { + if (type.contains(Munitions.M_AIRBURST)) { abr = "AB"; - } else if (type == AmmoType.M_ANTI_PERSONNEL) { + } else if (type.contains(Munitions.M_ANTI_PERSONNEL)) { abr = "AP"; - } else if (type == AmmoType.M_FLARE) { + } else if (type.contains(Munitions.M_FLARE)) { abr = "FL"; - } else if (type == AmmoType.M_SMOKE_WARHEAD) { + } else if (type.contains(Munitions.M_SMOKE_WARHEAD)) { abr = "SM"; - } else if (type == AmmoType.M_SEMIGUIDED) { + } else if (type.contains(Munitions.M_SEMIGUIDED)) { abr = "SG"; } munition.shortName = base.shortName.replace("SC", abr); @@ -13329,7 +13324,7 @@ public AmmoType createMunitionType(AmmoType base) { munition.rulesRefs = rulesRefs; // Reduce base number of shots to reflect the munition's weight. - if (munition.getMunitionType() == AmmoType.M_CASELESS) { + if (munition.getMunitionType().contains(Munitions.M_CASELESS)) { munition.shots = Math.max(1, base.shots * 2); munition.kgPerShot = base.kgPerShot * (weight / 2); } else { @@ -13346,26 +13341,26 @@ public AmmoType createMunitionType(AmmoType base) { if (((munition.getAmmoType() == T_LONG_TOM) || (munition.getAmmoType() == T_LONG_TOM_CANNON) || (munition.getAmmoType() == T_SNIPER) || (munition.getAmmoType() == T_SNIPER_CANNON) || (munition.getAmmoType() == T_THUMPER) || (munition.getAmmoType() == T_THUMPER_CANNON)) - && munition.getMunitionType() == AmmoType.M_FAE) { + && munition.getMunitionType().contains(Munitions.M_FAE)) { bv *= 1.4; cost *= 3; } if ((munition.getAmmoType() == T_AC) || (munition.getAmmoType() == T_LAC) || (munition.getAmmoType() == T_PAC)) { - if (munition.getMunitionType() == AmmoType.M_ARMOR_PIERCING) { + if (munition.getMunitionType().contains(Munitions.M_ARMOR_PIERCING)) { cost *= 4; - } else if ((munition.getMunitionType() == AmmoType.M_FLECHETTE) - || (munition.getMunitionType() == AmmoType.M_FLAK)) { + } else if ((munition.getMunitionType().contains(Munitions.M_FLECHETTE)) + || (munition.getMunitionType().contains(Munitions.M_FLAK))) { cost *= 1.5; - } else if (munition.getMunitionType() == AmmoType.M_TRACER) { + } else if (munition.getMunitionType().contains(Munitions.M_TRACER)) { cost *= 1.5; bv *= 0.25; - } else if (munition.getMunitionType() == AmmoType.M_INCENDIARY_AC) { + } else if (munition.getMunitionType().contains(Munitions.M_INCENDIARY_AC)) { cost *= 2; - } else if (munition.getMunitionType() == AmmoType.M_PRECISION) { + } else if (munition.getMunitionType().contains(Munitions.M_PRECISION)) { cost *= 6; - } else if (munition.getMunitionType() == AmmoType.M_CASELESS) { + } else if (munition.getMunitionType().contains(Munitions.M_CASELESS)) { cost *= 1.5; bv *= 1.0; } @@ -13374,7 +13369,7 @@ public AmmoType createMunitionType(AmmoType base) { if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_AX_HEAD)) { + && (munition.getMunitionType().contains(Munitions.M_AX_HEAD))) { cost *= 0.5; bv *= 1; } @@ -13382,154 +13377,154 @@ public AmmoType createMunitionType(AmmoType base) { if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_SMOKE_WARHEAD)) { + && (munition.getMunitionType().contains(Munitions.M_SMOKE_WARHEAD))) { cost *= 0.5; bv *= 1; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_INCENDIARY_LRM)) { + && (munition.getMunitionType().contains(Munitions.M_INCENDIARY_LRM))) { cost *= 1.5; } if (((munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML)) - && (munition.getMunitionType() == AmmoType.M_INFERNO)) { + && (munition.getMunitionType().contains(Munitions.M_INFERNO))) { cost = 13500; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_SEMIGUIDED)) { + && (munition.getMunitionType().contains(Munitions.M_SEMIGUIDED))) { cost *= 3; bv *= 1; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_SWARM)) { + && (munition.getMunitionType().contains(Munitions.M_SWARM))) { cost *= 2; bv *= 1; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_SWARM_I)) { + && (munition.getMunitionType().contains(Munitions.M_SWARM_I))) { cost *= 3; bv *= 0.2; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_THUNDER)) { + && (munition.getMunitionType().contains(Munitions.M_THUNDER))) { cost *= 2; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_THUNDER_AUGMENTED)) { + && (munition.getMunitionType().contains(Munitions.M_THUNDER_AUGMENTED))) { cost *= 4; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_THUNDER_INFERNO)) { + && (munition.getMunitionType().contains(Munitions.M_THUNDER_INFERNO))) { cost *= 1; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_THUNDER_VIBRABOMB)) { + && (munition.getMunitionType().contains(Munitions.M_THUNDER_VIBRABOMB))) { cost *= 2.5; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_THUNDER_ACTIVE)) { + && (munition.getMunitionType().contains(Munitions.M_THUNDER_ACTIVE))) { cost *= 3; } - if (munition.getMunitionType() == AmmoType.M_HOMING) { + if (munition.getMunitionType().contains(Munitions.M_HOMING)) { cost = 15000; // Allow Homing munitions to instantly switch between modes munition.instantModeSwitch = true; munition.setModes("Homing", "Non-Homing"); } - if (munition.getMunitionType() == AmmoType.M_FASCAM) { + if (munition.getMunitionType().contains(Munitions.M_FASCAM)) { cost *= 1.5; } - if (munition.getMunitionType() == AmmoType.M_INFERNO_IV) { + if (munition.getMunitionType().contains(Munitions.M_INFERNO_IV)) { cost *= 1; } - if (munition.getMunitionType() == AmmoType.M_VIBRABOMB_IV) { + if (munition.getMunitionType().contains(Munitions.M_VIBRABOMB_IV)) { cost *= 2; } // This is just a hack to make it expensive. // We don't actually have a price for this. - if (munition.getMunitionType() == AmmoType.M_DAVY_CROCKETT_M) { + if (munition.getMunitionType().contains(Munitions.M_DAVY_CROCKETT_M)) { cost *= 50; } - if (munition.getMunitionType() == AmmoType.M_LASER_INHIB) { + if (munition.getMunitionType().contains(Munitions.M_LASER_INHIB)) { cost *= 4; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_NARC_CAPABLE)) { + && (munition.getMunitionType().contains(Munitions.M_NARC_CAPABLE))) { cost *= 2; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (munition.getMunitionType().contains(Munitions.M_ARTEMIS_CAPABLE))) { cost *= 2; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && (munition.getMunitionType() == AmmoType.M_LISTEN_KILL)) { + && (munition.getMunitionType().contains(Munitions.M_LISTEN_KILL))) { cost *= 1.1; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && ((munition.getMunitionType() == AmmoType.M_ANTI_TSM) - || (munition.getMunitionType() == AmmoType.M_FRAGMENTATION))) { + && ((munition.getMunitionType().contains(Munitions.M_ANTI_TSM)) + || (munition.getMunitionType().contains(Munitions.M_FRAGMENTATION)))) { cost *= 2; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && ((munition.getMunitionType() == AmmoType.M_DEAD_FIRE))) { + && ((munition.getMunitionType().contains(Munitions.M_DEAD_FIRE)))) { cost *= 0.6; // TODO - DEAD-FIRE AMMO needs BV which is not a constant but launcher Ammo. } if (((munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP)) - && ((munition.getMunitionType() == AmmoType.M_TANDEM_CHARGE) - || (munition.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE))) { + && ((munition.getMunitionType().contains(Munitions.M_TANDEM_CHARGE)) + || (munition.getMunitionType().contains(Munitions.M_ARTEMIS_V_CAPABLE)))) { cost *= 5; } if (((munition.getAmmoType() == AmmoType.T_LRM) || (munition.getAmmoType() == AmmoType.T_LRM_IMP) || (munition.getAmmoType() == AmmoType.T_MML) || (munition.getAmmoType() == AmmoType.T_SRM) || (munition.getAmmoType() == AmmoType.T_SRM_IMP) || (munition.getAmmoType() == AmmoType.T_NLRM)) - && ((munition.getMunitionType() == AmmoType.M_HEAT_SEEKING) - || (munition.getMunitionType() == AmmoType.M_FOLLOW_THE_LEADER))) { + && ((munition.getMunitionType().contains(Munitions.M_HEAT_SEEKING)) + || (munition.getMunitionType().contains(Munitions.M_FOLLOW_THE_LEADER)))) { cost *= 2; bv *= 0.5; } if (((munition.getAmmoType() == AmmoType.T_VEHICLE_FLAMER) || (munition.getAmmoType() == AmmoType.T_HEAVY_FLAMER) || (munition.getAmmoType() == AmmoType.T_FLUID_GUN)) - && (munition.getMunitionType() == AmmoType.M_COOLANT)) { + && (munition.getMunitionType().contains(Munitions.M_COOLANT))) { cost = 3000; } // Account for floating point imprecision @@ -13647,8 +13642,8 @@ public static boolean canSwitchToAmmo(Mounted weapon, AmmoType otherAmmo) { && (otherAmmo.getAmmoType() == AmmoType.T_AC_LBX) && (currentAmmoType.getRackSize() == otherAmmo.getRackSize()); - boolean caselessLoaded = currentAmmoType.getMunitionType() == AmmoType.M_CASELESS; - boolean otherBinCaseless = otherAmmo.getMunitionType() == AmmoType.M_CASELESS; + boolean caselessLoaded = currentAmmoType.getMunitionType().contains(Munitions.M_CASELESS); + boolean otherBinCaseless = otherAmmo.getMunitionType().contains(Munitions.M_CASELESS); boolean caselessMismatch = caselessLoaded != otherBinCaseless; boolean hasStaticFeed = weapon.hasQuirk(OptionsConstants.QUIRK_WEAP_NEG_STATIC_FEED); diff --git a/megamek/src/megamek/common/BombType.java b/megamek/src/megamek/common/BombType.java index 9150544f3cb..d77c8c327cf 100644 --- a/megamek/src/megamek/common/BombType.java +++ b/megamek/src/megamek/common/BombType.java @@ -14,6 +14,7 @@ */ package megamek.common; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -48,7 +49,7 @@ public class BombType extends AmmoType { "Arrow IV Homing Missile", "Inferno Bomb", "LAA Missile", "Thunder Bomb", "Torpedo Bomb", "Alamo Missile", "Fuel-Air Bomb (small)", "Fuel-Air Bomb (large)" }; - + public static final String[] bombInternalNames = { "HEBomb","ClusterBomb","LGBomb", "RL 10 Ammo (Bomb)", "TAGBomb", "AAAMissile Ammo", "ASMissile Ammo", @@ -62,28 +63,28 @@ public class BombType extends AmmoType { null, "LAAMissile", null, null, "AlamoMissile", null, null }; public static final int[] bombCosts = { 1, 1, 1, 1, 1, 5, 6, 6, 5, 5, 1, 2, 1, 1, 10, 1, 2 }; - + public static final Map blastRadius; private int bombType; static { blastRadius = new HashMap<>(); } - + /** * Get the blast radius of a particular bomb type, given the internal name. */ public static int getBombBlastRadius(String name) { return blastRadius.getOrDefault(name, 0); } - + public static String getBombName(int type) { if ((type >= B_NUM) || (type < 0)) { return "Unknown bomb type"; } return bombNames[type]; } - + public static int getBombTypeFromName(String name) { for (int i = 0; i < B_NUM; i++) { if (bombNames[i].equals(name)) { @@ -92,7 +93,7 @@ public static int getBombTypeFromName(String name) { } return B_NONE; } - + public static int getBombTypeFromInternalName(String name) { for (int i = 0; i < B_NUM; i++) { if (bombInternalNames[i].equalsIgnoreCase(name)) { @@ -108,7 +109,7 @@ public static String getBombWeaponName(int type) { } return bombWeaponNames[type]; } - + public static int getBombTypeForWeapon(EquipmentType weapon) { for (int i = 0; i < B_NUM; i++) { if (bombWeaponNames[i] != null @@ -204,7 +205,7 @@ public static List allBombTypes() { .map(eType -> (BombType) eType) .collect(toList()); } - + public static BombType createBombByType(int bType) { switch (bType) { case B_HE: @@ -245,7 +246,7 @@ public static BombType createBombByType(int bType) { return null; } } - + // START OF BOMBS private static BombType createAAAMissileBomb() { @@ -351,7 +352,7 @@ private static BombType createArrowIVHomingBomb() { bomb.rackSize = 20; bomb.ammoType = AmmoType.T_ARROW_IV_BOMB; bomb.bombType = BombType.B_HOMING; - bomb.munitionType = AmmoType.M_HOMING; + bomb.munitionType = EnumSet.of(AmmoType.Munitions.M_HOMING); // Allow Homing munitions to instantly switch between modes bomb.instantModeSwitch = true; bomb.setModes("Homing", "Non-Homing"); @@ -463,7 +464,7 @@ private static BombType createSmallFuelAirBomb() { .setClanApproximate(false, false, false, false, false); blastRadius.put(BombType.getBombInternalName(BombType.B_FAE_SMALL), 2); - + return bomb; } @@ -489,7 +490,7 @@ private static BombType createLargeFuelAirBomb() { .setISApproximate(false, false, false, false, false) .setClanAdvancement(DATE_PS, DATE_PS, DATE_PS, DATE_NONE, DATE_NONE) .setClanApproximate(false, false, false, false, false); - + blastRadius.put(BombType.getBombInternalName(BombType.B_FAE_LARGE), 3); return bomb; diff --git a/megamek/src/megamek/common/Compute.java b/megamek/src/megamek/common/Compute.java index 1c265af30ca..b0ae48d0fa3 100644 --- a/megamek/src/megamek/common/Compute.java +++ b/megamek/src/megamek/common/Compute.java @@ -22,6 +22,7 @@ import megamek.common.enums.BasementType; import megamek.common.enums.IlluminationLevel; import megamek.common.options.OptionsConstants; +import megamek.common.verifier.TestEntity; import megamek.common.weapons.InfantryAttack; import megamek.common.weapons.Weapon; import megamek.common.weapons.artillery.ArtilleryCannonWeapon; @@ -1213,9 +1214,9 @@ public static ToHitData getRangeMods(Game game, Entity ae, int weaponId, || (wtype.getAmmoType() == AmmoType.T_LRM_IMP) || (wtype.getAmmoType() == AmmoType.T_MML)) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_TORPEDO) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_TORPEDO)) { weaponRanges = wtype.getRanges(weapon); - } else if (atype.getMunitionType() == AmmoType.M_MULTI_PURPOSE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_MULTI_PURPOSE)) { weaponRanges = wtype.getRanges(weapon); MPM = true; } @@ -1353,7 +1354,7 @@ public static ToHitData getRangeMods(Game game, Entity ae, int weaponId, if (isIndirect) { c3spotter = ae; // no c3 when using indirect fire } - + if (isIndirect && indirectAttackImpossible(game, ae, target, wtype, weapon)) { return new ToHitData(TargetRoll.IMPOSSIBLE, Messages.getString("WeaponAttackAction.NoIndirectWithLOS")); @@ -3049,7 +3050,7 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa, loaded_ammo = (AmmoType) weapon.getLinked().getType(); if (((loaded_ammo.getAmmoType() == AmmoType.T_AC_LBX) || (loaded_ammo .getAmmoType() == AmmoType.T_AC_LBX_THB)) - && (loaded_ammo.getMunitionType() == AmmoType.M_CLUSTER)) { + && (loaded_ammo.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER))) { use_table = true; } } @@ -3149,7 +3150,7 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa, if ((!ComputeECM.isAffectedByECM(attacker, attacker.getPosition(), g .getEntity(waa.getTargetId()).getPosition(), allECMInfo)) && (wt.getDamage() == WeaponType.DAMAGE_BY_CLUSTERTABLE) - && (wt.hasFlag(WeaponType.F_MISSILE))) { + && (wt.hasFlag(WeaponType.F_MISSILE)) && null != at) { // Check for linked artemis guidance system if ((wt.getAmmoType() == AmmoType.T_LRM) || (wt.getAmmoType() == AmmoType.T_LRM_IMP) @@ -3165,11 +3166,11 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa, // -> Hook for Artemis V Level 3 Clan tech here; use // 1.30f multiplier when implemented if (((weapon.curMode() == null) || !weapon.curMode().equals("Indirect")) - && (at.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (at.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) { fHits *= 1.2f; } if (((weapon.curMode() == null) || !weapon.curMode().equals("Indirect")) - && (at.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)) { + && (at.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))) { fHits *= 1.3f; } } @@ -3189,7 +3190,7 @@ public static float getExpectedDamage(Game g, WeaponAttackAction waa, || (at.getAmmoType() == AmmoType.T_MML) || (at.getAmmoType() == AmmoType.T_SRM) || (at.getAmmoType() == AmmoType.T_SRM_IMP)) - && (at.getMunitionType() == AmmoType.M_NARC_CAPABLE)) { + && (at.getMunitionType().contains(AmmoType.Munitions.M_NARC_CAPABLE))) { fHits *= 1.2f; } } @@ -3530,12 +3531,12 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { || (abin_type.getAmmoType() == AmmoType.T_MML) || (abin_type.getAmmoType() == AmmoType.T_SRM) || (abin_type.getAmmoType() == AmmoType.T_SRM_IMP))) - && (abin_type.getMunitionType() == AmmoType.M_FRAGMENTATION)) + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_FRAGMENTATION))) || (((abin_type.getAmmoType() == AmmoType.T_AC) || (abin_type.getAmmoType() == AmmoType.T_LAC) || (abin_type.getAmmoType() == AmmoType.T_AC_IMP) || (abin_type.getAmmoType() == AmmoType.T_PAC)) - && (abin_type.getMunitionType() == AmmoType.M_FLECHETTE))) { + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_FLECHETTE)))) { ammo_multiple = target.isConventionalInfantry() ? 2.0 : 0.0; } @@ -3547,7 +3548,7 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { if (((abin_type.getAmmoType() == AmmoType.T_AC_LBX) || (abin_type.getAmmoType() == AmmoType.T_AC_LBX_THB) || (abin_type.getAmmoType() == AmmoType.T_SBGAUSS)) - && (abin_type.getMunitionType() == AmmoType.M_CLUSTER)) { + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER))) { if (target.getArmorRemainingPercent() <= 0.25) { ammo_multiple = 1.0 + (wtype.getRackSize() / 10.0); } @@ -3566,7 +3567,7 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { || (abin_type.getAmmoType() == AmmoType.T_LAC) || (abin_type.getAmmoType() == AmmoType.T_AC_IMP) || (abin_type.getAmmoType() == AmmoType.T_PAC)) - && (abin_type.getMunitionType() == AmmoType.M_ARMOR_PIERCING)) { + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_ARMOR_PIERCING))) { if ((target instanceof Mech) || (target instanceof Tank)) { ammo_multiple = 1.0 + (wtype.getRackSize() / 10); @@ -3583,7 +3584,7 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { if (((abin_type.getAmmoType() == AmmoType.T_SRM) || (abin_type.getAmmoType() == AmmoType.T_SRM_IMP) || (abin_type.getAmmoType() == AmmoType.T_MML)) - && (abin_type.getMunitionType() == AmmoType.M_INFERNO)) { + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_INFERNO))) { ammo_multiple = 0.5; if (target instanceof Mech) { if ((target.infernos.getTurnsLeftToBurn() < 4) @@ -3608,7 +3609,7 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { // one, give 'em one by making it an attractive // option if ((wtype.getAmmoType() == AmmoType.T_NARC) - && (abin_type.getMunitionType() == AmmoType.M_STANDARD)) { + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_STANDARD))) { if (!(target.isNarcedBy(shooter.getOwner().getTeam())) && !(target instanceof Infantry)) { ex_damage = 5.0; @@ -3622,7 +3623,7 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { // one, give 'em one by making it an attractive // option if (wtype.getAmmoType() == AmmoType.T_INARC) { - if ((abin_type.getMunitionType() == AmmoType.M_STANDARD) + if ((abin_type.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) && !(target instanceof Infantry)) { if (!(target.isINarcedBy(shooter.getOwner().getTeam()))) { ex_damage = 7.0; @@ -3640,9 +3641,9 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { // loads // when "true" double blind is implemented if ((abin_type.getAmmoType() == AmmoType.T_INARC) - && (abin_type.getMunitionType() == AmmoType.M_ECM) + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_ECM)) && !(target instanceof Infantry)) { - if (!target.isINarcedWith(AmmoType.M_ECM)) { + if (!target.isINarcedWith(INarcPod.ECM)) { if (!(target.getC3MasterId() == Entity.NONE) || target.hasC3M() || target.hasC3MM() @@ -3671,9 +3672,9 @@ public static double getAmmoAdjDamage(Game cgame, WeaponAttackAction atk) { // priority because they are usually out // front if ((abin_type.getAmmoType() == AmmoType.T_INARC) - && (abin_type.getMunitionType() == AmmoType.M_NEMESIS) + && (abin_type.getMunitionType().contains(AmmoType.Munitions.M_NEMESIS)) && !(target instanceof Infantry)) { - if (!target.isINarcedWith(AmmoType.M_NEMESIS)) { + if (!target.isINarcedWith(INarcPod.NEMESIS)) { ex_damage = (double) (target.getWalkMP() + target.getJumpMP()) / 2; } else { ex_damage = 0.5; @@ -4957,6 +4958,17 @@ public static int getSensorRangeByBracket(Game game, Entity ae, @Nullable Target } + public static int getADARangeModifier(int distance) { + // +0 for same ground map / Low-Altitude hex + // +2 for 1 LAH away + // +4 for 2 LAH away + if (distance <= 0){ + return 0; + } + return (((distance - 1) / Board.DEFAULT_BOARD_HEIGHT) * 2); + + } + public static final class SensorRangeHelper { public int minSensorRange; public int maxSensorRange; @@ -6902,14 +6914,14 @@ public static boolean allowAimedShotWith(Mounted weapon, AimingMode aimingMode) if (((atype.getAmmoType() == AmmoType.T_AC_LBX_THB) || (atype.getAmmoType() == AmmoType.T_AC_LBX) || (atype.getAmmoType() == AmmoType.T_SBGAUSS)) - && (atype.getMunitionType() == AmmoType.M_CLUSTER)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER))) { return false; } // Flak Ammo can't make aimed shots if (((atype.getAmmoType() == AmmoType.T_AC) || (atype.getAmmoType() == AmmoType.T_AC_ULTRA) || (atype.getAmmoType() == AmmoType.T_AC_ULTRA_THB)) - && (atype.getMunitionType() == AmmoType.M_FLAK)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_FLAK))) { return false; } @@ -6928,7 +6940,7 @@ public static boolean allowAimedShotWith(Mounted weapon, AimingMode aimingMode) && ((atype.getAmmoType() == AmmoType.T_AC_LBX_THB) || (atype.getAmmoType() == AmmoType.T_AC_LBX) || (atype.getAmmoType() == AmmoType.T_SBGAUSS)) - && (atype.getMunitionType() == AmmoType.M_CLUSTER)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER))) { return false; } @@ -6937,7 +6949,7 @@ public static boolean allowAimedShotWith(Mounted weapon, AimingMode aimingMode) && ((atype.getAmmoType() == AmmoType.T_AC) || (atype.getAmmoType() == AmmoType.T_AC_ULTRA) || (atype.getAmmoType() == AmmoType.T_AC_ULTRA_THB)) - && (atype.getMunitionType() == AmmoType.M_FLAK)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_FLAK))) { return false; } break; @@ -7197,15 +7209,15 @@ public static boolean useSpheroidAtmosphere(Game game, Entity en) { // are we in atmosphere? return en.isAirborne(); } - + /** * Worker function that checks if an indirect attack is impossible for the given passed-in arguments */ - public static boolean indirectAttackImpossible(Game game, Entity ae, Targetable target, WeaponType wtype, Mounted weapon) { + public static boolean indirectAttackImpossible(Game game, Entity ae, Targetable target, WeaponType wtype, Mounted weapon) { boolean isLandedSpheroid = ae.isAero() && ((IAero) ae).isSpheroid() && (ae.getAltitude() == 0) && game.getBoard().onGround(); int altDif = target.getAltitude() - ae.getAltitude(); boolean noseWeaponAimedAtGroundTarget = (weapon != null) && (weapon.getLocation() == Aero.LOC_NOSE) && (altDif < 1); - + return game.getOptions().booleanOption(OptionsConstants.BASE_INDIRECT_FIRE) && !game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_INDIRECT_ALWAYS_POSSIBLE) && LosEffects.calculateLOS(game, ae, target).canSee() diff --git a/megamek/src/megamek/common/Entity.java b/megamek/src/megamek/common/Entity.java index a4384333aa0..36417ab4adf 100644 --- a/megamek/src/megamek/common/Entity.java +++ b/megamek/src/megamek/common/Entity.java @@ -9099,11 +9099,11 @@ public boolean hasInfernoAmmo() { for (Mounted amounted : getAmmo()) { AmmoType atype = (AmmoType) amounted.getType(); if (((atype.getAmmoType() == AmmoType.T_SRM) || (atype.getAmmoType() == AmmoType.T_SRM_IMP) - || (atype.getAmmoType() == AmmoType.T_MML)) && (atype.getMunitionType() == AmmoType.M_INFERNO) + || (atype.getAmmoType() == AmmoType.T_MML)) && (atype.getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) && (amounted.getHittableShotsLeft() > 0)) { found = true; } - if ((atype.getAmmoType() == AmmoType.T_IATM) && (atype.getMunitionType() == AmmoType.M_IATM_IIW) + if ((atype.getAmmoType() == AmmoType.T_IATM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IIW)) && (amounted.getHittableShotsLeft() > 0)) { found = true; } @@ -11381,6 +11381,11 @@ public PilotingRollData checkSideSlip(EntityMovementType moveType, @Override public boolean isAirborneVTOLorWIGE() { + // Dead VTOLs/ WiGEs can't be airborne + if (isDestroyed()) { + return false; + } + // stuff that moves like a VTOL is flying unless at elevation 0 or on // top of/in a building, if ((getMovementMode() == EntityMovementMode.VTOL) @@ -12861,7 +12866,8 @@ public int getRearArc() { @Override public boolean isAirborne() { - return (getAltitude() > 0) + return (!isDestroyed()) + && (getAltitude() > 0) || (getMovementMode() == EntityMovementMode.AERODYNE) || (getMovementMode() == EntityMovementMode.SPHEROID); } @@ -12876,7 +12882,7 @@ public boolean isSpaceborne() { } /** - * is the unit flying Nape of the Earth? (i.e. one elevation above ground) + * is the unit flying Nap of the Earth? (i.e. one elevation above ground) */ public boolean isNOE() { diff --git a/megamek/src/megamek/common/EntityListFile.java b/megamek/src/megamek/common/EntityListFile.java index bd3711f1c5e..84f5c11649e 100644 --- a/megamek/src/megamek/common/EntityListFile.java +++ b/megamek/src/megamek/common/EntityListFile.java @@ -100,7 +100,7 @@ private static String formatSlot(String index, Mounted mount, boolean isHit, boo if (mount.getType() instanceof AmmoType) { output.append("\" shots=\"") .append(mount.getBaseShotsLeft()); - if (mount.getEntity().usesWeaponBays() + if (mount.getEntity().usesWeaponBays() || (mount.getEntity() instanceof Dropship)) { output.append("\" capacity=\"") .append(mount.getSize()); @@ -117,7 +117,7 @@ private static String formatSlot(String index, Mounted mount, boolean isHit, boo if (mount.getEntity().isSupportVehicle() && (mount.getType() instanceof InfantryWeapon)) { for (Mounted ammo = mount.getLinked(); ammo != null; ammo = ammo.getLinked()) { - if (((AmmoType) ammo.getType()).getMunitionType() == AmmoType.M_INFERNO) { + if (((AmmoType) ammo.getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) { output.append("\" inferno=\"").append(ammo.getBaseShotsLeft()) .append(":").append(ammo.getOriginalShots()); } else { @@ -258,9 +258,9 @@ public static String getLocString(Entity entity, int indentLvl) { } } - // + // Map baySlotMap = new HashMap<>(); - + // Walk through the slots in this location. for (int loop = 0; loop < entity.getNumberOfCriticals(loc); loop++) { @@ -289,7 +289,7 @@ public static String getLocString(Entity entity, int indentLvl) { mount = slot.getMount(); } - // if the "equipment" is a weapons bay, + // if the "equipment" is a weapons bay, // then let's make a note of it if (entity.usesWeaponBays() && (mount != null) && !mount.getBayAmmo().isEmpty()) { @@ -343,27 +343,27 @@ else if ((mount != null) && (mount.isRapidfire())) { // N.B. the slot CAN\"T be damaged at this point. else if (!isDestroyed && (mount != null) && (mount.getType() instanceof AmmoType)) { - + String bayIndex = ""; - + for (Mounted bay : baySlotMap.keySet()) { if (bay.ammoInBay(entity.getEquipmentNum(mount))) { bayIndex = String.valueOf(baySlotMap.get(bay)); } } - + thisLoc.append(indentStr(indentLvl + 1) + "\n"); haveSlot = true; } @@ -620,7 +620,7 @@ public static void saveTo(File file, Client client) throws IOException { } devastated.add(entity); } - + if (!living.isEmpty()) { output.write("\n"); output.write(indentStr(1) + "\n\n"); @@ -837,7 +837,7 @@ private static void writeEntityList(Writer output, ArrayList list) throw // crits output.write(EntityListFile.getTankCritString(tentity)); } - + // Aero stuff that also applies to LAMs if (entity instanceof IAero) { IAero a = (IAero) entity; @@ -921,7 +921,7 @@ private static void writeEntityList(Writer output, ArrayList list) throw // general aero crits output.write(EntityListFile.getAeroCritString(a)); - + // dropship only crits if (a instanceof Dropship) { Dropship d = (Dropship) a; @@ -984,7 +984,7 @@ private static void writeEntityList(Writer output, ArrayList list) throw } output.write(indentStr(indentLvl + 1) + "\n"); } - + // Write the NC3 Data if needed if (entity.hasNavalC3()) { output.write(indentStr(indentLvl + 1) + "\n"); @@ -1000,7 +1000,7 @@ private static void writeEntityList(Writer output, ArrayList list) throw } output.write(indentStr(indentLvl + 1) + "\n"); } - + // Record if this entity is transported by another if (entity.getTransportId() != Entity.NONE) { output.write(indentStr(indentLvl + 1) + " list) throw output.write(entity.getGame().getForces().forceStringFor(entity)); output.write("\"/>\n"); } - + // Write the escape craft data, if needed if (entity instanceof Aero) { Aero aero = (Aero) entity; @@ -1053,12 +1053,12 @@ private static void writeEntityList(Writer output, ArrayList list) throw } output.write(indentStr(indentLvl + 1) + "\n"); } - if (craft instanceof EscapePods) { + if (craft instanceof EscapePods) { // Original number of pods, used to set the strength of a group of pods output.write(indentStr(indentLvl + 1) + "\n"); } - + } else if (entity instanceof EjectedCrew) { EjectedCrew eCrew = (EjectedCrew) entity; if (!eCrew.getNOtherCrew().isEmpty()) { @@ -1091,7 +1091,7 @@ private static void writeEntityList(Writer output, ArrayList list) throw /** * Writes crew attributes that are tracked individually for multi-crew cockpits. - * + * * @param output * @param entity * @param crew @@ -1165,7 +1165,7 @@ private static void writePilotAttributes(Writer output, final Entity entity, fin output.write(extraData); } } - + private static void writeLAMAeroAttributes(Writer output, final LAMPilot crew, boolean rpgGunnery) throws IOException { output.write("\" gunneryAero=\""); @@ -1180,11 +1180,11 @@ private static void writeLAMAeroAttributes(Writer output, final LAMPilot crew, } output.write("\" pilotingAero=\""); output.write(String.valueOf(crew.getPilotingAero())); - } + } /** * Writes attributes that pertain to entire crew. - * + * * @param output * @param entity * @param crew @@ -1263,7 +1263,7 @@ private static String getMovementString(Tank e) { retVal = retVal.concat("\"/>\n"); return retVal; } - + // Aero crits private static String getAeroCritString(Aero a) { diff --git a/megamek/src/megamek/common/EquipmentType.java b/megamek/src/megamek/common/EquipmentType.java index ae4d1328aa1..0da262a348a 100644 --- a/megamek/src/megamek/common/EquipmentType.java +++ b/megamek/src/megamek/common/EquipmentType.java @@ -196,7 +196,7 @@ public class EquipmentType implements ITechnology { // static list of eq protected static Vector allTypes; protected static Hashtable lookupHash; - + /** * Keeps track of page numbers for rules references. */ @@ -214,7 +214,7 @@ public void setFlags(BigInteger inF) { public long getSubType() { return subType; } - + public void setSubType(int newFlags) { subType = newFlags; } @@ -250,7 +250,7 @@ public String getDesc(double size) { public String getInternalName() { return internalName; } - + public String getRulesRefs() { return rulesRefs; } @@ -297,12 +297,12 @@ public Map getTechLevels() { public int getTechLevel(int date) { return techAdvancement.getTechLevel(date); } - + @Override public int getTechLevel(int date, boolean clan) { return techAdvancement.getTechLevel(date, clan); } - + @Override public SimpleTechLevel getStaticTechLevel() { if (null != techAdvancement.getStaticTechLevel()) { @@ -398,7 +398,7 @@ public boolean isExplosive(Mounted mounted, boolean ignoreCharge) { if (null == mounted) { return explosive; } - + // Special case: discharged M- and B-pods shouldn't explode. if (((this instanceof MPodWeapon) || (this instanceof BPodWeapon)) && ((mounted.getLinked() == null) || (mounted.getLinked() @@ -434,7 +434,7 @@ public boolean isExplosive(Mounted mounted, boolean ignoreCharge) { } Mounted ammo = mounted.getLinked(); if ((ammo == null) || !(ammo.getType() instanceof AmmoType) - || (((AmmoType) ammo.getType()).getMunitionType() != AmmoType.M_INCENDIARY_AC)) { + || (!((AmmoType) ammo.getType()).getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY_AC))) { return false; } } @@ -527,7 +527,7 @@ public boolean isOmniFixedOnly() { public boolean hasModes() { return (modes != null) && (!modes.isEmpty()); } - + /** * Simple way to check if a piece of equipment has a specific usage/firing mode * @param modeType The name of the mode to check. @@ -610,7 +610,7 @@ public boolean removeMode(String mode) { return false; } } - + /** * Add a mode to the Equipment * @@ -791,7 +791,7 @@ public static String getArmorTypeName(int armorType, boolean clan) { public static boolean isArmorType(EquipmentType et) { return getArmorType(et) != T_ARMOR_UNKNOWN; } - + public static int getStructureType(EquipmentType et) { if (et == null) { return T_STRUCTURE_UNKNOWN; @@ -886,10 +886,10 @@ public static double getBaArmorWeightPerPoint(int type, boolean isClan) { return 0.05; } } - + /** * Computes protomech armor weight by point. - * + * * @param type The armor type * @return The weight of a point of armor in kg */ @@ -964,7 +964,7 @@ public static double getSupportVehicleArmorCostPerPoint(int bar) { } return SV_ARMOR_COST[Math.min(bar, SV_ARMOR_COST.length - 1)]; } - + /* Armor and structure are stored as integers and standard uses a generic MiscType that * does not have its own TechAdvancement. */ @@ -1023,7 +1023,7 @@ public static double getSupportVehicleArmorCostPerPoint(int bar) { /** * Tech advancement for armor based on the armor type index and tech base - * + * * @param at The armor type constant * @param clan The armor tech base * @return The tech advancement for the armor @@ -1145,12 +1145,12 @@ public int getTechRating() { public boolean isClan() { return techAdvancement.getTechBase() == TECH_BASE_CLAN; } - + @Override public boolean isMixedTech() { return techAdvancement.getTechBase() == TECH_BASE_ALL; } - + @Override public int getTechBase() { return techAdvancement.getTechBase(); @@ -1169,12 +1169,12 @@ public static String getEquipDateAsString(int date) { public int getIntroductionDate(boolean clan) { return techAdvancement.getIntroductionDate(clan); } - + @Override public int getIntroductionDate() { return techAdvancement.getIntroductionDate(); } - + @Override public int getIntroductionDate(boolean clan, int faction) { return techAdvancement.getIntroductionDate(clan, faction); @@ -1269,7 +1269,7 @@ public boolean equals(Object obj) { final EquipmentType other = (EquipmentType) obj; return Objects.equals(internalName, other.internalName); } - + @Override public int hashCode() { return Objects.hashCode(internalName); @@ -1478,7 +1478,7 @@ public int getBaseAvailability(int era) { /** * This does not include heat generated by stealth armor, as that depends on whether * it is installed as patchwork and does not appear in the equipment list of all unit types. - * + * * @return The amount of heat generated by the equipment */ public int getHeat() { diff --git a/megamek/src/megamek/common/MULParser.java b/megamek/src/megamek/common/MULParser.java index 3a0a97e2eb6..a18781f04b0 100644 --- a/megamek/src/megamek/common/MULParser.java +++ b/megamek/src/megamek/common/MULParser.java @@ -592,7 +592,7 @@ private Entity getEntity(String chassis, @Nullable String model) { Entity newEntity = null; // First check for ejected MechWarriors, vee crews, escape pods and spacecraft crews - if (chassis.equals(EjectedCrew.VEE_EJECT_NAME) + if (chassis.equals(EjectedCrew.VEE_EJECT_NAME) || chassis.equals(EjectedCrew.SPACE_EJECT_NAME)) { return new EjectedCrew(); } else if (chassis.equals(EjectedCrew.PILOT_EJECT_NAME) @@ -701,7 +701,7 @@ private void parseEntityAttributes(Entity entity, Element entityTag) { } catch (Exception e) { entity.setStartingWidth(3); } - + // deployment zone offset try { int deployZoneOffset = Integer.parseInt(entityTag.getAttribute(DEPLOYMENT_ZONE_OFFSET)); @@ -759,7 +759,7 @@ private void parseEntityAttributes(Entity entity, Element entityTag) { if (entity instanceof VTOL) { String elevString = entityTag.getAttribute(ELEVATION); VTOL v = (VTOL) entity; - + if (!elevString.isBlank()) { int elevation = 0; @@ -865,7 +865,7 @@ private void parseEntityAttributes(Entity entity, Element entityTag) { if (!infSpec.isBlank()) { inf.setSpecializations(Integer.parseInt(infSpec)); } - + String infSquadNum = entityTag.getAttribute(INF_SQUAD_NUM); if (!infSquadNum.isBlank()) { inf.setSquadCount(Integer.parseInt(infSquadNum)); @@ -1053,7 +1053,7 @@ private void setCrewAttributes(final @Nullable GameOptions options, final Entity crew.setCurrentSize(Compute.getFullCrewSize(entity)); } } - + if (attributes.containsKey(CURRENTSIZE)) { if (!attributes.get(CURRENTSIZE).isBlank()) { int crewCurrentSize = 1; @@ -1852,7 +1852,7 @@ else if (!mounted.getType().getInternalName() } if (entity.isSupportVehicle() && (mounted.getType() instanceof InfantryWeapon)) { for (Mounted ammo = mounted.getLinked(); ammo != null; ammo = ammo.getLinked()) { - if (((AmmoType) ammo.getType()).getMunitionType() == AmmoType.M_INFERNO) { + if (((AmmoType) ammo.getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) { if (!inferno.isBlank()) { String[] fields = inferno.split(":"); ammo.setShotsLeft(Integer.parseInt(fields[0])); @@ -2295,7 +2295,7 @@ private void parseNC3(Element nc3Tag, Entity entity) { } } } - + /** * Parse an EscapeCraft tag for the given Entity. * @@ -2316,7 +2316,7 @@ private void parseEscapeCraft(Element escCraftTag, Entity entity) { warning.append("Invalid external entity id in EscapeCraft tag.\n"); } } - + /** * Parse an EscapedPassengers tag for the given Entity. * @@ -2378,7 +2378,7 @@ private void parseEscapedCrew(Element escCrewTag, Entity entity) { } } } - + /** * Parse an original si tag for the given Entity. Used by Escape Pods * @@ -2394,7 +2394,7 @@ private void parseOSI(Element OsiTag, Entity entity) { warning.append("Invalid SI value in original structural integrity tag.\n"); } } - + /** * Parse an original men tag for the given Entity. Used by Escaped spacecraft crew * @@ -2410,7 +2410,7 @@ private void parseOMen(Element OMenTag, Entity entity) { warning.append("Invalid internal value in original number of men tag.\n"); } } - + /** * Parse a conveyance tag for the given Entity. Used to resolve crew damage to transported entities * @@ -2426,7 +2426,7 @@ private void parseConveyance(Element conveyanceTag, Entity entity) { warning.append("Invalid transport id in conveyance tag.\n"); } } - + /** * Parse an id tag for the given Entity. Used to resolve crew damage to transported entities * @@ -2446,9 +2446,9 @@ private void parseId(Element idTag, Entity entity) { warning.append("Invalid id in conveyance tag.\n"); } } - + /** - * Parse a force tag for the given Entity. + * Parse a force tag for the given Entity. */ private void parseForce(Element forceTag, Entity entity) { entity.setForceString(forceTag.getAttribute(FORCEATT)); diff --git a/megamek/src/megamek/common/Mounted.java b/megamek/src/megamek/common/Mounted.java index 302a5bcd1a9..9e04dd0eebb 100644 --- a/megamek/src/megamek/common/Mounted.java +++ b/megamek/src/megamek/common/Mounted.java @@ -1212,21 +1212,21 @@ public int getExplosionDamage() { damagePerShot = 15; } - long mType = atype.getMunitionType(); + EnumSet mType = atype.getMunitionType(); // both Dead-Fire and Tandem-charge SRM's do 3 points of damage per // shot when critted // Dead-Fire LRM's do 2 points of damage per shot when critted. - if ((mType == AmmoType.M_DEAD_FIRE) - || (mType == AmmoType.M_TANDEM_CHARGE)) { + if ((mType.contains(AmmoType.Munitions.M_DEAD_FIRE)) + || (mType.contains(AmmoType.Munitions.M_TANDEM_CHARGE))) { damagePerShot++; } else if (atype.getAmmoType() == AmmoType.T_TASER) { damagePerShot = 6; } if (atype.getAmmoType() == AmmoType.T_MEK_MORTAR) { - if ((mType == AmmoType.M_AIRBURST) - || (mType == AmmoType.M_FLARE) - || (mType == AmmoType.M_SMOKE_WARHEAD)) { + if ((mType.contains(AmmoType.Munitions.M_AIRBURST)) + || (mType.contains(AmmoType.Munitions.M_FLARE)) + || (mType.contains(AmmoType.Munitions.M_SMOKE_WARHEAD))) { damagePerShot = 1; } else { damagePerShot = 2; @@ -1248,9 +1248,9 @@ && curMode().equals("Powered Down")) { Mounted link = getLinked(); AmmoType atype = ((AmmoType) link.getType()); int damagePerShot = atype.getDamagePerShot(); - // Launchers with Dead-Fire missles in them do an extra point of + // Launchers with Dead-Fire missiles in them do an extra point of // damage per shot when critted - if (atype.getAmmoType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { damagePerShot++; } @@ -2098,7 +2098,7 @@ public boolean isHomingAmmoInHomingMode() { } AmmoType ammoType = (AmmoType) getType(); - return ammoType.getMunitionType() == AmmoType.M_HOMING && + return ammoType.getMunitionType().contains(AmmoType.Munitions.M_HOMING) && curMode().equals("Homing"); } } \ No newline at end of file diff --git a/megamek/src/megamek/common/SmallWeaponAmmoType.java b/megamek/src/megamek/common/SmallWeaponAmmoType.java index b7a2c776602..e166fb9712d 100644 --- a/megamek/src/megamek/common/SmallWeaponAmmoType.java +++ b/megamek/src/megamek/common/SmallWeaponAmmoType.java @@ -16,6 +16,7 @@ import megamek.common.weapons.infantry.InfantryWeapon; +import java.util.EnumSet; import java.util.List; import java.util.stream.Collectors; @@ -32,10 +33,10 @@ public SmallWeaponAmmoType(InfantryWeapon weapon) { setInternalName(generateInternalName(weapon)); name = weapon.name + " Ammo"; if (weapon.getInternalName().endsWith("Inferno")) { - munitionType = M_INFERNO; + munitionType = EnumSet.of(AmmoType.Munitions.M_INFERNO); name += " (Inferno)"; } else { - munitionType = M_STANDARD; + munitionType = EnumSet.of(AmmoType.Munitions.M_STANDARD); } tonnage = weapon.getAmmoWeight(); cost = weapon.getAmmoCost(); diff --git a/megamek/src/megamek/common/WeaponType.java b/megamek/src/megamek/common/WeaponType.java index 31a3fe55d2b..4b37d4d680d 100644 --- a/megamek/src/megamek/common/WeaponType.java +++ b/megamek/src/megamek/common/WeaponType.java @@ -398,13 +398,13 @@ public int[] getRanges(Mounted weapon) { boolean hasLoadedAmmo = (weapon.getLinked() != null); if ((getAmmoType() == AmmoType.T_ATM) && hasLoadedAmmo) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE)) { + if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE))) { minRange = 4; sRange = 9; mRange = 18; lRange = 27; eRange = 36; - } else if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE)) { + } else if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE))) { minRange = 0; sRange = 3; mRange = 6; @@ -414,13 +414,15 @@ public int[] getRanges(Mounted weapon) { } if ((getAmmoType() == AmmoType.T_IATM) && hasLoadedAmmo) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if ((atype.getAmmoType() == AmmoType.T_IATM) && (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE)) { + if ((atype.getAmmoType() == AmmoType.T_IATM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE))) { minRange = 4; sRange = 9; mRange = 18; lRange = 27; eRange = 36; - } else if ((atype.getAmmoType() == AmmoType.T_IATM) && ((atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE)||(atype.getMunitionType() == AmmoType.M_IATM_IMP))) { + } else if ((atype.getAmmoType() == AmmoType.T_IATM) + && ((atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IMP)))) { minRange = 0; sRange = 3; mRange = 6; @@ -443,7 +445,7 @@ public int[] getRanges(Mounted weapon) { lRange = 9; eRange = 12; } - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { if (atype.hasFlag(AmmoType.F_MML_LRM)) { minRange = 4; sRange = 5; @@ -461,7 +463,7 @@ public int[] getRanges(Mounted weapon) { } if ((getAmmoType() == AmmoType.T_LRM) && hasLoadedAmmo) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if ((atype.getAmmoType() == AmmoType.T_LRM) && (atype.getMunitionType() == AmmoType.M_DEAD_FIRE)) { + if ((atype.getAmmoType() == AmmoType.T_LRM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE))) { minRange = 4; sRange = 5; mRange = 10; @@ -471,7 +473,7 @@ public int[] getRanges(Mounted weapon) { } if ((getAmmoType() == AmmoType.T_SRM) && hasLoadedAmmo) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if ((atype.getAmmoType() == AmmoType.T_SRM) && (atype.getMunitionType() == AmmoType.M_DEAD_FIRE)) { + if ((atype.getAmmoType() == AmmoType.T_SRM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE))) { minRange = 0; sRange = 2; mRange = 4; @@ -538,9 +540,9 @@ public int getMaxRange(Mounted weapon) { if (null != weapon) { if (getAmmoType() == AmmoType.T_ATM) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE)) { + if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE))) { return RANGE_EXT; - } else if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE)) { + } else if ((atype.getAmmoType() == AmmoType.T_ATM) && (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE))) { return RANGE_SHORT; } } diff --git a/megamek/src/megamek/common/actions/AbstractAttackAction.java b/megamek/src/megamek/common/actions/AbstractAttackAction.java index 4e008125bf3..cc1564ab644 100644 --- a/megamek/src/megamek/common/actions/AbstractAttackAction.java +++ b/megamek/src/megamek/common/actions/AbstractAttackAction.java @@ -155,8 +155,8 @@ public static ToHitData nightModifiers(Game game, Targetable target, AmmoType at || (atype.getAmmoType() == AmmoType.T_LAC) || (atype.getAmmoType() == AmmoType.T_AC_IMP) || (atype.getAmmoType() == AmmoType.T_PAC)) - && ((atype.getMunitionType() == AmmoType.M_INCENDIARY_AC) - || (atype.getMunitionType() == AmmoType.M_TRACER))) { + && ((atype.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY_AC)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_TRACER)))) { toHit.addModifier(-1, "incendiary/tracer ammo"); night_modifier--; } diff --git a/megamek/src/megamek/common/actions/WeaponAttackAction.java b/megamek/src/megamek/common/actions/WeaponAttackAction.java index e59cc8bf9b8..18fbe60125c 100644 --- a/megamek/src/megamek/common/actions/WeaponAttackAction.java +++ b/megamek/src/megamek/common/actions/WeaponAttackAction.java @@ -36,10 +36,7 @@ import org.apache.logging.log4j.LogManager; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.Vector; +import java.util.*; /** * Represents intention to fire a weapon at the target. @@ -51,7 +48,7 @@ public class WeaponAttackAction extends AbstractAttackAction implements Serializ private int weaponId; private int ammoId = -1; - private long ammoMunitionType; + private EnumSet ammoMunitionType = EnumSet.noneOf(AmmoType.Munitions.class); private int ammoCarrier = -1; private int aimedLocation = Entity.LOC_NONE; private AimingMode aimMode = AimingMode.NONE; @@ -136,7 +133,7 @@ public int getAmmoId() { return ammoId; } - public long getAmmoMunitionType() { + public EnumSet getAmmoMunitionType() { return ammoMunitionType; } @@ -164,7 +161,7 @@ public void setAmmoId(int ammoId) { this.ammoId = ammoId; } - public void setAmmoMunitionType(long ammoMunitionType) { + public void setAmmoMunitionType(EnumSet ammoMunitionType) { this.ammoMunitionType = ammoMunitionType; } @@ -348,7 +345,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, final AmmoType atype = ammo == null ? null : (AmmoType) ammo.getType(); - long munition = AmmoType.M_STANDARD; + EnumSet munition = EnumSet.of(AmmoType.Munitions.M_STANDARD); if (atype != null) { munition = atype.getMunitionType(); } @@ -365,9 +362,9 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, && ( (((atype.getAmmoType() == AmmoType.T_AC_LBX) || (atype.getAmmoType() == AmmoType.T_AC_LBX_THB) || (atype.getAmmoType() == AmmoType.T_SBGAUSS)) - && (munition == AmmoType.M_CLUSTER) + && (munition.contains(AmmoType.Munitions.M_CLUSTER)) ) - || (munition == AmmoType.M_FLAK) || (atype.getAmmoType() == AmmoType.T_HAG) + || munition.contains(AmmoType.Munitions.M_FLAK) || (atype.getAmmoType() == AmmoType.T_HAG) || atype.countsAsFlak() ); @@ -375,15 +372,15 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, // BMM p. 31, semi-guided indirect missile attacks vs tagged targets ignore terrain modifiers boolean semiGuidedIndirectVsTaggedTarget = isIndirect && - (atype != null) && atype.getMunitionType() == AmmoType.M_SEMIGUIDED && + (atype != null) && atype.getMunitionType().contains(AmmoType.Munitions.M_SEMIGUIDED) && Compute.isTargetTagged(target, game); boolean isInferno = ((atype != null) && ((atype.getAmmoType() == AmmoType.T_SRM) || (atype.getAmmoType() == AmmoType.T_SRM_IMP) || (atype.getAmmoType() == AmmoType.T_MML)) - && (atype.getMunitionType() == AmmoType.M_INFERNO)) - || (isWeaponInfantry && (wtype.hasFlag(WeaponType.F_INFERNO))); + && (atype.getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) + || (isWeaponInfantry && (wtype.hasFlag(WeaponType.F_INFERNO)))); boolean isArtilleryDirect = (wtype.hasFlag(WeaponType.F_ARTILLERY) || (wtype instanceof CapitalMissileWeapon @@ -432,14 +429,14 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_LRM) || (atype.getAmmoType() == AmmoType.T_LRM_IMP)) - && (munition == AmmoType.M_HEAT_SEEKING); + && (munition.contains(AmmoType.Munitions.M_HEAT_SEEKING)); boolean bFTL = (atype != null) && ((atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_LRM) || (atype.getAmmoType() == AmmoType.T_LRM_IMP)) - && (munition == AmmoType.M_FOLLOW_THE_LEADER) - && !ComputeECM.isAffectedByECM(ae, ae.getPosition(), target.getPosition()); + && (munition.contains(AmmoType.Munitions.M_FOLLOW_THE_LEADER) + && !ComputeECM.isAffectedByECM(ae, ae.getPosition(), target.getPosition())); Mounted mLinker = weapon.getLinkedBy(); @@ -450,7 +447,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, boolean bArtemisV = ((mLinker != null) && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag(MiscType.F_ARTEMIS_V) && !isECMAffected && !bMekTankStealthActive && (atype != null) - && (munition == AmmoType.M_ARTEMIS_V_CAPABLE)); + && (munition.contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))); if (ae.usesWeaponBays()) { for (int wId : weapon.getBayWeapons()) { @@ -464,7 +461,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, AmmoType bAmmo = (AmmoType) bayWAmmo.getType(); //If we're using optional rules and firing Arrow Homing missiles from a bay... - isHoming = bAmmo != null && bAmmo.getMunitionType() == AmmoType.M_HOMING; + isHoming = bAmmo != null && bAmmo.getMunitionType().contains(AmmoType.Munitions.M_HOMING); //If the artillery bay is firing cruise missiles, they have some special rules //It is possible to combine cruise missiles and other artillery in a bay, so @@ -481,7 +478,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, bArtemisV = ((mLinker != null) && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag(MiscType.F_ARTEMIS_V) && !isECMAffected && !bMekTankStealthActive && (atype != null) - && (bAmmo != null) && (bAmmo.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)); + && (bAmmo != null) && (bAmmo.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))); } } @@ -513,7 +510,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, || (atype.getAmmoType() == AmmoType.T_SRM) || (atype.getAmmoType() == AmmoType.T_SRM_IMP) || (atype.getAmmoType() == AmmoType.T_NLRM)) - && (munition == AmmoType.M_NARC_CAPABLE)) { + && (munition.contains(AmmoType.Munitions.M_NARC_CAPABLE))) { isINarcGuided = true; } } @@ -527,8 +524,8 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, boolean narcSpotter = false; if (isIndirect && !ae.hasAbility(OptionsConstants.GUNNERY_OBLIQUE_ATTACKER)) { if ((target instanceof Entity) && !isTargetECMAffected && (te != null) && (atype != null) && usesAmmo - && (munition == AmmoType.M_NARC_CAPABLE) - && (te.isNarcedBy(ae.getOwner().getTeam()) || te.isINarcedBy(ae.getOwner().getTeam()))) { + && (munition.contains(AmmoType.Munitions.M_NARC_CAPABLE) + && (te.isNarcedBy(ae.getOwner().getTeam()) || te.isINarcedBy(ae.getOwner().getTeam())))) { spotter = te; narcSpotter = true; } else { @@ -540,7 +537,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_NLRM) || (atype.getAmmoType() == AmmoType.T_MEK_MORTAR)) - && (munition == AmmoType.M_SEMIGUIDED)) { + && (munition.contains(AmmoType.Munitions.M_SEMIGUIDED))) { for (TagInfo ti : game.getTagInfo()) { if (target.getId() == ti.target.getId()) { spotter = game.getEntity(ti.attackerId); @@ -560,7 +557,7 @@ private static ToHitData toHitCalc(Game game, int attackerId, Targetable target, if (usesAmmo && ((wtype.getAmmoType() == AmmoType.T_LRM) || (wtype.getAmmoType() == AmmoType.T_LRM_IMP)) && (atype != null) - && (munition == AmmoType.M_MULTI_PURPOSE) + && (munition.contains(AmmoType.Munitions.M_MULTI_PURPOSE)) && (ae.getElevation() == -1) && (ae.getLocationStatus(weapon.getLocation()) == ILocationExposureStatus.WET)) { mpMelevationHack = true; @@ -854,25 +851,25 @@ public static ToHitData toHit(Game game, int attackerId, Targetable target) { //Conventional fighter, Aerospace and fighter LAM attackers if (ae.isAero()) { toHit = compileAeroAttackerToHitMods(game, ae, target, ttype, toHit, Entity.LOC_NONE, - AimingMode.NONE, eistatus, null, null, null, AmmoType.M_STANDARD, + AimingMode.NONE, eistatus, null, null, null, EnumSet.of(AmmoType.Munitions.M_STANDARD), false, false, false, false, false); //Everyone else } else { toHit = compileAttackerToHitMods(game, ae, target, los, toHit, toSubtract, Entity.LOC_NONE, - AimingMode.NONE, null, null, weaponId, null, AmmoType.M_STANDARD, + AimingMode.NONE, null, null, weaponId, null, EnumSet.of(AmmoType.Munitions.M_STANDARD), false, false, false, false, false); } } // Collect the modifiers for the target's condition/actions toHit = compileTargetToHitMods(game, ae, target, ttype, los, toHit, toSubtract, Entity.LOC_NONE, - AimingMode.NONE, distance, null, null, null, AmmoType.M_STANDARD, + AimingMode.NONE, distance, null, null, null, EnumSet.of(AmmoType.Munitions.M_STANDARD), false, false, isAttackerInfantry, false, false, false, false); // Collect the modifiers for terrain and line-of-sight. This includes any related to-hit table changes toHit = compileTerrainAndLosToHitMods(game, ae, target, ttype, aElev, tElev, targEl, distance, los, toHit, - losMods, toSubtract, eistatus, null, null, weaponId, null, AmmoType.M_STANDARD, isAttackerInfantry, + losMods, toSubtract, eistatus, null, null, weaponId, null, EnumSet.of(AmmoType.Munitions.M_STANDARD), isAttackerInfantry, inSameBuilding, false, false, false); // okay! @@ -921,7 +918,7 @@ public static ToHitData toHit(Game game, int attackerId, Targetable target) { */ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Targetable target, int ttype, LosEffects los, ToHitData losMods, ToHitData toHit, int distance, Entity spotter, - WeaponType wtype, Mounted weapon, int weaponId, AmmoType atype, Mounted ammo, long munition, + WeaponType wtype, Mounted weapon, int weaponId, AmmoType atype, Mounted ammo, EnumSet munition, boolean isArtilleryDirect, boolean isArtilleryFLAK, boolean isArtilleryIndirect, boolean isAttackerInfantry, boolean isBearingsOnlyMissile, boolean isCruiseMissile, boolean exchangeSwarmTarget, boolean isHoming, boolean isInferno, boolean isIndirect, boolean isStrafing, boolean isTAG, boolean targetInBuilding, @@ -978,7 +975,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_LRM_IMP) || (atype.getAmmoType() == AmmoType.T_MEK_MORTAR)) - && (munition == AmmoType.M_FLARE))) { + && (munition.contains(AmmoType.Munitions.M_FLARE)))) { return Messages.getString("WeaponAttackAction.NoFlares"); } @@ -986,7 +983,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta if (((atype.getAmmoType() == AmmoType.T_LRM) || (atype.getAmmoType() == AmmoType.T_LRM_IMP) || (atype.getAmmoType() == AmmoType.T_MML)) - && (atype.getMunitionType() == AmmoType.M_FLARE) + && (atype.getMunitionType().contains(AmmoType.Munitions.M_FLARE)) && (target.getTargetType() != Targetable.TYPE_FLARE_DELIVER)) { return Messages.getString("WeaponAttackAction.OnlyFlare"); } @@ -1000,8 +997,8 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // Some Mek mortar ammo types can only be aimed at a hex if (wtype != null && wtype.hasFlag(WeaponType.F_MEK_MORTAR) - && ((atype.getMunitionType() == AmmoType.M_AIRBURST) || (atype.getMunitionType() == AmmoType.M_FLARE) - || (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD))) { + && ((atype.getMunitionType().contains(AmmoType.Munitions.M_AIRBURST)) || (atype.getMunitionType().contains(AmmoType.Munitions.M_FLARE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)))) { if (!(target instanceof HexTarget)) { return String.format(Messages.getString("WeaponAttackAction.AmmoAtHexOnly"), atype.getSubMunitionName()); } @@ -1018,11 +1015,11 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta || (atype.getAmmoType() == AmmoType.T_LRM_IMP) || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_MEK_MORTAR)) - && ((atype.getMunitionType() == AmmoType.M_THUNDER) - || (atype.getMunitionType() == AmmoType.M_THUNDER_ACTIVE) - || (atype.getMunitionType() == AmmoType.M_THUNDER_INFERNO) - || (atype.getMunitionType() == AmmoType.M_THUNDER_VIBRABOMB) - || (atype.getMunitionType() == AmmoType.M_THUNDER_AUGMENTED)) + && ((atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_ACTIVE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_INFERNO)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_AUGMENTED))) && (target.getTargetType() != Targetable.TYPE_MINEFIELD_DELIVER)) { return Messages.getString("WeaponAttackAction.OnlyMinefields"); } @@ -1070,7 +1067,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta return Messages.getString("WeaponAttackAction.AeEvading"); } - //If we're lying mines, we can't shoot. + //If we're laying mines, we can't shoot. if (ae.isLayingMines()) { return Messages.getString("WeaponAttackAction.BusyLayingMines"); } @@ -1145,7 +1142,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // but we do allow vehicle flamers to cool. Also swarm missile secondary targets and strafing are exempt. if (!game.getOptions().booleanOption(OptionsConstants.BASE_FRIENDLY_FIRE) && !isStrafing && !exchangeSwarmTarget) { if (te != null && !te.getOwner().isEnemyOf(ae.getOwner())) { - if (!(usesAmmo && atype != null && (atype.getMunitionType() == AmmoType.M_COOLANT))) { + if (!(usesAmmo && atype != null && (atype.getMunitionType().contains(AmmoType.Munitions.M_COOLANT)))) { return Messages.getString("WeaponAttackAction.NoFriendlyTarget"); } } @@ -1182,7 +1179,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // Mine Clearance munitions can only target hexes for minefield clearance if (!(target instanceof HexTarget) && (atype != null) - && (atype.getMunitionType() == AmmoType.M_MINE_CLEARANCE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_MINE_CLEARANCE))) { return Messages.getString("WeaponAttackAction.MineClearHexOnly"); } @@ -1296,15 +1293,15 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta //Torpedos must remain in the water over their whole path to the target if ((atype != null) - && ((atype.getAmmoType() == AmmoType.T_LRM_TORPEDO) + && (((atype.getAmmoType() == AmmoType.T_LRM_TORPEDO)) || (atype.getAmmoType() == AmmoType.T_SRM_TORPEDO) || (((atype.getAmmoType() == AmmoType.T_SRM) || (atype.getAmmoType() == AmmoType.T_SRM_IMP) || (atype.getAmmoType() == AmmoType.T_MRM) || (atype.getAmmoType() == AmmoType.T_LRM) || (atype.getAmmoType() == AmmoType.T_LRM_IMP) - || (atype.getAmmoType() == AmmoType.T_MML)) && (atype.getMunitionType() == AmmoType.M_TORPEDO))) - && (los.getMinimumWaterDepth() < 1)) { + || (atype.getAmmoType() == AmmoType.T_MML)) && (atype.getMunitionType().contains(AmmoType.Munitions.M_TORPEDO))) + && (los.getMinimumWaterDepth() < 1))) { return Messages.getString("WeaponAttackAction.TorpOutOfWater"); } @@ -1598,7 +1595,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // "Cool" mode for vehicle flamer requires coolant ammo boolean vf_cool = false; - if (atype != null && ammo != null && (((AmmoType) ammo.getType()).getMunitionType() == AmmoType.M_COOLANT)) { + if (atype != null && ammo != null && (((AmmoType) ammo.getType()).getMunitionType().contains(AmmoType.Munitions.M_COOLANT))) { vf_cool = true; } @@ -1782,6 +1779,20 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta return Messages.getString("WeaponAttackAction.OnlyArrowArty"); } } + } else if ((wtype.getAmmoType() == AmmoType.T_ARROW_IV) + && atype != null && atype.getMunitionType().contains(AmmoType.Munitions.M_ADA) ) { + // Air-Defense Arrow IV can only target airborne enemy units between 1 and 51 hexes away + // (same ground map/Low Altitude hex, 1 LAH, or 2 Low Altitude hexes away) and below + // altitude 8. + if(!(target.isAirborne() || target.isAirborneVTOLorWIGE())){ + return Messages.getString("WeaponAttackAction.AaaGroundAttack"); + } + if (target.getAltitude() > 8){ + return Messages.getString("WeaponAttackAction.OutOfRange"); + } + if (distance > Board.DEFAULT_BOARD_HEIGHT * 3){ + return Messages.getString("WeaponAttackAction.OutOfRange"); + } } } else if (weapon.isInBearingsOnlyMode()) { // We don't really need to do anything here. This just prevents these weapons @@ -1801,20 +1812,21 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta // Direct-fire artillery attacks. if (isArtilleryDirect) { - if ((atype != null && atype.countsAsFlak()) && !(target.isAirborne() || target.isAirborneVTOLorWIGE())){ - return Messages.getString("WeaponAttackAction.FlakOnGroundedAero"); - } // Cruise missiles cannot make direct-fire attacks if (isCruiseMissile) { return Messages.getString("WeaponAttackAction.NoDirectCruiseMissile"); } - // Direct fire artillery cannot be fired at less than 6 hexes - if (isArtilleryDirect && !target.isAirborne() && (Compute.effectiveDistance(game, ae, target) <= 6)) { - return Messages.getString("WeaponAttackAction.TooShortForDirectArty"); - } - // ...or more than 17 hexes - if (distance > Board.DEFAULT_BOARD_HEIGHT) { - return Messages.getString("WeaponAttackAction.TooLongForDirectArty"); + // ADA is _fired_ by artillery but is just a Flak attack, and so bypasses these restrictions + if (null != atype && !atype.getMunitionType().contains(AmmoType.Munitions.M_ADA)) { + // Direct fire artillery cannot be fired at less than 6 hexes, + // except at ASFs in the air (TO:AR 6th print, p153.) + if (!(target.isAirborne()) && (Compute.effectiveDistance(game, ae, target) <= 6)) { + return Messages.getString("WeaponAttackAction.TooShortForDirectArty"); + } + // ...or more than 17 hexes + if (distance > Board.DEFAULT_BOARD_HEIGHT) { + return Messages.getString("WeaponAttackAction.TooLongForDirectArty"); + } } if (isHoming) { if ((te == null) || (te.getTaggedBy() == -1)) { @@ -2908,7 +2920,7 @@ private static ToHitData compileEnvironmentalToHitMods(Game game, Entity ae, Tar * @param narcSpotter flag that indicates whether this spotting entity is using NARC equipment */ private static ToHitData compileWeaponToHitMods(Game game, Entity ae, Entity spotter, Targetable target, - int ttype, ToHitData toHit, WeaponType wtype, Mounted weapon, AmmoType atype, long munition, + int ttype, ToHitData toHit, WeaponType wtype, Mounted weapon, AmmoType atype, EnumSet munition, boolean isFlakAttack, boolean isIndirect, boolean narcSpotter) { if (ae == null || wtype == null || weapon == null) { // Can't calculate weapon mods without a valid weapon and an attacker to fire it @@ -3029,7 +3041,7 @@ private static ToHitData compileWeaponToHitMods(Game game, Entity ae, Entity spo || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_NLRM) || (atype.getAmmoType() == AmmoType.T_MEK_MORTAR)) - && (munition == AmmoType.M_SEMIGUIDED)) { + && (munition.contains(AmmoType.Munitions.M_SEMIGUIDED))) { if (Compute.isTargetTagged(target, game)) { toHit.addModifier(-1, Messages.getString("WeaponAttackAction.SemiGuidedIndirect")); @@ -3192,7 +3204,7 @@ private static ToHitData compileWeaponToHitMods(Game game, Entity ae, Entity spo * @param isINarcGuided flag that indicates whether the target is broadcasting an iNarc beacon */ private static ToHitData compileAmmoToHitMods(Game game, Entity ae, Targetable target, int ttype, ToHitData toHit, - WeaponType wtype, Mounted weapon, AmmoType atype, long munition, boolean bApollo, boolean bArtemisV, + WeaponType wtype, Mounted weapon, AmmoType atype, EnumSet munition, boolean bApollo, boolean bArtemisV, boolean bFTL, boolean bHeatSeeking, boolean isECMAffected, boolean isINarcGuided) { if (ae == null || atype == null) { // Can't calculate ammo mods without valid ammo and an attacker to fire it @@ -3217,7 +3229,7 @@ private static ToHitData compileAmmoToHitMods(Game game, Entity ae, Targetable t || (atype.getAmmoType() == AmmoType.T_LAC) || (atype.getAmmoType() == AmmoType.T_AC_IMP) || (atype.getAmmoType() == AmmoType.T_PAC)) - && (munition == AmmoType.M_ARMOR_PIERCING)) { + && (munition.contains(AmmoType.Munitions.M_ARMOR_PIERCING))) { toHit.addModifier(1, Messages.getString("WeaponAttackAction.ApAmmo")); } @@ -3305,7 +3317,7 @@ private static ToHitData compileAmmoToHitMods(Game game, Entity ae, Targetable t || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_SRM) || (atype.getAmmoType() == AmmoType.T_SRM_IMP)) - && (munition == AmmoType.M_LISTEN_KILL) && !((te != null) && te.isClan())) { + && (munition.contains(AmmoType.Munitions.M_LISTEN_KILL)) && !((te != null) && te.isClan())) { toHit.addModifier(-1, Messages.getString("WeaponAttackAction.ListenKill")); } @@ -3344,7 +3356,7 @@ private static ToHitData compileAttackerToHitMods(Game game, Entity ae, Targetab int toSubtract, int aimingAt, AimingMode aimingMode, WeaponType wtype, Mounted weapon, int weaponId, AmmoType atype, - long munition, boolean isFlakAttack, + EnumSet munition, boolean isFlakAttack, boolean isHaywireINarced, boolean isNemesisConfused, boolean isWeaponFieldGuns, boolean usesAmmo) { @@ -3542,10 +3554,10 @@ private static ToHitData compileAttackerToHitMods(Game game, Entity ae, Targetab // LB-X cluster, HAG flak, flak ammo ineligible for TC bonus boolean usesLBXCluster = usesAmmo && (atype != null) && (atype.getAmmoType() == AmmoType.T_AC_LBX || atype.getAmmoType() == AmmoType.T_AC_LBX_THB) - && munition == AmmoType.M_CLUSTER; + && munition.contains(AmmoType.Munitions.M_CLUSTER); boolean usesHAGFlak = usesAmmo && (atype != null) && atype.getAmmoType() == AmmoType.T_HAG && isFlakAttack; boolean isSBGauss = usesAmmo && (atype != null) && atype.getAmmoType() == AmmoType.T_SBGAUSS; - boolean isFlakAmmo = usesAmmo && (atype != null) && (munition == AmmoType.M_FLAK); + boolean isFlakAmmo = usesAmmo && (atype != null) && (munition.contains(AmmoType.Munitions.M_FLAK)); if (ae.hasTargComp() && wtype != null && wtype.hasFlag(WeaponType.F_DIRECT_FIRE) && !wtype.hasFlag(WeaponType.F_CWS) && !wtype.hasFlag(WeaponType.F_TASER) && (!usesAmmo || !(usesLBXCluster || usesHAGFlak || isSBGauss || isFlakAmmo))) { @@ -3626,7 +3638,7 @@ private static ToHitData compileAeroAttackerToHitMods(Game game, Entity ae, Targ int ttype, ToHitData toHit, int aimingAt, AimingMode aimingMode, int eistatus, WeaponType wtype, Mounted weapon, - AmmoType atype, long munition, + AmmoType atype, EnumSet munition, boolean isArtilleryIndirect, boolean isFlakAttack, boolean isNemesisConfused, @@ -3675,10 +3687,10 @@ private static ToHitData compileAeroAttackerToHitMods(Game game, Entity ae, Targ // LB-X cluster, HAG flak, flak ammo ineligible for TC bonus boolean usesLBXCluster = usesAmmo && (atype != null) && (atype.getAmmoType() == AmmoType.T_AC_LBX || atype.getAmmoType() == AmmoType.T_AC_LBX_THB) - && munition == AmmoType.M_CLUSTER; + && munition.contains(AmmoType.Munitions.M_CLUSTER); boolean usesHAGFlak = usesAmmo && (atype != null) && atype.getAmmoType() == AmmoType.T_HAG && isFlakAttack; boolean isSBGauss = usesAmmo && (atype != null) && atype.getAmmoType() == AmmoType.T_SBGAUSS; - boolean isFlakAmmo = usesAmmo && (atype != null) && (munition == AmmoType.M_FLAK); + boolean isFlakAmmo = usesAmmo && (atype != null) && (munition.contains(AmmoType.Munitions.M_FLAK)); if (ae.hasTargComp() && wtype != null && wtype.hasFlag(WeaponType.F_DIRECT_FIRE) && !wtype.hasFlag(WeaponType.F_CWS) && !wtype.hasFlag(WeaponType.F_TASER) && (!usesAmmo || !(usesLBXCluster || usesHAGFlak || isSBGauss || isFlakAmmo))) { @@ -3930,7 +3942,7 @@ else if (wtype.getAtClass() == WeaponType.CLASS_LBX_AC) { Mounted bammo = bweap.getLinked(); if (bammo != null) { AmmoType batype = (AmmoType) bammo.getType(); - if (batype.getMunitionType() != AmmoType.M_CLUSTER) { + if (!batype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { onlyCluster = false; break; } @@ -4154,7 +4166,7 @@ private static ToHitData compileTargetToHitMods(Game game, Entity ae, Targetable int toSubtract, int aimingAt, AimingMode aimingMode, int distance, WeaponType wtype, Mounted weapon, AmmoType atype, - long munition, boolean isArtilleryDirect, + EnumSet munition, boolean isArtilleryDirect, boolean isArtilleryIndirect, boolean isAttackerInfantry, boolean exchangeSwarmTarget, boolean isIndirect, @@ -4276,7 +4288,7 @@ else if ((te instanceof Tank || (te instanceof QuadVee && te.getConversionMode() && !wtype.hasFlag(WeaponType.F_TASER) && (atype != null) && (!usesAmmo || !(((atype.getAmmoType() == AmmoType.T_AC_LBX) || (atype.getAmmoType() == AmmoType.T_AC_LBX_THB)) - && (munition == AmmoType.M_CLUSTER)))) { + && (munition.contains(AmmoType.Munitions.M_CLUSTER))))) { tcMod = 2; } int ghostTargetMoF = (ae.getCrew().getSensorOps() + ghostTargetMod) @@ -4309,7 +4321,7 @@ else if ((te instanceof Tank || (te instanceof QuadVee && te.getConversionMode() || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_NLRM) || (atype.getAmmoType() == AmmoType.T_MEK_MORTAR)) - && (munition == AmmoType.M_SEMIGUIDED) && (te.getTaggedBy() != -1)) { + && (munition.contains(AmmoType.Munitions.M_SEMIGUIDED)) && (te.getTaggedBy() != -1)) { int nAdjust = thTemp.getValue(); if (nAdjust > 0) { toHit.append(new ToHitData(-nAdjust, Messages.getString("WeaponAttackAction.SemiGuidedTag"))); @@ -4321,7 +4333,7 @@ else if ((atype != null) || (atype.getAmmoType() == AmmoType.T_LAC) || (atype.getAmmoType() == AmmoType.T_AC_IMP) || (atype.getAmmoType() == AmmoType.T_PAC)) - && (munition == AmmoType.M_PRECISION)) { + && (munition.contains(AmmoType.Munitions.M_PRECISION))) { int nAdjust = Math.min(2, thTemp.getValue()); if (nAdjust > 0) { toHit.append(new ToHitData(-nAdjust, Messages.getString("WeaponAttackAction.Precision"))); @@ -4351,7 +4363,7 @@ else if ((atype != null) // target immobile boolean mekMortarMunitionsIgnoreImmobile = wtype != null && wtype.hasFlag(WeaponType.F_MEK_MORTAR) - && (atype != null) && (munition == AmmoType.M_AIRBURST); + && (atype != null) && (munition.contains(AmmoType.Munitions.M_AIRBURST)); if (wtype != null && !(wtype instanceof ArtilleryCannonWeapon) && !mekMortarMunitionsIgnoreImmobile) { ToHitData immobileMod; // grounded dropships are treated as immobile as well for purpose of @@ -4496,7 +4508,7 @@ else if ((atype != null) */ private static ToHitData compileTerrainAndLosToHitMods(Game game, Entity ae, Targetable target, int ttype, int aElev, int tElev, int targEl, int distance, LosEffects los, ToHitData toHit, ToHitData losMods, int toSubtract, int eistatus, - WeaponType wtype, Mounted weapon, int weaponId, AmmoType atype, long munition, boolean isAttackerInfantry, + WeaponType wtype, Mounted weapon, int weaponId, AmmoType atype, EnumSet munition, boolean isAttackerInfantry, boolean inSameBuilding, boolean isIndirect, boolean isPointBlankShot, boolean underWater) { if (ae == null || target == null) { // Can't handle these attacks without a valid attacker and target @@ -4540,7 +4552,7 @@ private static ToHitData compileTerrainAndLosToHitMods(Game game, Entity ae, Tar // BMM p. 31, semi-guided indirect missile attacks vs tagged targets ignore terrain modifiers boolean semiGuidedIndirectVsTaggedTarget = isIndirect && - (atype != null) && atype.getMunitionType() == AmmoType.M_SEMIGUIDED && + (atype != null) && atype.getMunitionType().contains(AmmoType.Munitions.M_SEMIGUIDED) && Compute.isTargetTagged(target, game); // TW p.111 @@ -4771,6 +4783,7 @@ private static ToHitData handleSpecialWeaponAttacks(Game game, Entity ae, Target return toHit; } } + //If we get here, no special weapons apply. Return the input data and continue on return toHit; } @@ -4915,7 +4928,7 @@ private static ToHitData handleSwarmSecondaryAttacks(Game game, Entity ae, Targe ToHitData toHit, int toSubtract, int eistatus, int aimingAt, AimingMode aimingMode, Mounted weapon, - AmmoType atype, long munition, + AmmoType atype, EnumSet munition, boolean isECMAffected, boolean inSameBuilding, boolean underWater) { if (ae == null || swarmPrimaryTarget == null || swarmSecondaryTarget == null) { @@ -5001,7 +5014,7 @@ private static ToHitData handleSwarmSecondaryAttacks(Game game, Entity ae, Targe toHit.append(proneMod); if (!isECMAffected && (atype != null) && !oldEnt.isEnemyOf(ae) && !(oldEnt.getBadCriticals(CriticalSlot.TYPE_SYSTEM, Mech.SYSTEM_SENSORS, Mech.LOC_HEAD) > 0) - && (munition == AmmoType.M_SWARM_I)) { + && (munition.contains(AmmoType.Munitions.M_SWARM_I))) { toHit.addModifier(+2, Messages.getString("WeaponAttackAction.SwarmIFriendly")); } } @@ -5009,7 +5022,7 @@ private static ToHitData handleSwarmSecondaryAttacks(Game game, Entity ae, Targe } /** - * Convenience method that compiles the ToHit modifiers applicable to artillery attacks + * Convenience method that compiles the ToHit modifiers applicable to direct artillery attacks * * @param game The current {@link Game} * @param ae The Entity making this attack @@ -5021,13 +5034,179 @@ private static ToHitData handleSwarmSecondaryAttacks(Game game, Entity ae, Targe * @param weapon The Mounted weapon being used * @param atype The AmmoType being used for this attack * - * @param isArtilleryDirect flag that indicates whether this is a direct-fire artillery attack * @param isArtilleryFLAK flag that indicates whether this is a flak artillery attack - * @param isArtilleryIndirect flag that indicates whether this is an indirect-fire artillery attack - * @param isHoming flag that indicates whether this is a homing missile/copperhead shot * @param usesAmmo flag that indicates if the WeaponType being used is ammo-fed * @param srt Class that stores whether or not this WAA should return a special resolution */ + private static ToHitData artilleryDirectToHit(Game game, Entity ae, Targetable target, int ttype, + ToHitData losMods, ToHitData toHit, WeaponType wtype, Mounted weapon, AmmoType atype, + boolean isArtilleryFLAK, boolean usesAmmo, SpecialResolutionTracker srt) { + + if (null == atype) { + return new ToHitData(TargetRoll.AUTOMATIC_FAIL, + "No ammo type!"); + } + Entity te = null; + if (ttype == Targetable.TYPE_ENTITY) { + te = (Entity) target; + } + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ADA)){ + // Air-Defense Arrow missiles use a much-simplified to-hit calculation because they: + // A) are Flak; B) are not Artillery, C) use three ranges (same low-alt hex, 1 hex, 2 hexes) + // as S/M/L + // Per TO:AR 6th printing, p153, other mods are: Flak (-2), AMM, damage, intervening trees/jungle + int distance = Compute.effectiveDistance(game, ae, target); + toHit = new ToHitData(ae.getCrew().getGunnery(), Messages.getString("WeaponAttackAction.GunSkill")); + // Flak; ADA won't hit the later artillery flak check so add this modifier directly. + toHit.addModifier(-2, Messages.getString("WeaponAttackAction.Flak")); + // AMM + toHit.append(Compute.getAttackerMovementModifier(game, ae.getId())); + // LOS + toHit.append(losMods); + // Special range calc + toHit.addModifier(Compute.getADARangeModifier(distance), Messages.getString("WeaponAttackAction.ADARangeBracket")); + // actuator & sensor damage to attacker + if (weapon != null) { + toHit.append(Compute.getDamageWeaponMods(ae, weapon)); + } + // Vs Aero, hits from below + if (Compute.isGroundToAir(ae, target) && ((ae.getAltitude() - target.getAltitude()) > 2)) { + toHit.setHitTable(ToHitData.HIT_BELOW); + } + + srt.setSpecialResolution(true); + return toHit; + } + //If an airborne unit occupies the target hex, standard artillery ammo makes a flak attack against it + //TN is a flat 3 + the altitude mod + the attacker's weapon skill - 2 for Flak + //Grounded/destroyed/landed/wrecked ASF/VTOL/WiGE should be treated as normal. + else if ((isArtilleryFLAK || (atype.countsAsFlak())) && te != null) { + if (te.isAirborne() || te.isAirborneVTOLorWIGE()) { + toHit.addModifier(3, Messages.getString("WeaponAttackAction.ArtyFlak")); + toHit.addModifier(-2, Messages.getString("WeaponAttackAction.Flak")); + if (te.getAltitude() > 3) { + if (te.getAltitude() > 9) { + toHit.addModifier(3, Messages.getString("WeaponAttackAction.AeroTeAlt10")); + } else if (te.getAltitude() > 6) { + toHit.addModifier(2, Messages.getString("WeaponAttackAction.AeroTeAlt79")); + } else if (te.getAltitude() > 3) { + toHit.addModifier(1, Messages.getString("WeaponAttackAction.AeroTeAlt46")); + } + } + srt.setSpecialResolution(true); + return toHit; + } + } + + //All other direct fire artillery attacks + toHit.addModifier(4, Messages.getString("WeaponAttackAction.DirectArty")); + toHit.append(Compute.getAttackerMovementModifier(game, ae.getId())); + toHit.append(losMods); + toHit.append(Compute.getSecondaryTargetMod(game, ae, target)); + // actuator & sensor damage to attacker + if (weapon != null) { + toHit.append(Compute.getDamageWeaponMods(ae, weapon)); + } + // heat + if (ae.getHeatFiringModifier() != 0) { + toHit.addModifier(ae.getHeatFiringModifier(), Messages.getString("WeaponAttackAction.Heat")); + } + // weapon to-hit modifier + if (wtype.getToHitModifier() != 0) { + toHit.addModifier(wtype.getToHitModifier(), Messages.getString("WeaponAttackAction.WeaponMod")); + } + // ammo to-hit modifier + if (usesAmmo && (atype.getToHitModifier() != 0)) { + toHit.addModifier(atype.getToHitModifier(), + atype.getSubMunitionName() + + Messages.getString("WeaponAttackAction.AmmoMod")); + } + srt.setSpecialResolution(true); + return toHit; + } + + /** + * Convenience method that compiles the ToHit modifiers applicable to indirect artillery attacks + * + * @param ae The Entity making this attack + * @param target The Targetable object being attacked + * @param toHit The running total ToHitData for this WeaponAttackAction + * + * @param wtype The WeaponType of the weapon being used + * @param weapon The Mounted weapon being used + * + * @param srt Class that stores whether or not this WAA should return a special resolution + */ + private static ToHitData artilleryIndirectToHit(Entity ae, Targetable target, + ToHitData toHit, WeaponType wtype, Mounted weapon, SpecialResolutionTracker srt) { + + int mod = 7; + if (ae.hasAbility(OptionsConstants.GUNNERY_OBLIQUE_ATTACKER)) { + mod--; + } + toHit.addModifier(mod, Messages.getString("WeaponAttackAction.IndirectArty")); + int adjust = 0; + if (weapon != null) { + adjust = ae.aTracker.getModifier(weapon, target.getPosition()); + } + boolean spotterIsForwardObserver = ae.aTracker.getSpotterHasForwardObs(); + if (adjust == TargetRoll.AUTOMATIC_SUCCESS) { + return new ToHitData(TargetRoll.AUTOMATIC_SUCCESS, + "Artillery firing at target that's been hit before."); + } else if (adjust != 0) { + toHit.addModifier(adjust, Messages.getString("WeaponAttackAction.AdjustedFire")); + if (spotterIsForwardObserver) { + toHit.addModifier(-2, Messages.getString("WeaponAttackAction.FooSpotter")); + } + } + // Capital missiles used for surface-to-surface artillery attacks + // See SO p110 + // Start with a flat +2 modifier + if (wtype instanceof CapitalMissileWeapon + && Compute.isGroundToGround(ae, target)) { + toHit.addModifier(2, Messages.getString("WeaponAttackAction.SubCapArtillery")); + // +3 additional modifier if fired underwater + if (ae.isUnderwater()) { + toHit.addModifier(3, Messages.getString("WeaponAttackAction.SubCapUnderwater")); + } + // +1 modifier if attacker cruised/walked + if (ae.moved == EntityMovementType.MOVE_WALK) { + toHit.addModifier(1, Messages.getString("WeaponAttackAction.Walked")); + } else if (ae.moved == EntityMovementType.MOVE_RUN) { + // +2 modifier if attacker ran + toHit.addModifier(2, Messages.getString("WeaponAttackAction.Ran")); + } + } else if (ae.isAirborne()) { + if (ae.getAltitude() > 6) { + toHit.addModifier(+2, Messages.getString("WeaponAttackAction.Altitude")); + } else if (ae.getAltitude() > 3) { + toHit.addModifier(+1, Messages.getString("WeaponAttackAction.Altitude")); + } + } + srt.setSpecialResolution(true); + return toHit; + } + + /** + * Convenience method that compiles the ToHit modifiers applicable to artillery attacks + * + * @param game The current {@link Game} + * @param ae The Entity making this attack + * @param target The Targetable object being attacked + * @param ttype The targetable object type + * @param toHit The running total ToHitData for this WeaponAttackAction + * + * @param wtype The WeaponType of the weapon being used + * @param weapon The Mounted weapon being used + * @param atype The AmmoType being used for this attack + * + * @param isArtilleryDirect flag that indicates whether this is a direct-fire artillery attack + * @param isArtilleryFLAK flag that indicates whether this is a flak artillery attack + * @param isArtilleryIndirect flag that indicates whether this is an indirect-fire artillery attack + * @param isHoming flag that indicates whether this is a homing missile/copperhead shot + * @param usesAmmo flag that indicates if the WeaponType being used is ammo-fed + * @param srt Class that stores whether or not this WAA should return a special resolution + */ private static ToHitData handleArtilleryAttacks(Game game, Entity ae, Targetable target, int ttype, ToHitData losMods, ToHitData toHit, WeaponType wtype, Mounted weapon, AmmoType atype, boolean isArtilleryDirect, boolean isArtilleryFLAK, boolean isArtilleryIndirect, boolean isHoming, @@ -5057,99 +5236,13 @@ private static ToHitData handleArtilleryAttacks(Game game, Entity ae, Targetable // Handle direct artillery attacks. if (isArtilleryDirect) { - //If an airborne unit occupies the target hex, standard artillery ammo makes a flak attack against it - //TN is a flat 3 + the altitude mod + the attacker's weapon skill - 2 for Flak - if ((isArtilleryFLAK || (atype != null && atype.countsAsFlak())) && te != null) { - toHit.addModifier(3, Messages.getString("WeaponAttackAction.ArtyFlak")); - toHit.addModifier(-2, Messages.getString("WeaponAttackAction.Flak")); - if (te.isAirborne()) { - if (te.getAltitude() > 3) { - if (te.getAltitude() > 9) { - toHit.addModifier(3, Messages.getString("WeaponAttackAction.AeroTeAlt10")); - } else if (te.getAltitude() > 6) { - toHit.addModifier(2, Messages.getString("WeaponAttackAction.AeroTeAlt79")); - } else if (te.getAltitude() > 3) { - toHit.addModifier(1, Messages.getString("WeaponAttackAction.AeroTeAlt46")); - } - } - } - srt.setSpecialResolution(true); - return toHit; - } else { - //All other direct fire artillery attacks - toHit.addModifier(4, Messages.getString("WeaponAttackAction.DirectArty")); - toHit.append(Compute.getAttackerMovementModifier(game, ae.getId())); - toHit.append(losMods); - toHit.append(Compute.getSecondaryTargetMod(game, ae, target)); - // actuator & sensor damage to attacker - if (weapon != null) { - toHit.append(Compute.getDamageWeaponMods(ae, weapon)); - } - // heat - if (ae.getHeatFiringModifier() != 0) { - toHit.addModifier(ae.getHeatFiringModifier(), Messages.getString("WeaponAttackAction.Heat")); - } - // weapon to-hit modifier - if (wtype.getToHitModifier() != 0) { - toHit.addModifier(wtype.getToHitModifier(), Messages.getString("WeaponAttackAction.WeaponMod")); - } - // ammo to-hit modifier - if (usesAmmo && (atype != null) && (atype.getToHitModifier() != 0)) { - toHit.addModifier(atype.getToHitModifier(), - atype.getSubMunitionName() - + Messages.getString("WeaponAttackAction.AmmoMod")); - } - } - srt.setSpecialResolution(true); - return toHit; + return artilleryDirectToHit(game, ae, target, ttype, losMods, toHit, wtype, + weapon, atype, isArtilleryFLAK, usesAmmo, srt + ); } //And now for indirect artillery fire if (isArtilleryIndirect) { - int mod = 7; - if (ae.hasAbility(OptionsConstants.GUNNERY_OBLIQUE_ATTACKER)) { - mod--; - } - toHit.addModifier(mod, Messages.getString("WeaponAttackAction.IndirectArty")); - int adjust = 0; - if (weapon != null) { - adjust = ae.aTracker.getModifier(weapon, target.getPosition()); - } - boolean spotterIsForwardObserver = ae.aTracker.getSpotterHasForwardObs(); - if (adjust == TargetRoll.AUTOMATIC_SUCCESS) { - return new ToHitData(TargetRoll.AUTOMATIC_SUCCESS, - "Artillery firing at target that's been hit before."); - } else if (adjust != 0) { - toHit.addModifier(adjust, Messages.getString("WeaponAttackAction.AdjustedFire")); - if (spotterIsForwardObserver) { - toHit.addModifier(-2, Messages.getString("WeaponAttackAction.FooSpotter")); - } - } - // Capital missiles used for surface to surface artillery attacks - // See SO p110 - // Start with a flat +2 modifier - if (wtype instanceof CapitalMissileWeapon - && Compute.isGroundToGround(ae, target)) { - toHit.addModifier(2, Messages.getString("WeaponAttackAction.SubCapArtillery")); - // +3 additional modifier if fired underwater - if (ae.isUnderwater()) { - toHit.addModifier(3, Messages.getString("WeaponAttackAction.SubCapUnderwater")); - } - // +1 modifier if attacker cruised/walked - if (ae.moved == EntityMovementType.MOVE_WALK) { - toHit.addModifier(1, Messages.getString("WeaponAttackAction.Walked")); - } else if (ae.moved == EntityMovementType.MOVE_RUN) { - // +2 modifier if attacker ran - toHit.addModifier(2, Messages.getString("WeaponAttackAction.Ran")); - } - } else if (ae.isAirborne()) { - if (ae.getAltitude() > 6) { - toHit.addModifier(+2, Messages.getString("WeaponAttackAction.Altitude")); - } else if (ae.getAltitude() > 3) { - toHit.addModifier(+1, Messages.getString("WeaponAttackAction.Altitude")); - } - } - srt.setSpecialResolution(true); - return toHit; + return artilleryIndirectToHit(ae, target, toHit, wtype, weapon, srt); } //If we get here, this isn't an artillery attack return toHit; diff --git a/megamek/src/megamek/common/battlevalue/BVCalculator.java b/megamek/src/megamek/common/battlevalue/BVCalculator.java index b0e60537ab0..4fae5fc1ba3 100644 --- a/megamek/src/megamek/common/battlevalue/BVCalculator.java +++ b/megamek/src/megamek/common/battlevalue/BVCalculator.java @@ -1272,9 +1272,10 @@ public void processTagBonus() { } for (Mounted mounted : otherEntity.getAmmo()) { AmmoType atype = (AmmoType) mounted.getType(); - long munitionType = atype.getMunitionType(); + EnumSet munitionType = atype.getMunitionType(); if ((mounted.getUsableShotsLeft() > 0) - && ((munitionType == M_SEMIGUIDED) || (munitionType == M_HOMING))) { + && ((munitionType.contains(AmmoType.Munitions.M_SEMIGUIDED)) + || (munitionType.contains(AmmoType.Munitions.M_HOMING)))) { adjustedBV += mounted.getType().getBV(entity) * tagCount; bvReport.addLine("- " + equipmentDescriptor(mounted), "+ " + tagCount + " x " + formatForReport(mounted.getType().getBV(entity)) diff --git a/megamek/src/megamek/common/enums/GamePhase.java b/megamek/src/megamek/common/enums/GamePhase.java index 2540698ddfb..39ac59fb282 100644 --- a/megamek/src/megamek/common/enums/GamePhase.java +++ b/megamek/src/megamek/common/enums/GamePhase.java @@ -267,7 +267,7 @@ private boolean isOffboardPlayable(final Game game) { || (ammoType.getAmmoType() == AmmoType.T_LONG_TOM) || (ammoType.getAmmoType() == AmmoType.T_SNIPER) || (ammoType.getAmmoType() == AmmoType.T_THUMPER)) - && (ammoType.getMunitionType() == AmmoType.M_HOMING)) { + && (ammoType.getMunitionType().contains(AmmoType.Munitions.M_HOMING))) { return true; } } @@ -284,7 +284,7 @@ private boolean isOffboardPlayable(final Game game) { // unit having left the field already, for example return game.getAttacksVector().stream() .map(attackHandler -> attackHandler.getWaa()) - .filter(Objects::nonNull).anyMatch(waa -> waa.getAmmoMunitionType() == AmmoType.M_HOMING); + .filter(Objects::nonNull).anyMatch(waa -> waa.getAmmoMunitionType().contains(AmmoType.Munitions.M_HOMING)); } /** diff --git a/megamek/src/megamek/common/net/connections/AbstractConnection.java b/megamek/src/megamek/common/net/connections/AbstractConnection.java index 56b2773ed11..8761093ad74 100644 --- a/megamek/src/megamek/common/net/connections/AbstractConnection.java +++ b/megamek/src/megamek/common/net/connections/AbstractConnection.java @@ -284,6 +284,9 @@ public void update() { while ((np = readNetworkPacket()) != null) { processPacket(np); } + } catch (java.io.InvalidClassException ex) { + LogManager.getLogger().error(getConnectionTypeText(), ex); + close(); } catch (SocketException | EOFException ignored) { // Do nothing, happens when the socket closes close(); diff --git a/megamek/src/megamek/common/verifier/TestAero.java b/megamek/src/megamek/common/verifier/TestAero.java index 9b088295cc7..a73dc39c625 100644 --- a/megamek/src/megamek/common/verifier/TestAero.java +++ b/megamek/src/megamek/common/verifier/TestAero.java @@ -709,21 +709,21 @@ public boolean correctCriticals(StringBuffer buff) { AmmoType linkedAT = (AmmoType) linkedType; // Check LBX's if (wt.getAmmoType() == AmmoType.T_AC_LBX && - linkedAT.getMunitionType() != AmmoType.M_CLUSTER) { + !linkedAT.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { correct = false; buff.append("Aeros must use cluster munitions!").append(m.getType().getInternalName()) .append(" is using ").append(linkedAT.getInternalName()).append("\n"); } // Allow Artemis munitions for artemis-linked launchers if (hasArtemisFCS - && linkedAT.getMunitionType() != AmmoType.M_STANDARD - && linkedAT.getMunitionType() != AmmoType.M_ARTEMIS_CAPABLE - && linkedAT.getMunitionType() != AmmoType.M_ARTEMIS_V_CAPABLE) { + && !linkedAT.getMunitionType().contains(AmmoType.Munitions.M_STANDARD) + && !linkedAT.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE) + && !linkedAT.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE)) { correct = false; buff.append("Aero using illegal special missile type!").append(m.getType().getInternalName()) .append(" is using ").append(linkedAT.getInternalName()).append("\n"); } - if (linkedAT.getMunitionType() != AmmoType.M_STANDARD + if (!linkedAT.getMunitionType().contains(AmmoType.Munitions.M_STANDARD) && !hasArtemisFCS && wt.getAmmoType() != AmmoType.T_AC_LBX && wt.getAmmoType() != AmmoType.T_SBGAUSS) { diff --git a/megamek/src/megamek/common/weapons/ACFlakHandler.java b/megamek/src/megamek/common/weapons/ACFlakHandler.java index 8f902e31cec..92b0322ce09 100644 --- a/megamek/src/megamek/common/weapons/ACFlakHandler.java +++ b/megamek/src/megamek/common/weapons/ACFlakHandler.java @@ -54,7 +54,7 @@ protected int calcnCluster() { @Override protected boolean usesClusterTable() { - return ((AmmoType) ammo.getType()).getMunitionType() == AmmoType.M_FLAK; + return ((AmmoType) ammo.getType()).getMunitionType().contains(AmmoType.Munitions.M_FLAK); } } diff --git a/megamek/src/megamek/common/weapons/ADAMissileWeaponHandler.java b/megamek/src/megamek/common/weapons/ADAMissileWeaponHandler.java new file mode 100644 index 00000000000..139c20eaab3 --- /dev/null +++ b/megamek/src/megamek/common/weapons/ADAMissileWeaponHandler.java @@ -0,0 +1,70 @@ +/* + * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +package megamek.common.weapons; + +import megamek.common.*; +import megamek.common.actions.WeaponAttackAction; +import megamek.common.options.OptionsConstants; +import megamek.server.GameManager; + +import java.util.Vector; + +/** + * @author Martin Metke + * + * This class extends MissleWeaponHandler to ensure that Air-Defense Arrow IV + * missiles, which act differently from most other missiles, are handled correctly. + * + * Specifically, ADA Missiles do a single hit of 20 damage to 1 location without + * AE damage and without rolling on the cluster table. + */ +public class ADAMissileWeaponHandler extends MissileWeaponHandler { + private static final long serialVersionUID = 6329291710822071023L; + + /** + * @param t + * @param w + * @param g + * @param m + */ + public ADAMissileWeaponHandler(ToHitData t, WeaponAttackAction w, Game g, + GameManager m) { + super(t, w, g, m); + } + + /* + * (non-Javadoc) + * + * @see megamek.common.weapons.WeaponHandler#calcDamagePerHit() + */ + @Override + protected int calcDamagePerHit() { + return 20; + } + + @Override + protected int calcHits(Vector vPhaseReport) { + return 1; + } + + @Override + protected int calcnCluster() { + return 1; + } + + @Override + protected boolean usesClusterTable(){ + return false; + } +} diff --git a/megamek/src/megamek/common/weapons/AR10Handler.java b/megamek/src/megamek/common/weapons/AR10Handler.java index 293ab58d2d6..60c6e8d1047 100644 --- a/megamek/src/megamek/common/weapons/AR10Handler.java +++ b/megamek/src/megamek/common/weapons/AR10Handler.java @@ -1,14 +1,14 @@ /** * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ package megamek.common.weapons; @@ -35,7 +35,7 @@ public class AR10Handler extends AmmoWeaponHandler { /** - * + * */ private static final long serialVersionUID = -2536312899803153911L; @@ -48,7 +48,7 @@ public class AR10Handler extends AmmoWeaponHandler { public AR10Handler(ToHitData t, WeaponAttackAction w, Game g, GameManager m) { super(t, w, g, m); } - + /* * (non-Javadoc) * @@ -59,12 +59,12 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { if (!cares(phase)) { return true; } - + int numAttacks = 1; - + Entity entityTarget = (target.getTargetType() == Targetable.TYPE_ENTITY) ? (Entity) target : null; - + if (entityTarget != null) { ae.setLastTarget(entityTarget.getId()); ae.setLastTargetDisplayName(entityTarget.getDisplayName()); @@ -84,7 +84,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { && (weapon.getLinked() != null) && (weapon.getLinked().getType() instanceof AmmoType)) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if (atype.getMunitionType() != AmmoType.M_STANDARD) { + if (!atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) { r.messageId = 3116; r.add(atype.getSubMunitionName()); } @@ -95,12 +95,12 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.add(target.getDisplayName(), true); } vPhaseReport.addElement(r); - + //Point Defense fire vs Capital Missiles - + // are we a glancing hit? Check for this here, report it later setGlancingBlowFlags(entityTarget); - + // Set Margin of Success/Failure and check for Direct Blows toHit.setMoS(roll - Math.max(2, toHit.getValue())); bDirect = game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_DIRECT_BLOW) @@ -108,10 +108,10 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { //This has to be up here so that we don't screw up glancing/direct blow reports attackValue = calcAttackValue(); - + //CalcAttackValue triggers counterfire, so now we can safely get this CapMissileAMSMod = getCapMissileAMSMod(); - + //Only do this if the missile wasn't destroyed if (CapMissileAMSMod > 0 && CapMissileArmor > 0) { toHit.addModifier(CapMissileAMSMod, "Damage from Point Defenses"); @@ -119,14 +119,14 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { CapMissileMissed = true; } } - + // Report any AMS bay action against Capital missiles that doesn't destroy them all. if (amsBayEngagedCap && CapMissileArmor > 0) { r = new Report(3358); r.add(CapMissileAMSMod); r.subject = subjectId; vPhaseReport.addElement(r); - + // Report any PD bay action against Capital missiles that doesn't destroy them all. } else if (pdBayEngagedCap && CapMissileArmor > 0) { r = new Report(3357); @@ -134,7 +134,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.subject = subjectId; vPhaseReport.addElement(r); } - + if (toHit.getValue() == TargetRoll.IMPOSSIBLE) { r = new Report (3135); r.subject = subjectId; @@ -175,7 +175,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { //Report Glancing/Direct Blow here because of Capital Missile weirdness if (!(amsBayEngagedCap || pdBayEngagedCap)) { addGlancingBlowReports(vPhaseReport); - + if (bDirect) { r = new Report(3189); r.subject = ae.getId(); @@ -265,7 +265,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { /** * Calculate the attack value based on range - * + * * @return an int representing the attack value at that range. */ @Override diff --git a/megamek/src/megamek/common/weapons/ATMHandler.java b/megamek/src/megamek/common/weapons/ATMHandler.java index c9a45f24cc1..109fae1efc0 100644 --- a/megamek/src/megamek/common/weapons/ATMHandler.java +++ b/megamek/src/megamek/common/weapons/ATMHandler.java @@ -64,10 +64,10 @@ public ATMHandler(ToHitData t, WeaponAttackAction w, Game g, GameManager m) { protected int calcDamagePerHit() { double toReturn; AmmoType atype = (AmmoType) ammo.getType(); - if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { sSalvoType = " high-explosive missile(s) "; toReturn = 3; - } else if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { sSalvoType = " extended-range missile(s) "; toReturn = 1; } else { @@ -110,7 +110,7 @@ protected int calcHits(Vector vPhaseReport) { int hits; AmmoType atype = (AmmoType) ammo.getType(); // TacOPs p.84 Cluster Hit Penalites will only effect ATM HE - if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { hits = super.calcHits(vPhaseReport); } else { hits = calcStandardAndExtendedAmmoHits(vPhaseReport); @@ -132,12 +132,12 @@ protected int calcAttackValue() { int counterAV = 0; int range = RangeType.rangeBracket(nRange, wtype.getATRanges(), true, false); AmmoType atype = (AmmoType) ammo.getType(); - if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { if (range == WeaponType.RANGE_SHORT) { av = wtype.getRoundShortAV(); av = av + (av / 2); } - } else if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { if (range == WeaponType.RANGE_SHORT) { av = wtype.getRoundShortAV(); } else if (range == WeaponType.RANGE_MED) { @@ -159,11 +159,11 @@ protected int calcAttackValue() { av = wtype.getRoundExtAV(); } } - + //Point Defenses engage the missiles still aimed at us counterAV = calcCounterAV(); av = av - counterAV; - + if (bDirect) { av = Math.min(av + (toHit.getMoS() / 3), av * 2); } @@ -211,7 +211,7 @@ protected int calcStandardAndExtendedAmmoHits(Vector vPhaseReport) { Mounted mLinker = weapon.getLinkedBy(); AmmoType atype = (AmmoType) ammo.getType(); - int nMissilesModifier = getClusterModifiers(atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE); + int nMissilesModifier = getClusterModifiers(atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)); // is any hex in the flight path of the missile ECM affected? boolean bECMAffected = false; @@ -225,7 +225,7 @@ protected int calcStandardAndExtendedAmmoHits(Vector vPhaseReport) { && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag( MiscType.F_ARTEMIS)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) { if (bECMAffected) { // ECM prevents bonus Report r = new Report(3330); @@ -270,7 +270,7 @@ protected int calcStandardAndExtendedAmmoHits(Vector vPhaseReport) { if (((atype.getAmmoType() == AmmoType.T_LRM) || (atype .getAmmoType() == AmmoType.T_SRM)) || ((atype.getAmmoType() == AmmoType.T_MML) - && (atype.getMunitionType() == AmmoType.M_NARC_CAPABLE) && ((weapon + && (atype.getMunitionType().contains(AmmoType.Munitions.M_NARC_CAPABLE)) && ((weapon .curMode() == null) || !weapon.curMode().equals( "Indirect")))) { if (bTargetECMAffected) { @@ -287,7 +287,7 @@ protected int calcStandardAndExtendedAmmoHits(Vector vPhaseReport) { // add AMS mods nMissilesModifier += getAMSHitsMod(vPhaseReport); - + if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY) && entityTarget != null && entityTarget.isLargeCraft()) { nMissilesModifier -= getAeroSanityAMSHitsMod(); diff --git a/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java b/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java index 8c2dd2d168d..c86bab494d4 100644 --- a/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/AmmoBayWeaponHandler.java @@ -1,14 +1,14 @@ /** * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ package megamek.common.weapons; @@ -51,7 +51,7 @@ public AmmoBayWeaponHandler(ToHitData t, WeaponAttackAction w, Game g, * function because I may run out of ammo while going through the loop Sine * this function is called in the WeaponHandler constructor it should be ok * to use the ammo here - * + * * @return an int representing the attack value at that range. */ @Override @@ -118,13 +118,13 @@ protected int calcAttackValue() { } /* - * check for special munitions and their effect on av + * check for special munitions and their effect on av */ protected double updateAVforAmmo(double current_av, AmmoType atype, WeaponType bayWType, int range, int wId) { - if (atype.getMunitionType() == AmmoType.M_CLUSTER) { - current_av = Math.floor(0.6 * current_av); + if (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { + current_av = Math.floor(0.6 * current_av); } return current_av; } diff --git a/megamek/src/megamek/common/weapons/AreaEffectHelper.java b/megamek/src/megamek/common/weapons/AreaEffectHelper.java index 361846c7e53..055298e43f0 100644 --- a/megamek/src/megamek/common/weapons/AreaEffectHelper.java +++ b/megamek/src/megamek/common/weapons/AreaEffectHelper.java @@ -97,7 +97,7 @@ private static void addFuelAirBlastRadiusIndex(int ammoType, int blastRadius) { // this is relatively inefficient, but probably the least inefficient of the options // to acquire a list of the ammo types for (AmmoType at : AmmoType.getMunitionsFor(ammoType)) { - if (at.getMunitionType() == AmmoType.M_FAE) { + if (at.getMunitionType().contains(AmmoType.Munitions.M_FAE)) { fuelAirBlastRadiusIndex.put(at.getInternalName(), blastRadius); } } @@ -361,7 +361,7 @@ public static void artilleryDamageEntity(Entity entity, int damage, Building bld // flak against ASF should only hit Aeros, because their elevation // is actually altitude, so shouldn't hit VTOLs - if (asfFlak && !entity.isAero()) { + if (asfFlak && !(entity.isAirborne())) { return; } @@ -393,14 +393,22 @@ public static void artilleryDamageEntity(Entity entity, int damage, Building bld // Work out hit table to use if (attackSource != null) { toHit.setSideTable(entity.sideTable(attackSource)); - if ((ammo != null) - && (ammo.getMunitionType() == AmmoType.M_CLUSTER) - && attackSource.equals(coords)) { - if (entity instanceof Mech) { - toHit.setHitTable(ToHitData.HIT_ABOVE); - } else if (entity instanceof Tank) { - toHit.setSideTable(ToHitData.SIDE_FRONT); - toHit.addModifier(2, "cluster artillery hitting a Tank"); + if (ammo != null){ + if(ammo.getMunitionType().contains(AmmoType.Munitions.M_ADA)){ + if(entity.isAero()) { + toHit.setHitTable(ToHitData.HIT_BELOW); + } + // Also update cluster value to be identical to damage; + // this should also be done for homing, I believe + cluster = damage; + } else if (ammo.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER) + && attackSource.equals(coords)) { + if (entity instanceof Mech) { + toHit.setHitTable(ToHitData.HIT_ABOVE); + } else if (entity instanceof Tank) { + toHit.setSideTable(ToHitData.SIDE_FRONT); + toHit.addModifier(2, "cluster artillery hitting a Tank"); + } } } } @@ -418,13 +426,13 @@ public static void artilleryDamageEntity(Entity entity, int damage, Building bld // Entity/ammo specific damage modifiers if (ammo != null) { - if (ammo.getMunitionType() == AmmoType.M_CLUSTER) { + if (ammo.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { if (hex.containsTerrain(Terrains.FORTIFIED) && entity.isConventionalInfantry()) { hits *= 2; } } // fuel-air bombs do an additional 2x damage to infantry - else if (ammo.getMunitionType() == AmmoType.M_FLECHETTE) { + else if (ammo.getMunitionType().contains(AmmoType.Munitions.M_FLECHETTE)) { // wheeled and hover tanks take movement critical if ((entity instanceof Tank) @@ -624,7 +632,12 @@ public static DamageFalloff calculateDamageFallOff(AmmoType ammo, int attackingB damage *= attackingBA; falloff = 2 * attackingBA; } - if (ammo.getMunitionType() == AmmoType.M_CLUSTER) { + // Air-Defense Arrow IV missiles + if (ammo.getAmmoType() == AmmoType.T_ARROW_IV + && ammo.getMunitionType().contains(AmmoType.Munitions.M_ADA)){ + falloff = damage; + } + if (ammo.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { // non-arrow-iv cluster does 5 less than standard if (ammo.getAmmoType() != AmmoType.T_ARROW_IV) { damage -= 5; @@ -635,7 +648,7 @@ public static DamageFalloff calculateDamageFallOff(AmmoType ammo, int attackingB } clusterMunitionsFlag = true; - } else if (ammo.getMunitionType() == AmmoType.M_FLECHETTE) { + } else if (ammo.getMunitionType().contains(AmmoType.Munitions.M_FLECHETTE)) { switch (ammo.getAmmoType()) { // for flechette, damage and falloff is number of d6, not absolute // damage diff --git a/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java b/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java index bcca3a4e059..7d374bf415b 100644 --- a/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java +++ b/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectFireHandler.java @@ -45,7 +45,7 @@ public ArtilleryBayWeaponIndirectFireHandler(ToHitData t, WeaponAttackAction w, public boolean cares(final GamePhase phase) { return phase.isOffboard() || phase.isTargeting(); } - + @Override protected void useAmmo() { nweaponsHit = weapon.getBayWeapons().size(); @@ -63,7 +63,7 @@ protected void useAmmo() { //if this option is on, we may have odd amounts of ammo in multiple bins. Only fire rounds that we have. if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_ARTILLERY_MUNITIONS)) { if (bayWAmmo.getUsableShotsLeft() < 1) { - nweaponsHit--; + nweaponsHit--; } else { bayWAmmo.setShotsLeft(bayWAmmo.getBaseShotsLeft() - 1); } @@ -147,10 +147,10 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { LogManager.getLogger().error("Artillery Entity is null!"); return true; } - + Mounted ammoUsed = ae.getEquipment(aaa.getAmmoId()); final AmmoType atype = (AmmoType) ammoUsed.getType(); - + // Are there any valid spotters? if ((null != spottersBefore) && !isFlak) { // fetch possible spotters now @@ -302,7 +302,7 @@ public boolean accept(Entity entity) { if (!mineClear) { vPhaseReport.addElement(r); } - artyMsg = "Artillery hit here on round " + game.getRoundCount() + artyMsg = "Artillery hit here on round " + game.getRoundCount() + ", fired by " + game.getPlayer(aaa.getPlayerId()).getName() + " (this hex is now an auto-hit)"; game.getBoard().addSpecialHexDisplay(targetPos, @@ -361,7 +361,7 @@ public boolean accept(Entity entity) { return !bMissed; } } - if (atype.getMunitionType() == AmmoType.M_FLARE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FLARE)) { int radius; if (atype.getAmmoType() == AmmoType.T_ARROW_IV) { radius = 4; @@ -384,7 +384,7 @@ public boolean accept(Entity entity) { } return false; } - if (atype.getMunitionType() == AmmoType.M_DAVY_CROCKETT_M) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DAVY_CROCKETT_M)) { // The appropriate term here is "Bwahahahahaha..." if (!bMissed) { // Keep blasting the target hex with each weapon in the bay that fired @@ -400,7 +400,7 @@ public boolean accept(Entity entity) { } return false; } - if (atype.getMunitionType() == AmmoType.M_FASCAM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FASCAM)) { if (!bMissed) { // If we hit, only one effect will stack in the target hex gameManager.deliverFASCAMMinefield(targetPos, ae.getOwner().getId(), @@ -414,7 +414,7 @@ public boolean accept(Entity entity) { } return false; } - if (atype.getMunitionType() == AmmoType.M_INFERNO_IV) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_INFERNO_IV)) { if (!bMissed) { // If we hit, only one effect will stack in the target hex gameManager.deliverArtilleryInferno(targetPos, ae, subjectId, vPhaseReport); @@ -426,7 +426,7 @@ public boolean accept(Entity entity) { } return false; } - if (atype.getMunitionType() == AmmoType.M_VIBRABOMB_IV) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_VIBRABOMB_IV)) { if (!bMissed) { // If we hit, only one effect will stack in the target hex gameManager.deliverThunderVibraMinefield(targetPos, ae.getOwner().getId(), @@ -440,7 +440,7 @@ public boolean accept(Entity entity) { } return false; } - if (atype.getMunitionType() == AmmoType.M_SMOKE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE)) { if (!bMissed) { // If we hit, only one effect will stack in the target hex gameManager.deliverArtillerySmoke(targetPos, vPhaseReport); @@ -452,7 +452,7 @@ public boolean accept(Entity entity) { } return false; } - if (atype.getMunitionType() == AmmoType.M_LASER_INHIB) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_LASER_INHIB)) { if (!bMissed) { //If we hit, only one effect will stack in the target hex gameManager.deliverLIsmoke(targetPos, vPhaseReport); @@ -535,7 +535,7 @@ public boolean accept(Entity entity) { gameManager.artilleryDamageArea(c, aaa.getCoords(), atype, subjectId, ae, isFlak, altitude, mineClear, vPhaseReport, asfFlak, -1); } - + } return false; } diff --git a/megamek/src/megamek/common/weapons/ArtilleryCannonWeaponHandler.java b/megamek/src/megamek/common/weapons/ArtilleryCannonWeaponHandler.java index 45bca1ff21f..6fa1a02415e 100644 --- a/megamek/src/megamek/common/weapons/ArtilleryCannonWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/ArtilleryCannonWeaponHandler.java @@ -151,33 +151,35 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { // According to TacOps eratta, artillery cannons can only fire standard // rounds and fuel-air cannon shells (Interstellar Ops p165). // But, they're still in as unofficial tech, because they're fun. :) - if (ammoType.getMunitionType() == AmmoType.M_FLARE) { - int radius; - if (ammoType.getAmmoType() == AmmoType.T_LONG_TOM) { - radius = 3; - } else if (ammoType.getAmmoType() == AmmoType.T_SNIPER) { - radius = 2; - } else { - radius = 1; + if(null != ammoType) { + if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_FLARE)) { + int radius; + if (ammoType.getAmmoType() == AmmoType.T_LONG_TOM) { + radius = 3; + } else if (ammoType.getAmmoType() == AmmoType.T_SNIPER) { + radius = 2; + } else { + radius = 1; + } + gameManager.deliverArtilleryFlare(targetPos, radius); + return false; + } else if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_DAVY_CROCKETT_M)) { + // The appropriate term here is "Bwahahahahaha..." + gameManager.doNuclearExplosion(targetPos, 1, vPhaseReport); + return false; + } else if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_FASCAM)) { + gameManager.deliverFASCAMMinefield(targetPos, ae.getOwner().getId(), + ammoType.getRackSize(), ae.getId()); + return false; + } else if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_SMOKE)) { + gameManager.deliverArtillerySmoke(targetPos, vPhaseReport); + return false; + } else if (ammoType.getMunitionType().contains(AmmoType.Munitions.M_FAE)) { + AreaEffectHelper.processFuelAirDamage(targetPos, + ammoType, ae, vPhaseReport, gameManager); + + return false; } - gameManager.deliverArtilleryFlare(targetPos, radius); - return false; - } else if (ammoType.getMunitionType() == AmmoType.M_DAVY_CROCKETT_M) { - // The appropriate term here is "Bwahahahahaha..." - gameManager.doNuclearExplosion(targetPos, 1, vPhaseReport); - return false; - } else if (ammoType.getMunitionType() == AmmoType.M_FASCAM) { - gameManager.deliverFASCAMMinefield(targetPos, ae.getOwner().getId(), - ammoType.getRackSize(), ae.getId()); - return false; - } else if (ammoType.getMunitionType() == AmmoType.M_SMOKE) { - gameManager.deliverArtillerySmoke(targetPos, vPhaseReport); - return false; - } else if (ammoType.getMunitionType() == AmmoType.M_FAE) { - AreaEffectHelper.processFuelAirDamage(targetPos, - ammoType, ae, vPhaseReport, gameManager); - - return false; } int altitude = 0; diff --git a/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectFireHandler.java b/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectFireHandler.java index 09f33ebaa0c..94874ec89b5 100644 --- a/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectFireHandler.java +++ b/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectFireHandler.java @@ -101,7 +101,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { aaa.decrementTurnsTilHit(); return true; } - + final Vector spottersBefore = aaa.getSpotterIds(); Coords targetPos = target.getPosition(); final int playerId = aaa.getPlayerId(); @@ -114,19 +114,19 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { LogManager.getLogger().error("Artillery Entity is null!"); return true; } - + // Trailers can share ammo, which means the entity carrying the ammo might not be // the firing entity, so we get the specific ammo used from the ammo carrier // However, we only bother with this if the ammo carrier is actually different from the attacker - Entity ammoCarrier = ae; - + Entity ammoCarrier = ae; + if (aaa.getAmmoCarrier() != ae.getId()) { ammoCarrier = aaa.getEntity(game, aaa.getAmmoCarrier()); } - + Mounted ammoUsed = ammoCarrier.getEquipment(aaa.getAmmoId()); final AmmoType atype = (ammoUsed != null) ? (AmmoType) ammoUsed.getType() : null; - + // Are there any valid spotters? if ((null != spottersBefore) && !isFlak) { // fetch possible spotters now @@ -190,7 +190,7 @@ public boolean accept(Entity entity) { // If the shot hit the target hex, then all subsequent // fire will hit the hex automatically. // This should only happen for indirect shots - if (roll >= toHit.getValue() + if (roll >= toHit.getValue() && !(this instanceof ArtilleryWeaponDirectFireHandler)) { ae.aTracker.setModifier(TargetRoll.AUTOMATIC_SUCCESS, targetPos); } @@ -198,9 +198,9 @@ public boolean accept(Entity entity) { // spotter, future shots are more likely to hit. // Note: Because artillery fire is adjusted on a per-unit basis, - // this can result in a unit firing multiple artillery weapons at + // this can result in a unit firing multiple artillery weapons at // the same hex getting this bonus more than once per turn. Since - // the Artillery Modifiers Table on TacOps p. 180 lists a -1 per + // the Artillery Modifiers Table on TacOps p. 180 lists a -1 per // shot (not salvo!) previously fired at the target hex, this would // in fact appear to be correct. // Only apply these modifiers to indirect artillery @@ -272,13 +272,13 @@ else if ((null != bestSpotter) && !(this instanceof ArtilleryWeaponDirectFireHan if (!handledAmmoAndReport) { addHeat(); } - + targetPos = handleReportsAndDirectScatter(isFlak, targetPos, vPhaseReport, aaa); - + if (targetPos == null) { return false; } - + // if attacker is an off-board artillery piece, check to see if we need to set observation flags if (aaa.getEntity(game).isOffBoard()) { handleCounterBatteryObservation(aaa, targetPos, vPhaseReport); @@ -289,15 +289,15 @@ else if ((null != bestSpotter) && !(this instanceof ArtilleryWeaponDirectFireHan LogManager.getLogger().error("Artillery weapon fired with no ammo.\n\n" + Thread.currentThread().getStackTrace()); return false; } - - if (atype.getMunitionType() == AmmoType.M_FAE) { - AreaEffectHelper.processFuelAirDamage(targetPos, + + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FAE)) { + AreaEffectHelper.processFuelAirDamage(targetPos, atype, aaa.getEntity(game), vPhaseReport, gameManager); - + return false; } - - if (atype.getMunitionType() == AmmoType.M_FLARE) { + + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FLARE)) { int radius; if (atype.getAmmoType() == AmmoType.T_ARROW_IV) { radius = 4; @@ -311,7 +311,7 @@ else if ((null != bestSpotter) && !(this instanceof ArtilleryWeaponDirectFireHan gameManager.deliverArtilleryFlare(targetPos, radius); return false; } - if (atype.getMunitionType() == AmmoType.M_DAVY_CROCKETT_M) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DAVY_CROCKETT_M)) { // The appropriate term here is "Bwahahahahaha..." if (target.isOffBoard()) { AreaEffectHelper.doNuclearExplosion((Entity) aaa.getTarget(game), targetPos, 1, vPhaseReport, gameManager); @@ -320,30 +320,30 @@ else if ((null != bestSpotter) && !(this instanceof ArtilleryWeaponDirectFireHan } return false; } - if (atype.getMunitionType() == AmmoType.M_FASCAM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FASCAM)) { // Arrow IVs deliver fixed 30-point minefields. int rackSize = (atype.getAmmoType() == AmmoType.T_ARROW_IV) ? 30 : atype.getRackSize(); gameManager.deliverFASCAMMinefield(targetPos, ae.getOwner().getId(), rackSize, ae.getId()); return false; } - if (atype.getMunitionType() == AmmoType.M_INFERNO_IV) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_INFERNO_IV)) { gameManager.deliverArtilleryInferno(targetPos, ae, subjectId, vPhaseReport); return false; } - if (atype.getMunitionType() == AmmoType.M_VIBRABOMB_IV) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_VIBRABOMB_IV)) { gameManager.deliverThunderVibraMinefield(targetPos, ae.getOwner().getId(), 30, waa.getOtherAttackInfo(), ae.getId()); return false; } - if (atype.getMunitionType() == AmmoType.M_SMOKE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE)) { gameManager.deliverArtillerySmoke(targetPos, vPhaseReport); return false; } - if (atype.getMunitionType() == AmmoType.M_LASER_INHIB) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_LASER_INHIB)) { gameManager.deliverLIsmoke(targetPos, vPhaseReport); return false; } - + int altitude = 0; if (isFlak) { altitude = target.getElevation(); @@ -363,18 +363,18 @@ else if ((null != bestSpotter) && !(this instanceof ArtilleryWeaponDirectFireHan } Targetable updatedTarget = aaa.getTarget(game); - + // the attack's target may have been destroyed or fled since the attack was generated // so we need to carry out offboard/null checks against the "current" version of the target. if ((updatedTarget != null) && updatedTarget.isOffBoard()) { DamageFalloff df = AreaEffectHelper.calculateDamageFallOff(atype, shootingBA, mineClear); int actualDamage = df.damage - (df.falloff * targetPos.distance(target.getPosition())); Coords effectiveTargetPos = aaa.getCoords(); - + if (df.clusterMunitionsFlag) { effectiveTargetPos = targetPos; } - + if (actualDamage > 0) { AreaEffectHelper.artilleryDamageEntity((Entity) updatedTarget, actualDamage, null, 0, false, asfFlak, isFlak, altitude, @@ -394,15 +394,15 @@ else if ((null != bestSpotter) && !(this instanceof ArtilleryWeaponDirectFireHan return false; } - + /** * Worker function that handles "artillery round landed here" reports, - * and direct artillery scatter. + * and direct artillery scatter. * @return Whether or not we should continue attack resolution afterwards */ private Coords handleReportsAndDirectScatter(boolean isFlak, Coords targetPos, Vector vPhaseReport, ArtilleryAttackAction aaa) { Coords originalTargetPos = targetPos; - + Report r; // special report for off-board target if (target.isOffBoard()) { @@ -410,7 +410,7 @@ private Coords handleReportsAndDirectScatter(boolean isFlak, Coords targetPos, V r.subject = subjectId; vPhaseReport.addElement(r); } - + if (!bMissed) { // off-board targets can just report direct hit and move on if (target.isOffBoard()) { @@ -419,8 +419,8 @@ private Coords handleReportsAndDirectScatter(boolean isFlak, Coords targetPos, V r.indent(); vPhaseReport.addElement(r); return targetPos; - } - + } + if (!isFlak) { r = new Report(3190); } else { @@ -430,7 +430,7 @@ private Coords handleReportsAndDirectScatter(boolean isFlak, Coords targetPos, V r.add(targetPos.getBoardNum()); vPhaseReport.addElement(r); - String artyMsg = "Artillery hit here on round " + game.getRoundCount() + String artyMsg = "Artillery hit here on round " + game.getRoundCount() + ", fired by " + game.getPlayer(aaa.getPlayerId()).getName() + " (this hex is now an auto-hit)"; game.getBoard().addSpecialHexDisplay( @@ -490,13 +490,13 @@ private Coords handleReportsAndDirectScatter(boolean isFlak, Coords targetPos, V return null; } } - + return targetPos; } - + /** * Worker function that contains logic for "has my shot been observed so that I can be targeted by counter-battery fire" - * + * */ private void handleCounterBatteryObservation(WeaponAttackAction aaa, Coords targetPos, Vector vPhaseReport) { // if the round landed on the board, and the attacker is an off-board artillery piece @@ -504,15 +504,15 @@ private void handleCounterBatteryObservation(WeaponAttackAction aaa, Coords targ // if so, mark the attacker so that it can be targeted by counter-battery fire if (game.getBoard().contains(targetPos)) { HexTarget hexTarget = new HexTarget(targetPos, Targetable.TYPE_HEX_ARTILLERY); - + for (Entity entity : game.getEntitiesVector()) { - + // if the entity is hostile and the attacker has not been designated // as observed already by the entity's team if (entity.isEnemyOf(aaa.getEntity(game)) && !aaa.getEntity(game).isOffBoardObserved(entity.getOwner().getTeam())) { boolean hasLoS = LosEffects.calculateLOS(game, entity, hexTarget).canSee(); - + if (hasLoS) { aaa.getEntity(game).addOffBoardObserver(entity.getOwner().getTeam()); Report r = new Report(9997); @@ -526,10 +526,10 @@ private void handleCounterBatteryObservation(WeaponAttackAction aaa, Coords targ } else if (target.isOffBoard()) { Entity attacker = aaa.getEntity(game); int targetTeam = ((Entity) target).getOwner().getTeam(); - + if (attacker.isOffBoard() && !attacker.isOffBoardObserved(targetTeam)) { attacker.addOffBoardObserver(targetTeam); - + Report r = new Report(9997); r.add(target.getDisplayName()); r.subject = subjectId; @@ -537,7 +537,7 @@ private void handleCounterBatteryObservation(WeaponAttackAction aaa, Coords targ } } } - + /* * (non-Javadoc) * diff --git a/megamek/src/megamek/common/weapons/CLIATMHandler.java b/megamek/src/megamek/common/weapons/CLIATMHandler.java index ce2cf02bf56..c8323d59ed9 100644 --- a/megamek/src/megamek/common/weapons/CLIATMHandler.java +++ b/megamek/src/megamek/common/weapons/CLIATMHandler.java @@ -40,16 +40,16 @@ public CLIATMHandler(ToHitData t, WeaponAttackAction w, Game g, GameManager m) { protected int calcDamagePerHit() { double toReturn; AmmoType atype = (AmmoType) ammo.getType(); - if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { sSalvoType = " high-explosive missile(s) "; toReturn = 3; - } else if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { sSalvoType = " extended-range missile(s) "; toReturn = 1; - } else if (atype.getMunitionType() == AmmoType.M_IATM_IMP) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IMP)) { sSalvoType = " IMP missile(s) "; toReturn = 1; - } else if (atype.getMunitionType() == AmmoType.M_IATM_IIW) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IIW)) { sSalvoType = " IIW missile(s) "; toReturn = 2; } else { @@ -62,7 +62,7 @@ protected int calcDamagePerHit() { wtype.getInfantryDamageClass(), ((Infantry) target).isMechanized(), toHit.getThruBldg() != null, ae.getId(), calcDmgPerHitReport); - + // some question here about "partial streak missiles" if (streakInactive()) { toReturn = applyGlancingBlowModifier(toReturn, true); @@ -84,13 +84,13 @@ protected int calcHits(Vector vPhaseReport) { int hits = calcMissileHits(vPhaseReport); // If we use IIW or IMP we are done. - if ((atype.getMunitionType() == AmmoType.M_IATM_IIW) - || (atype.getMunitionType() == AmmoType.M_IATM_IMP)) { + if ((atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IIW)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IMP))) { return hits; } // Normalize into clusters (for standard and HE) - if (atype.getMunitionType() != AmmoType.M_EXTENDED_RANGE) { + if (!atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { // change to 5 damage clusters here, after AMS has been done hits = nDamPerHit * hits; nDamPerHit = 1; @@ -157,8 +157,8 @@ protected int calcMissileHits(Vector vPhaseReport) { // Only apply if not all shots hit. IATM IMP have HE ranges and thus // suffer from spread too - if (((atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) - || (atype.getMunitionType() == AmmoType.M_IATM_IMP)) + if (((atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IMP))) && tacopscluster && !allShotsHit()) { if (nRange <= 1) { nMissilesModifier += 1; @@ -168,7 +168,7 @@ protected int calcMissileHits(Vector vPhaseReport) { nMissilesModifier -= 1; } } - + // ////// // This applies even with streaks. if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_RANGE) @@ -179,7 +179,7 @@ protected int calcMissileHits(Vector vPhaseReport) { && (nRange > ranges[RangeType.RANGE_EXTREME])) { nMissilesModifier -= 3; } - + // Don't need to check for ECM here since we can't have artemis boni. // And Streak bonus is allready handled. @@ -207,7 +207,7 @@ protected int calcMissileHits(Vector vPhaseReport) { if (bGlancing && streakInactive()) { nMissilesModifier -= 4; } - + if (bLowProfileGlancing && streakInactive()) { nMissilesModifier -= 4; } @@ -225,7 +225,7 @@ protected int calcMissileHits(Vector vPhaseReport) { // add AMS mods int amsMod = getAMSHitsMod(vPhaseReport); nMissilesModifier += amsMod; - + if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY)) { Entity entityTarget = (target.getTargetType() == Targetable.TYPE_ENTITY) ? (Entity) target : null; @@ -396,13 +396,13 @@ protected boolean handleSpecialMiss(Entity entityTarget, } return false; } - + /** * Streak effect only works for iATM when not firing indirectly, and not at all for fusillade. */ private boolean streakInactive() { return weapon.curMode().equals("Indirect") - || weapon.getType().hasFlag(WeaponType.F_PROTO_WEAPON); + || weapon.getType().hasFlag(WeaponType.F_PROTO_WEAPON); } /* @@ -413,7 +413,7 @@ private boolean streakInactive() { @Override public boolean handle(GamePhase phase, Vector vPhaseReport) { AmmoType atype = (AmmoType) ammo.getType(); - if (atype.getMunitionType() == AmmoType.M_IATM_IIW) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IIW)) { if (!cares(phase)) { return true; } @@ -531,7 +531,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { hits, weapon.getCalledShot().getCall())); } return false; - } else if (atype.getMunitionType() == AmmoType.M_IATM_IMP) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IMP)) { if (!cares(phase)) { return true; } @@ -753,7 +753,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { && (toHit.getThruBldg() == null)) { bldgAbsorbs = bldg.getAbsorbtion(target.getPosition()); } - + // Attacking infantry in buildings from same building if (targetInBuilding && (bldg != null) && (toHit.getThruBldg() != null) diff --git a/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java b/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java index 289afc0788e..2adb53a035c 100644 --- a/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java +++ b/megamek/src/megamek/common/weapons/CapitalMissileBayHandler.java @@ -1,11 +1,11 @@ /* * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org) - * + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License @@ -40,7 +40,7 @@ public CapitalMissileBayHandler(ToHitData t, WeaponAttackAction w, Game g, super(t, w, g, m); advancedPD = g.getOptions().booleanOption(OptionsConstants.ADVAERORULES_STRATOPS_ADV_POINTDEF); } - + /* * (non-Javadoc) * @@ -48,16 +48,16 @@ public CapitalMissileBayHandler(ToHitData t, WeaponAttackAction w, Game g, */ @Override public boolean handle(GamePhase phase, Vector vPhaseReport) { - + if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY)) { return handleAeroSanity(phase, vPhaseReport); } - + int numAttacks = 1; - + Entity entityTarget = (target.getTargetType() == Targetable.TYPE_ENTITY) ? (Entity) target : null; - + if (entityTarget != null) { ae.setLastTarget(entityTarget.getId()); ae.setLastTargetDisplayName(entityTarget.getDisplayName()); @@ -77,7 +77,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { && (weapon.getLinked() != null) && (weapon.getLinked().getType() instanceof AmmoType)) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if (atype.getMunitionType() != AmmoType.M_STANDARD) { + if (!atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) { r.messageId = 3116; r.add(atype.getSubMunitionName()); } @@ -88,12 +88,12 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.add(target.getDisplayName(), true); } vPhaseReport.addElement(r); - + //Point Defense fire vs Capital Missiles - + // are we a glancing hit? Check for this here, report it later setGlancingBlowFlags(entityTarget); - + // Set Margin of Success/Failure and check for Direct Blows toHit.setMoS(roll - Math.max(2, toHit.getValue())); bDirect = game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_DIRECT_BLOW) @@ -101,10 +101,10 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { //This has to be up here so that we don't screw up glancing/direct blow reports attackValue = calcAttackValue(); - + //CalcAttackValue triggers counterfire, so now we can safely get this CapMissileAMSMod = getCapMissileAMSMod(); - + //Only do this if the missile wasn't destroyed if (CapMissileAMSMod > 0 && CapMissileArmor > 0) { toHit.addModifier(CapMissileAMSMod, "Damage from Point Defenses"); @@ -112,14 +112,14 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { CapMissileMissed = true; } } - + // Report any AMS bay action against Capital missiles that doesn't destroy them all. if (amsBayEngagedCap && CapMissileArmor > 0) { r = new Report(3358); r.add(CapMissileAMSMod); r.subject = subjectId; vPhaseReport.addElement(r); - + // Report any PD bay action against Capital missiles that doesn't destroy them all. } else if (pdBayEngagedCap && CapMissileArmor > 0) { r = new Report(3357); @@ -127,7 +127,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.subject = subjectId; vPhaseReport.addElement(r); } - + if (toHit.getValue() == TargetRoll.IMPOSSIBLE) { r = new Report (3135); r.subject = subjectId; @@ -168,7 +168,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { //Report Glancing/Direct Blow here because of Capital Missile weirdness if (!(amsBayEngagedCap || pdBayEngagedCap)) { addGlancingBlowReports(vPhaseReport); - + if (bDirect) { r = new Report(3189); r.subject = ae.getId(); @@ -176,7 +176,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addElement(r); } } - + CounterAV = getCounterAV(); //use this if AMS counterfire destroys all the Capital missiles if (amsBayEngagedCap && (CapMissileArmor <= 0)) { @@ -225,7 +225,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { } nCluster = aeroResults[1]; } - + //Capital missiles shouldn't be able to target buildings, being space-only weapons // but if they aren't defined, handleEntityDamage() doesn't work. int bldgAbsorbs = 0; @@ -257,7 +257,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { Report.addNewline(vPhaseReport); return false; } - + @Override protected int calcAttackValue() { @@ -310,11 +310,11 @@ protected int calcAttackValue() { } else if (range == WeaponType.RANGE_EXT) { current_av = bayWType.getExtAV(); } - + if (atype.hasFlag(AmmoType.F_NUCLEAR)) { nukeS2S = true; } - + current_av = updateAVforAmmo(current_av, atype, bayWType, range, wId); av = av + current_av; @@ -336,11 +336,11 @@ protected int calcAttackValue() { } } } - + CapMissileArmor = armor - (int) counterAV; CapMissileAMSMod = calcCapMissileAMSMod(); - - + + if (bDirect) { av = Math.min(av + (toHit.getMoS() / 3), av * 2); } @@ -349,20 +349,20 @@ protected int calcAttackValue() { return (int) Math.ceil(av); // } } - - - + + + @Override protected int calcCapMissileAMSMod() { CapMissileAMSMod = (int) Math.ceil(CounterAV / 10.0); return CapMissileAMSMod; } - + @Override protected int getCapMissileAMSMod() { return CapMissileAMSMod; } - + /** * Calculate the starting armor value of a flight of Capital Missiles * Used for Aero Sanity. This is done in calcAttackValue() otherwise @@ -444,7 +444,7 @@ protected int getCritMod(AmmoType atype) { return 11; } } - + @Override protected double updateAVforAmmo(double current_av, AmmoType atype, WeaponType bayWType, int range, int wId) { @@ -469,7 +469,7 @@ protected double updateAVforAmmo(double current_av, AmmoType atype, current_av = 1000; } return current_av; - } + } /** * Insert any additional attacks that should occur before this attack */ @@ -498,7 +498,7 @@ protected void insertAttacks(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addAll(newReports); } } - + /** * 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. @@ -507,7 +507,7 @@ protected void insertAttacks(GamePhase phase, Vector vPhaseReport) { protected boolean canEngageCapitalMissile(Mounted counter) { return counter.getBayWeapons().size() >= 2; } - + /** * Sets the appropriate AMS Bay reporting flag depending on what type of missile this is */ @@ -515,7 +515,7 @@ protected boolean canEngageCapitalMissile(Mounted counter) { protected void setAMSBayReportingFlag() { amsBayEngagedCap = true; } - + /** * Sets the appropriate PD Bay reporting flag depending on what type of missile this is */ @@ -523,7 +523,7 @@ protected void setAMSBayReportingFlag() { protected void setPDBayReportingFlag() { pdBayEngagedCap = true; } - + @Override public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { if (!cares(phase)) { @@ -555,7 +555,7 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { && (weapon.getLinked() != null) && (weapon.getLinked().getType() instanceof AmmoType)) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if (atype.getMunitionType() != AmmoType.M_STANDARD) { + if (!atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) { r.messageId = 3116; r.add(atype.getSubMunitionName()); } @@ -566,27 +566,27 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { r.add(target.getDisplayName(), true); } vPhaseReport.addElement(r); - + // are we a glancing hit? Check for this here, report it later setGlancingBlowFlags(entityTarget); - + // Set Margin of Success/Failure and check for Direct Blows toHit.setMoS(roll - Math.max(2, toHit.getValue())); bDirect = game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_DIRECT_BLOW) && ((toHit.getMoS() / 3) >= 1) && (entityTarget != null); - + // Point Defense fire vs Capital Missiles CounterAV = calcCounterAV(); - + // CalcAttackValue triggers counterfire, so now we can safely get this CapMissileAMSMod = calcCapMissileAMSMod(); - + // Set up Capital Missile armor CapMissileArmor = initializeCapMissileArmor(); - + // and now damage it CapMissileArmor = (CapMissileArmor - CounterAV); - + // Only do this if the missile wasn't destroyed if (CapMissileAMSMod > 0 && CapMissileArmor > 0) { toHit.addModifier(CapMissileAMSMod, "Damage from Point Defenses"); @@ -594,14 +594,14 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { CapMissileMissed = true; } } - + // Report any AMS bay action against Capital missiles that doesn't destroy them all. if (amsBayEngagedCap && CapMissileArmor > 0) { r = new Report(3358); r.add(CapMissileAMSMod); r.subject = subjectId; vPhaseReport.addElement(r); - + // Report any PD bay action against Capital missiles that doesn't destroy them all. } else if (pdBayEngagedCap && CapMissileArmor > 0) { r = new Report(3357); @@ -650,7 +650,7 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { // Report Glancing/Direct Blow here because of Capital Missile weirdness if (!(amsBayEngagedCap || pdBayEngagedCap)) { addGlancingBlowReports(vPhaseReport); - + if (bDirect) { r = new Report(3189); r.subject = ae.getId(); @@ -658,7 +658,7 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addElement(r); } } - + // use this if AMS counterfire destroys all the Capital missiles if (amsBayEngagedCap && (CapMissileArmor <= 0)) { r = new Report(3356); @@ -677,7 +677,7 @@ public boolean handleAeroSanity(GamePhase phase, Vector vPhaseReport) { } // Don't add heat here, because that will be handled by individual weapons (even if heat by arc) - + // Any necessary PSRs, jam checks, etc. // If this boolean is true, don't report // the miss later, as we already reported diff --git a/megamek/src/megamek/common/weapons/CapitalMissileHandler.java b/megamek/src/megamek/common/weapons/CapitalMissileHandler.java index 820abc53a5b..06ea61d633c 100644 --- a/megamek/src/megamek/common/weapons/CapitalMissileHandler.java +++ b/megamek/src/megamek/common/weapons/CapitalMissileHandler.java @@ -55,7 +55,7 @@ public CapitalMissileHandler(ToHitData t, WeaponAttackAction w, Game g, GameMana super(t, w, g, m); advancedPD = g.getOptions().booleanOption(OptionsConstants.ADVAERORULES_STRATOPS_ADV_POINTDEF); } - + /* * (non-Javadoc) * @@ -66,12 +66,12 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { if (!cares(phase)) { return true; } - + int numAttacks = 1; - + Entity entityTarget = (target.getTargetType() == Targetable.TYPE_ENTITY) ? (Entity) target : null; - + if (entityTarget != null) { ae.setLastTarget(entityTarget.getId()); ae.setLastTargetDisplayName(entityTarget.getDisplayName()); @@ -91,7 +91,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { && (weapon.getLinked() != null) && (weapon.getLinked().getType() instanceof AmmoType)) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if (atype.getMunitionType() != AmmoType.M_STANDARD) { + if (!atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) { r.messageId = 3116; r.add(atype.getSubMunitionName()); } @@ -116,7 +116,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { setGlancingBlowFlags(entityTarget); } } - + // Set Margin of Success/Failure and check for Direct Blows if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY) && getParentBayHandler() != null) { @@ -128,11 +128,11 @@ && getParentBayHandler() != null) { } bDirect = game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_DIRECT_BLOW) && ((toHit.getMoS() / 3) >= 1) && (entityTarget != null); - + // Used when using a grounded DropShip with individual weapons // or a fighter squadron loaded with ASM or Alamo bombs. nDamPerHit = calcDamagePerHit(); - + // Point Defense fire vs Capital Missiles if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY) && getParentBayHandler() != null) { @@ -144,7 +144,7 @@ && getParentBayHandler() != null) { } // CalcAttackValue triggers counterfire, so now we can safely get this CapMissileAMSMod = getCapMissileAMSMod(); - + // Only do this if the missile wasn't destroyed if (CapMissileAMSMod > 0 && CapMissileArmor > 0) { toHit.addModifier(CapMissileAMSMod, "Damage from Point Defenses"); @@ -152,14 +152,14 @@ && getParentBayHandler() != null) { CapMissileMissed = true; } } - + // Report any AMS bay action against Capital missiles that doesn't destroy them all. if (amsBayEngagedCap && CapMissileArmor > 0) { r = new Report(3358); r.add(CapMissileAMSMod); r.subject = subjectId; vPhaseReport.addElement(r); - + // Report any PD bay action against Capital missiles that doesn't destroy them all. } else if (pdBayEngagedCap && CapMissileArmor > 0) { r = new Report(3357); @@ -167,7 +167,7 @@ && getParentBayHandler() != null) { r.subject = subjectId; vPhaseReport.addElement(r); } - + if (toHit.getValue() == TargetRoll.IMPOSSIBLE) { r = new Report (3135); r.subject = subjectId; @@ -208,7 +208,7 @@ && getParentBayHandler() != null) { //Report Glancing/Direct Blow here because of Capital Missile weirdness if (!(amsBayEngagedCap || pdBayEngagedCap)) { addGlancingBlowReports(vPhaseReport); - + if (bDirect) { r = new Report(3189); r.subject = ae.getId(); @@ -216,7 +216,7 @@ && getParentBayHandler() != null) { vPhaseReport.addElement(r); } } - + CounterAV = getCounterAV(); //use this if AMS counterfire destroys all the Capital missiles if (amsBayEngagedCap && (CapMissileArmor <= 0)) { @@ -265,7 +265,7 @@ && getParentBayHandler() != null) { } nCluster = aeroResults[1]; } - + //Capital missiles shouldn't be able to target buildings, being space-only weapons // but if they aren't defined, handleEntityDamage() doesn't work. int bldgAbsorbs = 0; @@ -326,7 +326,7 @@ && getParentBayHandler() != null) { Report.addNewline(vPhaseReport); return false; } - + /** * Calculate the attack value based on range * @@ -384,17 +384,17 @@ protected int calcAttackValue() { } CapMissileArmor = armor - (int) counterAV; CapMissileAMSMod = calcCapMissileAMSMod(); - + if (bDirect) { av = Math.min(av + (toHit.getMoS() / 3), av * 2); } av = applyGlancingBlowModifier(av, false); av = (int) Math.floor(getBracketingMultiplier() * av); - + return av; } - + /** * Calculate the damage per hit. * @@ -404,7 +404,7 @@ protected int calcAttackValue() { protected int calcDamagePerHit() { AmmoType atype = (AmmoType) ammo.getType(); double toReturn = wtype.getDamage(nRange); - + //AR10 munitions if (atype != null) { if (atype.getAmmoType() == AmmoType.T_AR10) { @@ -425,10 +425,10 @@ protected int calcDamagePerHit() { toReturn = 100; } else if (atype.hasFlag(AmmoType.F_PEACEMAKER)) { toReturn = 1000; - } + } nukeS2S = atype.hasFlag(AmmoType.F_NUCLEAR); } - + // we default to direct fire weapons for anti-infantry damage if (bDirect) { toReturn = Math.min(toReturn + (toHit.getMoS() / 3), toReturn * 2); @@ -438,18 +438,18 @@ protected int calcDamagePerHit() { return (int) toReturn; } - + @Override protected int calcCapMissileAMSMod() { CapMissileAMSMod = (int) Math.ceil(CounterAV / 10.0); return CapMissileAMSMod; } - + @Override protected int getCapMissileAMSMod() { return CapMissileAMSMod; } - + @Override protected int getCapMisMod() { AmmoType atype = (AmmoType) ammo.getType(); @@ -489,7 +489,7 @@ protected int getCritMod(AmmoType atype) { return 11; } } - + /** * 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. @@ -502,7 +502,7 @@ protected boolean canEngageCapitalMissile(Mounted counter) { return true; } } - + /** * Sets the appropriate AMS Bay reporting flag depending on what type of missile this is */ @@ -510,7 +510,7 @@ protected boolean canEngageCapitalMissile(Mounted counter) { protected void setAMSBayReportingFlag() { amsBayEngagedCap = true; } - + /** * Sets the appropriate PD Bay reporting flag depending on what type of missile this is */ diff --git a/megamek/src/megamek/common/weapons/LBXHandler.java b/megamek/src/megamek/common/weapons/LBXHandler.java index 9becc862f6b..c30855335c9 100644 --- a/megamek/src/megamek/common/weapons/LBXHandler.java +++ b/megamek/src/megamek/common/weapons/LBXHandler.java @@ -48,7 +48,7 @@ public LBXHandler(ToHitData t, WeaponAttackAction w, Game g, GameManager m) { /* * (non-Javadoc) - * + * * @see megamek.common.weapons.WeaponHandler#calcDamagePerHit() */ @Override @@ -82,7 +82,7 @@ protected int calcAttackValue() { /* * (non-Javadoc) - * + * * @see megamek.common.weapons.WeaponHandler#calcHits(Vector * vPhaseReport) */ @@ -140,7 +140,7 @@ protected int calcHits(Vector vPhaseReport) { @Override protected boolean usesClusterTable() { - return ((AmmoType) ammo.getType()).getMunitionType() == AmmoType.M_CLUSTER; + return ((AmmoType) ammo.getType()).getMunitionType().contains(AmmoType.Munitions.M_CLUSTER); } } diff --git a/megamek/src/megamek/common/weapons/LRMHandler.java b/megamek/src/megamek/common/weapons/LRMHandler.java index c43ffa0d720..6ed50b69c3e 100644 --- a/megamek/src/megamek/common/weapons/LRMHandler.java +++ b/megamek/src/megamek/common/weapons/LRMHandler.java @@ -149,7 +149,7 @@ protected int calcHits(Vector vPhaseReport) { && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag( MiscType.F_ARTEMIS)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE) + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE)) && !weapon.curMode().equals("Indirect")) { if (bECMAffected) { // ECM prevents bonus @@ -166,13 +166,13 @@ protected int calcHits(Vector vPhaseReport) { } else { nMissilesModifier += 2; } - + } else if (((mLinker != null) && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag( MiscType.F_ARTEMIS_PROTO)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) { if (bECMAffected) { // ECM prevents bonus Report r = new Report(3330); @@ -188,14 +188,14 @@ protected int calcHits(Vector vPhaseReport) { } else { nMissilesModifier += 1; } - - + + } else if (((mLinker != null) && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag( MiscType.F_ARTEMIS_V)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))) { if (bECMAffected) { // ECM prevents bonus Report r = new Report(3330); @@ -243,7 +243,7 @@ protected int calcHits(Vector vPhaseReport) { || (atype.getAmmoType() == AmmoType.T_SRM_IMP) || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_NLRM)) - && (atype.getMunitionType() == AmmoType.M_NARC_CAPABLE) + && (atype.getMunitionType().contains(AmmoType.Munitions.M_NARC_CAPABLE)) && ((weapon.curMode() == null) || !weapon.curMode().equals( "Indirect"))) { if (bTargetECMAffected) { @@ -260,7 +260,7 @@ protected int calcHits(Vector vPhaseReport) { // add AMS mods nMissilesModifier += getAMSHitsMod(vPhaseReport); - + if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY) && entityTarget != null && entityTarget.isLargeCraft()) { nMissilesModifier -= getAeroSanityAMSHitsMod(); @@ -268,7 +268,7 @@ protected int calcHits(Vector vPhaseReport) { int rackSize = wtype.getRackSize(); boolean minRangeELRMAttack = false; - + // ELRMs only hit with half their rack size rounded up at minimum range. // Ignore this for space combat. 1 hex is 18km across. if (wtype instanceof ExtendedLRMWeapon @@ -277,7 +277,7 @@ protected int calcHits(Vector vPhaseReport) { rackSize = rackSize / 2 + rackSize % 2; minRangeELRMAttack = true; } - + if (allShotsHit()) { // We want buildings and large craft to be able to affect this number with AMS // treat as a Streak launcher (cluster roll 11) to make this happen diff --git a/megamek/src/megamek/common/weapons/LRMScatterableHandler.java b/megamek/src/megamek/common/weapons/LRMScatterableHandler.java index b0306c98628..1d36634aa63 100644 --- a/megamek/src/megamek/common/weapons/LRMScatterableHandler.java +++ b/megamek/src/megamek/common/weapons/LRMScatterableHandler.java @@ -1,18 +1,19 @@ /** * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ package megamek.common.weapons; +import java.util.EnumSet; import java.util.Vector; import megamek.common.AmmoType; @@ -31,7 +32,7 @@ public class LRMScatterableHandler extends MissileWeaponHandler { /** - * + * */ private static final long serialVersionUID = -3661776853552779877L; @@ -48,7 +49,7 @@ public LRMScatterableHandler(ToHitData t, WeaponAttackAction w, Game g, /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.WeaponHandler#specialResolution(java.util.Vector, * megamek.common.Entity, boolean) @@ -58,19 +59,19 @@ protected boolean specialResolution(Vector vPhaseReport, Entity entityTarget) { Coords coords = target.getPosition(); AmmoType atype = (AmmoType) ammo.getType(); - long amType = atype.getMunitionType(); - boolean mineDelivery = amType == AmmoType.M_THUNDER - || amType == AmmoType.M_THUNDER_ACTIVE - || amType == AmmoType.M_THUNDER_AUGMENTED - || amType == AmmoType.M_THUNDER_INFERNO - || amType == AmmoType.M_THUNDER_VIBRABOMB; + EnumSet amType = atype.getMunitionType(); + boolean mineDelivery = amType.contains(AmmoType.Munitions.M_THUNDER) + || amType.contains(AmmoType.Munitions.M_THUNDER_ACTIVE) + || amType.contains(AmmoType.Munitions.M_THUNDER_AUGMENTED) + || amType.contains(AmmoType.Munitions.M_THUNDER_INFERNO) + || amType.contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB); int whoReport = Report.PUBLIC; // only report to player if mine delivery if (mineDelivery) { whoReport = Report.HIDDEN; } int density = atype.getRackSize(); - if (amType == AmmoType.M_THUNDER_AUGMENTED) { + if (amType.contains(AmmoType.Munitions.M_THUNDER_AUGMENTED)) { density = density / 2 + density % 2; } if (!bMissed) { @@ -114,19 +115,19 @@ protected boolean specialResolution(Vector vPhaseReport, } // Handle the thunder munitions. - if (atype.getMunitionType() == AmmoType.M_THUNDER_AUGMENTED) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_AUGMENTED)) { gameManager.deliverThunderAugMinefield(coords, ae.getOwner().getId(), density, ae.getId()); - } else if (atype.getMunitionType() == AmmoType.M_THUNDER) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER)) { gameManager.deliverThunderMinefield(coords, ae.getOwner().getId(), density, ae.getId()); - } else if (atype.getMunitionType() == AmmoType.M_THUNDER_INFERNO) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_INFERNO)) { gameManager.deliverThunderInfernoMinefield(coords, ae.getOwner().getId(), density, ae.getId()); - } else if (atype.getMunitionType() == AmmoType.M_THUNDER_VIBRABOMB) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) { gameManager.deliverThunderVibraMinefield(coords, ae.getOwner().getId(), density, waa.getOtherAttackInfo(), ae.getId()); - } else if (atype.getMunitionType() == AmmoType.M_THUNDER_ACTIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_ACTIVE)) { gameManager.deliverThunderActiveMinefield(coords, ae.getOwner().getId(), density, ae.getId()); } diff --git a/megamek/src/megamek/common/weapons/LRMSmokeWarheadHandler.java b/megamek/src/megamek/common/weapons/LRMSmokeWarheadHandler.java index 95db13e9605..ee4d120c7ef 100644 --- a/megamek/src/megamek/common/weapons/LRMSmokeWarheadHandler.java +++ b/megamek/src/megamek/common/weapons/LRMSmokeWarheadHandler.java @@ -44,7 +44,7 @@ public LRMSmokeWarheadHandler(ToHitData t, WeaponAttackAction w, Game g, GameMan /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.WeaponHandler#specialResolution(java.util.Vector, * megamek.common.Entity, boolean) @@ -81,15 +81,15 @@ protected boolean specialResolution(Vector vPhaseReport, Entity entityTa } // Handle munitions. - if (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)) { int damage = wtype.getRackSize() * calcDamagePerHit(); int smokeType = SmokeCloud.SMOKE_LIGHT; if (damage > 5) { smokeType = SmokeCloud.SMOKE_HEAVY; } - + gameManager.deliverMissileSmoke(center, smokeType, vPhaseReport); - } else if (atype.getMunitionType() == AmmoType.M_ANTI_TSM) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_ANTI_TSM)) { gameManager.deliverMissileSmoke(center, SmokeCloud.SMOKE_GREEN, vPhaseReport); return false; } diff --git a/megamek/src/megamek/common/weapons/MekMortarAirburstHandler.java b/megamek/src/megamek/common/weapons/MekMortarAirburstHandler.java index 6e4fdaaa3f7..25fb2525496 100644 --- a/megamek/src/megamek/common/weapons/MekMortarAirburstHandler.java +++ b/megamek/src/megamek/common/weapons/MekMortarAirburstHandler.java @@ -41,7 +41,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { Mounted ammoUsed = ae.getEquipment(waa.getAmmoId()); final AmmoType ammoType = (ammoUsed == null) ? null : (AmmoType) ammoUsed.getType(); - if ((ammoType == null) || (ammoType.getMunitionType() != AmmoType.M_AIRBURST)) { + if ((ammoType == null) || (!ammoType.getMunitionType().contains(AmmoType.Munitions.M_AIRBURST))) { LogManager.getLogger().error("Not using airburst ammo!"); return true; } @@ -97,22 +97,22 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { bMissed = roll < toHit.getValue(); // Set Margin of Success/Failure. toHit.setMoS(roll - Math.max(2, toHit.getValue())); - + if (bMissed) { // misses - r = new Report(3196); + r = new Report(3196); r.subject = subjectId; r.add(targetPos.getBoardNum()); - vPhaseReport.addElement(r); + vPhaseReport.addElement(r); return false; } - + // Report hit r = new Report(3190); r.subject = subjectId; r.add(targetPos.getBoardNum()); vPhaseReport.addElement(r); - + // Report amount of damage r = new Report(9940); r.subject = subjectId; @@ -121,7 +121,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.add(wtype.getName() + " " + ammoType.getSubMunitionName()); r.add(wtype.getRackSize()); vPhaseReport.addElement(r); - + Vector newReports; int numRounds = wtype.getRackSize(); // Damage building directly @@ -131,7 +131,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { adjustReports(newReports); vPhaseReport.addAll(newReports); } - + // Damage Terrain if applicable Hex h = game.getBoard().getHex(targetPos); newReports = new Vector<>(); @@ -143,18 +143,18 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.add(numRounds); newReports.add(r); } - + // Update hex and report any changes newReports.addAll(gameManager.tryClearHex(targetPos, numRounds, subjectId)); adjustReports(newReports); vPhaseReport.addAll(newReports); - + for (Entity target : game.getEntitiesVector(targetPos)) { // Ignore airborne units if (target.isAirborne() || target.isAirborneVTOLorWIGE()) { continue; } - + // Units in a building apply damage to building if (Compute.isInBuilding(game, target, targetPos)) { Player tOwner = target.getOwner(); @@ -219,14 +219,14 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { } } } - + return false; } - + /** * Indents all reports in the collection, and adds a new line to the last * one. This is used to make nested reports line-up and look nicer. - * + * * @param reports */ private void adjustReports(Vector reports) { diff --git a/megamek/src/megamek/common/weapons/MekMortarFlareHandler.java b/megamek/src/megamek/common/weapons/MekMortarFlareHandler.java index a8e0e37b0d2..08fedfc2107 100644 --- a/megamek/src/megamek/common/weapons/MekMortarFlareHandler.java +++ b/megamek/src/megamek/common/weapons/MekMortarFlareHandler.java @@ -46,7 +46,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { Mounted ammoUsed = ae.getEquipment(waa.getAmmoId()); final AmmoType ammoType = (ammoUsed == null) ? null : (AmmoType) ammoUsed.getType(); - if ((ammoType == null) || ammoType.getMunitionType() != AmmoType.M_FLARE) { + if ((ammoType == null) || !ammoType.getMunitionType().contains(AmmoType.Munitions.M_FLARE)) { LogManager.getLogger().error("Trying to use a Mek Mortar Flare with non-flare ammo"); return true; } @@ -103,7 +103,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { // Set Margin of Success/Failure. toHit.setMoS(roll - Math.max(2, toHit.getValue())); int duration = wtype.getRackSize() * 2; - + if (!bMissed) { r = new Report(3190); r.subject = subjectId; @@ -114,7 +114,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { targetPos = Compute.scatter(targetPos, 1); if (game.getBoard().contains(targetPos)) { // misses and scatters to another hex - r = new Report(3195); + r = new Report(3195); r.subject = subjectId; r.add(targetPos.getBoardNum()); vPhaseReport.addElement(r); diff --git a/megamek/src/megamek/common/weapons/MekMortarSmokeHandler.java b/megamek/src/megamek/common/weapons/MekMortarSmokeHandler.java index bfb284ff033..a5bd24bfaeb 100644 --- a/megamek/src/megamek/common/weapons/MekMortarSmokeHandler.java +++ b/megamek/src/megamek/common/weapons/MekMortarSmokeHandler.java @@ -46,8 +46,8 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { Mounted ammoUsed = ae.getEquipment(waa.getAmmoId()); final AmmoType ammoType = (ammoUsed == null) ? null : (AmmoType) ammoUsed.getType(); - - if ((ammoType == null) || (ammoType.getMunitionType() != AmmoType.M_SMOKE_WARHEAD)) { + + if ((ammoType == null) || (!ammoType.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD))) { LogManager.getLogger().error("Not using smoke ammo!"); return true; } @@ -104,7 +104,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { // Set Margin of Success/Failure. toHit.setMoS(roll - Math.max(2, toHit.getValue())); int duration = wtype.getRackSize() * 2; - + if (!bMissed) { r = new Report(3190); r.subject = subjectId; @@ -115,7 +115,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { targetPos = Compute.scatter(targetPos, 1); if (game.getBoard().contains(targetPos)) { // misses and scatters to another hex - r = new Report(3195); + r = new Report(3195); r.subject = subjectId; r.add(targetPos.getBoardNum()); vPhaseReport.addElement(r); diff --git a/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java b/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java index 7e299a59415..ca43f38c942 100644 --- a/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/MissileBayWeaponHandler.java @@ -1,14 +1,14 @@ /** * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ package megamek.common.weapons; @@ -40,7 +40,7 @@ public class MissileBayWeaponHandler extends AmmoBayWeaponHandler { private static final long serialVersionUID = -1618484541772117621L; - + protected MissileBayWeaponHandler() { // deserialization only } @@ -62,7 +62,7 @@ public MissileBayWeaponHandler(ToHitData t, WeaponAttackAction w, Game g, * function because I may run out of ammo while going through the loop Sine * this function is called in the WeaponHandler constructor it should be ok * to use the ammo here - * + * * @return an int representing the attack value at that range. */ @Override @@ -126,7 +126,7 @@ protected int calcAttackValue() { } //Bracketing fire reduces the number of missiles that hit av = (int) Math.floor(getBracketingMultiplier() * av); - + //Point Defenses engage the missiles still aimed at us counterAV = calcCounterAV(); if (isTbolt()) { @@ -135,7 +135,7 @@ protected int calcAttackValue() { } else { av = av - counterAV; } - + //Apply direct/glancing blow modifiers to the survivors if (bDirect) { av = Math.min(av + (toHit.getMoS() / 3), av * 2); @@ -144,9 +144,9 @@ protected int calcAttackValue() { av = applyGlancingBlowModifier(av, false); return (int) Math.ceil(av); - + } - + /** * Sets the appropriate AMS Bay reporting flag depending on what type of missile this is */ @@ -158,7 +158,7 @@ protected void setAMSBayReportingFlag() { amsBayEngaged = true; } } - + /** * Sets the appropriate PD Bay reporting flag depending on what type of missile this is */ @@ -170,13 +170,13 @@ protected void setPDBayReportingFlag() { pdBayEngaged = true; } } - + //Check for Thunderbolt. We'll use this for single AMS resolution @Override protected boolean isTbolt() { return wtype.hasFlag(WeaponType.F_LARGEMISSILE); } - + /** * Calculate the starting armor value of a flight of thunderbolts * Used for Aero Sanity. This is done in calcAttackValue() otherwise @@ -194,7 +194,7 @@ protected int initializeCapMissileArmor() { } return armor; } - + @Override protected int calcCapMissileAMSMod() { CapMissileAMSMod = 0; @@ -205,8 +205,8 @@ protected int calcCapMissileAMSMod() { } /* - * check for special munitions and their effect on av - * + * check for special munitions and their effect on av + * */ @Override protected double updateAVforAmmo(double current_av, AmmoType atype, @@ -218,7 +218,7 @@ protected double updateAVforAmmo(double current_av, AmmoType atype, && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag( MiscType.F_ARTEMIS)) - && atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE) { + && atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE)) { bonus = (int) Math.ceil(atype.getRackSize() / 5.0); if ((atype.getAmmoType() == AmmoType.T_SRM) || (atype.getAmmoType() == AmmoType.T_SRM_IMP)) { bonus = 2; @@ -230,7 +230,7 @@ protected double updateAVforAmmo(double current_av, AmmoType atype, && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag( MiscType.F_ARTEMIS_V)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))) { // MML3 WOULD get a bonus from Artemis V, if you were crazy enough // to cross-tech it bonus = (int) Math.ceil(atype.getRackSize() / 5.0); @@ -239,12 +239,12 @@ protected double updateAVforAmmo(double current_av, AmmoType atype, } } - if (atype.getMunitionType() == AmmoType.M_CLUSTER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { current_av = Math.floor(0.6 * current_av); } else if (AmmoType.T_ATM == atype.getAmmoType()) { - if (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) { current_av = bayWType.getShortAV() / 2; - } else if (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)) { current_av = 1.5 * current_av; if (range > WeaponType.RANGE_SHORT) { current_av = 0.0; @@ -256,14 +256,14 @@ protected double updateAVforAmmo(double current_av, AmmoType atype, if (range > WeaponType.RANGE_SHORT) { current_av = 0; } - } + } return current_av; - - } - + + } + @Override public boolean handle(GamePhase phase, Vector vPhaseReport) { - + if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY)) { return handleAeroSanity(phase, vPhaseReport); } @@ -271,13 +271,13 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { Entity entityTarget = (target.getTargetType() == Targetable.TYPE_ENTITY) ? (Entity) target : null; - if ((((null == entityTarget) || entityTarget.isAirborne()) - && (target.getTargetType() != Targetable.TYPE_HEX_CLEAR + if ((((null == entityTarget) || entityTarget.isAirborne()) + && (target.getTargetType() != Targetable.TYPE_HEX_CLEAR && target.getTargetType() != Targetable.TYPE_HEX_IGNITE - && target.getTargetType() != Targetable.TYPE_BUILDING)) + && target.getTargetType() != Targetable.TYPE_BUILDING)) || game.getBoard().inSpace()) { return super.handle(phase, vPhaseReport); - } + } // then we have a ground target, so we need to handle it in a special // way @@ -348,7 +348,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { // do we hit? bMissed = roll < toHit.getValue(); - + // are we a glancing hit? setGlancingBlowFlags(entityTarget); addGlancingBlowReports(vPhaseReport); @@ -367,8 +367,8 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { // Do this stuff first, because some weapon's miss report reference the // amount of shots fired and stuff. nDamPerHit = calcAttackValue(); - addHeat(); - + addHeat(); + // Report any AMS bay action against standard missiles. // This only gets used in atmosphere/ground battles // Non AMS point defenses only work in space @@ -455,7 +455,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { av = bayWType.getExtAV(); } } - + nDamPerHit = (int) (Math.ceil(av) - CounterAV); if (nDamPerHit <= 0) { continue; @@ -469,7 +469,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { && (toHit.getThruBldg() == null)) { bldgAbsorbs = bldg.getAbsorbtion(target.getPosition()); } - + // Attacking infantry in buildings from same building if (targetInBuilding && (bldg != null) && (toHit.getThruBldg() != null) @@ -500,7 +500,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { nCluster, bldgAbsorbs); gameManager.creditKill(entityTarget, ae); } // Handle the next weapon in the bay - Report.addNewline(vPhaseReport); + Report.addNewline(vPhaseReport); return false; } } diff --git a/megamek/src/megamek/common/weapons/MissileMineClearanceHandler.java b/megamek/src/megamek/common/weapons/MissileMineClearanceHandler.java index 26b026700c7..cebc5dd8454 100644 --- a/megamek/src/megamek/common/weapons/MissileMineClearanceHandler.java +++ b/megamek/src/megamek/common/weapons/MissileMineClearanceHandler.java @@ -44,7 +44,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { Mounted ammoUsed = ae.getEquipment(waa.getAmmoId()); final AmmoType ammoType = (ammoUsed == null) ? null : (AmmoType) ammoUsed.getType(); - if ((ammoType == null) || (ammoType.getMunitionType() != AmmoType.M_MINE_CLEARANCE)) { + if ((ammoType == null) || (!ammoType.getMunitionType().contains(AmmoType.Munitions.M_MINE_CLEARANCE))) { LogManager.getLogger().error("Not using mine clearance ammo!"); return true; } @@ -100,13 +100,13 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { bMissed = roll < toHit.getValue(); // Set Margin of Success/Failure. toHit.setMoS(roll - Math.max(2, toHit.getValue())); - + if (bMissed) { // misses - r = new Report(3196); + r = new Report(3196); r.subject = subjectId; r.add(targetPos.getBoardNum()); - vPhaseReport.addElement(r); + vPhaseReport.addElement(r); return false; } @@ -159,7 +159,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addElement(r); Vector newReports; - + // Damage building directly Building bldg = game.getBoard().getBuildingAt(targetPos); if (bldg != null) { @@ -190,7 +190,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { if (target.isAirborne() || target.isAirborneVTOLorWIGE()) { continue; } - + // Units in a building apply damage to building // The rules don't state this, but I'm going to treat mine clearance // munitions like airburst mortars for purposes of units in @@ -231,14 +231,14 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { } } } - + return false; } - + /** * Indents all reports in the collection, and adds a new line to the last * one. This is used to make nested reports line-up and look nicer. - * + * * @param reports */ private void adjustReports(Vector reports) { diff --git a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java index 5f6d4b83b8d..1fcc79bad04 100644 --- a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java @@ -81,7 +81,7 @@ protected int calcHits(Vector vPhaseReport) { } Mounted mLinker = weapon.getLinkedBy(); AmmoType atype = (AmmoType) ammo.getType(); - + // is any hex in the flight path of the missile ECM affected? boolean bECMAffected = false; // if the attacker is affected by ECM or the target is protected by ECM @@ -94,7 +94,7 @@ protected int calcHits(Vector vPhaseReport) { && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag( MiscType.F_ARTEMIS)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) { if (bECMAffected) { // ECM prevents bonus Report r = new Report(3330); @@ -114,7 +114,7 @@ protected int calcHits(Vector vPhaseReport) { && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag(MiscType.F_ARTEMIS_PROTO)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) { if (bECMAffected) { // ECM prevents bonus Report r = new Report(3330); @@ -134,7 +134,7 @@ protected int calcHits(Vector vPhaseReport) { && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag(MiscType.F_ARTEMIS_V)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))) { if (bECMAffected) { // ECM prevents bonus Report r = new Report(3330); @@ -187,7 +187,7 @@ protected int calcHits(Vector vPhaseReport) { || (atype.getAmmoType() == AmmoType.T_SRM_IMP) || (atype.getAmmoType() == AmmoType.T_MML) || (atype.getAmmoType() == AmmoType.T_NLRM)) - && (atype.getMunitionType() == AmmoType.M_NARC_CAPABLE) + && (atype.getMunitionType().contains(AmmoType.Munitions.M_NARC_CAPABLE)) && ((weapon.curMode() == null) || !weapon.curMode().equals("Indirect"))) { if (bTargetECMAffected) { // ECM prevents bonus @@ -203,7 +203,7 @@ protected int calcHits(Vector vPhaseReport) { // add AMS mods nMissilesModifier += getAMSHitsMod(vPhaseReport); - + if (game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY) && entityTarget != null && entityTarget.isLargeCraft()) { nMissilesModifier -= getAeroSanityAMSHitsMod(); @@ -299,7 +299,7 @@ protected int calcAttackValue() { if (((mLinker != null) && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag(MiscType.F_ARTEMIS)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) { // MML3 gets no bonus from Artemis IV (how sad) if (atype.getRackSize() > 3) { bonus = (int) Math.ceil(atype.getRackSize() / 5.0); @@ -312,7 +312,7 @@ protected int calcAttackValue() { if (((mLinker != null) && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag(MiscType.F_ARTEMIS_PROTO)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) { // MML3 gets no bonus from Artemis IV (how sad) if (atype.getRackSize() > 3) { bonus = (int) Math.ceil(atype.getRackSize() / 5.0); @@ -325,7 +325,7 @@ protected int calcAttackValue() { if (((mLinker != null) && (mLinker.getType() instanceof MiscType) && !mLinker.isDestroyed() && !mLinker.isMissing() && !mLinker.isBreached() && mLinker.getType().hasFlag(MiscType.F_ARTEMIS_V)) - && (atype.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))) { // MML3 WOULD get a bonus from Artemis V, if you were crazy enough // to cross-tech it bonus = (int) Math.ceil(atype.getRackSize() / 5.0); @@ -339,20 +339,20 @@ protected int calcAttackValue() { } // Set the Capital Fighter AV here. We'll apply counterAV to this later originalAV = av; - + // Point Defenses engage the missiles still aimed at us if (ae.usesWeaponBays() || ae.isCapitalFighter()) { av = av - calcCounterAV(); } - + if (bDirect) { av = Math.min(av + (toHit.getMoS() / 3), av * 2); } - + av = applyGlancingBlowModifier(av, false); return (int) Math.floor(getBracketingMultiplier() * av); } - + /** * Sets the appropriate AMS Bay reporting flag depending on what type of missile this is */ @@ -360,7 +360,7 @@ protected int calcAttackValue() { protected void setAMSBayReportingFlag() { amsBayEngaged = true; } - + /** * Sets the appropriate PD Bay reporting flag depending on what type of missile this is */ @@ -412,7 +412,7 @@ protected boolean handleSpecialMiss(Entity entityTarget, boolean bldgDamagedOnMi return true; } - + // Aero sanity reduces effectiveness of AMS bays with default cluster mods. // This attempts to account for that, but might need some balancing... protected double getAeroSanityAMSHitsMod() { @@ -456,14 +456,14 @@ protected int getAMSHitsMod(Vector vPhaseReport) { boolean isAMS = counter.getType().hasFlag(WeaponType.F_AMS); boolean isAMSBay = counter.getType().hasFlag(WeaponType.F_AMSBAY); boolean isAPDS = counter.isAPDS(); - + // Only one AMS and one APDS can engage each missile attack if (isAMS && amsEngaged) { continue; } else if (isAPDS && apdsEngaged) { continue; } - + // Check the firing arc, even though this was done when the AMS was assigned Entity pdEnt = counter.getEntity(); boolean isInArc; @@ -476,7 +476,7 @@ protected int getAMSHitsMod(Vector vPhaseReport) { isInArc = Compute.isInArc(game, pdEnt.getId(), pdEnt.getEquipmentNum(counter), entityTarget); } - + if (!isInArc) { continue; } @@ -490,7 +490,7 @@ protected int getAMSHitsMod(Vector vPhaseReport) { || pdEnt.isShutDown()) { continue; } - + // If we're an AMSBay, heat and ammo must be calculated differently if (isAMSBay) { for (int wId : counter.getBayWeapons()) { @@ -516,11 +516,11 @@ protected int getAMSHitsMod(Vector vPhaseReport) { if (bayWAmmo != null) { bayWAmmo.setShotsLeft(Math.max(0, bayWAmmo.getBaseShotsLeft() - 1)); } - + //Optional rule to allow multiple AMS shots per round if (!multiAMS) { // set the ams as having fired, which is checked by isReady() - bayW.setUsedThisRound(true); + bayW.setUsedThisRound(true); } amsEngaged = true; } @@ -531,19 +531,19 @@ protected int getAMSHitsMod(Vector vPhaseReport) { } else { pdEnt.heatBuildup += counter.getCurrentHeat(); } - + // decrement the ammo Mounted mAmmo = counter.getLinked(); if (mAmmo != null) { mAmmo.setShotsLeft(Math.max(0, mAmmo.getBaseShotsLeft() - 1)); } - + // Optional rule to allow multiple AMS shots per round if (!multiAMS) { // set the ams as having fired counter.setUsedThisRound(true); } - + if (isAMS) { amsEngaged = true; } @@ -582,7 +582,7 @@ protected int getAMSHitsMod(Vector vPhaseReport) { vPhaseReport.add(r); amsMod = -4; } - + // Report APDS fire. Effect relies on internal variables and must be separated above if (apdsEngaged) { Report r = new Report(3351); @@ -625,7 +625,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { if (entityTarget != null) { if (wtype.getAmmoType() != AmmoType.T_NA) { AmmoType atype = (AmmoType) ammo.getType(); - if (atype.getMunitionType() != AmmoType.M_STANDARD) { + if (!atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) { r.messageId = 3116; r.add(atype.getSubMunitionName()); } @@ -679,13 +679,13 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addElement(r); } } - + attackValue = calcAttackValue(); CounterAV = getCounterAV(); - + // CalcAttackValue triggers counterfire, so now we can safely get this CapMissileAMSMod = getCapMissileAMSMod(); - + // Only do this if a flight of large missiles wasn't destroyed if ((CapMissileAMSMod > 0) && (CapMissileArmor > 0)) { toHit.addModifier(CapMissileAMSMod, "Damage from Point Defenses"); @@ -707,7 +707,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.subject = subjectId; vPhaseReport.addElement(r); } - + if (toHit.getValue() == TargetRoll.IMPOSSIBLE) { r = new Report(3135); r.subject = subjectId; @@ -765,18 +765,18 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { if (!shotAtNemesisTarget) { addHeat(); } - + // Any necessary PSRs, jam checks, etc. // If this boolean is true, don't report // the miss later, as we already reported // it in doChecks boolean missReported = doChecks(vPhaseReport); - + //This is for firing ATM/LRM/MML/MRM/SRMs at a DropShip, but is ignored for ground-to-air fire //It's also rare but possible for two hostile grounded DropShips to shoot at each other with individual weapons //with this handler. They'll use the cluster table too. //Don't use this if Aero Sanity is on... - if (entityTarget != null + if (entityTarget != null && entityTarget.hasETypeFlag(Entity.ETYPE_DROPSHIP) && !game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_AERO_SANITY) && (waa.isAirToAir(game) || (waa.isAirToGround(game) && !ae.usesWeaponBays()))) { @@ -784,8 +784,8 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { } else { //This is for all other targets in atmosphere nDamPerHit = calcDamagePerHit(); - } - + } + // Do we need some sort of special resolution (minefields, artillery, if (specialResolution(vPhaseReport, entityTarget)) { return false; @@ -811,7 +811,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { hits = aeroResults[0]; nCluster = aeroResults[1]; // Report AMS/Pointdefense failure due to Overheating. - if (pdOverheated + if (pdOverheated && (!(amsBayEngaged || amsBayEngagedCap || amsBayEngagedMissile @@ -827,7 +827,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r = new Report (3361); r.subject = subjectId; r.indent(); - vPhaseReport.addElement(r); + vPhaseReport.addElement(r); } if (!bMissed && amsEngaged && isTbolt() && !ae.isCapitalFighter()) { @@ -865,9 +865,9 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.add(CounterAV); r.subject = subjectId; vPhaseReport.addElement(r); - + // Report any Point Defense bay action against standard missiles. - + } else if (pdBayEngaged && (originalAV <= 0)) { // use this if PD counterfire destroys all the missiles r = new Report(3355); @@ -880,7 +880,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.subject = subjectId; vPhaseReport.addElement(r); } - } + } } else { // If none of the above apply hits = calcHits(vPhaseReport); @@ -901,7 +901,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { && (toHit.getThruBldg() == null)) { bldgAbsorbs = bldg.getAbsorbtion(target.getPosition()); } - + // Attacking infantry in buildings from same building if (targetInBuilding && (bldg != null) && (toHit.getThruBldg() != null) @@ -1006,24 +1006,24 @@ protected boolean isNemesisConfusable() { MiscType.F_ARTEMIS_V) || mLinker.getType().hasFlag( MiscType.F_ARTEMIS_PROTO)))) { if ((!weapon.getType().hasModes() || !weapon.curMode().equals("Indirect")) - && (((atype.getAmmoType() == AmmoType.T_ATM) && - ((atype.getMunitionType() == AmmoType.M_STANDARD) - || (atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) - || (atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE))) + && (((atype.getAmmoType() == AmmoType.T_ATM) && + ((atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_EXTENDED_RANGE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_HIGH_EXPLOSIVE)))) || ((((atype.getAmmoType() == AmmoType.T_LRM) - || (atype.getAmmoType() == AmmoType.T_LRM_IMP) + || (atype.getAmmoType() == AmmoType.T_LRM_IMP) || (atype.getAmmoType() == AmmoType.T_SRM) - || (atype.getAmmoType() == AmmoType.T_SRM_IMP)) && - (atype.getMunitionType() == AmmoType.M_ARTEMIS_CAPABLE)) - || (atype.getMunitionType() == AmmoType.M_ARTEMIS_V_CAPABLE)))) { + || (atype.getAmmoType() == AmmoType.T_SRM_IMP)) && + (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_CAPABLE))) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_ARTEMIS_V_CAPABLE))))) { isNemesisConfusable = true; } } else if ((wtype.getAmmoType() == AmmoType.T_LRM) || (wtype.getAmmoType() == AmmoType.T_LRM_IMP) || (wtype.getAmmoType() == AmmoType.T_SRM) || (wtype.getAmmoType() == AmmoType.T_SRM_IMP)) { - if ((atype.getMunitionType() == AmmoType.M_NARC_CAPABLE) - || (atype.getMunitionType() == AmmoType.M_LISTEN_KILL)) { + if ((atype.getMunitionType().contains(AmmoType.Munitions.M_NARC_CAPABLE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_LISTEN_KILL))) { isNemesisConfusable = true; } } diff --git a/megamek/src/megamek/common/weapons/NarcHandler.java b/megamek/src/megamek/common/weapons/NarcHandler.java index 1d3c40a90b0..a92facc1ffb 100644 --- a/megamek/src/megamek/common/weapons/NarcHandler.java +++ b/megamek/src/megamek/common/weapons/NarcHandler.java @@ -50,7 +50,7 @@ public NarcHandler(ToHitData t, WeaponAttackAction w, Game g, GameManager m) { /* * (non-Javadoc) - * + * * @see megamek.common.weapons.WeaponHandler#calcHits(java.util.Vector) */ @Override @@ -72,7 +72,7 @@ protected int calcHits(Vector vPhaseReport) { calcCounterAV(); } // Report AMS/Pointdefense failure due to Overheating. - if (pdOverheated + if (pdOverheated && (!(amsBayEngaged || amsBayEngagedCap || amsBayEngagedMissile @@ -83,7 +83,7 @@ protected int calcHits(Vector vPhaseReport) { r.subject = subjectId; r.indent(); vPhaseReport.addElement(r); - } + } if (amsEngaged || apdsEngaged || amsBayEngagedMissile || pdBayEngagedMissile) { Report r = new Report(3235); r.subject = subjectId; @@ -109,7 +109,7 @@ protected int calcHits(Vector vPhaseReport) { } return 1; } - + /** * Sets the appropriate AMS Bay reporting flag depending on what type of missile this is */ @@ -117,7 +117,7 @@ protected int calcHits(Vector vPhaseReport) { protected void setAMSBayReportingFlag() { amsBayEngagedMissile = true; } - + /** * Sets the appropriate PD Bay reporting flag depending on what type of missile this is */ @@ -128,14 +128,14 @@ protected void setPDBayReportingFlag() { /* * (non-Javadoc) - * + * * @see megamek.common.weapons.WeaponHandler#calcnCluster() */ @Override protected int calcnCluster() { return 1; } - + @Override /** * Narcs apply "damage" all in one block for AMS purposes @@ -147,7 +147,7 @@ protected boolean usesClusterTable() { /* * (non-Javadoc) - * + * * @see megamek.common.weapons.WeaponHandler#calcDamagePerHit() */ @Override @@ -157,7 +157,7 @@ protected int calcDamagePerHit() { /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.WeaponHandler#handleEntityDamage(megamek.common * .Entity, java.util.Vector, megamek.common.Building, int, int, int, int) @@ -181,7 +181,7 @@ protected void handleEntityDamage(Entity entityTarget, } } hit.setAttackerId(getAttackerId()); - + // Catch Protomech near-misses here. // So what do we do for a near miss on a glider? Assume attach to wings. if (entityTarget instanceof Protomech @@ -192,7 +192,7 @@ protected void handleEntityDamage(Entity entityTarget, vPhaseReport.add(r); return; } - + if (entityTarget.removePartialCoverHits(hit.getLocation(), toHit .getCover(), Compute.targetSideTable(ae, entityTarget, weapon .getCalledShot().getCall()))) { @@ -210,7 +210,7 @@ protected void handleEntityDamage(Entity entityTarget, hit = entityTarget.getTransferLocation(hit); } } - + // Now the same check for ProtoMechs. We've already covered near-misses // above, so here we only have to worry about the actual hits left over. if (entityTarget instanceof Protomech) { @@ -219,7 +219,7 @@ protected void handleEntityDamage(Entity entityTarget, hit = entityTarget.getTransferLocation(hit); } } - + AmmoType atype = (AmmoType) ammo.getType(); if (atype.getAmmoType() == AmmoType.T_NARC) { // narced @@ -234,7 +234,7 @@ protected void handleEntityDamage(Entity entityTarget, } else if (atype.getAmmoType() == AmmoType.T_INARC) { // iNarced INarcPod pod = null; - if (atype.getMunitionType() == AmmoType.M_ECM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ECM)) { pod = new INarcPod(ae.getOwner().getTeam(), INarcPod.ECM, hit.getLocation()); Report r = new Report(3251); @@ -242,7 +242,7 @@ protected void handleEntityDamage(Entity entityTarget, r.add(entityTarget.getDisplayName()); r.add(entityTarget.getLocationAbbr(hit)); vPhaseReport.addElement(r); - } else if (atype.getMunitionType() == AmmoType.M_HAYWIRE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_HAYWIRE)) { pod = new INarcPod(ae.getOwner().getTeam(), INarcPod.HAYWIRE, hit.getLocation()); Report r = new Report(3252); @@ -250,7 +250,7 @@ protected void handleEntityDamage(Entity entityTarget, r.add(entityTarget.getDisplayName()); r.add(entityTarget.getLocationAbbr(hit)); vPhaseReport.addElement(r); - } else if (atype.getMunitionType() == AmmoType.M_NEMESIS) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_NEMESIS)) { pod = new INarcPod(ae.getOwner().getTeam(), INarcPod.NEMESIS, hit.getLocation()); Report r = new Report(3253); @@ -270,7 +270,7 @@ protected void handleEntityDamage(Entity entityTarget, entityTarget.attachINarcPod(pod); } } - + private boolean narcCanAttachTo(Entity entity, int location) { return (entity.getInternal(location) > 0) && !entity.isLocationBlownOff(location) diff --git a/megamek/src/megamek/common/weapons/SRMSmokeWarheadHandler.java b/megamek/src/megamek/common/weapons/SRMSmokeWarheadHandler.java index d7dc1aa6911..f3919e77c97 100644 --- a/megamek/src/megamek/common/weapons/SRMSmokeWarheadHandler.java +++ b/megamek/src/megamek/common/weapons/SRMSmokeWarheadHandler.java @@ -38,7 +38,7 @@ public SRMSmokeWarheadHandler(ToHitData t, WeaponAttackAction w, Game g, GameMan /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.WeaponHandler#specialResolution(java.util.Vector, * megamek.common.Entity, boolean) @@ -75,7 +75,7 @@ protected boolean specialResolution(Vector vPhaseReport, Entity entityTa } // Handle munitions. - if (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)) { int damage = wtype.getRackSize() * calcDamagePerHit(); int smokeType = SmokeCloud.SMOKE_LIGHT; if (damage > 5) { @@ -83,7 +83,7 @@ protected boolean specialResolution(Vector vPhaseReport, Entity entityTa } gameManager.deliverMissileSmoke(center, smokeType, vPhaseReport); - } else if (atype.getMunitionType() == AmmoType.M_ANTI_TSM) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_ANTI_TSM)) { gameManager.deliverMissileSmoke(center, SmokeCloud.SMOKE_GREEN, vPhaseReport); } return true; diff --git a/megamek/src/megamek/common/weapons/VGLWeaponHandler.java b/megamek/src/megamek/common/weapons/VGLWeaponHandler.java index 19d93b0e345..7debd131550 100644 --- a/megamek/src/megamek/common/weapons/VGLWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/VGLWeaponHandler.java @@ -38,7 +38,7 @@ /** * Weapon handler for vehicular grenade launchers. Rather than have a separate * handler for each ammo type, all ammo types are handled here. - * + * * @author arlith */ public class VGLWeaponHandler extends AmmoWeaponHandler { @@ -58,7 +58,7 @@ public VGLWeaponHandler(ToHitData t, WeaponAttackAction w, Game g, super(t, w, g, m); generalDamageType = HitData.DAMAGE_NONE; } - + /** * handle this weapons firing * @@ -71,8 +71,8 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { return true; } // VGLs automatically hit the three adjacent hex in their side - - + + // Determine what coords get hit AmmoType atype = (AmmoType) ammo.getType(); int facing = weapon.getFacing(); @@ -84,7 +84,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { affectedCoords.add(ae.getPosition().translated(af + facing)); affectedCoords.add(ae.getPosition().translated((af + facing + 1) % 6)); affectedCoords.add(ae.getPosition().translated((af + facing + 5) % 6)); - + Report r = new Report(3117); r.indent(); r.subject = subjectId; @@ -94,15 +94,15 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.add(affectedCoords.get(1).getBoardNum()); r.add(affectedCoords.get(2).getBoardNum()); vPhaseReport.add(r); - - + + for (Coords c : affectedCoords) { Building bldg = game.getBoard().getBuildingAt(c); - if (atype.getMunitionType() == AmmoType.M_SMOKE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE)) { gameManager.deliverSmokeGrenade(c, vPhaseReport); - } else if (atype.getMunitionType() == AmmoType.M_CHAFF) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_CHAFF)) { gameManager.deliverChaffGrenade(c, vPhaseReport); - } else if (atype.getMunitionType() == AmmoType.M_INCENDIARY) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY)) { Vector dmgReports; // Delivery an inferno to the hex Targetable grenadeTarget = new HexTarget(c, Targetable.TYPE_HEX_IGNITE); @@ -137,7 +137,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { for (Entity entTarget : game.getEntitiesVector(c)) { // Infantry in a building take damage when the building is // targeted, so should be ignored here - if (bldg != null && (entTarget instanceof Infantry) + if (bldg != null && (entTarget instanceof Infantry) && Compute.isInBuilding(game, entTarget)) { continue; } @@ -156,14 +156,14 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { } else { // Assume fragmentation grenade // Damage each Entity in the target coord for (Entity entTarget : game.getEntitiesVector(c)) { - boolean inBuilding = (bldg != null) + boolean inBuilding = (bldg != null) && Compute.isInBuilding(game, entTarget, c); - + hit = entTarget.rollHitLocation(toHit.getHitTable(), toHit.getSideTable(), waa.getAimedLocation(), waa.getAimingMode(), toHit.getCover()); hit.setAttackerId(getAttackerId()); - + Vector dmgReports = new Vector<>(); // Infantry take 2D6 burst damage if (!inBuilding && entTarget.isConventionalInfantry()) { @@ -190,8 +190,8 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addAll(dmgReports); } } - } - + } + return false; } diff --git a/megamek/src/megamek/common/weapons/WeaponHandler.java b/megamek/src/megamek/common/weapons/WeaponHandler.java index d8e6a3247b4..a41fe90bbe1 100644 --- a/megamek/src/megamek/common/weapons/WeaponHandler.java +++ b/megamek/src/megamek/common/weapons/WeaponHandler.java @@ -95,7 +95,7 @@ public class WeaponHandler implements AttackHandler, Serializable { * added once. */ protected boolean isStrafingFirstShot = false; - + // Large Craft Point Defense/AMS Bay Stuff protected int CounterAV; // the combined attack value of all point defenses used against this weapon attack protected int CapMissileArmor; // the standard scale armor points of a capital missile bay @@ -111,7 +111,7 @@ public class WeaponHandler implements AttackHandler, Serializable { protected boolean advancedPD = false; // true if advanced StratOps game rule is on protected WeaponHandler parentBayHandler = null; //Used for weapons bays when Aero Sanity is on protected int originalAV = 0; // Used to handle AMS damage to standard missile flights fired by capital fighters - + protected boolean amsEngaged = false; protected boolean apdsEngaged = false; @@ -128,7 +128,7 @@ public int getSalvoBonus() { */ protected int getLargeCraftHeat(Entity e) { int totalheat = 0; - if (e.hasETypeFlag(Entity.ETYPE_DROPSHIP) + if (e.hasETypeFlag(Entity.ETYPE_DROPSHIP) || e.hasETypeFlag(Entity.ETYPE_JUMPSHIP)) { if (e.usesWeaponBays()) { for (Enumeration i = game.getAttacks(); i.hasMoreElements();) { @@ -155,11 +155,11 @@ protected int getLargeCraftHeat(Entity e) { } return totalheat; } - + /** * Checks to see if the basic conditions needed for point defenses to work are in place * Artillery weapons need to change this slightly - * See also TeleMissileAttackAction, which contains a modified version of this to work against + * See also TeleMissileAttackAction, which contains a modified version of this to work against * a TeleMissile entity in the physical phase */ protected boolean checkPDConditions() { @@ -172,7 +172,7 @@ protected boolean checkPDConditions() { || (waa.isGroundToAir(game) && (!(wtype.isSubCapital() || wtype.isCapital())))) { return false; } - if (target instanceof Dropship + if (target instanceof Dropship && waa.isAirToGround(game) && !ae.usesWeaponBays()) { //Prevents a grounded dropship using individual weapons from engaging with AMSBays unless attacked by a dropship or capital fighter @@ -181,46 +181,46 @@ protected boolean checkPDConditions() { } return true; } - + /** * 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. - * See also TeleMissileAttackAction, which contains a modified version of this to work against + * 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) { return true; } - + /** * Sets the appropriate AMS Bay reporting flag depending on what type of missile this is - * See also TeleMissileAttackAction, which contains a modified version of this to work against + * See also TeleMissileAttackAction, which contains a modified version of this to work against * a TeleMissile entity in the physical phase */ protected void setAMSBayReportingFlag() { } - + /** * Sets the appropriate PD Bay reporting flag depending on what type of missile this is - * See also TeleMissileAttackAction, which contains a modified version of this to work against + * See also TeleMissileAttackAction, which contains a modified version of this to work against * a TeleMissile entity in the physical phase */ protected void setPDBayReportingFlag() { } - + /** * Sets whether or not this weapon is considered a single, large missile for AMS resolution */ protected boolean isTbolt() { return false; } - + /** * Calculates the attack value of point defense weapons used against a missile bay attack * This is the main large craft point defense method - * See also TeleMissileAttackAction, which contains a modified version of this to work against + * See also TeleMissileAttackAction, which contains a modified version of this to work against * a TeleMissile entity in the physical phase - */ + */ protected int calcCounterAV() { if (!checkPDConditions()) { return 0; @@ -247,7 +247,7 @@ protected int calcCounterAV() { pdEnt.getEquipmentNum(counter), entityTarget); } - + if (!isInArc) { continue; } @@ -262,18 +262,18 @@ protected int calcCounterAV() { if (!canEngageCapitalMissile(counter)) { continue; } - + // Set up differences between point defense and AMS bays boolean isAMSBay = counter.getType().hasFlag(WeaponType.F_AMSBAY); boolean isPDBay = counter.getType().hasFlag(WeaponType.F_PDBAY); - + // Point defense bays can only fire at one attack per round if (isPDBay) { if (counter.isUsedThisRound()) { continue; } } - + // Now for heat, damage and ammo we need the individual weapons in the bay // First, reset the temporary damage counters amsAV = 0; @@ -282,7 +282,7 @@ protected int calcCounterAV() { Mounted bayW = pdEnt.getEquipment(wId); Mounted bayWAmmo = bayW.getLinked(); WeaponType bayWType = ((WeaponType) bayW.getType()); - + // build up some heat // First Check to see if we have enough heat capacity to fire if ((weaponHeat + bayW.getCurrentHeat()) > pdEnt.getHeatCapacity()) { @@ -298,7 +298,7 @@ protected int calcCounterAV() { pdEnt.heatBuildup += bayW.getCurrentHeat(); weaponHeat += bayW.getCurrentHeat(); } - + // Bays use lots of ammo. Check to make sure we haven't run out if (bayWAmmo != null) { if (bayWAmmo.getBaseShotsLeft() == 0) { @@ -320,12 +320,12 @@ protected int calcCounterAV() { // get the attack value pdAV += bayWType.getShortAV(); // set the pdbay as having fired, if it was able to - counter.setUsedThisRound(true); + counter.setUsedThisRound(true); setPDBayReportingFlag(); } } // non-AMS only add half their damage, rounded up - counterAV += (int) Math.ceil(pdAV / 2.0); + counterAV += (int) Math.ceil(pdAV / 2.0); // AMS add their full damage counterAV += amsAV; } @@ -335,49 +335,49 @@ protected int calcCounterAV() { return counterAV; } - + /** * Return the attack value of point defense weapons used against a missile bay attack - */ + */ protected int getCounterAV() { return CounterAV; } - + /** * Used with Aero Sanity mod * Returns the handler for the BayWeapon this individual weapon belongs to - */ + */ protected WeaponHandler getParentBayHandler() { return parentBayHandler; } - + /** * Sets the parent handler for each sub-weapon handler called when looping through bay weapons * Used with Aero Sanity to pass counterAV through to the individual missile handler from the bay handler - * + * * @param bh - The AttackHandler for the BayWeapon this individual weapon belongs to - */ + */ protected void setParentBayHandler(WeaponHandler bh) { parentBayHandler = bh; } - + /** * Calculates the to-hit penalty inflicted on a capital missile attack by point defense fire * this should return 0 unless this is a capital missile attack (otherwise, reporting and to-hit get screwed up) - */ + */ protected int calcCapMissileAMSMod() { return 0; } - + /** * Return the to-hit penalty inflicted on a capital missile attack by point defense fire - */ + */ protected int getCapMissileAMSMod() { return CapMissileAMSMod; } - + //End of Large Craft Point Defense Methods and Variables - + /** * Used to store reports from calls to calcDamagePerHit. This * is necessary because the method is called before the report needs to be @@ -397,7 +397,7 @@ public int getAttackerId() { public Entity getAttacker() { return ae; } - + /** * Do we care about the specified phase? */ @@ -415,7 +415,7 @@ public boolean cares(GamePhase phase) { protected boolean doChecks(Vector vPhaseReport) { return false; } - + /** * Carries out a check to see if the weapon in question explodes due to the 'ammo feed problem' quirk * Not the case for weapons without ammo @@ -606,7 +606,7 @@ protected int[] calcAeroDamage(Entity entityTarget, r.add("missile"); r.add(destroyRoll); r.subject = subjectId; - vPhaseReport.add(r); + vPhaseReport.add(r); } } nweaponsHit = nweaponsHit - AMSHits; @@ -649,7 +649,7 @@ protected int[] calcAeroDamage(Entity entityTarget, r.add("missile"); r.add(destroyRoll); r.subject = subjectId; - vPhaseReport.add(r); + vPhaseReport.add(r); } nweaponsHit = nweaponsHit - AMSHits; } @@ -699,7 +699,7 @@ protected int[] calcAeroDamage(Entity entityTarget, hits = 1; nCluster = 1; } - } + } } else if (nCluster > 1) { bSalvo = true; nDamPerHit = 1; @@ -799,7 +799,7 @@ public boolean handle(GamePhase phase, Vector returnedReports) { && (weapon.getLinked() != null) && (weapon.getLinked().getType() instanceof AmmoType)) { AmmoType atype = (AmmoType) weapon.getLinked().getType(); - if (atype.getMunitionType() != AmmoType.M_STANDARD) { + if (!atype.getMunitionType().contains(AmmoType.Munitions.M_STANDARD)) { r.messageId = 3116; r.add(atype.getSubMunitionName()); } @@ -810,12 +810,12 @@ public boolean handle(GamePhase phase, Vector returnedReports) { r.add(target.getDisplayName(), true); } vPhaseReport.addElement(r); - + //Point Defense fire vs Capital Missiles - + // are we a glancing hit? Check for this here, report it later setGlancingBlowFlags(entityTarget); - + // Set Margin of Success/Failure and check for Direct Blows toHit.setMoS(roll - Math.max(2, toHit.getValue())); bDirect = game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_DIRECT_BLOW) @@ -851,7 +851,7 @@ public boolean handle(GamePhase phase, Vector returnedReports) { } // Report AMS/Pointdefense failure due to Overheating. - if (pdOverheated + if (pdOverheated && (!(amsBayEngaged || amsBayEngagedCap || amsBayEngagedMissile @@ -867,7 +867,7 @@ public boolean handle(GamePhase phase, Vector returnedReports) { r = new Report (3361); r.subject = subjectId; r.indent(); - vPhaseReport.addElement(r); + vPhaseReport.addElement(r); } if (toHit.getValue() == TargetRoll.IMPOSSIBLE) { @@ -907,14 +907,14 @@ public boolean handle(GamePhase phase, Vector returnedReports) { // do we hit? bMissed = roll < toHit.getValue(); - + //Report Glancing/Direct Blow here because of Capital Missile weirdness //TODO: Can't figure out a good way to make Capital Missile bays report direct/glancing blows //when Advanced Point Defense is on, but they work correctly. if (!(amsBayEngagedCap || pdBayEngagedCap)) { addGlancingBlowReports(vPhaseReport); - + if (bDirect) { r = new Report(3189); r.subject = ae.getId(); @@ -932,8 +932,8 @@ public boolean handle(GamePhase phase, Vector returnedReports) { heatAdded = true; } - - + + // Report any AMS bay action against standard missiles. CounterAV = getCounterAV(); //use this if counterfire destroys all the missiles @@ -956,7 +956,7 @@ public boolean handle(GamePhase phase, Vector returnedReports) { r.indent(); r.subject = subjectId; vPhaseReport.addElement(r); - } + } // Report any Point Defense bay action against standard missiles. if (pdBayEngaged && (attackValue <= 0)) { @@ -1050,7 +1050,7 @@ public boolean handle(GamePhase phase, Vector returnedReports) { && (toHit.getThruBldg() == null)) { bldgAbsorbs = bldg.getAbsorbtion(target.getPosition()); } - + // Attacking infantry in buildings from same building if (targetInBuilding && (bldg != null) && (toHit.getThruBldg() != null) @@ -1091,15 +1091,15 @@ public boolean handle(GamePhase phase, Vector returnedReports) { || (target.getTargetType() == Targetable.TYPE_BLDG_TAG)) { TagInfo info = new TagInfo(ae.getId(), target.getTargetType(), target, false); game.addTagInfo(info); - + ae.setSpotting(true); ae.setSpotTargetId(target.getId()); - + r = new Report(3390); r.subject = subjectId; vPhaseReport.addElement(r); hits = 0; - // targeting a hex for igniting + // targeting a hex for igniting } else if ((target.getTargetType() == Targetable.TYPE_HEX_IGNITE) || (target.getTargetType() == Targetable.TYPE_BLDG_IGNITE)) { handleIgnitionDamage(vPhaseReport, bldg, hits); @@ -1256,9 +1256,9 @@ protected int calcAttackValue() { if (bDirect) { av = Math.min(av + (toHit.getMoS() / 3), av * 2); } - + av = applyGlancingBlowModifier(av, false); - + av = (int) Math.floor(getBracketingMultiplier() * av); return av; @@ -1440,24 +1440,24 @@ protected void handleEntityDamage(Entity entityTarget, missed = false; initHit(entityTarget); - + boolean isIndirect = wtype.hasModes() && weapon.curMode().equals("Indirect"); - + Hex targetHex = game.getBoard().getHex(target.getPosition()); boolean mechPokingOutOfShallowWater = unitGainsPartialCoverFromWater(targetHex, entityTarget); - + // a very specific situation where a mech is standing in a height 1 building - // or its upper torso is otherwise somehow poking out of said building + // or its upper torso is otherwise somehow poking out of said building boolean targetInShortBuilding = WeaponAttackAction.targetInShortCoverBuilding(target); boolean legHit = entityTarget.locationIsLeg(hit.getLocation()); boolean shortBuildingBlocksLegHit = targetInShortBuilding && legHit; - - boolean partialCoverForIndirectFire = + + boolean partialCoverForIndirectFire = isIndirect && (mechPokingOutOfShallowWater || shortBuildingBlocksLegHit); //For indirect fire, remove leg hits only if target is in water partial cover //Per TW errata for indirect fire - if ((!isIndirect || partialCoverForIndirectFire) + if ((!isIndirect || partialCoverForIndirectFire) && entityTarget.removePartialCoverHits(hit.getLocation(), toHit .getCover(), Compute.targetSideTable(ae, entityTarget, weapon.getCalledShot().getCall()))) { @@ -1499,18 +1499,18 @@ protected void handleEntityDamage(Entity entityTarget, if (bDirect) { hit.makeDirectBlow(toHit.getMoS() / 3); } - + // Report calcDmgPerHitReports here if (!calcDmgPerHitReport.isEmpty()) { vPhaseReport.addAll(calcDmgPerHitReport); calcDmgPerHitReport.clear(); } - + // if the target was in partial cover, then we already handled // damage absorption by the partial cover, if it would have happened boolean targetStickingOutOfBuilding = unitStickingOutOfBuilding(targetHex, entityTarget); - - nDamage = absorbBuildingDamage(nDamage, entityTarget, bldgAbsorbs, + + nDamage = absorbBuildingDamage(nDamage, entityTarget, bldgAbsorbs, vPhaseReport, bldg, targetStickingOutOfBuilding); nDamage = checkTerrain(nDamage, entityTarget, vPhaseReport); @@ -1534,11 +1534,11 @@ protected void handleEntityDamage(Entity entityTarget, if (bGlancing) { hit.makeGlancingBlow(); } - + if (bLowProfileGlancing) { hit.makeGlancingBlow(); } - + vPhaseReport.addAll(gameManager.damageEntity(entityTarget, hit, nDamage, false, ae.getSwarmTargetId() == entityTarget.getId() ? DamageType.IGNORE_PASSENGER : damageType, false, false, throughFront, underWater, nukeS2S)); @@ -1562,18 +1562,18 @@ protected void handleEntityDamage(Entity entityTarget, nDamPerHit = calcDamagePerHit(); } } - + /** * Worker function - does the entity gain partial cover from shallow water? */ protected boolean unitGainsPartialCoverFromWater(Hex targetHex, Entity entityTarget) { - return (targetHex != null) && + return (targetHex != null) && targetHex.containsTerrain(Terrains.WATER) && (entityTarget.relHeight() == targetHex.getLevel()); } - + /** - * Worker function - is a part of this unit inside the hex's terrain features, + * Worker function - is a part of this unit inside the hex's terrain features, * but part sticking out? */ protected boolean unitStickingOutOfBuilding(Hex targetHex, Entity entityTarget) { @@ -1595,7 +1595,7 @@ protected int absorbBuildingDamage(int nDamage, Entity entityTarget, int bldgAbs boolean targetStickingOutOfBuilding) { // if the building will absorb some damage and the target is actually // entirely inside the building: - if ((bldgAbsorbs > 0) && !targetStickingOutOfBuilding) { + if ((bldgAbsorbs > 0) && !targetStickingOutOfBuilding) { int toBldg = Math.min(bldgAbsorbs, nDamage); nDamage -= toBldg; Report.addNewline(vPhaseReport); @@ -1623,7 +1623,7 @@ protected int absorbBuildingDamage(int nDamage, Entity entityTarget, int bldgAbs } vPhaseReport.addAll(buildingReport); } - + return nDamage; } @@ -1765,7 +1765,7 @@ public WeaponHandler(ToHitData t, WeaponAttackAction w, Game g, GameManager m) { } else { roll = Compute.d6(2); } - + nweapons = getNumberWeapons(); nweaponsHit = 1; // use ammo when creating this, so it works when shooting the last shot @@ -1846,7 +1846,7 @@ protected void addHeat() { } } } - + /** * Does this attack use the cluster hit table? necessary to determine how * Aero damage should be applied @@ -1888,9 +1888,9 @@ public int checkTerrain(int nDamage, Entity entityTarget, Vector vPhaseR } Hex hex = game.getBoard().getHex(entityTarget.getPosition()); boolean hasWoods = hex.containsTerrain(Terrains.WOODS) || hex.containsTerrain(Terrains.JUNGLE); - boolean isAboveWoods = (entityTarget.relHeight() + 1 > hex.terrainLevel(Terrains.FOLIAGE_ELEV)) + boolean isAboveWoods = (entityTarget.relHeight() + 1 > hex.terrainLevel(Terrains.FOLIAGE_ELEV)) || entityTarget.isAirborne() || !hasWoods; - + if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_WOODS_COVER) && hasWoods && !isAboveWoods && !(entityTarget.getSwarmAttackerId() == ae.getId())) { @@ -2051,7 +2051,7 @@ protected int getClusterModifiers(boolean clusterRangePenalty) { if (bGlancing) { nMissilesModifier -= 4; } - + if (bLowProfileGlancing) { nMissilesModifier -= 4; } @@ -2111,7 +2111,7 @@ public void setStrafingFirstShot(boolean isStrafingFirstShot) { protected int applyGlancingBlowModifier(int initialValue, boolean roundup) { return (int) applyGlancingBlowModifier((double) initialValue, roundup); } - + /** * Determine the "glancing blow" divider. * 2 if the shot is "glancing" or "glancing due to low profile" @@ -2123,12 +2123,12 @@ protected double applyGlancingBlowModifier(double initialValue, boolean roundup) if (!bGlancing && !bLowProfileGlancing) { return initialValue; } - - double divisor = getTotalGlancingBlowFactor(); + + double divisor = getTotalGlancingBlowFactor(); double intermediateValue = initialValue / divisor; return roundup ? Math.ceil(intermediateValue) : Math.floor(intermediateValue); } - + /** * Logic to determine the glancing blow multiplier: * 1 if no glancing blow @@ -2138,7 +2138,7 @@ protected double applyGlancingBlowModifier(double initialValue, boolean roundup) protected double getTotalGlancingBlowFactor() { return (bGlancing ? 2.0 : 1.0) * (bLowProfileGlancing ? 2.0 : 1.0); } - + /** * Worker function that sets the glancing blow flags for this attack for the target when appropriate */ @@ -2151,11 +2151,11 @@ protected void setGlancingBlowFlags(Entity entityTarget) { bGlancing = false; } } - + // low profile glancing blows are triggered on roll = toHit or toHit - 1 bLowProfileGlancing = isLowProfileGlancingBlow(entityTarget, toHit); } - + /** * Worker function that determines if the given hit on the given entity is a glancing blow * as per narrow/low profile quirk rules @@ -2165,20 +2165,20 @@ protected boolean isLowProfileGlancingBlow(Entity entityTarget, ToHitData hitDat entityTarget.hasQuirk(OptionsConstants.QUIRK_POS_LOW_PROFILE) && ((roll == hitData.getValue()) || (roll == hitData.getValue() + 1)); } - + /** * Worker function that adds the 'glancing blow' reports */ protected void addGlancingBlowReports(Vector vPhaseReport) { Report r; - + if (bGlancing) { r = new Report(3186); r.subject = ae.getId(); r.newlines = 0; vPhaseReport.addElement(r); } - + if (bLowProfileGlancing) { r = new Report(9985); r.subject = ae.getId(); diff --git a/megamek/src/megamek/common/weapons/artillery/ArrowIV.java b/megamek/src/megamek/common/weapons/artillery/ArrowIV.java new file mode 100644 index 00000000000..cf674481eda --- /dev/null +++ b/megamek/src/megamek/common/weapons/artillery/ArrowIV.java @@ -0,0 +1,86 @@ +/* + * MegaMek - Copyright (C) 2004, 2005 Ben Mazur (bmazur@sev.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +package megamek.common.weapons.artillery; + +import megamek.common.*; +import megamek.common.actions.WeaponAttackAction; +import megamek.common.weapons.ADAMissileWeaponHandler; +import megamek.common.weapons.AttackHandler; +import megamek.server.GameManager; + +/** + * @author Martin Metke + * @since Sep 12, 2023 + */ + + +public abstract class ArrowIV extends ArtilleryWeapon { + private static final long serialVersionUID = -4495524659692575107L; + + // Air-Defense Arrow IV (ADA) missile ranges differ from normal Arrow IV ammo + public final int ADA_MIN_RANGE = 0; + public final int ADA_SHORT_RANGE = 17; + public final int ADA_MED_RANGE = 34; + public final int ADA_LONG_RANGE = 51; + public final int ADA_EXT_RANGE = 51; + + public ArrowIV() { + super(); + + name = "Arrow IV"; + setInternalName("ArrowIV"); + addLookupName("ArrowIVSystem"); + addLookupName("Arrow IV System"); + addLookupName("Arrow IV Missile System"); + heat = 10; + rackSize = 20; + ammoType = AmmoType.T_ARROW_IV; + bv = 240; + cost = 450000; + this.flags = flags.or(F_MISSILE); + this.missileArmor = 20; + rulesRefs = "284, TO"; + } + + @Override + public int[] getRanges(Mounted weapon) { + // modify the ranges for Arrow missile systems based on the ammo selected + int minRange = getMinimumRange(); + int sRange = getShortRange(); + int mRange = getMediumRange(); + int lRange = getLongRange(); + int eRange = getExtremeRange(); + boolean hasLoadedAmmo = (weapon.getLinked() != null); + if (hasLoadedAmmo) { + AmmoType atype = (AmmoType) weapon.getLinked().getType(); + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ADA)) { + minRange = ADA_MIN_RANGE; + sRange = ADA_SHORT_RANGE; + mRange = ADA_MED_RANGE; + lRange = ADA_LONG_RANGE; + eRange = ADA_EXT_RANGE; + } + } + return new int[] { minRange, sRange, mRange, lRange, eRange }; + } + + @Override + protected AttackHandler getCorrectHandler(ToHitData toHit, + WeaponAttackAction waa, Game game, GameManager manager) { + if(waa.getAmmoMunitionType().contains(AmmoType.Munitions.M_ADA)){ + return new ADAMissileWeaponHandler(toHit, waa, game, manager); + } + return super.getCorrectHandler(toHit, waa, game, manager); + } +} diff --git a/megamek/src/megamek/common/weapons/artillery/CLArrowIV.java b/megamek/src/megamek/common/weapons/artillery/CLArrowIV.java index 96aef2134d8..f158394e3ce 100644 --- a/megamek/src/megamek/common/weapons/artillery/CLArrowIV.java +++ b/megamek/src/megamek/common/weapons/artillery/CLArrowIV.java @@ -13,20 +13,17 @@ */ package megamek.common.weapons.artillery; -import megamek.common.AmmoType; -import megamek.common.SimpleTechLevel; +import megamek.common.*; /** * @author Sebastian Brocks * @since Oct 20, 2004 */ -public class CLArrowIV extends ArtilleryWeapon { - private static final long serialVersionUID = -8623816593973861926L; +public class CLArrowIV extends ArrowIV { public CLArrowIV() { super(); - name = "Arrow IV"; setInternalName("CLArrowIV"); addLookupName("CLArrowIVSystem"); addLookupName("Clan Arrow IV System"); @@ -41,11 +38,6 @@ public CLArrowIV() { tonnage = 12; criticals = 12; svslots = 6; - bv = 240; - cost = 450000; - this.flags = flags.or(F_MISSILE); - this.missileArmor = 20; - rulesRefs = "284, TO"; techAdvancement.setTechBase(TECH_BASE_CLAN) .setTechRating(RATING_F) .setAvailability(RATING_X, RATING_F, RATING_E, RATING_D) diff --git a/megamek/src/megamek/common/weapons/artillery/ISArrowIV.java b/megamek/src/megamek/common/weapons/artillery/ISArrowIV.java index fd5d6ef1804..d2cfa012402 100644 --- a/megamek/src/megamek/common/weapons/artillery/ISArrowIV.java +++ b/megamek/src/megamek/common/weapons/artillery/ISArrowIV.java @@ -13,26 +13,21 @@ */ package megamek.common.weapons.artillery; -import megamek.common.AmmoType; -import megamek.common.SimpleTechLevel; +import megamek.common.*; /** * @author Sebastian Brocks * @since Oct 20, 2004 */ -public class ISArrowIV extends ArtilleryWeapon { - private static final long serialVersionUID = -4495524659692575107L; +public class ISArrowIV extends ArrowIV { public ISArrowIV() { super(); - name = "Arrow IV"; + setInternalName("ISArrowIV"); addLookupName("ISArrowIVSystem"); addLookupName("IS Arrow IV System"); addLookupName("IS Arrow IV Missile System"); - heat = 10; - rackSize = 20; - ammoType = AmmoType.T_ARROW_IV; shortRange = 1; mediumRange = 2; longRange = 8; @@ -40,11 +35,6 @@ public ISArrowIV() { tonnage = 15; criticals = 15; svslots = 7; - bv = 240; - cost = 450000; - this.flags = flags.or(F_MISSILE); - this.missileArmor = 20; - rulesRefs = "284, TO"; techAdvancement.setTechBase(TECH_BASE_IS) .setTechRating(RATING_E) .setAvailability(RATING_E, RATING_F, RATING_E, RATING_D) @@ -55,4 +45,4 @@ public ISArrowIV() { .setReintroductionFactions(F_CC) .setStaticTechLevel(SimpleTechLevel.ADVANCED); } -} +} \ No newline at end of file diff --git a/megamek/src/megamek/common/weapons/autocannons/ACWeapon.java b/megamek/src/megamek/common/weapons/autocannons/ACWeapon.java index 484b0f5b69f..8ed1f19fe16 100644 --- a/megamek/src/megamek/common/weapons/autocannons/ACWeapon.java +++ b/megamek/src/megamek/common/weapons/autocannons/ACWeapon.java @@ -57,7 +57,7 @@ public ACWeapon() { /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.Weapon#getCorrectHandler(megamek.common.ToHitData, * megamek.common.actions.WeaponAttackAction, megamek.common.Game, @@ -73,27 +73,27 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa RapidfireACWeaponHandler ah = new RapidfireACWeaponHandler(toHit, waa, game, gameManager); return ah; } - if (atype.getMunitionType() == AmmoType.M_ARMOR_PIERCING) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ARMOR_PIERCING)) { return new ACAPHandler(toHit, waa, game, gameManager); } - if (atype.getMunitionType() == AmmoType.M_FLECHETTE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FLECHETTE)) { return new ACFlechetteHandler(toHit, waa, game, gameManager); } - if (atype.getMunitionType() == AmmoType.M_INCENDIARY_AC) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_INCENDIARY_AC)) { return new ACIncendiaryHandler(toHit, waa, game, gameManager); } - if (atype.getMunitionType() == AmmoType.M_TRACER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_TRACER)) { return new ACTracerHandler(toHit, waa, game, gameManager); } - if (atype.getMunitionType() == AmmoType.M_FLAK) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FLAK)) { return new ACFlakHandler(toHit, waa, game, gameManager); } - - if (atype.getMunitionType() == AmmoType.M_CASELESS) { + + if (atype.getMunitionType().contains(AmmoType.Munitions.M_CASELESS)) { return new ACCaselessHandler (toHit, waa, game, gameManager); } diff --git a/megamek/src/megamek/common/weapons/autocannons/LBXACWeapon.java b/megamek/src/megamek/common/weapons/autocannons/LBXACWeapon.java index f62118d87d9..45a1ebdbee5 100644 --- a/megamek/src/megamek/common/weapons/autocannons/LBXACWeapon.java +++ b/megamek/src/megamek/common/weapons/autocannons/LBXACWeapon.java @@ -34,7 +34,7 @@ public abstract class LBXACWeapon extends AmmoWeapon { /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.Weapon#getCorrectHandler(megamek.common.ToHitData, * megamek.common.actions.WeaponAttackAction, megamek.common.Game, @@ -45,7 +45,7 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_CLUSTER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { return new LBXHandler(toHit, waa, game, manager); } return new ACWeaponHandler(toHit, waa, game, manager); @@ -58,7 +58,7 @@ public LBXACWeapon() { ammoType = AmmoType.T_AC_LBX; atClass = CLASS_LBX_AC; } - + @Override public double getBattleForceDamage(int range) { double damage = 0; @@ -71,7 +71,7 @@ public double getBattleForceDamage(int range) { } return damage; } - + @Override public int getBattleForceClass() { return BFCLASS_FLAK; diff --git a/megamek/src/megamek/common/weapons/flamers/VehicleFlamerWeapon.java b/megamek/src/megamek/common/weapons/flamers/VehicleFlamerWeapon.java index 6d77a207b1a..28c29ab94c8 100644 --- a/megamek/src/megamek/common/weapons/flamers/VehicleFlamerWeapon.java +++ b/megamek/src/megamek/common/weapons/flamers/VehicleFlamerWeapon.java @@ -52,8 +52,8 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - - if (atype.getMunitionType() == AmmoType.M_COOLANT) { + + if (atype.getMunitionType().contains(AmmoType.Munitions.M_COOLANT)) { return new VehicleFlamerCoolHandler(toHit, waa, game, manager); } else { return new VehicleFlamerHandler(toHit, waa, game, manager); diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java index 44ff07874ce..0d8e66c7105 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeapon.java @@ -132,7 +132,7 @@ public int getMaxRange(Mounted weapon) { public int getCrew() { return crew; } - + /** * The long range of this weapon type. Infantry weapons calculate ranges based on the "infantry range" value rather than * explicit short/long/medium ranges @@ -235,7 +235,7 @@ public InfantryWeapon getNonInfernoVariant() { public int getSupportVeeSlots(Entity entity) { return 1; } - + /* * (non-Javadoc) * @@ -250,7 +250,7 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa || (waa.getEntity(game).isSupportVehicle() && m.getLinked() != null && m.getLinked().getType() != null - && (((AmmoType) m.getLinked().getType()).getMunitionType() == AmmoType.M_INFERNO))))) { + && (((AmmoType) m.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)))))) { return new InfantryHeatWeaponHandler(toHit, waa, game, manager); } return new InfantryWeaponHandler(toHit, waa, game, manager); diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java index a51836a8cb0..440251184b2 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java @@ -69,15 +69,15 @@ protected int calcnCluster() { @Override protected int calcHits(Vector vPhaseReport) { int nHitMod = 0; - + if (bGlancing) { nHitMod -= 4; } - + if (this.bLowProfileGlancing) { nHitMod -= 4; } - + int troopersHit = 0; //when swarming all troopers hit if (ae.getSwarmTargetId() == target.getId()) { @@ -89,17 +89,17 @@ protected int calcHits(Vector vPhaseReport) { .getShootingStrength(), nHitMod); } double damage = calculateBaseDamage(ae, weapon, wtype); - + if ((ae instanceof Infantry) && nRange == 0 && ae.hasAbility(OptionsConstants.MD_TSM_IMPLANT)) { damage += 0.14; } int damageDealt = (int) Math.round(damage * troopersHit); - + // conventional infantry weapons with high damage get treated as if they have the infantry burst mod - if (target.isConventionalInfantry() && - (wtype.hasFlag(WeaponType.F_INF_BURST) || + if (target.isConventionalInfantry() && + (wtype.hasFlag(WeaponType.F_INF_BURST) || (ae.isConventionalInfantry() && ((Infantry) ae).primaryWeaponDamageCapped()))) { damageDealt += Compute.d6(); } @@ -186,7 +186,7 @@ public void useAmmo() { super.useAmmo(); } } - + /** * Utility function to calculate variable damage based only on the firing entity. */ @@ -197,7 +197,7 @@ public static double calculateBaseDamage(Entity ae, Mounted weapon, WeaponType w return ((Infantry) ae).getDamagePerTrooper(); } else if (ae.isSupportVehicle()) { // Damage for some weapons depends on what type of ammo is being used - if (((AmmoType) weapon.getLinked().getType()).getMunitionType() == AmmoType.M_INFERNO) { + if (((AmmoType) weapon.getLinked().getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) { return ((InfantryWeapon) wtype).getInfernoVariant().getInfantryDamage(); } else { return ((InfantryWeapon) wtype).getNonInfernoVariant().getInfantryDamage(); diff --git a/megamek/src/megamek/common/weapons/lrms/LRMWeapon.java b/megamek/src/megamek/common/weapons/lrms/LRMWeapon.java index 339190eacee..d1a3267244b 100644 --- a/megamek/src/megamek/common/weapons/lrms/LRMWeapon.java +++ b/megamek/src/megamek/common/weapons/lrms/LRMWeapon.java @@ -58,7 +58,7 @@ public LRMWeapon() { flags = flags.or(F_PROTO_WEAPON).or(F_ARTEMIS_COMPATIBLE); } - + @Override public double getTonnage(Entity entity, int location, double size) { if ((null != entity) && entity.hasETypeFlag(Entity.ETYPE_PROTOMECH)) { @@ -73,50 +73,50 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_FRAGMENTATION) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FRAGMENTATION)) { return new LRMFragHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_ANTI_TSM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ANTI_TSM)) { return new LRMAntiTSMHandler(toHit, waa, game, manager); } - if ((atype.getMunitionType() == AmmoType.M_THUNDER) - || (atype.getMunitionType() == AmmoType.M_THUNDER_ACTIVE) - || (atype.getMunitionType() == AmmoType.M_THUNDER_AUGMENTED) - || (atype.getMunitionType() == AmmoType.M_THUNDER_INFERNO) - || (atype.getMunitionType() == AmmoType.M_THUNDER_VIBRABOMB)) { + if ((atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_ACTIVE)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_AUGMENTED)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_INFERNO)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB))) { return new LRMScatterableHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SWARM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SWARM)) { return new LRMSwarmHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SWARM_I) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SWARM_I)) { return new LRMSwarmIHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { return new LRMDeadFireHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_FOLLOW_THE_LEADER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FOLLOW_THE_LEADER)) { return new LRMFollowTheLeaderHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)) { return new LRMSmokeWarheadHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_MINE_CLEARANCE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_MINE_CLEARANCE)) { return new MissileMineClearanceHandler(toHit, waa, game, manager); } return new LRMHandler(toHit, waa, game, manager); } - + @Override public int getBattleForceClass() { return BFCLASS_LRM; } - + @Override public boolean hasIndirectFire() { return true; } - + @Override public void adaptToGameOptions(GameOptions gOp) { super.adaptToGameOptions(gOp); diff --git a/megamek/src/megamek/common/weapons/missiles/MMLWeapon.java b/megamek/src/megamek/common/weapons/missiles/MMLWeapon.java index efac8c412e7..4b4387566e8 100644 --- a/megamek/src/megamek/common/weapons/missiles/MMLWeapon.java +++ b/megamek/src/megamek/common/weapons/missiles/MMLWeapon.java @@ -1,6 +1,6 @@ /* * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org) - * + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) @@ -54,7 +54,7 @@ public MMLWeapon() { /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.Weapon#getCorrectHandler(megamek.common.ToHitData, * megamek.common.actions.WeaponAttackAction, megamek.common.Game, @@ -66,57 +66,57 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); if (atype.hasFlag(AmmoType.F_MML_LRM)) { - if (atype.getMunitionType() == AmmoType.M_FRAGMENTATION) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FRAGMENTATION)) { return new LRMFragHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_ANTI_TSM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ANTI_TSM)) { return new LRMAntiTSMHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_THUNDER - || atype.getMunitionType() == AmmoType.M_THUNDER_ACTIVE - || atype.getMunitionType() == AmmoType.M_THUNDER_AUGMENTED - || atype.getMunitionType() == AmmoType.M_THUNDER_INFERNO - || atype.getMunitionType() == AmmoType.M_THUNDER_VIBRABOMB) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER) + || atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_ACTIVE) + || atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_AUGMENTED) + || atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_INFERNO) + || atype.getMunitionType().contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) { return new LRMScatterableHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SWARM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SWARM)) { return new LRMSwarmHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SWARM_I) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SWARM_I)) { return new LRMSwarmIHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { return new LRMDeadFireHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_FOLLOW_THE_LEADER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FOLLOW_THE_LEADER)) { return new LRMFollowTheLeaderHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)) { return new LRMSmokeWarheadHandler(toHit, waa, game, manager); } return new LRMHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_FRAGMENTATION) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FRAGMENTATION)) { return new SRMFragHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_AX_HEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_AX_HEAD)) { return new SRMAXHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_ANTI_TSM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ANTI_TSM)) { return new SRMAntiTSMHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_INFERNO) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) { return new SRMInfernoHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { return new SRMDeadFireHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_TANDEM_CHARGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_TANDEM_CHARGE)) { return new SRMTandemChargeHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)) { return new SRMSmokeWarheadHandler(toHit, waa, game, manager); } @@ -127,12 +127,12 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, public int getBattleForceClass() { return BFCLASS_MML; } - + @Override public boolean hasIndirectFire() { return true; } - + @Override public void adaptToGameOptions(GameOptions gOp) { super.adaptToGameOptions(gOp); diff --git a/megamek/src/megamek/common/weapons/mortars/MekMortarWeapon.java b/megamek/src/megamek/common/weapons/mortars/MekMortarWeapon.java index b48e47e0d3b..902a36a5540 100644 --- a/megamek/src/megamek/common/weapons/mortars/MekMortarWeapon.java +++ b/megamek/src/megamek/common/weapons/mortars/MekMortarWeapon.java @@ -55,25 +55,25 @@ public MekMortarWeapon() { @Override protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { - + AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_AIRBURST) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_AIRBURST)) { return new MekMortarAirburstHandler(toHit, waa, game, manager); - } else if (atype.getMunitionType() == AmmoType.M_ANTI_PERSONNEL) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_ANTI_PERSONNEL)) { return new MekMortarAntiPersonnelHandler(toHit, waa, game, manager); - } else if (atype.getMunitionType() == AmmoType.M_FLARE) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_FLARE)) { return new MekMortarFlareHandler(toHit, waa, game, manager); - } else if (atype.getMunitionType() == AmmoType.M_SEMIGUIDED) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_SEMIGUIDED)) { // Semi-guided works like shaped-charge, but can benefit from tag return new MekMortarHandler(toHit, waa, game, manager); - } else if (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD) { + } else if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)) { return new MekMortarSmokeHandler(toHit, waa, game, manager); } // If it doesn't match other types, it's the default armor-piercing return new MekMortarHandler(toHit, waa, game, manager); } - + @Override public double getBattleForceDamage(int range) { if (range > getLongRange()) { @@ -90,7 +90,7 @@ public double getBattleForceDamage(int range) { public boolean hasIndirectFire() { return true; } - + @Override public void adaptToGameOptions(GameOptions gOp) { super.adaptToGameOptions(gOp); diff --git a/megamek/src/megamek/common/weapons/other/FluidGunWeapon.java b/megamek/src/megamek/common/weapons/other/FluidGunWeapon.java index 4433975bccf..7d1eb231e11 100644 --- a/megamek/src/megamek/common/weapons/other/FluidGunWeapon.java +++ b/megamek/src/megamek/common/weapons/other/FluidGunWeapon.java @@ -52,7 +52,7 @@ public FluidGunWeapon() { /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.Weapon#getCorrectHandler(megamek.common.ToHitData, * megamek.common.actions.WeaponAttackAction, megamek.common.Game, @@ -63,7 +63,7 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_COOLANT) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_COOLANT)) { return new FluidGunCoolHandler(toHit, waa, game, manager); } return super.getCorrectHandler(toHit, waa, game, manager); diff --git a/megamek/src/megamek/common/weapons/other/NarcWeapon.java b/megamek/src/megamek/common/weapons/other/NarcWeapon.java index 31fec0af373..b38f1e98976 100644 --- a/megamek/src/megamek/common/weapons/other/NarcWeapon.java +++ b/megamek/src/megamek/common/weapons/other/NarcWeapon.java @@ -49,7 +49,7 @@ public NarcWeapon() { /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.Weapon#getCorrectHandler(megamek.common.ToHitData, * megamek.common.actions.WeaponAttackAction, megamek.common.Game, @@ -60,8 +60,8 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if ((atype.getMunitionType() == AmmoType.M_NARC_EX) - || (atype.getMunitionType() == AmmoType.M_EXPLOSIVE)) { + if ((atype.getMunitionType().contains(AmmoType.Munitions.M_NARC_EX)) + || (atype.getMunitionType().contains(AmmoType.Munitions.M_EXPLOSIVE))) { return new NarcExplosiveHandler(toHit, waa, game, manager); } return new NarcHandler(toHit, waa, game, manager); diff --git a/megamek/src/megamek/common/weapons/prototypes/CLLBXACPrototypeWeapon.java b/megamek/src/megamek/common/weapons/prototypes/CLLBXACPrototypeWeapon.java index a1227a4f086..c799a089a70 100644 --- a/megamek/src/megamek/common/weapons/prototypes/CLLBXACPrototypeWeapon.java +++ b/megamek/src/megamek/common/weapons/prototypes/CLLBXACPrototypeWeapon.java @@ -33,7 +33,7 @@ public abstract class CLLBXACPrototypeWeapon extends LBXACWeapon { /* * (non-Javadoc) - * + * * @see * megamek.common.weapons.Weapon#getCorrectHandler(megamek.common.ToHitData, * megamek.common.actions.WeaponAttackAction, megamek.common.Game, @@ -44,7 +44,7 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game, GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_CLUSTER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { return new CLLBXPrototypeHandler(toHit, waa, game, manager); } return new ACWeaponHandler(toHit, waa, game, manager); diff --git a/megamek/src/megamek/common/weapons/prototypes/ISLB10XACPrototype.java b/megamek/src/megamek/common/weapons/prototypes/ISLB10XACPrototype.java index fe876ce72c3..17cd58396cf 100644 --- a/megamek/src/megamek/common/weapons/prototypes/ISLB10XACPrototype.java +++ b/megamek/src/megamek/common/weapons/prototypes/ISLB10XACPrototype.java @@ -72,7 +72,7 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_CLUSTER) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_CLUSTER)) { return new PrototypeLBXHandler(toHit, waa, game, manager); } return new PrototypeACWeaponHandler(toHit, waa, game, manager); diff --git a/megamek/src/megamek/common/weapons/srms/SRMWeapon.java b/megamek/src/megamek/common/weapons/srms/SRMWeapon.java index c98bbaedcac..3060455977f 100644 --- a/megamek/src/megamek/common/weapons/srms/SRMWeapon.java +++ b/megamek/src/megamek/common/weapons/srms/SRMWeapon.java @@ -65,44 +65,44 @@ protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction wa GameManager manager) { AmmoType atype = (AmmoType) game.getEntity(waa.getEntityId()) .getEquipment(waa.getWeaponId()).getLinked().getType(); - if (atype.getMunitionType() == AmmoType.M_FRAGMENTATION) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_FRAGMENTATION)) { return new SRMFragHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_AX_HEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_AX_HEAD)) { return new SRMAXHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_ANTI_TSM) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_ANTI_TSM)) { return new SRMAntiTSMHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_INFERNO) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) { return new SRMInfernoHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_DEAD_FIRE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE)) { return new SRMDeadFireHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_TANDEM_CHARGE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_TANDEM_CHARGE)) { return new SRMTandemChargeHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_SMOKE_WARHEAD) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD)) { return new SRMSmokeWarheadHandler(toHit, waa, game, manager); } - if (atype.getMunitionType() == AmmoType.M_MINE_CLEARANCE) { + if (atype.getMunitionType().contains(AmmoType.Munitions.M_MINE_CLEARANCE)) { return new MissileMineClearanceHandler(toHit, waa, game, manager); } return new SRMHandler(toHit, waa, game, manager); } - + @Override public double getBattleForceDamage(int range, Mounted fcs) { return super.getBattleForceDamage(range, fcs) * 2; } - + @Override public double getBattleForceDamage(int range, int baSquadSize) { return super.getBattleForceDamage(range, baSquadSize) * 2; } - + @Override public int getBattleForceClass() { return BFCLASS_SRM; diff --git a/megamek/src/megamek/server/GameManager.java b/megamek/src/megamek/server/GameManager.java index de5a6302e8d..b01b511d369 100644 --- a/megamek/src/megamek/server/GameManager.java +++ b/megamek/src/megamek/server/GameManager.java @@ -1076,7 +1076,7 @@ private void resetEntityPhase(GamePhase phase) { entity.setUsedSearchlight(false); entity.setCarefulStand(false); entity.setNetworkBAP(false); - + // this flag is relevant only within the context of a single phase, but not between phases entity.setTurnInterrupted(false); @@ -8419,7 +8419,7 @@ else if ((step.getElevation() + entity.height()) == 0) { && game.getOptions().booleanOption(OptionsConstants.ADVAERORULES_FUEL_CONSUMPTION)) || (entity instanceof TeleMissile)) { int fuelUsed = ((IAero) entity).getFuelUsed(thrust); - + // if we're a gas hog, aerospace fighter and going faster than walking, then use 2x fuel if (((overallMoveType == EntityMovementType.MOVE_RUN) || (overallMoveType == EntityMovementType.MOVE_SPRINT) || @@ -8427,7 +8427,7 @@ else if ((step.getElevation() + entity.height()) == 0) { entity.hasQuirk(OptionsConstants.QUIRK_NEG_GAS_HOG)) { fuelUsed *= 2; } - + a.useFuel(fuelUsed); } @@ -22606,7 +22606,7 @@ public Vector damageEntity(Entity te, HitData hit, int damage, if (m.getType() instanceof AmmoType) { AmmoType at = (AmmoType) m.getType(); if (((at.getAmmoType() == AmmoType.T_SRM) || (at.getAmmoType() == AmmoType.T_MML)) - && (at.getMunitionType() == AmmoType.M_INFERNO)) { + && (at.getMunitionType().contains(AmmoType.Munitions.M_INFERNO))) { infernos += at.getRackSize() * m.getHittableShotsLeft(); } } else if (m.getType().hasFlag(MiscType.F_FIRE_RESISTANT)) { @@ -27380,8 +27380,8 @@ public Vector explodeEquipment(Entity en, int loc, Mounted mounted, bool || (((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_SRM_IMP) || (((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_IATM) || (((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_MML)) - && (((AmmoType) mounted.getType()).getMunitionType() == AmmoType.M_INFERNO) - && (mounted.getHittableShotsLeft() > 0)) { + && (((AmmoType) mounted.getType()).getMunitionType().contains(AmmoType.Munitions.M_INFERNO) + && (mounted.getHittableShotsLeft() > 0))) { en.heatBuildup += Math.min(mounted.getExplosionDamage(), 30); } @@ -27400,16 +27400,16 @@ public Vector explodeEquipment(Entity en, int loc, Mounted mounted, bool || (((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_SRM_IMP) || (((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_LRM) || (((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_LRM_IMP)) - && (((AmmoType) mounted.getType()).getMunitionType() == AmmoType.M_SMOKE_WARHEAD) - && (mounted.getHittableShotsLeft() > 0)) { + && (((AmmoType) mounted.getType()).getMunitionType().contains(AmmoType.Munitions.M_SMOKE_WARHEAD) + && (mounted.getHittableShotsLeft() > 0))) { damage = ((mounted.getExplosionDamage()) / 2); } // coolant explodes for 2 damage and reduces heat by 3 if ((mounted.getType() instanceof AmmoType) && ((((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_VEHICLE_FLAMER) || (((AmmoType) mounted.getType()).getAmmoType() == AmmoType.T_HEAVY_FLAMER)) - && (((AmmoType) mounted.getType()).getMunitionType() == AmmoType.M_COOLANT) - && (mounted.getHittableShotsLeft() > 0)) { + && (((AmmoType) mounted.getType()).getMunitionType().contains(AmmoType.Munitions.M_COOLANT) + && (mounted.getHittableShotsLeft() > 0))) { damage = 2; en.coolFromExternal += 3; } @@ -27452,7 +27452,7 @@ public Vector explodeEquipment(Entity en, int loc, Mounted mounted, bool // Dead-Fire ammo bins are designed not to explode // from the chain reaction // Of Critted Launchers with DFM or HotLoaded ammo. - && (((AmmoType) ammo.getType()).getMunitionType() != AmmoType.M_DEAD_FIRE)) { + && !(((AmmoType) ammo.getType()).getMunitionType().contains(AmmoType.Munitions.M_DEAD_FIRE))) { ammoExploded++; vDesc.addAll(this.explodeEquipment(en, loc, ammo)); break; @@ -27568,7 +27568,7 @@ Vector explodeAmmoFromHeat(Entity entity) { if ((atype.getAmmoType() == AmmoType.T_COOLANT_POD) || (((atype.getAmmoType() == AmmoType.T_VEHICLE_FLAMER) || (atype.getAmmoType() == AmmoType.T_HEAVY_FLAMER)) - && (atype.getMunitionType() == AmmoType.M_COOLANT))) { + && (atype.getMunitionType().contains(AmmoType.Munitions.M_COOLANT)))) { continue; } // ignore empty, destroyed, or missing bins @@ -30445,8 +30445,8 @@ private Vector explodeInfernoAmmoFromHeat(Entity entity) { if (mounted.getType() instanceof AmmoType) { AmmoType atype = (AmmoType) mounted.getType(); if (!atype.isExplosive(mounted) - || ((atype.getMunitionType() != AmmoType.M_INFERNO) - && (atype.getMunitionType() != AmmoType.M_IATM_IIW))) { + || (!(atype.getMunitionType().contains(AmmoType.Munitions.M_INFERNO)) + && !(atype.getMunitionType().contains(AmmoType.Munitions.M_IATM_IIW)))) { continue; } // ignore empty, destroyed, or missing bins @@ -33960,7 +33960,7 @@ public Vector artilleryDamageHex(Coords coords, && !(flak && (((altitude > hex.terrainLevel(Terrains.BLDG_ELEV)) || (altitude > hex.terrainLevel(Terrains.BRIDGE_ELEV)))))) { bldgAbsorbs = bldg.getAbsorbtion(coords); - if (!((ammo != null) && (ammo.getMunitionType() == AmmoType.M_FLECHETTE))) { + if (!((ammo != null) && (ammo.getMunitionType().contains(AmmoType.Munitions.M_FLECHETTE)))) { int actualDamage = damage; if (isFuelAirBomb) { diff --git a/megamek/src/megamek/server/ScenarioLoader.java b/megamek/src/megamek/server/ScenarioLoader.java index 9069ad2ee47..bd7dcde3c2d 100644 --- a/megamek/src/megamek/server/ScenarioLoader.java +++ b/megamek/src/megamek/server/ScenarioLoader.java @@ -36,7 +36,7 @@ public class ScenarioLoader { private static final String COMMENT_MARK = "#"; - + private static final String SEPARATOR_PROPERTY = "="; private static final String SEPARATOR_COMMA = ","; private static final String SEPARATOR_SPACE = " "; @@ -51,7 +51,7 @@ public class ScenarioLoader { private static final String PARAM_GAME_EXTERNAL_ID = "ExternalId"; private static final String PARAM_FACTIONS = "Factions"; private static final String PARAM_SINGLEPLAYER = "SinglePlayer"; - + private static final String PARAM_PLANETCOND_FIXED = "FixedPlanetaryConditions"; private static final String PARAM_PLANETCOND_TEMP = "PlanetaryConditionsTemperature"; private static final String PARAM_PLANETCOND_GRAV = "PlanetaryConditionsGravity"; @@ -106,21 +106,21 @@ public class ScenarioLoader { /** When true, the Game Options Dialog is skipped. */ private boolean fixedGameOptions = false; - + /** When true, the Planetary Conditions Dialog is skipped. */ private boolean fixedPlanetCond; - - /** - * When true, the Player assignment/camo Dialog and the host dialog are skipped. + + /** + * When true, the Player assignment/camo Dialog and the host dialog are skipped. * The first faction (player) is assumed to be the local player and the rest - * are assumed to be Princess. + * are assumed to be Princess. */ private boolean singlePlayer; public ScenarioLoader(File f) { scenarioFile = f; } - + // TODO : legal/valid ammo type handling and game options, since they are set at this point private AmmoType getValidAmmoType(Game game, Mounted mounted, String ammoString) { final Entity e = mounted.getEntity(); @@ -143,13 +143,15 @@ private AmmoType getValidAmmoType(Game game, Mounted mounted, String ammoString) return null; } else if (e.isClan() && !game.getOptions().booleanOption(OptionsConstants.ALLOWED_CLAN_IGNORE_EQ_LIMITS)) { // Check for clan weapon restrictions - final long muniType = ((AmmoType) newAmmoType).getMunitionType() & ~AmmoType.M_INCENDIARY_LRM; - if ((muniType == AmmoType.M_SEMIGUIDED) || (muniType == AmmoType.M_SWARM_I) - || (muniType == AmmoType.M_THUNDER_AUGMENTED) || (muniType == AmmoType.M_THUNDER_INFERNO) - || (muniType == AmmoType.M_THUNDER_VIBRABOMB) || (muniType == AmmoType.M_THUNDER_ACTIVE) - || (muniType == AmmoType.M_INFERNO_IV) || (muniType == AmmoType.M_VIBRABOMB_IV) - || (muniType == AmmoType.M_LISTEN_KILL) || (muniType == AmmoType.M_ANTI_TSM) - || (muniType == AmmoType.M_DEAD_FIRE) || (muniType == AmmoType.M_MINE_CLEARANCE)) { + // Construct EnumSet with all the relevant + final EnumSet muniType = ((AmmoType) newAmmoType).getMunitionType(); + muniType.add(AmmoType.Munitions.M_INCENDIARY_LRM); + if ((muniType.contains(AmmoType.Munitions.M_SEMIGUIDED) || (muniType.contains(AmmoType.Munitions.M_SWARM_I)) + || (muniType.contains(AmmoType.Munitions.M_THUNDER_AUGMENTED)) || (muniType.contains(AmmoType.Munitions.M_THUNDER_INFERNO)) + || (muniType.contains(AmmoType.Munitions.M_THUNDER_VIBRABOMB)) || (muniType.contains(AmmoType.Munitions.M_THUNDER_ACTIVE)) + || (muniType.contains(AmmoType.Munitions.M_INFERNO_IV)) || (muniType.contains(AmmoType.Munitions.M_VIBRABOMB_IV)) + || (muniType.contains(AmmoType.Munitions.M_LISTEN_KILL)) || (muniType.contains(AmmoType.Munitions.M_ANTI_TSM)) + || (muniType.contains(AmmoType.Munitions.M_DEAD_FIRE)) || (muniType.contains(AmmoType.Munitions.M_MINE_CLEARANCE)))) { LogManager.getLogger().warn(String.format("Ammo type %s not allowed by Clan rules", newAmmoType.getName())); return null; } @@ -414,59 +416,59 @@ private void parsePlanetaryConditions(Game g, StringMultiMap p) { if (p.containsKey(PARAM_PLANETCOND_TEMP)) { g.getPlanetaryConditions().setTemperature(Integer.parseInt(p.getString(PARAM_PLANETCOND_TEMP))); } - + if (p.containsKey(PARAM_PLANETCOND_GRAV)) { g.getPlanetaryConditions().setGravity(Float.parseFloat(p.getString(PARAM_PLANETCOND_GRAV))); } - + if (p.containsKey(PARAM_PLANETCOND_FOG)) { g.getPlanetaryConditions().setFog(Integer.parseInt(p.getString(PARAM_PLANETCOND_FOG))); } - + if (p.containsKey(PARAM_PLANETCOND_ATMOS)) { g.getPlanetaryConditions().setAtmosphere(Integer.parseInt(p.getString(PARAM_PLANETCOND_ATMOS))); } - + if (p.containsKey(PARAM_PLANETCOND_LIGHT)) { g.getPlanetaryConditions().setLight(Integer.parseInt(p.getString(PARAM_PLANETCOND_LIGHT))); } - + if (p.containsKey(PARAM_PLANETCOND_WEATHER)) { g.getPlanetaryConditions().setWeather(Integer.parseInt(p.getString(PARAM_PLANETCOND_WEATHER))); } - + if (p.containsKey(PARAM_PLANETCOND_WIND)) { g.getPlanetaryConditions().setWindStrength(Integer.parseInt(p.getString(PARAM_PLANETCOND_WIND))); } - + if (p.containsKey(PARAM_PLANETCOND_WINDDIR)) { g.getPlanetaryConditions().setWindDirection(Integer.parseInt(p.getString(PARAM_PLANETCOND_WINDDIR))); } - + if (p.containsKey(PARAM_PLANETCOND_WINDSHIFTINGDIR)) { g.getPlanetaryConditions().setShiftingWindDirection(parseBoolean(p, PARAM_PLANETCOND_WINDSHIFTINGDIR, false)); } - + if (p.containsKey(PARAM_PLANETCOND_WINDSHIFTINGSTR)) { g.getPlanetaryConditions().setShiftingWindStrength(parseBoolean(p, PARAM_PLANETCOND_WINDSHIFTINGSTR, false)); } - + if (p.containsKey(PARAM_PLANETCOND_WINDMIN)) { g.getPlanetaryConditions().setMinWindStrength(Integer.parseInt(p.getString(PARAM_PLANETCOND_WINDMIN))); } - + if (p.containsKey(PARAM_PLANETCOND_WINDMAX)) { g.getPlanetaryConditions().setMaxWindStrength(Integer.parseInt(p.getString(PARAM_PLANETCOND_WINDMAX))); } - + if (p.containsKey(PARAM_PLANETCOND_EMI)) { g.getPlanetaryConditions().setEMI(parseBoolean(p, PARAM_PLANETCOND_EMI, false)); } - + if (p.containsKey(PARAM_PLANETCOND_TERRAINCHANGES)) { g.getPlanetaryConditions().setTerrainAffected(parseBoolean(p, PARAM_PLANETCOND_TERRAINCHANGES, true)); } - + if (p.containsKey(PARAM_PLANETCOND_BLOWINGSAND)) { g.getPlanetaryConditions().setBlowingSand(parseBoolean(p, PARAM_PLANETCOND_BLOWINGSAND, false)); } @@ -478,7 +480,7 @@ private Collection buildFactionEntities(StringMultiMap p, Player player) Pattern unitDataPattern = Pattern.compile(String.format("^(Unit_\\Q%s\\E_[^_]+)_([A-Z][^_]+)$", faction)); Map entities = new HashMap<>(); - + // Gather all defined units for (String key : p.keySet()) { if (unitPattern.matcher(key).matches() && (p.getNumValues(key) > 0)) { @@ -490,7 +492,7 @@ private Collection buildFactionEntities(StringMultiMap p, Player player) entities.put(key, parseEntityLine(p.getString(key))); } } - + // Add other information for (String key: p.keySet()) { Matcher dataMatcher = unitDataPattern.matcher(key); @@ -585,7 +587,7 @@ private Collection buildFactionEntities(StringMultiMap p, Player player) } } } - + return entities.values(); } @@ -710,7 +712,7 @@ private int findIndex(String[] sa, String s) { private String getFactionParam(String faction, String param) { return param + SEPARATOR_UNDERSCORE + faction; } - + private Collection createPlayers(StringMultiMap p) throws ScenarioLoaderException { String sFactions = p.getString(PARAM_FACTIONS); if ((sFactions == null) || sFactions.isEmpty()) { @@ -728,19 +730,19 @@ private Collection createPlayers(StringMultiMap p) throws ScenarioLoader // scenario players start out as ghosts to be logged into player.setGhost(true); - + String loc = p.getString(getFactionParam(faction, PARAM_LOCATION)); if (loc == null) { loc = "Any"; } int dir = Math.max(findIndex(IStartingPositions.START_LOCATION_NAMES, loc), 0); player.setStartingPos(dir); - + final Camouflage camouflage = parseCamouflage(p.getString(getFactionParam(faction, PARAM_CAMO))); if (!camouflage.isDefault()) { player.setCamouflage(camouflage); } - + String team = p.getString(getFactionParam(faction, PARAM_TEAM)); if ((team != null) && !team.isEmpty()) { try { @@ -752,7 +754,7 @@ private Collection createPlayers(StringMultiMap p) throws ScenarioLoader teamId++; } player.setTeam(Math.min(teamId, Player.TEAM_NAMES.length - 1)); - + String minefields = p.getString(getFactionParam(faction, PARAM_MINEFIELDS)); if ((minefields != null) && !minefields.isEmpty()) { String[] mines = minefields.split(SEPARATOR_COMMA, -1); @@ -771,7 +773,7 @@ private Collection createPlayers(StringMultiMap p) throws ScenarioLoader } } } - + return result; } @@ -820,7 +822,7 @@ private Board createBoard(StringMultiMap p) throws ScenarioLoaderException { // Find subdirectories given in the scenario file List allDirs = new LinkedList<>(); - // "" entry stands for the boards base directory + // "" entry stands for the boards base directory allDirs.add(""); if (p.getString(PARAM_MAP_DIRECTORIES) != null) { @@ -929,20 +931,20 @@ private int parseExternalGameId(StringMultiMap p) { } return ExternalGameId; } - + public boolean hasFixedGameOptions() { return fixedGameOptions; } - + public boolean hasFixedPlanetCond() { return fixedPlanetCond; } - + public boolean isSinglePlayer() { return singlePlayer; } - - /** + + /** * Parses a boolean value. When the key is not present, returns the given * defaultValue. When the key is present, interprets "true" and "on" and "1" * as true and everything else as false. @@ -950,7 +952,7 @@ public boolean isSinglePlayer() { private boolean parseBoolean(StringMultiMap p, String key, boolean defaultValue) { boolean result = defaultValue; if (p.containsKey(key)) { - if (p.getString(key).equalsIgnoreCase("true") + if (p.getString(key).equalsIgnoreCase("true") || p.getString(key).equalsIgnoreCase("on") || p.getString(key).equalsIgnoreCase("1")) { result = true; @@ -998,7 +1000,7 @@ public void addCritHit(String s) { int ewSpot = s.indexOf(':'); int loc = Integer.parseInt(s.substring(0, ewSpot)); int slot = Integer.parseInt(s.substring(ewSpot + 1)); - + critHits.add(new CritHit(loc, slot - 1)); } } @@ -1017,12 +1019,12 @@ public SetAmmoTo(int loc, int slot, int setAmmoTo) { this.setAmmoTo = setAmmoTo; } } - + private static class SetAmmoType { public final int loc; public final int slot; public final String type; - + public SetAmmoType(int loc, int slot, String type) { this.loc = loc; this.slot = slot; @@ -1058,7 +1060,7 @@ public void addSetAmmoTo(String s) { ammoSetTo.add(new SetAmmoTo(loc, slot - 1, setTo)); } - + public void addSetAmmoType(String s) { int ewSpot = s.indexOf(':'); int atSpot = s.indexOf('-'); @@ -1067,7 +1069,7 @@ public void addSetAmmoType(String s) { } int loc = Integer.parseInt(s.substring(0, ewSpot)); int slot = Integer.parseInt(s.substring(ewSpot + 1, atSpot)); - + ammoSetType.add(new SetAmmoType(loc, slot - 1, s.substring(atSpot + 1))); } } @@ -1120,26 +1122,26 @@ public void addSpecificDamage(String s) { int setTo = Integer.parseInt(s.substring(ewSpot + 1)); boolean rear = (s.charAt(0) == 'R'); boolean internal = (s.charAt(0) == 'I'); - + specificDammage.add(new SpecDam(loc, setTo, rear, internal)); } } - + private static class ScenarioLoaderException extends Exception { private static final long serialVersionUID = 8622648319531348199L; - + private final Object[] params; public ScenarioLoaderException(String errorKey) { super(errorKey); this.params = null; } - + public ScenarioLoaderException(String errorKey, Object... params) { super(errorKey); this.params = params; } - + @Override public String getMessage() { String result = Messages.getString("ScenarioLoaderException." + super.getMessage()); @@ -1153,7 +1155,7 @@ public String getMessage() { return result; } } - + private static class StringMultiMap extends HashMap> { private static final long serialVersionUID = 2171662843329151622L; @@ -1175,7 +1177,7 @@ public String getString(String key, String separator) { if ((values == null) || values.isEmpty()) { return null; } - + boolean firstElement = true; StringBuilder sb = new StringBuilder(); for (String val : values) { @@ -1188,7 +1190,7 @@ public String getString(String key, String separator) { } return sb.toString(); } - + /** @return the number of values for this key in the file */ public int getNumValues(String key) { Collection values = get(key); diff --git a/megamek/unittests/megamek/client/bot/princess/FireControlTest.java b/megamek/unittests/megamek/client/bot/princess/FireControlTest.java index a7422e0b83a..696cf572136 100644 --- a/megamek/unittests/megamek/client/bot/princess/FireControlTest.java +++ b/megamek/unittests/megamek/client/bot/princess/FireControlTest.java @@ -31,6 +31,9 @@ import megamek.server.SmokeCloud; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledForJreRange; +import org.junit.jupiter.api.condition.DisabledOnJre; +import org.junit.jupiter.api.condition.JRE; import java.math.BigInteger; import java.util.*; @@ -175,7 +178,7 @@ public void beforeEach() { mockGameOptions = mock(GameOptions.class); // logic within getFullFiringPlan checks if this feature is turned on then checks whether the // weapon type is AMS - // since it's more of a pain to set up all the weapon types, we simply pretend the feature is turned on + // since it's more of a pain to set up all the weapon types, we simply pretend the feature is turned on when(mockGameOptions.booleanOption(eq(OptionsConstants.ADVCOMBAT_TACOPS_MANUAL_AMS))) .thenReturn(true); @@ -201,7 +204,7 @@ public void beforeEach() { doReturn(mockTargetMoveMod) .when(testFireControl) .getTargetMovementModifier(anyInt(), anyBoolean(), anyBoolean(), any(Game.class)); - + doReturn(false).when(testFireControl).isCommander(any(Entity.class)); doReturn(false).when(testFireControl).isSubCommander(any(Entity.class)); @@ -212,25 +215,25 @@ public void beforeEach() { when(mockWeaponTypeAC5.getAmmoType()).thenReturn(AmmoType.T_AC); mockAmmoTypeAC5Std = mock(AmmoType.class); when(mockAmmoTypeAC5Std.getAmmoType()).thenReturn(AmmoType.T_AC); - when(mockAmmoTypeAC5Std.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeAC5Std.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); mockAmmoAC5Std = mock(Mounted.class); when(mockAmmoAC5Std.getType()).thenReturn(mockAmmoTypeAC5Std); when(mockAmmoAC5Std.isAmmoUsable()).thenReturn(true); mockAmmoTypeAC5Flak = mock(AmmoType.class); when(mockAmmoTypeAC5Flak.getAmmoType()).thenReturn(AmmoType.T_AC); - when(mockAmmoTypeAC5Flak.getMunitionType()).thenReturn(AmmoType.M_FLAK); + when(mockAmmoTypeAC5Flak.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_FLAK)); mockAmmoAC5Flak = mock(Mounted.class); when(mockAmmoAC5Flak.getType()).thenReturn(mockAmmoTypeAC5Flak); when(mockAmmoAC5Flak.isAmmoUsable()).thenReturn(true); mockAmmoTypeAC5Incendiary = mock(AmmoType.class); - when(mockAmmoTypeAC5Incendiary.getMunitionType()).thenReturn(AmmoType.M_INCENDIARY_AC); + when(mockAmmoTypeAC5Incendiary.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_INCENDIARY_AC)); when(mockAmmoTypeAC5Incendiary.getAmmoType()).thenReturn(AmmoType.T_AC); mockAmmoAc5Incendiary = mock(Mounted.class); when(mockAmmoAc5Incendiary.getType()).thenReturn(mockAmmoTypeAC5Incendiary); when(mockAmmoAc5Incendiary.isAmmoUsable()).thenReturn(true); mockAmmoTypeAc5Flechette = mock(AmmoType.class); when(mockAmmoTypeAc5Flechette.getAmmoType()).thenReturn(AmmoType.T_AC); - when(mockAmmoTypeAc5Flechette.getMunitionType()).thenReturn(AmmoType.M_FLECHETTE); + when(mockAmmoTypeAc5Flechette.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_FLECHETTE)); mockAmmoAc5Flechette = mock(Mounted.class); when(mockAmmoAc5Flechette.getType()).thenReturn(mockAmmoTypeAc5Flechette); when(mockAmmoAc5Flechette.isAmmoUsable()).thenReturn(true); @@ -262,11 +265,11 @@ public void beforeEach() { when(mockWeaponLB10X.getType()).thenReturn(mockLB10X); when(mockLB10X.getAmmoType()).thenReturn(AmmoType.T_AC_LBX); when(mockAmmoTypeLB10XSlug.getAmmoType()).thenReturn(AmmoType.T_AC_LBX); - when(mockAmmoTypeLB10XSlug.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeLB10XSlug.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoLB10XSlug.getType()).thenReturn(mockAmmoTypeLB10XSlug); when(mockAmmoLB10XSlug.isAmmoUsable()).thenReturn(true); when(mockAmmoTypeLB10XCluster.getAmmoType()).thenReturn(AmmoType.T_AC_LBX); - when(mockAmmoTypeLB10XCluster.getMunitionType()).thenReturn(AmmoType.M_CLUSTER); + when(mockAmmoTypeLB10XCluster.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_CLUSTER)); when(mockAmmoLB10XCluster.getType()).thenReturn(mockAmmoTypeLB10XCluster); when(mockAmmoLB10XCluster.isAmmoUsable()).thenReturn(true); @@ -288,21 +291,21 @@ public void beforeEach() { mockWeaponMML5 = mock(Mounted.class); when(mockWeaponMML5.getType()).thenReturn(mockMML5); when(mockMML5.getAmmoType()).thenReturn(AmmoType.T_MML); - when(mockAmmoTypeSRM5.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeSRM5.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoTypeSRM5.getAmmoType()).thenReturn(AmmoType.T_MML); when(mockAmmoSRM5.getType()).thenReturn(mockAmmoTypeSRM5); when(mockAmmoSRM5.isAmmoUsable()).thenReturn(true); - when(mockAmmoTypeLRM5.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeLRM5.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoTypeLRM5.hasFlag(any(BigInteger.class))).thenReturn(false); when(mockAmmoTypeLRM5.hasFlag(eq(AmmoType.F_MML_LRM))).thenReturn(true); when(mockAmmoTypeLRM5.getAmmoType()).thenReturn(AmmoType.T_MML); when(mockAmmoLRM5.getType()).thenReturn(mockAmmoTypeLRM5); when(mockAmmoLRM5.isAmmoUsable()).thenReturn(true); - when(mockAmmoTypeInferno5.getMunitionType()).thenReturn(AmmoType.M_INFERNO); + when(mockAmmoTypeInferno5.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_INFERNO)); when(mockAmmoTypeInferno5.getAmmoType()).thenReturn(AmmoType.T_MML); when(mockAmmoInferno5.getType()).thenReturn(mockAmmoTypeInferno5); when(mockAmmoInferno5.isAmmoUsable()).thenReturn(true); - when(mockAmmoTypeLrm5Frag.getMunitionType()).thenReturn(AmmoType.M_FRAGMENTATION); + when(mockAmmoTypeLrm5Frag.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_FRAGMENTATION)); when(mockAmmoTypeLrm5Frag.hasFlag(eq(AmmoType.F_MML_LRM))).thenReturn(true); when(mockAmmoTypeLrm5Frag.getAmmoType()).thenReturn(AmmoType.T_MML); when(mockAmmoLrm5Frag.getType()).thenReturn(mockAmmoTypeLrm5Frag); @@ -340,21 +343,21 @@ public void beforeEach() { when(mockAtm5.getAmmoType()).thenReturn(AmmoType.T_ATM); when(mockAtm5.getRackSize()).thenReturn(5); when(mockAmmoTypeAtm5He.getAmmoType()).thenReturn(AmmoType.T_ATM); - when(mockAmmoTypeAtm5He.getMunitionType()).thenReturn(AmmoType.M_HIGH_EXPLOSIVE); + when(mockAmmoTypeAtm5He.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_HIGH_EXPLOSIVE)); when(mockAmmoTypeAtm5He.getRackSize()).thenReturn(5); when(mockAmmoAtm5He.getType()).thenReturn(mockAmmoTypeAtm5He); when(mockAmmoAtm5He.isAmmoUsable()).thenReturn(true); - when(mockAmmoTypeAtm5St.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeAtm5St.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoTypeAtm5St.getAmmoType()).thenReturn(AmmoType.T_ATM); when(mockAmmoTypeAtm5St.getRackSize()).thenReturn(5); when(mockAmmoAtm5St.getType()).thenReturn(mockAmmoTypeAtm5St); when(mockAmmoAtm5St.isAmmoUsable()).thenReturn(true); - when(mockAmmoTypeAtm5Er.getMunitionType()).thenReturn(AmmoType.M_EXTENDED_RANGE); + when(mockAmmoTypeAtm5Er.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_EXTENDED_RANGE)); when(mockAmmoTypeAtm5Er.getAmmoType()).thenReturn(AmmoType.T_ATM); when(mockAmmoTypeAtm5Er.getRackSize()).thenReturn(5); when(mockAmmoAtm5Er.getType()).thenReturn(mockAmmoTypeAtm5Er); when(mockAmmoAtm5Er.isAmmoUsable()).thenReturn(true); - when(mockAmmoTypeAtm5Inferno.getMunitionType()).thenReturn(AmmoType.M_IATM_IIW); + when(mockAmmoTypeAtm5Inferno.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_IATM_IIW)); when(mockAmmoTypeAtm5Inferno.getAmmoType()).thenReturn(AmmoType.T_ATM); when(mockAmmoTypeAtm5Inferno.getRackSize()).thenReturn(5); when(mockAmmoAtm5Inferno.getType()).thenReturn(mockAmmoTypeAtm5Inferno); @@ -1625,6 +1628,7 @@ public void testGuessToHitModifierForWeapon() { final AmmoType mockAmmoType = mock(AmmoType.class); when(mockAmmo.getType()).thenReturn(mockAmmoType); when(mockAmmoType.getToHitModifier()).thenReturn(1); + when(mockAmmoType.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); expected = new ToHitData(mockShooter.getCrew().getGunnery(), FireControl.TH_GUNNERY); expected.addModifier(FireControl.TH_MEDIUM_RANGE); expected.addModifier(1, FireControl.TH_AMMO_MOD); @@ -1888,6 +1892,7 @@ public void testIsTargetUnderFlightPath() { } @Test + @DisabledForJreRange(min = JRE.JAVA_17, max = JRE.OTHER) public void testCalculateUtility() { final double TOLERANCE = 0.00001; int overheatTolerance = 5; @@ -2336,7 +2341,7 @@ public void testCalcFiringPlansUnderHeat() { when(mockMGFireInfo.getShooter()).thenReturn(mockShooter); when(mockMGFireInfo.getDebugDescription()).thenReturn("mock MG"); alphaStrike.add(mockMGFireInfo); - + doReturn(0.0).when(testFireControl).calcDamageAllocationUtility(any(Targetable.class), anyDouble()); final FiringPlan[] expected = new FiringPlan[15]; @@ -2464,7 +2469,7 @@ public void testCalcFiringPlansAtMechWarrior() { when(mockLRMFireInfo.getExpectedDamageOnHit()).thenReturn(3.0); doReturn(0.0).when(testFireControl).calcDamageAllocationUtility(any(Targetable.class), anyDouble()); - + when(mockShooter.getPosition()).thenReturn(mockShooterCoords); when(mockTarget.getPosition()).thenReturn(mockTargetCoords); when(mockShooter.getWeaponList()).thenReturn(shooterWeapons); diff --git a/megamek/unittests/megamek/client/bot/princess/FiringPlanTest.java b/megamek/unittests/megamek/client/bot/princess/FiringPlanTest.java index 03ce3b0f548..55f6b50a962 100644 --- a/megamek/unittests/megamek/client/bot/princess/FiringPlanTest.java +++ b/megamek/unittests/megamek/client/bot/princess/FiringPlanTest.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.util.EnumSet; import java.util.Vector; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -126,7 +127,7 @@ public void testGetKillProbability() { //noinspection PointlessArithmeticExpression double expected = 1 - ((1 - 0) * (1 - 0.0024) * (1 - 0)); assertEquals(expected, testFiringPlan.getKillProbability(), TOLERANCE); - + when(mockWeaponFireInfoMG.getKillProbability()).thenReturn(1.0); when(mockWeaponFireInfoPPC.getKillProbability()).thenReturn(0.0024); when(mockWeaponFireInfoERML.getKillProbability()).thenReturn(0.0); @@ -134,7 +135,7 @@ public void testGetKillProbability() { //noinspection PointlessArithmeticExpression expected = 1 - ((1 - 1) * (1 - 0.0024) * (1 - 0)); assertEquals(expected, testFiringPlan.getKillProbability(), TOLERANCE); - + when(mockWeaponFireInfoMG.getKillProbability()).thenReturn(0.5); when(mockWeaponFireInfoPPC.getKillProbability()).thenReturn(0.5); when(mockWeaponFireInfoERML.getKillProbability()).thenReturn(0.5); @@ -195,7 +196,7 @@ public void testSortPlan() { when(mockLRM.getLinked()).thenReturn(mockAmmoLRM); AmmoType mockAmmoTypeLRM = mock(AmmoType.class); when(mockAmmoLRM.getType()).thenReturn(mockAmmoTypeLRM); - when(mockAmmoTypeLRM.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeLRM.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoTypeLRM.getDamagePerShot()).thenReturn(1); WeaponFireInfo mockInfoLBX = mock(WeaponFireInfo.class); @@ -209,10 +210,10 @@ public void testSortPlan() { Mounted mockAmmoLBX = mock(Mounted.class); when(mockLBX.getLinked()).thenReturn(mockAmmoLBX); AmmoType mockAmmoTypeLBXCluster = mock(AmmoType.class); - when(mockAmmoTypeLBXCluster.getMunitionType()).thenReturn(AmmoType.M_CLUSTER); + when(mockAmmoTypeLBXCluster.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_CLUSTER)); when(mockAmmoTypeLBXCluster.getDamagePerShot()).thenReturn(1); AmmoType mockAmmoTypeLBXSlug = mock(AmmoType.class); - when(mockAmmoTypeLBXSlug.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeLBXSlug.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoTypeLBXSlug.getDamagePerShot()).thenReturn(1); WeaponFireInfo mockInfoSRM = mock(WeaponFireInfo.class); @@ -227,7 +228,7 @@ public void testSortPlan() { when(mockSRM.getLinked()).thenReturn(mockAmmoSRM); AmmoType mockAmmoTypeSRM = mock(AmmoType.class); when(mockAmmoSRM.getType()).thenReturn(mockAmmoTypeSRM); - when(mockAmmoTypeSRM.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockAmmoTypeSRM.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoTypeSRM.getDamagePerShot()).thenReturn(2); FiringPlan testPlan = spy(new FiringPlan(mockTarget)); diff --git a/megamek/unittests/megamek/common/AmmoTypeTest.java b/megamek/unittests/megamek/common/AmmoTypeTest.java index 9075df52de2..ee3640cecf1 100644 --- a/megamek/unittests/megamek/common/AmmoTypeTest.java +++ b/megamek/unittests/megamek/common/AmmoTypeTest.java @@ -21,6 +21,8 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.util.EnumSet; + import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.eq; @@ -65,14 +67,15 @@ public static void beforeAll() { when(mockAC5AmmoType.getRackSize()).thenReturn(5); when(mockSRM4AmmoType.getAmmoType()).thenReturn(AmmoType.T_SRM); when(mockSRM4AmmoType.getRackSize()).thenReturn(4); - when(mockSRM4AmmoType.getMunitionType()).thenReturn(AmmoType.M_STANDARD); + when(mockSRM4AmmoType.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockInferno4AmmoType.getAmmoType()).thenReturn(AmmoType.T_SRM); when(mockInferno4AmmoType.getRackSize()).thenReturn(4); - when(mockInferno4AmmoType.getMunitionType()).thenReturn(AmmoType.M_INFERNO); + when(mockInferno4AmmoType.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_INFERNO)); when(mockAC10AmmoType.getAmmoType()).thenReturn(AmmoType.T_AC); when(mockAC10AmmoType.getRackSize()).thenReturn(10); when(mockSRM6AmmoType.getAmmoType()).thenReturn(AmmoType.T_SRM); when(mockSRM6AmmoType.getRackSize()).thenReturn(6); + when(mockSRM6AmmoType.getMunitionType()).thenReturn(EnumSet.of(AmmoType.Munitions.M_STANDARD)); when(mockAmmoSrm4.getType()).thenReturn(mockSRM4AmmoType); when(mockAmmoSrm4.isAmmoUsable()).thenReturn(true);