Set part of selected thing's memory of the game map to string argument: the line
of the argument's number.
+T_MEMDEPTHMAP [0 to 255] [string]
+Set part of selected thing's game map memory depth map to string argument: the
+line of the argument's number.
+
T_MEMTHING [0 to 255] [0 to 255] [0 to 255]
Add to selected thing's memory of things on map thing of ID of first argument,
y position of second argument and x position of third argument.
redo-ifchange build/build_template
TARGET=server
+LIBRARY_LINKS=-lm
. ./build/build_template
*/
static void dijkstra_map(uint16_t * score_map, uint16_t max_score);
-/* get_dir_to_nearest_thing() helper: Prepare "score_map" for dijkstra_map(). */
+/* get_dir_to_nearest_target() helper: Prepare "score_map" for dijkstra_map(). */
static void init_score_map(char filter, uint16_t * score_map, uint32_t map_size,
struct Thing * t_eye);
/* Set (if possible) as "t_eye"'s command a move to the path to the path-wise
- * nearest thing that is not "t_eye" and fits criteria set by "filter". On
- * success, return 1, else 0. Values for "filter":
+ * nearest target that is not "t_eye" and fits criteria set by "filter". On
+ * success, return !0, else 0. Values for "filter":
* "e": thing in FOV is animate, but not of "t_eye"'s thing type; build path as
* avoiding things of "t_eye"'s type
- * "c": thing in memorized map is consumable.
+ * "c": thing in memorized map is consumable
+ * "s": memory map cell with greatest-reachable degree of unexploredness
*/
-static uint8_t get_dir_to_nearest_thing(struct Thing * t_eye, char filter);
+static uint8_t get_dir_to_nearest_target(struct Thing * t_eye, char filter);
/* Return 1 if any thing not "t_eye" is known and fulfills some criteria defined
* by "filter", else 0. Values for "filter":
score_map[tm->pos.y * world.map.length + tm->pos.x] = 0;
}
}
+ else if (('0' < filter && '9' >= filter) || ' ' == filter)
+ {
+ uint32_t i;
+ for (i = 0; i < (uint32_t) (world.map.length * world.map.length); i++)
+ {
+ score_map[i] = filter == t_eye->mem_depth_map[i] ? 0 : score_map[i];
+ }
+ }
}
-static uint8_t get_dir_to_nearest_thing(struct Thing * t_eye, char filter)
+static uint8_t get_dir_to_nearest_target(struct Thing * t_eye, char filter)
{
- char dir_to_nearest_thing = 0;
- if (seeing_thing(t_eye, filter))
+ char dir_to_nearest_target = 0;
+ uint8_t run_i = 9 /* maximum mem depth age below never-explored */ + 1;
+ uint8_t mem_depth_char = ' ';
+ while (run_i && ('s' == filter || seeing_thing(t_eye, filter)))
{
+ run_i = 's' != filter ? 0 : run_i - 1;
uint32_t map_size = world.map.length * world.map.length;
uint16_t * score_map = try_malloc(map_size * sizeof(uint16_t),__func__);
- init_score_map(filter, score_map, map_size, t_eye);
+ init_score_map('s' == filter ? mem_depth_char : filter,
+ score_map, map_size, t_eye);
+ mem_depth_char = ' ' == mem_depth_char ? '9' : mem_depth_char - 1;
dijkstra_map(score_map, UINT16_MAX-1);
uint16_t neighbors[N_DIRS];
uint16_t pos_i = (t_eye->pos.y * world.map.length) + t_eye->pos.x;
if (min_neighbor > neighbors[i])
{
min_neighbor = neighbors[i];
- dir_to_nearest_thing = dirs[i];
+ dir_to_nearest_target = dirs[i];
}
}
+ if (dir_to_nearest_target)
+ {
+ t_eye->command = get_thing_action_id_by_name(s[S_CMD_MOVE]);
+ t_eye->arg = dir_to_nearest_target;
+ run_i = 0;
+ }
}
- if (dir_to_nearest_thing)
- {
- t_eye->command = get_thing_action_id_by_name(s[S_CMD_MOVE]);
- t_eye->arg = dir_to_nearest_thing;
- return 1;
- }
- return 0;
+ return dir_to_nearest_target;
}
extern void ai(struct Thing * t)
{
t->command = get_thing_action_id_by_name(s[S_CMD_WAIT]);
- if (!get_dir_to_nearest_thing(t, 'e'))
+ if (!get_dir_to_nearest_target(t, 'e'))
{
int16_t sel = get_inventory_slot_to_consume(t);
if (-1 != sel)
{
t->command = get_thing_action_id_by_name(s[S_CMD_PICKUP]);
}
- else
+ else if (!get_dir_to_nearest_target(t, 'c'))
{
- get_dir_to_nearest_thing(t, 'c');
+ get_dir_to_nearest_target(t, 's');
}
}
}
* type); if they see none, they will consume consumables in their inventory; if
* there are none, they will pick up any consumables they stand on; if they
* stand on none, they will move towards the next consumable they see or
- * remember on the map; if they see or remember none, they'll simply wait.
+ * remember on the map; if they see or remember none, they'll explore parts of
+ * the map unseen since ever or for at least one turn; if there is nothing to
+ * explore, they will simply wait.
*/
extern void ai(struct Thing * t);
*/
#include "field_of_view.h"
+#include <math.h> /* pow() */
#include <stddef.h> /* NULL */
#include <stdint.h> /* uint8_t, uint16_t, uint32_t, int32_t, UINT8_MAX */
#include <stdlib.h> /* free() */
#include "../common/try_malloc.h" /* try_malloc() */
#include "../common/yx_uint8.h" /* yx_uint8 */
#include "map.h" /* mv_yx_in_dir_legal(), init_empty_map() */
+#include "rrand.h" /* rrand() */
#include "things.h" /* Thing, ThingInMemory, add_thing_to_memory_map() */
#include "world.h" /* world */
struct yx_uint8 * test_pos,
struct shadow_angle ** shadows);
+/* Update "t_eye"'s things-on-map memory by removing from its .t_mem all
+ * memorized thing in FOV, and adding inanimate things in FOV to it.
+ */
+static void add_things_to_map_memory(struct Thing * t_eye);
+
static uint32_t correct_angle(int32_t angle)
-extern void update_map_memory(struct Thing * t_eye)
+static void add_things_to_map_memory(struct Thing * t_eye)
{
- if (!t_eye->mem_map)
- {
- init_empty_map(&(t_eye->mem_map));
- }
- uint32_t i;
- for (i = 0; i < (uint32_t) (world.map.length * world.map.length); i++)
- {
- if (' ' == t_eye->mem_map[i] && t_eye->fov_map[i] == 'v')
- {
- t_eye->mem_map[i] = world.map.cells[i];
- }
- }
struct ThingInMemory * tm = t_eye->t_mem;
struct ThingInMemory * tm_prev = NULL;
struct ThingInMemory * tm_next = NULL;
+extern void update_map_memory(struct Thing * t_eye)
+{
+ if (!t_eye->mem_map)
+ {
+ init_empty_map(&(t_eye->mem_map));
+ }
+ if (!t_eye->mem_depth_map)
+ {
+ init_empty_map(&(t_eye->mem_depth_map));
+ }
+ uint32_t i;
+ for (i = 0; i < (uint32_t) (world.map.length * world.map.length); i++)
+ {
+ if ('v' == t_eye->fov_map[i])
+ {
+ t_eye->mem_depth_map[i] = '0';
+ if (' ' == t_eye->mem_map[i])
+ {
+ t_eye->mem_map[i] = world.map.cells[i];
+ }
+ continue;
+ }
+ if ( '0' <= t_eye->mem_depth_map[i] && '9' > t_eye->mem_depth_map[i]
+ && !(rrand() % (uint16_t) pow(2, t_eye->mem_depth_map[i] - 48)))
+ {
+ t_eye->mem_depth_map[i]++;
+ }
+ }
+ add_things_to_map_memory(t_eye);
+}
+
+
+
extern void build_fov_map(struct Thing * t)
{
uint32_t map_size = world.map.length * world.map.length;
-/* Update "t"'s .mem_map memory with what's in its current FOV, remove from its
- * .t_mem all memorized things in FOV and add inanimate things in FOV to it.
+/* Update "t_eye"'s .mem_map memory with what's in its current FOV, and update
+ * and age the .mem_depth_map.
*/
extern void update_map_memory(struct Thing * t_eye);
extern uint8_t parse_god_command_2arg(char * tok0, char * tok1, char * tok2)
{
- if (!t && !strcmp(tok0, s[S_CMD_T_MEMMAP]))
+ if (!t && ( !strcmp(tok0, s[S_CMD_T_MEMMAP])
+ || !strcmp(tok0, s[S_CMD_T_MEMDEPTHMAP])))
{
return err_line(1, "No thing defined to manipulate yet.");
}
- if (!strcmp(tok0, s[S_CMD_T_MEMMAP]))
+ if (!strcmp(tok0,s[S_CMD_T_MEMMAP]) || !strcmp(tok0,s[S_CMD_T_MEMDEPTHMAP]))
{
uint8_t y = atoi(tok1);
if (parsetest_int(tok1, '8') || y >= world.map.length)
{
return err_line(1, "Map line length is unequal map width.");
}
- if (!t->mem_map)
+ if (!strcmp(tok0,s[S_CMD_T_MEMMAP]))
{
- init_empty_map(&(t->mem_map));
+ if (!t->mem_map)
+ {
+ init_empty_map(&(t->mem_map));
+ }
+ memcpy(t->mem_map + y * world.map.length, tok2, world.map.length);
+ }
+ else
+ {
+ if (!t->mem_depth_map)
+ {
+ init_empty_map(&(t->mem_depth_map));
+ }
+ memcpy(t->mem_depth_map+y*world.map.length, tok2, world.map.length);
}
- memcpy(t->mem_map + y * world.map.length, tok2, world.map.length);
}
else
{
-char * s[42];
+char * s[43];
s[S_CMD_T_HP] = "T_LIFEPOINTS";
s[S_CMD_T_CARRIES] = "T_CARRIES";
s[S_CMD_T_MEMMAP] = "T_MEMMAP";
+ s[S_CMD_T_MEMDEPTHMAP] = "T_MEMDEPTHMAP";
s[S_CMD_T_MEMTHING] = "T_MEMTHING";
s[S_CMD_AI] = "ai";
s[S_CMD_WAIT] = "wait";
S_CMD_T_HP,
S_CMD_T_CARRIES,
S_CMD_T_MEMMAP,
+ S_CMD_T_MEMDEPTHMAP,
S_CMD_T_MEMTHING,
S_CMD_AI,
S_CMD_WAIT,
extern void init_strings();
-extern char * s[42];
+extern char * s[43];
static void write_key_space_value(FILE * file, char * key, uint32_t value);
static void write_key_space_string(FILE * file, char * key, char * string);
+/* Write to "file" game-map-sized "map" in "command"-prefixed numbered lines. */
+static void write_mem_map(FILE * file, char * map, char * command);
+
/* Write to "file" \n-delimited line of "key" + space + "value" as string. */
static void write_thing(FILE * file, struct Thing * t);
+static void write_mem_map(FILE * file, char * map, char * command)
+{
+ if (map)
+ {
+ uint32_t map_size = world.map.length * world.map.length;/* snprintf() */
+ char * map_copy = try_malloc(map_size + 1, __func__); /* reads one */
+ memcpy(map_copy, map, map_size); /* byte beyond map_size */
+ map_copy[map_size] = '\0'; /* if string is not \0-terminated. */
+ uint16_t y;
+ char string[UINT8_MAX + 1 + 1];
+ for (y = 0; y < world.map.length; y++)
+ {
+ int test = snprintf(string, world.map.length + 1, "%s",
+ map_copy + (y * world.map.length));
+ exit_trouble(test < 0, __func__, "snprintf()");
+ write_key_space(file, command);
+ write_value(file, y);
+ try_fputc(' ', file, __func__);
+ write_string(file, string);
+ try_fputc('\n', file, __func__);
+ }
+ free(map_copy);
+ }
+}
+
+
+
static void write_thing(FILE * file, struct Thing * t)
{
struct Thing * o;
{
write_key_space_value(file, s[S_CMD_T_CARRIES], o->id);
}
- if (t->mem_map)
+ write_mem_map(file, t->mem_depth_map, s[S_CMD_T_MEMDEPTHMAP]);
+ write_mem_map(file, t->mem_map, s[S_CMD_T_MEMMAP]);
+ struct ThingInMemory * tm = t->t_mem;
+ for (; tm; tm = tm->next)
{
- uint32_t map_size = world.map.length * world.map.length;/* snprintf() */
- char * mem_map_copy = try_malloc(map_size + 1, __func__);/* reads one */
- memcpy(mem_map_copy, t->mem_map, map_size); /* byte beyond map_size */
- mem_map_copy[map_size] = '\0'; /* if string is not \0-terminated. */
- uint16_t y;
- char string[UINT8_MAX + 1 + 1];
- for (y = 0; y < world.map.length; y++)
- {
-
- int test = snprintf(string, world.map.length + 1, "%s",
- mem_map_copy + (y * world.map.length));
- exit_trouble(test < 0, __func__, "snprintf()");
- write_key_space(file, s[S_CMD_T_MEMMAP]);
- write_value(file, y);
- try_fputc(' ', file, __func__);
- write_string(file, string);
- try_fputc('\n', file, __func__);
- }
- free(mem_map_copy);
- struct ThingInMemory * tm = t->t_mem;
- for (; tm; tm = tm->next)
- {
- write_key_space(file, s[S_CMD_T_MEMTHING]);
- write_value(file, tm->type);
- try_fputc(' ', file, __func__);
- write_value(file, tm->pos.y);
- try_fputc(' ', file, __func__);
- write_value(file, tm->pos.x);
- try_fputc('\n', file, __func__);
- }
+ write_key_space(file, s[S_CMD_T_MEMTHING]);
+ write_value(file, tm->type);
+ try_fputc(' ', file, __func__);
+ write_value(file, tm->pos.y);
+ try_fputc(' ', file, __func__);
+ write_value(file, tm->pos.x);
+ try_fputc('\n', file, __func__);
}
try_fputc('\n', file, __func__);
}
hitted->fov_map = NULL;
free(hitted->mem_map);
hitted->mem_map = NULL;
+ free(hitted->mem_depth_map);
+ hitted->mem_depth_map = NULL;
free_things_in_memory(hitted->t_mem);
hitted->t_mem = NULL;
}
free_things(t->next);
free(t->fov_map);
free(t->mem_map);
+ free(t->mem_depth_map);
free_things_in_memory(t->t_mem);
free(t);
if (t == world.things) /* So add_things()' NULL-delimited thing */
struct yx_uint8 pos; /* coordinate on map */
char * fov_map; /* thing's FOV map; 'v':visible, 'H':hidden */
char * mem_map; /* map knowledge of thing by FOV and memory */
+ char * mem_depth_map; /* map of map memory up-to-dateness */
uint8_t type; /* ID of appropriate thing definition */
uint8_t lifepoints; /* 0: thing is inanimate; >0: hitpoints */
uint8_t command; /* thing's current action; 0 if none */