]> granicus.if.org Git - nethack/commitdiff
fix #H1826 - split long worm with 0 hit points
authornethack.rankin <nethack.rankin>
Fri, 6 Mar 2009 02:22:14 +0000 (02:22 +0000)
committernethack.rankin <nethack.rankin>
Fri, 6 Mar 2009 02:22:14 +0000 (02:22 +0000)
     From a bug report, a long worm with 0 HP
was observed via stethoscope after cutting one or more worms in half many
times, followed by an unspecified crash.  Cutting a worm doesn't reduce
its level below 3, but if a worm is drained to level 0 by some other means
and then gets cut in half (and still has at least 2 HP left), cutworm()
would give the new level 0 worm 0d8 (hence 0) for current and max HP.
That could confuse end-of-move monster cleanup, which thinks 0 HP is a
dead monster who has been removed from the map but not yet purged from the
fmon list.  Purging it would then leave a stale monster pointer on the map.

     cutworm() should have special cased level 0 to use 1d4 for HP, but
instead I've changed it to not produce a cloned worm if the source one is
lower than level 3.

doc/fixes34.4
src/worm.c

index 63f635b9e752274e85332cae8b2f2a2b54adb53b..41281b004cb063af257c9bc06fca958e2c29856e 100644 (file)
@@ -366,6 +366,7 @@ could get "suddenly you cannot see the <mon>" while invisible mon remained
        displayed due to telepathy or extended detection
 cutting a long worm in half would trigger segfault/accvio crash if the hit
        took parent down to 1 hit point or if long worms had become extinct
+cutting a level 0 long worm in half produced a new worm with 0 hit points
 blinded invisible hero can't see self as invisible via ';' or '/'
 a hangup save while picking up gold from shop floor could duplicate that gold
 jellyfish do not technically have a head
index aac8ce41f48e181cdb064f68643e9660d7afe6df..4f0dcc59ba8d38b586aaa5023d15ce7c0d857d45 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)worm.c     3.5     2007/07/15      */
+/*     SCCS Id: @(#)worm.c     3.5     2009/03/05      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -363,11 +363,12 @@ cutworm(worm, x, y, weap)
 
     /*
      *  At this point, the old worm is correct.  Any new worm will have
-     *  it's head at "curr" and its tail at "new_tail".
+     *  it's head at "curr" and its tail at "new_tail".  The old worm   
+     *  must be at least level 3 in order to produce a new worm.
      */
 
     new_worm = 0;
-    new_wnum = rn2(3) ? 0 : get_wormno();
+    new_wnum = (worm->m_lev >= 3 && !rn2(3)) ? get_wormno() : 0;
     if (new_wnum) {
        remove_monster(x, y);   /* clone_mon puts new head here */
        /* clone_mon() will fail if enough long worms have been
@@ -392,19 +393,16 @@ cutworm(worm, x, y, weap)
     new_worm->wormno = new_wnum;       /* affix new worm number */
     new_worm->mcloned = 0;     /* treat second worm as a normal monster */
 
-    /* Devalue the monster level of both halves of the worm. */
-    worm->m_lev = ((unsigned)worm->m_lev <= 3) ?
-                  (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
+    /* Devalue the monster level of both halves of the worm.
+       Note: m_lev is always at least 3 in order to get this far. */
+    worm->m_lev = max((unsigned)worm->m_lev - 2, 3);
     new_worm->m_lev = worm->m_lev;
 
-    /* Calculate the mhp on the new_worm for the (lower) monster level. */
+    /* Calculate the lower-level mhp; use <N>d8 for long worms.
+       Can't use newmonhp() here because it would reset m_lev. */
     new_worm->mhpmax = new_worm->mhp = d((int)new_worm->m_lev, 8);
-
-    /* Calculate the mhp on the old worm for the (lower) monster level. */
-    if (worm->m_lev > 3) {
-       worm->mhpmax = d((int)worm->m_lev, 8);
-       if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax;
-    }
+    worm->mhpmax = d((int)worm->m_lev, 8);     /* new maxHP for old worm */
+    if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax;
 
     wtails[new_wnum] = new_tail;       /* We've got all the info right now */
     wheads[new_wnum] = curr;           /* so we can do this faster than    */