home · contact · privacy
a4d4fbe09d15b03e8f3d5747dd272e59dc1ff056
[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, j;
70     uint16_t i;
71     for (dist = 1; !escape && dist <= dist_max; dist++)
72     {
73         char * path = try_malloc(dist + 1, f_name);
74         memset(path, 'N', dist);
75         path[dist] = '\0';
76         for (i = 0; !escape && i < (dist * 4); i++)
77         {
78             clockwise_path(&path);
79             struct yx_uint16 testpos = origin;
80             for (j = 0; j < dist; j++)
81             {
82                 testpos = mv_yx_in_dir(path[j], testpos);
83             }
84             if (yx_uint16_cmp(&testpos, &origin) ||
85                 testpos.y > world.map->size.y || testpos.x > world.map->size.x)
86             {
87                 continue;
88             }
89             for (mo = world.map_objs; mo != 0; mo = mo->next)
90             {
91                 if (mo->lifepoints && 1 == yx_uint16_cmp(&testpos, &mo->pos))
92                 {
93                     sel = path[0];
94                     escape = 1;
95                     break;
96                 }
97             }
98         }
99         free(path);
100     }
101     return sel;
102 }
103
104
105
106 extern void pretty_dumb_ai(struct MapObj * mo)
107 {
108     mo->command = get_moa_id_by_name("wait");
109     char sel = nearest_enemy_dir(mo->pos);
110     if (0 != sel)
111     {
112         mo->command = get_moa_id_by_name("move");
113         mo->arg = sel;
114     }
115 }