\#wizmakemap vs migrating monsters

The bookkeeping for number of dead or removed monsters got out of sync
if a shopkeeper, temple priest, or vault guard on the migrating_mons
list who was scheduled to return to the current level got passed to
mongone() when #wizmakemap destroyed the current level in order to
replace it.

When getting rid of such monsters, first put them on fmon.  Once 'gone'
they'll still be on that list and dmonsfree() will include them in the
tally of dead or removed monsters and hopefully the count will match
the number it thinks were pending.

This works for a vault guard; I didn't try for shopkeeper or priest.
Ditch pet(s) so that they won't kill stuff and open up map spots while
you're waiting for guard activity; enter vault away from the wall
nearest to 'civilization'; fill the level with lichens or other junk;
wait for guard to arrive; don't drop gold.  After a short while the
guard will try to teleport next to you but with the level full will
end up in limbo instead (migrating, scheduled to come back to current
level).  Then perform #wizmakemap.  Prior to this patch, there will be
an impossible about N removed not matching N+1 pending; after it, no
such impossible.
This commit is contained in:
PatR
2022-07-15 14:36:03 -07:00
parent b37f922cf7
commit e5977a3a2d
3 changed files with 25 additions and 9 deletions

View File

@@ -93,7 +93,7 @@ sanity_check_single_mon(
#endif
if (DEADMONSTER(mtmp)) {
#if 0
/* bad if not fmons list or if not vault guard */
/* bad if not fmon list or if not vault guard */
if (strcmp(msg, "fmon") || !mtmp->isgd)
impossible("dead monster on %s; %s at <%d,%d>",
msg, mons[mndx].pmnames[NEUTRAL],
@@ -2129,7 +2129,7 @@ dmonsfree(void)
char buf[QBUFSZ];
buf[0] = '\0';
for (mtmp = &fmon; *mtmp;) {
for (mtmp = &fmon; *mtmp; ) {
freetmp = *mtmp;
if (DEADMONSTER(freetmp) && !freetmp->isgd) {
*mtmp = freetmp->nmon;
@@ -2401,8 +2401,13 @@ m_detach(
if (In_endgame(&u.uz))
mtmp->mstate |= MON_ENDGAME_FREE;
mtmp->mstate |= MON_DETACH;
iflags.purge_monsters++;
if ((mtmp->mstate & MON_DETACH) != 0) {
impossible("m_detach: %s is already detached?",
minimal_monnam(mtmp, FALSE));
} else {
mtmp->mstate |= MON_DETACH;
iflags.purge_monsters++;
}
}
/* give a life-saved monster a reasonable mhpmax value in case it has