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:
@@ -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
|
||||
|
||||
82
src/mon.c
82
src/mon.c
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user