Skip to content

Commit

Permalink
fix #H2636 - vault guard "fakecorr overflow" panic
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
PatR committed Dec 19, 2018
1 parent 81d73ce commit b32c93c
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 56 deletions.
3 changes: 3 additions & 0 deletions doc/fixes36.2
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
126 changes: 70 additions & 56 deletions src/vault.c
Original file line number Diff line number Diff line change
@@ -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));
Expand Down Expand Up @@ -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()
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -848,10 +851,10 @@ register struct monst *grd;
goto proceed;
}
}
nextnxy:
nextnxy:
;
}
nextpos:
nextpos:
nx = x;
ny = y;
gx = egrd->gdx;
Expand Down Expand Up @@ -892,19 +895,30 @@ register struct monst *grd;
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 */
Expand All @@ -916,7 +930,7 @@ register struct monst *grd;
/* 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> */
Expand Down

0 comments on commit b32c93c

Please sign in to comment.