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.)
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:
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
-/* 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. */
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);
-/* 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. */
{
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)
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)
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)
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()
{
/* 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 */
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);
} else {
impossible("do_takeoff: taking off %lx", doff->what);
}
+ context.takeoff.mask &= ~I_SPECIAL; /* clear cancel_doff() flag */
return otmp;
}
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;
}
-/* 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. */
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();
}
{
if (uswapwep) {
setworn((struct obj *) 0, W_SWAPWEP);
- context.takeoff.mask &= ~W_SWAPWEP;
update_inventory();
}
}
{
if (uquiver) {
setworn((struct obj *) 0, W_QUIVER);
- context.takeoff.mask &= ~W_QUIVER;
update_inventory();
}
}
-/* 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. */
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) {
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;