From: Christian Heller Date: Tue, 26 Nov 2013 01:57:10 +0000 (+0100) Subject: Replaced random movement by enemies with a pretty dumb AI of "move in direction of... X-Git-Tag: tce~909 X-Git-Url: https://plomlompom.com/repos/%7B%7Bprefix%7D%7D/static/%7B%7Byoutube_prefix%7D%7D%7B%7Bvideo_data.id_%7D%7D?a=commitdiff_plain;h=75b0ee910d9a50de67e77ba40e877f9c8dabdd40;p=plomrogue Replaced random movement by enemies with a pretty dumb AI of "move in direction of nearest enemy". --- diff --git a/src/ai.c b/src/ai.c new file mode 100644 index 0000000..aee8e73 --- /dev/null +++ b/src/ai.c @@ -0,0 +1,115 @@ +/* ai.c */ + +#include "ai.h" +#include /* for free() */ +#include /* for strlen(), memset() */ +#include /* 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 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 diff --git a/src/misc.c b/src/misc.c index 2cf9e62..c637a5d 100644 --- a/src/misc.c +++ b/src/misc.c @@ -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++; diff --git a/src/yx_uint16.c b/src/yx_uint16.c index e14d16d..c980693 100644 --- a/src/yx_uint16.c +++ b/src/yx_uint16.c @@ -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--; } diff --git a/src/yx_uint16.h b/src/yx_uint16.h index d055a6d..f6f90a3 100644 --- a/src/yx_uint16.h +++ b/src/yx_uint16.h @@ -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);