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