Apply the new ground_level method.
[crawl.git] / crawl-ref / source / mon-pathfind.cc
blob857d98948ca7513b431b93bb3bf999bc9a4c0f2e
1 #include "AppHdr.h"
3 #include "mon-pathfind.h"
5 #include "coord.h"
6 #include "directn.h"
7 #include "env.h"
8 #include "mon-place.h"
9 #include "mon-stuff.h"
10 #include "mon-util.h"
11 #include "monster.h"
12 #include "random.h"
13 #include "terrain.h"
14 #include "traps.h"
16 /////////////////////////////////////////////////////////////////////////////
17 // monster_pathfind
19 // The pathfinding is an implementation of the A* algorithm. Beginning at the
20 // destination square we check all neighbours of a given grid, estimate the
21 // distance needed for any shortest path including this grid and push the
22 // result into a hash. We can then easily access all points with the shortest
23 // distance estimates and then check _their_ neighbours and so on.
24 // The algorithm terminates once we reach the monster position since - because
25 // of the sorting of grids by shortest distance in the hash - there can be no
26 // path between start and target that is shorter than the current one. There
27 // could be other paths that have the same length but that has no real impact.
28 // If the hash has been cleared and the start grid has not been encountered,
29 // then there's no path that matches the requirements fed into monster_pathfind.
30 // (These requirements are usually preference of habitat of a specific monster
31 // or a limit of the distance between start and any grid on the path.)
33 int mons_tracking_range(const monster* mon)
36 int range = 0;
37 switch (mons_intel(mon))
39 case I_PLANT:
40 range = 2;
41 break;
42 case I_INSECT:
43 range = 4;
44 break;
45 case I_ANIMAL:
46 range = 5;
47 break;
48 case I_NORMAL:
49 range = LOS_RADIUS;
50 break;
51 default:
52 // Highly intelligent monsters can find their way
53 // anywhere. (range == 0 means no restriction.)
54 break;
57 if (range)
59 if (mons_is_native_in_branch(mon))
60 range += 3;
61 else if (mons_class_flag(mon->type, M_BLOOD_SCENT))
62 range++;
65 if (you.penance[GOD_ASHENZARI])
66 range *= 5;
68 return (range);
71 //#define DEBUG_PATHFIND
72 monster_pathfind::monster_pathfind()
73 : mons(NULL), start(), target(), pos(), allow_diagonals(true),
74 traverse_unmapped(false), range(0), min_length(0), max_length(0),
75 dist(), prev(), hash()
79 monster_pathfind::~monster_pathfind()
83 void monster_pathfind::set_range(int r)
85 if (r >= 0)
86 range = r;
89 coord_def monster_pathfind::next_pos(const coord_def &c) const
91 return c + Compass[prev[c.x][c.y]];
94 // The main method in the monster_pathfind class.
95 // Returns true if a path was found, else false.
96 bool monster_pathfind::init_pathfind(const monster* mon, coord_def dest,
97 bool diag, bool msg, bool pass_unmapped)
99 mons = mon;
101 // We're doing a reverse search from target to monster.
102 start = dest;
103 target = mon->pos();
104 pos = start;
105 allow_diagonals = diag;
106 traverse_unmapped = pass_unmapped;
108 // Easy enough. :P
109 if (start == target)
111 if (msg)
112 mpr("The monster is already there!");
114 return (true);
117 return start_pathfind(msg);
120 bool monster_pathfind::init_pathfind(coord_def src, coord_def dest, bool diag,
121 bool msg)
123 start = src;
124 target = dest;
125 pos = start;
126 allow_diagonals = diag;
128 // Easy enough. :P
129 if (start == target)
130 return (true);
132 return start_pathfind(msg);
135 bool monster_pathfind::start_pathfind(bool msg)
137 // NOTE: We never do any traversable() check for the starting square
138 // (target). This means that even if the target cannot be reached
139 // we may still find a path leading adjacent to this position, which
140 // is desirable if e.g. the player is hovering over deep water
141 // surrounded by shallow water or floor, or if a foe is hiding in
142 // a wall.
143 // If the surrounding squares also are not traversable, we return
144 // early that no path could be found.
146 max_length = min_length = grid_distance(pos, target);
147 for (int i = 0; i < GXM; i++)
148 for (int j = 0; j < GYM; j++)
149 dist[i][j] = INFINITE_DISTANCE;
151 dist[pos.x][pos.y] = 0;
153 bool success = false;
156 // Calculate the distance to all neighbours of the current position,
157 // and add them to the hash, if they haven't already been looked at.
158 success = calc_path_to_neighbours();
159 if (success)
160 return (true);
162 // Pull the position with shortest distance estimate to our target grid.
163 success = get_best_position();
165 if (!success)
167 if (msg)
169 mprf("Couldn't find a path from (%d,%d) to (%d,%d).",
170 target.x, target.y, start.x, start.y);
172 return (false);
175 while (true);
178 // Returns true as soon as we encounter the target.
179 bool monster_pathfind::calc_path_to_neighbours()
181 coord_def npos;
182 int distance, old_dist, total;
184 // For each point, we look at all neighbour points. Check the orthogonals
185 // last, so that, should an orthogonal and a diagonal direction have the
186 // same total travel cost, the orthogonal will be picked first, and thus
187 // zigzagging will be significantly reduced.
189 // 1 0 3 This means directions are looked at, in order,
190 // \ | / 1, 3, 5, 7 (diagonals) followed by 0, 2, 4, 6
191 // 6--.--2 (orthogonals). This is achieved by the assignment
192 // / | \ of (dir = 0) once dir has passed 7.
193 // 7 4 5
195 // To avoid bias, we'll choose a random 90 degree rotation
196 int rotate = random2(4) * 2; // equal probability of 0,2,4,6
197 for (int idir = 1; idir < 8; (idir += 2) == 9 && (idir = 0))
199 // Skip diagonal movement.
200 if (!allow_diagonals && (idir % 2))
201 continue;
203 int dir = (idir + rotate) % 8; // apply our random 90 degree rotation
205 npos = pos + Compass[dir];
207 #ifdef DEBUG_PATHFIND
208 mprf("Looking at neighbour (%d,%d)", npos.x, npos.y);
209 #endif
210 if (!in_bounds(npos))
211 continue;
213 if (!traversable(npos))
214 continue;
216 // Ignore this grid if it takes us above the allowed distance.
217 if (range && estimated_cost(npos) > range)
218 continue;
220 distance = dist[pos.x][pos.y] + travel_cost(npos);
221 old_dist = dist[npos.x][npos.y];
222 #ifdef DEBUG_PATHFIND
223 mprf("old dist: %d, new dist: %d, infinite: %d", old_dist, distance,
224 INFINITE_DISTANCE);
225 #endif
226 // If the new distance is better than the old one (initialised with
227 // INFINITE), update the position.
228 if (distance < old_dist)
230 // Calculate new total path length.
231 total = distance + estimated_cost(npos);
232 if (old_dist == INFINITE_DISTANCE)
234 #ifdef DEBUG_PATHFIND
235 mprf("Adding (%d,%d) to hash (total dist = %d)",
236 npos.x, npos.y, total);
237 #endif
238 add_new_pos(npos, total);
239 if (total > max_length)
240 max_length = total;
242 else
244 #ifdef DEBUG_PATHFIND
245 mprf("Improving (%d,%d) to total dist %d",
246 npos.x, npos.y, total);
247 #endif
249 update_pos(npos, total);
252 // Update distance start->pos.
253 dist[npos.x][npos.y] = distance;
255 // Set backtracking information.
256 // Converts the Compass direction to its counterpart.
257 // 0 1 2 4 5 6
258 // 7 . 3 ==> 3 . 7 e.g. (3 + 4) % 8 = 7
259 // 6 5 4 2 1 0 (7 + 4) % 8 = 11 % 8 = 3
261 prev[npos.x][npos.y] = (dir + 4) % 8;
263 // Are we finished?
264 if (npos == target)
266 #ifdef DEBUG_PATHFIND
267 mpr("Arrived at target.");
268 #endif
269 return (true);
273 return (false);
276 // Starting at known min_length (minimum total estimated path distance), check
277 // the hash for existing vectors, then pick the last entry of the first vector
278 // that matches. Update min_length, if necessary.
279 bool monster_pathfind::get_best_position()
281 for (int i = min_length; i <= max_length; i++)
283 if (!hash[i].empty())
285 if (i > min_length)
286 min_length = i;
288 std::vector<coord_def> &vec = hash[i];
289 // Pick the last position pushed into the vector as it's most
290 // likely to be close to the target.
291 pos = vec[vec.size()-1];
292 vec.pop_back();
294 #ifdef DEBUG_PATHFIND
295 mprf("Returning (%d, %d) as best pos with total dist %d.",
296 pos.x, pos.y, min_length);
297 #endif
299 return (true);
301 #ifdef DEBUG_PATHFIND
302 mprf("No positions for path length %d.", i);
303 #endif
306 // Nothing found? Then there's no path! :(
307 return (false);
310 // Using the prev vector backtrack from start to target to find all steps to
311 // take along the shortest path.
312 std::vector<coord_def> monster_pathfind::backtrack()
314 #ifdef DEBUG_PATHFIND
315 mpr("Backtracking...");
316 #endif
317 std::vector<coord_def> path;
318 pos = target;
319 path.push_back(pos);
321 if (pos == start)
322 return path;
324 int dir;
327 dir = prev[pos.x][pos.y];
328 pos = pos + Compass[dir];
329 ASSERT(in_bounds(pos));
330 #ifdef DEBUG_PATHFIND
331 mprf("prev: (%d, %d), pos: (%d, %d)", Compass[dir].x, Compass[dir].y,
332 pos.x, pos.y);
333 #endif
334 path.push_back(pos);
336 if (pos.x == 0 && pos.y == 0)
337 break;
339 while (pos != start);
340 ASSERT(pos == start);
342 return (path);
345 // Reduces the path coordinates to only a couple of key waypoints needed
346 // to reach the target. Waypoints are chosen such that from one waypoint you
347 // can see (and, more importantly, reach) the next one. Note that
348 // can_go_straight() is probably rather too conservative in these estimates.
349 // This is done because Crawl's pathfinding - once a target is in sight and easy
350 // reach - is both very robust and natural, especially if we want to flexibly
351 // avoid plants and other monsters in the way.
352 std::vector<coord_def> monster_pathfind::calc_waypoints()
354 std::vector<coord_def> path = backtrack();
356 // If no path found, nothing to be done.
357 if (path.empty())
358 return path;
360 dungeon_feature_type can_move =
361 (mons_habitat(mons) == HT_AMPHIBIOUS) ? DNGN_DEEP_WATER
362 : DNGN_SHALLOW_WATER;
364 std::vector<coord_def> waypoints;
365 pos = path[0];
367 #ifdef DEBUG_PATHFIND
368 mpr("\nWaypoints:");
369 #endif
370 for (unsigned int i = 1; i < path.size(); i++)
372 if (can_go_straight(pos, path[i], can_move))
373 continue;
374 else
376 pos = path[i-1];
377 waypoints.push_back(pos);
378 #ifdef DEBUG_PATHFIND
379 mprf("waypoint: (%d, %d)", pos.x, pos.y);
380 #endif
384 // Add the actual target to the list of waypoints, so we can later check
385 // whether a tracked enemy has moved too much, in case we have to update
386 // the path.
387 if (pos != path[path.size() - 1])
388 waypoints.push_back(path[path.size() - 1]);
390 return (waypoints);
393 bool monster_pathfind::traversable(const coord_def& p)
395 if (!traverse_unmapped && grd(p) == DNGN_UNSEEN)
396 return (false);
398 // XXX: Hack to be somewhat consistent with uses of
399 // opc_immob elsewhere in pathfinding.
400 // All of this should eventually be replaced by
401 // giving the monster a proper pathfinding LOS.
402 if (opc_immob(p) == OPC_OPAQUE)
403 return (false);
405 if (mons)
406 return mons_traversable(p);
408 return feat_has_solid_floor(grd(p));
411 // Checks whether a given monster can pass over a certain position, respecting
412 // its preferred habit and capability of flight or opening doors.
413 bool monster_pathfind::mons_traversable(const coord_def& p)
415 return (mons_can_traverse(mons, p));
418 int monster_pathfind::travel_cost(coord_def npos)
420 if (mons)
421 return mons_travel_cost(npos);
423 return (1);
426 // Assumes that grids that really cannot be entered don't even get here.
427 // (Checked by traversable().)
428 int monster_pathfind::mons_travel_cost(coord_def npos)
430 ASSERT(grid_distance(pos, npos) <= 1);
432 // Doors need to be opened.
433 if (feat_is_closed_door(grd(npos)) || grd(npos) == DNGN_SECRET_DOOR
434 && env.markers.property_at(npos, MAT_ANY, "door_restict") != "veto")
436 return (2);
439 const monster_type mt = mons_base_type(mons);
440 const bool airborne = mons_airborne(mt, -1, false);
442 // Travelling through water, entering or leaving water is more expensive
443 // for non-amphibious monsters, so they'll avoid it where possible.
444 // (The resulting path might not be optimal but it will lead to a path
445 // a monster of such habits is likely to prefer.)
446 // Only tested for shallow water since they can't enter deep water anyway.
447 if (!airborne && !mons_class_habitat(mt) == HT_AMPHIBIOUS
448 && (grd(pos) == DNGN_SHALLOW_WATER || grd(npos) == DNGN_SHALLOW_WATER))
450 return (2);
453 // Try to avoid (known) traps.
454 const trap_def* ptrap = find_trap(npos);
455 if (ptrap)
457 const bool knows_trap = ptrap->is_known(mons);
458 const trap_type tt = ptrap->type;
459 if (tt == TRAP_ALARM || tt == TRAP_ZOT)
461 // Your allies take extra precautions to avoid known alarm traps.
462 // Zot traps are considered intraversable.
463 if (knows_trap && mons->friendly())
464 return (3);
466 // To hostile monsters, these traps are completely harmless.
467 return (1);
470 // Mechanical traps can be avoided by flying, as can shafts, and
471 // tele traps are never traversable anyway.
472 if (knows_trap && !airborne)
473 return (2);
476 return (1);
479 // The estimated cost to reach a grid is simply max(dx, dy).
480 int monster_pathfind::estimated_cost(coord_def p)
482 return (grid_distance(p, target));
485 void monster_pathfind::add_new_pos(coord_def npos, int total)
487 hash[total].push_back(npos);
490 void monster_pathfind::update_pos(coord_def npos, int total)
492 // Find hash position of old distance and delete it,
493 // then call_add_new_pos.
494 int old_total = dist[npos.x][npos.y] + estimated_cost(npos);
496 std::vector<coord_def> &vec = hash[old_total];
497 for (unsigned int i = 0; i < vec.size(); i++)
499 if (vec[i] == npos)
501 vec.erase(vec.begin() + i);
502 break;
506 add_new_pos(npos, total);