home · contact · privacy
Strongly overhauled keybinding managemment. Window-specific keybindings and a window...
[plomrogue] / src / map_objects.c
1 /* map_objects.c */
2
3 #include "map_objects.h"
4 #include <stdlib.h> /* for free(), atoi() */
5 #include <stdint.h> /* for uint8_t */
6 #include <stdio.h> /* for FILE typedef */
7 #include <string.h> /* for strchr(), strlen(), memcpy(), strtok() */
8 #include "readwrite.h" /* for get_linemax(), try_fopen(), try_fclose()
9                         * [read/write]_uint[8/16/23][_bigendian]()
10                         */
11 #include "misc.h" /* for try_malloc(), try_calloc(), find_passable_pos() */
12 #include "main.h" /* for World struct */
13 #include "rexit.h" /* for err_exit() */
14
15
16
17 /* Return pointer to newly allocated map object struct of size "size". If first
18  * in map object chain ("first" pointing to !0), point "start" to it.
19  */
20 static struct MapObj * get_next_map_obj(struct World * world,
21                                         void * start, char * first,
22                                         size_t size, struct MapObj * map_obj);
23
24
25
26 /* Map-object-type-specific helpers to (build|write|read)_map_objects(). */
27 static void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
28                                        void * start);
29 static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
30                                           void * start);
31 static uint8_t write_map_objects_monsterdata(void * start, FILE * file);
32 static uint8_t read_map_objects_monsterdata( void * start, FILE * file);
33
34
35
36 static struct MapObj * get_next_map_obj(struct World * world,
37                                         void * start, char * first,
38                                         size_t size, struct MapObj * map_obj)
39 {
40     char * f_name = "get_next_map_obj()";
41     if (* first)
42     {
43         struct MapObj * * z = start;
44         map_obj = try_malloc(size, world, f_name);
45         * z = map_obj;
46         * first = 0;
47     }
48     else
49     {
50         map_obj->next = try_malloc(size, world, f_name);
51         map_obj = map_obj->next;
52     }
53     return map_obj;
54 }
55
56
57
58 static void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
59                                        void * start)
60 {
61   struct Item * i = (struct Item *) start;
62   i->map_obj.type = map_obj_def->id;
63 }
64
65
66
67 static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
68                                           void * start)
69 {
70     struct Monster * m = (struct Monster *) start;
71     m->map_obj.type = map_obj_def->id;
72     struct MonsterDef * md = (struct MonsterDef *) map_obj_def;
73     m->hitpoints = md->hitpoints_start;
74 }
75
76
77
78 static uint8_t write_map_objects_monsterdata(void * start, FILE * file)
79 {
80     struct Monster * m = (struct Monster *) start;
81     return write_uint8(m->hitpoints, file);
82 }
83
84
85
86 static uint8_t read_map_objects_monsterdata (void * start, FILE * file)
87 {
88     struct Monster * m = (struct Monster *) start;
89     return read_uint8(file, &m->hitpoints);
90 }
91
92
93
94 extern void init_map_object_defs(struct World * world, char * filename)
95 {
96     char * f_name = "init_map_object_defs()";
97     FILE * file = try_fopen(filename, "r", world, f_name);
98     uint16_t linemax = get_linemax(file, world, f_name);
99     struct MapObjDef  mod;
100     struct ItemDef    id;
101     struct MonsterDef md;
102     world->item_def    = 0;
103     world->monster_def = 0;
104     struct ItemDef    * * p_p_id  = &world->item_def;
105     struct MonsterDef * * p_p_md  = &world->monster_def;
106     char defline[linemax + 1];
107     char * line_p;
108     char * delim = " ";
109     while (fgets(defline, linemax + 1, file))
110     {
111         mod.next    = 0;
112         mod.id      = atoi(strtok(defline, delim));
113         mod.m_or_i  = * strtok(NULL, delim);
114         mod.mapchar = * strtok(NULL, delim);
115         if ('i' == mod.m_or_i)
116         {
117             line_p = strtok(NULL, delim);
118         }
119         else
120         {
121             md.corpse_id       = atoi(strtok(NULL, delim));
122             md.hitpoints_start = atoi(strtok(NULL, delim));
123             line_p             = strtok(NULL, delim);
124         }
125         mod.desc = try_calloc(strlen(line_p), sizeof(char), world, f_name);
126         memcpy(mod.desc, line_p, strlen(line_p) - 1);
127         if ('i' == mod.m_or_i)
128         {
129             id.map_obj_def = mod;
130             * p_p_id       = try_malloc(sizeof(struct ItemDef), world, f_name);
131             * * p_p_id     = id;
132             p_p_id         = (struct ItemDef    * *) * p_p_id;
133         }
134         else
135         {
136             md.map_obj_def = mod;
137             * p_p_md     = try_malloc(sizeof(struct MonsterDef), world, f_name);
138             * * p_p_md     = md;
139             p_p_md         = (struct MonsterDef * *) * p_p_md;
140         }
141     }
142     try_fclose(file, world, f_name);
143 }
144
145
146
147 extern void free_item_defs(struct ItemDef * id_start)
148 {
149     if (0 != id_start->map_obj_def.next)
150     {
151         free_item_defs((struct ItemDef *) id_start->map_obj_def.next);
152     }
153     free(id_start->map_obj_def.desc);
154     free(id_start);
155 }
156
157
158
159
160 extern void free_monster_defs(struct MonsterDef * md_start)
161 {
162     if (0 != md_start->map_obj_def.next)
163     {
164         free_monster_defs((struct MonsterDef *) md_start->map_obj_def.next);
165     }
166     free(md_start->map_obj_def.desc);
167     free(md_start);
168 }
169
170
171
172 extern uint8_t write_map_objects(struct World * world, void * start,
173                                  FILE * file)
174 {
175     struct MapObj * map_obj;
176     struct MapObjDef * mod;
177     for (map_obj = start; map_obj != 0; map_obj = map_obj->next)
178     {
179         if (   write_uint8(map_obj->type, file)
180             || write_uint16_bigendian(map_obj->pos.y + 1, file)
181             || write_uint16_bigendian(map_obj->pos.x + 1, file))
182         {
183             return 1;
184         }
185         mod = get_map_obj_def(world, map_obj->type);
186         if ('m' == mod->m_or_i)
187         {
188             if (write_map_objects_monsterdata(map_obj, file))
189             {
190                 return 1;
191             }
192         }
193     }
194     return write_uint16_bigendian(0, file);
195 }
196
197
198
199 extern uint8_t read_map_objects(struct World * world, void * start, FILE * file)
200 {
201     char * err = "Trouble in read_map_objects() with get_next_map_obj().";
202     struct MapObj * map_obj;
203     struct MapObjDef * mod;
204     size_t size;
205     uint8_t type;
206     char first = 1;
207     long pos;
208     uint16_t read_uint16 = 0;
209     while (1)
210     {
211         pos = ftell(file);
212         if (read_uint16_bigendian(file, &read_uint16))
213         {
214             return 1;
215         }
216         if (0 == read_uint16)
217         {
218             break;
219         }
220         fseek(file, pos, SEEK_SET);
221         if (read_uint8(file, &type))
222         {
223             return 1;
224         }
225         mod = get_map_obj_def(world, type);
226         if ('m' == mod->m_or_i)
227         {
228             size = sizeof(struct Monster);
229         }
230         else
231         {
232             size = sizeof(struct Item);
233         }
234         map_obj = get_next_map_obj(world, start, &first, size, map_obj);
235         exit_err(NULL == map_obj, world, err);
236         map_obj->type = type;
237         if (   read_uint16_bigendian(file, &map_obj->pos.y)
238             || read_uint16_bigendian(file, &map_obj->pos.x))
239         {
240             return 1;
241         }
242         map_obj->pos.y--;
243         map_obj->pos.x--;
244         if ('m' == mod->m_or_i)
245         {
246             if (read_map_objects_monsterdata(map_obj, file))
247             {
248                 return 1;
249             }
250         }
251     }
252     if (!first)
253     {
254         map_obj->next = 0;
255     }
256     return 0;
257 }
258
259
260
261 extern void * build_map_objects(struct World * world, void * start, char def_id,
262                                 uint8_t n)
263 {
264     char * err = "Trouble in build_map_objects() with get_next_map_obj().";
265     uint8_t i;
266     struct MapObj * mo;
267     char first = 1;
268     struct MapObjDef * mod = get_map_obj_def(world, def_id);
269     size_t size = 0;
270     if ('i' == mod->m_or_i)
271     {
272         size = sizeof(struct Item);
273     }
274     else
275     {
276         size = sizeof(struct Monster);
277     }
278     for (i = 0; i < n; i++)
279     {
280         mo = get_next_map_obj(world, start, &first, size, mo);
281         exit_err(NULL == mo, world, err);
282         mo->pos = find_passable_pos(world->map);
283         if ('i' == mod->m_or_i)
284         {
285             build_map_objects_itemdata(mod, mo);
286         }
287         else
288         {
289             build_map_objects_monsterdata(mod, mo);
290         }
291
292     }
293     if (!first)
294     {
295         mo->next = 0;
296     }
297     return &mo->next;
298 }
299
300
301
302 extern void free_items(struct Item * item)
303 {
304     if (0 == item)
305     {
306         return;
307     }
308     free_items((struct Item *) item->map_obj.next);
309     free(item);
310 }
311
312
313
314 extern void free_monsters(struct Monster * monster)
315 {
316     if (0 == monster)
317     {
318         return;
319     }
320     free_monsters((struct Monster *) monster->map_obj.next);
321     free(monster);
322 }
323
324
325
326 extern struct MapObjDef * get_map_obj_def(struct World * world, char def_id)
327 {
328     struct MapObjDef * d = NULL;
329     for (d = (struct MapObjDef *) world->monster_def;
330          d->id != def_id && 0 != d->next;
331          d = d->next);
332     if (d->id != def_id)
333     {
334         for (d = (struct MapObjDef *) world->item_def;
335              d->id != def_id && 0 != d->next;
336              d = d->next);
337     }
338     return d;
339 }