diff --git a/doc/fixes34.4 b/doc/fixes34.4 index 300998f01..87b403319 100644 --- a/doc/fixes34.4 +++ b/doc/fixes34.4 @@ -167,6 +167,8 @@ a samurai quest guardian message used "ninja" where "ronin" was intended revive from fainting if vault guard or bribe-demanding demon approaches tame flaming spheres and shocking spheres shouldn't pick up items can hear the opening or closing of an unseen drawbridge +prevent "object lost" panic caused by accessing freed memory after worn + non-fireproof water walking boots are destroyed by lava Platform- and/or Interface-Specific Fixes diff --git a/include/context.h b/include/context.h index 3e8ae3781..676cabf54 100644 --- a/include/context.h +++ b/include/context.h @@ -80,6 +80,7 @@ struct context_info { /* 8: travel */ unsigned startingpet_mid; int warnlevel; + int in_lava_effects; /* hack for Boots_off() */ long next_attrib_check; /* next attribute check */ long stethoscope_move; short stethoscope_movement; diff --git a/src/do_wear.c b/src/do_wear.c index 402492ef9..43cd21285 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)do_wear.c 3.5 2004/11/11 */ +/* SCCS Id: @(#)do_wear.c 3.5 2005/12/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -35,6 +35,7 @@ STATIC_PTR int NDECL(Boots_on); STATIC_DCL int NDECL(Cloak_on); STATIC_PTR int NDECL(Helmet_on); STATIC_PTR int NDECL(Gloves_on); +STATIC_DCL void FDECL(wielding_corpse, (struct obj *,BOOLEAN_P)); STATIC_PTR int NDECL(Shield_on); #ifdef TOURIST STATIC_PTR int NDECL(Shirt_on); @@ -151,7 +152,9 @@ Boots_off() /* check for lava since fireproofed boots make it viable */ if ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) && !Levitation && !Flying && !is_clinger(youmonst.data) && - !context.takeoff.cancelled_don) { + !context.takeoff.cancelled_don && + /* avoid recursive call to lava_effects() */ + !context.in_lava_effects) { /* make boots known in case you survive the drowning */ makeknown(otyp); spoteffects(TRUE); @@ -407,6 +410,29 @@ Gloves_on() return 0; } +STATIC_OVL void +wielding_corpse(obj, voluntary) +struct obj *obj; +boolean voluntary; /* taking gloves off on purpose? */ +{ + char kbuf[BUFSZ]; + + if (!obj || obj->otyp != CORPSE) return; + if (obj != uwep && (obj != uswapwep || !u.twoweap)) return; + + if (touch_petrifies(&mons[obj->corpsenm]) && !Stone_resistance) { + You("now wield %s in your bare %s.", + the(corpse_xname(obj, TRUE)), + makeplural(body_part(HAND))); + Sprintf(kbuf, "%s gloves while wielding %s", + voluntary ? "removing" : "losing", + killer_xname(obj)); + instapetrify(kbuf); + /* life-saved; can't continue wielding cockatrice corpse though */ + remove_worn_item(obj, FALSE); + } +} + int Gloves_off() { @@ -414,6 +440,7 @@ Gloves_off() u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES; context.takeoff.mask &= ~W_ARMG; + boolean on_purpose = !context.mon_moving && !uarmg->in_use; switch(uarmg->otyp) { case LEATHER_GLOVES: @@ -435,30 +462,15 @@ Gloves_off() context.takeoff.cancelled_don = FALSE; (void) encumber_msg(); /* immediate feedback for GoP */ - /* Prevent wielding cockatrice when not wearing gloves */ - if (uwep && uwep->otyp == CORPSE && - touch_petrifies(&mons[uwep->corpsenm])) { - char kbuf[BUFSZ]; + /* prevent wielding cockatrice when not wearing gloves */ + if (uwep && uwep->otyp == CORPSE) + wielding_corpse(uwep, on_purpose); - You("wield the %s in your bare %s.", - corpse_xname(uwep, TRUE), makeplural(body_part(HAND))); - Strcpy(kbuf, an(corpse_xname(uwep, TRUE))); - instapetrify(kbuf); - uwepgone(); /* life-saved still doesn't allow touching cockatrice */ - } - - /* KMH -- ...or your secondary weapon when you're wielding it */ - if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE && - touch_petrifies(&mons[uswapwep->corpsenm])) { - char kbuf[BUFSZ]; - - You("wield the %s in your bare %s.", - corpse_xname(uswapwep, TRUE), body_part(HAND)); - - Strcpy(kbuf, an(corpse_xname(uswapwep, TRUE))); - instapetrify(kbuf); - uswapwepgone(); /* lifesaved still doesn't allow touching cockatrice */ - } + /* KMH -- ...or your secondary weapon when you're wielding it + [This case can't actually happen; twoweapon mode won't + engage if a corpse has been set up as the alternate weapon.] */ + if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE) + wielding_corpse(uswapwep, on_purpose); return 0; } @@ -2127,7 +2139,8 @@ register struct obj *atmp; register struct obj *otmp; #define DESTROY_ARM(o) ((otmp = (o)) != 0 && \ (!atmp || atmp == otmp) && \ - (!obj_resists(otmp, 0, 90))) + (!obj_resists(otmp, 0, 90)) ? \ + (otmp->in_use = TRUE) : FALSE) if (DESTROY_ARM(uarmc)) { if (donning(otmp)) cancel_don(); diff --git a/src/read.c b/src/read.c index cc6069ea7..008eea41c 100644 --- a/src/read.c +++ b/src/read.c @@ -729,19 +729,23 @@ struct obj *sobj; /* KMH -- catch underflow */ s = sobj->cursed ? -otmp->spe : otmp->spe; if (s > (special_armor ? 5 : 3) && rn2(s)) { - pline("%s violently %s%s%s for a while, then %s.", - Yname2(otmp), - otense(otmp, Blind ? "vibrate" : "glow"), - (!Blind && !same_color) ? " " : nul, - (Blind || same_color) ? nul : - hcolor(sobj->cursed ? NH_BLACK : NH_SILVER), - otense(otmp, "evaporate")); + otmp->in_use = TRUE; + pline("%s violently %s%s%s for a while, then %s.", + Yname2(otmp), + otense(otmp, Blind ? "vibrate" : "glow"), + (!Blind && !same_color) ? " " : nul, + (Blind || same_color) ? nul : + hcolor(sobj->cursed ? NH_BLACK : NH_SILVER), + otense(otmp, "evaporate")); if(is_cloak(otmp)) (void) Cloak_off(); if(is_boots(otmp)) (void) Boots_off(); if(is_helmet(otmp)) (void) Helmet_off(); if(is_gloves(otmp)) (void) Gloves_off(); if(is_shield(otmp)) (void) Shield_off(); if(otmp == uarm) (void) Armor_gone(); +#ifdef TOURIST + if (is_shirt(otmp)) (void) Shirt_off(); +#endif useup(otmp); break; } diff --git a/src/trap.c b/src/trap.c index b3c530a23..ec60c7fca 100644 --- a/src/trap.c +++ b/src/trap.c @@ -4095,17 +4095,23 @@ boolean lava_effects() { register struct obj *obj, *obj2; - int dmg; + int dmg = d(6, 6); /* only applicable for water walking */ boolean usurvive; + usurvive = Fire_resistance || (Wwalking && dmg < u.uhp); + /* a timely interrupt might manage to salvage your life + but not your gear; do this before messages */ + if (!usurvive) + for (obj = invent; obj; obj = obj->nobj) + if (is_organic(obj) && !obj->oerodeproof) obj->in_use = TRUE; + burn_away_slime(); if (likes_lava(youmonst.data)) return FALSE; if (!Fire_resistance) { if(Wwalking) { - dmg = d(6,6); pline_The("lava here burns you!"); - if(dmg < u.uhp) { + if (usurvive) { losehp(dmg, lava_killer, KILLED_BY); /* lava damage */ goto burn_stuff; } @@ -4116,6 +4122,13 @@ lava_effects() #ifdef WIZARD if (wizard) usurvive = TRUE; #endif + + /* prevent Boots_off() -> spoteffects() -> lava_effects() recursion + which would successfully delete (via useupall) the no-longer-worn + boots; once recursive call returned, we would try to delete them + again here in the outer call (access stale memory, probably panic) */ + context.in_lava_effects++; + for(obj = invent; obj; obj = obj2) { obj2 = obj->nobj; if(is_organic(obj) && !obj->oerodeproof) { @@ -4130,7 +4143,7 @@ lava_effects() else if(obj == uarmg) (void) Gloves_off(); else if(obj == uarmf) (void) Boots_off(); #ifdef TOURIST - else if(obj == uarmu) setnotworn(obj); + else if(obj == uarmu) (void) Shirt_off(); #endif else if(obj == uleft) Ring_gone(obj); else if(obj == uright) Ring_gone(obj); @@ -4144,6 +4157,8 @@ lava_effects() } } + context.in_lava_effects--; + /* s/he died... */ u.uhp = -1; killer.format = KILLED_BY;