home · contact · privacy
Added primitive inventory system. Any objects may now own/contain/carry other objects.
[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 #include "yx_uint16.h" /* for yx_uint16 struct, yx_uint16_cmp() */
15
16
17
18 /* Write representation of "mo" and all of the map objects it owns to "file". */
19 static void write_map_object(struct World * w, FILE * file, struct MapObj * mo);
20
21
22
23 /* Return pointer to map object of "id" in chain starting at "ptr". */
24 static struct MapObj * get_map_object(struct MapObj * ptr, uint8_t id);
25
26
27
28 static void write_map_object(struct World * w, FILE * file, struct MapObj * mo)
29 {
30     char * f_name = "write_map_object()";
31     struct MapObj * mo_ptr = mo->owns;
32     uint8_t i = 0;
33     for (; NULL != mo_ptr; mo_ptr = mo_ptr->next, i++);
34     uint8_t size = 3+1 + 3+1 + 3+1 + 5+1 + 5 + ((1+3)*i) + 1 + 1;
35     char line[size];
36     sprintf(line, "%d %d %d %d %d",
37                   mo->id, mo->type, mo->lifepoints, mo->pos.y, mo->pos.x);
38     for (mo_ptr = mo->owns; NULL != mo_ptr; mo_ptr = mo_ptr->next)
39     {
40         sprintf(line + strlen(line), " %d", mo_ptr->id);
41     }
42     line[strlen(line) + 1] = '\0';
43     line[strlen(line)] = '\n';
44     try_fwrite(line, strlen(line), 1, file, w, f_name);
45     for (mo_ptr = mo->owns; NULL != mo_ptr; mo_ptr = mo_ptr->next)
46     {
47         write_map_object(w, file, mo_ptr);
48     }
49 }
50
51
52
53 static struct MapObj * get_map_object(struct MapObj * ptr, uint8_t id)
54 {
55     while (1)
56     {
57         if (NULL == ptr || id == ptr->id)
58         {
59             return ptr;
60         }
61         struct MapObj * owned_object = get_map_object(ptr->owns, id);
62         if (NULL != owned_object)
63         {
64             return ptr;
65         }
66         ptr = ptr->next;
67     }
68 }
69
70
71
72 extern void init_map_object_defs(struct World * world, char * filename)
73 {
74     char * f_name = "init_map_object_defs()";
75     FILE * file = try_fopen(filename, "r", world, f_name);
76     uint16_t linemax = get_linemax(file, world, f_name);
77     struct MapObjDef ** last_mod_ptr_ptr = &world->map_obj_defs;
78     char * delim = " ";
79     char line[linemax + 1];
80     while (try_fgets(line, linemax + 1, file, world, f_name))
81     {
82         struct MapObjDef * mod;
83         mod = try_malloc(sizeof(struct MapObjDef), world, f_name);
84         mod->next = NULL;
85         mod->id = atoi(strtok(line, delim));
86         mod->corpse_id = atoi(strtok(NULL, delim));
87         mod->char_on_map = * strtok(NULL, delim);
88         mod->lifepoints = atoi(strtok(NULL, delim));
89         char * name = strtok(NULL, "\n");
90         mod->name = try_malloc(strlen(name) + 1, world, f_name);
91         memcpy(mod->name, name, strlen(name) + 1);
92         * last_mod_ptr_ptr = mod;
93         last_mod_ptr_ptr = &mod->next;
94     }
95     try_fclose(file, world, f_name);
96 }
97
98
99
100 extern void free_map_object_defs(struct MapObjDef * mod_start)
101 {
102     if (NULL == mod_start)
103     {
104         return;
105     }
106     free_map_object_defs(mod_start->next);
107     free(mod_start->name);
108     free(mod_start);
109 }
110
111
112
113 extern void write_map_objects(struct World * world, FILE * file)
114 {
115     struct MapObj * mo = world->map_objs;
116     while (NULL != mo)
117     {
118         write_map_object(world, file, mo);
119         mo = mo->next;
120     }
121 }
122
123
124
125 extern void read_map_objects(struct World * world, FILE * file, char * line,
126                               int linemax)
127 {
128     char * f_name = "read_map_objects()";
129     struct MapObj ** mo_ptr_ptr = &world->map_objs;
130     char * delim = " ";
131     struct MapObj * mo;
132     fpos_t pos;
133     exit_err(-1 == fgetpos(file, &pos), world, f_name);
134     while (try_fgets(line, linemax + 1, file, world, f_name))
135     {
136         mo = malloc(sizeof(struct MapObj));
137         mo->next       = NULL;
138         mo->id         = atoi(strtok(line, delim));
139         mo->type       = atoi(strtok(NULL, delim));
140         mo->lifepoints = atoi(strtok(NULL, delim));
141         mo->pos.y      = atoi(strtok(NULL, delim));
142         mo->pos.x      = atoi(strtok(NULL, delim));
143         mo->owns       = NULL;
144         if (mo->id > world->map_obj_count)
145         {
146             world->map_obj_count = mo->id;
147         }
148         * mo_ptr_ptr = mo;
149         mo_ptr_ptr = &mo->next;
150     }
151     exit_err(-1 == fsetpos(file, &pos), world, f_name);
152     while (try_fgets(line, linemax + 1, file, world, f_name))
153     {
154         uint8_t id = atoi(strtok(line, delim));
155         strtok(NULL, delim);
156         strtok(NULL, delim);
157         strtok(NULL, delim);
158         strtok(NULL, delim);
159         char * owned = strtok(NULL, "\n");
160         if (NULL != owned)
161         {
162             mo = get_map_object(world->map_objs, id);
163             char * owned_id = "";
164             owned_id = strtok(owned, delim);
165             while (NULL != owned_id)
166             {
167                 own_map_object(&mo->owns, &world->map_objs,
168                                (uint8_t) atoi(owned_id));
169                 owned_id = strtok(NULL, delim);
170             }
171         }
172     }
173 }
174
175
176
177 extern void add_map_object(struct World * world, uint8_t type)
178 {
179     char * f_name = "add_map_object()";
180     struct MapObjDef * mod = get_map_object_def(world, type);
181     struct MapObj * mo = try_malloc(sizeof(struct MapObj), world, f_name);
182     mo->id = world->map_obj_count;
183     world->map_obj_count++;
184     mo->type = mod->id;
185     mo->lifepoints = mod->lifepoints;
186     while (1)
187     {
188         struct yx_uint16 pos = find_passable_pos(world->map);
189         struct MapObj * mo_ptr;
190         uint8_t clear = 1;
191         for (mo_ptr = world->map_objs;
192              mo_ptr != NULL;
193              mo_ptr = mo_ptr->next)
194         {
195             if (yx_uint16_cmp(&pos, &mo_ptr->pos) && 0 != mo_ptr->lifepoints)
196             {
197                 clear = 0;
198                 break;
199             }
200         }
201         if (1 == clear)
202         {
203             mo->pos = pos;
204             break;
205         }
206     }
207     mo->owns = NULL;
208     mo->next = NULL;
209     struct MapObj ** last_ptr_ptr = &world->map_objs;
210     struct MapObj * mo_ptr;
211     while (NULL != * last_ptr_ptr)
212     {
213         mo_ptr = * last_ptr_ptr;
214         last_ptr_ptr = & mo_ptr->next;
215     }
216     * last_ptr_ptr = mo;
217 }
218
219
220
221 extern void add_map_objects(struct World * world, uint8_t type, uint8_t n)
222 {
223     uint8_t i;
224     for (i = 0; i < n; i++)
225     {
226         add_map_object(world, type);
227     }
228 }
229
230
231
232 extern void free_map_objects(struct MapObj * mo_start)
233 {
234     if (NULL == mo_start)
235     {
236         return;
237     }
238     free_map_objects(mo_start->owns);
239     free_map_objects(mo_start->next);
240     free(mo_start);
241 }
242
243
244
245 extern void own_map_object(struct MapObj ** target, struct MapObj ** source,
246                            uint8_t id)
247 {
248     struct MapObj * mo;
249     if (id == (*source)->id)
250     {
251         mo = * source;
252         * source = mo->next;
253     }
254     else
255     {
256         struct MapObj * penult = * source;
257         while (1)
258         {
259             if (id == penult->next->id)
260             {
261                 break;
262             }
263             penult = penult->next;
264         }
265         mo = penult->next;
266         penult->next = mo->next;
267     }
268     struct MapObj ** last_ptr_ptr = target;
269     struct MapObj * mo_ptr;
270     while (NULL != * last_ptr_ptr)
271     {
272         mo_ptr = * last_ptr_ptr;
273         last_ptr_ptr = & mo_ptr->next;
274     }
275     * last_ptr_ptr = mo;
276     mo->next = NULL;
277 }
278
279
280
281 extern struct MapObj * get_player(struct World * world)
282 {
283     return get_map_object(world->map_objs, 0);
284 }
285
286
287
288 extern struct MapObjDef * get_map_object_def(struct World * w, uint8_t id)
289 {
290     struct MapObjDef * mod = w->map_obj_defs;
291     while (id != mod->id)
292     {
293         mod = mod->next;
294     }
295     return mod;
296 }
297
298
299
300 extern void set_object_position(struct MapObj * mo, struct yx_uint16 pos)
301 {
302     mo->pos = pos;
303     struct MapObj * owned = mo->owns;
304     for (; owned != NULL; owned = owned->next)
305     {
306         set_object_position(owned, pos);
307     }
308 }