home · contact · privacy
Replaced random movement by enemies with a pretty dumb AI of "move in direction of...
authorChristian Heller <c.heller@plomlompom.de>
Tue, 26 Nov 2013 01:57:10 +0000 (02:57 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Tue, 26 Nov 2013 01:57:10 +0000 (02:57 +0100)
src/ai.c [new file with mode: 0644]
src/ai.h [new file with mode: 0644]
src/misc.c
src/yx_uint16.c
src/yx_uint16.h

diff --git a/src/ai.c b/src/ai.c
new file mode 100644 (file)
index 0000000..aee8e73
--- /dev/null
+++ b/src/ai.c
@@ -0,0 +1,115 @@
+/* ai.c */
+
+#include "ai.h"
+#include <stdlib.h> /* for free() */
+#include <string.h> /* for strlen(), memset() */
+#include <stdint.h> /* for uint8_t */
+#include "main.h" /* for world global */
+#include "misc.h" /* for try_malloc() */
+#include "map.h" /* for Map struct */
+#include "yx_uint16.h" /* for yx_uint16 struct,yx_uint16_cmp(),mv_yx_in_dir() */
+#include "map_objects.h" /* for MapObj struct */
+#include "map_object_actions.h" /* for get_moa_id_by_name() */
+
+
+
+/* Change cardinal direction string ("NNE" etc.) of any length >1 pointed to by
+ * "path_ptr" one step clockwise ("NNE" -> "NEE", "NEE" -> "EEE" etc.).
+ */
+static void clockwise_path(char ** path_ptr);
+
+/* Return dir char (north = "N" etc.) to enemy nearest to "origin" (beeline). */
+static char nearest_enemy_dir(struct yx_uint16 origin);
+
+
+
+static void clockwise_path(char ** path_ptr)
+{
+    char * path = * path_ptr;
+    char old_char = path[0];
+    char new_char = 'N';
+    if      ('N' == old_char)
+    {
+        new_char = 'E';
+    }
+    else if ('E' == old_char)
+    {
+        new_char = 'S';
+    }
+    else if ('S' == old_char)
+    {
+        new_char = 'W';
+    }
+    uint8_t len = strlen(path);
+    uint8_t i;
+    for (; i < len; i++)
+    {
+        uint8_t next_i = i + 1;
+        if (   next_i == len
+            || old_char != path[next_i])
+        {
+            break;
+        }
+    }
+    path[i] = new_char;
+}
+
+
+
+static char nearest_enemy_dir(struct yx_uint16 origin)
+{
+    char * f_name = "nearest_enemy_dir()";
+    struct MapObj * mo;
+    char sel = 0;
+    uint16_t dist_max = world.map->size.y;
+    if (world.map->size.x > world.map->size.y)
+    {
+        dist_max = world.map->size.x;
+    }
+    uint8_t escape = 0;
+    uint8_t dist, i, j;
+    for (dist = 1; !escape && dist <= dist_max; dist++)
+    {
+        char * path = try_malloc(dist + 1, f_name);
+        memset(path, 'N', dist);
+        path[dist] = '\0';
+        for (i = 0; !escape && i < (dist * 4); i++)
+        {
+            clockwise_path(&path);
+            struct yx_uint16 testpos = origin;
+            for (j = 0; j < dist; j++)
+            {
+                testpos = mv_yx_in_dir(path[j], testpos);
+            }
+            if (yx_uint16_cmp(&testpos, &origin) ||
+                testpos.y > world.map->size.y || testpos.x > world.map->size.x)
+            {
+                continue;
+            }
+            for (mo = world.map_objs; mo != 0; mo = mo->next)
+            {
+                if (mo->lifepoints && 1 == yx_uint16_cmp(&testpos, &mo->pos))
+                {
+                    sel = path[0];
+                    escape = 1;
+                    break;
+                }
+            }
+        }
+        free(path);
+    }
+    return sel;
+}
+
+
+
+extern void pretty_dumb_ai(struct MapObj * mo)
+{
+    mo->command = get_moa_id_by_name("wait");
+    char sel = nearest_enemy_dir(mo->pos);
+    if (0 != sel)
+    {
+        mo->command = get_moa_id_by_name("move");
+        mo->arg = sel;
+    }
+}
diff --git a/src/ai.h b/src/ai.h
new file mode 100644 (file)
index 0000000..3799f96
--- /dev/null
+++ b/src/ai.h
@@ -0,0 +1,18 @@
+/* ai.h
+ *
+ * Pseudo AI for actor movement.
+ */
+
+#ifndef AI_H
+#define AI_H
+
+struct MapObj;
+
+
+
+/* Determine next non-player actor command / arguments. Pretty dumb so far. */
+extern void pretty_dumb_ai(struct MapObj * mo);
+
+
+
+#endif
index 2cf9e62f936671b84faeca3eaecb4df8cb5fd267..c637a5d8ea478bdc17d2135e721036bd9537a8a0 100644 (file)
@@ -13,6 +13,7 @@
                           * write_map_objects()
                           */
 #include "map_object_actions.h" /* for struct MapObjAct */
+#include "ai.h" /* for pretty_dumb_ai() */
 #include "map.h" /* for Map struct, is_passable() */
 #include "main.h" /* for world global */
 #include "yx_uint16.h" /* for yx_uint16 struct */
@@ -237,9 +238,7 @@ extern void turn_over(char action)
                 {
                     break;
                 }
-                char * sel = "NSEW";
-                map_object->command = get_moa_id_by_name("move");
-                map_object->arg = sel[rrand() % 4];
+                pretty_dumb_ai(map_object);
             }
             first_round = 0;
             map_object->progress++;
index e14d16de8b51fd5d57c8cfe1ec52a4f72f7bf173..c980693b998bf3156ea70e1f3f5a8df8fc36402b 100644 (file)
@@ -18,19 +18,19 @@ extern uint8_t yx_uint16_cmp(struct yx_uint16 * a, struct yx_uint16 * b)
 
 extern struct yx_uint16 mv_yx_in_dir(char d, struct yx_uint16 yx)
 {
-    if      (d == 'N')
+    if      (d == 'N' && yx.y > 0)
     {
         yx.y--;
     }
-    else if (d == 'E')
+    else if (d == 'E' && yx.x < UINT16_MAX)
     {
         yx.x++;
     }
-    else if (d == 'S')
+    else if (d == 'S' && yx.y < UINT16_MAX)
     {
         yx.y++;
     }
-    else if (d == 'W')
+    else if (d == 'W' && yx.x > 0)
     {
         yx.x--;
     }
index d055a6d4c7a3df45ba1b4de482532bb42156f633..f6f90a372dca46c8af4b63a17dcd1e4e3f37bcb6 100644 (file)
@@ -24,7 +24,8 @@ struct yx_uint16
 extern uint8_t yx_uint16_cmp(struct yx_uint16 * a, struct yx_uint16 * b);
 
 /* Return yx_uint16 coordinate one step from "yx" in direction "dir" (east: 'E',
- * west: 'W', north: 'N', south: 'S'). An invalid dir leaves "yx" unchanged.
+ * west: 'W', north: 'N', south: 'S'). If "dir" is invalid or would wrap the
+ * move around the edge of a 2^16x2^16 cells field, "yx" remains unchanged.
  */
 extern struct yx_uint16 mv_yx_in_dir(char dir, struct yx_uint16 yx);