boolean isIndirect = ((wtype.getAmmoType() == AmmoType.T_LRM) || (wtype .getAmmoType() == AmmoType.T_LRM_TORPEDO))
boolean isIndirect = ((wtype.getAmmoType() == AmmoType.T_LRM) || (wtype.getAmmoType() == AmmoType.T_EXLRM) || (wtype.getAmmoType() == AmmoType.T_TBOLT5) || (wtype.getAmmoType() == AmmoType.T_TBOLT10) || (wtype.getAmmoType() == AmmoType.T_TBOLT15) || (wtype.getAmmoType() == AmmoType.T_TBOLT20) || (wtype.getAmmoType() == AmmoType.T_LRM_TORPEDO))
    public static ToHitData getRangeMods(IGame game, Entity ae, int weaponId,            Targetable target) {        Mounted weapon = ae.getEquipment(weaponId);        WeaponType wtype = (WeaponType) weapon.getType();        int[] weaponRanges = wtype.getRanges();        boolean isAttackerInfantry = (ae instanceof Infantry);        boolean isWeaponInfantry = wtype.hasFlag(WeaponType.F_INFANTRY);        boolean isLRMInfantry = isWeaponInfantry                && wtype.getAmmoType() == AmmoType.T_LRM;        boolean isIndirect = ((wtype.getAmmoType() == AmmoType.T_LRM) || (wtype                .getAmmoType() == AmmoType.T_LRM_TORPEDO))                && weapon.curMode().equals("Indirect");        boolean useExtremeRange = game.getOptions().booleanOption(                "maxtech_range");        ToHitData mods = new ToHitData();        // modify the ranges for ATM missile systems based on the ammo selected        // TODO: this is not the right place to hardcode these        if (wtype.getAmmoType() == AmmoType.T_ATM) {            AmmoType atype = (AmmoType) weapon.getLinked().getType();            if ((atype.getAmmoType() == AmmoType.T_ATM)                    && atype.getMunitionType() == AmmoType.M_EXTENDED_RANGE) {                weaponRanges = new int[] { 4, 9, 18, 27, 36 };            } else if ((atype.getAmmoType() == AmmoType.T_ATM)                    && atype.getMunitionType() == AmmoType.M_HIGH_EXPLOSIVE) {                weaponRanges = new int[] { 0, 3, 6, 9, 12 };            }        }        //        // modifiy the ranges for PPCs when field inhibitors are turned off        // TODO: See above, it should be coded elsewhere...        //        if (wtype.getName().equals("Particle Cannon")) {            if (game.getOptions().booleanOption("maxtech_ppc_inhibitors")) {                if (weapon.curMode().equals("Field Inhibitor OFF")) {                    weaponRanges[0] = 0;                }            }        }        // is water involved?        IHex attHex = game.getBoard().getHex(ae.getPosition());        IHex targHex = game.getBoard().getHex(target.getPosition());        int targTop = 0;        int targBottom = 0;        if (target != null) {            targTop = target.absHeight();            targBottom = target.getElevation();        }        boolean targetInPartialWater = false;        boolean targetUnderwater = false;        boolean weaponUnderwater = (ae.getLocationStatus(weapon.getLocation()) == ILocationExposureStatus.WET);        if (targHex.containsTerrain(Terrains.WATER) && targBottom < 0) {            if (targTop >= 0)                targetInPartialWater = true;            else                targetUnderwater = true;        }        // allow naval units on surface to be attacked from above or below        Entity te = null;        if (target instanceof Entity) {            te = (Entity) target;            if (targBottom == 0                    && UnitType.determineUnitTypeCode(te) == UnitType.NAVAL) {                targetInPartialWater = true;            }        }        // allow naval units to target underwater units,        // torpedo tubes are mounted underwater        if ((targetUnderwater || wtype.getAmmoType() == AmmoType.T_LRM_TORPEDO || wtype                .getAmmoType() == AmmoType.T_SRM_TORPEDO)                && UnitType.determineUnitTypeCode(ae) == UnitType.NAVAL) {            weaponUnderwater = true;            weaponRanges = wtype.getWRanges();        }        // allow ice to be cleared from below        if(targHex.containsTerrain(Terrains.WATER) && target.getTargetType() == Targetable.TYPE_HEX_CLEAR) {            targetInPartialWater = true;        }        if (weaponUnderwater) {            weaponRanges = wtype.getWRanges();            // HACK on ranges: for those without underwater range,            // long == medium; iteration in rangeBracket() allows this            if (weaponRanges[RangeType.RANGE_SHORT] == 0) {                return new ToHitData(ToHitData.IMPOSSIBLE,                        "Weapon cannot fire underwater.");            }            if (!targetUnderwater && !targetInPartialWater) {                // target on land or over water                return new ToHitData(ToHitData.IMPOSSIBLE,                        "Weapon underwater, but not target.");            }            // special case: mechs can only fire upper body weapons at surface            // naval            if (te != null                    && UnitType.determineUnitTypeCode(te) == UnitType.NAVAL                    && ae instanceof Mech && ae.height() > 0                    && ae.getElevation() == -1) {                return new ToHitData(ToHitData.IMPOSSIBLE,                        "Partially submerged mech cannot fire leg weapons at surface naval vessels.");            }        } else if (targetUnderwater) {            return new ToHitData(ToHitData.IMPOSSIBLE,                    "Target underwater, but not weapon.");        } else if (wtype.getAmmoType() == AmmoType.T_LRM_TORPEDO                || wtype.getAmmoType() == AmmoType.T_SRM_TORPEDO) {            // Torpedos only fire underwater.            return new ToHitData(ToHitData.IMPOSSIBLE,                    "Weapon can only fire underwater.");        }        // determine base distance & range bracket        int distance = effectiveDistance(game, ae, target);        int range = RangeType.rangeBracket(distance, weaponRanges,                useExtremeRange);        // short circuit if at zero range or out of range        if (range == RangeType.RANGE_OUT) {            return new ToHitData(ToHitData.AUTOMATIC_FAIL,                    "Target out of range");        }        if (distance == 0 && !isAttackerInfantry) {            return new ToHitData(ToHitData.AUTOMATIC_FAIL,                    "Only infantry shoot at zero range");        }        // find any c3 spotters that could help        Entity c3spotter = findC3Spotter(game, ae, target);        if (isIndirect) {            c3spotter = ae; // no c3 when using indirect fire        }        if (isIndirect && game.getOptions().booleanOption("indirect_fire")                && !game.getOptions().booleanOption("indirect_always_possible")                && LosEffects.calculateLos(game, ae.getId(), target).canSee()) {            return new ToHitData(ToHitData.IMPOSSIBLE,                    "Indirect fire impossible with direct LOS");        }        int c3dist = effectiveDistance(game, c3spotter, target);        int c3range = RangeType.rangeBracket(c3dist, weaponRanges,                useExtremeRange);        // determine which range we're using        int usingRange = Math.min(range, c3range);        String targSysType = "";        // Get the targetting system type string ready, if necessary        if ((ae.getTargSysType() == MiscType.T_TARGSYS_LONGRANGE)                && (ae.getTargSysType() == MiscType.T_TARGSYS_SHORTRANGE)) {            targSysType = " (w/"                    + MiscType.getTargetSysName(ae.getTargSysType()) + ")";        }        // add range modifier        if (usingRange == range) {            // no c3 adjustment            if ((range == RangeType.RANGE_SHORT || range == RangeType.RANGE_MINIMUM)                    && (ae.getShortRangeModifier() != 0)) {                mods.addModifier(ae.getShortRangeModifier(), "short range"                        + targSysType);            } else if (range == RangeType.RANGE_MEDIUM) {                // Right now, the range-mod affecting targetting systems DON'T                // affect medium range, so we won't add that here ever.                mods.addModifier(ae.getMediumRangeModifier(), "medium range");            } else if (range == RangeType.RANGE_LONG) {                // Protos that loose head sensors can't shoot long range.                if ((ae instanceof Protomech)                        && (2 == ((Protomech) ae)                                .getCritsHit(Protomech.LOC_HEAD))) {                    mods                            .addModifier(ToHitData.IMPOSSIBLE,                                    "No long range attacks with destroyed head sensors.");                } else {                    mods.addModifier(ae.getLongRangeModifier(), "long range"                            + targSysType);                }            } else if (range == RangeType.RANGE_EXTREME) {                // Protos that loose head sensors can't shoot extreme range.                if ((ae instanceof Protomech)                        && (2 == ((Protomech) ae)                                .getCritsHit(Protomech.LOC_HEAD))) {                    mods                            .addModifier(ToHitData.IMPOSSIBLE,                                    "No extreme range attacks with destroyed head sensors.");                } else {                    mods.addModifier(ae.getExtremeRangeModifier(),                            "extreme range" + targSysType);                }            }        } else {            // report c3 adjustment            if (c3range == RangeType.RANGE_SHORT || range == RangeType.RANGE_MINIMUM) {                mods.addModifier(ae.getShortRangeModifier(),                        "short range due to C3 spotter" + targSysType);            } else if (c3range == RangeType.RANGE_MEDIUM) {                mods.addModifier(ae.getMediumRangeModifier(),                        "medium range due to C3 spotter" + targSysType);            } else if (c3range == RangeType.RANGE_LONG) {                mods.addModifier(ae.getLongRangeModifier(),                        "long range due to C3 spotter" + targSysType);            }        }        // add infantry LRM maximum range penalty        if (isLRMInfantry && distance == weaponRanges[RangeType.RANGE_LONG]) {            mods.addModifier(1, "infantry LRM maximum range");        }        // add infantry zero-range modifier        // TODO: this is not the right place to hardcode these        if (isWeaponInfantry && distance == 0) {            // Infantry platoons attacking with infantry weapons can attack            // in the same hex with a base of 2, except for flamers and            // SRMs, which have a base of 3 and LRMs, which suffer badly.            if (wtype.hasFlag(WeaponType.F_FLAMER)) {                mods.addModifier(-1, "infantry flamer assault");            } else if (wtype.getAmmoType() == AmmoType.T_SRM) {                mods.addModifier(-1, "infantry SRM assault");            } else if (wtype.getAmmoType() != AmmoType.T_LRM) {                mods.addModifier(-2, "infantry assault");            }        }        // add minimum range modifier        int minRange = weaponRanges[RangeType.RANGE_MINIMUM];        if (minRange > 0 && distance <= minRange) {            int minPenalty = (minRange - distance) + 1;            // Infantry LRMs suffer double minimum range penalties.            if (isLRMInfantry) {                mods.addModifier(minPenalty * 2, "infantry LRM minimum range");            } else {                mods.addModifier(minPenalty, "minimum range");            }        }        // add any target stealth modifier        if (target instanceof Entity) {            TargetRoll tmpTR = ((Entity)target).getStealthModifier(usingRange);            if (tmpTR.getValue() != 0)                mods.append(((Entity)target).getStealthModifier(usingRange));        }        return mods;    }