diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index c648fd898..a4bdf6e2d 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1854,6 +1854,10 @@ debug fuzzer was triggering out of bounds array access in loseexp() if levels and restored those all the way to level 30; introducing an assert(u.ulevel < MAXULEV) changed bounds issue to assertion failure strength less than 25 was unintentionally being capped at 18/07 +if an amulet of flying gets stolen while hero is over lava without other + protection against lava, it will be destroyed even though it isn't + flammable, then attempting to format it for messages will trigger an + impossible warning about "glorkum", then a crash occurs Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/steal.c b/src/steal.c index 29999de41..80d33ab3d 100644 --- a/src/steal.c +++ b/src/steal.c @@ -312,6 +312,7 @@ int steal(struct monst* mtmp, char* objnambuf) { struct obj *otmp; + char Monnambuf[BUFSZ]; int tmp, could_petrify, armordelay, olddelay, icnt, named = 0, retrycnt = 0; boolean monkey_business, /* true iff an animal is doing the thievery */ @@ -394,6 +395,13 @@ steal(struct monst* mtmp, char* objnambuf) if (otmp->o_id == gs.stealoid) return 0; + /* stealing a worn item might drop hero into water or lava where + teleporting to safety could result in a previously visible thief + no longer being visible; remember the name in order to avoid "It" + in the eventual " stole " message; (the name might + already be "It"; if so, that's ok) */ + Strcpy(Monnambuf, Monnam(mtmp)); + if (otmp->otyp == BOULDER && !throws_rocks(mtmp->data)) { if (!retrycnt++) goto retry; @@ -420,7 +428,7 @@ steal(struct monst* mtmp, char* objnambuf) static const char *const how[] = { "steal", "snatch", "grab", "take" }; cant_take: - pline("%s tries to %s %s%s but gives up.", Monnam(mtmp), + pline("%s tries to %s %s%s but gives up.", Monnambuf, ROLL_FROM(how), (otmp->owornmask & W_ARMOR) ? "your " : "", (otmp->owornmask & W_ARMOR) ? equipname(otmp) @@ -474,7 +482,7 @@ steal(struct monst* mtmp, char* objnambuf) slowly = (armordelay >= 1 || gm.multi < 0); if (flags.female) urgent_pline("%s charms you. You gladly %s your %s.", - !seen ? "She" : Monnam(mtmp), + !seen ? "She" : Monnambuf, curssv ? "let her take" : !slowly ? "hand over" : was_doffing ? "continue removing" @@ -523,7 +531,7 @@ steal(struct monst* mtmp, char* objnambuf) subfrombill(otmp, shop_keeper(*u.ushops)); freeinv(otmp); /* if attached ball was taken, uball and uchain are now Null */ - urgent_pline("%s%s stole %s.", named ? "She" : Monnam(mtmp), + urgent_pline("%s%s stole %s.", named ? "She" : Monnambuf, (was_punished && !Punished) ? " removed your chain and" : "", doname(otmp)); (void) encumber_msg(); diff --git a/src/trap.c b/src/trap.c index 5e46a03b6..321a38798 100644 --- a/src/trap.c +++ b/src/trap.c @@ -6516,6 +6516,7 @@ lava_effects(void) { register struct obj *obj, *obj2; boolean usurvive, boil_away; + unsigned protect_oid = 0; int burncount = 0, burnmesgcount = 0; int dmg = d(6, 6); /* only applicable for water walking */ @@ -6539,14 +6540,34 @@ lava_effects(void) * that player causing hangup at --More-- won't get an * emergency save file created before item destruction. */ - if (!usurvive) - for (obj = gi.invent; obj; obj = obj->nobj) + if (!usurvive) { + for (obj = gi.invent; obj; obj = obj->nobj) { + if (obj->in_use) { /* remove_worn_item() sets in_use */ + /* one item can be protected from burning up [accommodates + steal(AMULET_OF_FLYING) -> remove_worn_item() -> drop + into lava (which happens before item is transferred + from invent to thief->minvent)]; item will still be in + inventory when we return to caller or save bones (or + perform hangup save if that occurs) */ + if (!protect_oid) { + protect_oid = obj->o_id; + obj->in_use = 0; + } else { + impossible( + "lava_effects: '%s' (#%u) is already in use; so is #%u.", + simpleonames(obj), obj->o_id, protect_oid); + } + continue; + } + /* set obj->in_use for items which will be destroyed below */ if ((is_organic(obj) || obj->oclass == POTION_CLASS) && !obj->oerodeproof && objects[obj->otyp].oc_oprop != FIRE_RES && obj->otyp != SCR_FIRE && obj->otyp != SPE_FIREBALL && !obj_resists(obj, 0, 0)) /* for invocation items */ obj->in_use = 1; + } + } /* Check whether we should burn away boots *first* so we know whether to * make the player sink into the lava. Assumption: water walking only @@ -6554,7 +6575,7 @@ lava_effects(void) * (3.7: that assumption is no longer true, but having boots be the first * thing to come into contact with lava makes sense.) */ - if (uarmf && is_organic(uarmf) && !uarmf->oerodeproof) { + if (uarmf && uarmf->in_use) { obj = uarmf; pline("%s into flame!", Yobjnam2(obj, "burst")); ++burnmesgcount; @@ -6589,7 +6610,9 @@ lava_effects(void) for (obj = gi.invent; obj; obj = obj2) { obj2 = obj->nobj; /* above, we set in_use for objects which are to be destroyed */ - if (obj->otyp == SPE_BOOK_OF_THE_DEAD && !Blind) { + if (obj->o_id == protect_oid) { + ; /* skip protected item; caller expects to retain access */ + } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD && !Blind) { if (usurvive) pline("%s glows a strange %s, but remains intact.", The(xname(obj)), hcolor("dark red"));