]> git.pond.sub.org Git - empserver/commitdiff
Fix confusion of landmines with seamines
authorMarkus Armbruster <armbru@pond.sub.org>
Sun, 29 Mar 2009 13:03:44 +0000 (15:03 +0200)
committerMarkus Armbruster <armbru@pond.sub.org>
Tue, 31 Mar 2009 20:52:03 +0000 (22:52 +0200)
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
src/lib/commands/mine.c
src/lib/commands/stre.c
src/lib/subs/attsub.c
src/lib/subs/bridgefall.c
src/lib/subs/lndsub.c
src/lib/subs/move.c
src/lib/subs/plnsub.c
src/lib/subs/retreat.c

index 6e64ce39ac063b0b5839b0d9c845cd4e7400a50d..f5d6722e0630ba9036158f0e5746d1799209ce58 100644 (file)
@@ -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)
 
     (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
 #define MOB_MOVE    0
 #define MOB_MARCH   1
 #define MOB_RAIL    2
index 069333794f905c7603d0f3bdc6f88e03b0186677..99dc5753408a6d9766d9a8e2d630b07ae50604a5 100644 (file)
@@ -68,7 +68,7 @@ mine(void)
            continue;
        mines_avail = MIN(shells, mines);
        if (getsect(ship.shp_x, ship.shp_y, &sect) == 0 ||
            continue;
        mines_avail = MIN(shells, mines);
        if (getsect(ship.shp_x, ship.shp_y, &sect) == 0 ||
-           (sect.sct_type != SCT_WATER && sect.sct_type != SCT_BSPAN)) {
+           !SCT_MINES_ARE_SEAMINES(&sect)) {
            pr("You can't lay mines there!!\n");
            continue;
        }
            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)
            continue;
        }
        if (!getsect(land.lnd_x, land.lnd_y, &sect)
-           || sect.sct_type == SCT_WATER || sect.sct_type == SCT_BSPAN
+           || SCT_MINES_ARE_SEAMINES(&sect)
            || sect.sct_own != land.lnd_own) {
            pr("You can't lay mines there!!\n");
            continue;
            || sect.sct_own != land.lnd_own) {
            pr("You can't lay mines there!!\n");
            continue;
index f65525221529d28de1232fc2103c85e550fb95d2..1215c31f8521ac4bf1745bba60e8818903690822 100644 (file)
@@ -88,11 +88,11 @@ stre(void)
        def->own = 0;
        eff = att_combat_eff(def);
        if (sect.sct_own == sect.sct_oldown || player->god) {
        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(&sect) > 0) {
                pr("%7d", sect.sct_mines);
                pr("%7d", sect.sct_mines);
-           else
+               eff *= (1.0 + MIN(sect.sct_mines, 20) * 0.02);
+           } else
                pr("%7s", "");
                pr("%7s", "");
-           eff *= (1.0 + MIN(sect.sct_mines, 20) * 0.02);
        } else {
            pr("%7s", "?");
        }
        } else {
            pr("%7s", "?");
        }
index 95349c517774d9074b178cdbc2f376ab9fcc3318..a5abbbe65d652c3fc0ae0352d6b2f9cad2d67617 100644 (file)
@@ -1656,7 +1656,8 @@ get_mine_dsupport(struct combat *def, int a_engineer)
     getsect(def->x, def->y, &sect);
 
     if (sect.sct_oldown != player->cnum) {
     getsect(def->x, def->y, &sect);
 
     if (sect.sct_oldown != player->cnum) {
-       mines = MIN(sect.sct_mines, 20);
+       mines = SCT_LANDMINES(&sect);
+       mines = MIN(mines, 20);
        if (a_engineer)
            mines = ldround(mines / 2.0, 1);
        if (mines > 0) {
        if (a_engineer)
            mines = ldround(mines / 2.0, 1);
        if (mines > 0) {
index 40086a180f11c060fe278c54b3985c4f827746d4..fe408880afb931661936b2f40246a4b168fabf2f 100644 (file)
@@ -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));
        "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;
     sp->sct_type = SCT_WATER;
     sp->sct_newtype = SCT_WATER;
     sp->sct_own = 0;
index bfda69e532c17c4f2c07a2b56f05094bbbaa6f96..03b8de0d8da5ce9ab6a80a714eae217cf1a272da 100644 (file)
@@ -553,10 +553,10 @@ lnd_sweep(struct emp_qelem *land_list, int verbose, int takemob,
                    prland(&llp->unit.land));
            continue;
        }
                    prland(&llp->unit.land));
            continue;
        }
-       if (sect.sct_type == SCT_BSPAN) {
+       if (SCT_MINES_ARE_SEAMINES(&sect)) {
            if (verbose)
            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) {
            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, &sect);
        if (sect.sct_oldown == llp->unit.land.lnd_own)
            continue;
        getsect(llp->unit.land.lnd_x, llp->unit.land.lnd_y, &sect);
        if (sect.sct_oldown == llp->unit.land.lnd_own)
            continue;
-       if (sect.sct_type == SCT_BSPAN)
-           continue;
-       if (!sect.sct_mines)
+       if (SCT_LANDMINES(&sect) == 0)
            continue;
        if (chance(DMINE_LHITCHANCE(sect.sct_mines) / (1 + 2 * with_eng))) {
            lnd_hit_mine(&llp->unit.land, ((struct lchrstr *)llp->chrp));
            continue;
        if (chance(DMINE_LHITCHANCE(sect.sct_mines) / (1 + 2 * with_eng))) {
            lnd_hit_mine(&llp->unit.land, ((struct lchrstr *)llp->chrp));
index 34fe0c9291b73a4f9a55f59b318f800830006522..91a8931f0f561d048a7bc2291d11eb65fbc0b5e1 100644 (file)
@@ -318,7 +318,7 @@ check_lmines(coord x, coord y, double weight)
     int dam = 0;
 
     getsect(x, y, &sect);
     int dam = 0;
 
     getsect(x, y, &sect);
-    if (sect.sct_mines > 0 &&
+    if (SCT_LANDMINES(&sect) > 0 &&
        sect.sct_oldown != player->cnum &&
        chance(DMINE_LHITCHANCE(sect.sct_mines)) && chance(weight / 100.0)) {
        pr_beep();
        sect.sct_oldown != player->cnum &&
        chance(DMINE_LHITCHANCE(sect.sct_mines)) && chance(weight / 100.0)) {
        pr_beep();
index b13a7e0ef7062e25bb31a80914655ff81acb07b3..9bae8323b376722197797fb25dd094877118cd17 100644 (file)
@@ -904,7 +904,7 @@ plane_sweep(struct emp_qelem *plane_list, coord x, coord y)
     if (mines_there == 0)
        return;
 
     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));
        return;
 
     for (qp = plane_list->q_forw; ((qp != plane_list) && (mines_there));
index 64acb854918abb637d57ba0278678537cf880204..7928302430f76346fd35d8626c8f399c02fcdc5a 100644 (file)
@@ -475,7 +475,7 @@ retreat_land1(struct lndstr *lp, char code, int orig)
        if (stopping)
            continue;
 
        if (stopping)
            continue;
 
-       mines = sect.sct_mines;
+       mines = SCT_LANDMINES(&sect);
        if ((lcp->l_flags & L_ENGINEER) && mines > 0 &&
            (sect.sct_oldown != lp->lnd_own)) {
            max = lcp->l_item[I_SHELL];
        if ((lcp->l_flags & L_ENGINEER) && mines > 0 &&
            (sect.sct_oldown != lp->lnd_own)) {
            max = lcp->l_item[I_SHELL];