From 743d3a1eb59d7fffe0a1bb3a9afd2576d411d9bf Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 8 Jun 2017 15:05:24 -0700 Subject: [PATCH] yet another pass at 'A' bugs I think this finally quashes the "cursed without otmp" issue. Various ways of destroying wielded weapon used setnotworn() rather than unwield(), so the previous change to have unwield() clear the pending W_WEP bit from takeoff.mask wasn't sufficient to prevent 'A' moving on from another item (blindfold--it's the only thing processed before primary weapon) to weapon which wasn't there any more. Also, if weapon was already set in takeoff.what to be processed on the next move, clearing W_WEP from takeoff.mask wasn't sufficient either. Move the previous unwield() 'fix' to setworn() and setnotworn() and extend it to include cancel_don() if the item being replaced or removed is in progress or scheduled for next. (Most of the time, remove_worn_item() has already done that before setworn() or setnotworn() is called.) --- doc/fixes36.1 | 5 ++++- include/extern.h | 3 ++- src/do_wear.c | 41 ++++++++++++++++++++++++++++++++--------- src/wield.c | 8 +------- src/worn.c | 9 ++++++++- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 4a43125d1..bf5df58cb 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -379,7 +379,9 @@ levitation vs encumbrance message sequencing issues: putting on boots of and float-up messages, taking off such boots didn't report increase of encumbrance until player took another action removing a blindfold with 'A' took two turns, with 'R' (and 'T') only one, - and could result in a panic if the blindfold was stolen during removal + and could result in a crash if the blindfold was stolen during removal +removing a blindfold and wielded weapon with 'A' could result in crash if the + weapon was destroyed by various methods cmdassist help for movement prefix followed by invalid direction was strange when the direction was up, down, or self disallowed for that prefix poor message when shape-shifted vampire reverts to vampire if it has a name: @@ -396,6 +398,7 @@ adult green dragons and the Chromatic Dragon were blinded by gas clouds named floating eye (when hit by another monster with reflection) or named silver weapon (when hero hits silver-hating monster) could disrupt message formatting and conceivably trigger crash if name had '%' in it +crashes for 'A' above were downgraded to impossible "cursed without otmp" Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 58a451c67..72df6d58d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1496860756 2017/06/07 18:39:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.590 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1496959470 2017/06/08 22:04:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.591 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -436,6 +436,7 @@ E void FDECL(off_msg, (struct obj *)); E void FDECL(set_wear, (struct obj *)); E boolean FDECL(donning, (struct obj *)); E boolean FDECL(doffing, (struct obj *)); +E void FDECL(cancel_doff, (struct obj *, long)); E void NDECL(cancel_don); E int FDECL(stop_donning, (struct obj *)); E int NDECL(Armor_off); diff --git a/src/do_wear.c b/src/do_wear.c index 2d16d34d1..71599fd7a 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_wear.c $NHDT-Date: 1496614914 2017/06/04 22:21:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.97 $ */ +/* NetHack 3.6 do_wear.c $NHDT-Date: 1496959478 2017/06/08 22:04:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1207,7 +1207,7 @@ struct obj *otmp; { boolean result = FALSE; - /* 'W' and 'T' set afternmv, 'A' sets context.takeoff.what */ + /* 'W' (or 'P' used for armor) sets afternmv */ if (doffing(otmp)) result = TRUE; else if (otmp == uarm) @@ -1237,7 +1237,7 @@ struct obj *otmp; long what = context.takeoff.what; boolean result = FALSE; - /* 'T' (also 'W') sets afternmv, 'A' sets context.takeoff.what */ + /* 'T' (or 'R' used for armor) sets afternmv, 'A' sets takeoff.what */ if (otmp == uarm) result = (afternmv == Armor_off || what == WORN_ARMOR); else if (otmp == uarmu) @@ -1252,8 +1252,7 @@ struct obj *otmp; result = (afternmv == Gloves_off || what == WORN_GLOVES); else if (otmp == uarms) result = (afternmv == Shield_off || what == WORN_SHIELD); - /* these 1-turn items don't need 'afternmv' checks - [and may not actually need 'what' checks] */ + /* these 1-turn items don't need 'afternmv' checks */ else if (otmp == uamul) result = (what == WORN_AMUL); else if (otmp == uleft) @@ -1272,6 +1271,29 @@ struct obj *otmp; return result; } +/* despite their names, cancel_don() and cancel_doff() both apply to both + donning and doffing... */ +void +cancel_doff(obj, slotmask) +struct obj *obj; +long slotmask; +{ + /* Called by setworn() for old item in specified slot or by setnotworn() + * for specified item. We don't want to call cancel_don() if we got + * here via _off() -> setworn((struct obj *)0) -> cancel_doff() + * because that would stop the 'A' command from continuing with next + * selected item. So do_takeoff() sets a flag in takeoff.mask for us. + * [For taking off an individual item with 'T'/'R'/'w-', it doesn't + * matter whether cancel_don() gets called here--the item has already + * been removed by now.] + */ + if (!(context.takeoff.mask & I_SPECIAL) && donning(obj)) + cancel_don(); /* applies to doffing too */ + context.takeoff.mask &= ~slotmask; +} + +/* despite their names, cancel_don() and cancel_doff() both apply to both + donning and doffing... */ void cancel_don() { @@ -1308,7 +1330,7 @@ struct obj *stolenobj; /* no message if stolenobj is already being doffing */ /* donning() returns True when doffing too; doffing() is more specific */ putting_on = !doffing(otmp); - /* cancel_don() looks at afternmv; it also serves as cancel_doff() */ + /* cancel_don() looks at afternmv; it can also cancel doffing */ cancel_don(); /* don't want _on() or _off() being called by unmul() since the on or off action isn't completing */ @@ -2302,6 +2324,7 @@ do_takeoff() struct obj *otmp = (struct obj *) 0; struct takeoff_info *doff = &context.takeoff; + context.takeoff.mask |= I_SPECIAL; /* set flag for cancel_doff() */ if (doff->what == W_WEP) { if (!cursed(uwep)) { setuwep((struct obj *) 0); @@ -2361,6 +2384,7 @@ do_takeoff() } else { impossible("do_takeoff: taking off %lx", doff->what); } + context.takeoff.mask &= ~I_SPECIAL; /* clear cancel_doff() flag */ return otmp; } @@ -2378,10 +2402,9 @@ take_off(VOID_ARGS) if (doff->delay > 0) { doff->delay--; return 1; /* still busy */ - } else { - if ((otmp = do_takeoff())) - off_msg(otmp); } + if ((otmp = do_takeoff()) != 0) + off_msg(otmp); doff->mask &= ~doff->what; doff->what = 0L; } diff --git a/src/wield.c b/src/wield.c index d2f51a2ee..bd176a812 100644 --- a/src/wield.c +++ b/src/wield.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wield.c $NHDT-Date: 1496614915 2017/06/04 22:21:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.53 $ */ +/* NetHack 3.6 wield.c $NHDT-Date: 1496959480 2017/06/08 22:04:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.54 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -676,10 +676,6 @@ uwepgone() pline("%s shining.", Tobjnam(uwep, "stop")); } setworn((struct obj *) 0, W_WEP); - /* update takeoff mask in case uwep has just gone away while - its removal via 'A' was pending, similar to what the various - Xyzzy_off(do_wear.c) routines do for armor and accessories */ - context.takeoff.mask &= ~W_WEP; unweapon = TRUE; update_inventory(); } @@ -690,7 +686,6 @@ uswapwepgone() { if (uswapwep) { setworn((struct obj *) 0, W_SWAPWEP); - context.takeoff.mask &= ~W_SWAPWEP; update_inventory(); } } @@ -700,7 +695,6 @@ uqwepgone() { if (uquiver) { setworn((struct obj *) 0, W_QUIVER); - context.takeoff.mask &= ~W_QUIVER; update_inventory(); } } diff --git a/src/worn.c b/src/worn.c index a99d1336d..abc1d4c3e 100644 --- a/src/worn.c +++ b/src/worn.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worn.c $NHDT-Date: 1493510127 2017/04/29 23:55:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.48 $ */ +/* NetHack 3.6 worn.c $NHDT-Date: 1496959481 2017/06/08 22:04:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -77,6 +77,9 @@ long mask; if (oobj->oartifact) set_artifact_intrinsic(oobj, 0, mask); } + /* in case wearing or removal is in progress or removal + is pending (via 'A' command for multiple items) */ + cancel_doff(oobj, wp->w_mask); } *(wp->w_obj) = obj; if (obj) { @@ -119,6 +122,10 @@ register struct obj *obj; u.twoweap = 0; for (wp = worn; wp->w_mask; wp++) if (obj == *(wp->w_obj)) { + /* in case wearing or removal is in progress or removal + is pending (via 'A' command for multiple items) */ + cancel_doff(obj, wp->w_mask); + *(wp->w_obj) = 0; p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; -- 2.40.0