]> granicus.if.org Git - nethack/commitdiff
more vault guard (trunk only)
authornethack.rankin <nethack.rankin>
Thu, 13 Oct 2011 00:31:13 +0000 (00:31 +0000)
committernethack.rankin <nethack.rankin>
Thu, 13 Oct 2011 00:31:13 +0000 (00:31 +0000)
     Fix several obscure bugs that can happen when a guard leads someone
out of a vault:
1) non-pit traps created in the temporary corridor would persist inside
   solid rock after the corridor was removed (pits dug by the hero were
   explicitly removed but several other trap types are possible);
2) lighting the corridor with scroll/wand/spell left the affected spots
   flagged as lit after they reverted to rock; tunneling through that
   area, either by digging or by teleporting back to the vault and having
   another guard appear, unearthed lit corridor there;
3) if you became encased in solid rock because you were in the temporary
   corridor when it was removed (which will happen if the guard is killed
   while you're in his corridor), you were only told so if you saw part of
   it revert to rock; when blind, you simply found yourself unable to move;
4) dragging an iron ball in the temporary corridor could result in part
   of that corridor becoming permanent if the guard was killed; in 3.4.3,
   it would only occur if the cause of death took away all the guard's
   hit points (which happens for most but not all deaths); in development
   code after my recent patch, that would be every cause of death.
#4 could also yield "dmonsfree: <N+1> removed doesn't match <N> pending"
warning in 3.4.3 when the fmon list was scanned and a guard at <0,0> with
no hit points was found but hadn't passed through to the end of mondead()
and m_detach().  The previous patch fixed that, I think/hope.  Most guard
deaths won't trigger that; grddead() moves the guard to <0,0> but then
removes the temp corridor on its second try, returns true, and mondead()
finishes normally.

doc/fixes35.0
include/extern.h
src/display.c
src/mon.c
src/vault.c

index 303ef1f832d564ab00dd76114f697dd3258fdd77..e237863350c1324322880efb0287b54cc22d9add 100644 (file)
@@ -384,6 +384,14 @@ when dying outside all shops on a level with multiple shopkeepers and one takes
 hero poly'd into a critter without hands could still open tins
 if a vault guard was killed, his inventory would be dropped at <0,0>
 throwing gold to/at a vault guard will no longer be treated as an attack
+non-pit traps created in vault guard's temporary corridor would remain after
+       the location reverted to solid rock
+using magic to light vault guard's temporary corridor would produce lit solid
+       rock after reversion, and then yield lit corridor if dug out again
+if hero was blind, killing the vault guard while in his temporary corridor
+       would leave hero encased in solid rock without informing player
+if hero dragged iron ball into temporary corridor and then killed vault guard,
+       the portion of corridor currently in existence would become permanent
 
 
 Platform- and/or Interface-Specific Fixes
index 3ad7c4d272d80088b34aa68455335cda76537eff..24b4f81b62c03fcf89edf39f267c4437ae41ae4e 100644 (file)
@@ -332,6 +332,7 @@ E int FDECL(back_to_glyph, (XCHAR_P,XCHAR_P));
 E int FDECL(zapdir_to_glyph, (int,int,int));
 E int FDECL(glyph_at, (XCHAR_P,XCHAR_P));
 E void NDECL(set_wall_state);
+E void FDECL(unset_seenv, (struct rm *,int,int,int,int));
 
 /* ### do.c ### */
 
index 7e1c3b0e01211f075b45c49a1a8ec4adf4f50d1b..c9437b1ef0345b5e0a9a0f68c5c3ab1c244e0a51 100644 (file)
@@ -1858,9 +1858,22 @@ set_seenv(lev, x0, y0, x, y)
     int x0, y0, x, y;  /* from, to */
 {
     int dx = x-x0, dy = y0-y;
+
     lev->seenv |= seenv_matrix[sign(dy)+1][sign(dx)+1];
 }
 
+/* Called by blackout(vault.c) when vault guard removes temporary corridor,
+   turning spot <x0,y0> back into stone; <x1,y1> is an adjacent spot. */
+void
+unset_seenv(lev, x0, y0, x1, y1)
+    struct rm *lev;            /* &levl[x1][y1] */
+    int x0, y0, x1, y1;        /* from, to; abs(x1-x0)==1 && abs(y0-y1)==1 */
+{
+    int dx = x1 - x0, dy = y0 - y1;
+
+    lev->seenv &= ~seenv_matrix[dy + 1][dx + 1];
+}
+
 /* ------------------------------------------------------------------------- */
 
 /* T wall types, one for each row in wall_matrix[][]. */
index 214c2a482cce318ccb0203a0f53ed7114b02c81e..3238792e07433e29c4aa480821d951117d894720 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -535,6 +535,9 @@ movemon()
        }
 #endif
        nmtmp = mtmp->nmon;
