fix bullwhip-induced panic

While testing some corpse/statue name manipulation changes I managed
to trigger a panic during end-of-game cleanup.  Using a bullwhip to
snatch a wielded cockatrice corpse from a monster's inventory into
the hero's inventory and being turned to stone due to lack of gloves
took the corpse out of the monster's inventory but didn't place it
anywhere.  If no life-saving took place, it led to an "obj_is_local"
panic during timer cleanup when freeing the level.

This patch includes some of the stuff I've been testing rather than
just the fix for the panic (which is the very last bit of the diff).
This commit is contained in:
PatR
2021-06-15 18:42:30 -07:00
parent 7088f6a846
commit f6e60c7516
2 changed files with 28 additions and 17 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 apply.c $NHDT-Date: 1621387861 2021/05/19 01:31:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.344 $ */
/* NetHack 3.7 apply.c $NHDT-Date: 1623807747 2021/06/16 01:42:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.345 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
@@ -271,7 +271,7 @@ its_dead(int rx, int ry, int *resp)
humanoid(mptr) ? "person" : "creature");
what = buf;
} else {
what = pmname(mptr, NEUTRAL);
what = obj_pmname(statue);
if (!type_is_pname(mptr))
what = The(what);
}
@@ -1920,6 +1920,7 @@ static void
use_tinning_kit(struct obj *obj)
{
struct obj *corpse, *can;
struct permonst *mptr;
/* This takes only 1 move. If this is to be changed to take many
* moves, we've got to deal with decaying corpses...
@@ -1934,29 +1935,28 @@ use_tinning_kit(struct obj *obj)
You("cannot tin %s which is partly eaten.", something);
return;
}
if (touch_petrifies(&mons[corpse->corpsenm]) && !Stone_resistance
&& !uarmg) {
mptr = &mons[corpse->corpsenm];
if (touch_petrifies(mptr) && !Stone_resistance && !uarmg) {
char kbuf[BUFSZ];
const char *corpse_name = an(cxname(corpse));
if (poly_when_stoned(g.youmonst.data))
You("tin %s without wearing gloves.",
an(mons[corpse->corpsenm].pmnames[NEUTRAL]));
else {
if (poly_when_stoned(g.youmonst.data)) {
You("tin %s without wearing gloves.", corpse_name);
} else {
pline("Tinning %s without wearing gloves is a fatal mistake...",
an(mons[corpse->corpsenm].pmnames[NEUTRAL]));
Sprintf(kbuf, "trying to tin %s without gloves",
an(mons[corpse->corpsenm].pmnames[NEUTRAL]));
corpse_name);
Sprintf(kbuf, "trying to tin %s without gloves", corpse_name);
}
instapetrify(kbuf);
}
if (is_rider(&mons[corpse->corpsenm])) {
if (is_rider(mptr)) {
if (revive_corpse(corpse))
verbalize("Yes... But War does not preserve its enemies...");
else
pline_The("corpse evades your grasp.");
return;
}
if (mons[corpse->corpsenm].cnutrit == 0) {
if (mptr->cnutrit == 0) {
pline("That's too insubstantial to tin.");
return;
}
@@ -2141,7 +2141,7 @@ fig_transform(anything *arg, long timeout)
char monnambuf[BUFSZ], carriedby[BUFSZ];
if (!figurine) {
debugpline0("null figurine in fig_transform()");
impossible("null figurine in fig_transform()");
return;
}
silent = (timeout != g.monstermoves); /* happened while away */
@@ -2908,10 +2908,18 @@ use_whip(struct obj *obj)
&& polymon(PM_STONE_GOLEM))) {
char kbuf[BUFSZ];
Sprintf(kbuf, "%s corpse",
an(mons[otmp->corpsenm].pmnames[NEUTRAL]));
Strcpy(kbuf, (otmp->quan == 1L) ? an(onambuf)
: onambuf);
pline("Snatching %s is a fatal mistake.", kbuf);
/* corpse probably has a rot timer but is now
OBJ_FREE; end of game cleanup will panic if
it isn't part of current level; plus it would
be missing from bones, so put it on the floor */
place_object(otmp, u.ux, u.uy); /* but don't stack */
instapetrify(kbuf);
/* life-saved; free the corpse again */
obj_extract_self(otmp);
}
(void) hold_another_object(otmp, "You drop %s!",
doname(otmp), (const char *) 0);