]> granicus.if.org Git - nethack/commitdiff
fix #K3503 - boulder-carrying monster killed twice
authorPatR <rankin@nethack.org>
Sun, 26 Dec 2021 17:44:10 +0000 (09:44 -0800)
committerPatR <rankin@nethack.org>
Sun, 26 Dec 2021 17:44:10 +0000 (09:44 -0800)
A giant that is carrying a boulder and standing on ice who drowns when
the ice gets melted could die a second time if the resulting pool gets
plugged by the boulder.  It results in an impossible from dmonsfree()
about bookkeeping inconsistency when dead monsters are removed at the
end of the turn.  The fuzzer escalates that to a panic.

doc/fixes37.0
src/do.c

index c18e04a9dda885645e3dc9e0064d6221cc756561..b929cbf6da09459d05865febef2303361746fce3 100644 (file)
@@ -722,6 +722,9 @@ attack feedback when using a bullwhip said "swing"; change to "lash"
 attack feedback for monster using polearm when adjacent said "thrust"; change
        to "bash"
 apply runmode delay to multiturn actions, not just running
+if a giant carrying a boulder was on ice that melted, it could be killed
+       twice, first by drowning, then by boulder filling the resulting pool
+       when it dropped inventory before being removed from the map
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index cde8a8e451e66cdabc6cdde03a13070c796b65ab..bcf8c8f0fb0f4d300f0e0c18560ab17cb7d8cfa2 100644 (file)
--- a/src/do.c
+++ b/src/do.c
@@ -66,7 +66,15 @@ boulder_hits_pool(struct obj *otmp, int rx, int ry, boolean pushing)
             } else
                 levl[rx][ry].typ = ROOM, levl[rx][ry].flags = 0;
 
-            if ((mtmp = m_at(rx, ry)) != 0)
+            /* 3.7: normally DEADMONSTER() is used when traversing the fmon
+               list--dead monsters usually aren't still at specific map
+               locations; however, if ice melts causing a giant to drown,
+               that giant would still be on the map when it drops inventory;
+               if it was carrying a boulder which now fills the pool, 'mtmp'
+               will be dead here; killing it again would yield impossible
+               "dmonsfree: N removed doesn't match N+1 pending" when other
+               monsters have finished their current turn */
+            if ((mtmp = m_at(rx, ry)) != 0 && !DEADMONSTER(mtmp))
                 mondied(mtmp);
 
             if (ttmp)