]> granicus.if.org Git - nethack/commitdiff
Fix ceiling hiders on pools
authorPasi Kallinen <paxed@alt.org>
Thu, 2 Feb 2023 17:04:48 +0000 (19:04 +0200)
committerPasi Kallinen <paxed@alt.org>
Thu, 2 Feb 2023 17:04:51 +0000 (19:04 +0200)
While fuzzing, I saw a sanity checking error complaining about
a ceiling hider being on top of a pool; the rock piercer was
teleported on top of the pool while it was hiding in the ceiling.

Try to be a bit more consistent when a monster is hiding in ceiling,
and if it's valid for it to be on a pool.

include/extern.h
src/mon.c
src/teleport.c

index ab57154d6581096af77b5b6aa9407843bb9a7b00..62feb5e48e26896842267f131ebf7633bbbd4804 100644 (file)
@@ -1559,6 +1559,7 @@ extern int max_mon_load(struct monst *);
 extern boolean can_touch_safely(struct monst *, struct obj *);
 extern int can_carry(struct monst *, struct obj *);
 extern long mon_allowflags(struct monst *);
+extern boolean m_in_air(struct monst *);
 extern int mfndpos(struct monst *, coord *, long *, long);
 extern boolean monnear(struct monst *, coordxy, coordxy);
 extern void dmonsfree(void);
index a181e11f84dde04f718502d3c581cd6df44aba5a..cd898fb8cee6e7f8354354725aaf92bb714751cb 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -153,7 +153,10 @@ sanity_check_single_mon(
         if (ceiling_hider(mptr)
             /* normally !accessible would be overridable with passes_walls,
                but not for hiding on the ceiling */
-            && (!has_ceiling(&u.uz) || !accessible(mx, my)))
+            && (!has_ceiling(&u.uz) ||
+                !(levl[mx][my].typ == POOL
+                  || levl[mx][my].typ == MOAT
+                  || accessible(mx, my))))
             impossible("ceiling hider hiding %s (%s)",
                        !has_ceiling(&u.uz) ? "without ceiling"
                                            : "in solid stone",
@@ -1854,6 +1857,16 @@ mon_allowflags(struct monst* mtmp)
     return allowflags;
 }
 
+/* return TRUE if monster is up in the air/on the ceiling */
+boolean
+m_in_air(struct monst *mtmp)
+{
+    return (is_flyer(mtmp->data)
+            || is_floater(mtmp->data)
+            || (is_clinger(mtmp->data)
+                && has_ceiling(&u.uz) && mtmp->mundetected));
+}
+
 /* return number of acceptable neighbour positions */
 int
 mfndpos(
@@ -1881,11 +1894,11 @@ mfndpos(
 
     nodiag = NODIAG(mdat - mons);
     wantpool = (mdat->mlet == S_EEL);
-    poolok = ((!Is_waterlevel(&u.uz) && !grounded(mdat))
+    poolok = ((!Is_waterlevel(&u.uz) && m_in_air(mon))
               || (is_swimmer(mdat) && !wantpool));
     /* note: floating eye is the only is_floater() so this could be
        simplified, but then adding another floater would be error prone */
-    lavaok = (!grounded(mdat) || likes_lava(mdat));
+    lavaok = (m_in_air(mon) || likes_lava(mdat));
     if (mdat == &mons[PM_FLOATING_EYE]) /* prefers to avoid heat */
         lavaok = FALSE;
     thrudoor = ((flag & (ALLOW_WALL | BUSTDOOR)) != 0L);
index a9039cc20a1dde6950a7db6ade573e1e45d5a8a8..28db803d935c1ddaa2bdc75b222b24f8c9d12b14 100644 (file)
@@ -133,7 +133,7 @@ goodpos(
                 return (is_swimmer(mdat)
                         || (!Is_waterlevel(&u.uz)
                             && !is_waterwall(x, y)
-                            && !grounded(mdat)));
+                            && m_in_air(mtmp)));
         } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) {
             return FALSE;
         } else if (is_lava(x, y) && !ignorelava) {
@@ -147,8 +147,7 @@ goodpos(
                             && uarmf->oerodeproof)
                         || (Upolyd && likes_lava(gy.youmonst.data)));
             else
-                return (is_floater(mdat) || is_flyer(mdat)
-                        || likes_lava(mdat));
+                return (m_in_air(mtmp) || likes_lava(mdat));
         }
         if (passes_walls(mdat) && may_passwall(x, y))
             return TRUE;