From a506c32e8c34e3380fc7907ce8a9c967b73bf995 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Tue, 18 Apr 2006 05:26:00 +0000 Subject: [PATCH] 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. --- doc/fixes34.4 | 3 ++ src/zap.c | 81 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/doc/fixes34.4 b/doc/fixes34.4 index 37ed95456..80993755d 100644 --- a/doc/fixes34.4 +++ b/doc/fixes34.4 @@ -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 diff --git a/src/zap.c b/src/zap.c index 7aab24c6f..67c25842e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -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); -- 2.40.0