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.
This commit is contained in:
Pasi Kallinen
2020-11-24 19:26:12 +02:00
parent 43379bffcc
commit 229930e505
7 changed files with 53 additions and 2 deletions

View 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));

View 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 {

View 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 */
}

View 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)

View File

@@ -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)

View 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)

View 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 *