From: Pasi Kallinen Date: Thu, 2 Feb 2023 17:04:48 +0000 (+0200) Subject: Fix ceiling hiders on pools X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8535b248c8472b545ca8ae8ce1da9d671018a516;p=nethack Fix ceiling hiders on pools 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. --- diff --git a/include/extern.h b/include/extern.h index ab57154d6..62feb5e48 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); diff --git a/src/mon.c b/src/mon.c index a181e11f8..cd898fb8c 100644 --- 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); diff --git a/src/teleport.c b/src/teleport.c index a9039cc20..28db803d9 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -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;