]> granicus.if.org Git - nethack/commitdiff
fix #H79 - steed disintegration
authornethack.rankin <nethack.rankin>
Tue, 18 Apr 2006 05:26:00 +0000 (05:26 +0000)
committernethack.rankin <nethack.rankin>
Tue, 18 Apr 2006 05:26:00 +0000 (05:26 +0000)
     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
src/zap.c

index 37ed9545612ea3814acfe7219ffefd9e1e87acb9..80993755d317e522ec716d310a4028672ad590ba 100644 (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
index 7aab24c6fd6575a86e0e65038f1b025615487a7e..67c25842e7802ba1474786d9c4d957b7f98eb4a4 100644 (file)
--- 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);