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.
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));
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);
}
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 {
}
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 */
}
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)
/* 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
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)
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)
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 *