fix #H79 - steed disintegration

From a bug report, a steed hit by disintegration
breath survived via life-saving, but the program was confused about whether
the hero could still ride and issued some impossible warnings.  The code
to disintegrate a monster's inventory didn't bother to unwear worn items as
it destroyed them, presumeably assuming that the monster was sure to die,
so steed was left with a flag bit set claiming it was saddled even though
the saddle was gone.  This fixes that, and the rider will end up being
dismounted as the saddle gets destroyed, regardless of whether the steed
ultimately survives.  [Since the steed is still present at the time of
dismounting, the hero will get bumped to some other location, possibly to
the next spot about to be hit by the same black dragon breath attack which
just vaporized the steed.  That's suboptimal, to put it mildly....]

     I couldn't test the circumstances of the original report.  Post-3.4.3,
ki-rin has been marked no-hands and is no longer capable of wearing armor
or amulets.  I looked to see whether any other potential steed could wear
an amulet of life-saving and couldn't find one.  But the original bug also
applied to conferred properties of special armor worn by non-steed monsters
too, so the fix was needed anyway.

     The branch and trunk patches are different.  For the trunk, I moved a
big chunk of code out of buzz() into a seperate routine.  That actual fix
is the same in both variants.
This commit is contained in:
nethack.rankin
2006-04-18 05:26:00 +00:00
parent fc9c337e27
commit a506c32e8c
2 changed files with 53 additions and 31 deletions

View File

@@ -211,6 +211,9 @@ monsters who ate lizard corpses to cure confusion would lose intrinsic speed
monsters couldn't eat lizard corpses to cure being stunned
code handling a monster's use of potion or food to cure stoning or confusion
was accessing freed memory after the object had been used up
properly handle destruction of equipment carried by monsters hit by
disintegration breath; life-saving retained conferred properties of
formerly worn items (loss of steed's saddle caused much confusion)
Platform- and/or Interface-Specific Fixes

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)zap.c 3.5 2006/04/14 */
/* SCCS Id: @(#)zap.c 3.5 2006/04/17 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -32,6 +32,7 @@ STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
STATIC_DCL void FDECL(skiprange, (int,int *,int *));
STATIC_DCL int FDECL(zap_hit, (int,int));
STATIC_OVL void FDECL(disintegrate_mon, (struct monst *,int,const char *));
STATIC_DCL void FDECL(backfire, (struct obj *));
STATIC_DCL int FDECL(spell_hit_bonus, (int));
@@ -3438,6 +3439,53 @@ int type; /* either hero cast spell type or 0 */
return (3 - chance) < ac+spell_bonus;
}
STATIC_OVL void
disintegrate_mon(mon, type, fltxt)
struct monst *mon;
int type; /* hero vs other */
const char *fltxt;
{
struct obj *otmp, *otmp2, *m_amulet = mlifesaver(mon);
if (canseemon(mon)) {
if (!m_amulet)
pline("%s is disintegrated!", Monnam(mon));
else
hit(fltxt, mon, "!");
}
/* note: worn amulet of life saving must be preserved in order to operate */
#define oresist_disintegration(obj) \
(objects[obj->otyp].oc_oprop == DISINT_RES || \
obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \
obj == m_amulet)
for (otmp = mon->minvent; otmp; otmp = otmp2) {
otmp2 = otmp->nobj;
if (!oresist_disintegration(otmp)) {
if (otmp->owornmask) {
/* in case monster's life gets saved */
mon->misc_worn_check &= ~otmp->owornmask;
/* also dismounts hero if this object is steed's saddle */
update_mon_intrinsics(mon, otmp, FALSE, TRUE);
otmp->owornmask = 0L;
}
obj_extract_self(otmp);
obfree(otmp, (struct obj *)0);
}
}
#ifndef GOLDOBJ
mon->mgold = 0L;
#endif
#undef oresist_disintegration
if (type < 0)
monkilled(mon, (char *)0, -AD_RBRE);
else
xkilled(mon, 2);
}
/* type == 0 to 9 : you shooting a wand */
/* type == 10 to 19 : you casting a spell */
/* type == 20 to 29 : you breathing as a monster */
@@ -3556,36 +3604,7 @@ register int dx,dy;
}
if (tmp == MAGIC_COOKIE) { /* disintegration */
struct obj *otmp2, *m_amulet = mlifesaver(mon);
if (canseemon(mon)) {
if (!m_amulet)
pline("%s is disintegrated!", Monnam(mon));
else
hit(fltxt, mon, "!");
}
#ifndef GOLDOBJ
mon->mgold = 0L;
#endif
/* note: worn amulet of life saving must be preserved in order to operate */
#define oresist_disintegration(obj) \
(objects[obj->otyp].oc_oprop == DISINT_RES || \
obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \
obj == m_amulet)
for (otmp = mon->minvent; otmp; otmp = otmp2) {
otmp2 = otmp->nobj;
if (!oresist_disintegration(otmp)) {
obj_extract_self(otmp);
obfree(otmp, (struct obj *)0);
}
}
if (type < 0)
monkilled(mon, (char *)0, -AD_RBRE);
else
xkilled(mon, 2);
disintegrate_mon(mon, type, fltxt);
} else if(mon->mhp < 1) {
if(type < 0)
monkilled(mon, fltxt, AD_RBRE);