home · contact · privacy
Built error checking into file reading/writing routines and calls of them.
[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 <stdio.h> /* for FILE typedef */
6 #include <string.h> /* for strchr(), strlen(), memcpy()  */
7 #include "readwrite.h" /* for [read/write]_uint[8/16/23][_bigendian]() */
8 #include "misc.h" /* for textfile_sizes(), find_passable_pos() */
9 #include "main.h" /* for World struct */
10
11
12
13 /* Return pointer to newly allocated map object struct of size "size". If first
14  * in map object chain ("first" pointing to !0), point "start" to it.
15  */
16 static struct MapObj * get_next_map_obj(void * start, char * first,
17                                         size_t size, struct MapObj * map_obj);
18
19
20
21 /* Map-object-type-specific helpers to (build|write|read)_map_objects(). */
22 static void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
23                                        void * start);
24 static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
25                                           void * start);
26 static uint8_t write_map_objects_monsterdata(void * start, FILE * file);
27 static uint8_t read_map_objects_monsterdata( void * start, FILE * file);
28
29
30
31 static struct MapObj * get_next_map_obj(void * start, char * first,
32                                         size_t size, struct MapObj * map_obj)
33 {
34     if (* first)
35     {
36         struct MapObj * * z = start;
37         map_obj = malloc(size);
38         * z = map_obj;
39         * first = 0;
40     }
41     else
42     {
43         map_obj->next = malloc(size);
44         map_obj = map_obj->next;
45     }
46     return map_obj;
47 }
48
49
50
51 static void build_map_objects_itemdata(struct MapObjDef * map_obj_def,
52                                        void * start)
53 {
54   struct Item * i = (struct Item *) start;
55   i->map_obj.type = map_obj_def->id;
56 }
57
58
59
60 static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def,
61                                           void * start)
62 {
63     struct Monster * m = (struct Monster *) start;
64     m->map_obj.type = map_obj_def->id;
65     struct MonsterDef * md = (struct MonsterDef *) map_obj_def;
66     m->hitpoints = md->hitpoints_start;
67 }
68
69
70
71 static uint8_t write_map_objects_monsterdata(void * start, FILE * file)
72 {
73     struct Monster * m = (struct Monster *) start;
74     return write_uint8(m->hitpoints, file);
75 }
76
77
78
79 static uint8_t read_map_objects_monsterdata (void * start, FILE * file)
80 {
81     struct Monster * m = (struct Monster *) start;
82     return read_uint8(file, &m->hitpoints);
83 }
84
85
86
87 extern void init_map_object_defs(struct World * world, char * filename)
88 {
89     world->item_def    = 0;
90     world->monster_def = 0;
91     FILE * file = fopen(filename, "r");
92     uint16_t linemax;
93     textfile_sizes (file, &linemax, NULL);
94     struct MapObjDef  mod;
95     struct ItemDef    id;
96     struct MonsterDef md;
97     struct ItemDef    * * p_p_id  = &world->item_def;
98     struct MonsterDef * * p_p_md  = &world->monster_def;
99     char * defline = malloc(linemax);
100     char * line_p;
101     while (fgets(defline, linemax, file))
102     {
103         mod.next    = 0;
104         mod.id      = atoi(defline);
105         line_p      = strchr(defline, ' ') + 1;
106         mod.m_or_i  = * line_p;
107         mod.mapchar = * (line_p + 2);
108         if ('i' == mod.m_or_i)
109         {
110             line_p = line_p + 5;
111         }
112         else
113         {
114             md.hitpoints_start = atoi   (line_p + 4);
115             line_p             = strchr (line_p + 4, ' ') + 1;
116         }
117         mod.desc = calloc (strlen (line_p), sizeof(char));
118         memcpy (mod.desc, line_p, strlen(line_p) - 1);
119         if ('i' == mod.m_or_i)
120         {
121             id.map_obj_def = mod;
122             * p_p_id       = malloc(sizeof(struct ItemDef));
123             * * p_p_id     = id;
124             p_p_id         = (struct ItemDef    * *) * p_p_id;
125         }
126         else
127         {
128             md.map_obj_def = mod;
129             * p_p_md       = malloc(sizeof(struct MonsterDef));
130             * * p_p_md     = md;
131             p_p_md         = (struct MonsterDef * *) * p_p_md;
132         }
133     }
134     free(defline);
135     fclose(file);
136 };
137
138
139
140 extern uint8_t write_map_objects(struct World * world, void * start,
141                                  FILE * file)
142 {
143     struct MapObj * map_obj;
144     struct MapObjDef * mod;
145     uint8_t fail = 0;
146     for (map_obj = start; map_obj != 0; map_obj = map_obj->next)
147     {
148         fail = fail | write_uint8(map_obj->type, file);
149         fail = fail | write_uint16_bigendian(map_obj->pos.y + 1, file);
150         fail = fail | write_uint16_bigendian(map_obj->pos.x + 1, file);
151         mod = get_map_obj_def(world, map_obj->type);
152         if ('m' == mod->m_or_i)
153         {
154             fail = fail | write_map_objects_monsterdata(map_obj, file);
155         }
156     }
157     return (fail | write_uint16_bigendian(0, file));
158 }
159
160
161
162 extern uint8_t read_map_objects(struct World * world, void * start, FILE * file)
163 {
164     struct MapObj * map_obj;
165     struct MapObjDef * mod;
166     size_t size;
167     uint8_t type;
168     char first = 1;
169     long pos;
170     uint16_t read_uint16 = 0;
171     uint8_t fail = 0;
172     while (1)
173     {
174         pos = ftell(file);
175         fail = fail | read_uint16_bigendian(file, &read_uint16);
176         if (0 == read_uint16)
177         {
178             break;
179         }
180         fseek(file, pos, SEEK_SET);
181         fail = fail | read_uint8(file, &type);
182         mod = get_map_obj_def(world, type);
183         if ('m' == mod->m_or_i)
184         {
185             size = sizeof(struct Monster);
186         }
187         else
188         {
189             size = sizeof(struct Item);
190         }
191         map_obj = get_next_map_obj(start, &first, size, map_obj);
192         map_obj->type = type;
193         fail = fail | read_uint16_bigendian(file, &map_obj->pos.y);
194         fail = fail | read_uint16_bigendian(file, &map_obj->pos.x);
195         map_obj->pos.y--;
196         map_obj->pos.x--;
197         if ('m' == mod->m_or_i)
198         {
199             fail = fail | read_map_objects_monsterdata(map_obj, file);
200         }
201     }
202     if (!first)
203     {
204         map_obj->next = 0;
205     }
206     return fail;
207 }
208
209
210
211 extern void * build_map_objects(struct World * world, void * start, char def_id,
212                                 unsigned char n)
213 {
214     unsigned char i;
215     struct MapObj * mo;
216     char first = 1;
217     struct MapObjDef * mod = get_map_obj_def(world, def_id);
218     size_t size = 0;
219     if ('i' == mod->m_or_i)
220     {
221         size = sizeof(struct Item);
222     }
223     else
224     {
225         size = sizeof(struct Monster);
226     }
227     for (i = 0; i < n; i++)
228     {
229         mo = get_next_map_obj(start, &first, size, mo);
230         mo->pos = find_passable_pos(world->map);
231         if ('i' == mod->m_or_i)
232         {
233             build_map_objects_itemdata(mod, mo);
234         }
235         else
236         {
237             build_map_objects_monsterdata(mod, mo);
238         }
239
240     }
241     if (!first)
242     {
243         mo->next = 0;
244     }
245     return &mo->next;
246 }
247
248
249
250 extern struct MapObjDef * get_map_obj_def (struct World * world, char def_id)
251 {
252     struct MapObjDef * d = NULL;
253     for (d = (struct MapObjDef *) world->monster_def;
254          d->id != def_id && 0 != d->next;
255          d = d->next);
256     if (d->id != def_id)
257     {
258         for (d = (struct MapObjDef *) world->item_def;
259              d->id != def_id && 0 != d->next;
260              d = d->next);
261     }
262     return d;
263 }