home · contact · privacy
Each map object action now take different numbers of turns to complete. Re-wrote...
[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(), get_linemax() */
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_select 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_select)
139         {
140             world.inventory_select--;
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_select)
175         {
176             world.inventory_select--;
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 = get_linemax(file, f_name);
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 void actor_wait(struct MapObj * mo)
237 {
238     if (mo == get_player())
239     {
240         playerbonus_wait();
241     }
242 }
243
244
245
246 extern void actor_move(struct MapObj * mo)
247 {
248     char d = mo->arg;
249     struct yx_uint16 target = mv_yx_in_dir(d, mo->pos);
250     struct MapObj * other_mo;
251     for (other_mo = world.map_objs; other_mo != 0; other_mo = other_mo->next)
252     {
253         if (0 == other_mo->lifepoints || other_mo == mo)
254         {
255             continue;
256         }
257         if (yx_uint16_cmp(&target, &other_mo->pos))
258         {
259             actor_hits_actor(mo, other_mo);
260             return;
261         }
262     }
263     uint8_t passable = is_passable(world.map, target);
264     if (passable)
265     {
266         set_object_position(mo, target);
267     }
268     if (mo == get_player())
269     {
270         playerbonus_move(d, passable);
271     }
272 }
273
274
275
276 extern void actor_drop(struct MapObj * mo)
277 {
278     uint8_t owns_none = (NULL == mo->owns);
279     if (!owns_none)
280     {
281         uint8_t select = mo->arg;
282         struct MapObj * owned = mo->owns;
283         uint8_t i = 0;
284         for (; i != select; i++, owned = owned->next);
285         own_map_object(&world.map_objs, &mo->owns, owned->id);
286     }
287     if (mo == get_player())
288     {
289         playerbonus_drop(owns_none);
290     }
291 }
292
293
294
295 extern void actor_pick(struct MapObj * mo)
296 {
297     struct MapObj * picked;
298     for (picked = world.map_objs; NULL != picked; picked = picked->next)
299     {
300         if (picked != mo && yx_uint16_cmp(&picked->pos, &mo->pos))
301         {
302             break;
303         }
304     }
305     if (NULL != picked)
306     {
307         own_map_object(&mo->owns, &world.map_objs, picked->id);
308         set_object_position(picked, mo->pos);
309     }
310     if (mo == get_player())
311     {
312         playerbonus_pick(NULL != picked);
313     }
314 }
315
316
317
318 extern void actor_use(struct MapObj * mo)
319 {
320     uint8_t wrong_object = 1;
321     uint8_t no_object = (NULL == mo->owns);
322     if (!no_object)
323     {
324         uint8_t select = mo->arg;
325         uint8_t i = 0;
326         struct MapObj * selected = mo->owns;
327         for (; i != select; i++, selected = selected->next);
328         struct MapObjDef * mod = get_map_object_def(selected->type);
329         if (!strcmp("MAGIC MEAT", mod->name))
330         {
331             wrong_object = 0;
332             struct MapObj * next = selected->next;
333             free(selected);
334             if (0 < select)
335             {
336                 select--;
337                 for (i = 0, selected = mo->owns;
338                      i != select;
339                      i++, selected = selected->next);
340                 selected->next = next;
341             }
342             else
343             {
344                 mo->owns = next;
345             }
346             mo->lifepoints++;
347         }
348     }
349     if (mo == get_player())
350     {
351         playerbonus_use(no_object, wrong_object);
352     }
353 }