diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 2c6b4fd92..542ce3b44 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -287,6 +287,9 @@ when probing from inside an engulfer, "not carrying anything" overlooked hero wearing or removing an amulet of restful sleep clobbered permanent sleepiness if attempt to select a co-aligned artifact for first divine gift fails because none is available, choose one from among nonaligned artifacts +if breaking a wand of polymorph causes hero to drop items, don't transform them +if polymorph causes a monster to drop items, they won't be used up via + shuddering vibrations or as golem creation fodder Platform- and/or Interface-Specific Fixes diff --git a/src/apply.c b/src/apply.c index c97cd8558..9036c6ee8 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)apply.c 3.5 2008/03/07 */ +/* SCCS Id: @(#)apply.c 3.5 2008/10/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2891,6 +2891,7 @@ do_break_wand(obj) /* we want this before the explosion instead of at the very end */ pline("A wall of force smashes down around you!"); dmg = d(1 + obj->spe,6); /* normally 2d12 */ + /*FALLTHRU*/ case WAN_CANCELLATION: case WAN_POLYMORPH: case WAN_TELEPORTATION: @@ -2902,6 +2903,9 @@ do_break_wand(obj) } /* magical explosion and its visual effect occur before specific effects */ + /* [TODO? This really ought to prevent the explosion from being + fatal so that we never leave a bones file where none of the + surrounding targets (or underlying objects) got affected yet.] */ explode(obj->ox, obj->oy, -(obj->otyp), rnd(dmg), WAND_CLASS, EXPL_MAGICAL); /* this makes it hit us last, so that we can see the action first */ @@ -2942,23 +2946,17 @@ do_break_wand(obj) /* u.ux,u.uy creates it near you--x,y might create it in rock */ (void) makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS); continue; - } else { - if (x == u.ux && y == u.uy) { - /* teleport objects first to avoid race with tele control and - autopickup. Other wand/object effects handled after - possible wand damage is assessed */ - if (obj->otyp == WAN_TELEPORTATION && - affects_objects && level.objects[x][y]) { - (void) bhitpile(obj, bhito, x, y); - if (context.botl) bot(); /* potion effects */ - } - damage = zapyourself(obj, FALSE); - if (damage) { - Sprintf(buf, "killed %sself by breaking a wand", uhim()); - losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX); - } - if (context.botl) bot(); /* blindness */ - } else if ((mon = m_at(x, y)) != 0) { + } else if (x != u.ux || y != u.uy) { + /* + * Wand breakage is targetting a square adjacent to the hero, + * which might contain a monster or a pile of objects or both. + * Handle objects last; avoids having undead turning raise an + * undead's corpse and then attack resulting undead monster. + * obj->bypass in bhitm() prevents the polymorphing of items + * dropped due to monster's polymorph and prevents undead + * turning that kills an undead from raising resulting corpse. + */ + if ((mon = m_at(x, y)) != 0) { (void) bhitm(mon, obj); /* if (context.botl) bot(); */ } @@ -2966,6 +2964,29 @@ do_break_wand(obj) (void) bhitpile(obj, bhito, x, y); if (context.botl) bot(); /* potion effects */ } + } else { + /* + * Wand breakage is targetting the hero. Using xdir[]+ydir[] + * deltas for location selection causes this case to happen + * after all the surrounding squares have been handled. + * Process objects first, in case damage is fatal and leaves + * bones, or teleportation sends one or more of the objects to + * same destination as hero (lookhere/autopickup); also avoids + * the polymorphing of gear dropped due to hero's transformation. + * (Unlike with monsters being hit by zaps, we can't rely on use + * of obj->bypass in the zap code to accomplish that last case + * since it's also used by retouch_equipment() for polyself.) + */ + if (affects_objects && level.objects[x][y]) { + (void) bhitpile(obj, bhito, x, y); + if (context.botl) bot(); /* potion effects */ + } + damage = zapyourself(obj, FALSE); + if (damage) { + Sprintf(buf, "killed %sself by breaking a wand", uhim()); + losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX); + } + if (context.botl) bot(); /* blindness */ } } diff --git a/src/zap.c b/src/zap.c index 7047faffd..4fd68681e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)zap.c 3.5 2008/03/19 */ +/* SCCS Id: @(#)zap.c 3.5 2008/10/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1088,6 +1088,8 @@ struct obj *obj; { int zap_odds; + if (context.bypasses && obj->bypass) return FALSE; + if (obj->oclass == WAND_CLASS) zap_odds = 3; /* half-life = 2 zaps */ else if (obj->cursed) @@ -1117,6 +1119,7 @@ polyuse(objhdr, mat, minwt) for(otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) { otmp2 = otmp->nexthere; + if (context.bypasses && otmp->bypass) continue; if (otmp == uball || otmp == uchain) continue; if (obj_resists(otmp, 0, 0)) continue; /* preserve unique objects */ #ifdef MAIL @@ -1156,6 +1159,14 @@ create_polymon(obj, okind) const char *material; int pm_index; + if (context.bypasses) { + /* this is approximate because the "no golems" !obj->nexthere + check below doesn't understand bypassed objects; but it + should suffice since bypassed objects always end up as a + consecutive group at the top of their pile */ + while (obj && obj->bypass) obj = obj->nexthere; + } + /* no golems if you zap only one object -- not enough stuff */ if(!obj || (!obj->nexthere && obj->quan == 1L)) return;