]> granicus.if.org Git - nethack/commitdiff
steed vs "no monster to remove"
authorPatR <rankin@nethack.org>
Thu, 29 Nov 2018 20:15:14 +0000 (12:15 -0800)
committerPatR <rankin@nethack.org>
Thu, 29 Nov 2018 20:15:14 +0000 (12:15 -0800)
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
src/steed.c

index 3acebaa54c3e6f8c1a16e0eff88899111226fc35..6d64fb8fde73f46d01b3d3c068b5f709d31a214f 100644 (file)
@@ -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
index bf675cca9d8a4227ebeec1c778b4b3a361a9ab51..91ed935f4fefe999db3a6d597bbfa5cf5a62b573 100644 (file)
@@ -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, <u.ux,u.uy> (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;