sequencing issue: dismounting from dying steed
Reported by entrez: if a trap killed hero's steed and dismounting
was fatal for the hero (probably by falling onto the same trap),
impossible "dmonsfree: 1 removed doesn't match 0 pending" warning
occurred during game-over cleanup.
Move the dismount calls in mondead() and mongone() from before their
m_detach() call to the end of m_detach() itself. This led to a
cascade of problems and attempted fixes until finally zeroing in on
place_monster()'s sanity checks and dismount_steed()'s attempts to
work-around one of them.
This reverts the convoluted hack from four years ago in commit
be327d9822 and deals with the issue in
a simpler way. After that, the new dismount_steed() placement at
end of m_detach() works cleanly.
This commit is contained in:
@@ -1075,6 +1075,8 @@ if punished and iron ball was cursed and wielded--so welded to hand--falling
|
|||||||
if player's run-time config file had OPTIONS=role:Val and the environment had
|
if player's run-time config file had OPTIONS=role:Val and the environment had
|
||||||
NETHACKOPTIONS='role:!Val' the hero would be a Val instead of !Val
|
NETHACKOPTIONS='role:!Val' the hero would be a Val instead of !Val
|
||||||
sleeping or unconscious hero attacked by Medusa would meet her gaze
|
sleeping or unconscious hero attacked by Medusa would meet her gaze
|
||||||
|
if a trap killed both the hero's steed and the hero an impossible "dmonsfree:
|
||||||
|
N+1 removed doesn't match N pending" warning could occur
|
||||||
|
|
||||||
|
|
||||||
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
|
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
|
||||||
|
|||||||
+2
-1
@@ -2897,7 +2897,8 @@ spoteffects(boolean pick)
|
|||||||
: (time_left < 10L) ? 1
|
: (time_left < 10L) ? 1
|
||||||
: 0]);
|
: 0]);
|
||||||
}
|
}
|
||||||
if ((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
|
|
||||||
|
if ((mtmp = m_at(u.ux, u.uy)) != 0 && !u.uswallow) {
|
||||||
mtmp->mundetected = mtmp->msleeping = 0;
|
mtmp->mundetected = mtmp->msleeping = 0;
|
||||||
switch (mtmp->data->mlet) {
|
switch (mtmp->data->mlet) {
|
||||||
case S_PIERCER:
|
case S_PIERCER:
|
||||||
|
|||||||
@@ -2465,6 +2465,11 @@ m_detach(
|
|||||||
mtmp->mstate |= MON_DETACH;
|
mtmp->mstate |= MON_DETACH;
|
||||||
iflags.purge_monsters++;
|
iflags.purge_monsters++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hero is thrown from his steed when it dies or gets genocided */
|
||||||
|
if (mtmp == u.usteed)
|
||||||
|
dismount_steed(DISMOUNT_GENERIC);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* give a life-saved monster a reasonable mhpmax value in case it has
|
/* give a life-saved monster a reasonable mhpmax value in case it has
|
||||||
@@ -2636,10 +2641,6 @@ mondead(struct monst *mtmp)
|
|||||||
if (mtmp->isgd && !grddead(mtmp))
|
if (mtmp->isgd && !grddead(mtmp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Player is thrown from his steed when it dies */
|
|
||||||
if (mtmp == u.usteed)
|
|
||||||
dismount_steed(DISMOUNT_GENERIC);
|
|
||||||
|
|
||||||
mptr = mtmp->data; /* save this for m_detach() */
|
mptr = mtmp->data; /* save this for m_detach() */
|
||||||
/* restore chameleon, lycanthropes to true form at death */
|
/* restore chameleon, lycanthropes to true form at death */
|
||||||
if (mtmp->cham >= LOW_PM) {
|
if (mtmp->cham >= LOW_PM) {
|
||||||
@@ -2740,6 +2741,7 @@ mondead(struct monst *mtmp)
|
|||||||
|
|
||||||
if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
|
if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
|
||||||
unmap_object(mtmp->mx, mtmp->my);
|
unmap_object(mtmp->mx, mtmp->my);
|
||||||
|
|
||||||
m_detach(mtmp, mptr);
|
m_detach(mtmp, mptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2834,9 +2836,6 @@ mongone(struct monst* mdef)
|
|||||||
his temporary corridor to/from the vault has been removed */
|
his temporary corridor to/from the vault has been removed */
|
||||||
if (mdef->isgd && !grddead(mdef))
|
if (mdef->isgd && !grddead(mdef))
|
||||||
return;
|
return;
|
||||||
/* hero is thrown from his steed when it disappears */
|
|
||||||
if (mdef == u.usteed)
|
|
||||||
dismount_steed(DISMOUNT_GENERIC);
|
|
||||||
/* stuck to you? release */
|
/* stuck to you? release */
|
||||||
unstuck(mdef);
|
unstuck(mdef);
|
||||||
/* drop special items like the Amulet so that a dismissed Kop or nurse
|
/* drop special items like the Amulet so that a dismissed Kop or nurse
|
||||||
|
|||||||
+5
-12
@@ -660,19 +660,12 @@ dismount_steed(
|
|||||||
/* still no spot; last resort is any spot within bounds */
|
/* still no spot; last resort is any spot within bounds */
|
||||||
(void) enexto(&steedcc, u.ux, u.uy, &mons[PM_GHOST]);
|
(void) enexto(&steedcc, u.ux, u.uy, &mons[PM_GHOST]);
|
||||||
}
|
}
|
||||||
if (!m_at(steedcc.x, steedcc.y)) {
|
|
||||||
if (mtmp->mhp < 1) /* make sure it isn't negative so that */
|
|
||||||
mtmp->mhp = 0; /* ++mhp produces a positive value */
|
|
||||||
mtmp->mhp++; /* force at least one hit point, possibly resurrecting
|
|
||||||
* to avoid impossible("placing defunct monst on map") */
|
|
||||||
place_monster(mtmp, steedcc.x, steedcc.y);
|
|
||||||
mtmp->mhp--; /* take the extra hit point away: cancel resurrection
|
|
||||||
* if former steed has died */
|
|
||||||
} else {
|
|
||||||
impossible("Dismounting: can't place former steed on map.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DEADMONSTER(mtmp)) {
|
if (!DEADMONSTER(mtmp)) {
|
||||||
|
gi.in_steed_dismounting++;
|
||||||
|
place_monster(mtmp, steedcc.x, steedcc.y);
|
||||||
|
gi.in_steed_dismounting--;
|
||||||
|
|
||||||
/* if for bones, there's no reason to place the hero;
|
/* if for bones, there's no reason to place the hero;
|
||||||
we want to make room for potential ghost, so move steed */
|
we want to make room for potential ghost, so move steed */
|
||||||
if (reason == DISMOUNT_BONES) {
|
if (reason == DISMOUNT_BONES) {
|
||||||
@@ -855,7 +848,7 @@ place_monster(struct monst* mon, int x, int y)
|
|||||||
minimal_monnam(mon, TRUE), x, y, mon->mstate, buf);
|
minimal_monnam(mon, TRUE), x, y, mon->mstate, buf);
|
||||||
x = y = 0;
|
x = y = 0;
|
||||||
}
|
}
|
||||||
if (mon == u.usteed
|
if ((mon == u.usteed && !gi.in_steed_dismounting)
|
||||||
/* special case is for convoluted vault guard handling */
|
/* special case is for convoluted vault guard handling */
|
||||||
|| (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) {
|
|| (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) {
|
||||||
describe_level(buf, 0);
|
describe_level(buf, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user