+       /* one dead monster needs to perform a move after death:
+          vault guard whose temporary corridor is still on the map */
+       if (mtmp->isgd && !mtmp->mx && mtmp->mhp <= 0) (void)gd_move(mtmp);
        if (DEADMONSTER(mtmp)) continue;
 
        /* Find a monster that we have not treated yet.  */
index b46ce50bb1f180c3163ccb5920b56005c07b8f7a..af37a062553086cc6ce7fc5c6590805da394e65a 100644 (file)
@@ -7,6 +7,7 @@
 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 boolean FDECL(in_fcorridor, (struct monst *,int,int));
 STATIC_DCL void FDECL(move_gold,(struct obj *,int));
@@ -43,7 +44,8 @@ boolean forceshow;
        struct monst *mtmp;
        boolean sawcorridor = FALSE;
        struct egd *egrd = EGD(grd);
-       struct trap *trap = (struct trap *)0;
+       struct trap *trap;
+       struct rm *lev;
 
        if (!on_level(&egrd->gdlevel, &u.uz)) return TRUE;
 
@@ -60,31 +62,60 @@ boolean forceshow;
                        return FALSE;
 
                if ((mtmp = m_at(fcx,fcy)) != 0) {
-                       if(mtmp->isgd) return(FALSE);
-                       else if(!in_fcorridor(grd, u.ux, u.uy)) {
-                           if(mtmp->mtame) yelp(mtmp);
-                           (void) rloc(mtmp, FALSE);
-                       }
-               }
-               if ((trap = t_at(fcx,fcy)) != 0 &&
-                    trap->ttyp == PIT && trap->madeby_u &&
-                    IS_STWALL(egrd->fakecorr[fcbeg].ftyp)) {
-                    /* you dug a pit while following the guard out,
-                       so fill it in when the location reverts to stone */
-                       deltrap(trap);
+                   if (mtmp->isgd) {
+                       return FALSE;
+                   } else if (!in_fcorridor(grd, u.ux, u.uy)) {
+                       if (mtmp->mtame) yelp(mtmp);
+                       (void) rloc(mtmp, FALSE);
+                   }
                }
-               if (levl[fcx][fcy].typ == CORR && cansee(fcx, fcy))
+               lev = &levl[fcx][fcy];
+               if (lev->typ == CORR && cansee(fcx, fcy))
                    sawcorridor = TRUE;
-               levl[fcx][fcy].typ = egrd->fakecorr[fcbeg].ftyp;
+               lev->typ = egrd->fakecorr[fcbeg].ftyp;
+               if (IS_STWALL(lev->typ)) {
+                   /* destroy any trap here (pit dug by you, hole dug via
+                      wand while levitating or by monster, bear trap or land
+                      mine via object, spun web) when spot reverts to stone */
+                   if ((trap = t_at(fcx, fcy)) != 0) deltrap(trap);
+                   /* undo scroll/wand/spell of light affecting this spot */
+                   if (lev->typ == STONE) blackout(fcx, fcy);
+               }
                map_location(fcx, fcy, 1);      /* bypass vision */
-               if(!ACCESSIBLE(levl[fcx][fcy].typ)) block_point(fcx,fcy);
+               if (!ACCESSIBLE(lev->typ)) block_point(fcx, fcy);
+               vision_full_recalc = 1;
                egrd->fcbeg++;
        }
-       if (sawcorridor) {
+       if (sawcorridor)
            pline_The("corridor disappears.");
-           if(IS_ROCK(levl[u.ux][u.uy].typ)) You("are encased in rock.");
+       if (IS_ROCK(levl[u.ux][u.uy].typ))
+           You("are encased in rock.");
+       return TRUE;
+}
+
+/* as a temporary corridor is removed, set stone locations and adjacent
+   spots to unlit; if player used scroll/wand/spell of light while inside
+   the corridor, we don't want the light to reappear if/when a new tunnel
+   goes through the same area */
+STATIC_OVL void
+blackout(x, y)
+int x, y;
+{
+    struct rm *lev;
+    int i, j;
+
+    for (i = x - 1; i <= x + 1; ++i)
+       for (j = y - 1; j <= y + 1; ++j) {
+           if (!isok(i, j)) continue;
+           lev  = &levl[i][j];
+           /* [possible bug: when (i != x || j != y), perhaps we ought
+              to check whether the spot on the far side is lit instead
+              of doing a blanket blackout of adjacent locations] */
+           if (lev->typ == STONE)
+               lev->lit = lev->waslit = 0;
+           /* mark <i,j> as not having been seen from <x,y> */
+           unset_seenv(lev, x, y, i, j);
        }
-       return(TRUE);
 }
 
 STATIC_OVL void