From 229930e50570599239cfc7df1fd00e367f38e8b4 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 24 Nov 2020 19:26:12 +0200 Subject: [PATCH] Fixes and sanity checks for monster undetected and trapped states Adds sanity checks for mtrapped and mundetected states. Fixes cases where those were left in wrong state. 1. Trapped monster (eg. a nymph) teleported out of a trap 2. Monster was hiding under ball or chain, which then got removed 3. While restoring a level, a zombie corpse revived while monster was hiding under it 4. A general case where the only object was deleted off floor and a monster was hiding under it Monsters hiding under ball or chain will now get revealed when the b or c are moved. --- include/extern.h | 1 + src/ball.c | 4 +++- src/invent.c | 4 +++- src/mkobj.c | 4 ++++ src/mon.c | 36 ++++++++++++++++++++++++++++++++++++ src/restore.c | 2 ++ src/teleport.c | 4 ++++ 7 files changed, 53 insertions(+), 2 deletions(-) diff --git a/include/extern.h b/include/extern.h index ce3d3bd87..4ea7e7575 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1514,6 +1514,7 @@ E void FDECL(seemimic, (struct monst *)); E void NDECL(rescham); E void NDECL(restartcham); E void FDECL(restore_cham, (struct monst *)); +E void FDECL(maybe_unhide_at, (XCHAR_P, XCHAR_P)); E boolean FDECL(hideunder, (struct monst *)); E void FDECL(hide_monst, (struct monst *)); E void FDECL(mon_animal_list, (BOOLEAN_P)); diff --git a/src/ball.c b/src/ball.c index 7bc78dd07..60099a83b 100644 --- a/src/ball.c +++ b/src/ball.c @@ -162,7 +162,7 @@ unplacebc_core() obj_extract_self(uball); if (Blind && (u.bc_felt & BC_BALL)) /* drop glyph */ levl[uball->ox][uball->oy].glyph = u.bglyph; - + maybe_unhide_at(uball->ox, uball->oy); newsym(uball->ox, uball->oy); } obj_extract_self(uchain); @@ -536,9 +536,11 @@ xchar ballx, bally, chainx, chainy; /* only matter !before */ } remove_object(uchain); + maybe_unhide_at(uchain->ox, uchain->oy); newsym(uchain->ox, uchain->oy); if (!carried(uball)) { remove_object(uball); + maybe_unhide_at(uball->ox, uball->oy); newsym(uball->ox, uball->oy); } } else { diff --git a/src/invent.c b/src/invent.c index 7c1393d2d..16d6ff01f 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1225,8 +1225,10 @@ register struct obj *obj; } update_map = (obj->where == OBJ_FLOOR); obj_extract_self(obj); - if (update_map) + if (update_map) { + maybe_unhide_at(obj->ox, obj->oy); newsym(obj->ox, obj->oy); + } obfree(obj, (struct obj *) 0); /* frees contents also */ } diff --git a/src/mkobj.c b/src/mkobj.c index f4960008b..71ef55a88 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2175,6 +2175,10 @@ struct obj *obj; panic("dealloc_obj with nobj"); if (obj->cobj) panic("dealloc_obj with cobj"); + if (obj == uball || obj == uchain) + impossible("dealloc_obj called on %s, owornmask=%lx", + (obj == uball) ? "uball" : "uchain", + obj->owornmask); /* free up any timers attached to the object */ if (obj->timed) diff --git a/src/mon.c b/src/mon.c index 6ae225d44..6a534d084 100644 --- a/src/mon.c +++ b/src/mon.c @@ -99,6 +99,29 @@ const char *msg; /* guardian angel on astral level is tame but has emin rather than edog */ if (mtmp->mtame && !has_edog(mtmp) && !mtmp->isminion) impossible("pet without edog (%s)", msg); + + if (mtmp->mtrapped) { + if (mtmp->wormno) { + /* TODO: how to check worm in trap? */ + } else if (!t_at(mtmp->mx, mtmp->my)) + impossible("trapped without a trap (%s)", msg); + } + + /* monster is hiding? */ + if (mtmp->mundetected) { + struct trap *t; + + if (mtmp == u.ustuck) + impossible("hiding monster stuck to you (%s)", msg); + if (m_at(mtmp->mx, mtmp->my) == mtmp && hides_under(mtmp->data) && !OBJ_AT(mtmp->mx, mtmp->my)) + impossible("mon hiding under nonexistent obj (%s)", msg); + if (mtmp->data->mlet == S_EEL && !is_pool(mtmp->mx, mtmp->my) && !Is_waterlevel(&u.uz)) + impossible("eel hiding out of water (%s)", msg); + if (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0 + && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT)) + impossible("hiding while trapped in a non-pit (%s)", msg); + } + } void @@ -3537,6 +3560,19 @@ register struct monst *mtmp; return FALSE; } +/* reveal a monster at x,y hiding under an object, + if there are no objects there */ +void +maybe_unhide_at(x, y) +xchar x, y; +{ + struct monst *mtmp; + + if (!OBJ_AT(x, y) && (mtmp = m_at(x, y)) != 0 + && mtmp->mundetected && hides_under(mtmp->data)) + (void) hideunder(mtmp); +} + /* monster/hero tries to hide under something at the current location */ boolean hideunder(mtmp) diff --git a/src/restore.c b/src/restore.c index 3ca9c0e2a..deaabb4fb 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1128,6 +1128,8 @@ xchar lev; place_monster(mtmp, mtmp->mx, mtmp->my); if (mtmp->wormno) place_wsegs(mtmp, NULL); + if (hides_under(mtmp->data) && mtmp->mundetected) + (void) hideunder(mtmp); /* regenerate monsters while on another level */ if (!u.uz.dlevel) diff --git a/src/teleport.c b/src/teleport.c index b46a9b56d..e5e34c5ae 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1258,6 +1258,10 @@ register int x, y; the latter only happens if you've attacked them with polymorph */ if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy); + + /* trapped monster teleported away */ + if (mtmp->mtrapped && !mtmp->wormno) + (void) mintrap(mtmp); } static stairway *