home · contact · privacy
Make server config files more readable, their parsing more lenient.
[plomrogue] / src / server / map_objects.c
1 /* src/server/map_objects.c */
2
3 #include "map_objects.h"
4 #include <stddef.h> /* NULL */
5 #include <stdint.h> /* uint8_t, uint16_t */
6 #include <stdlib.h> /* free() */
7 #include <string.h> /* memset(), strlen() */
8 #include "../common/rexit.h" /* exit_err() */
9 #include "../common/try_malloc.h" /* try_malloc() */
10 #include "../common/yx_uint8.h" /* yx_uint8 struct */
11 #include "map.h" /* is_passable() */
12 #include "rrand.h" /* rrand() */
13 #include "world.h" /* global world */
14 #include "yx_uint8.h" /* yx_uint8_cmp() */
15
16
17
18 /* Return pointer to map object of "id" in chain starting at "ptr". */
19 static struct MapObj * get_map_object(struct MapObj * ptr, uint8_t id);
20
21 /* Return random passable (as by is_passable()) position on world.map. */
22 static struct yx_uint8 find_passable_pos();
23
24 /* Add object of "type" to map on random position. Don't place actor on actor.*/
25 static void add_map_object(uint8_t type);
26
27
28
29 static struct MapObj * get_map_object(struct MapObj * ptr, uint8_t id)
30 {
31     while (1)
32     {
33         if (NULL == ptr || id == ptr->id)
34         {
35             return ptr;
36         }
37         struct MapObj * owned_object = get_map_object(ptr->owns, id);
38         if (NULL != owned_object)
39         {
40             return ptr;
41         }
42         ptr = ptr->next;
43     }
44 }
45
46
47
48 static struct yx_uint8 find_passable_pos()
49 {
50     struct yx_uint8 pos;
51     for (pos.y = pos.x = 0; 0 == is_passable(pos);)
52     {
53         pos.y = rrand() % world.map.size.y;
54         pos.x = rrand() % world.map.size.x;
55     }
56     return pos;
57 }
58
59
60
61 static void add_map_object(uint8_t type)
62 {
63     char * f_name = "add_map_object()";
64     struct MapObjDef * mod = get_map_object_def(type);
65     struct MapObj *    mo  = try_malloc(sizeof(struct MapObj), f_name);
66     memset(mo, 0, sizeof(struct MapObj));
67     mo->id         = world.map_obj_count++;
68     mo->type       = mod->id;
69     mo->lifepoints = mod->lifepoints;
70     while (1)
71     {
72         struct yx_uint8 pos = find_passable_pos(world.map);
73         struct MapObj * mo_ptr;
74         uint8_t clear = 1;
75         for (mo_ptr = world.map_objs; mo_ptr != NULL; mo_ptr = mo_ptr->next)
76         {
77             if (yx_uint8_cmp(&pos, &mo_ptr->pos) && 0 != mo_ptr->lifepoints)
78             {
79                 clear = 0;
80                 break;
81             }
82         }
83         if (1 == clear)
84         {
85             mo->pos = pos;
86             break;
87         }
88     }
89     struct MapObj ** mo_ptr_ptr = &world.map_objs;
90     for (; NULL != * mo_ptr_ptr; mo_ptr_ptr = &(*mo_ptr_ptr)->next);
91     * mo_ptr_ptr = mo;
92 }
93
94
95
96 extern void free_map_object_defs(struct MapObjDef * mod_start)
97 {
98     if (NULL == mod_start)
99     {
100         return;
101     }
102     free_map_object_defs(mod_start->next);
103     free(mod_start->name);
104     free(mod_start);
105 }
106
107
108
109 extern void add_map_objects(uint8_t type, uint8_t n)
110 {
111     uint8_t i;
112     for (i = 0; i < n; i++)
113     {
114         add_map_object(type);
115     }
116 }
117
118
119
120 extern void free_map_objects(struct MapObj * mo_start)
121 {
122     if (NULL == mo_start)
123     {
124         return;
125     }
126     free_map_objects(mo_start->owns);
127     free_map_objects(mo_start->next);
128     free(mo_start);
129     if (mo_start == world.map_objs)  /* So add_map_objects()' NULL-delimited  */
130     {                                /* map object iteration loop does not    */
131         world.map_objs = NULL;       /* iterate over freed memory when called */
132     }                                /* the 1st time after world re-seeding.  */
133 }
134
135
136
137 extern void own_map_object(struct MapObj ** target, struct MapObj ** source,
138                            uint8_t id)
139 {
140     struct MapObj * mo;
141     if (id == (*source)->id)
142     {
143         mo = * source;
144         * source = mo->next;
145     }
146     else
147     {
148         struct MapObj * penult = * source;
149         while (1)
150         {
151             if (id == penult->next->id)
152             {
153                 break;
154             }
155             penult = penult->next;
156         }
157         mo = penult->next;
158         penult->next = mo->next;
159     }
160     struct MapObj ** mo_ptr_ptr = target;
161     for (; NULL != * mo_ptr_ptr; mo_ptr_ptr = &(*mo_ptr_ptr)->next);
162     * mo_ptr_ptr = mo;
163     mo->next = NULL;
164 }
165
166
167
168 extern struct MapObj * get_player()
169 {
170     return get_map_object(world.map_objs, 0);
171 }
172
173
174
175 extern struct MapObjDef * get_map_object_def(uint8_t id)
176 {
177     struct MapObjDef * mod = world.map_obj_defs;
178     for (; NULL != mod && id != mod->id; mod = mod->next);
179     char * err_intro = "Requested map object definition of unused ID ";
180     char err[strlen(err_intro) + 3 + 1 + 1];
181     sprintf(err, "%s%d.", err_intro, id);
182     exit_err(NULL == mod, err);
183     return mod;
184 }
185
186
187
188 extern void set_object_position(struct MapObj * mo, struct yx_uint8 pos)
189 {
190     mo->pos = pos;
191     struct MapObj * owned = mo->owns;
192     for (; owned != NULL; set_object_position(owned, pos), owned = owned->next);
193 }