}
// First, crater the terrain.
// All terrain, units, buildings... EVERYTHING in here is just gone.
// Gotta love nukes.
Report r = new Report(1215, Report.PUBLIC);
r.indent();
r.add(position.getBoardNum(), true);
vDesc.add(r);
int curDepth = game.getBoard().getHex(position).floor() - craterDepth;
int range = 0;
while (range < 2 * craterDepth) {
// Get the set of hexes at this range.
Enumeration<Coords> hexSet = game.getBoard().getHexesAtDistance(position, range);
// Iterate through the hexes.
while (hexSet.hasMoreElements()) {
Coords myHexCoords = hexSet.nextElement();
IHex myHex = game.getBoard().getHex(myHexCoords);
// In each hex, first, sink the terrain if necessary.
myHex.setElevation(myHex.getElevation() - craterDepth + (range / 2));
// Then, remove ANY terrains here.
// I mean ALL of them; they're all just gone.
// No ruins, no water, no rough, no nothing.
if (myHex.containsTerrain(Terrains.WATER)) {
myHex.setElevation(myHex.floor());
}
myHex.removeAllTerrains();
myHex.clearExits();
sendChangedHex(myHexCoords);
}
// Now that the hexes are dealt with, increment the distance.
range++;
// Lastly, if the next distance is a multiple of 2...
// The crater depth goes down one.
if ((range > 0) && (range % 2 == 0)) {
curDepth++;
}
}
// This is technically part of cratering, but...
// Now we destroy all the units inside the cratering range.
Enumeration<Entity> entitiesInCrater = game.getEntities();
while (entitiesInCrater.hasMoreElements()) {
Entity entity = entitiesInCrater.nextElement();
// loaded units and off board units don't have a position,
// so we don't count 'em here
if ((entity.getTransportId() != Entity.NONE) || (entity.getPosition() == null)) {
continue;
}
// If it's too far away for this...
if (position.distance(entity.getPosition()) >= range) {
continue;
}
// If it's already destroyed...
if (entity.isDestroyed()) {
continue;
}
vDesc.addAll(destroyEntity(entity, "nuclear explosion proximity", false, false));
// Kill the crew
entity.getCrew().setDoomed(true);
}
entitiesInCrater = null;
// Then, do actual blast damage.
// Use the standard blast function for this.
Vector<Report> tmpV = new Vector<Report>();
Vector<Integer> blastedUnitsVec = new Vector<Integer>();
doExplosion(baseDamage, degredation, true, position, true, tmpV, blastedUnitsVec);
Report.indentAll(tmpV, 2);
vDesc.addAll(tmpV);
// Everything that was blasted by the explosion has to make a piloting
// check at +6.
for (Object i : blastedUnitsVec) {
Entity o = game.getEntity((Integer) i);
if (o instanceof Mech) {
Mech bm = (Mech) o;
// Needs a piloting check at +6 to avoid falling over.
// Obviously not if it's already prone, though.
if (!bm.isProne()) {
game.addPSR(new PilotingRollData(bm.getId(), 6, "hit by nuclear blast"));
}
} else if (o instanceof VTOL) {
// Needs a piloting check at +6 to avoid crashing.
// Wheeeeee!
VTOL vt = (VTOL) o;
// Check only applies if it's in the air.
// FIXME: is this actually correct? What about
// buildings/bridges?
if (vt.getElevation() > 0) {
game.addPSR(new PilotingRollData(vt.getId(), 6, "hit by nuclear blast"));
}
} else if (o instanceof Tank) {
// As per official answer on the rules questions board...
// Needs a piloting check at +6 to avoid a 1-level fall...
// But ONLY if a hover-tank.
// FIXME
}
}
// Just get rid of it for the balance of the function...
tmpV = null;
// This ISN'T part of the blast, but if there's ANYTHING in the ground
// zero hex, destroy it.
Building tmpB = game.getBoard().getBuildingAt(position);
if (tmpB != null) {
r = new Report(2415);
r.add(tmpB.getName());
addReport(r);
tmpB.setCurrentCF(0, position);
}
IHex gzHex = game.getBoard().getHex(position);
if (gzHex.containsTerrain(Terrains.WATER)) {
gzHex.setElevation(gzHex.floor());
}
gzHex.removeAllTerrains();
// Next, for whatever's left, do terrain effects
// such as clearing, roughing, and boiling off water.
boolean damageFlag = true;
int damageAtRange = baseDamage - (degredation * range);
if (damageAtRange > 0) {
for (int x = range; damageFlag; x++) {
// Damage terrain as necessary.
// Get all the hexes, and then iterate through them.
Enumeration<Coords> hexSet = game.getBoard().getHexesAtDistance(position, x);
// Iterate through the hexes.
while (hexSet.hasMoreElements()) {
Coords myHexCoords = hexSet.nextElement();
IHex myHex = game.getBoard().getHex(myHexCoords);
// For each 3000 damage, water level is reduced by 1.
if ((damageAtRange >= 3000) && (myHex.containsTerrain(Terrains.WATER))) {
int numCleared = damageAtRange / 3000;
int oldLevel = myHex.terrainLevel(Terrains.WATER);
myHex.removeTerrain(Terrains.WATER);
if (oldLevel > numCleared) {
myHex.addTerrain(new Terrain(Terrains.WATER, oldLevel - numCleared));
}
}
// ANY non-water hex that takes 200 becomes rough.
if ((damageAtRange >= 200) && (!myHex.containsTerrain(Terrains.WATER))) {
myHex.removeAllTerrains();
myHex.clearExits();
myHex.addTerrain(new Terrain(Terrains.ROUGH, 1));
} else if ((damageAtRange >= 20) && ((myHex.containsTerrain(Terrains.WOODS)) || (myHex.containsTerrain(Terrains.JUNGLE)))) {
// Each 20 clears woods by 1 level.
int numCleared = damageAtRange / 20;
int terrainType = (myHex.containsTerrain(Terrains.WOODS) ? Terrains.WOODS : Terrains.JUNGLE);
int oldLevel = myHex.terrainLevel(terrainType);
myHex.removeTerrain(terrainType);
if (oldLevel > numCleared) {
myHex.addTerrain(new Terrain(terrainType, oldLevel - numCleared));
}
}
sendChangedHex(myHexCoords);
}
// Initialize for the next iteration.
damageAtRange = baseDamage - (degredation * x + 1);
// If the damage is less than 20, it has no terrain effect.
if (damageAtRange < 20) {
damageFlag = false;
}
}
}
// Lastly, do secondary effects.
Enumeration<Entity> entitiesInSecondaryRange = game.getEntities();
while (entitiesInSecondaryRange.hasMoreElements()) {
Entity entity = entitiesInSecondaryRange.nextElement();
// loaded units and off board units don't have a position,
// so we don't count 'em here
if ((entity.getTransportId() != Entity.NONE) || (entity.getPosition() == null)) {
continue;
}
// If it's already destroyed...
if ((entity.isDoomed()) || (entity.isDestroyed())) {
continue;
}
// If it's too far away for this...
if (position.distance(entity.getPosition()) > secondaryRadius) {
continue;
}
// Actually do secondary effects against it.
// Since the effects are unit-dependant, we'll just define it in the
// entity.
applySecondaryNuclearEffects(entity, position, vDesc);
}
// All right. We're done.
r = new Report(1216, Report.PUBLIC);
r.indent();
r.newlines = 2;
vDesc.add(r);
}