]> granicus.if.org Git - nethack/commitdiff
Refine attempt to clamp trap door fall destination
authorMichael Meyer <me@entrez.cc>
Thu, 22 Sep 2022 00:06:35 +0000 (20:06 -0400)
committerPasi Kallinen <paxed@alt.org>
Thu, 22 Sep 2022 08:36:48 +0000 (11:36 +0300)
This should prevent anyone from exploiting falling into the sanctum (by
taking advantage of a trap door in a bones file from a differently
laid-out dungeon, as described in the previous commit) to bypass the
invocation, in addition to falling past the actual end of the dungeon.

src/trap.c

index 193d401c4234b7117560348fca0cbe7dc6c536d4..97cc712bc66cef6093c9910114805663c3efd26e 100644 (file)
@@ -8,7 +8,7 @@
 extern const char *const destroy_strings[][3]; /* from zap.c */
 
 static void mk_trap_statue(coordxy, coordxy);
-static int dng_bottom(void);
+static int dng_bottom(d_level *lev);
 static void hole_destination(d_level *);
 static boolean keep_saddle_with_steedcorpse(unsigned, struct obj *,
                                             struct obj *);
@@ -375,19 +375,19 @@ mk_trap_statue(coordxy x, coordxy y)
     mongone(mtmp);
 }
 
-/* find "bottom" level of current dungeon, stopping at quest locate */
+/* find "bottom" level of specified dungeon, stopping at quest locate */
 static int
-dng_bottom(void)
+dng_bottom(d_level *lev)
 {
-    int bottom = dunlevs_in_dungeon(&u.uz);
+    int bottom = dunlevs_in_dungeon(lev);
 
     /* when in the upper half of the quest, don't fall past the
        middle "quest locate" level if hero hasn't been there yet */
-    if (In_quest(&u.uz)) {
+    if (In_quest(lev)) {
         int qlocate_depth = qlocate_level.dlevel;
 
         /* deepest reached < qlocate implies current < qlocate */
-        if (dunlev_reached(&u.uz) < qlocate_depth)
+        if (dunlev_reached(lev) < qlocate_depth)
             bottom = qlocate_depth; /* early cut-off */
     }
     return bottom;
@@ -397,7 +397,7 @@ dng_bottom(void)
 static void
 hole_destination(d_level *dst)
 {
-    int bottom = dng_bottom();
+    int bottom = dng_bottom(&u.uz);
 
     dst->dnum = u.uz.dnum;
     dst->dlevel = dunlev(&u.uz);
@@ -520,7 +520,7 @@ fall_through(
     d_level dtmp;
     char msgbuf[BUFSZ];
     const char *dont_fall = 0;
-    int newlevel, bottom = dng_bottom();
+    int newlevel, bottom = dng_bottom(&u.uz);
     struct trap *t = (struct trap *) 0;
 
     /* we'll fall even while levitating in Sokoban; otherwise, if we
@@ -550,6 +550,8 @@ fall_through(
              || ((Flying || is_clinger(g.youmonst.data)
                   || (ceiling_hider(g.youmonst.data) && u.uundetected))
                  && !(ftflags & TOOKPLUNGE))
+             /* this is no longer a very useful test because newlevel isn't
+                the real destination we're aiming for, if t != 0 */
              || (Inhell && !u.uevent.invoked && newlevel == bottom)) {
         dont_fall = "don't fall in.";
     } else if (g.youmonst.data->msize >= MZ_HUGE) {
@@ -586,13 +588,17 @@ fall_through(
             dtmp.dnum = t->dst.dnum;
             /* don't fall beyond the bottom, in case this came from a bones
                file with different dungeon size  */
+            bottom = dng_bottom(&t->dst);
             dtmp.dlevel = min(t->dst.dlevel, bottom);
-            dist = dtmp.dlevel - dunlev(&u.uz);
+            if (In_hell(&t->dst) && !u.uevent.invoked
+                && dtmp.dlevel == bottom)
+                dtmp.dlevel--;
         } else {
             dtmp.dnum = u.uz.dnum;
             dtmp.dlevel = newlevel;
-            dist = newlevel - dunlev(&u.uz);
         }
+        /* XXX: dist won't be accurate if dtmp.dnum may not match u.uz.dnum */
+        dist = dtmp.dlevel - dunlev(&u.uz);
         if (dist > 1)
             You("fall down a %s%sshaft!", dist > 3 ? "very " : "",
                 dist > 2 ? "deep " : "");