1 /*
2 * map.h
3 * Copyright (C) 2009-2020 Joachim de Groot <jdegroot@web.de>
4 *
5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef __MAP_H_
20 #define __MAP_H_
21
22 #include "cJSON.h"
23 #include "items.h"
24 #include "monsters.h"
25 #include "position.h"
26 #include "sobjects.h"
27 #include "traps.h"
28 #include "utils.h"
29
30 /* map dimensions */
31 #define MAP_MAX_X 67
32 #define MAP_MAX_Y 17
33 #define MAP_SIZE MAP_MAX_X*MAP_MAX_Y
34
35 /* number of levels */
36 #define MAP_CMAX 11 /* max # levels in the caverns */
37 #define MAP_VMAX 3 /* max # of levels in the temple of the luran */
38 #define MAP_MAX (MAP_CMAX + MAP_VMAX) /* total number of levels */
39
40 /* number of the last custom maze map (including town) */
41 #define MAP_MAX_MAZE_NUM 24
42 #define MAP_MAZE_NUM (MAP_MAX_MAZE_NUM + 1)
43
44 typedef enum map_tile_type
45 {
46 LT_NONE,
47 LT_MOUNTAIN,
48 LT_GRASS,
49 LT_DIRT,
50 LT_TREE,
51 LT_FLOOR,
52 LT_WATER,
53 LT_DEEPWATER,
54 LT_LAVA,
55 LT_FIRE,
56 LT_CLOUD, /* gas cloud */
57 LT_WALL,
58 LT_MAX /* ~ map tile type count */
59 } map_tile_t;
60
61 typedef enum map_element_type
62 {
63 LE_GROUND,
64 LE_SOBJECT,
65 LE_TRAP,
66 LE_ITEM,
67 LE_MONSTER,
68 LE_SWIMMING_MONSTER,
69 LE_FLYING_MONSTER,
70 LE_XORN, /* can move through walls */
71 LE_MAX
72 } map_element_t;
73
74 typedef struct map_tile
75 {
76 guint32
77 type: 8,
78 base_type: 8, /* if tile is covered with e.g. fire the original type is stored here */
79 sobject: 8, /* something special located on this tile */
80 trap: 8; /* trap located on this tile */
81 guint8 timer; /* countdown to when the type will become base_type again */
82 gpointer m_oid; /* id of monster located on this tile */
83 inventory *ilist; /* items located on this tile */
84 } map_tile;
85
86 typedef struct map_tile_data
87 {
88 map_tile_t tile;
89 const char glyph;
90 int colour;
91 const char *description;
92 unsigned
93 passable: 1, /* can be passed */
94 transparent: 1; /* see-through */
95 } map_tile_data;
96
97 typedef struct map
98 {
99 guint32 nlevel; /* map number */
100 guint32 visited; /* last time player has been on this map */
101 guint32 mcount; /* monster count */
102 map_tile grid[MAP_MAX_Y][MAP_MAX_X]; /* the map */
103 } map;
104
105 /* callback function for trajectories */
106 typedef gboolean (*trajectory_hit_sth)(const GList *trajectory,
107 const damage_originator *damo,
108 gpointer data1, gpointer data2);
109
110 /* function declarations */
111
112 map *map_new(int num, const char *mazefile);
113 void map_destroy(map *m);
114
115 cJSON *map_serialize(map *m);
116 map *map_deserialize(cJSON *mser);
117 char *map_dump(map *m, position ppos);
118
119 position map_find_space(map *m, map_element_t element,
120 gboolean dead_end);
121
122 position map_find_space_in(map *m,
123 rectangle where,
124 map_element_t element,
125 gboolean dead_end);
126
127 position map_find_sobject(map *m, sobject_t sobject);
128
129 gboolean map_pos_validate(map *m,
130 position pos,
131 map_element_t element,
132 gboolean dead_end);
133
134 void map_item_add(map *m, item *it);
135
136 int *map_get_surrounding(map *m, position pos, sobject_t type);
137
138 /**
139 * determine if a position can be seen from another position
140 *
141 * @param the map
142 * @param first position
143 * @param second position
144 * @return TRUE or FALSE
145 */
146 int map_pos_is_visible(map *m, position source, position target);
147
148 /**
149 * Return a linked list with every position between two points.
150 *
151 * @param The map that contains both positions.
152 * @param The starting position.
153 * @param The destination.
154 */
155 GList *map_ray(map *m, position source, position target);
156
157 /**
158 * Follow a ray from target to destination.
159 *
160 * @param The starting position.
161 * @param The destination.
162 * @param The originator of the trajectory.
163 * @param The callback function for every affected position.
164 * @param A pointer passed to the callback function.
165 * @param A pointer passed to the callback function.
166 * @param TRUE if reflection should be honoured.
167 * @param The glyph to display at an affected position
168 * @param The colour of the glyph.
169 * @param TRUE to keep the glyph at affected positions.
170 *
171 * @return TRUE if one of the callbacks returned TRUE.
172 */
173 gboolean map_trajectory(position source, position target,
174 const damage_originator *damo,
175 trajectory_hit_sth pos_hitfun,
176 gpointer data1, gpointer data2, gboolean reflectable,
177 char glyph, int colour, gboolean keep_ray);
178
179 /**
180 * @brief Get an area of defined dimensions with all blocked positions set.
181 *
182 * @param A map.
183 * @param The center position.
184 * @param The radius.
185 * @param Shall closed doors be handled as passable?
186 *
187 * @return A freshly allocated area with all impassable positions set.
188 */
189 area *map_get_obstacles(map *m, position center, int radius, gboolean doors);
190
191 void map_set_tiletype(map *m, area *area, map_tile_t type, guint8 duration);
192
193 damage *map_tile_damage(map *m, position pos, gboolean flying);
194
195 /**
196 * @brief Creates description of items on the floor for a given position.
197 *
198 * @param a map
199 * @param a position
200 * @param "here" or "there"
201 * @param a filter function to restrict the described items
202 */
203 char *map_inv_description(map *m, position pos, const char* where, int (*ifilter)(item *));
204
205 char *map_pos_examine(position pos);
206
207 monster *map_get_monster_at(map *m, position pos);
208
209 /**
210 * @brief Creates new monsters for a map.
211 *
212 * @param a map
213 */
214 void map_fill_with_life(map *m);
215
216 gboolean map_is_exit_at(map *m, position pos);
217
218 /**
219 * Process temporary effects for a map.
220 *
221 * @param the map on which timed events have to be processed
222 */
223 void map_timer(map *m);
224
225 /**
226 * @brief Get the glyph for a door.
227 *
228 * @param The map.
229 * @param The position of the door.
230 *
231 * @return The glyph for the door.
232 */
233 char map_get_door_glyph(map *m, position pos);
234
235 /* external vars */
236
237 extern const map_tile_data map_tiles[LT_MAX];
238 extern const char *map_names[MAP_MAX];
239
240 /* inline accessor functions */
241
map_tile_at(map * m,position pos)242 static inline map_tile *map_tile_at(map *m, position pos)
243 {
244 g_assert(m != NULL && pos_valid(pos));
245 return &m->grid[Y(pos)][X(pos)];
246 }
247
map_ilist_at(map * m,position pos)248 static inline inventory **map_ilist_at(map *m, position pos)
249 {
250 g_assert(m != NULL && pos_valid(pos));
251 return &m->grid[Y(pos)][X(pos)].ilist;
252 }
253
map_tiletype_at(map * m,position pos)254 static inline map_tile_t map_tiletype_at(map *m, position pos)
255 {
256 g_assert(m != NULL && pos_valid(pos));
257 return m->grid[Y(pos)][X(pos)].type;
258 }
259
map_tiletype_set(map * m,position pos,map_tile_t type)260 static inline void map_tiletype_set(map *m, position pos, map_tile_t type)
261 {
262 g_assert(m != NULL && pos_valid(pos));
263 m->grid[Y(pos)][X(pos)].type = type;
264 }
265
map_basetype_at(map * m,position pos)266 static inline map_tile_t map_basetype_at(map *m, position pos)
267 {
268 g_assert(m != NULL && pos_valid(pos));
269 return m->grid[Y(pos)][X(pos)].base_type;
270 }
271
map_basetype_set(map * m,position pos,map_tile_t type)272 static inline void map_basetype_set(map *m, position pos, map_tile_t type)
273 {
274 g_assert(m != NULL && pos_valid(pos));
275 m->grid[Y(pos)][X(pos)].base_type = type;
276 }
277
map_timer_at(map * m,position pos)278 static inline guint8 map_timer_at(map *m, position pos)
279 {
280 g_assert(m != NULL && pos_valid(pos));
281 return m->grid[Y(pos)][X(pos)].timer;
282 }
283
map_trap_at(map * m,position pos)284 static inline trap_t map_trap_at(map *m, position pos)
285 {
286 g_assert(m != NULL && pos_valid(pos));
287 return m->grid[Y(pos)][X(pos)].trap;
288 }
289
map_trap_set(map * m,position pos,trap_t type)290 static inline void map_trap_set(map *m, position pos, trap_t type)
291 {
292 g_assert(m != NULL && pos_valid(pos));
293 m->grid[Y(pos)][X(pos)].trap = type;
294 }
295
map_sobject_at(map * m,position pos)296 static inline sobject_t map_sobject_at(map *m, position pos)
297 {
298 g_assert(m != NULL && pos_valid(pos));
299 return m->grid[Y(pos)][X(pos)].sobject;
300 }
301
map_sobject_set(map * m,position pos,sobject_t type)302 static inline void map_sobject_set(map *m, position pos, sobject_t type)
303 {
304 g_assert(m != NULL && pos_valid(pos));
305 m->grid[Y(pos)][X(pos)].sobject = type;
306 }
307
map_set_monster_at(map * m,position pos,monster * monst)308 static inline void map_set_monster_at(map *m, position pos, monster *monst)
309 {
310 g_assert(m != NULL && m->nlevel == Z(pos) && pos_valid(pos));
311 m->grid[Y(pos)][X(pos)].m_oid = (monst != NULL) ? monster_oid(monst) : NULL;
312 }
313
map_is_monster_at(map * m,position pos)314 static inline gboolean map_is_monster_at(map *m, position pos)
315 {
316 g_assert(m != NULL);
317 return ((map_get_monster_at(m, pos) != NULL));
318 }
319
mt_get_glyph(map_tile_t t)320 static inline char mt_get_glyph(map_tile_t t)
321 {
322 return map_tiles[t].glyph;
323 }
324
mt_get_colour(map_tile_t t)325 static inline int mt_get_colour(map_tile_t t)
326 {
327 return map_tiles[t].colour;
328 }
329
mt_get_desc(map_tile_t t)330 static inline const char *mt_get_desc(map_tile_t t)
331 {
332 return map_tiles[t].description;
333 }
334
mt_is_passable(map_tile_t t)335 static inline gboolean mt_is_passable(map_tile_t t)
336 {
337 return map_tiles[t].passable;
338 }
339
mt_is_transparent(map_tile_t t)340 static inline gboolean mt_is_transparent(map_tile_t t)
341 {
342 return map_tiles[t].transparent;
343 }
344
map_name(map * m)345 static inline const char *map_name(map *m)
346 {
347 return map_names[m->nlevel];
348 }
349
map_pos_transparent(map * m,position pos)350 static inline gboolean map_pos_transparent(map *m, position pos)
351 {
352 return mt_is_transparent(m->grid[Y(pos)][X(pos)].type)
353 && so_is_transparent(m->grid[Y(pos)][X(pos)].sobject);
354 }
355
map_pos_passable(map * m,position pos)356 static inline gboolean map_pos_passable(map *m, position pos)
357 {
358 return mt_is_passable(m->grid[Y(pos)][X(pos)].type)
359 && so_is_passable(m->grid[Y(pos)][X(pos)].sobject);
360 }
361
362 #endif
363