From be327d9822a17823a86553bb33d414ba56522fd4 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 29 Nov 2018 12:15:14 -0800 Subject: [PATCH] steed vs "no monster to remove" Noticed whlie testing the steed-in-pit fix. The EXTRA_SANITY_CHECKS for remove_monster() are being tripped if riding hero has steed killed out from under him because the steed is not on the map. This started out simple but got a bit complicated. It seems to be sufficient but I'm not very confident about it. Being engulfed while mounted gave "placing monster over another?" due to a change made along with EXTRA_SANITY_CHECKS but not conditional on it. (The change was to issue a warning about an actual problem which was previously undiagnosed.) I think bumping the engulfer off the map in favor of the former steed only worked because some u.uswallow code eventually used the hero's location to put the engulfer back. I didn't pursue that to try to figure what really happened, just prevent it. The DISMOUNT_BONES handling was being executed even if the steed was dead. DISMOUNT_BONES only happens if the hero is dead. Since I don't know whether it's possible for dead hero and dead steed to happen at the same time, move it inside the steed-not-dead block just in case. --- doc/fixes36.2 | 2 ++ src/steed.c | 51 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 3acebaa54..6d64fb8fd 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -246,6 +246,8 @@ ensure tmp_at() structures are initialized for all code paths when swallowed trapped-vs-levitation/flying change broke Sting releasing hero from web life-saving while poly'd and Unchanging wasn't restoring u.mh (HP as monster) change in searching stopped finding unseen monsters except hiders and eels +buliding with EXTRA_SANITY_CHECKS enabled would issue "no monster to remove" + warning if steed was killed out from under the hero tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes tty: ensure that current status fields are always copied to prior status diff --git a/src/steed.c b/src/steed.c index bf675cca9..91ed935f4 100644 --- a/src/steed.c +++ b/src/steed.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 steed.c $NHDT-Date: 1542765364 2018/11/21 01:56:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.57 $ */ +/* NetHack 3.6 steed.c $NHDT-Date: 1543522486 2018/11/29 20:14:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.58 $ */ /* Copyright (c) Kevin Hugo, 1998-1999. */ /* NetHack may be freely redistributed. See license for details. */ @@ -481,7 +481,7 @@ int reason; /* Player was thrown off etc. */ { struct monst *mtmp; struct obj *otmp; - coord cc; + coord cc, steedcc; const char *verb = "fall"; boolean repair_leg_damage = (Wounded_legs != 0L); unsigned save_utrap = u.utrap; @@ -548,19 +548,44 @@ int reason; /* Player was thrown off etc. */ /* Release the steed and saddle */ u.usteed = 0; u.ugallop = 0L; - - /* Set player and steed's position. Try moving the player first - unless we're in the midst of creating a bones file. */ - if (reason == DISMOUNT_BONES) { - /* move the steed to an adjacent square */ - if (enexto(&cc, u.ux, u.uy, mtmp->data)) - rloc_to(mtmp, cc.x, cc.y); - else /* evidently no room nearby; move steed elsewhere */ - (void) rloc(mtmp, FALSE); - return; + /* + * rloc(), rloc_to(), and monkilled()->mondead()->m_detach() all + * expect mtmp to be on the map or else have mtmp->mx be 0, but + * setting the latter to 0 here would interfere with dropping + * the saddle. Prior to 3.6.2, being off the map didn't matter. + * + * place_monster() expects mtmp to be alive and not be u.usteed. + * + * Unfortunately, (former steed's implicit location) + * might now be occupied by an engulfer, so we can't just put mtmp + * at that spot. An engulfer's previous spot will be unoccupied + * but we don't know where that was and even if we did, it might + * be hostile terrain. + */ + steedcc.x = u.ux, steedcc.y = u.uy; + if (m_at(u.ux, u.uy)) + (void) enexto(&steedcc, u.ux, u.uy, mtmp->data); + if (!m_at(steedcc.x, steedcc.y)) { + if (mtmp->mhp < 1) + mtmp->mhp = 0; /* make sure it isn't negative */ + mtmp->mhp++; /* force at least one hit point, possibly resurrecting */ + place_monster(mtmp, steedcc.x, steedcc.y); + mtmp->mhp--; /* take the extra hit point away: cancel resurrection */ + } else { + impossible("Dismounting: can't place former steed on map."); } + if (!DEADMONSTER(mtmp)) { - place_monster(mtmp, u.ux, u.uy); + /* Set player and steed's position. Try moving the player first + unless we're in the midst of creating a bones file. */ + if (reason == DISMOUNT_BONES) { + /* move the steed to an adjacent square */ + if (enexto(&cc, u.ux, u.uy, mtmp->data)) + rloc_to(mtmp, cc.x, cc.y); + else /* evidently no room nearby; move steed elsewhere */ + (void) rloc(mtmp, FALSE); + return; + } if (!u.uswallow && !u.ustuck && have_spot) { struct permonst *mdat = mtmp->data; -- 2.50.1