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