home · contact · privacy
Individual map objects are now identified by unique numbers stored in the savefiles...
[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, uint8_t * 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, uint8_t * 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_uint8(map_obj->id, file)
181             || write_uint16_bigendian(map_obj->pos.y + 1, file)
182             || write_uint16_bigendian(map_obj->pos.x + 1, file))
183         {
184             return 1;
185         }
186         mod = get_map_obj_def(world, map_obj->type);
187         if ('m' == mod->m_or_i)
188         {
189             if (write_map_objects_monsterdata(map_obj, file))
190             {
191                 return 1;
192             }
193         }
194     }
195     return write_uint16_bigendian(0, file);
196 }
197
198
199
200 extern uint8_t read_map_objects(struct World * world, void * start, FILE * file)
201 {
202     char * err = "Trouble in read_map_objects() with get_next_map_obj().";
203     struct MapObj * map_obj;
204     struct MapObjDef * mod;
205     size_t size;
206     uint8_t type;
207     uint8_t first = 1;
208     long pos;
209     uint16_t read_uint16 = 0;
210     while (1)
211     {
212         pos = ftell(file);
213         if (read_uint16_bigendian(file, &read_uint16))
214         {
215             return 1;
216         }
217         if (0 == read_uint16)
218         {
219             break;
220         }
221         fseek(file, pos, SEEK_SET);
222         if (read_uint8(file, &type))
223         {
224             return 1;
225         }
226         mod = get_map_obj_def(world, type);
227         if ('m' == mod->m_or_i)
228         {
229             size = sizeof(struct Monster);
230         }
231         else
232         {
233             size = sizeof(struct Item);
234         }
235         map_obj = get_next_map_obj(world, start, &first, size, map_obj);
236         exit_err(NULL == map_obj, world, err);
237         map_obj->type = type;
238         if (   read_uint8(file, &map_obj->id)
239             || read_uint16_bigendian(file, &map_obj->pos.y)
240             || read_uint16_bigendian(file, &map_obj->pos.x))
241         {
242             return 1;
243         }
244         map_obj->pos.y--;
245         map_obj->pos.x--;
246         if ('m' == mod->m_or_i)
247         {
248             if (read_map_objects_monsterdata(map_obj, file))
249             {
250                 return 1;
251             }
252         }
253     }
254     if (!first)
255     {
256         map_obj->next = 0;
257     }
258     return 0;
259 }
260
261
262
263 extern void * build_map_objects(struct World * world, void * start, char def_id,
264                                 uint8_t n)
265 {
266     char * err = "Trouble in build_map_objects() with get_next_map_obj().";
267     uint8_t i;
268     struct MapObj * mo;
269     uint8_t first = 1;
270     struct MapObjDef * mod = get_map_obj_def(world, def_id);
271     size_t size = 0;
272     if ('i' == mod->m_or_i)
273     {
274         size = sizeof(struct Item);
275     }
276     else
277     {
278         size = sizeof(struct Monster);
279     }
280     for (i = 0; i < n; i++)
281     {
282         mo = get_next_map_obj(world, start, &first, size, mo);
283         exit_err(NULL == mo, world, err);
284         mo->pos = find_passable_pos(world->map);
285         mo->id = world->map_object_count;
286         world->map_object_count++;
287         if ('i' == mod->m_or_i)
288         {
289             build_map_objects_itemdata(mod, mo);
290         }
291         else
292         {
293             build_map_objects_monsterdata(mod, mo);
294         }
295     }
296     if (!first)
297     {
298         mo->next = 0;
299     }
300     return &mo->next;
301 }
302
303
304
305 extern void free_items(struct Item * item)
306 {
307     if (0 == item)
308     {
309         return;
310     }
311     free_items((struct Item *) item->map_obj.next);
312     free(item);
313 }
314
315
316
317 extern void free_monsters(struct Monster * monster)
318 {
319     if (0 == monster)
320     {
321         return;
322     }
323     free_monsters((struct Monster *) monster->map_obj.next);
324     free(monster);
325 }
326
327
328
329 extern struct MapObjDef * get_map_obj_def(struct World * world, char def_id)
330 {
331     struct MapObjDef * d = NULL;
332     for (d = (struct MapObjDef *) world->monster_def;
333          d->id != def_id && 0 != d->next;
334          d = d->next);
335     if (d->id != def_id)
336     {
337         for (d = (struct MapObjDef *) world->item_def;
338              d->id != def_id && 0 != d->next;
339              d = d->next);
340     }
341     return d;
342 }