retouch_equipment() bypass handling

Simplify retouch_equipment (post-3.4.3.code, called when hero
changes alignment or turns into a silver-hating critter; inventory
traversal must cope with the possibility of losing object->nobj when
processing object) by switching to recently added object->bypass code.
This commit is contained in:
nethack.rankin
2013-11-07 01:03:16 +00:00
parent e8e291b018
commit 5cc7f32044
+21 -23
View File
@@ -1809,9 +1809,6 @@ boolean drop_untouchable;
boolean beingworn, carryeffect, invoked; boolean beingworn, carryeffect, invoked;
long wearmask = ~(W_QUIVER | (u.twoweap ? 0L : W_SWAPWEP) | W_BALL); long wearmask = ~(W_QUIVER | (u.twoweap ? 0L : W_SWAPWEP) | W_BALL);
if (obj->bypass) return FALSE; /* already handled */
bypass_obj(obj); /* mark it as handled now */
beingworn = (obj->owornmask & wearmask) != 0L || beingworn = (obj->owornmask & wearmask) != 0L ||
/* some items in use don't have any wornmask setting */ /* some items in use don't have any wornmask setting */
(obj->oclass == TOOL_CLASS && (obj->oclass == TOOL_CLASS &&
@@ -1841,16 +1838,27 @@ boolean drop_untouchable;
return FALSE; return FALSE;
} }
/* check items currently in use (mostly worn) for touchability */ /* check all items currently in use (mostly worn) for touchability */
void void
retouch_equipment(dropflag) retouch_equipment(dropflag)
int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */ int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */
{ {
static int nesting = 0; /* recursion control */ static int nesting = 0; /* recursion control */
struct obj *obj; struct obj *obj;
boolean scanagain, dropit, had_gloves = (uarmg != 0); boolean dropit, had_gloves = (uarmg != 0);
int had_rings = (!!uleft + !!uright); int had_rings = (!!uleft + !!uright);
/*
* We can potentially be called recursively if losing/unwearing
* an item causes worn helm of opposite alignment to come off or
* be destroyed.
*
* BUG: if the initial call was due to putting on a helm of
* opposite alignment and it does come off to trigger recursion,
* after the inner call executes, the outer call will finish
* using the non-helm alignment rather than the helm alignment
* which triggered this in the first place.
*/
if (!nesting++) clear_bypasses(); /* init upon initial entry */ if (!nesting++) clear_bypasses(); /* init upon initial entry */
dropit = (dropflag > 0); /* drop all or drop weapon */ dropit = (dropflag > 0); /* drop all or drop weapon */
@@ -1872,27 +1880,17 @@ int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */
* TODO? Force off gloves if either or both rings are going to * TODO? Force off gloves if either or both rings are going to
* become unworn; force off cloak [suit] before suit [shirt]. * become unworn; force off cloak [suit] before suit [shirt].
* The torso handling is hyphothetical; the case for gloves is * The torso handling is hyphothetical; the case for gloves is
* not due the possibility of unwearing silver rings. * not, due to the possibility of unwearing silver rings.
*/ */
dropit = (dropflag == 1); /* all untouchable items */ dropit = (dropflag == 1); /* all untouchable items */
do { /* loss of levitation (silver ring, or Heart of Ahriman invocation)
scanagain = FALSE; might cause hero to lose inventory items (by dropping into lava,
for instance), so inventory traversal needs to rescan the whole
for (obj = invent; obj; obj = obj->nobj) { invent chain each time it moves on to another object; we use bypass
if (obj->bypass) continue; handling to keep track of which items have already been processed */
while ((obj = nxt_unbypassed_obj(invent)) != 0)
if (untouchable(obj, dropit)) { /* always sets obj->bypass */ (void) untouchable(obj, dropit);
/* can't directly continue inventory traversal;
hero might have lost levitation, causing items to
be dropped or destroyed (poly trap, water, lava);
might even have lost helm of opposite alignment
and caused us to be called recursively... */
scanagain = TRUE;
break; /* use outer loop to restart inner one */
}
}
} while (scanagain);
if (had_rings != (!!uleft + !!uright) && uarmg && uarmg->cursed) if (had_rings != (!!uleft + !!uright) && uarmg && uarmg->cursed)
uncurse(uarmg); /* temporary? hack for ring removal plausibility */ uncurse(uarmg); /* temporary? hack for ring removal plausibility */