]> granicus.if.org Git - nethack/commitdiff
avoid lava recursion
authornethack.rankin <nethack.rankin>
Thu, 21 Apr 2011 23:45:02 +0000 (23:45 +0000)
committernethack.rankin <nethack.rankin>
Thu, 21 Apr 2011 23:45:02 +0000 (23:45 +0000)
     Noticed while working on the "lava inconsistencies" patch:  it was
possible for lava_effects() to be called recursively, despite a patch
five and half years ago which was supposed to prevent that.  That patch
handled the case where the hero dies and gets life-saved, but it didn't
deal with a hero who survives due to water walking boots and then has
those burned away.  [Not an issue in 3.4.3 because Boots_off() didn't
call spoteffects() for lava then, but it does in post-3.4.3 branch as
well as trunk.  fixes34.4 has an entry about fixing an "object lost"
panic for this but I don't think it's accurate.  I think that the panic
only became possible after the post-3.4.3 "handle lava when removing or
losing water walking boots" fix was introduced.]

src/trap.c

index f05067fd6381cead7b577dc14ee6dbb833e88892..44123680a08114d54f491c3e75604e2c5d43aad4 100644 (file)
@@ -4732,13 +4732,6 @@ lava_effects()
        return(TRUE);
     }  /* !Fire_resistance */
 
-    if (!Wwalking) {
-       u.utrap = rn1(4, 4) + (rn1(4, 12) << 8);
-       u.utraptype = TT_LAVA;
-       You("sink into the lava, but it only burns slightly!");
-       if (u.uhp > 1)
-           losehp(1, lava_killer, KILLED_BY);  /* lava damage */
-    }
     /* just want to burn boots, not all armor; destroy_item doesn't work on
        armor anyway */
 burn_stuff:
@@ -4747,8 +4740,23 @@ burn_stuff:
        /* save uarmf value because Boots_off() sets uarmf to null */
        obj = uarmf;
        pline("%s into flame!", Yobjnam2(obj, "burst"));
+       iflags.in_lava_effects++;       /* (see above) */
        (void) Boots_off();
        useup(obj);
+       iflags.in_lava_effects--;
+    }
+    if (!Wwalking) {
+       boil_away = !Fire_resistance;
+       /* if not fire resistant, sink_into_lava() will quickly be fatal;
+          hero needs to escape immediately */
+       u.utrap = rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8);
+       u.utraptype = TT_LAVA;
+       You("sink into the lava%s!",
+           !boil_away ? ", but it only burns slightly" :
+                        " and are about to be immolated");
+       if (u.uhp > 1)
+           losehp(!boil_away ? 1 : (u.uhp / 2),
+                  lava_killer, KILLED_BY);     /* lava damage */
     }
     destroy_item(SCROLL_CLASS, AD_FIRE);
     destroy_item(SPBOOK_CLASS, AD_FIRE);
@@ -4767,6 +4775,12 @@ sink_into_lava()
     } else if (!is_lava(u.ux, u.uy)) {
        u.utrap = 0;    /* this shouldn't happen either */
     } else if (!u.uinvulnerable) {
+       /* ordinarily we'd have to be fire resistant to survive long
+          enough to become stuck in lava, but it can happen without
+          resistance if water walking boots allow survival and then
+          get burned up; u.utrap time will be quite short in that case */
+       if (!Fire_resistance) u.uhp = (u.uhp + 2) / 3;
+
        u.utrap -= (1 << 8);
        if (u.utrap < (1 << 8)) {
            killer.format = KILLED_BY;