Add thing of ID in argument to inventory of selected thing, if said thing is
available for carrying and not the selected thing.
+T_MEMMAP [0 to 255] [string]
+Set part of selected thing's memory of the game map to string argument: the line
+of the argument's number.
+
TT_ID [-32768 to 32767]
Select thing type to manipulate by argument as ID. If argument is <0 or <255,
change it to the lowest unused thing type ID. If thing type of ID does not exist
- expand use of hardcoded_strings module(s)
+SERVER:
+
+- check whether saving every player turn slows down gameplay
+
BOTH SERVER/CLIENT:
- make server and client communicate by specific world state info requests
CLIENT:
- re-work unnecessary complex command / keybinding / server message mapping
+
+- fix memory leakin draw_wins module
extern void cleanup()
{
free(world.map.cells);
+ free(world.mem_map);
free(world.log);
free(world.player_inventory);
if (cleanup_flags & CLEANUP_INTERFACE)
#define _POSIX_C_SOURCE 200809L /* strdup() */
#include "draw_wins.h"
-#include <ncurses.h> /* typedefs attr_t, chtype, define A_REVERSE */
+#include <ncurses.h> /* attr_t, chtype, init_pair(), A_REVERSE, COLOR_PAIR() */
#include <stddef.h> /* NULL */
#include <stdint.h> /* uint8_t, uint16_t, uint32_t, UINT16_MAX */
#include <stdio.h> /* sprintf() */
extern void draw_win_map(struct Win * win)
{
+ init_pair(1, COLOR_WHITE, COLOR_BLUE);
+ init_pair(2, COLOR_BLUE, COLOR_BLACK);
+ attr_t attr_fov = 0;
+ attr_t attr_mem = COLOR_PAIR(2);
+ attr_t attr_sha = COLOR_PAIR(1);
try_resize_winmap(win, world.map.length, world.map.length * 2);
- uint16_t z = 0;
- uint16_t x, y;
- for (y = 0; y < world.map.length; y++)
+ uint16_t x, y, z;
+ for (y = 0, z = 0; y < world.map.length; y++)
{
for (x = 0; x < world.map.length; x++)
{
- set_ch_on_yx(win, y, x * 2 + (y % 2), world.map.cells[z]);
+ attr_t attr_c = ' ' == world.mem_map[z] ? attr_sha : attr_mem;
+ chtype c = world.mem_map[z] | attr_c;
+ set_ch_on_yx(win, y, x * 2 + (y % 2), c);
+ if (x + (y % 2) < world.map.length)
+ {
+ set_ch_on_yx(win, y, x * 2 + (y % 2) + 1, ' ' | attr_c);
+ }
+ z++;
+ }
+ }
+ for (y = 0, z = 0; y < world.map.length; y++)
+ {
+ for (x = 0; x < world.map.length; x++)
+ {
+ if (' ' != world.map.cells[z])
+ {
+ chtype c = world.map.cells[z] | attr_fov;
+ set_ch_on_yx(win, y, x * 2 + (y % 2), c);
+ if (x + (y % 2) < world.map.length)
+ {
+ set_ch_on_yx(win, y, x * 2 + (y % 2) + 1, ' ' | attr_fov);
+ }
+ }
z++;
}
}
*/
static void read_inventory(char * read_buf, uint32_t linemax, FILE * file);
-/* Read the next characters in "file" into world.map.cells. In detail: Read
+/* Read the next characters in "file" into "map". In detail: Read
* world.map.length times world.map.length characters, followed by one ignored
* character (that we assume is a newline).
*/
-static void read_map_cells(FILE * file);
+static void read_map_cells(FILE * file, char ** map);
/* Repeatedly use try_fgets() with given arguments to read the remaining lines
* of "file" into the world.log string.
-static void read_map_cells(FILE * file)
+static void read_map_cells(FILE * file, char ** map)
{
- free(world.map.cells);
- world.map.cells = try_malloc(world.map.length * world.map.length, __func__);
+ if (*map)
+ {
+ free(*map);
+ *map = NULL;
+ }
+ *map = try_malloc(world.map.length * world.map.length, __func__);
+ char * map_cells = *map;
uint16_t y, x;
for (y = 0; y < world.map.length; y++)
{
for (x = 0; x < world.map.length; x++)
{
char c = try_fgetc(file, __func__);
- world.map.cells[(y * world.map.length) + x] = c;
+ map_cells[y * world.map.length + x] = c;
}
try_fgetc(file, __func__);
}
first_read = 0;
}
world.map.length = read_value_from_line(read_buf, linemax, file);
- read_map_cells(file);
+ read_map_cells(file, &world.map.cells);
+ read_map_cells(file, &world.mem_map);
read_log(read_buf, linemax, file);
free(read_buf);
try_fclose(file, __func__);
#define _POSIX_C_SOURCE 1 /* sigaction, sigaction() */
#define _DARWIN_C_SOURCE 1 /* SIGWINCH on OS X */
-#include <ncurses.h> /* keypad() */
+#include <ncurses.h> /* keypad(), start_color() */
#include <signal.h> /* SIGWINCH, sigaction, sigaction() */
#include <stddef.h> /* NULL */
#include <stdlib.h> /* exit() */
/* Initialize the whole interface. */
world.winDB.t_screen = initscr();
+ start_color();
set_cleanup_flag(CLEANUP_NCURSES);
noecho();
curs_set(0);
struct KeyBindingDB kb_global; /* globally availabe keybindings */
struct KeyBindingDB kb_wingeom; /* Win geometry config view keybindings */
struct KeyBindingDB kb_winkeys; /* Win keybindings config view keybindings*/
- struct Map map; /* game map geometry and content */
+ struct Map map; /* game map geometry and content of player's map view */
time_t last_update; /* used for comparison with worldstate file's mtime */
char * log; /* log of player's activities */
char * path_interface; /* path of interface configuration file */
char * path_commands; /* path of commands config file */
char * player_inventory; /* one-item-per-line string list of owned items */
+ char * mem_map; /* map cells of player's map memory */
struct yx_uint8 player_pos; /* coordinates of player on map */
uint16_t turn; /* world/game turn */
uint8_t halfdelay; /* how long to wait for getch() input in io_loop() */
#include <stdint.h> /* uint8_t, uint16_t, uint32_t, UINT16_MAX */
#include <stdlib.h> /* free() */
#include "../common/try_malloc.h" /* try_malloc() */
-#include "field_of_view.h" /* VISIBLE */
#include "hardcoded_strings.h" /* s */
#include "thing_actions.h" /* get_thing_action_id_by_name() */
#include "things.h" /* struct Thing */
for (i = 0; i < map_size; i++)
{
score_map[i] = UINT16_MAX;
- if (t_origin->fov_map[i] & VISIBLE && world.map.cells[i] == '.')
+ if ('.' == t_origin->mem_map[i])
{
score_map[i] = max_score;
}
struct yx_uint8 * test_pos,
struct shadow_angle ** shadows);
+/* Update "t"'s .mem_map memory with what's in its current field of view. */
+static void update_map_memory(struct Thing * t, uint32_t map_size);
+
static void mv_yx_in_hex_dir(char d, struct yx_uint8 * yx)
+static void update_map_memory(struct Thing * t, uint32_t map_size)
+{
+ if (!t->mem_map)
+ {
+ t->mem_map = try_malloc(map_size, __func__);
+ memset(t->mem_map, ' ', map_size);
+ }
+ uint32_t i;
+ for (i = 0; i < map_size; i++)
+ {
+ if (' ' == t->mem_map[i] && t->fov_map[i] & VISIBLE)
+ {
+ t->mem_map[i] = world.map.cells[i];
+ }
+ }
+}
+
+
+
extern void build_fov_map(struct Thing * t)
{
uint32_t map_size = world.map.length * world.map.length;
}
mv_yx_in_dir_wrap(0, NULL, 1);
free_angles(shadows);
+ update_map_memory(t, map_size);
}
VISIBLE = 0x01
};
-/* Build "t"'s field of view. */
+/* Build "t"'s field of view and update its map memory with the result. */
extern void build_fov_map(struct Thing * t);
#include <stddef.h> /* NULL */
#include <stdint.h> /* uint8_t */
#include <stdlib.h> /* atoi(), free() */
-#include <string.h> /* strcmp() */
+#include <string.h> /* strcmp(), memset(), memcpy() */
#include <unistd.h> /* F_OK, access(), unlink() */
#include "../common/parse_file.h" /* err_line(), parse_val(), parsetest_int() */
#include "../common/rexit.h" /* exit_trouble() */
+#include "../common/try_malloc.h" /* try_malloc() */
#include "cleanup.h" /* unset_cleanup_flag() */
#include "field_of_view.h" /* build_fov_map() */
#include "hardcoded_strings.h" /* s */
static uint8_t parse_carry(char * tok0, char * tok1, struct Thing * t);
/* Parse/apply god command in "tok0"/"tok1" to manipulate a Thing. */
-static uint8_t parse_thing_manipulation(char * tok0, char * tok1);
+static uint8_t parse_thing_manipulation_1arg(char * tok0, char * tok1);
/* Performs parse_world_active()'s world activation legality tests. */
static uint8_t world_may_be_set_active();
+/* Thing, ThingType or ThingAction selected to be manipulated. */
+static struct Thing * t = NULL;
+static struct ThingType * tt = NULL;
+static struct ThingAction * ta = NULL;
+
+
+
static uint8_t parse_thingtype_manipulation(char * tok0, char * tok1)
{
- static struct ThingType * tt = NULL;
if (!tt &&
( !strcmp(tok0, s[S_CMD_TT_CONSUM]) || !strcmp(tok0, s[S_CMD_TT_SYMB])
|| !strcmp(tok0, s[S_CMD_TT_STARTN]) || !strcmp(tok0, s[S_CMD_TT_NAME])
static uint8_t parse_thingaction_manipulation(char * tok0, char * tok1)
{
- static struct ThingAction * ta = NULL;
if (!ta &&
(!strcmp(tok0, s[S_CMD_TA_EFFORT]) || !strcmp(tok0, s[S_CMD_TA_NAME])))
{
-static uint8_t parse_thing_manipulation(char * tok0, char * tok1)
+static uint8_t parse_thing_manipulation_1arg(char * tok0, char * tok1)
{
- static struct Thing * t = NULL;
if (!t &&
( !strcmp(tok0, s[S_CMD_T_PROGRESS]) || !strcmp(tok0, s[S_CMD_T_TYPE])
|| !strcmp(tok0, s[S_CMD_T_CARRIES]) || !strcmp(tok0, s[S_CMD_T_POSY])
{
if ( parse_thingtype_manipulation(tok0, tok1)
|| parse_thingaction_manipulation(tok0, tok1)
- || parse_thing_manipulation(tok0, tok1)
+ || parse_thing_manipulation_1arg(tok0, tok1)
|| set_map_length(tok0,tok1)
|| parse_val(tok0,tok1,s[S_CMD_SEED_RAND],'U', (char *)&world.seed)
|| parse_val(tok0,tok1,s[S_CMD_TURN],'u',(char *)&world.turn)
}
return 1;
}
+
+
+
+extern uint8_t parse_god_command_2arg(char * tok0, char * tok1, char * tok2)
+{
+ if (!t && !strcmp(tok0, s[S_CMD_T_MEMMAP]))
+ {
+ err_line(1, "No thing defined to manipulate yet.");
+ return 1;
+ }
+ if (!strcmp(tok0, s[S_CMD_T_MEMMAP]))
+ {
+ uint8_t y = atoi(tok1);
+ if (parsetest_int(tok1, '8') || y >= world.map.length)
+ {
+ err_line(1, "Illegal value for map line number.");
+ return 1;
+ }
+ if (strlen(tok2) != world.map.length)
+ {
+ err_line(1, "Map line length is unequal map width.");
+ return 1;
+ }
+ if (!t->mem_map)
+ {
+ uint32_t map_size = world.map.length * world.map.length;
+ t->mem_map = try_malloc(map_size, __func__);
+ memset(t->mem_map, ' ', map_size);
+ }
+ memcpy(t->mem_map + y * world.map.length, tok2, world.map.length);
+ }
+ else
+ {
+ return 0;
+ }
+ return 1;
+}
#include <stdint.h> /* uint8_t */
-/* Parse/apply god command "tok0" with argument "tok1". */
-extern uint8_t parse_god_command_1arg(char * tok1, char * tok2);
+/* Parse/apply god command "tok0" with argument "tok1", "tok2" etc. . */
+extern uint8_t parse_god_command_1arg(char * tok0, char * tok1);
+extern uint8_t parse_god_command_2arg(char * tok0, char * tok1, char * tok2);
-char * s[38];
+char * s[39];
s[S_CMD_T_PROGRESS] = "T_PROGRESS";
s[S_CMD_T_HP] = "T_LIFEPOINTS";
s[S_CMD_T_CARRIES] = "T_CARRIES";
+ s[S_CMD_T_MEMMAP] = "T_MEMMAP";
s[S_CMD_WAIT] = "wait";
s[S_CMD_MOVE] = "move";
s[S_CMD_PICKUP] = "pick_up";
S_CMD_T_PROGRESS,
S_CMD_T_HP,
S_CMD_T_CARRIES,
+ S_CMD_T_MEMMAP,
S_CMD_WAIT,
S_CMD_MOVE,
S_CMD_PICKUP,
extern void init_strings();
-extern char * s[38];
+extern char * s[39];
#include <errno.h> /* global errno */
#include <limits.h> /* PIPE_BUF */
#include <stddef.h> /* size_t, NULL */
-#include <stdint.h> /* uint8_t, uint16_t, uint32_t */
+#include <stdint.h> /* uint8_t, uint16_t, uint32_t, UINT8_MAX */
#include <stdio.h> /* defines EOF, FILE, sprintf(), fprintf() */
#include <stdlib.h> /* free() */
-#include <string.h> /* strlen(), memcpy(), memset(), strchr() */
+#include <string.h> /* strlen(), snprintf(), memcpy(), memset(), strchr() */
#include <sys/types.h> /* time_t */
#include <time.h> /* time(), nanosleep() */
#include "../common/readwrite.h" /* atomic_write_start(), atomic_write_finish(),
-/* Write to "file" god commands (one per line) to recreate thing "t". */
-static void write_key_value(FILE * file, char * key, uint32_t value);
-static void write_key_string(FILE * file, char * key, char * string);
+/* Helpers to write lines of god commands to recreate thing "t". */
+static void write_key_space(FILE * file, char * key);
+static void write_value(FILE * file, uint32_t value);
+static void write_string(FILE * file, char * string);
+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" \n-delimited line of "key" + space + "value" as string. */
static void write_thing(FILE * file, struct Thing * t);
*/
static char * build_visible_map(struct Thing * player);
-/* Write to "file" game map as visible to "player", build_visible_map()-drawn.
- * Write one row per \n-delimited line.
+/* Write to "file" game map as visible to "player" right now, as drawn by
+ * build_visible_map(), and thereafter game map as memorized by player in its
+ * .mem_map. Write one row per \n-delimited line.
*/
static void write_map(struct Thing * player, FILE * file);
-static void write_key_value(FILE * file, char * key, uint32_t value)
+static void write_key_space(FILE * file, char * key)
{
try_fwrite(key, strlen(key), 1, file, __func__);
try_fputc(' ', file, __func__);
+}
+
+
+
+static void write_value(FILE * file, uint32_t value)
+{
char * line = try_malloc(11, __func__);
exit_trouble(-1 == sprintf(line, "%u", value), __func__, s[S_FCN_SPRINTF]);
try_fwrite(line, strlen(line), 1, file, __func__);
free(line);
- try_fputc('\n', file, __func__);
}
-static void write_key_string(FILE * file, char * key, char * string)
+static void write_string(FILE * file, char * string)
{
- try_fwrite(key, strlen(key), 1, file, __func__);
- try_fputc(' ', file, __func__);
uint8_t contains_space = NULL != strchr(string, ' ');
if (contains_space)
{
{
try_fputc('\'', file, __func__);
}
+}
+
+
+
+static void write_key_space_value(FILE * file, char * key, uint32_t value)
+{
+ write_key_space(file, key);
+ write_value(file, value);
+ try_fputc('\n', file, __func__);
+}
+
+
+
+static void write_key_space_string(FILE * file, char * key, char * string)
+{
+ write_key_space(file, key);
+ write_string(file, string);
try_fputc('\n', file, __func__);
}
{
write_thing(file, o);
}
- write_key_value(file, s[S_CMD_T_ID], t->id);
- write_key_value(file, s[S_CMD_T_TYPE], t->type);
- write_key_value(file, s[S_CMD_T_POSY], t->pos.y);
- write_key_value(file, s[S_CMD_T_POSX], t->pos.x);
- write_key_value(file, s[S_CMD_T_COMMAND], t->command);
- write_key_value(file, s[S_CMD_T_ARGUMENT], t->arg);
- write_key_value(file, s[S_CMD_T_PROGRESS], t->progress);
- write_key_value(file, s[S_CMD_T_HP], t->lifepoints);
+ write_key_space_value(file, s[S_CMD_T_ID], t->id);
+ write_key_space_value(file, s[S_CMD_T_TYPE], t->type);
+ write_key_space_value(file, s[S_CMD_T_POSY], t->pos.y);
+ write_key_space_value(file, s[S_CMD_T_POSX], t->pos.x);
+ write_key_space_value(file, s[S_CMD_T_COMMAND], t->command);
+ write_key_space_value(file, s[S_CMD_T_ARGUMENT], t->arg);
+ write_key_space_value(file, s[S_CMD_T_PROGRESS], t->progress);
+ write_key_space_value(file, s[S_CMD_T_HP], t->lifepoints);
for (o = t->owns; o; o = o->next)
{
- write_key_value(file, s[S_CMD_T_CARRIES], o->id);
+ write_key_space_value(file, s[S_CMD_T_CARRIES], o->id);
+ }
+ if (t->mem_map)
+ {
+ 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);
}
try_fputc('\n', file, __func__);
}
{
for (x = 0; x < world.map.length; x++)
{
- try_fputc(visible_map[(y * world.map.length) + x], file, __func__);
+ try_fputc(visible_map[y * world.map.length + x], file, __func__);
}
try_fputc('\n', file, __func__);
}
free(visible_map);
+ for (y = 0; y < world.map.length; y++)
+ {
+ for (x = 0; x < world.map.length; x++)
+ {
+ try_fputc(player->mem_map[y * world.map.length + x], file, __func__);
+ }
+ try_fputc('\n', file, __func__);
+ }
}
{
char * path_tmp;
FILE * file = atomic_write_start(s[S_PATH_SAVE], &path_tmp);
- write_key_value(file, s[S_CMD_MAPLENGTH], world.map.length);
- write_key_value(file, s[S_CMD_PLAYTYPE], world.player_type);
+ write_key_space_value(file, s[S_CMD_MAPLENGTH], world.map.length);
+ write_key_space_value(file, s[S_CMD_PLAYTYPE], world.player_type);
try_fputc('\n', file, __func__);
struct ThingAction * ta;
for (ta = world.thing_actions; ta; ta = ta->next)
{
- write_key_value(file, s[S_CMD_TA_ID], ta->id);
- write_key_value(file, s[S_CMD_TA_EFFORT], ta->effort);
- write_key_string(file, s[S_CMD_TA_NAME], ta->name);
+ write_key_space_value(file, s[S_CMD_TA_ID], ta->id);
+ write_key_space_value(file, s[S_CMD_TA_EFFORT], ta->effort);
+ write_key_space_string(file, s[S_CMD_TA_NAME], ta->name);
try_fputc('\n', file, __func__);
}
struct ThingType * tt;
for (tt = world.thing_types; tt; tt = tt->next)
{
- write_key_value(file, s[S_CMD_TT_ID], tt->id);
- write_key_value(file, s[S_CMD_TT_STARTN], tt->start_n);
- write_key_value(file, s[S_CMD_TT_HP], tt->lifepoints);
+ write_key_space_value(file, s[S_CMD_TT_ID], tt->id);
+ write_key_space_value(file, s[S_CMD_TT_STARTN], tt->start_n);
+ write_key_space_value(file, s[S_CMD_TT_HP], tt->lifepoints);
int test = fprintf(file, "%s %c\n", s[S_CMD_TT_SYMB], tt->char_on_map);
exit_trouble(test < 0, __func__, "fprintf");
- write_key_string(file, s[S_CMD_TT_NAME], tt->name);
- write_key_value(file, s[S_CMD_TT_CONSUM], tt->consumable);
+ write_key_space_string(file, s[S_CMD_TT_NAME], tt->name);
+ write_key_space_value(file, s[S_CMD_TT_CONSUM], tt->consumable);
try_fputc('\n', file, __func__);
}
for (tt = world.thing_types; tt; tt = tt->next)
{
- write_key_value(file, s[S_CMD_TT_ID], tt->id);
- write_key_value(file, s[S_CMD_TT_CORPS], tt->corpse_id);
+ write_key_space_value(file, s[S_CMD_TT_ID], tt->id);
+ write_key_space_value(file, s[S_CMD_TT_CORPS], tt->corpse_id);
}
try_fputc('\n', file, __func__);
- write_key_value(file, s[S_CMD_SEED_MAP], world.seed_map);
- write_key_value(file, s[S_CMD_SEED_RAND], world.seed);
- write_key_value(file, s[S_CMD_TURN], world.turn);
+ write_key_space_value(file, s[S_CMD_SEED_MAP], world.seed_map);
+ write_key_space_value(file, s[S_CMD_SEED_RAND], world.seed);
+ write_key_space_value(file, s[S_CMD_TURN], world.turn);
try_fputc('\n', file, __func__);
struct Thing * t;
for (t = world.things; t; t = t->next)
{
write_thing(file, t);
}
- write_key_value(file, s[S_CMD_WORLD_ACTIVE], 1);
+ write_key_space_value(file, s[S_CMD_WORLD_ACTIVE], 1);
atomic_write_finish(file, s[S_PATH_SAVE], path_tmp);
}
#include "../common/try_malloc.h" /* try_malloc() */
#include "ai.h" /* ai() */
#include "cleanup.h" /* unset_cleanup_flag() */
-#include "god_commands.h" /* parse_god_command_1arg() */
+#include "god_commands.h" /* parse_god_command_1arg(),parse_god_command_2arg()*/
#include "hardcoded_strings.h" /* s */
#include "io.h" /* io_round(), save_world() */
#include "things.h" /* Thing, get_thing_action_id_by_name(), get_player() */
/* Parse player command "tok0" with one argument "tok1" to player action. */
static uint8_t parse_player_command_1arg(char * tok0, char * tok1);
-/* Parse/apply command "tok0". */
+/* Parse/apply command "tok0" (read further tokens as necessary). */
static uint8_t parse_command(char * tok0);
/* Compares first line of server out file to world.server_test, aborts if they
{
return 1;
}
+ else
+ {
+ char * tok2 = token_from_line(NULL);
+ if (tok2 && parse_god_command_2arg(tok0, tok1, tok2))
+ {
+ return 1;
+ }
+ }
}
return 0;
}
ai(thing);
}
thing->progress++;
-
struct ThingAction * ta = get_thing_action(thing->command);
if (thing->progress == ta->effort)
{
if (player == hitted)
{
update_log(" You die.");
+ memset(hitted->fov_map, ' ', world.map.length * world.map.length);
return;
}
+ else
+ {
+ free(hitted->fov_map);
+ hitted->fov_map = NULL;
+ free(hitted->mem_map);
+ hitted->mem_map = NULL;
+ }
update_log(" It dies.");
}
}
free_things(t->owns);
free_things(t->next);
free(t->fov_map);
+ free(t->mem_map);
free(t);
if (t == world.things) /* So add_things()' NULL-delimited thing */
{ /* iteration loop does not iterate over */
struct Thing * owns; /* chain of things owned / in inventory */
struct yx_uint8 pos; /* coordinate on map */
uint8_t * fov_map; /* map of the thing's field of view */
+ uint8_t * mem_map; /* map knowledge of thing by FOV and memory */
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 */