From: nethack.rankin Date: Tue, 20 Mar 2007 04:38:29 +0000 (+0000) Subject: worn gear after polymorph alignment change [2 of 2] (trunk only) X-Git-Tag: MOVE2GIT~663 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2bd1f86cffa6d1736cd0d5a20a99b656d927785b;p=nethack worn gear after polymorph alignment change [2 of 2] (trunk only) Extend rotouch_equipment() to cover all items in use, worn/carried/ invoked in addition to wielded. Done when you change alignment, change shape, or catch lycanthropy. No-longer-touchable items inflict modest damage; worn/wielded ones will be unworn/unwielded. For the shape change and lycanthropy cases, unwieled weapons are also dropped. Other unworn stuff stays in inventory, as do weapons for the alignment change case. It ought to force off gloves if worn silver--or hypothetical artifact--ring has become untouchable and gets unworn. Instead it just curses the gloves, if necessary, so that there's some plausibility to having the ring come off. --- diff --git a/src/artifact.c b/src/artifact.c index 9b632db09..d313656cf 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -25,6 +25,7 @@ STATIC_DCL boolean FDECL(Mb_hit, (struct monst *magr,struct monst *mdef, struct obj *,int *,int,BOOLEAN_P,char *)); STATIC_DCL unsigned long FDECL(abil_to_spfx, (long *)); STATIC_DCL uchar FDECL(abil_to_adtyp,(long *)); +STATIC_DCL boolean FDECL(untouchable, (struct obj *,BOOLEAN_P)); /* The amount added to the victim's total hit points to insure that the @@ -1678,7 +1679,7 @@ boolean loseit; /* whether to drop it if hero can longer touch it */ /* dropx gives a message iff item lands on an altar */ if (!IS_ALTAR(levl[u.ux][u.uy].typ)) pline("%s to the %s.", - Tobjnam(obj, "drop"), surface(u.ux, u.uy)); + Tobjnam(obj, "fall"), surface(u.ux, u.uy)); dropx(obj); } *objp = obj = 0; /* no longer in inventory */ @@ -1686,17 +1687,109 @@ boolean loseit; /* whether to drop it if hero can longer touch it */ return 0; } +/* an item which is worn/wielded or an artifact which conveys + something via being carried or which has an #invoke effect + currently in operation undergoes a touch test; if it fails, + it will be unworn/unwielded and revoked but not dropped */ +STATIC_OVL boolean +untouchable(obj, drop_untouchable) +struct obj *obj; +boolean drop_untouchable; +{ + struct artifact *art; + boolean beingworn, carryeffect, invoked; + 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 || + /* some items in use don't have any wornmask setting */ + (obj->oclass == TOOL_CLASS && + (obj->lamplit || + (obj->otyp == LEASH && obj->leashmon) || + (Is_container(obj) && Has_contents(obj)))); + + if ((art = get_artifact(obj)) != 0) { + carryeffect = (art->cary.adtyp || art->cspfx); + invoked = (art->inv_prop > 0 && art->inv_prop <= LAST_PROP && + (u.uprops[art->inv_prop].extrinsic & W_ARTI) != 0L); + } else { + carryeffect = invoked = FALSE; + } + + if (beingworn || carryeffect || invoked) { + if (!retouch_object(&obj, drop_untouchable)) { + /* " is beyond your control" or "you can't handle + " has been given and it is now unworn/unwielded + and possibly dropped (depending upon caller); if dropped, + carried effect was turned off, else we leave that alone; + we turn off invocation property here if still carried */ + if (invoked && obj) arti_invoke(obj); /* reverse #invoke */ + return TRUE; + } + } + return FALSE; +} + +/* check items currently in use (mostly worn) for touchability */ void retouch_equipment(dropflag) int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */ { - boolean dropit; + static int nesting = 0; /* recursion control */ + struct obj *obj; + boolean scanagain, dropit, had_gloves = (uarmg != 0); + int had_rings = (!!uleft + !!uright); + + if (!nesting++) clear_bypasses(); /* init upon initial entry */ dropit = (dropflag > 0); /* drop all or drop weapon */ /* check secondary weapon first, before possibly unwielding primary */ - if (u.twoweap) (void)retouch_object(&uswapwep, dropit); + if (u.twoweap) (void)untouchable(uswapwep, dropit); /* check primary weapon next so that they're handled together */ - if (uwep) (void)retouch_object(&uwep, dropit); + if (uwep) (void)untouchable(uwep, dropit); + +#ifdef STEED + /* in case someone is daft enough to add artifact or silver saddle */ + if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) { + /* untouchable() calls retouch_object() which expects an object in + hero's inventory, but remove_worn_item() will be harmless for + saddle and we're suppressing drop, so this works as intended */ + if (untouchable(obj, FALSE)) dismount_steed(DISMOUNT_THROWN); + } +#endif + /* + * TODO? Force off gloves if either or both rings are going to + * become unworn; force off cloak [suit] before suit [shirt]. + * The torso handling is hyphothetical; the case for gloves is + * not due the possibility of unwearing silver rings. + */ + + dropit = (dropflag == 1); /* all untouchable items */ + do { + scanagain = FALSE; + + for (obj = invent; obj; obj = obj->nobj) { + if (obj->bypass) continue; + + if (untouchable(obj, dropit)) { /* always sets obj->bypass */ + /* 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) + uncurse(uarmg); /* temporary? hack for ring removal plausibility */ + if (had_gloves && !uarmg) selftouch("After losing your gloves, you"); + + if (!--nesting) clear_bypasses(); /* reset upon final exit */ } /*artifact.c*/ diff --git a/src/do_wear.c b/src/do_wear.c index 71a1cb2e7..8fc236f68 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1446,7 +1446,7 @@ dowear() if (!canwearobj(otmp,&mask,TRUE)) return(0); - if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) + if (!retouch_object(&otmp, FALSE)) return 1; /* costs a turn even though it didn't get worn */ if (otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT && @@ -1492,7 +1492,7 @@ dowear() int doputon() { - register struct obj *otmp; + struct obj *otmp; long mask = 0L; if(uleft && uright && uamul && ublindf) { @@ -1566,7 +1566,7 @@ doputon() You("cannot free your weapon hand to put on the ring."); return(0); } - if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) + if (!retouch_object(&otmp, FALSE)) return 1; /* costs a turn even though it didn't get worn */ setworn(otmp, mask); Ring_on(otmp); @@ -1575,7 +1575,7 @@ doputon() already_wearing("an amulet"); return(0); } - if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) + if (!retouch_object(&otmp, FALSE)) return 1; setworn(otmp, W_AMUL); if (otmp->otyp == AMULET_OF_CHANGE) { @@ -1607,7 +1607,7 @@ doputon() You_cant("wear that!"); return(0); } - if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) + if (!retouch_object(&otmp, FALSE)) return 1; Blindf_on(otmp); return(1); diff --git a/src/worn.c b/src/worn.c index 00eabda59..67404cd0e 100644 --- a/src/worn.c +++ b/src/worn.c @@ -638,7 +638,8 @@ clear_bypasses() #endif /*0*/ } } - /* invent and mydogs chains shouldn't matter here */ + for (otmp = invent; otmp; otmp = otmp->nobj) + otmp->bypass = 0; for (otmp = migrating_objs; otmp; otmp = otmp->nobj) otmp->bypass = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { @@ -650,6 +651,7 @@ clear_bypasses() for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; } + /* billobjs and mydogs chains don't matter here */ context.bypasses = FALSE; }