home · contact · privacy
Refactorisation and comment improvements in misc library.
[plomrogue] / src / map_object_actions.c
1 /* map_object_actions.c */
2
3 #include "map_object_actions.h"
4 #include <stdint.h> /* for uint8_t */
5 #include <string.h> /* for strlen(), strcmp() */
6 #include "yx_uint16.h" /* for yx_uint16 struct, mv_yx_in_dir(),
7                         * yx_uint16_cmp()
8                         */
9 #include "map_objects.h" /* for MapObj, MapObjDef structs, get_player(),
10                           * set_object_position(), own_map_object()
11                           */
12 #include "misc.h" /* for update_log(), try_malloc() */
13 #include "map.h" /* for is_passable() */
14 #include "main.h" /* for world global */
15 #include "readwrite.h" /* for try_fopen(), try_fclose(), textfile_sizes() */
16 #include "rexit.h" /* for exit_err() */
17
18
19
20 /* If "name" fits "moa"->name, set "moa"->func to "func". */
21 static uint8_t try_func_name(struct MapObjAct * moa,
22                              char * name, void (* func) (struct MapObj *));
23
24 /* One actor "wounds" another actor, decrementing his lifepoints and, if they
25  * reach zero in the process, killing it. Generates appropriate log message.
26  */
27 static void actor_hits_actor(struct MapObj * hitter, struct MapObj * hitted);
28
29 /* Bonus stuff to actor_*() to happen if actor==player. Mostly writing of log
30  * messages; _pick and _drop also decrement world.inventory_sel by 1 if >0.
31  */
32 static void playerbonus_wait();
33 static void playerbonus_move(char d, uint8_t passable);
34 static void playerbonus_drop(uint8_t owns_none);
35 static void playerbonus_pick(uint8_t picked);
36 static void playerbonus_use(uint8_t no_object, uint8_t wrong_object);
37
38
39
40 static uint8_t try_func_name(struct MapObjAct * moa,
41                              char * name, void (* func) (struct MapObj *))
42 {
43     if (0 == strcmp(moa->name, name))
44     {
45         moa->func = func;
46         return 1;
47     }
48     return 0;
49 }
50
51
52
53 static void actor_hits_actor(struct MapObj * hitter, struct MapObj * hitted)
54 {
55     struct MapObjDef * mod_hitter = get_map_object_def(hitter->type);
56     struct MapObjDef * mod_hitted = get_map_object_def(hitted->type);
57     struct MapObj * player = get_player();
58     char * msg1 = "You";
59     char * msg2 = "wound";
60     char * msg3 = "you";
61     if      (player != hitter)
62     {
63         msg1 = mod_hitter->name;
64         msg2 = "wounds";
65     }
66     if (player != hitted)
67     {
68         msg3 = mod_hitted->name;
69     }
70     uint8_t len = 1 + strlen(msg1) + 1 + strlen(msg2) + 1 + strlen(msg3) + 2;
71     char msg[len];
72     sprintf(msg, "\n%s %s %s.", msg1, msg2, msg3);
73     update_log(msg);
74     hitted->lifepoints--;
75     if (0 == hitted->lifepoints)
76     {
77         hitted->type = mod_hitted->corpse_id;
78         if (player == hitted)
79         {
80             update_log(" You die.");
81         }
82         else
83         {
84             update_log(" It dies.");
85             if (player == hitter)
86             {
87                 world.score = world.score + mod_hitted->lifepoints;
88             }
89         }
90     }
91 }
92
93
94
95 static void playerbonus_wait()
96 {
97         update_log("\nYou wait.");
98 }
99
100
101
102 static void playerbonus_move(char d, uint8_t passable)
103 {
104     char * dsc_dir = "north";
105     if      ('E' == d)
106     {
107         dsc_dir = "east" ;
108     }
109     else if ('S' == d)
110     {
111         dsc_dir = "south";
112     }
113     else if ('W' == d)
114     {
115         dsc_dir = "west" ;
116     }
117     char * dsc_move = "You move ";
118     if (0 == passable)
119     {
120         dsc_move = "You fail to move ";
121     }
122     char msg[strlen(dsc_move) + strlen (dsc_dir) + 3];
123     sprintf(msg, "\n%s%s.", dsc_move, dsc_dir);
124     update_log(msg);
125 }
126
127
128
129 static void playerbonus_drop(uint8_t owns_none)
130 {
131     if (0 != owns_none)
132     {
133         update_log("\nYou try to drop an object, but you own none.");
134     }
135     else
136     {
137         update_log("\nYou drop an object.");
138         if (0 < world.inventory_sel)
139         {
140             world.inventory_sel--;
141         }
142     }
143 }
144
145
146
147 static void playerbonus_pick(uint8_t picked)
148 {
149     if (picked)
150     {
151         update_log("\nYou pick up an object.");
152     }
153     else
154     {
155         update_log("\nYou try to pick up an object, but there is none.");
156     }
157 }
158
159
160
161 static void playerbonus_use(uint8_t no_object, uint8_t wrong_object)
162 {
163     if      (no_object)
164     {
165         update_log("\nYou try to use an object, but you own none.");
166     }
167     else if (wrong_object)
168     {
169         update_log("\nYou try to use this object, but fail.");
170     }
171     else
172     {
173         update_log("\nYou consume MAGIC MEAT.");
174         if (0 < world.inventory_sel)
175         {
176             world.inventory_sel--;
177         }
178     }
179 }
180
181
182
183 extern void init_map_object_actions()
184 {
185     char * f_name = "init_map_object_actions()";
186
187     char * path = "config/map_object_actions";
188     FILE * file = try_fopen(path, "r", f_name);
189     uint16_t linemax = textfile_sizes(file, NULL);
190     char line[linemax + 1];
191
192     struct MapObjAct ** moa_ptr_ptr = &world.map_obj_acts;
193     char * delim = " ";
194     while (fgets(line, linemax + 1, file))
195     {
196         if ('\n' == line[0] || 0 == line[0])
197         {
198             break;
199         }
200         struct MapObjAct * moa = try_malloc(sizeof(struct MapObjAct), f_name);
201         moa->id = atoi(strtok(line, delim));
202         moa->effort = atoi(strtok(NULL, delim));
203         char * funcname = strtok(NULL, "\n");
204         uint8_t len_name = strlen(funcname) + 1;
205         moa->name = try_malloc(len_name, f_name);
206         memcpy(moa->name, funcname, len_name);
207         if (!(   try_func_name(moa, "move", actor_move)
208               || try_func_name(moa, "pick_up", actor_pick)
209               || try_func_name(moa, "drop", actor_drop)
210               || try_func_name(moa, "use", actor_use)))
211         {
212             moa->func = actor_wait;
213         }
214         moa->next = NULL;
215         * moa_ptr_ptr = moa;
216         moa_ptr_ptr = &moa->next;
217     }
218     try_fclose(file, f_name);
219 }
220
221
222
223 extern void free_map_object_actions(struct MapObjAct * moa)
224 {
225     if (NULL == moa)
226     {
227         return;
228     }
229     free(moa->name);
230     free_map_object_actions(moa->next);
231     free(moa);
232 }
233
234
235
236 extern uint8_t get_moa_id_by_name(char * name)
237 {
238     struct MapObjAct * moa = world.map_obj_acts;
239     while (NULL != moa)
240     {
241         if (0 == strcmp(moa->name, name))
242         {
243             break;
244         }
245         moa = moa->next;
246     }
247     exit_err(NULL == moa, "get_moa_id_name() did not find map object action.");
248     return moa->id;
249 }
250
251
252
253 extern void actor_wait(struct MapObj * mo)
254 {
255     if (mo == get_player())
256     {
257         playerbonus_wait();
258     }
259 }
260
261
262
263 extern void actor_move(struct MapObj * mo)
264 {
265     char d = mo->arg;
266     struct yx_uint16 target = mv_yx_in_dir(d, mo->pos);
267     struct MapObj * other_mo;
268     for (other_mo = world.map_objs; other_mo != 0; other_mo = other_mo->next)
269     {
270         if (0 == other_mo->lifepoints || other_mo == mo)
271         {
272             continue;
273         }
274         if (yx_uint16_cmp(&target, &other_mo->pos))
275         {
276             actor_hits_actor(mo, other_mo);
277             return;
278         }
279     }
280     uint8_t passable = is_passable(world.map, target);
281     if (passable)
282     {
283         set_object_position(mo, target);
284     }
285     if (mo == get_player())
286     {
287         playerbonus_move(d, passable);
288     }
289 }
290
291
292
293 extern void actor_drop(struct MapObj * mo)
294 {
295     uint8_t owns_none = (NULL == mo->owns);
296     if (!owns_none)
297     {
298         uint8_t select = mo->arg;
299         struct MapObj * owned = mo->owns;
300         uint8_t i = 0;
301         for (; i != select; i++, owned = owned->next);
302         own_map_object(&world.map_objs, &mo->owns, owned->id);
303     }
304     if (mo == get_player())
305     {
306         playerbonus_drop(owns_none);
307     }
308 }
309
310
311
312 extern void actor_pick(struct MapObj * mo)
313 {
314     struct MapObj * picked;
315     for (picked = world.map_objs; NULL != picked; picked = picked->next)
316     {
317         if (picked != mo && yx_uint16_cmp(&picked->pos, &mo->pos))
318         {
319             break;
320         }
321     }
322     if (NULL != picked)
323     {
324         own_map_object(&mo->owns, &world.map_objs, picked->id);
325         set_object_position(picked, mo->pos);
326     }
327     if (mo == get_player())
328     {
329         playerbonus_pick(NULL != picked);
330     }
331 }
332
333
334
335 extern void actor_use(struct MapObj * mo)
336 {
337     uint8_t wrong_object = 1;
338     uint8_t no_object = (NULL == mo->owns);
339     if (!no_object)
340     {
341         uint8_t select = mo->arg;
342         uint8_t i = 0;
343         struct MapObj * selected = mo->owns;
344         for (; i != select; i++, selected = selected->next);
345         struct MapObjDef * mod = get_map_object_def(selected->type);
346         if (!strcmp("MAGIC MEAT", mod->name))
347         {
348             wrong_object = 0;
349             struct MapObj * next = selected->next;
350             free(selected);
351             if (0 < select)
352             {
353                 select--;
354                 for (i = 0, selected = mo->owns;
355                      i != select;
356                      i++, selected = selected->next);
357                 selected->next = next;
358             }
359             else
360             {
361                 mo->owns = next;
362             }
363             mo->lifepoints++;
364         }
365     }
366     if (mo == get_player())
367     {
368         playerbonus_use(no_object, wrong_object);
369     }
370 }