1 /** 2 * @defgroup mapdef Map Parsing 3 * @brief Parse .des files into map objects. 4 * @section DESCRIPTION 5 * 6 * mapdef.h: 7 * Header for map structures used by the level compiler. 8 * 9 * NOTE: When we refer to map, this could be a full map, filling an entire 10 * level or a minivault that occupies just a portion of the level. 11 */ 12 13 #pragma once 14 15 #include <cstdio> 16 #include <memory> 17 #include <stdexcept> 18 #include <string> 19 #include <vector> 20 #include <unordered_set> 21 22 #include "dlua.h" 23 #include "enum.h" 24 #include "fprop.h" 25 #include "god-type.h" 26 #include "makeitem.h" 27 #include "matrix.h" 28 #include "mon-attitude-type.h" 29 #include "mon-ench.h" 30 #include "mon-flags.h" 31 #include "tags.h" 32 #include "trap-type.h" 33 #include "travel-defs.h" 34 35 #define NEVER_CORPSE_KEY "never_corpse" 36 37 #define RANDBK_OWNER_KEY "randbook_owner" 38 #define RANDBK_TITLE_KEY "randbook_title" 39 #define RANDBK_DISC1_KEY "randbook_disc1" 40 #define RANDBK_DISC2_KEY "randbook_disc2" 41 #define RANDBK_SPELLS_KEY "randbook_spells" 42 #define RANDBK_SLVLS_KEY "randbook_slevels" 43 #define RANDBK_NSPELLS_KEY "randbook_num_spells" 44 45 #ifdef DEBUG_TAG_PROFILING 46 void tag_profile_out(); 47 #endif 48 49 class mon_enchant; 50 extern const char *traversable_glyphs; 51 52 // Invalid heightmap height. 53 static const int INVALID_HEIGHT = -31999; 54 55 static const int BRANCH_END = 100; 56 57 // Exception thrown when a map cannot be loaded from its .dsc file 58 // because the .dsc file has changed under it. 59 struct map_load_exception : public runtime_error 60 { 61 // g++ 4.7 doesn't have inherited constructors, sadly map_load_exceptionmap_load_exception62 map_load_exception(const string &s) : runtime_error(s) { } map_load_exceptionmap_load_exception63 map_load_exception(const char *s) : runtime_error(s) { } 64 }; 65 66 // [dshaligram] Maps can be mirrored; for every orientation, there must be 67 // a suitable mirror. 68 enum map_section_type // see maps.cc and dungeon.cc {dlb} 69 { 70 MAP_NONE = -1, 71 MAP_NORTH = 1, // 1 72 MAP_SOUTH, 73 MAP_EAST, 74 MAP_WEST, 75 MAP_NORTHWEST, // 5 76 MAP_NORTHEAST, 77 MAP_SOUTHWEST, 78 MAP_SOUTHEAST, 79 MAP_ENCOMPASS, 80 81 // A "floating" vault is placed somewhat like a minivault, away from 82 // the edges, although in other respects it behaves like a regular vault. 83 MAP_FLOAT, 84 85 // Place at the centre of the map, and use a "central" layout. 86 MAP_CENTRE, 87 88 MAP_NUM_SECTION_TYPES 89 }; 90 91 struct raw_range 92 { 93 branch_type branch; 94 int shallowest, deepest; 95 bool deny; 96 }; 97 98 struct level_range 99 { 100 public: 101 branch_type branch; 102 int shallowest, deepest; 103 bool deny; 104 105 public: 106 level_range(const raw_range &range); 107 /// @throws bad_level_id if d < s and d != -1. 108 level_range(branch_type br = BRANCH_DUNGEON, int s = -1, int d = -1); 109 110 /// @throws bad_level_id if d < s and d != -1. 111 void set(int s, int d = -1); 112 /// @throws bad_level_id if d < s, d < 0, or branch could not be parsed. 113 void set(const string &branch, int s, int d); 114 115 void reset(); 116 bool matches(const level_id &) const; 117 bool matches(int depth) const; 118 119 void write(writer&) const; 120 void read(reader&); 121 122 bool valid() const; 123 124 /// @throws bad_level_id if lr does not specify a valid level range. 125 static level_range parse(string lr); 126 127 string describe() const; 128 string str_depth_range() const; 129 130 bool operator == (const level_range &lr) const; 131 132 operator raw_range () const; stringlevel_range133 operator string () const 134 { 135 return describe(); 136 } 137 138 private: 139 /// @throws bad_level_id if s does not specify a valid level range. 140 static void parse_partial(level_range &lr, const string &s); 141 /// @throws bad_level_id if s does not specify a valid level range. 142 static void parse_depth_range(const string &s, int *low, int *high); 143 }; 144 145 typedef pair<int,int> glyph_weighted_replacement_t; 146 typedef vector<glyph_weighted_replacement_t> glyph_replacements_t; 147 148 class map_lines; 149 150 class subst_spec 151 { 152 public: 153 subst_spec(string torepl, bool fix, const glyph_replacements_t &repls); 154 subst_spec(int count, bool fix, const glyph_replacements_t &repls); subst_spec()155 subst_spec() : key(""), count(-1), fix(false), frozen_value(0), repl() { } 156 157 int value(); 158 159 public: 160 string key; 161 // If this is part of an nsubst spec, how many to replace. 162 // -1 corresponds to all (i.e. '*') 163 int count; 164 165 bool fix; 166 int frozen_value; 167 168 glyph_replacements_t repl; 169 }; 170 171 class nsubst_spec 172 { 173 public: 174 nsubst_spec(string key, const vector<subst_spec> &specs); 175 public: 176 string key; 177 vector<subst_spec> specs; 178 }; 179 180 typedef pair<int, int> map_weighted_colour; 181 class map_colour_list : public vector<map_weighted_colour> 182 { 183 public: 184 bool parse(const string &s, int weight); 185 }; 186 class colour_spec 187 { 188 public: colour_spec(string _key,bool _fix,const map_colour_list & clist)189 colour_spec(string _key, bool _fix, const map_colour_list &clist) 190 : key(_key), fix(_fix), fixed_colour(BLACK), colours(clist) 191 { 192 } 193 194 int get_colour(); 195 196 public: 197 string key; 198 bool fix; 199 int fixed_colour; 200 map_colour_list colours; 201 }; 202 203 typedef pair<feature_property_type, int> map_weighted_fprop; 204 class map_fprop_list : public vector<map_weighted_fprop> 205 { 206 public: 207 bool parse(const string &fp, int weight); 208 }; 209 210 typedef pair<int, int> map_weighted_fheight; 211 class map_featheight_list : public vector<map_weighted_fheight> 212 { 213 public: 214 bool parse(const string &fp, int weight); 215 }; 216 217 class fprop_spec 218 { 219 public: fprop_spec(string _key,bool _fix,const map_fprop_list & flist)220 fprop_spec(string _key, bool _fix, const map_fprop_list &flist) 221 : key(_key), fix(_fix), fixed_prop(FPROP_NONE), fprops(flist) 222 { 223 } 224 225 feature_property_type get_property(); 226 227 public: 228 string key; 229 bool fix; 230 feature_property_type fixed_prop; 231 map_fprop_list fprops; 232 }; 233 234 class fheight_spec 235 { 236 public: fheight_spec(string _key,bool _fix,const map_featheight_list & _fheights)237 fheight_spec(string _key, bool _fix, const map_featheight_list &_fheights) 238 : key(_key), fix(_fix), fixed_height(INVALID_HEIGHT), 239 fheights(_fheights) 240 { 241 } 242 int get_height(); 243 public: 244 string key; 245 bool fix; 246 int fixed_height; 247 map_featheight_list fheights; 248 }; 249 250 typedef pair<string, int> map_weighted_tile; 251 class map_tile_list : public vector<map_weighted_tile> 252 { 253 public: 254 bool parse(const string &s, int weight); 255 }; 256 257 class tile_spec 258 { 259 public: tile_spec(const string & _key,bool _fix,bool _rand,bool _last,bool _floor,bool _feat,const map_tile_list & _tiles)260 tile_spec(const string &_key, bool _fix, bool _rand, bool _last, bool _floor, bool _feat, const map_tile_list &_tiles) 261 : key(_key), fix(_fix), chose_fixed(false), no_random(_rand), last_tile(_last), floor(_floor), feat(_feat), 262 fixed_tile(""), tiles(_tiles) 263 { 264 } 265 266 string get_tile(); 267 268 public: 269 string key; 270 bool fix; 271 bool chose_fixed; 272 bool no_random; 273 bool last_tile; 274 bool floor; 275 bool feat; 276 string fixed_tile; 277 map_tile_list tiles; 278 }; 279 280 class map_marker_spec 281 { 282 public: 283 string key; 284 string marker; 285 286 // Special handling for Lua markers: 287 unique_ptr<lua_datum> lua_fn; 288 map_marker_spec(string _key,const string & mark)289 map_marker_spec(string _key, const string &mark) 290 : key(_key), marker(mark), lua_fn() { } 291 map_marker_spec(string _key,const lua_datum & fn)292 map_marker_spec(string _key, const lua_datum &fn) 293 : key(_key), marker(), lua_fn(new lua_datum(fn)) { } 294 295 string apply_transform(map_lines &map); 296 297 private: 298 map_marker *create_marker(); 299 }; 300 301 typedef pair<string, int> map_weighted_string; 302 class map_string_list : public vector<map_weighted_string> 303 { 304 public: 305 bool parse(const string &fp, int weight); 306 }; 307 class string_spec 308 { 309 public: string_spec(string _key,bool _fix,const map_string_list & slist)310 string_spec(string _key, bool _fix, const map_string_list &slist) 311 : key(_key), fix(_fix), fixed_str(""), strlist(slist) 312 { 313 } 314 315 string get_property(); 316 317 public: 318 string key; 319 bool fix; 320 string fixed_str; 321 map_string_list strlist; 322 }; 323 324 typedef pair<coord_def, coord_def> map_corner_t; 325 class map_def; 326 class rectangle_iterator; 327 struct keyed_mapspec; 328 class map_lines 329 { 330 public: 331 class iterator 332 { 333 public: 334 iterator(map_lines &ml, const string &key); 335 operator bool () const; 336 coord_def operator ++ (); 337 coord_def operator ++ (int); 338 coord_def operator * () const; 339 private: 340 void advance(); 341 private: 342 map_lines &maplines; 343 string key; 344 coord_def p; 345 }; 346 347 public: 348 map_lines(); 349 map_lines(const map_lines &); 350 ~map_lines(); 351 352 map_lines &operator = (const map_lines &); 353 354 bool in_map(const coord_def &pos) const; 355 356 void add_line(const string &s); 357 string add_nsubst(const string &st); 358 string add_subst(const string &st); 359 string add_shuffle(const string &s); 360 string add_clear(const string &s); 361 string add_colour(const string &col); 362 string add_fproperty(const string &sub); 363 string add_fheight(const string &arg); 364 void clear_markers(); 365 366 void write_maplines(writer &) const; 367 void read_maplines(reader&); 368 369 string add_floortile(const string &s); 370 string add_rocktile(const string &s); 371 string add_spec_tile(const string &s); 372 373 vector<coord_def> find_glyph(const string &glyphs) const; 374 vector<coord_def> find_glyph(int glyph) const; 375 coord_def find_first_glyph(int glyph) const; 376 coord_def find_first_glyph(const string &glyphs) const; 377 378 // Find rectangular bounds (inclusive) for uses of the glyph in the map. 379 // Returns false if glyph could not be found. 380 bool find_bounds(int glyph, coord_def &tl, coord_def &br) const; 381 // Same as above, but for any of the glyphs in glyph_str. 382 bool find_bounds(const char *glyph_str, coord_def &tl, coord_def &br) const; 383 384 void set_orientation(const string &s); 385 386 int width() const; 387 int height() const; 388 coord_def size() const; 389 390 int glyph(int x, int y) const; 391 int glyph(const coord_def &) const; 392 bool is_solid(int gly) const; 393 394 bool solid_borders(map_section_type border); 395 396 // Make all lines the same length. 397 void normalise(char fillc = ' '); 398 399 // Rotate 90 degrees either clockwise or anticlockwise 400 void rotate(bool clockwise); 401 void hmirror(); 402 void vmirror(); 403 404 void clear(); 405 406 void add_marker(map_marker *marker); 407 string add_feature_marker(const string &desc); 408 string add_lua_marker(const string &key, const lua_datum &fn); 409 410 void apply_markers(const coord_def &pos); 411 void apply_grid_overlay(const coord_def &pos, bool is_layout); 412 void apply_overlays(const coord_def &pos, bool is_layout); 413 414 const vector<string> &get_lines() const; 415 vector<string> &get_lines(); 416 417 rectangle_iterator get_iter() const; 418 char operator () (const coord_def &c) const; 419 char& operator () (const coord_def &c); 420 char operator () (int x, int y) const; 421 char& operator () (int x, int y); 422 423 const keyed_mapspec *mapspec_at(const coord_def &c) const; 424 keyed_mapspec *mapspec_at(const coord_def &c); 425 426 string add_key_item(const string &s); 427 string add_key_mons(const string &s); 428 string add_key_feat(const string &s); 429 string add_key_mask(const string &s); 430 431 bool in_bounds(const coord_def &c) const; 432 433 // Extend map dimensions with glyph 'fill' to minimum width and height. 434 void extend(int min_width, int min_height, char fill); 435 436 bool fill_zone(travel_distance_grid_t &tpd, const coord_def &start, 437 const coord_def &tl, const coord_def &br, int zone, 438 const char *wanted, const char *passable) const; 439 440 int count_feature_in_box(const coord_def &tl, const coord_def &br, 441 const char *feat) const; 442 443 void fill_mask_matrix(const string &glyphs, const coord_def &tl, 444 const coord_def &br, Matrix<bool> &flags); 445 446 // Merge vault onto the tl/br subregion, where mask is true. 447 map_corner_t merge_subvault(const coord_def &tl, const coord_def &br, 448 const Matrix<bool> &mask, const map_def &vault); 449 private: 450 void init_from(const map_lines &map); 451 void vmirror_markers(); 452 void hmirror_markers(); 453 void rotate_markers(bool clock); 454 void vmirror_marker(map_marker *, int par); 455 void hmirror_marker(map_marker *, int par); 456 void rotate_marker(map_marker *, int par); 457 void translate_marker(void (map_lines::*xform)(map_marker *, int par), 458 int par = 0); 459 460 void resolve_shuffle(const string &shuffle); 461 void clear(const string &clear); 462 void subst(string &s, subst_spec &spec); 463 void subst(subst_spec &); 464 void nsubst(nsubst_spec &); 465 void bind_overlay(); 466 void overlay_colours(colour_spec &); 467 void overlay_fprops(fprop_spec &); 468 void overlay_fheights(fheight_spec &); 469 470 // Merge cell (vx, vy) from vault onto this map's (x, y) cell. 471 typedef FixedVector<int, 256> keyspec_map; 472 void merge_cell(int x, int y, const map_def &vault, int vx, int vy, 473 int keyspec_idx); 474 475 void overlay_tiles(tile_spec &); 476 void check_borders(); 477 string shuffle(string s); 478 string block_shuffle(const string &s); 479 string check_shuffle(string &s); 480 string check_block_shuffle(const string &s); 481 string clean_shuffle(string s); 482 string check_clear(string &s); 483 string parse_nsubst_spec(const string &s, subst_spec &spec); 484 int apply_nsubst(vector<coord_def> &pos, int start, int nsub, 485 subst_spec &spec); 486 string parse_glyph_replacements(string s, glyph_replacements_t &gly); 487 488 string add_tile(const string &sub, bool is_floor, bool is_feat); 489 490 string add_key_field( 491 const string &s, 492 string (keyed_mapspec::*set_field)(const string &s, bool fixed), 493 void (keyed_mapspec::*copy_field)(const keyed_mapspec &spec)); 494 495 const keyed_mapspec *mapspec_for_key(int key) const; 496 keyed_mapspec *mapspec_for_key(int key); 497 498 friend class subst_spec; 499 friend class nsubst_spec; 500 friend class shuffle_spec; 501 friend class map_marker_spec; 502 friend class colour_spec; 503 friend class tile_spec; 504 505 private: 506 vector<map_marker *> markers; 507 vector<string> lines; 508 509 struct overlay_def 510 { overlay_defoverlay_def511 overlay_def() : 512 colour(0), rocktile(""), floortile(""), tile(""), 513 no_random(false), last_tile(false), property(), 514 height(INVALID_HEIGHT), keyspec_idx(0) 515 {} 516 colour_t colour; 517 string rocktile; 518 string floortile; 519 string tile; 520 bool no_random; 521 bool last_tile; 522 terrain_property_t property; 523 int height; // heightmap height 524 int keyspec_idx; 525 }; 526 typedef Matrix<overlay_def> overlay_matrix; 527 unique_ptr<overlay_matrix> overlay; 528 529 typedef map<int, keyed_mapspec> keyed_specs; 530 keyed_specs keyspecs; 531 int next_keyspec_idx; 532 533 enum 534 { 535 SUBVAULT_GLYPH = 1, 536 }; 537 538 int map_width; 539 bool solid_north, solid_east, solid_south, solid_west; 540 bool solid_checked; 541 }; 542 543 enum item_spec_type 544 { 545 ISPEC_STAR = -2, 546 ISPEC_SUPERB = -3, 547 ISPEC_DAMAGED = -4, 548 ISPEC_BAD = -5, 549 ISPEC_RANDART = -6, 550 ISPEC_MUNDANE = -7, 551 ISPEC_ACQUIREMENT = -9, 552 ISPEC_GIFT = 350, // worse than the next one 553 ISPEC_GOOD_ITEM = 351, 554 }; 555 556 class mons_spec; 557 class item_spec 558 { 559 public: 560 int genweight; 561 562 object_class_type base_type; 563 int sub_type; 564 int plus, plus2; 565 int ego; 566 int allow_uniques; 567 int level; 568 int item_special; 569 int qty; 570 int acquirement_source; 571 level_id place; 572 573 // Specifically for storing information about randart spell books. 574 CrawlHashTable props; 575 item_spec()576 item_spec() : genweight(10), base_type(OBJ_RANDOM), sub_type(OBJ_RANDOM), 577 plus(-1), plus2(-1), ego(0), allow_uniques(1), level(-1), 578 item_special(0), qty(0), acquirement_source(0), place(), props(), 579 _corpse_monster_spec(nullptr) 580 { 581 } 582 583 item_spec(const item_spec &other); 584 item_spec &operator = (const item_spec &other); 585 ~item_spec(); 586 587 bool corpselike() const; 588 const mons_spec &corpse_monster_spec() const; 589 void set_corpse_monster_spec(const mons_spec &spec); 590 591 private: 592 mons_spec *_corpse_monster_spec; 593 594 private: 595 void release_corpse_monster_spec(); 596 }; 597 typedef vector<item_spec> item_spec_list; 598 599 class item_list 600 { 601 public: item_list()602 item_list() : items() { } 603 604 void clear(); 605 606 item_spec get_item(int index); 607 item_spec random_item(); 608 item_spec random_item_weighted(); size()609 size_t size() const { return items.size(); } empty()610 bool empty() const { return items.empty(); } 611 612 string add_item(const string &spec, bool fix = false); 613 string set_item(int index, const string &spec); 614 615 // Set this list to be a copy of the item_spec_slot in list. 616 void set_from_slot(const item_list &list, int slot_index); 617 618 private: 619 struct item_spec_slot 620 { 621 item_spec_list ilist; 622 bool fix_slot; 623 item_spec_slotitem_spec_slot624 item_spec_slot() : ilist(), fix_slot(false) 625 { 626 } 627 }; 628 629 private: 630 item_spec item_by_specifier(const string &spec); 631 item_spec_slot parse_item_spec(string spec); 632 bool parse_single_spec(item_spec &result, string s); 633 int parse_acquirement_source(const string &source); 634 void parse_raw_name(string name, item_spec &spec); 635 void parse_random_by_class(string c, item_spec &spec); 636 item_spec pick_item(item_spec_slot &slot); 637 bool parse_corpse_spec(item_spec &result, string s); 638 bool monster_corpse_is_valid(monster_type *, const string &name, 639 bool skeleton); 640 641 private: 642 vector<item_spec_slot> items; 643 string error; 644 }; 645 646 class mons_spec 647 { 648 public: 649 monster_type type; 650 level_id place; 651 monster_type monbase; // Base monster for zombies and dracs. 652 mon_attitude_type attitude; 653 int quantity; // Number of monsters (usually 1). 654 int genweight; 655 bool generate_awake; 656 bool patrolling; 657 bool band; 658 int colour; // either COLOUR_INHERIT for "default", COLOUR_UNDEF for any 659 // colour upon creation, or an otherwise valid colour_t value. 660 661 god_type god; 662 bool god_gift; 663 664 int hd; 665 int hp; 666 int abjuration_duration; 667 int summon_type; 668 669 item_list items; 670 string monname; 671 string non_actor_summoner; 672 673 bool explicit_spells; 674 vector<monster_spells> spells; 675 monster_flags_t extra_monster_flags; 676 vector<mon_enchant> ench; 677 678 monster_type initial_shifter; 679 680 CrawlHashTable props; 681 682 mons_spec(monster_type t = RANDOM_MONSTER, 683 monster_type base = MONS_NO_MONSTER) type(t)684 : type(t), place(), monbase(base), attitude(ATT_HOSTILE), 685 quantity(1), genweight(10), 686 generate_awake(false), patrolling(false), band(false), 687 colour(COLOUR_INHERIT), god(GOD_NO_GOD), god_gift(false), hd(0), 688 hp(0), abjuration_duration(0), summon_type(0), items(), monname(""), 689 non_actor_summoner(""), explicit_spells(false), spells(), 690 extra_monster_flags(), initial_shifter(RANDOM_MONSTER), props() 691 { 692 } 693 }; 694 695 class mons_list 696 { 697 public: 698 mons_list(); 699 700 void clear(); 701 702 // Set this list to be a copy of the mons_spec_slot in list. 703 void set_from_slot(const mons_list &list, int slot_index); 704 705 mons_spec get_monster(int index); 706 mons_spec get_monster(int slot_index, int list_index) const; 707 708 // Returns an error string if the monster is unrecognised. 709 string add_mons(const string &s, bool fix_slot = false); 710 string set_mons(int slot, const string &s); 711 empty()712 bool empty() const { return mons.empty(); } size()713 size_t size() const { return mons.size(); } slot_size(int slot)714 size_t slot_size(int slot) const { return mons[slot].mlist.size(); } 715 716 private: 717 typedef vector<mons_spec> mons_spec_list; 718 719 struct mons_spec_slot 720 { 721 mons_spec_list mlist; 722 bool fix_slot; 723 724 mons_spec_slot(const mons_spec_list &list, bool fix = false) mlistmons_spec_slot725 : mlist(list), fix_slot(fix) 726 { 727 } 728 mons_spec_slotmons_spec_slot729 mons_spec_slot() 730 : mlist(), fix_slot(false) 731 { 732 } 733 }; 734 735 private: 736 mons_spec mons_by_name(string name) const; 737 mons_spec drac_monspec(string name) const; 738 mons_spec demonspawn_monspec(string name) const; 739 mons_spec soh_monspec(string name) const; 740 void get_zombie_type(string s, mons_spec &spec) const; 741 mons_spec get_hydra_spec(const string &name) const; 742 mons_spec get_slime_spec(const string &name) const; 743 mons_spec get_salt_spec(const string &name) const; 744 mons_spec get_zombified_monster(const string &name, 745 monster_type zomb) const; 746 mons_spec_slot parse_mons_spec(string spec); 747 void parse_mons_spells(mons_spec &slot, vector<string> &spells); 748 mon_enchant parse_ench(string &ench_str, bool perm); 749 mons_spec pick_monster(mons_spec_slot &slot); 750 751 private: 752 vector< mons_spec_slot > mons; 753 string error; 754 }; 755 756 /** 757 * @class shop_spec 758 * @ingroup mapdef 759 * @brief Specify how to create a shop. 760 * 761 * This specification struct is used when converting a vault-specified shop from 762 * a string into something the builder can use to actually create and place a 763 * shop. 764 **/ 765 struct shop_spec 766 { 767 shop_type sh_type; /**< One of the shop_type enum values. */ 768 769 string name; /**< If provided, this is apostrophised and used as the 770 * shop keeper's name, ie, Plog as a name becomes 771 * Plog's. */ 772 773 string type; /**< If provided, this is used as the shop type name, 774 * ie, Hide, Antique, Wand, etc. */ 775 776 string suffix; /**< If provided, this is used as the shop suffix, 777 * ie, Shop, Boutique, Parlour, etc. */ 778 779 int greed; /**< If provided, this value is used for price 780 * calculation. The higher the greed, the more 781 * inflation applied to prices. */ 782 783 int num_items; /**< Cap the number of items in a shop at this. */ 784 785 item_list items; /**< If provided, and `use_all` is false, items will be 786 * selected at random from the list and used to 787 * populate the shop. If `use_all` is true, the items 788 * contained will be placed precisely and in order. If 789 * the number of items contained is less than 790 * specified, random items according to the shop's 791 * type will be used to fill in the rest of the stock. 792 * */ 793 794 bool use_all; /**< True if all items in `items` should be used. */ 795 796 bool gozag; /**< True if this shop was created by Gozag's Call 797 * Merchant ability (and therefore should have better 798 * stock). 799 * */ 800 801 shop_spec(shop_type sh, string n="", string t="", 802 string s="", int g=-1, int ni=-1, bool u=false, bool goz=false) sh_typeshop_spec803 : sh_type(sh), name(n), type(t), suffix(s), 804 greed(g), num_items(ni), items(), use_all(u), gozag(goz) { } 805 }; 806 807 /** 808 * @class trap_spec 809 * @ingroup mapdef 810 * @brief Specify how to create a trap. 811 * 812 * This specification struct is used when converting a vault-specified trap 813 * string into something that the builder can use to place a trap. 814 **/ 815 struct trap_spec 816 { 817 trap_type tr_type; /*> One of the trap_type enum values. */ trap_spectrap_spec818 trap_spec(trap_type tr) 819 : tr_type(static_cast<trap_type>(tr)) { } 820 }; 821 822 /** 823 * @class feature_spec 824 * @ingroup mapdef 825 * @brief Specify how to create a feature. 826 * 827 * This specification struct is used firstly when a feature is specified in 828 * vault code (any feature), and secondly, if that feature is either a trap or a 829 * shop, as a container for a unique_ptr to that shop_spec or trap_spec. 830 **/ 831 struct feature_spec 832 { 833 int genweight; /**> The weight of this specific feature. */ 834 int feat; /**> The specific feature being placed. */ 835 unique_ptr<shop_spec> shop; /**> A pointer to a shop_spec. */ 836 unique_ptr<trap_spec> trap; /**> A pointer to a trap_spec. */ 837 int glyph; /**> What glyph to use instead. */ 838 int mimic; /**> 1 chance in x to be a feature mimic. */ 839 bool no_mimic; /**> Prevents random feature mimic here. */ 840 841 feature_spec(); 842 feature_spec(int f, int wt = 10, int _mimic = 0, bool _no_mimic = false); 843 feature_spec(const feature_spec& other); 844 feature_spec& operator = (const feature_spec& other); 845 void init_with(const feature_spec& other); 846 }; 847 848 typedef vector<feature_spec> feature_spec_list; 849 struct feature_slot 850 { 851 feature_spec_list feats; 852 bool fix_slot; 853 854 feature_slot(); 855 feature_spec get_feat(int default_glyph); 856 }; 857 858 struct bad_map_flag : public runtime_error 859 { bad_map_flagbad_map_flag860 explicit bad_map_flag(const string &flag) : runtime_error(flag) {} bad_map_flagbad_map_flag861 explicit bad_map_flag(const char *flag) : runtime_error(flag) {} 862 }; 863 864 struct map_flags 865 { 866 unsigned long flags_set, flags_unset; 867 868 map_flags(); 869 void clear(); 870 map_flags &operator |= (const map_flags &o); 871 872 /// @throws bad_map_flag if one of the flags was invalid. 873 static map_flags parse(const string flag_list[], const string &s); 874 }; 875 876 struct keyed_mapspec 877 { 878 public: 879 int key_glyph; 880 881 feature_slot feat; 882 item_list item; 883 mons_list mons; 884 map_flags map_mask; 885 886 public: 887 keyed_mapspec(); 888 889 // Parse the string and set the given entry. If fix is true, 890 // then whatever is selected for the first feature will be 891 // permanently fixed. 892 string set_feat(const string &s, bool fix); 893 string set_mons(const string &s, bool fix); 894 string set_item(const string &s, bool fix); 895 string set_mask(const string &s, bool /*garbage*/); 896 897 // Copy from the given mapspec. If that entry is fixed, 898 // it should be pre-selected prior to the copy. 899 void copy_feat(const keyed_mapspec &spec); 900 void copy_mons(const keyed_mapspec &spec); 901 void copy_item(const keyed_mapspec &spec); 902 void copy_mask(const keyed_mapspec &spec); 903 void copy_height(const keyed_mapspec &spec); 904 905 feature_spec get_feat(); 906 mons_list &get_monsters(); 907 item_list &get_items(); 908 map_flags &get_mask(); 909 910 // Does this mapspec specify a feature, item, or monster? If so, the 911 // glyph should be ignored. 912 bool replaces_glyph(); 913 private: 914 string err; 915 916 private: 917 void parse_features(const string &); 918 feature_spec_list parse_feature(const string &s); 919 feature_spec parse_shop(string s, int weight, int mimic, bool no_mimic); 920 feature_spec parse_trap(string s, int weight); 921 }; 922 923 class dlua_set_map 924 { 925 public: 926 dlua_set_map(map_def *map); 927 ~dlua_set_map(); 928 private: 929 unique_ptr<lua_datum> old_map; 930 }; 931 932 dungeon_feature_type map_feature_at(map_def *map, 933 const coord_def &c, 934 int rawfeat); 935 936 struct map_file_place 937 { 938 string filename; 939 int lineno; 940 941 map_file_place(const string &s = "", int line = 0) filenamemap_file_place942 : filename(s), lineno(line) 943 { 944 } 945 clearmap_file_place946 void clear() 947 { 948 filename.clear(); 949 lineno = 0; 950 } 951 }; 952 953 struct map_chance 954 { 955 int chance; map_chancemap_chance956 map_chance() : chance(-1) { } map_chancemap_chance957 map_chance(int _chance) : chance(_chance) { } validmap_chance958 bool valid() const { return chance >= 0; } 959 string describe() const; 960 // Returns true if the vault makes the random CHANCE_ROLL. 961 bool roll() const; 962 void write(writer &) const; 963 void read(reader &); 964 }; 965 966 typedef vector<level_range> depth_ranges_v; 967 class depth_ranges 968 { 969 private: 970 depth_ranges_v depths; 971 public: 972 // @throws bad_level_id if one if the comma-separated ranges is invalid. 973 static depth_ranges parse_depth_ranges(const string &depth_ranges_string); 974 void read(reader &); 975 void write(writer &) const; clear()976 void clear() { depths.clear(); } empty()977 bool empty() const { return depths.empty(); } 978 bool is_usable_in(const level_id &lid) const; add_depth(const level_range & range)979 void add_depth(const level_range &range) { depths.push_back(range); } 980 void add_depths(const depth_ranges &other_ranges); 981 string describe() const; 982 }; 983 984 template <typename X> 985 struct depth_range_X 986 { 987 depth_ranges depths; 988 X depth_thing; depth_range_Xdepth_range_X989 depth_range_X() : depths(), depth_thing() { } 990 /// @throws bad_level_id if depth_range_string is invalid. depth_range_Xdepth_range_X991 depth_range_X(const string &depth_range_string, const X &thing) 992 : depths(depth_ranges::parse_depth_ranges(depth_range_string)), 993 depth_thing(thing) 994 { 995 } is_usable_indepth_range_X996 bool is_usable_in(const level_id &lid) const 997 { 998 return depths.is_usable_in(lid); 999 } 1000 template <typename reader_fn_type> readdepth_range_X1001 static depth_range_X read(reader &inf, reader_fn_type reader_fn) 1002 { 1003 depth_range_X range_x; 1004 range_x.depths.read(inf); 1005 range_x.depth_thing = reader_fn(inf); 1006 return range_x; 1007 } 1008 template <typename writer_fn_type> writedepth_range_X1009 void write(writer &outf, writer_fn_type writer_fn) const 1010 { 1011 depths.write(outf); 1012 writer_fn(outf, depth_thing); 1013 } 1014 }; 1015 1016 template <typename X> 1017 class depth_ranges_X 1018 { 1019 private: 1020 typedef vector<depth_range_X<X> > depth_range_X_v; 1021 1022 X default_thing; 1023 depth_range_X_v depth_range_Xs; 1024 public: depth_ranges_X()1025 depth_ranges_X() : default_thing(), depth_range_Xs() { } depth_ranges_X(const X & _default_thing)1026 depth_ranges_X(const X &_default_thing) 1027 : default_thing(_default_thing), depth_range_Xs() { } 1028 void clear(const X &_default_X = X()) 1029 { 1030 depth_range_Xs.clear(); 1031 set_default(_default_X); 1032 } set_default(const X & _default_X)1033 void set_default(const X &_default_X) 1034 { 1035 default_thing = _default_X; 1036 } get_default()1037 X get_default() const { return default_thing; } 1038 /// @throws bad_level_id if depth_range_string is invalid. add_range(const string & depth_range_string,const X & thing)1039 void add_range(const string &depth_range_string, const X &thing) 1040 { 1041 depth_range_Xs.push_back(depth_range_X<X>(depth_range_string, thing)); 1042 } depth_value(const level_id & lid)1043 X depth_value(const level_id &lid) const 1044 { 1045 typename depth_range_X_v::const_iterator i = depth_range_Xs.begin(); 1046 for ( ; i != depth_range_Xs.end(); ++i) 1047 if (i->is_usable_in(lid)) 1048 return i->depth_thing; 1049 return default_thing; 1050 } 1051 template <typename reader_fn_type> read(reader & inf,reader_fn_type reader_fn)1052 static depth_ranges_X read(reader &inf, reader_fn_type reader_fn) 1053 { 1054 depth_ranges_X ranges; 1055 ranges.clear(reader_fn(inf)); 1056 const int count = unmarshallShort(inf); 1057 for (int i = 0; i < count; ++i) 1058 { 1059 ranges.depth_range_Xs.push_back( 1060 depth_range_X<X>::read(inf, reader_fn)); 1061 } 1062 return ranges; 1063 } 1064 template <typename writer_fn_type> write(writer & outf,writer_fn_type writer_fn)1065 void write(writer &outf, writer_fn_type writer_fn) const 1066 { 1067 writer_fn(outf, default_thing); 1068 marshallShort(outf, depth_range_Xs.size()); 1069 for (const auto &range : depth_range_Xs) 1070 range.write(outf, writer_fn); 1071 } 1072 }; 1073 1074 // Position of a subvault inside its parent. 1075 struct subvault_place 1076 { 1077 coord_def tl, br; 1078 unique_ptr<map_def> subvault; 1079 1080 subvault_place(); 1081 subvault_place(const coord_def &_tl, const coord_def &_br, 1082 const map_def &_subvault); 1083 subvault_place(const subvault_place &place); 1084 subvault_place &operator = (const subvault_place &place); 1085 1086 void set_subvault(const map_def &); 1087 }; 1088 1089 ///////////////////////////////////////////////////////////////////////////// 1090 // map_def: map definitions for maps loaded from .des files. 1091 // 1092 // Please read this before changing map_def. 1093 // 1094 // When adding Lua-visible fields to map_def, note that there are two 1095 // kinds of fields: 1096 // 1097 // * Fields that determine placement of the map, or are unchanging, 1098 // such as "place", "depths" (determine placement), or "name" (does 1099 // not change between different evaluations of the map). Such fields 1100 // must be reset to their default values in map_def::init() if they 1101 // determine placement, or just initialised in the constructor if 1102 // they will not change. 1103 // 1104 // * Fields that do not determine placement and may change between 1105 // different uses of the map (such as "mons", "items", etc.). Such fields 1106 // must be reset to their default values in map_def::reinit(), which is 1107 // called before the map is used. 1108 // 1109 // If you do not do this, maps will not work correctly, and will break 1110 // in obscure, hard-to-find ways. The level-compiler will not (cannot) 1111 // warn you. 1112 // 1113 class map_def 1114 { 1115 public: 1116 string name; 1117 // Description for the map that can be shown to players. 1118 string description; 1119 // Order among related maps; used only for tutorial/sprint. 1120 int order; 1121 depth_ranges place; 1122 1123 depth_ranges depths; 1124 map_section_type orient; 1125 1126 typedef depth_ranges_X<map_chance> range_chance_t; 1127 typedef depth_ranges_X<int> range_weight_t; 1128 1129 range_chance_t _chance; 1130 range_weight_t _weight; 1131 1132 map_lines map; 1133 mons_list mons; 1134 item_list items; 1135 1136 static bool valid_item_array_glyph(int gly); 1137 static int item_array_glyph_to_slot(int gly); 1138 static bool valid_monster_array_glyph(int gly); 1139 static bool valid_monster_glyph(int gly); 1140 static int monster_array_glyph_to_slot(int gly); 1141 1142 vector<mons_spec> random_mons; 1143 1144 dlua_chunk prelude, mapchunk, main, validate, veto, epilogue; 1145 1146 map_file_place place_loaded_from; 1147 1148 map_def *original; 1149 1150 colour_t rock_colour, floor_colour; 1151 string rock_tile, floor_tile; 1152 1153 dungeon_feature_type border_fill_type; 1154 1155 ::map<dungeon_feature_type, string> feat_renames; 1156 vector<subvault_place> subvault_places; 1157 string file; 1158 1159 private: 1160 unordered_set<string> tags; 1161 // This map has been loaded from an index, and not fully realised. 1162 bool index_only; 1163 mutable long cache_offset; 1164 string cache_name; 1165 1166 typedef Matrix<bool> subvault_mask; 1167 subvault_mask *svmask; 1168 1169 // True if this map is in the process of being validated. 1170 bool validating_map_flag; 1171 1172 // values cached from tags -- adding to this is only recommended if you've 1173 // actually done the profiling... 1174 // These are the top three worst tags, which jointly amount to about 3-4% 1175 // of levelgen time if not cached. 1176 bool cache_minivault; 1177 bool cache_overwritable; 1178 bool cache_extra; 1179 1180 public: 1181 map_def(); 1182 1183 string name_at(const coord_def &pos) const; 1184 string desc_or_name() const; 1185 1186 string describe() const; 1187 void init(); 1188 void reinit(); 1189 void reload_epilogue(); 1190 1191 void load(); 1192 void strip(); 1193 1194 int weight(const level_id &lid) const; 1195 map_chance chance(const level_id &lid) const; 1196 1197 bool in_map(const coord_def &p) const; 1198 bool map_already_used() const; 1199 size()1200 coord_def size() const { return coord_def(map.width(), map.height()); } 1201 1202 vector<coord_def> find_glyph(int glyph) const; 1203 coord_def find_first_glyph(int glyph) const; 1204 coord_def find_first_glyph(const string &glyphs) const; 1205 1206 void write_index(writer&) const; 1207 void write_full(writer&) const; 1208 void write_maplines(writer &) const; 1209 1210 void read_index(reader&); 1211 void read_full(reader&); 1212 void read_maplines(reader&); 1213 1214 void set_file(const string &s); 1215 string run_lua(bool skip_main); 1216 bool run_hook(const string &hook_name, bool die_on_lua_error = false); 1217 bool run_postplace_hook(bool die_on_lua_error = false); 1218 void copy_hooks_from(const map_def &other_map, const string &hook_name); 1219 1220 // Returns true if the validation passed. 1221 bool test_lua_validate(bool croak = false); 1222 1223 // Returns true if *not* vetoed, i.e., the map is good to go. 1224 bool test_lua_veto(); 1225 1226 // Executes post-generation lua code. 1227 bool run_lua_epilogue(bool croak = false); 1228 1229 string validate_map_def(const depth_ranges &); 1230 string validate_temple_map(); 1231 // Returns true if this map is in the middle of validation. is_validating()1232 bool is_validating() const { return validating_map_flag; } 1233 1234 void add_prelude_line(int line, const string &s); 1235 void add_main_line(int line, const string &s); 1236 1237 void hmirror(); 1238 void vmirror(); 1239 void rotate(bool clockwise); 1240 void normalise(); 1241 string resolve(); 1242 void fixup(); 1243 1244 bool is_usable_in(const level_id &lid) const; 1245 1246 const keyed_mapspec *mapspec_at(const coord_def &c) const; 1247 keyed_mapspec *mapspec_at(const coord_def &c); 1248 1249 bool has_depth() const; 1250 void add_depth(const level_range &depth); 1251 void add_depths(const depth_ranges &depth); 1252 1253 bool can_dock(map_section_type) const; 1254 coord_def dock_pos(map_section_type) const; 1255 coord_def float_dock(); 1256 coord_def float_place(); 1257 coord_def float_aligned_place() const; 1258 coord_def float_random_place() const; 1259 1260 vector<coord_def> anchor_points() const; 1261 1262 bool is_minivault() const; 1263 bool is_overwritable_layout() const; 1264 bool is_extra_vault() const; 1265 bool has_tag(const string &tagwanted) const; 1266 bool has_tag_prefix(const string &tag) const; 1267 bool has_tag_suffix(const string &suffix) const; 1268 1269 template <typename TagIterator> has_all_tags(TagIterator begin,TagIterator end)1270 bool has_all_tags(TagIterator begin, TagIterator end) const 1271 { 1272 if (tags.empty() || begin == end) // legacy behaviour for empty case 1273 return false; 1274 for ( ; begin != end; ++begin) 1275 if (!has_tag(*begin)) 1276 return false; 1277 return true; 1278 } 1279 bool has_all_tags(const string &tagswanted) const; 1280 1281 template <typename TagIterator> has_any_tag(TagIterator begin,TagIterator end)1282 bool has_any_tag(TagIterator begin, TagIterator end) const 1283 { 1284 for ( ; begin != end; ++begin) 1285 if (has_tag(*begin)) 1286 return true; 1287 return false; 1288 } 1289 1290 const vector<string> get_tags() const; 1291 const unordered_set<string> get_tags_unsorted() const; 1292 void add_tags(const string &tag); 1293 void set_tags(const string &tag); 1294 bool remove_tags(const string &tag); 1295 void clear_tags(); 1296 string tags_string() const; 1297 1298 vector<string> get_shuffle_strings() const; 1299 vector<string> get_subst_strings() const; 1300 1301 int glyph_at(const coord_def &c) const; 1302 1303 // Subvault functions. 1304 string subvault_from_tagstring(const string &s); 1305 bool is_subvault() const; 1306 void apply_subvault_mask(); 1307 bool subvault_cell_valid(const coord_def &c) const; 1308 int subvault_width() const; 1309 int subvault_height() const; 1310 // Returns the number of cells in the subvault map that 1311 // will not get copied to parent vault at a given placement. 1312 int subvault_mismatch_count(const coord_def &place) const; 1313 1314 public: 1315 struct map_feature_finder 1316 { 1317 map_def ↦ map_feature_findermap_feature_finder1318 map_feature_finder(map_def &map_) : map(map_) { } 1319 // This may actually modify the underlying map by fixing KFEAT: 1320 // feature slots, but that's fine by us. operatormap_feature_finder1321 dungeon_feature_type operator () (const coord_def &c) const 1322 { 1323 return map_feature_at(&map, c, -1); 1324 } 1325 }; 1326 1327 struct map_bounds_check 1328 { 1329 map_def ↦ map_bounds_checkmap_bounds_check1330 map_bounds_check(map_def &map_) : map(map_) { } operatormap_bounds_check1331 bool operator () (const coord_def &c) const 1332 { 1333 return c.x >= 0 && c.x < map.map.width() 1334 && c.y >= 0 && c.y < map.map.height(); 1335 } 1336 }; 1337 1338 private: 1339 bool test_lua_boolchunk(dlua_chunk &, bool def = false, bool croak = false); 1340 string rewrite_chunk_errors(const string &s) const; 1341 string apply_subvault(string_spec &); 1342 string validate_map_placeable(); 1343 bool has_exit() const; 1344 void update_cached_tags(); 1345 }; 1346 1347 const int CHANCE_ROLL = 10000; 1348 1349 void clear_subvault_stack(); 1350 1351 void map_register_flag(const string &flag); 1352 1353 string mapdef_split_key_item(const string &s, string *key, int *separator, 1354 string *arg, int key_max_len = 1); 1355 1356 const char *map_section_name(int msect); 1357 1358 int store_tilename_get_index(const string& tilename); 1359 1360 int str_to_ego(object_class_type item_type, string ego_str); 1361