]> granicus.if.org Git - nethack/commitdiff
fix #H9272 - "object lost" panic
authorPatR <rankin@nethack.org>
Fri, 4 Oct 2019 23:12:08 +0000 (16:12 -0700)
committerPatR <rankin@nethack.org>
Fri, 4 Oct 2019 23:12:08 +0000 (16:12 -0700)
when polymorph causes loss of levitation boots or water walking boots
while over water.  If discarding stuff while trying to crawl out got
rid of the taken-off boots, they wouldn't be in inventory any more
when break_armor() tried to drop them after taking them off.

doc/fixes36.3
src/polyself.c

index ea0ebba13a4957675c5d71566987456ca6f05a49..d39eff5c6585112c845960f8ffc98b6eba79f434 100644 (file)
@@ -1,4 +1,4 @@
-$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.122 $ $NHDT-Date: 1570227405 2019/10/04 22:16:45 $
+$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.123 $ $NHDT-Date: 1570230710 2019/10/04 23:11:50 $
 
 This fixes36.3 file is here to capture information about updates in the 3.6.x
 lineage following the release of 3.6.2 in May 2019. Please note, however,
@@ -168,6 +168,9 @@ ball and chain could end up too far from punished hero (triggering b&c warning
        water failed because dropping stuff left hero overly encumbered and
        hero was life saved--or player declined to die--if the hero got
        teleported one step further from ball and chain's current location
+avoid 'object lost' panic when polymorph causes loss of levitation boots or
+       water walking boots which dumps hero into water where emergency
+       disrobing/dropping in order to crawl out chooses to drop those boots
 
 
 Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository
index 3f33c8e9b8a0058ae1cca141095f6ecccc75cbc6..ab84a7e18932a4ddffc10419f721e1b4450d1889 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 polyself.c      $NHDT-Date: 1559664952 2019/06/04 16:15:52 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.133 $ */
+/* NetHack 3.6 polyself.c      $NHDT-Date: 1570230710 2019/10/04 23:11:50 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.134 $ */
 /*      Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -23,6 +23,7 @@
 
 STATIC_DCL void FDECL(check_strangling, (BOOLEAN_P));
 STATIC_DCL void FDECL(polyman, (const char *, const char *));
+STATIC_DCL void FDECL(dropp, (struct obj *));
 STATIC_DCL void NDECL(break_armor);
 STATIC_DCL void FDECL(drop_weapon, (int));
 STATIC_DCL int FDECL(armor_to_dragon, (int));
@@ -858,6 +859,33 @@ int mntmp;
     return 1;
 }
 
+/* dropx() jacket for break_armor() */
+STATIC_OVL void
+dropp(obj)
+struct obj *obj;
+{
+    struct obj *otmp;
+
+    /*
+     * Dropping worn armor while polymorphing might put hero into water
+     * (loss of levitation boots or water walking boots that the new
+     * form can't wear), where emergency_disrobe() could remove it from
+     * inventory.  Without this, dropx() could trigger an 'object lost'
+     * panic.  Right now, boots are the only armor which might encounter
+     * this situation, but handle it for all armor.
+     *
+     * Hypothetically, 'obj' could have merged with something (not
+     * applicable for armor) and no longer be a valid pointer, so scan
+     * inventory for it instead of trusting obj->where.
+     */
+    for (otmp = invent; otmp; otmp = otmp->nobj) {
+        if (otmp == obj) {
+            dropx(obj);
+            break;
+        }
+    }
+}
+
 STATIC_OVL void
 break_armor()
 {
@@ -876,7 +904,7 @@ break_armor()
             if (otmp->oartifact) {
                 Your("%s falls off!", cloak_simple_name(otmp));
                 (void) Cloak_off();
-                dropx(otmp);
+                dropp(otmp);
             } else {
                 Your("%s tears apart!", cloak_simple_name(otmp));
                 (void) Cloak_off();
@@ -893,7 +921,7 @@ break_armor()
                 cancel_don();
             Your("armor falls around you!");
             (void) Armor_gone();
-            dropx(otmp);
+            dropp(otmp);
         }
         if ((otmp = uarmc) != 0) {
             if (is_whirly(youmonst.data))
@@ -901,7 +929,7 @@ break_armor()
             else
                 You("shrink out of your %s!", cloak_simple_name(otmp));
             (void) Cloak_off();
-            dropx(otmp);
+            dropp(otmp);
         }
         if ((otmp = uarmu) != 0) {
             if (is_whirly(youmonst.data))
@@ -909,7 +937,7 @@ break_armor()
             else
                 You("become much too small for your shirt!");
             setworn((struct obj *) 0, otmp->owornmask & W_ARMU);
-            dropx(otmp);
+            dropp(otmp);
         }
     }
     if (has_horns(youmonst.data)) {
@@ -927,7 +955,7 @@ break_armor()
                 Your("%s falls to the %s!", helm_simple_name(otmp),
                      surface(u.ux, u.uy));
                 (void) Helmet_off();
-                dropx(otmp);
+                dropp(otmp);
             }
         }
     }
@@ -939,12 +967,12 @@ break_armor()
             You("drop your gloves%s!", uwep ? " and weapon" : "");
             drop_weapon(0);
             (void) Gloves_off();
-            dropx(otmp);
+            dropp(otmp);
         }
         if ((otmp = uarms) != 0) {
             You("can no longer hold your shield!");
             (void) Shield_off();
-            dropx(otmp);
+            dropp(otmp);
         }
         if ((otmp = uarmh) != 0) {
             if (donning(otmp))
@@ -952,7 +980,7 @@ break_armor()
             Your("%s falls to the %s!", helm_simple_name(otmp),
                  surface(u.ux, u.uy));
             (void) Helmet_off();
-            dropx(otmp);
+            dropp(otmp);
         }
     }
     if (nohands(youmonst.data) || verysmall(youmonst.data)
@@ -966,7 +994,7 @@ break_armor()
                 Your("boots %s off your feet!",
                      verysmall(youmonst.data) ? "slide" : "are pushed");
             (void) Boots_off();
-            dropx(otmp);
+            dropp(otmp);
         }
     }
 }
@@ -1019,6 +1047,10 @@ int alone;
                 updateinv = FALSE;
             else if (candropwep)
                 dropx(otmp);
+            /* [note: dropp vs dropx -- if heart of ahriman is wielded, we
+               might be losing levitation by dropping it; but that won't
+               happen until the drop, unlike Boots_off() dumping hero into
+               water and triggering emergency_disrobe() before dropx()] */
 
             if (updateinv)
                 update_inventory();