fix #K3920 - migrating mimicker sanity
Report says that Wizard of Yendor posing as some other monster triggers a sanity_check warning if on the migrating_mons list and hero has Protection_from_shape_changers attribute. My attmpts to reproduce that failed, but this updates the mon_sanity checking to explicitly allow a monster posing as another monster to be on the migrating monsters list. This also adds checks for whether a monster on the fmon list has MON_MIGRATING or MON_LIMBO or MON_DETACH bits set in monst->mstate and whether a monster on the migrating_mons list has MON_DETACH set or both MON_MIGRATING and MON_LIMBO clear. I won't be surprised if these new checks trigger sanity complaints.
This commit is contained in:
35
src/mon.c
35
src/mon.c
@@ -1,4 +1,4 @@
|
|||||||
/* NetHack 3.7 mon.c $NHDT-Date: 1681429657 2023/04/13 23:47:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.495 $ */
|
/* NetHack 3.7 mon.c $NHDT-Date: 1683831104 2023/05/11 18:51:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.501 $ */
|
||||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/*-Copyright (c) Derek S. Ray, 2015. */
|
/*-Copyright (c) Derek S. Ray, 2015. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
@@ -67,6 +67,7 @@ sanity_check_single_mon(
|
|||||||
but this would be too extreme to keep going */
|
but this would be too extreme to keep going */
|
||||||
panic("illegal mon data %s; mnum=%d (%s)",
|
panic("illegal mon data %s; mnum=%d (%s)",
|
||||||
fmt_ptr((genericptr_t) mptr), mtmp->mnum, msg);
|
fmt_ptr((genericptr_t) mptr), mtmp->mnum, msg);
|
||||||
|
/*NOTREACHED*/
|
||||||
} else {
|
} else {
|
||||||
int mndx = monsndx(mptr);
|
int mndx = monsndx(mptr);
|
||||||
|
|
||||||
@@ -174,10 +175,15 @@ sanity_check_single_mon(
|
|||||||
: (M_AP_TYPE(mtmp) == M_AP_OBJECT) ? "an object"
|
: (M_AP_TYPE(mtmp) == M_AP_OBJECT) ? "an object"
|
||||||
: "something strange";
|
: "something strange";
|
||||||
|
|
||||||
if (Protection_from_shape_changers)
|
if (!strcmp(msg, "migr")) {
|
||||||
|
if (M_AP_TYPE(mtmp) != M_AP_MONSTER)
|
||||||
|
impossible("migrating %s mimicking %s %s",
|
||||||
|
is_mimic ? "mimic" : "monster", what, msg);
|
||||||
|
} else if (Protection_from_shape_changers) {
|
||||||
impossible(
|
impossible(
|
||||||
"mimic%s concealed as %s despite Prot-from-shape-changers %s",
|
"mimic%s concealed as %s despite Prot-from-shape-changers %s",
|
||||||
is_mimic ? "" : "ker", what, msg);
|
is_mimic ? "" : "ker", what, msg);
|
||||||
|
}
|
||||||
/* the Wizard's clone after "double trouble" starts out mimicking
|
/* the Wizard's clone after "double trouble" starts out mimicking
|
||||||
some other monster; pet's quickmimic effect can temporarily take
|
some other monster; pet's quickmimic effect can temporarily take
|
||||||
on furniture, object, or monster shape, but only until the pet
|
on furniture, object, or monster shape, but only until the pet
|
||||||
@@ -229,6 +235,12 @@ mon_sanity_check(void)
|
|||||||
fmt_ptr((genericptr_t) mtmp), x, y);
|
fmt_ptr((genericptr_t) mtmp), x, y);
|
||||||
} else if (mtmp->wormno) {
|
} else if (mtmp->wormno) {
|
||||||
sanity_check_worm(mtmp);
|
sanity_check_worm(mtmp);
|
||||||
|
|
||||||
|
/* TODO: figure out which other bits shouldn't be set for 'fmon' */
|
||||||
|
} else if ((mtmp->mstate & (MON_DETACH | MON_MIGRATING | MON_LIMBO))
|
||||||
|
!= 0) {
|
||||||
|
impossible("floor mon (%s) with mstate set to 0x%08lx",
|
||||||
|
fmt_ptr((genericptr_t) mtmp), mtmp->mstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,6 +265,13 @@ mon_sanity_check(void)
|
|||||||
|
|
||||||
for (mtmp = gm.migrating_mons; mtmp; mtmp = mtmp->nmon) {
|
for (mtmp = gm.migrating_mons; mtmp; mtmp = mtmp->nmon) {
|
||||||
sanity_check_single_mon(mtmp, FALSE, "migr");
|
sanity_check_single_mon(mtmp, FALSE, "migr");
|
||||||
|
|
||||||
|
/* TODO: figure out which other bits could or shouldn't be set
|
||||||
|
* when migrating */
|
||||||
|
if ((mtmp->mstate & (MON_DETACH)) != 0
|
||||||
|
|| (mtmp->mstate & (MON_MIGRATING | MON_LIMBO)) == 0)
|
||||||
|
impossible("migrating mon (%s) with mstate set to 0x%08lx",
|
||||||
|
fmt_ptr((genericptr_t) mtmp), mtmp->mstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
wormno_sanity_check(); /* test for bogus worm tail */
|
wormno_sanity_check(); /* test for bogus worm tail */
|
||||||
@@ -709,6 +728,8 @@ make_corpse(struct monst *mtmp, unsigned int corpseflags)
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef KEEPTRAITS
|
||||||
|
|
||||||
/* check mtmp and water/lava for compatibility, 0 (survived), 1 (died) */
|
/* check mtmp and water/lava for compatibility, 0 (survived), 1 (died) */
|
||||||
int
|
int
|
||||||
minliquid(struct monst* mtmp)
|
minliquid(struct monst* mtmp)
|
||||||
@@ -1388,6 +1409,8 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */
|
|||||||
return (count > 0 || ecount > 0) ? 1 : 0;
|
return (count > 0 || ecount > 0) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef mstoning
|
||||||
|
|
||||||
/* Monster eats a corpse off the ground.
|
/* Monster eats a corpse off the ground.
|
||||||
* Return value is 0 = nothing eaten, 1 = ate a corpse, 2 = died */
|
* Return value is 0 = nothing eaten, 1 = ate a corpse, 2 = died */
|
||||||
int
|
int
|
||||||
@@ -2778,6 +2801,8 @@ mondead(struct monst *mtmp)
|
|||||||
|
|
||||||
RESTORE_WARNING_FORMAT_NONLITERAL
|
RESTORE_WARNING_FORMAT_NONLITERAL
|
||||||
|
|
||||||
|
#undef livelog_mon_nam
|
||||||
|
|
||||||
/* TRUE if corpse might be dropped, magr may die if mon was swallowed */
|
/* TRUE if corpse might be dropped, magr may die if mon was swallowed */
|
||||||
boolean
|
boolean
|
||||||
corpse_chance(
|
corpse_chance(
|
||||||
@@ -3215,7 +3240,7 @@ xkilled(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (wasinside) {
|
if (wasinside) {
|
||||||
/* spoteffects() can end up clearing the level of monsters; grab a copy */
|
/* spoteffects() can end up clearing level of monsters; grab a copy */
|
||||||
museum = *mtmp;
|
museum = *mtmp;
|
||||||
museum.nmon = 0;
|
museum.nmon = 0;
|
||||||
museum.minvent = 0;
|
museum.minvent = 0;
|
||||||
@@ -3301,6 +3326,8 @@ xkilled(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef LEVEL_SPECIFIC_NOCORPSE
|
||||||
|
|
||||||
/* changes the monster into a stone monster of the same type
|
/* changes the monster into a stone monster of the same type
|
||||||
this should only be called when poly_when_stoned() is true */
|
this should only be called when poly_when_stoned() is true */
|
||||||
void
|
void
|
||||||
@@ -4929,6 +4956,8 @@ egg_type_from_parent(
|
|||||||
return mnum;
|
return mnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef BREEDER_EGG
|
||||||
|
|
||||||
/* decide whether an egg of the indicated monster type is viable;
|
/* decide whether an egg of the indicated monster type is viable;
|
||||||
also used to determine whether an egg or tin can be created... */
|
also used to determine whether an egg or tin can be created... */
|
||||||
boolean
|
boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user