Fix travel moving player back and forth infinitely

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.
This commit is contained in:
Tung Nguyen
2016-03-11 00:24:40 +11:00
parent 7cf75b707a
commit 3ed1aedeb7

View 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)