From f3bc5e5c78b67064551137091f5c41703aa4fb03 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 4 Oct 2019 16:12:08 -0700 Subject: [PATCH] fix #H9272 - "object lost" panic 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 | 5 ++++- src/polyself.c | 52 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index ea0ebba13..d39eff5c6 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -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 diff --git a/src/polyself.c b/src/polyself.c index 3f33c8e9b..ab84a7e18 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -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();