Seamines and landmines share storage. Sea and bridge span sectors can
hold only sea mines, other sector types only landmines. Sector type
checks were missing or incorrect in several places:
* Seamines under bridge spans were mistaken for landmines in several
places:
- ground combat mine defense bonus, in get_mine_dsupport() and
stre(),
- land units retreating from bombs, in retreat_land1(),
- non-land unit ground movement (commands explore, move, transport,
and INTERDICT_ATT of military), in check_lmines(),
Fix them to check the sector type with new SCT_MINES_ARE_SEAMINES(),
SCT_LANDMINES().
* plane_sweep() mistook landmines for seamines in harbors. Bug could
not bite, because it's only called for sea sectors. Drop the bogus
check for harbor.
* Collapsing a bridge tower magically converted landmines into
seamines. Make knockdown() clear landmines.
Also use SCT_MINES_ARE_SEAMINES() and SCT_LANDMINES() in mine(),
landmine(), lnd_sweep() and lnd_check_mines(). No functional change
there.
Keep checking only for sea in pln_mine(), plane_sweep(),
retreat_ship1(), shp_sweep() and shp_check_one_mines(). This means
seamines continue not to work under bridges. Making them work there
is tempting, but as long as finding seamines clobbers the sector
designation in the bmap, it's better to have them in sea sectors only.
Historical notes:
Mines started out simple enough: you could mine sea and bridge spans,
and ships hit and swept mines in foreign sectors.
Chainsaw 2 introduced aerial mining and sweeping. Unlike ships,
planes could not mine bridge spans. plane_sweep() could sweep
harbors, which was wrong, but it was never called there, so the bug
could not bite.
Chainsaw 3 introduced landmines. The idea was to permit only seamines
in some sector types, and only landmines in the others, so they can
share storage. To figure out whether a sector has a particular kind
of mines, you need to check the sector type. Such checks already
existed in mine, drop and sweep, and they were kept unchanged. The
new lmine command also got the check. Everything else did not.
Ground movement and combat could hit and sweep seamines in bridge
spans. Ships could hit and sweep landmines in harbors.
Empire 2 fixed land unit movement (march, INTERDICT_ATT) not to
mistake seamines for landmines on bridge spans. It fixed ships not to
mistake landmines for seamines. The fix also neutered seamines under
bridge spans: ships could neither hit nor sweep them anymore. Both
fixes missed retreat.
Commit
5663713b (v4.3.1) made ship retreat consistent with other ship
movement.
(opt_RAILWAYS ? sct_rail_track((sp)) != 0 \
: intrchr[INT_RAIL].in_enable && (sp)->sct_rail != 0)
+#define SCT_MINES_ARE_SEAMINES(sp) \
+ ((sp)->sct_type == SCT_WATER || (sp)->sct_type == SCT_BSPAN)
+#define SCT_SEAMINES(sp) \
+ (SCT_MINES_ARE_SEAMINES((sp)) ? (sp)->sct_mines : 0)
+#define SCT_LANDMINES(sp) \
+ (SCT_MINES_ARE_SEAMINES((sp)) ? 0 : (sp)->sct_mines)
+
#define MOB_MOVE 0
#define MOB_MARCH 1
#define MOB_RAIL 2
continue;
mines_avail = MIN(shells, mines);
if (getsect(ship.shp_x, ship.shp_y, §) == 0 ||
- (sect.sct_type != SCT_WATER && sect.sct_type != SCT_BSPAN)) {
+ !SCT_MINES_ARE_SEAMINES(§)) {
pr("You can't lay mines there!!\n");
continue;
}
continue;
}
if (!getsect(land.lnd_x, land.lnd_y, §)
- || sect.sct_type == SCT_WATER || sect.sct_type == SCT_BSPAN
+ || SCT_MINES_ARE_SEAMINES(§)
|| sect.sct_own != land.lnd_own) {
pr("You can't lay mines there!!\n");
continue;
def->own = 0;
eff = att_combat_eff(def);
if (sect.sct_own == sect.sct_oldown || player->god) {
- if (sect.sct_mines > 0)
+ if (SCT_LANDMINES(§) > 0) {
pr("%7d", sect.sct_mines);
- else
+ eff *= (1.0 + MIN(sect.sct_mines, 20) * 0.02);
+ } else
pr("%7s", "");
- eff *= (1.0 + MIN(sect.sct_mines, 20) * 0.02);
} else {
pr("%7s", "?");
}
getsect(def->x, def->y, §);
if (sect.sct_oldown != player->cnum) {
- mines = MIN(sect.sct_mines, 20);
+ mines = SCT_LANDMINES(§);
+ mines = MIN(mines, 20);
if (a_engineer)
mines = ldround(mines / 2.0, 1);
if (mines > 0) {
"Crumble... SCREEEECH! Splash! Bridge%s falls at %s!\n",
sp->sct_type == SCT_BTOWER ? " tower" : "",
xyas(sp->sct_x, sp->sct_y, sp->sct_own));
+ if (!SCT_MINES_ARE_SEAMINES(sp))
+ sp->sct_mines = 0;
sp->sct_type = SCT_WATER;
sp->sct_newtype = SCT_WATER;
sp->sct_own = 0;
prland(&llp->unit.land));
continue;
}
- if (sect.sct_type == SCT_BSPAN) {
+ if (SCT_MINES_ARE_SEAMINES(§)) {
if (verbose)
- mpr(actor, "%s is on a bridge. No mines there!\n",
- prland(&llp->unit.land));
+ mpr(actor, "%s is in a %s sector. No landmines there!\n",
+ prland(&llp->unit.land), dchr[sect.sct_type].d_name);
continue;
}
if (takemob) {
getsect(llp->unit.land.lnd_x, llp->unit.land.lnd_y, §);
if (sect.sct_oldown == llp->unit.land.lnd_own)
continue;
- if (sect.sct_type == SCT_BSPAN)
- continue;
- if (!sect.sct_mines)
+ if (SCT_LANDMINES(§) == 0)
continue;
if (chance(DMINE_LHITCHANCE(sect.sct_mines) / (1 + 2 * with_eng))) {
lnd_hit_mine(&llp->unit.land, ((struct lchrstr *)llp->chrp));
int dam = 0;
getsect(x, y, §);
- if (sect.sct_mines > 0 &&
+ if (SCT_LANDMINES(§) > 0 &&
sect.sct_oldown != player->cnum &&
chance(DMINE_LHITCHANCE(sect.sct_mines)) && chance(weight / 100.0)) {
pr_beep();
if (mines_there == 0)
return;
- if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR))
+ if (sect.sct_type != SCT_WATER)
return;
for (qp = plane_list->q_forw; ((qp != plane_list) && (mines_there));
if (stopping)
continue;
- mines = sect.sct_mines;
+ mines = SCT_LANDMINES(§);
if ((lcp->l_flags & L_ENGINEER) && mines > 0 &&
(sect.sct_oldown != lp->lnd_own)) {
max = lcp->l_item[I_SHELL];