if (bSalvo) { phaseReport.append(hits + sSalvoType + "hit" + toHit.getTableDesc() + ".");  if (amsHits > 0) { phaseReport.append("\n\tAMS shoots down " + amsHits + " missile(s)."); }  }
    private void resolveWeaponAttack(WeaponAttackAction waa, int lastEntityId) {        final Entity ae = game.getEntity(waa.getEntityId());        final Entity te = game.getEntity(waa.getTargetId());        final Mounted weapon = ae.getEquipment(waa.getWeaponId());        final WeaponType wtype = (WeaponType)weapon.getType();                // 2002-09-16 Infantry weapons have unlimited ammo.        final boolean isWeaponInfantry = wtype.hasFlag(WeaponType.F_INFANTRY);        final boolean usesAmmo = wtype.getAmmoType() != AmmoType.T_NA && 	    !isWeaponInfantry;        Mounted ammo = null;        Infantry platoon = null;        if (usesAmmo) {            if (waa.getAmmoId() > -1) {                ammo = ae.getEquipment(waa.getAmmoId());                weapon.setLinked(ammo);            }            else {                ammo = weapon.getLinked();            }        }        final AmmoType atype = ammo == null ? null : (AmmoType)ammo.getType();                        if (lastEntityId != waa.getEntityId()) {            phaseReport.append("\nWeapons fire for " + ae.getDisplayName() + "\n");        }                phaseReport.append("    " + wtype.getName() + " at " + te.getDisplayName());                // has this weapon fired already?        if (weapon.isUsedThisRound()) {            phaseReport.append(" but the weapon has already fired this round!\n");            return;        }                // is the weapon functional?        if (weapon.isDestroyed()) {            phaseReport.append(" but the weapon has been destroyed in a previous round!\n");            return;        }                // try reloading        if (usesAmmo && (ammo == null || ammo.getShotsLeft() == 0 || ammo.isDumping())) {            ae.loadWeapon(weapon);            ammo = weapon.getLinked();        }        //        // should we even bother?//        if (te.isDestroyed() || te.isDoomed() || te.crew.isDead()) {//            phaseReport.append(" but the target is already destroyed!\n");//            return;//        }                // compute to-hit        ToHitData toHit = Compute.toHitWeapon(game, waa, attacks);        if (toHit.getValue() == ToHitData.IMPOSSIBLE) {            phaseReport.append(", but the shot is impossible (" + toHit.getDesc() + ")\n");            return;        } else if (toHit.getValue() == ToHitData.AUTOMATIC_FAIL) {            phaseReport.append(", the shot is an automatic miss (" + toHit.getDesc() + "), ");        } else {            phaseReport.append("; needs " + toHit.getValue() + ", ");        }                        // use up ammo (if weapon is out of ammo, we shouldn't be here)        if (usesAmmo) {            ammo.setShotsLeft(ammo.getShotsLeft() - 1);                /*                Fire Mode - Takes 2 shots of ammo away if we are firing uAC Double Rate.                If you don't have enough ammo for a Double Rate shot, you can't do it!                Rasia                 */            if (wtype.getAmmoType() == AmmoType.T_AC_ULTRA && ammo != null && weapon.curMode().equals("Ultra")) {                if (ammo.getShotsLeft() <= 0) {                    ae.loadWeapon(weapon);                    ammo = weapon.getLinked();                    if (ammo.getShotsLeft() <= 0) {                        weapon.switchMode();                        phaseReport.append("(Out of Ammo, Single Rate Only):");                    } else {                        ammo.setShotsLeft(ammo.getShotsLeft() - 1);                    }                                    } else {                    ammo.setShotsLeft(ammo.getShotsLeft() - 1);                }            }        }                // build up some heat        ae.heatBuildup += wtype.getHeat();        if (wtype.getAmmoType() == AmmoType.T_AC_ULTRA && weapon.curMode().equals("Ultra")) // Fire Mode - If we are shooting an Ultra AC twice            ae.heatBuildup += wtype.getHeat();                // set the weapon as having fired        weapon.setUsedThisRound(true);                // if firing an HGR unbraced, schedule a PSR        if (wtype.getAmmoType() == AmmoType.T_GAUSS_HEAVY && ae.mpUsed > 0) {            // the mod is weight-based            int nMod;            if (te.getWeight() <= Mech.WEIGHT_LIGHT) {                nMod = 2;            } else if (te.getWeight() <= Mech.WEIGHT_MEDIUM) {                nMod = 1;            } else if (te.getWeight() <= Mech.WEIGHT_HEAVY) {                nMod = 0;            } else {                nMod = -1;            }                        pilotRolls.addElement(new PilotingRollData(ae.getId(), nMod, "fired HeavyGauss unbraced"));        }                // roll        int roll = Compute.d6(2);        phaseReport.append("rolls " + roll + " : ");                // check for AC jams        int jamCheck = 0;        if (wtype.getAmmoType() == AmmoType.T_AC_ULTRA && weapon.curMode().equals("Ultra")) {            jamCheck = 2;        } else if (wtype.getAmmoType() == AmmoType.T_AC_ROTARY) {            if (weapon.curMode().equals("2-shot")) {                jamCheck = 2;            }            else if (weapon.curMode().equals("4-shot")) {                jamCheck = 3;            }            else if (weapon.curMode().equals("6-shot")) {                jamCheck = 4;            }        }                if (jamCheck > 0 && roll <= jamCheck) {            phaseReport.append("misses AND THE AUTOCANNON JAMS.\n");            weapon.setHit(true);            return;        }                // do we hit?        if (roll < toHit.getValue()) {            // miss            phaseReport.append("misses.\n");            if (wtype.getAmmoType() == AmmoType.T_SRM_STREAK) {                // this is sort of a hack...                ae.heatBuildup -= wtype.getHeat();                ammo.setShotsLeft(ammo.getShotsLeft() + 1);                phaseReport.append("    Streak fails to achieve lock on target.\n");            }            return;        }                // yeech.  handle damage. . different weapons do this in very different ways        int hits = 1, amsHits = 0, nCluster = 1;        boolean bSalvo = false;        String sSalvoType = " shot(s) ";                if (isWeaponInfantry) {            // Infantry damage depends on # men left in platoon.            bSalvo = true;            platoon = (Infantry)ae;            nCluster = 5;            hits = platoon.getDamage(platoon.getShootingStrength());        } else if (wtype.getDamage() == WeaponType.DAMAGE_MISSILE) {            sSalvoType = " missile(s) ";            bSalvo = true;                        if (wtype.getAmmoType() == AmmoType.T_LRM || wtype.getAmmoType() == AmmoType.T_MRM) {                nCluster = 5;            }                                    if (wtype.getAmmoType() == AmmoType.T_SRM_STREAK) {                hits = wtype.getRackSize();            } else if (wtype.getRackSize() == 30 || wtype.getRackSize() == 40) {                // I'm going to assume these are MRMs                hits = Compute.missilesHit(wtype.getRackSize() / 2) + Compute.missilesHit(wtype.getRackSize() / 2);            } else {                hits = Compute.missilesHit(wtype.getRackSize());            }                        // adjust for AMS            Vector vCounters = waa.getCounterEquipment();            if (vCounters != null) {                for (int x = 0; x < vCounters.size(); x++) {                    Mounted counter = (Mounted)vCounters.elementAt(x);                    if (counter.getType() instanceof WeaponType &&                             ((WeaponType)counter.getType()).getAmmoType() == AmmoType.T_AMS) {                        if (!counter.isReady() || counter.isMissing()) {                            continue;                        }                        amsHits = Compute.d6(((WeaponType)counter.getType()).getDamage());                                                if (amsHits > hits) amsHits = hits;                                                // build up some heat                        ae.heatBuildup += ((WeaponType)counter.getType()).getHeat();                            // decrement the ammo                        Mounted mAmmo = counter.getLinked();                        mAmmo.setShotsLeft(Math.max(0, mAmmo.getShotsLeft() - amsHits));                                                // set the ams as having fired                        weapon.setUsedThisRound(true);                    }                }            }                    } else if (atype != null && atype.hasFlag(AmmoType.F_CLUSTER)) {            bSalvo = true;            hits = Compute.missilesHit(wtype.getRackSize());        } else if (wtype.getAmmoType() == AmmoType.T_AC_ULTRA && weapon.curMode().equals("Ultra")) {            bSalvo = true;            hits = Compute.missilesHit(2);        } else if (wtype.getAmmoType() == AmmoType.T_AC_ROTARY && !weapon.curMode().equals("Single")) {            bSalvo = true;            if (weapon.curMode().equals("2-shot")) {                hits = Compute.missilesHit(2);            } else if (weapon.curMode().equals("4-shot")) {                hits = Compute.missilesHit(4);            } else if (weapon.curMode().equals("6-shot")) {                hits = Compute.missilesHit(6);            }        } else if (atype != null && atype.hasFlag(AmmoType.F_MG) && !isWeaponInfantry && (te instanceof Infantry)) {            // Mech and Vehicle MGs do *DICE* of damage to PBI.            bSalvo = true;            hits = Compute.d6(wtype.getDamage());        }                if (bSalvo) {            phaseReport.append(hits + sSalvoType + " hit" + toHit.getTableDesc() + ".");                        if (amsHits > 0) {                phaseReport.append("\n\tAMS shoots down " + amsHits + " missile(s).");            }            phaseReport.append("\n\t");                    }                int nDamPerHit = wtype.getDamage();        if (nDamPerHit == wtype.DAMAGE_MISSILE) {            nDamPerHit = atype.getDamagePerShot();        } else if (isWeaponInfantry) {            nDamPerHit = 1;        } else if (wtype.getAmmoType() == AmmoType.T_GAUSS_HEAVY) {            // HGR does range-dependent damage            int nRange = ae.getPosition().distance(te.getPosition());            if (nRange <= wtype.getShortRange()) {                nDamPerHit = 25;            } else if (nRange <= wtype.getMediumRange()) {                nDamPerHit = 20;            } else {                nDamPerHit = 10;            }        }                    // for each cluster of hits, do a chunk of damage        while (hits > 0) {            int nDamage = nDamPerHit * Math.min(nCluster, hits);                        if (wtype.hasFlag(WeaponType.F_FLAMER) && game.getOptions().booleanOption("flamer_heat")) {               phaseReport.append("\n\tTarget gains ").append(nDamage).append(" more heat during heat phase.\n");               te.heatBuildup += hits;               continue;            }            HitData hit = te.rollHitLocation(toHit.getHitTable(), toHit.getSideTable());            if (!bSalvo) {                phaseReport.append("hits" + toHit.getTableDesc() + " " + te.getLocationAbbr(hit));            }            phaseReport.append(damageEntity(te, hit, nDamage));                        hits -= nCluster;        }        phaseReport.append("\n");    }