1 /**
2  * @file
3  * @brief Functions used when building new levels.
4 **/
5 
6 #pragma once
7 
8 #include <algorithm>
9 #include <set>
10 #include <stdexcept>
11 #include <vector>
12 
13 #include "env.h"
14 #include "mapdef.h"
15 #include "tag-version.h"
16 
17 COMPILE_CHECK(sizeof(feature_property_type) <= sizeof(terrain_property_t));
18 
19 #define BUILD_METHOD_KEY "build_method_key"
20 #define LAYOUT_TYPE_KEY  "layout_type_key"
21 
22 // See _build_overflow_temples() in dungeon.cc for details on overflow
23 // temples.
24 #define TEMPLE_GODS_KEY      "temple_gods_key"
25 #define OVERFLOW_TEMPLES_KEY "overflow_temples_key"
26 #define TEMPLE_MAP_KEY       "temple_map_key"
27 #define TEMPLE_SIZE_KEY      "temple_size_key"
28 
29 #if TAG_MAJOR_VERSION == 34
30 #define TOMB_STONE_STAIRS_KEY "tomb_stone_stairs_key"
31 #endif
32 #define HATCH_NAME_PROP "_hatch_name"
33 #define HATCH_DEST_NAME_PROP "_hatch_dest_name"
34 
35 #define TRANSPORTER_NAME_PROP "_transporter_name"
36 #define TRANSPORTER_DEST_NAME_PROP "_transporter_dest_name"
37 
38 const unsigned short INVALID_MAP_INDEX = 10000;
39 
40 // Should be the larger of GXM/GYM
41 #define MAP_SIDE ((GXM) > (GYM) ? (GXM) : (GYM))
42 
43 // Map mask constants.
44 
45 // Be sure to change flag_list in keyed_mapspec::set_mask to match!
46 enum map_mask_type
47 {
48     MMT_NONE            = 0x0,
49     MMT_VAULT           = 0x01,  // This is a square in a vault.
50     MMT_NO_ITEM         = 0x02,  // Random items should not be placed here.
51     MMT_NO_MONS         = 0x04,  // Random monsters should not be placed here.
52     MMT_NO_POOL         = 0x08,  // Pool fixup should not be applied here.
53                        // 0x10,  // Unused
54     MMT_NO_WALL         = 0x20,  // Wall fixup should not be applied here.
55     MMT_OPAQUE          = 0x40,  // Vault may impede connectivity.
56     MMT_NO_TRAP         = 0x80,  // No trap generation
57     MMT_MIMIC           = 0x100, // Feature mimics
58     MMT_NO_MIMIC        = 0x200, // Feature shouldn't be turned into a mimic.
59 #if TAG_MAJOR_VERSION == 34
60     MMT_WAS_DOOR_MIMIC  = 0x400, // There was a door mimic there.
61 #endif
62     MMT_TURNED_TO_FLOOR = 0x800, // This feature was dug, deconstructed or such.
63     MMT_PASSABLE        = 0x1000 // Passable for purposes of determining level connectivity
64 };
65 
66 class dgn_region;
67 typedef vector<dgn_region> dgn_region_list;
68 
69 struct dgn_veto_exception : public runtime_error
70 {
dgn_veto_exceptiondgn_veto_exception71     dgn_veto_exception(const string& msg) : runtime_error(msg) {}
dgn_veto_exceptiondgn_veto_exception72     dgn_veto_exception(const char *msg) : runtime_error(msg) {}
73 };
74 
75 class dgn_region
76 {
77 public:
78     // pos is top-left corner.
79     coord_def pos, size;
80 
dgn_region(int left,int top,int width,int height)81     dgn_region(int left, int top, int width, int height)
82         : pos(left, top), size(width, height)
83     {
84     }
85 
dgn_region(const coord_def & _pos,const coord_def & _size)86     dgn_region(const coord_def &_pos, const coord_def &_size)
87         : pos(_pos), size(_size)
88     {
89     }
90 
dgn_region()91     dgn_region() : pos(-1, -1), size()
92     {
93     }
94 
end()95     coord_def end() const
96     {
97         return pos + size - coord_def(1, 1);
98     }
99 
100     coord_def random_edge_point() const;
101     coord_def random_point() const;
102 
absolute(int left,int top,int right,int bottom)103     static dgn_region absolute(int left, int top, int right, int bottom)
104     {
105         return dgn_region(left, top, right - left + 1, bottom - top + 1);
106     }
107 
absolute(const coord_def & c1,const coord_def & c2)108     static dgn_region absolute(const coord_def &c1, const coord_def &c2)
109     {
110         return dgn_region(c1.x, c1.y, c2.x, c2.y);
111     }
112 
between(int val,int low,int high)113     static bool between(int val, int low, int high)
114     {
115         return val >= low && val <= high;
116     }
117 
contains(const coord_def & p)118     bool contains(const coord_def &p) const
119     {
120         return contains(p.x, p.y);
121     }
122 
contains(int xp,int yp)123     bool contains(int xp, int yp) const
124     {
125         return xp >= pos.x && xp < pos.x + size.x
126                && yp >= pos.y && yp < pos.y + size.y;
127     }
128 
fully_contains(const coord_def & p)129     bool fully_contains(const coord_def &p) const
130     {
131         return p.x > pos.x && p.x < pos.x + size.x - 1
132                && p.y > pos.y && p.y < pos.y + size.y - 1;
133     }
134 
135     bool overlaps(const dgn_region &other) const;
136     bool overlaps_any(const dgn_region_list &others) const;
137     bool overlaps(const dgn_region_list &others,
138                   const map_mask &dgn_map_mask) const;
139     bool overlaps(const map_mask &dgn_map_mask) const;
140 };
141 
142 struct vault_placement
143 {
144 public:
145     coord_def pos;
146     coord_def size;
147 
148     map_section_type orient;
149     map_def map;
150     vector<coord_def> exits;
151 
152     // The PC has seen at least one square of this vault.
153     bool seen;
154 
155 public:
156     vault_placement();
157     void reset();
158     void apply_grid();
159     void draw_at(const coord_def &c);
160     int connect(bool spotty = false) const;
161     string map_name_at(const coord_def &c) const;
162     dungeon_feature_type feature_at(const coord_def &c);
163     bool is_exit(const coord_def &c) const;
164     bool is_space(const coord_def &c) const;
165 };
166 
167 class vault_place_iterator
168 {
169 public:
170     vault_place_iterator(const vault_placement &vp);
171     operator bool () const;
172     coord_def operator * () const;
173     coord_def vault_pos() const;
174     const coord_def *operator -> () const;
175     vault_place_iterator &operator ++ ();
176     vault_place_iterator operator ++ (int);
177 private:
178     const vault_placement &vault_place;
179     coord_def pos;
180     coord_def tl, br;
181 };
182 
183 class unwind_vault_placement_mask
184 {
185 public:
186     unwind_vault_placement_mask(const map_bitmask *mask);
187     ~unwind_vault_placement_mask();
188 private:
189     const map_bitmask *oldmask;
190 };
191 
192 extern vector<vault_placement> Temp_Vaults;
193 
194 extern const map_bitmask *Vault_Placement_Mask;
195 
196 set<string> &get_uniq_map_tags();
197 set<string> &get_uniq_map_names();
198 
199 void init_level_connectivity();
200 void read_level_connectivity(reader &th);
201 void write_level_connectivity(writer &th);
202 
203 bool builder(bool enable_random_maps = true);
204 
205 void dgn_clear_vault_placements();
206 void dgn_erase_unused_vault_placements();
207 void dgn_flush_map_memory();
208 
209 double dgn_degrees_to_radians(int degrees);
210 bool dgn_has_adjacent_feat(coord_def c, dungeon_feature_type feat);
211 coord_def dgn_random_point_in_margin(int margin);
212 coord_def dgn_random_point_from(const coord_def &c, int radius, int margin = 1);
213 coord_def dgn_find_feature_marker(dungeon_feature_type feat);
214 
215 // Generate 3 stone stairs in both directions.
216 void dgn_place_stone_stairs(bool maybe_place_hatches = false);
217 
218 void dgn_set_grid_colour_at(const coord_def &c, int colour);
219 
220 const vault_placement *dgn_place_map(const map_def *map,
221                                      bool check_collision,
222                                      bool make_no_exits,
223                                      const coord_def &pos = INVALID_COORD);
224 
225 const vault_placement *dgn_safe_place_map(const map_def *map,
226                                           bool check_collision,
227                                           bool make_no_exits,
228                                           const coord_def &pos = INVALID_COORD);
229 
230 void dgn_record_veto(const dgn_veto_exception &e);
231 
232 void level_clear_vault_memory();
233 void run_map_epilogues();
234 
235 void place_specific_trap(const coord_def& where, trap_type trap_spec, int charges = 0);
236 
237 struct shop_spec;
238 void place_spec_shop(const coord_def& where, shop_type force_type);
239 void place_spec_shop(const coord_def& where, shop_spec &spec, int shop_level = 0);
240 int greed_for_shop_type(shop_type shop, int level_number);
241 object_class_type item_in_shop(shop_type shop_type);
242 bool seen_destroy_feat(dungeon_feature_type old_feat);
243 bool map_masked(const coord_def &c, unsigned mask);
244 coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
245                                 coord_def base_pos, bool find_closest,
246                                 string hatch_name = "");
247 
248 class mons_spec;
249 monster *dgn_place_monster(mons_spec &mspec, coord_def where,
250                            bool force_pos = false, bool generate_awake = false,
251                            bool patrolling = false);
252 int dgn_place_item(const item_spec &spec,
253                    const coord_def &where,
254                    int level = INVALID_ABSDEPTH);
255 
256 class item_list;
257 void dgn_place_multiple_items(item_list &list,
258                               const coord_def& where);
259 
260 void dgn_set_branch_epilogue(branch_type br, string callback_name);
261 
262 void dgn_reset_level(bool enable_random_maps = true);
263 
264 const vault_placement *dgn_register_place(const vault_placement &place,
265                                           bool register_vault);
266 
267 int dgn_count_disconnected_zones(
268     bool choose_stairless,
269     dungeon_feature_type fill = DNGN_UNSEEN);
270 
271 int dgn_count_tele_zones(bool choose_stairless);
272 
273 void dgn_replace_area(const coord_def& p1, const coord_def& p2,
274                       dungeon_feature_type replace,
275                       dungeon_feature_type feature,
276                       unsigned mmask = 0, bool needs_update = false);
277 void dgn_replace_area(int sx, int sy, int ex, int ey,
278                       dungeon_feature_type replace,
279                       dungeon_feature_type feature,
280                       unsigned mmask = 0, bool needs_update = false);
281 
282 vault_placement *dgn_vault_at(coord_def gp);
283 void dgn_seen_vault_at(coord_def gp);
284 
285 int count_neighbours(int x, int y, dungeon_feature_type feat);
count_neighbours(const coord_def & p,dungeon_feature_type feat)286 static inline int count_neighbours(const coord_def& p, dungeon_feature_type feat)
287 {
288     return count_neighbours(p.x, p.y, feat);
289 }
290 
291 string dump_vault_maps();
292 
293 bool dgn_square_travel_ok(const coord_def &c);
294 
295 // Resets travel_point_distance!
296 vector<coord_def> dgn_join_the_dots_pathfind(const coord_def &from,
297                                              const coord_def &to,
298                                              uint32_t mapmask);
299 
300 bool join_the_dots(const coord_def &from, const coord_def &to,
301                    unsigned mmask,
302                    bool (*overwriteable)(dungeon_feature_type) = nullptr);
303 int count_feature_in_box(int x0, int y0, int x1, int y1,
304                          dungeon_feature_type feat);
305 bool door_vetoed(const coord_def pos);
306 
307 void fixup_misplaced_items();
308 
309 void dgn_place_transporter(const coord_def &pos, const coord_def &dest);
310 bool dgn_make_transporters_from_markers();
311 
312 int starting_absdepth();
313