]> granicus.if.org Git - nethack/commitdiff
fix #H2636 - vault guard "fakecorr overflow" panic
authorPatR <rankin@nethack.org>
Wed, 19 Dec 2018 11:06:40 +0000 (03:06 -0800)
committerPatR <rankin@nethack.org>
Wed, 19 Dec 2018 11:06:40 +0000 (03:06 -0800)
Another 6.5 year old report.  This one from Steven Melenchuk told
how to reproduce C343-23 which is still open on our 'known bugs'
page.  (I've no idea whether the original bug report came through
the contact page, and if so, what its assigned number was.)

I didn't try to solve this one, I just confirmed that it could be
reproduced and took the fix from grunthack at github.  He didn't
menion a fix at the time but implemented one before abandoing his
variant.  (Others kept it going afterwards; fix was during his time.)

The overflow occurred when the guard couldn't figure out where to
move to next and just repeatedly 'moved' to his current location
until the maximum number of fake corridor spots was used up.  The
fix detects not knowing where to go next and explicitly choosing a
new destination.

Original problem could be reproduced by teleporting into the vault,
digging out a wall and two spaces of stone in a straight line, then
going back into the vault to wait for a guard.  When he shows up:
answer, drop gold, follow.  If the guard's path walks through both
dug spaces, he will stop waiting for the hero.  But hero is in
between the guard and the gap in the vault wall and can't advance;
guard has reached a persistent corridor so doesn't know where to go
next.  Have hero wait for 125-ish more turns and then game panicks.

The code was 3.4.3 vintage so needed thorough reformatting, but not
any actual changes (unless I've overlooked something).

doc/fixes36.2
src/vault.c

index f499a63517dd8c735c0507bdcfb114119e0fdff9..d7348a2ee7789bb8ce8daf70034150f78bbcec7d 100644 (file)
@@ -286,6 +286,9 @@ while levitating inside a shop, throwing an unpaid item and having recoil move
        the shopkeeper and summon kops
 diluted potion of oil is less effective when filling lamps (adds less fuel)
        or burning (lasts less long) or exploding (inflicts less damage)
+apply fix from grunthack to prevent panic "fakecorr overflow" when vault guard
+       couldn't figure out how to lead the hero from vault to civilization;
+       fixes longstanding bug C343-23
 
 
 Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository
index 0e811d1171359411ba557e3bda1decc1a2eb4423..c23f555953dba7301b629df741ad1a192a657a86 100644 (file)
@@ -1,17 +1,17 @@
-/* NetHack 3.6 vault.c $NHDT-Date: 1544608469 2018/12/12 09:54:29 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.57 $ */
+/* NetHack 3.6 vault.c $NHDT-Date: 1545217597 2018/12/19 11:06:37 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.58 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2011. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 
-STATIC_DCL struct monst *NDECL(findgd);
-
 STATIC_DCL boolean FDECL(clear_fcorr, (struct monst *, BOOLEAN_P));
 STATIC_DCL void FDECL(blackout, (int, int));
 STATIC_DCL void FDECL(restfakecorr, (struct monst *));
 STATIC_DCL void FDECL(parkguard, (struct monst *));
 STATIC_DCL boolean FDECL(in_fcorridor, (struct monst *, int, int));
+STATIC_DCL struct monst *NDECL(findgd);
+STATIC_DCL boolean FDECL(find_guard_dest, (struct monst *, xchar *, xchar *));
 STATIC_DCL void FDECL(move_gold, (struct obj *, int));
 STATIC_DCL void FDECL(wallify_vault, (struct monst *));
 STATIC_DCL void FDECL(gd_mv_monaway, (struct monst *, int, int));
@@ -232,6 +232,44 @@ char *array;
     return '\0';
 }
 
+STATIC_OVL boolean
+find_guard_dest(guard, rx, ry)
+struct monst *guard;
+xchar *rx, *ry;
+{
+    register int x, y, dd, lx = 0, ly = 0;
+
+    for (dd = 2; (dd < ROWNO || dd < COLNO); dd++) {
+        for (y = u.uy - dd; y <= u.uy + dd; ly = y, y++) {
+            if (y < 0 || y > ROWNO - 1)
+                continue;
+            for (x = u.ux - dd; x <= u.ux + dd; lx = x, x++) {
+                if (y != u.uy - dd && y != u.uy + dd && x != u.ux - dd)
+                    x = u.ux + dd;
+                if (x < 1 || x > COLNO - 1)
+                    continue;
+                if (guard && ((x == guard->mx && y == guard->my)
+                              || (guard->isgd && in_fcorridor(guard, x, y))))
+                    continue;
+                if (levl[x][y].typ == CORR) {
+                    lx = (x < u.ux) ? x + 1 : (x > u.ux) ? x - 1 : x;
+                    ly = (y < u.uy) ? y + 1 : (y > u.uy) ? y - 1 : y;
+                    if (levl[lx][ly].typ != STONE && levl[lx][ly].typ != CORR)
+                        goto incr_radius;
+                    *rx = x;
+                    *ry = y;
+                    return TRUE;
+                }
+            }
+        }
+ incr_radius:
+        ;
+    }
+    impossible("Not a single corridor on this level?");
+    tele();
+    return FALSE;
+}
+
 void
 invault()
 {
@@ -252,49 +290,14 @@ invault()
     if (++u.uinvault % VAULT_GUARD_TIME == 0 && !guard) {
         /* if time ok and no guard now. */
         char buf[BUFSZ];
-        register int x, y, dd, gx, gy;
-        int lx = 0, ly = 0;
+        register int x, y, gx, gy;
+        xchar rx, ry;
         long umoney;
 
         /* first find the goal for the guard */
-        for (dd = 2; (dd < ROWNO || dd < COLNO); dd++) {
-            for (y = u.uy - dd; y <= u.uy + dd; ly = y, y++) {
-                if (y < 0 || y > ROWNO - 1)
-                    continue;
-                for (x = u.ux - dd; x <= u.ux + dd; lx = x, x++) {
-                    if (y != u.uy - dd && y != u.uy + dd && x != u.ux - dd)
-                        x = u.ux + dd;
-                    if (x < 1 || x > COLNO - 1)
-                        continue;
-                    if (levl[x][y].typ == CORR) {
-                        if (x < u.ux)
-                            lx = x + 1;
-                        else if (x > u.ux)
-                            lx = x - 1;
-                        else
-                            lx = x;
-                        if (y < u.uy)
-                            ly = y + 1;
-                        else if (y > u.uy)
-                            ly = y - 1;
-                        else
-                            ly = y;
-                        if (levl[lx][ly].typ != STONE
-                            && levl[lx][ly].typ != CORR)
-                            goto incr_radius;
-                        goto fnd;
-                    }
-                }
-            }
-        incr_radius:
-            ;
-        }
-        impossible("Not a single corridor on this level??");
-        tele();
-        return;
-    fnd:
-        gx = x;
-        gy = y;
+        if (!find_guard_dest((struct monst *)0, &rx, &ry))
+            return;
+        gx = rx, gy = ry;
 
         /* next find a good place for a door in the wall */
         x = u.ux;
@@ -621,7 +624,7 @@ gd_move(grd)
 register struct monst *grd;
 {
     int x, y, nx, ny, m, n;
-    int dx, dy, gx, gy, fci;
+    int dx, dy, gx = 0, gy = 0, fci;
     uchar typ;
     struct rm *crm;
     struct fakecorridor *fcp;
@@ -705,7 +708,7 @@ register struct monst *grd;
                 levl[m][n].typ = egrd->fakecorr[0].ftyp;
                 newsym(m, n);
                 grd->mpeaceful = 0;
           letknow:
+ letknow:
                 if (!cansee(grd->mx, grd->my) || !mon_visible(grd))
                     You_hear("%s.",
                              m_carrying(grd, TIN_WHISTLE)
@@ -848,10 +851,10 @@ register struct monst *grd;
                     goto proceed;
                 }
             }
       nextnxy:
+ nextnxy:
             ;
         }
