Vector<Report> vDesc = new Vector<Report>();
Report r;
// Handle hits on "critical slots" of tanks.
if (en instanceof Tank) {
Tank t = (Tank) en;
HitData hit;
switch (cs.getIndex()) {
case Tank.CRIT_NONE:
// no effect
r = new Report(6005);
r.subject = t.getId();
vDesc.add(r);
break;
case Tank.CRIT_AMMO:
// ammo explosion
r = new Report(6610);
r.subject = t.getId();
vDesc.add(r);
int damage = 0;
for (Mounted m : t.getAmmo()) {
m.setHit(true);
int tmp = m.getShotsLeft() * ((AmmoType) m.getType()).getDamagePerShot() * ((AmmoType) m.getType()).getRackSize();
m.setShotsLeft(0);
// non-explosive ammo can't explode
if (!m.getType().isExplosive()) {
continue;
}
damage += tmp;
r = new Report(6390);
r.subject = t.getId();
r.add(m.getName());
r.add(tmp);
r.newlines = 0;
vDesc.add(r);
}
hit = new HitData(loc);
vDesc.addAll(damageEntity(t, hit, damage, true));
break;
case Tank.CRIT_CARGO:
// Cargo/infantry damage
r = new Report(6615);
r.subject = t.getId();
vDesc.add(r);
Vector<Entity> passengers = t.getLoadedUnits();
Entity target = passengers.get(Compute.randomInt(passengers.size()));
hit = target.rollHitLocation(ToHitData.HIT_NORMAL, ToHitData.SIDE_FRONT);
// FIXME should be original weapon damage
vDesc.addAll(damageEntity(target, hit, 5));
break;
case Tank.CRIT_COMMANDER:
if (en.crew.getOptions().booleanOption("vdni") || en.crew.getOptions().booleanOption("bvdni")) {
r = new Report(6191);
r.subject = t.getId();
vDesc.add(r);
vDesc.addAll(damageCrew(en, 1));
} else {
if (en.crew.getOptions().booleanOption("pain_shunt") && !t.isCommanderHitPS()) {
r = new Report(6606);
r.subject = t.getId();
vDesc.add(r);
t.setCommanderHitPS(true);
} else {
r = new Report(6605);
r.subject = t.getId();
vDesc.add(r);
t.setCommanderHit(true);
}
}
// fall through here, because effects of crew stunned also apply
case Tank.CRIT_CREW_STUNNED:
if (en.crew.getOptions().booleanOption("vdni") || en.crew.getOptions().booleanOption("bvdni")) {
r = new Report(6191);
r.subject = t.getId();
vDesc.add(r);
vDesc.addAll(damageCrew(en, 1));
} else {
if (en.crew.getOptions().booleanOption("pain_shunt")
|| en.crew.getOptions().booleanOption("dermal_armor")) {
r = new Report(6186);
r.subject = t.getId();
vDesc.add(r);
} else {
t.stunCrew();
r = new Report(6185);
r.add(t.getStunnedTurns() - 1);
r.subject = t.getId();
vDesc.add(r);
}
}
break;
case Tank.CRIT_DRIVER:
if (en.crew.getOptions().booleanOption("vdni") || en.crew.getOptions().booleanOption("bvdni")) {
r = new Report(6191);
r.subject = t.getId();
vDesc.add(r);
vDesc.addAll(damageCrew(en, 1));
} else {
if (en.crew.getOptions().booleanOption("pain_shunt") && !t.isDriverHitPS()) {
r = new Report(6601);
r.subject = t.getId();
vDesc.add(r);
t.setDriverHitPS(true);
} else {
r = new Report(6600);
r.subject = t.getId();
vDesc.add(r);
t.setDriverHit(true);
}
}
break;
case Tank.CRIT_CREW_KILLED:
if (en.crew.getOptions().booleanOption("vdni") || en.crew.getOptions().booleanOption("bvdni")) {
r = new Report(6191);
r.subject = t.getId();
vDesc.add(r);
vDesc.addAll(damageCrew(en, 1));
} else {
if (en.crew.getOptions().booleanOption("pain_shunt") && !t.isCrewHitPS()) {
r = new Report(6191);
r.subject = t.getId();
vDesc.add(r);
t.setCrewHitPS(true);
} else {
r = new Report(6190);
r.subject = t.getId();
vDesc.add(r);
t.getCrew().setDoomed(true);
}
}
break;
case Tank.CRIT_ENGINE:
r = new Report(6210);
r.subject = t.getId();
vDesc.add(r);
t.engineHit();
t.engineHitsThisRound++;
boolean engineExploded = checkEngineExplosion(t, vDesc, 1);
if (engineExploded) {
vDesc.addAll(destroyEntity(en, "engine destruction", true, true));
}
if (t instanceof VTOL) {
PilotingRollData psr = t.getBasePilotingRoll();
IHex hex = game.getBoard().getHex(t.getPosition());
psr.addModifier(4, "forced landing");
int elevation = Math.max(hex.terrainLevel(Terrains.BLDG_ELEV), hex.terrainLevel(Terrains.BRIDGE_ELEV));
elevation = Math.max(elevation, 0);
elevation = Math.min(elevation, t.getElevation());
if (t.getElevation() > elevation) {
if (!hex.containsTerrain(Terrains.FUEL_TANK) && !hex.containsTerrain(Terrains.JUNGLE) && !hex.containsTerrain(Terrains.MAGMA) && !hex.containsTerrain(Terrains.MUD) && !hex.containsTerrain(Terrains.RUBBLE) && !hex.containsTerrain(Terrains.WATER) && !hex.containsTerrain(Terrains.WOODS)) {
r = new Report(2180);
r.subject = t.getId();
r.addDesc(t);
r.add(psr.getLastPlainDesc(), true);
vDesc.add(r);
// roll
final int diceRoll = Compute.d6(2);
r = new Report(2185);
r.subject = t.getId();
r.add(psr.getValueAsString());
r.add(psr.getDesc());
r.add(diceRoll);
if (diceRoll < psr.getValue()) {
r.choose(false);
vDesc.add(r);
vDesc.addAll(crashVTOLorWiGE(t));
} else {
r.choose(true);
vDesc.add(r);
t.setElevation(elevation);
}
} else {
vDesc.addAll(crashVTOLorWiGE(t));
}
}
}
break;
case Tank.CRIT_FUEL_TANK:
r = new Report(6215);
r.subject = t.getId();
vDesc.add(r);
vDesc.addAll(destroyEntity(t, "fuel explosion", false, false));
break;
case Tank.CRIT_SENSOR:
r = new Report(6620);
r.subject = t.getId();
vDesc.add(r);
t.setSensorHits(t.getSensorHits() + 1);
break;
case Tank.CRIT_STABILIZER:
r = new Report(6625);
r.subject = t.getId();
vDesc.add(r);
t.setStabiliserHit(loc);
break;
case Tank.CRIT_TURRET_DESTROYED:
r = new Report(6630);
r.subject = t.getId();
vDesc.add(r);
t.destroyLocation(Tank.LOC_TURRET);
vDesc.addAll(destroyEntity(t, "turret blown off", true, true));
break;
case Tank.CRIT_TURRET_JAM:
if (t.isTurretEverJammed()) {
r = new Report(6640);
r.subject = t.getId();
vDesc.add(r);
t.lockTurret();
break;
}
r = new Report(6635);
r.subject = t.getId();
vDesc.add(r);
t.jamTurret();
break;
case Tank.CRIT_TURRET_LOCK:
r = new Report(6640);
r.subject = t.getId();
vDesc.add(r);
t.lockTurret();
break;
case Tank.CRIT_WEAPON_DESTROYED: {
r = new Report(6305);
r.subject = t.getId();
ArrayList<Mounted> weapons = new ArrayList<Mounted>();
for (Mounted weap : t.getWeaponList()) {
if ((weap.getLocation() == loc) && !weap.isHit() && !weap.isDestroyed()) {
weapons.add(weap);
}
}
// sort weapons by BV
Collections.sort(weapons, new WeaponComparator());
int roll = Compute.d6();
Mounted weapon;
if (roll < 4) {
// defender should choose, we'll just use the lowest BV
// weapon
weapon = weapons.get(weapons.size() - 1);
} else {
// attacker chooses, we'll use the highest BV weapon
weapon = weapons.get(0);
}
weapon.setHit(true);
r.add(weapon.getName());
vDesc.add(r);
// explosive weapons e.g. gauss now explode
vDesc.addAll(explodeEquipment(t, loc, weapon));
weapon.setDestroyed(true);
break;
}
case Tank.CRIT_WEAPON_JAM: {
r = new Report(6645);
r.subject = t.getId();
ArrayList<Mounted> weapons = new ArrayList<Mounted>();
for (Mounted weap : t.getWeaponList()) {
if ((weap.getLocation() == loc) && !weap.isJammed() && !weap.isHit() && !weap.isDestroyed()) {
weapons.add(weap);
}
}
Mounted weapon = weapons.get(Compute.randomInt(weapons.size()));
weapon.setJammed(true);
t.addJammedWeapon(weapon);
r.add(weapon.getName());
vDesc.add(r);
break;
}
case VTOL.CRIT_PILOT:
r = new Report(6650);
r.subject = t.getId();
vDesc.add(r);
t.setDriverHit(true);
PilotingRollData psr = t.getBasePilotingRoll();
psr.addModifier(0, "pilot injury");
if (!doSkillCheckInPlace(t, psr)) {
r = new Report(6675);
r.subject = t.getId();
r.addDesc(t);
vDesc.add(r);
boolean crash = true;
if (t.canGoDown()) {
t.setElevation(t.getElevation() - 1);
crash = !t.canGoDown();
}
if (crash) {
vDesc.addAll(crashVTOLorWiGE(t));
}
}
break;
case VTOL.CRIT_COPILOT:
r = new Report(6655);
r.subject = t.getId();
vDesc.add(r);
t.setCommanderHit(true);
break;
case VTOL.CRIT_ROTOR_DAMAGE: {
r = new Report(6660);
r.subject = t.getId();
vDesc.add(r);
int mp = t.getOriginalWalkMP();
if (mp > 1) {
t.setOriginalWalkMP(mp - 1);
} else if (mp == 1) {
t.setOriginalWalkMP(0);
vDesc.addAll(crashVTOLorWiGE(t));
}
break;
}
case VTOL.CRIT_ROTOR_DESTROYED:
r = new Report(6670);
r.subject = t.getId();
vDesc.add(r);
t.immobilize();
t.destroyLocation(VTOL.LOC_ROTOR);
vDesc.addAll(crashVTOLorWiGE(t));
break;
case VTOL.CRIT_FLIGHT_STABILIZER:
r = new Report(6665);
r.subject = t.getId();
vDesc.add(r);
t.setStabiliserHit(VTOL.LOC_ROTOR);
break;
}
} else if (en instanceof Aero) {
Aero a = (Aero) en;