]> granicus.if.org Git - nethack/commitdiff
Fix travel moving player back and forth infinitely
authorTung Nguyen <tungtn3@gmail.com>
Thu, 10 Mar 2016 13:24:40 +0000 (00:24 +1100)
committerTung Nguyen <tungtn3@gmail.com>
Thu, 10 Mar 2016 13:24:40 +0000 (00:24 +1100)
This fixes a bug where hundreds of turns are wasted by the travel system
moving the player back and forth when the player targets an unreachable
space and sight-blocking obstacles occur in certain formations
in-between.  The player will only be stopped if they're interrupted
externally, e.g. growing hungry or being hit by a monster.  See the
comment in the code for full details.

Based on DynaHack commit 02da53e (Fix travel moving player back and
forth repeatedly) by me.

src/hack.c

index 6ce28907afe31b471b993f888f73294034bfb650..0669978cbfd2b82cfa63aabd04340f5afe7e2657 100644 (file)
@@ -929,7 +929,42 @@ boolean guess;
                     int nx = x + xdir[ordered[dir]];
                     int ny = y + ydir[ordered[dir]];
 
-                    if (!isok(nx, ny))
+                    /*
+                     * When guessing and trying to travel as close as possible
+                     * to an unreachable target space, don't include spaces
+                     * that would never be picked as a guessed target in the
+                     * travel matrix describing player-reachable spaces.
+                     * This stops travel from getting confused and moving the
+                     * player back and forth in certain degenerate configurations
+                     * of sight-blocking obstacles, e.g.
+                     *
+                     *    T         1. Dig this out and carry enough to not be
+                     *      ####       able to squeeze through diagonal gaps.
+                     *      #--.---    Stand at @ and target travel at space T.
+                     *       @.....
+                     *       |.....
+                     *
+                     *    T         2. couldsee() marks spaces marked a and x as
+                     *      ####       eligible guess spaces to move the player
+                     *      a--.---    towards.  Space a is closest to T, so it gets
+                     *       @xxxxx    chosen.  Travel system moves @ right to travel
+                     *       |xxxxx    to space a.
+                     *
+                     *    T         3. couldsee() marks spaces marked b, c and x
+                     *      ####       as eligible guess spaces to move the player
+                     *      a--c---    towards.  Since findtravelpath() is called
+                     *       b@xxxx    repeatedly during travel, it doesn't remember
+                     *       |xxxxx    that it wanted to go to space a, so in
+                     *                 comparing spaces b and c, b is chosen, since
+                     *                 it seems like the closest eligible space to T.
+                     *                 Travel system moves @ left to go to space b.
+                     *
+                     *              4. Go to 2.
+                     *
+                     * By limiting the travel matrix here, space a in the example
+                     * above is never included in it, preventing the cycle.
+                     */
+                    if (!isok(nx, ny) || (guess && !couldsee(nx, ny)))
                         continue;
                     if ((!Passes_walls && !can_ooze(&youmonst)
                          && closed_door(x, y)) || sobj_at(BOULDER, x, y)