-nextpos:
+ nextpos:
     nx = x;
     ny = y;
     gx = egrd->gdx;
@@ -892,19 +895,30 @@ nextpos:
         break;
     }
     crm->typ = CORR;
-proceed:
+ proceed:
     newspot = TRUE;
     unblock_point(nx, ny); /* doesn't block light */
     if (cansee(nx, ny))
         newsym(nx, ny);
 
-    fcp = &(egrd->fakecorr[egrd->fcend]);
-    if (egrd->fcend++ == FCSIZ)
-        panic("fakecorr overflow");
-    fcp->fx = nx;
-    fcp->fy = ny;
-    fcp->ftyp = typ;
-newpos:
+    if ((nx != gx || ny != gy) || (grd->mx != gx || grd->my != gy)) {
+        fcp = &(egrd->fakecorr[egrd->fcend]);
+        if (egrd->fcend++ == FCSIZ)
+            panic("fakecorr overflow");
+        fcp->fx = nx;
+        fcp->fy = ny;
+        fcp->ftyp = typ;
+    } else if (!egrd->gddone) {
+        /* We're stuck, so try to find a new destination. */
+        if (!find_guard_dest(grd, &egrd->gdx, &egrd->gdy)
+            || (egrd->gdx == gx && egrd->gdy == gy)) {
+            pline("%s, confused, disappears.", Monnam(grd));
+            disappear_msg_seen = TRUE;
+            goto cleanup;
+        } else
+            goto nextpos;
+    }
+ newpos:
     gd_mv_monaway(grd, nx, ny);
     if (egrd->gddone) {
         /* The following is a kludge.  We need to keep    */
@@ -916,7 +930,7 @@ newpos:
         /* to avoid a check at the top of this function.  */
         /* At the end of the process, the guard is killed */
         /* in restfakecorr().                             */
   cleanup:
+ cleanup:
         x = grd->mx, y = grd->my;
         see_guard = canspotmon(grd);
         parkguard(grd); /* move to <0,0> */