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