home · contact · privacy
Replaced fgets() with try_fgets() in keybindings library.
[plomrogue] / src / ai.c
1 /* ai.c */
2
3 #include "ai.h"
4 #include <stdlib.h> /* for free() */
5 #include <string.h> /* for strlen(), memset() */
6 #include <stdint.h> /* for uint8_t */
7 #include "main.h" /* for world global */
8 #include "misc.h" /* for try_malloc() */
9 #include "map.h" /* for Map struct */
10 #include "yx_uint16.h" /* for yx_uint16 struct,yx_uint16_cmp(),mv_yx_in_dir() */
11 #include "map_objects.h" /* for MapObj struct */
12 #include "map_object_actions.h" /* for get_moa_id_by_name() */
13
14
15
16 /* Change cardinal direction string ("NNE" etc.) of any length >1 pointed to by
17  * "path_ptr" one step clockwise ("NNE" -> "NEE", "NEE" -> "EEE" etc.).
18  */
19 static void clockwise_path(char ** path_ptr);
20
21 /* Return dir char (north = "N" etc.) to enemy nearest to "origin" (beeline). */
22 static char nearest_enemy_dir(struct yx_uint16 origin);
23
24
25
26 static void clockwise_path(char ** path_ptr)
27 {
28     char * path = * path_ptr;
29     char old_char = path[0];
30     char new_char = 'N';
31     if      ('N' == old_char)
32     {
33         new_char = 'E';
34     }
35     else if ('E' == old_char)
36     {
37         new_char = 'S';
38     }
39     else if ('S' == old_char)
40     {
41         new_char = 'W';
42     }
43     uint8_t len = strlen(path);
44     uint8_t i;
45     for (; i < len; i++)
46     {
47         uint8_t next_i = i + 1;
48         if (next_i == len || old_char != path[next_i])
49         {
50             break;
51         }
52     }
53     path[i] = new_char;
54 }
55
56
57
58 static char nearest_enemy_dir(struct yx_uint16 origin)
59 {
60     char * f_name = "nearest_enemy_dir()";
61     struct MapObj * mo;
62     char sel = 0;
63     uint16_t dist_max = world.map->size.y;
64     if (world.map->size.x > world.map->size.y)
65     {
66         dist_max = world.map->size.x;
67     }
68     uint8_t escape = 0;
69     uint8_t dist, i, j;
70     for (dist = 1; !escape && dist <= dist_max; dist++)
71     {
72         char * path = try_malloc(dist + 1, f_name);
73         memset(path, 'N', dist);
74         path[dist] = '\0';
75         for (i = 0; !escape && i < (dist * 4); i++)
76         {
77             clockwise_path(&path);
78             struct yx_uint16 testpos = origin;
79             for (j = 0; j < dist; j++)
80             {
81                 testpos = mv_yx_in_dir(path[j], testpos);
82             }
83             if (yx_uint16_cmp(&testpos, &origin) ||
84                 testpos.y > world.map->size.y || testpos.x > world.map->size.x)
85             {
86                 continue;
87             }
88             for (mo = world.map_objs; mo != 0; mo = mo->next)
89             {
90                 if (mo->lifepoints && 1 == yx_uint16_cmp(&testpos, &mo->pos))
91                 {
92                     sel = path[0];
93                     escape = 1;
94                     break;
95                 }
96             }
97         }
98         free(path);
99     }
100     return sel;
101 }
102
103
104
105 extern void pretty_dumb_ai(struct MapObj * mo)
106 {
107     mo->command = get_moa_id_by_name("wait");
108     char sel = nearest_enemy_dir(mo->pos);
109     if (0 != sel)
110     {
111         mo->command = get_moa_id_by_name("move");
112         mo->arg = sel;
113     }
114 }