]> granicus.if.org Git - nethack/commitdiff
Fixes and sanity checks for monster undetected and trapped states
authorPasi Kallinen <paxed@alt.org>
Tue, 24 Nov 2020 17:26:12 +0000 (19:26 +0200)
committerPasi Kallinen <paxed@alt.org>
Tue, 24 Nov 2020 17:37:43 +0000 (19:37 +0200)
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
src/ball.c
src/invent.c
src/mkobj.c
src/mon.c
src/restore.c
src/teleport.c

index ce3d3bd874f48c9e88bb276063a0670e4766c3b7..4ea7e757533c75fb9c3d6d8d20f747b2444f09b1 100644 (file)
@@ -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));
index 7bc78dd07d44212153b095f3698983fc1bd9b271..60099a83b623e997a67dd7f25027c71d01144615 100644 (file)
@@ -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 {
index 7c1393d2d4447025c47b08db2972a70a05e0ca07..16d6ff01fcb9f2f2da8cc103f6379a3168da3239 100644 (file)
@@ -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 */
 }
 
index f4960008b3c0b411b0856f54a3eb31a20f3c9f5b..71ef55a88a41d319df9ca00954beac8eca87f546 100644 (file)
@@ -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)
index 6ae225d44164590b21a53939cecf6dda78ddbdaa..6a534d08458d8a544cc22c44adf1df82cf1a4ac4 100644 (file)
--- 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)
index 3ca9c0e2a53b5acf40c60e1f1de64d4996bc6618..deaabb4fb1adb11ab90b56fc56cfabb4c75c412e 100644 (file)
@@ -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)
index b46a9b56daf14b9b355bac8ad78a43bba1e84d3c..e5e34c5ae145d033605fc077f3907f3fbb25efa1 100644 (file)
@@ -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 *