From 3722bafaf7e06d66d7506decb3c9f8decead60d8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 29 Mar 2009 15:03:44 +0200 Subject: [PATCH] Fix confusion of landmines with seamines 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. --- include/sect.h | 7 +++++++ src/lib/commands/mine.c | 4 ++-- src/lib/commands/stre.c | 6 +++--- src/lib/subs/attsub.c | 3 ++- src/lib/subs/bridgefall.c | 2 ++ src/lib/subs/lndsub.c | 10 ++++------ src/lib/subs/move.c | 2 +- src/lib/subs/plnsub.c | 2 +- src/lib/subs/retreat.c | 2 +- 9 files changed, 23 insertions(+), 15 deletions(-) diff --git a/include/sect.h b/include/sect.h index 6e64ce39..f5d6722e 100644 --- a/include/sect.h +++ b/include/sect.h @@ -187,6 +187,13 @@ extern struct dchrstr dchr[SCT_TYPE_MAX + 2]; (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 diff --git a/src/lib/commands/mine.c b/src/lib/commands/mine.c index 06933379..99dc5753 100644 --- a/src/lib/commands/mine.c +++ b/src/lib/commands/mine.c @@ -68,7 +68,7 @@ mine(void) 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; } @@ -117,7 +117,7 @@ landmine(void) 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; diff --git a/src/lib/commands/stre.c b/src/lib/commands/stre.c index f6552522..1215c31f 100644 --- a/src/lib/commands/stre.c +++ b/src/lib/commands/stre.c @@ -88,11 +88,11 @@ stre(void) 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", "?"); } diff --git a/src/lib/subs/attsub.c b/src/lib/subs/attsub.c index 95349c51..a5abbbe6 100644 --- a/src/lib/subs/attsub.c +++ b/src/lib/subs/attsub.c @@ -1656,7 +1656,8 @@ get_mine_dsupport(struct combat *def, int a_engineer) 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) { diff --git a/src/lib/subs/bridgefall.c b/src/lib/subs/bridgefall.c index 40086a18..fe408880 100644 --- a/src/lib/subs/bridgefall.c +++ b/src/lib/subs/bridgefall.c @@ -132,6 +132,8 @@ knockdown(struct sctstr *sp) "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; diff --git a/src/lib/subs/lndsub.c b/src/lib/subs/lndsub.c index bfda69e5..03b8de0d 100644 --- a/src/lib/subs/lndsub.c +++ b/src/lib/subs/lndsub.c @@ -553,10 +553,10 @@ lnd_sweep(struct emp_qelem *land_list, int verbose, int takemob, 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) { @@ -620,9 +620,7 @@ lnd_check_mines(struct emp_qelem *land_list) 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)); diff --git a/src/lib/subs/move.c b/src/lib/subs/move.c index 34fe0c92..91a8931f 100644 --- a/src/lib/subs/move.c +++ b/src/lib/subs/move.c @@ -318,7 +318,7 @@ check_lmines(coord x, coord y, double weight) 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(); diff --git a/src/lib/subs/plnsub.c b/src/lib/subs/plnsub.c index b13a7e0e..9bae8323 100644 --- a/src/lib/subs/plnsub.c +++ b/src/lib/subs/plnsub.c @@ -904,7 +904,7 @@ plane_sweep(struct emp_qelem *plane_list, coord x, coord y) 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)); diff --git a/src/lib/subs/retreat.c b/src/lib/subs/retreat.c index 64acb854..79283024 100644 --- a/src/lib/subs/retreat.c +++ b/src/lib/subs/retreat.c @@ -475,7 +475,7 @@ retreat_land1(struct lndstr *lp, char code, int orig) 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];