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.)
This commit is contained in:
PatR
2017-06-08 15:05:24 -07:00
parent 964fd0fdbd
commit 743d3a1eb5
5 changed files with 47 additions and 19 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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 <X>_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 <armor>_on() or <armor>_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;
}

View File

@@ -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();
}
}

View File

@@ -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;