ArtilleryAttackAction aaa = (ArtilleryAttackAction) waa;
if (phase == IGame.Phase.PHASE_TARGETING) {
if (!handledAmmoAndReport) {
addHeat();
// Report the firing itself
r = new Report(3121);
r.indent();
r.newlines = 0;
r.subject = subjectId;
r.add(wtype.getName());
r.add(aaa.turnsTilHit);
vPhaseReport.addElement(r);
Report.addNewline(vPhaseReport);
handledAmmoAndReport = true;
game.getBoard().addSpecialHexDisplay(
aaa.getTarget(game).getPosition(),
new SpecialHexDisplay(
SpecialHexDisplay.Type.ARTILLERY_INCOMING,
game.getRoundCount() + aaa.turnsTilHit,
game.getPlayer(aaa.getPlayerId()).getName(),
"Artilery Incoming. Better text later."));
}
// if this is the last targeting phase before we hit,
// make it so the firing entity is announced in the
// off-board attack phase that follows.
if (aaa.turnsTilHit == 0) {
announcedEntityFiring = false;
}
return true;
}
if (aaa.turnsTilHit > 0) {
aaa.turnsTilHit--;
return true;
}
final Vector<Integer> spottersBefore = aaa.getSpotterIds();
final Targetable target = aaa.getTarget(game);
final Coords targetPos = target.getPosition();
final int playerId = aaa.getPlayerId();
boolean isFlak = target instanceof VTOL;
Entity bestSpotter = null;
Entity ae = game.getEntity(aaa.getEntityId());
if (ae == null) {
ae = game.getOutOfGameEntity(aaa.getEntityId());
}
//TODO: Fix null pointer exception
if(ae == null) {
System.err.println("Artillery Entity is null!");
return true;
}
Mounted ammo = ae.getEquipment(aaa.getAmmoId());
final AmmoType atype = ammo == null ? null : (AmmoType) ammo.getType();
// Are there any valid spotters?
if ((null != spottersBefore) && !isFlak) {
// fetch possible spotters now
Enumeration<Entity> spottersAfter = game
.getSelectedEntities(new EntitySelector() {
public int player = playerId;
public Targetable targ = target;
public boolean accept(Entity entity) {
Integer id = new Integer(entity.getId());
if ((player == entity.getOwnerId())
&& spottersBefore.contains(id)
&& !(LosEffects.calculateLos(game, entity
.getId(), targ)).isBlocked()
&& entity.isActive()
&& !entity.isINarcedWith(INarcPod.HAYWIRE)) {
return true;
}
return false;
}
});
// Out of any valid spotters, pick the best.
while (spottersAfter.hasMoreElements()) {
Entity ent = spottersAfter.nextElement();
if ((bestSpotter == null)
|| (ent.crew.getGunnery() < bestSpotter.crew
.getGunnery())) {
bestSpotter = ent;
}
}
} // End have-valid-spotters
// If at least one valid spotter, then get the benefits thereof.
if (null != bestSpotter) {
int mod = (bestSpotter.crew.getGunnery() - 4) / 2;
toHit.addModifier(mod, "Spotting modifier");
}
// Is the attacker still alive and we're not shooting FLAK?
// then adjust the target
Entity artyAttacker = aaa.getEntity(game);
if ((null != artyAttacker) && !isFlak) {
// Get the arty weapon.
Mounted weapon = artyAttacker.getEquipment(aaa.getWeaponId());
// If the shot hit the target hex, then all subsequent
// fire will hit the hex automatically.
if (roll >= toHit.getValue()) {
artyAttacker.aTracker.setModifier(weapon,
TargetRoll.AUTOMATIC_SUCCESS, targetPos);
game.getBoard().addSpecialHexDisplay(targetPos,
new SpecialHexDisplay(
SpecialHexDisplay.Type.ARTILLERY_AUTOHIT,
game.getRoundCount(),
game.getPlayer(aaa.getPlayerId()).getName(),
"Artilery AutoHit. Better text later.",
false
)
);
}
// If the shot missed, but was adjusted by a
// spotter, future shots are more likely to hit.
else if (null != bestSpotter) {
artyAttacker.aTracker.setModifier(weapon, artyAttacker.aTracker
.getModifier(weapon, targetPos) - 1, targetPos);
game.getBoard().addSpecialHexDisplay(targetPos,
new SpecialHexDisplay(
SpecialHexDisplay.Type.ARTILLERY_ADJUSTED,
game.getRoundCount(),
game.getPlayer(aaa.getPlayerId()).getName(),
"Artilery toHit Adjusted. Better text later.",
false
)
);
}
} // End artyAttacker-alive
// Report weapon attack and its to-hit value.
r = new Report(3120);
r.indent();
r.newlines = 0;
r.subject = subjectId;
if (wtype != null) {
r.add(wtype.getName());
} else {
r.add("Error: From Nowhwere");
}
r.add(target.getDisplayName(), true);
vPhaseReport.addElement(r);
if (toHit.getValue() == TargetRoll.IMPOSSIBLE) {
r = new Report(3135);
r.subject = subjectId;
r.add(toHit.getDesc());
vPhaseReport.addElement(r);
return false;
} else if (toHit.getValue() == TargetRoll.AUTOMATIC_FAIL) {
r = new Report(3140);
r.newlines = 0;
r.subject = subjectId;
r.add(toHit.getDesc());
vPhaseReport.addElement(r);
} else if (toHit.getValue() == TargetRoll.AUTOMATIC_SUCCESS) {
r = new Report(3145);
r.newlines = 0;
r.subject = subjectId;
r.add(toHit.getDesc());
vPhaseReport.addElement(r);
} else {
// roll to hit
r = new Report(3150);
r.newlines = 0;
r.subject = subjectId;
r.add(toHit.getValue());
vPhaseReport.addElement(r);
}
// dice have been rolled, thanks
r = new Report(3155);
r.newlines = 0;
r.subject = subjectId;
r.add(roll);
vPhaseReport.addElement(r);
if (!isFlak) {
game.getBoard().addSpecialHexDisplay(
targetPos,
new SpecialHexDisplay(SpecialHexDisplay.Type.ARTILLERY_TARGET,
game.getRoundCount(),
game.getPlayer(aaa.getPlayerId()).getName(),
"Artilery Target. Better text later.",
false
)
);
}
// do we hit?
bMissed = roll < toHit.getValue();
// Set Margin of Success/Failure.
toHit.setMoS(roll-Math.max(2,toHit.getValue()));
// Do this stuff first, because some weapon's miss report reference the
// amount of shots fired and stuff.
if (!handledAmmoAndReport) {
addHeat();
}
Coords coords = target.getPosition();
if (!bMissed) {
if (!isFlak) {
r = new Report(3190);
} else {
r = new Report(3191);
}
r.subject = subjectId;
r.add(coords.getBoardNum());
vPhaseReport.addElement(r);
game.getBoard().addSpecialHexDisplay(targetPos,
new SpecialHexDisplay(SpecialHexDisplay.Type.ARTILLERY_HIT,
game.getRoundCount(),
"Artilery Hit. Better text later."));
} else {
// direct fire artillery only scatters by one d6
// we do this here to avoid duplicating handle()
// in the ArtilleryWeaponDirectFireHandler
if (phase == IGame.Phase.PHASE_FIRING) {
coords = Compute.scatterDirectArty(coords);
} else {
coords = Compute.scatter(coords, Math.abs(toHit.getMoS()));
}
if (game.getBoard().contains(coords)) {
// misses and scatters to another hex
if (!isFlak) {
r = new Report(3195);
game.getBoard().addSpecialHexDisplay(
coords,
new SpecialHexDisplay(
SpecialHexDisplay.Type.ARTILLERY_HIT,
game.getRoundCount(),
"Artilery Scatered Here. Better text later."
)
);
} else {
r = new Report(3192);
}
r.subject = subjectId;
r.add(coords.getBoardNum());
vPhaseReport.addElement(r);
} else {
// misses and scatters off-board
if (isFlak) {
r = new Report(3193);
} else {
r = new Report(3200);
}
r.subject = subjectId;
vPhaseReport.addElement(r);
return !bMissed;
}
}
if (atype.getMunitionType() == AmmoType.M_FLARE) {
int radius;
if (atype.getAmmoType() == AmmoType.T_ARROW_IV) {
radius = 4;
} else if (atype.getAmmoType() == AmmoType.T_LONG_TOM) {
radius = 3;
} else if (atype.getAmmoType() == AmmoType.T_SNIPER) {
radius = 2;
} else {
radius = 1;
}
server.deliverArtilleryFlare(coords, radius);
return false;
}
if (atype.getMunitionType() == AmmoType.M_DAVY_CROCKETT_M) {
// The appropriate term here is "Bwahahahahaha..."
server.doNuclearExplosion(coords, 1, vPhaseReport);
return false;
}
if (atype.getMunitionType() == AmmoType.M_FASCAM) {
server.deliverFASCAMMinefield(coords, ae.getOwner().getId(), atype.getRackSize(), ae.getId());
return false;
}
if (atype.getMunitionType() == AmmoType.M_INFERNO_IV) {
server.deliverArtilleryInferno(coords, artyAttacker, subjectId, vPhaseReport);
return false;
}
if (atype.getMunitionType() == AmmoType.M_VIBRABOMB_IV) {
server.deliverThunderVibraMinefield(coords, ae.getOwner().getId(),
atype.getRackSize(), waa.getOtherAttackInfo(), ae.getId());
return false;
}
if (atype.getMunitionType() == AmmoType.M_SMOKE) {
server.deliverArtillerySmoke(coords, vPhaseReport);
return false;
}
int altitude = 0;
if (isFlak) {
altitude = ((VTOL) target).getElevation();
}
//check to see if this is a mine clearing attack
//According to the RAW you have to hit the right hex to hit even if the scatter hex has minefields
boolean mineClear = target.getTargetType() == Targetable.TYPE_MINEFIELD_CLEAR;
if (mineClear && game.containsMinefield(coords)
&& !isFlak && !bMissed) {
r = new Report(3255);
r.indent(1);
r.subject = subjectId;
vPhaseReport.addElement(r);
Enumeration<Minefield> minefields = game.getMinefields(coords).elements();