concealed monster sanity checks

Add some more checks to sanity_check_single_mon().  If mon->data
is discovered to be bad, panic instead of just issuing a warning
since a subsequent crash would be inevitable.  Make sure hidden
ceiling hiders have a ceiling to hide at (so not on the planes of
air or water; some quest levels should probably be classified as
"no ceiling" but currently aren't).  Perform a few mimic checks.

Protection from shape changers had a couple of minor bugs.  A mimic
hidden at a spot the hero couldn't see would be allowed to remain
hidden (and stay that way once within view because protection from
shape changers isn't re-checked during ordinary activity).  Also,
if a pet was shape-changed while eating a mimic corpse at the time
protection from shape changers started, it would fall into untimed
sleep as part of being forced back to normal shape [rescham()] if
its location could be seen.
This commit is contained in:
PatR
2020-12-18 15:05:54 -08:00
parent f60ecfc3e7
commit c709c45780
2 changed files with 71 additions and 17 deletions

View File

@@ -1,4 +1,4 @@
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.394 $ $NHDT-Date: 1608236443 2020/12/17 20:20:43 $
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.395 $ $NHDT-Date: 1608332750 2020/12/18 23:05:50 $
General Fixes and Modified Features
-----------------------------------
@@ -337,6 +337,10 @@ when water damage wet a towel, the new wetness might randomly become less
when the wetness of a towel in inventory changed, persistent inventory wasn't
updated to show that
make Death revive earlier, and all the Riders after 67 turns at latest
when protection from shape changers begins, force mimic out of concealment
even if hero can't see its location; for locations that can be seen,
don't make double-trouble Wizard concealed as another monster--or pet
temporarily mimicking something while eating mimic corpse--fall asleep
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 mon.c $NHDT-Date: 1607901923 2020/12/13 23:25:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.360 $ */
/* NetHack 3.7 mon.c $NHDT-Date: 1608332750 2020/12/18 23:05:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.361 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */
@@ -46,11 +46,16 @@ struct monst *mtmp;
boolean chk_geno;
const char *msg;
{
if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS]) {
impossible("illegal mon data %s; mnum=%d (%s)",
fmt_ptr((genericptr_t) mtmp->data), mtmp->mnum, msg);
struct permonst *mptr = mtmp->data;
int mx = mtmp->mx, my = mtmp->my;
if (!mptr || mptr < &mons[LOW_PM] || mptr >= &mons[NUMMONS]) {
/* most sanity checks issue warnings if they detect a problem,
but this would be too extreme to keep going */
panic("illegal mon data %s; mnum=%d (%s)",
fmt_ptr((genericptr_t) mptr), mtmp->mnum, msg);
} else {
int mndx = monsndx(mtmp->data);
int mndx = monsndx(mptr);
if (mtmp->mnum != mndx) {
impossible("monster mnum=%d, monsndx=%d (%s)",
@@ -79,7 +84,7 @@ const char *msg;
/* bad if not fmons list or if not vault guard */
if (strcmp(msg, "fmon") || !mtmp->isgd)
impossible("dead monster on %s; %s at <%d,%d>",
msg, mons[mndx].mname, mtmp->mx, mtmp->my);
msg, mons[mndx].mname, mx, my);
#endif
return;
}
@@ -103,7 +108,7 @@ const char *msg;
if (mtmp->mtrapped) {
if (mtmp->wormno) {
/* TODO: how to check worm in trap? */
} else if (!t_at(mtmp->mx, mtmp->my))
} else if (!t_at(mx, my))
impossible("trapped without a trap (%s)", msg);
}
@@ -111,17 +116,54 @@ const char *msg;
if (mtmp->mundetected) {
struct trap *t;
if (!isok(mx, my)) /* caller will have checked this but not fixed it */
mx = my = 0;
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))
if (m_at(mx, my) == mtmp && hides_under(mptr) && !OBJ_AT(mx, 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))
if (mptr->mlet == S_EEL
&& !is_pool(mx, my) && !Is_waterlevel(&u.uz))
impossible("eel hiding out of water (%s)", msg);
if (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0
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)))
impossible("ceiling hider hiding %s (%s)",
!has_ceiling(&u.uz) ? "without ceiling"
: "in solid stone",
msg);
if (mtmp->mtrapped && (t = t_at(mx, my)) != 0
&& !(t->ttyp == PIT || t->ttyp == SPIKED_PIT))
impossible("hiding while trapped in a non-pit (%s)", msg);
}
} else if (M_AP_TYPE(mtmp) != M_AP_NOTHING) {
boolean is_mimic = (mptr->mlet == S_MIMIC);
const char *what = (M_AP_TYPE(mtmp) == M_AP_FURNITURE) ? "furniture"
: (M_AP_TYPE(mtmp) == M_AP_MONSTER) ? "a monster"
: (M_AP_TYPE(mtmp) == M_AP_OBJECT) ? "an object"
: "something strange";
if (Protection_from_shape_changers)
impossible(
"mimic%s concealed as %s despite Prot-from-shape-changers %s",
is_mimic ? "" : "ker", what, msg);
/* pet's quickmimic can take on furniture and object shapes,
but only until the pet finishes eating a mimic corpse */
if (!(is_mimic || mtmp->meating))
impossible("non-mimic (%s) posing as %s (%s)",
mptr->mname, what, msg);
if (!(accessible(mx, my) || passes_walls(mptr))) {
char buf[BUFSZ];
const char *typnam = levltyp_to_name(levl[mx][my].typ);
if (!typnam) {
Sprintf(buf, "[%d]", levl[mx][my].typ);
typnam = buf;
}
impossible("mimic%s concealed in inaccessible location: %s (%s)",
is_mimic ? "" : "ker", typnam, msg);
}
}
}
void
@@ -3569,11 +3611,19 @@ rescham()
}
if (is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
new_were(mtmp);
if (M_AP_TYPE(mtmp) && cansee(mtmp->mx, mtmp->my)) {
seemimic(mtmp);
/* we pretend that the mimic doesn't
know that it has been unmasked */
mtmp->msleeping = 1;
if (M_AP_TYPE(mtmp) != M_AP_NOTHING) {
/* this used to include a cansee() check but Protection_from_
_shape_changers shouldn't be trumped by being unseen */
if (!mtmp->meating) {
/* make revealed mimic fall asleep in lieu of shape change */
if (M_AP_TYPE(mtmp) != M_AP_MONSTER)
mtmp->msleeping = 1;
seemimic(mtmp);
} else {
/* quickmimic: pet is midst of eating a mimic corpse;
this terminates the meal early */
finish_meating(mtmp);
}
}
}
}