1 /** 2 * @file 3 * @brief Travel stuff 4 **/ 5 #pragma once 6 7 #include <cstdio> 8 #include <map> 9 #include <string> 10 #include <vector> 11 12 #include "command-type.h" 13 #include "daction-type.h" 14 #include "exclude.h" 15 #include "travel-defs.h" 16 17 class reader; 18 class writer; 19 20 enum run_check_type 21 { 22 RCHECK_LEFT, 23 RCHECK_FRONT, 24 RCHECK_RIGHT, 25 }; 26 27 enum run_dir_type 28 { 29 RDIR_UP = 0, 30 RDIR_UP_RIGHT, 31 RDIR_RIGHT, 32 RDIR_DOWN_RIGHT, 33 RDIR_DOWN, 34 RDIR_DOWN_LEFT, 35 RDIR_LEFT, 36 RDIR_UP_LEFT, 37 RDIR_REST, 38 }; 39 40 enum run_mode_type 41 { 42 RMODE_INTERLEVEL = -4, // Interlevel travel 43 RMODE_EXPLORE_GREEDY = -3, // Explore + grab items 44 RMODE_EXPLORE = -2, // Exploring 45 RMODE_TRAVEL = -1, // Classic or Plain Old travel 46 RMODE_NOT_RUNNING = 0, // must remain equal to 0 47 RMODE_CONTINUE, 48 RMODE_START, 49 RMODE_WAIT_DURATION = 100, 50 RMODE_REST_DURATION = 9999999, // just rest until fully healed 51 RMODE_CONNECTIVITY, // Pathfinding connectivity check, not running. 52 }; 53 54 /* *********************************************************************** 55 * Initialises the travel subsystem. 56 */ 57 void stop_running(bool clear_delays = true); 58 void travel_init_load_level(); 59 void travel_init_new_level(); 60 61 uint8_t is_waypoint(const coord_def &p); 62 command_type direction_to_command(int x, int y); 63 bool is_resting(); 64 void explore_pickup_event(int did_pickup, int tried_pickup); 65 bool feat_is_traversable_now(dungeon_feature_type feat, bool try_fallback = false); 66 bool feat_is_traversable(dungeon_feature_type feat, bool try_fallback = false); 67 bool is_known_branch_id(branch_type branch); 68 bool is_unknown_stair(const coord_def &p); 69 bool is_unknown_transporter(const coord_def &p); 70 71 void fill_travel_point_distance(const coord_def& youpos, 72 vector<coord_def>* coords = nullptr); 73 74 bool is_stair_exclusion(const coord_def &p); 75 76 /* *********************************************************************** 77 * Initiates explore - the character runs around the level to map it. Note 78 * that the caller has to ensure that the level is mappable before calling 79 * start_explore. start_explore may lock up the game on unmappable levels. 80 * If grab_items is true, greedy explore is triggered - in greedy mode, explore 81 * grabs items that are eligible for autopickup and visits (previously 82 * unvisited) shops. 83 */ 84 void start_explore(bool grab_items = false); 85 void do_explore_cmd(); 86 87 struct level_pos; 88 class level_id; 89 90 level_id find_up_level(level_id curr, bool up_branch = false); 91 level_id find_down_level(level_id curr); 92 93 void start_translevel_travel(const level_pos &pos); 94 95 void start_travel(const coord_def& p); 96 97 command_type travel(); 98 99 void prevent_travel_to(const string &dungeon_feature_name); 100 101 // Sort dungeon features as appropriate. 102 int level_distance(level_id first, level_id second); 103 level_id find_deepest_explored(level_id curr); 104 bool branch_entered(branch_type branch); 105 106 bool can_travel_to(const level_id &lid); 107 bool can_travel_interlevel(); 108 109 enum translevel_prompt_flags 110 { 111 TPF_NO_FLAGS = 0, 112 113 TPF_ALLOW_WAYPOINTS = 0x1, 114 TPF_ALLOW_UPDOWN = 0x2, 115 TPF_REMEMBER_TARGET = 0x4, 116 TPF_SHOW_ALL_BRANCHES = 0x8, 117 TPF_SHOW_PORTALS_ONLY = 0x10, 118 119 TPF_DEFAULT_OPTIONS = TPF_ALLOW_WAYPOINTS | TPF_ALLOW_UPDOWN 120 | TPF_REMEMBER_TARGET, 121 }; 122 123 level_pos prompt_translevel_target(int prompt_flags, string& dest_name); 124 125 // Magic numbers for point_distance: 126 127 // This square is a trap 128 const int PD_TRAP = -42; 129 130 // The user never wants to travel this square 131 const int PD_EXCLUDED = -20099; 132 133 // This square is within LOS radius of an excluded square 134 const int PD_EXCLUDED_RADIUS = -20100; 135 136 // This square has a damaging cloud 137 const int PD_CLOUD = -20101; 138 139 /* *********************************************************************** 140 * Array of points on the map, each value being the distance the character 141 * would have to travel to get there. Negative distances imply that the point 142 * is a) a trap or hostile terrain or b) only reachable by crossing a trap or 143 * hostile terrain. 144 * *********************************************************************** 145 * referenced in: travel - view 146 * *********************************************************************** */ 147 extern travel_distance_grid_t travel_point_distance; 148 149 enum explore_stop_type 150 { 151 ES_NONE = 0x00000, 152 153 // Explored into view of an item that is NOT eligible for autopickup. 154 ES_ITEM = 0x00001, 155 156 // Picked up an item during greedy explore; will stop for anything 157 // that's not explicitly ignored and that is not gold. 158 ES_GREEDY_PICKUP = 0x00002, 159 160 // Stop when picking up gold with greedy explore. 161 ES_GREEDY_PICKUP_GOLD = 0x00004, 162 163 // Picked up an item during greedy explore, ignoring items that were 164 // thrown by the PC, and items that the player already has one of in 165 // inventory, or a bunch of other conditions (see 166 // _interesting_explore_pickup in items.cc) 167 ES_GREEDY_PICKUP_SMART = 0x00008, 168 169 // Greedy-picked up an item previously thrown by the PC. 170 ES_GREEDY_PICKUP_THROWN = 0x00010, 171 ES_GREEDY_PICKUP_MASK = (ES_GREEDY_PICKUP 172 | ES_GREEDY_PICKUP_GOLD 173 | ES_GREEDY_PICKUP_SMART 174 | ES_GREEDY_PICKUP_THROWN), 175 176 // Explored into view of an item eligible for autopickup. 177 ES_GREEDY_ITEM = 0x00020, 178 179 // Stepped onto a stack of items that was previously unknown to 180 // the player (for instance, when stepping onto the heap of items 181 // of a freshly killed monster). 182 ES_GREEDY_VISITED_ITEM_STACK = 0x00040, 183 184 // Explored into view of a stair, shop, altar, portal, glowing 185 // item, artefact, or branch entrance. 186 ES_STAIR = 0x00080, 187 ES_SHOP = 0x00100, 188 ES_ALTAR = 0x00200, 189 ES_PORTAL = 0x00400, 190 ES_GLOWING_ITEM = 0x00800, 191 ES_ARTEFACT = 0x01000, 192 ES_RUNE = 0x02000, 193 ES_BRANCH = 0x04000, 194 ES_RUNED_DOOR = 0x08000, 195 ES_TRANSPORTER = 0x10000, 196 }; 197 198 //////////////////////////////////////////////////////////////////////////// 199 // Structs for interlevel travel. 200 201 // Tracks items discovered by explore in this turn. 202 class LevelStashes; 203 class explore_discoveries 204 { 205 public: 206 explore_discoveries(); 207 208 void found_feature(const coord_def &pos, dungeon_feature_type grid); 209 void found_item(const coord_def &pos, const item_def &item); 210 211 // Reports discoveries and stops exploration (if necessary). 212 bool stop_explore() const; 213 214 private: 215 template <class Z> struct named_thing 216 { 217 string name; 218 Z thing; 219 named_thingnamed_thing220 named_thing(const string &n, Z t) : name(n), thing(t) { } stringnamed_thing221 operator string () const { return name; } 222 223 bool operator == (const named_thing<Z> &other) const 224 { 225 return name == other.name; 226 } 227 }; 228 229 bool can_autopickup; 230 int es_flags; 231 const LevelStashes *current_level; 232 vector< named_thing<item_def> > items; 233 vector< named_thing<int> > stairs; 234 vector< named_thing<int> > portals; 235 vector< named_thing<int> > shops; 236 vector< named_thing<int> > altars; 237 vector< named_thing<int> > runed_doors; 238 vector< named_thing<int> > transporters; 239 240 vector<string> marker_msgs; 241 vector<string> marked_feats; 242 243 private: 244 template <class C> void say_any(const C &coll, const char *category) const; 245 template <class citer> bool has_duplicates(citer, citer) const; 246 247 string cleaned_feature_description(const coord_def &) const; 248 void add_item(const item_def &item); 249 void add_stair(const named_thing<int> &stair); 250 vector<string> apply_quantities(const vector< named_thing<int> > &v) const; 251 bool merge_feature(vector< named_thing<int> > &v, 252 const named_thing<int> &feat) const; 253 }; 254 255 struct stair_info 256 { 257 public: 258 enum stair_type 259 { 260 PHYSICAL, 261 PLACEHOLDER, 262 MAPPED, 263 }; 264 265 public: 266 coord_def position; // Position of stair 267 dungeon_feature_type grid; // Grid feature of the stair. 268 level_pos destination; // The level and the position on the level this 269 // stair leads to. This may be a guess. 270 int distance; // The distance travelled to reach this stair. 271 bool guessed_pos; // true if we're not sure that 'destination' is 272 // correct. 273 stair_type type; 274 stair_infostair_info275 stair_info() 276 : position(-1, -1), grid(DNGN_FLOOR), destination(), 277 distance(-1), guessed_pos(true), type(PHYSICAL) 278 { 279 } 280 clear_distancestair_info281 void clear_distance() { distance = -1; } 282 283 void save(writer&) const; 284 void load(reader&); 285 286 string describe() const; 287 can_travelstair_info288 bool can_travel() const { return type != PLACEHOLDER; } 289 }; 290 291 struct transporter_info 292 { 293 public: 294 enum transporter_type 295 { 296 PHYSICAL, 297 MAPPED, 298 }; 299 300 public: 301 coord_def position; // Position of transporter 302 coord_def destination; // The position on the level this transporter leads 303 // to. 304 transporter_type type; 305 transporter_infotransporter_info306 transporter_info(const coord_def &p, const coord_def &d, 307 transporter_type t) 308 : position(p), destination(d), type(t) { 309 } 310 transporter_infotransporter_info311 transporter_info() 312 : position(-1, -1), destination(), type(PHYSICAL) { 313 } 314 315 void save(writer&) const; 316 void load(reader&); 317 }; 318 319 // Information on a level that interlevel travel needs. 320 struct LevelInfo 321 { LevelInfoLevelInfo322 LevelInfo() : stairs(), excludes(), stair_distances(), id() 323 { 324 daction_counters.init(0); 325 } 326 327 void save(writer&) const; 328 void load(reader&, int minorVersion); 329 get_stairsLevelInfo330 vector<stair_info> &get_stairs() 331 { 332 return stairs; 333 } 334 get_transportersLevelInfo335 vector<transporter_info> &get_transporters() 336 { 337 return transporters; 338 } 339 340 stair_info *get_stair(const coord_def &pos); 341 transporter_info *get_transporter(const coord_def &pos); 342 bool empty() const; 343 bool know_stair(const coord_def &pos) const; 344 bool know_transporter(const coord_def &pos) const; 345 int get_stair_index(const coord_def &pos) const; 346 int get_transporter_index(const coord_def &pos) const; 347 348 void clear_distances(); 349 void set_level_excludes(); 350 get_excludesLevelInfo351 const exclude_set &get_excludes() const 352 { 353 return excludes; 354 } 355 356 // Returns the travel distance between two stairs. If either stair is nullptr, 357 // or does not exist in our list of stairs, returns 0. 358 int distance_between(const stair_info *s1, const stair_info *s2) const; 359 360 void update_excludes(); 361 void update(); // Update LevelInfo to be correct for the 362 // current level. 363 364 // Updates/creates a StairInfo for the stair at stairpos in grid coordinates 365 void update_stair(const coord_def& stairpos, const level_pos &p, 366 bool guess = false); 367 void update_transporter(const coord_def& transpos, const coord_def &dest); 368 369 // Clears all stair info for stairs matching this grid type. 370 void clear_stairs(dungeon_feature_type grid); 371 372 // Returns true if the given branch is known to be accessible from the 373 // current level. 374 bool is_known_branch(uint8_t branch) const; 375 376 FixedVector<int, NUM_DACTION_COUNTERS> daction_counters; 377 378 private: 379 // Gets a list of coordinates of all player-known stairs on the current 380 // level. 381 static void get_stairs(vector<coord_def> &stairs); 382 static void get_transporters(vector<coord_def> &transporters); 383 384 void correct_stair_list(const vector<coord_def> &s); 385 void correct_transporter_list(const vector<coord_def> &s); 386 void update_stair_distances(); 387 void sync_all_branch_stairs(); 388 void sync_branch_stairs(const stair_info *si); 389 void set_distance_between_stairs(int a, int b, int dist); 390 void fixup(); 391 392 private: 393 vector<stair_info> stairs; 394 vector<transporter_info> transporters; 395 396 // Squares that are not safe to travel to. 397 exclude_set excludes; 398 399 vector<short> stair_distances; // Dist between stairs 400 level_id id; 401 402 friend class TravelCache; 403 404 private: 405 void create_placeholder_stair(const coord_def &, const level_pos &); 406 void resize_stair_distances(); 407 }; 408 409 const int TRAVEL_WAYPOINT_COUNT = 10; 410 // Tracks all levels that the player has seen. 411 class TravelCache 412 { 413 public: 414 void clear_distances(); 415 get_level_info(const level_id & lev)416 LevelInfo& get_level_info(const level_id &lev) 417 { 418 LevelInfo &li = levels[lev]; 419 li.id = lev; 420 return li; 421 } 422 find_level_info(const level_id & lev)423 LevelInfo *find_level_info(const level_id &lev) 424 { 425 map<level_id, LevelInfo>::iterator i = levels.find(lev); 426 return i != levels.end()? &i->second : nullptr; 427 } 428 erase_level_info(const level_id & lev)429 void erase_level_info(const level_id& lev) 430 { 431 levels.erase(lev); 432 } 433 434 bool know_stair(const coord_def &c); 435 bool know_transporter(const coord_def &c); know_level(const level_id & lev)436 bool know_level(const level_id &lev) const 437 { 438 return levels.count(lev); 439 } 440 vector<level_id> known_levels() const; 441 get_waypoint(int number)442 const level_pos &get_waypoint(int number) const 443 { 444 return waypoints[number]; 445 } 446 447 int get_waypoint_count() const; 448 449 void set_level_excludes(); 450 451 void add_waypoint(int x = -1, int y = -1); 452 void set_waypoint(int waynum, int x, int y); 453 void delete_waypoint(); 454 uint8_t is_waypoint(const level_pos &lp) const; 455 void list_waypoints() const; 456 void update_waypoints() const; 457 458 void update_excludes(); 459 void update(); 460 void update_transporter(const coord_def &c); 461 462 void save(writer&) const; 463 void load(reader&, int minorVersion); 464 465 bool is_known_branch(uint8_t branch) const; 466 467 void update_daction_counters(); // of the current level 468 469 unsigned int query_daction_counter(daction_type c); 470 void clear_daction_counter(daction_type c); 471 472 private: 473 void update_stone_stair(const coord_def &c); 474 void fixup_levels(); 475 476 private: 477 typedef map<level_id, LevelInfo> travel_levels_map; 478 travel_levels_map levels; 479 level_pos waypoints[TRAVEL_WAYPOINT_COUNT]; 480 }; 481 482 // Handles travel and explore floodfill pathfinding. Does not do interlevel 483 // travel pathfinding directly (but is used internally by interlevel travel). 484 // * All coordinates are grid coords. 485 // * Do not reuse one travel_pathfind for different runmodes. 486 class travel_pathfind 487 { 488 public: 489 travel_pathfind(); 490 virtual ~travel_pathfind(); 491 492 // Finds travel direction or explore target. 493 // If fallback_explore is set, will consider temporary obstructions like 494 // sealed doors as traversable 495 coord_def pathfind(run_mode_type rt, bool fallback_explore = false); 496 497 // For flood-fills (explore), sets starting (seed) square. 498 void set_floodseed(const coord_def &seed, bool double_flood = false); 499 500 // For regular travel, set starting point (usually the character's current 501 // position) and destination. 502 void set_src_dst(const coord_def &src, const coord_def &dst); 503 504 // Set feature vector to use; if non-nullptr, also sets annotate_map to 505 // true. 506 void set_feature_vector(vector<coord_def> *features); 507 508 // Extract features without pathfinding 509 void get_features(); 510 511 // The next square to go to to move towards the travel destination. Return 512 // value is undefined if pathfind was not called with RMODE_TRAVEL. 513 const coord_def travel_move() const; 514 515 // Square to go to for (greedy) explore. Return value is undefined if 516 // pathfind was not called with RMODE_EXPLORE or RMODE_EXPLORE_GREEDY. 517 const coord_def explore_target() const; 518 set_ignore_danger()519 inline void set_ignore_danger() 520 { 521 ignore_danger = true; 522 } 523 524 // Determine if the level is fully explored, when called after pathfind(). 525 int explore_status(); 526 527 protected: 528 bool is_greed_inducing_square(const coord_def &c) const; 529 bool path_examine_point(const coord_def &c); 530 virtual bool point_traverse_delay(const coord_def &c); 531 virtual bool path_flood(const coord_def &c, const coord_def &dc); 532 bool square_slows_movement(const coord_def &c); 533 void check_square_greed(const coord_def &c); 534 void good_square(const coord_def &c); 535 536 protected: 537 static const int UNFOUND_DIST = -30000; 538 static const int INFINITE_DIST = INFINITE_DISTANCE; 539 540 protected: 541 run_mode_type runmode; 542 543 // Where pathfinding starts, and the destination. Note that dest is not 544 // relevant for explore! 545 coord_def start, dest; 546 547 // This is the square adjacent to the starting position to move 548 // along the shortest path to the destination. Does *not* apply 549 // for explore! 550 coord_def next_travel_move; 551 552 // True if flooding outwards from start square for explore. 553 bool floodout, double_flood; 554 555 // Set true in the second part of a double floodfill to completely ignore 556 // hostile squares. 557 bool ignore_hostile; 558 559 // Set to true for Tiles mode clicking, so you can move one step 560 // at a time through excluded areas and around stationary monsters. 561 bool ignore_danger; 562 563 // If true, use magic numbers in point distance array which can be 564 // used to colour the level-map. 565 bool annotate_map; 566 567 // Stashes on this level (needed for greedy explore and to populate the 568 // feature vector with stashes on the X level-map). 569 const LevelStashes *ls; 570 571 // Are we greedy exploring? 572 bool need_for_greed; 573 574 // Can we autopickup? 575 bool autopickup; 576 577 // Targets for explore and greedy explore. 578 coord_def unexplored_place, greedy_place; 579 580 // How far from player's location unexplored_place and greedy_place are. 581 int unexplored_dist, greedy_dist; 582 583 const int *refdist; 584 585 // For double-floods, the points to restart floodfill from at the end of 586 // the first flood. 587 vector<coord_def> reseed_points; 588 589 vector<coord_def> *features; 590 591 // List of unexplored and unreachable points. 592 set<coord_def> unreachables; 593 594 travel_distance_col *point_distance; 595 596 // How many points we'll consider next iteration. 597 int next_iter_points; 598 599 // How far we've travelled from (start_x, start_y), in moves (a diagonal move 600 // is no longer than an orthogonal move). 601 int traveled_distance; 602 603 // Which index of the circumference array are we currently looking at? 604 int circ_index; 605 606 // Used by all instances of travel_pathfind. Happily, we do not need to be 607 // re-entrant or thread-safe. 608 static FixedVector<coord_def, GXM * GYM> circumference[2]; 609 610 // Attempt to path through temporary obstructions (like sealed doors) 611 // due to the possibility they are no longer obstructing us 612 bool try_fallback; 613 }; 614 615 extern TravelCache travel_cache; 616 617 void do_interlevel_travel(); 618 619 // Travel from a mouse click. Take one step if not safe. Attack if adjacent. 620 // If force is true, then the player will attack empty squares/open doors. 621 #ifdef USE_TILE 622 bool click_travel_safe(const coord_def &gc); 623 int click_travel(const coord_def &gc, bool force); 624 #endif 625 626 bool check_for_interesting_features(); 627 void clear_level_target(); 628 629 void clear_travel_trail(); 630 int travel_trail_index(const coord_def& gc); 631 632 bool stairs_destination_is_excluded(const stair_info &si); 633