]> granicus.if.org Git - nethack/commitdiff
recursive spoteffects (trunk only)
authornethack.rankin <nethack.rankin>
Thu, 1 Jun 2006 03:54:25 +0000 (03:54 +0000)
committernethack.rankin <nethack.rankin>
Thu, 1 Jun 2006 03:54:25 +0000 (03:54 +0000)
     Attempt to fix a buglist item:  if hero poly'd into iron golem form
enters a pool of water and drowning triggers reversion to human/whatever
form due to water damage, he will fall into that pool again, crawl or
teleport out, then redundantly crawl or teleport out for the initial entry.
[ spoteffects -> drown -> losehp -> rehumanize -> polyman -> spoteffects
  -> drown ]

     I don't have a lot of confidence in this fix.  It does handle the
reported problem, and hasn't broken a couple of earlier tricky cases
(ice melting to water, land mine turning into a pit).  But drown() and
lava_effects() seem to leave a trail of special case handling wherever
they appear so they--or spoteffects, or both--ought to be redone somehow.

doc/fixes35.0
src/hack.c

index cbc8589ddf9809bbe3c30063d61fb993dfd9aec0..93494c9aef914b5d74411a0d65dbdf7df19e84eb 100644 (file)
@@ -143,6 +143,8 @@ don't give attribute adjustment messages ("you feel wise") unless the current
 meditating monsters stop meditating when affected by something which wakes
        sleeping mosnters
 monsters capable of hiding can't do so when trapped or while holding you
+limit recursive calls to spoteffects (poly'd hero fell into water, reverted
+       to human because of it, fell into same water, then crawled out twice)
 
 
 Platform- and/or Interface-Specific Fixes
index 01627cc04be6804cc7b670d757ea94848ac68ec4..8dfd01bc09b898df3a9ae6d4a98e04a9d933757a 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)hack.c     3.5     2006/04/10      */
+/*     SCCS Id: @(#)hack.c     3.5     2006/05/31      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1504,10 +1504,28 @@ void
 spoteffects(pick)
 boolean pick;
 {
+       static int inspoteffects = 0;
+       static coord spotloc;
+       static int spotterrain;
        static struct trap *spottrap = (struct trap *)0;
        static unsigned spottraptyp = NO_TRAP;
+       struct trap *trap = t_at(u.ux, u.uy);
        register struct monst *mtmp;
-       
+
+       /* prevent recursion from affecting the hero all over again
+          [hero poly'd to iron golem enters water here, drown() inflicts
+          damage that triggers rehumanize() which calls spoteffects()...] */
+       if (inspoteffects && u.ux == spotloc.x && u.uy == spotloc.y &&
+               /* except when reason is transformed terrain (ice -> water) */
+               spotterrain == levl[u.ux][u.uy].typ &&
+               /* or transformed trap (land mine -> pit) */
+               (!spottrap || !trap || trap->ttyp == spottraptyp))
+           return;
+
+       ++inspoteffects;
+       spotterrain = levl[u.ux][u.uy].typ;
+       spotloc.x = u.ux, spotloc.y = u.uy;
+
        if(u.uinwater) {
                int was_underwater;
 
@@ -1552,10 +1570,13 @@ stillinwater:;
                        pick = FALSE;
                } else
 #endif
+               /* drown(),lava_effects() return true if hero changes
+                  location while surviving the problem */
                if (is_lava(u.ux, u.uy)) {
-                   if (lava_effects()) return;
-               } else if (!Wwalking && drown())
-                   return;
+                   if (lava_effects()) goto spotdone;
+               } else if (!Wwalking) {
+                   if (drown()) goto spotdone;
+               }
            }
        }
        check_special_room(FALSE);
@@ -1564,7 +1585,6 @@ stillinwater:;
                dosinkfall();
 #endif
        if (!in_steed_dismounting) { /* if dismounting, we'll check again later */
-               struct trap *trap = t_at(u.ux, u.uy);
                boolean pit;
 
               /*
@@ -1646,6 +1666,12 @@ stillinwater:;
                }
                mnexto(mtmp); /* have to move the monster */
        }
+ spotdone:
+       if (!--inspoteffects) {
+           spotterrain = STONE;        /* 0 */
+           spotloc.x = spotloc.y = 0;
+       }
+       return;
 }
 
 /* returns first matching monster */