Hacking / server internals and configuration
--------------------------------------------
-The ./confserver/world file defines the map object types, actions available to
-them, the map geometry and the map object type (species) of the player. Each
-definition consists of a single- or multi-line block wherein each line sets one
-attribute.
+The ./confserver/world file defines the thing types, actions available to them,
+the map geometry and the thing type (species) of the player. Each definition
+consists of a single- or multi-line block wherein each line sets one attribute.
Here's a typical action definition block:
these strings to this action. All other names (including "wait") currently are
matched to a do-nothing wait function.
-Here's a typical map object type definition block:
+Here's a typical thing type definition block:
-OBJECT 2
+THINGTYPE 2
NAME ZOMBIE
SYMBOL z
LIFEPOINTS 3
CONSUMABLE 0
START_NUMBER 9
-A line of "OBJECT" followed by a number starts it, and the number sets the
-object type's internal id. The number after "CONSUMABLE" defines the object
-as consumable (and to so many hitpoints gain). The character after "SYMBOL" is
-the one shown on the map to represent to object type. "LIFEPOINTS" is the start
-hitpoints value for this object type and defines it as animate if it is
-non-zero. The string after "NAME" sets the object type's name. "CORPSE_ID" sets
-the id of the object type that objects of this type degrade to if their
-hitpoints drop to zero if they start out as inanimate (what is not implemented
-yet: or if they are inanimate, but are otherwise crushed). Note that the
-"CORPSE_ID" must match the id of an object type defined in the file (before or
-after, it may even be the same). "START_NUMBER" sets the number of objects that
-are to appear of the given type on the map on game start.
+A line of "THINGTYPE" followed by a number starts it, and the number sets the
+thing type's internal id. The number after "CONSUMABLE" defines the thing as
+consumable (and to so many hitpoints gain). The character after "SYMBOL" is the
+one shown on the map to represent to thing type. "LIFEPOINTS" is the start
+hitpoints value for this thing type and defines it as animate if it is non-zero.
+The string after "NAME" sets the thing type's name. "CORPSE_ID" sets the id of
+the thing type that things of this type degrade to if their hitpoints drop to
+zero if they start out as inanimate (what is not implemented yet: or if they are
+inanimate, but are otherwise crushed). Note that the "CORPSE_ID" must match the
+id of a thing type defined in the file (before or after, it may even be the
+same). "START_NUMBER" sets the number of things that are to appear of the
+given type on the map on game start.
The map is defined by a single-line block. Its number value sets the map
square's edge length. It must be >= 1 and <= 256:
MAP_LENGTH 64
The player type / species is also defined by a single line block. Its number
-value sets the player's creature's map object type by its id:
+value sets the player's creature's thing type by its id:
PLAYER_TYPE 0
All these definition block members must be present within their respective
-blocks, but only "ACTION" and "OBJECT" must be positioned at their respective
+blocks, but only "ACTION" and "THINGTYPE" must be positioned at their respective
blocks' first line; the others may appear in whatever order and even multiple
-times. If an object or action definition block is finished, however, it cannot
-be re-defined by starting a new block with the same object type or action id.
+times. If a thing or action definition block is finished, however, it cannot
+be re-defined by starting a new block with the same thing type or action id.
Tokens in this config file are separated by whitespace. Single quotes can be
put around string values that are to include whitespace by themslves. Note that
- for game continuation, replace re-playing of whole record files with loading
game state snapshots / save files
-- rename MapObject to Thing, MapObjectDef to ThingType etc.
-
CLIENT:
- enable toggling of window borders
NAME use
EFFORT 45
-OBJECT 0
+THINGTYPE 0
NAME HUMAN
SYMBOL @
LIFEPOINTS 5
CONSUMABLE 0
START_NUMBER 1
-OBJECT 1
+THINGTYPE 1
NAME ANT
SYMBOL a
LIFEPOINTS 1
CONSUMABLE 0
START_NUMBER 27
-OBJECT 2
+THINGTYPE 2
NAME ZOMBIE
SYMBOL z
LIFEPOINTS 3
CONSUMABLE 0
START_NUMBER 9
-OBJECT 3
+THINGTYPE 3
NAME SHOGGOTH
SYMBOL S
LIFEPOINTS 9
CONSUMABLE 0
START_NUMBER 3
-OBJECT 4
+THINGTYPE 4
NAME DIRT
SYMBOL #
LIFEPOINTS 0
CONSUMABLE 0
START_NUMBER 9
-OBJECT 5
+THINGTYPE 5
NAME SKELETON
SYMBOL %
LIFEPOINTS 0
CONSUMABLE 0
START_NUMBER 9
-OBJECT 6
+THINGTYPE 6
NAME 'MAGIC MEAT'
SYMBOL m
LIFEPOINTS 0
#include <stdlib.h> /* free() */
#include "../common/try_malloc.h" /* try_malloc() */
#include "field_of_view.h" /* VISIBLE */
-#include "map_object_actions.h" /* get_moa_id_by_name() */
-#include "map_objects.h" /* struct MapObj */
+#include "thing_actions.h" /* get_thing_action_id_by_name() */
+#include "things.h" /* struct Thing */
#include "world.h" /* global world */
static void dijkstra_map(uint16_t * score_map, uint16_t max_score);
/* Return numpad char of direction ("8", "6", "2", "4" etc.) of enemy with the
- * shortest path visible to "mo_origin". If no enemy is around, return 0.
+ * shortest path visible to "t_origin". If no enemy is around, return 0.
*/
-static char get_dir_to_nearest_enemy(struct MapObj * mo_origin);
+static char get_dir_to_nearest_enemy(struct Thing * thing_origin);
-static char get_dir_to_nearest_enemy(struct MapObj * mo_origin)
+static char get_dir_to_nearest_enemy(struct Thing * t_origin)
{
char * f_name = "get_dir_to_nearest_enemy()";
/* Calculate for each cell the distance to the visibly nearest map actor not
- * "mo_origin", with movement only possible in the directions of "dir".
+ * "t_origin", with movement only possible in the directions of "dir".
* (Actors' own cells start with a distance of 0 towards themselves.)
*/
uint32_t map_size = world.map.length * world.map.length;
uint32_t i;
for (i = 0; i < map_size; i++)
{
- score_map[i] = mo_origin->fov_map[i] & VISIBLE ? max_score : UINT16_MAX;
+ score_map[i] = t_origin->fov_map[i] & VISIBLE ? max_score : UINT16_MAX;
}
- struct MapObj * mo = world.map_objs;
- for (; mo != NULL; mo = mo->next)
+ struct Thing * t = world.things;
+ for (; t != NULL; t = t->next)
{
- if (!mo->lifepoints || mo == mo_origin)
+ if (!t->lifepoints || t == t_origin)
{
continue;
}
- score_map[(mo->pos.y * world.map.length) + mo->pos.x] = 0;
+ score_map[(t->pos.y * world.map.length) + t->pos.x] = 0;
}
dijkstra_map(score_map, max_score);
- /* Return direction of "mo_origin"'s lowest-scored neighbor cell. */
+ /* Return direction of "t_origin"'s lowest-scored neighbor cell. */
uint16_t neighbors[N_DIRS];
- uint16_t pos_i = (mo_origin->pos.y * world.map.length) + mo_origin->pos.x;
+ uint16_t pos_i = (t_origin->pos.y * world.map.length) + t_origin->pos.x;
get_neighbor_scores(score_map, pos_i, max_score, neighbors);
free(score_map);
char dir_to_nearest_enemy = 0;
-extern void ai(struct MapObj * mo)
+extern void ai(struct Thing * t)
{
- mo->command = get_moa_id_by_name("wait");
- char sel = get_dir_to_nearest_enemy(mo);
+ t->command = get_thing_action_id_by_name("wait");
+ char sel = get_dir_to_nearest_enemy(t);
if (0 != sel)
{
- mo->command = get_moa_id_by_name("move");
- mo->arg = sel;
+ t->command = get_thing_action_id_by_name("move");
+ t->arg = sel;
}
}
#ifndef AI_H
#define AI_H
-struct MapObj;
+struct Thing;
* pretty dumb so far. Actors will try to move towards their path-wise nearest
* neighbor. If no one else is found in the neighborhood, they will simply wait.
*/
-extern void ai(struct MapObj * mo);
+extern void ai(struct Thing * t);
#include <stdlib.h> /* free() */
#include <unistd.h> /* unlink() */
#include "../common/readwrite.h" /* try_fclose() */
-#include "map_object_actions.h" /* free_map_object_actions() */
-#include "map_objects.h" /* free_map_objects(), free_map_object_defs() */
+#include "thing_actions.h" /* free_thing_actions() */
+#include "things.h" /* free_things(), free_thing_types() */
#include "world.h" /* global world */
{
unlink(world.path_worldstate);
}
- if (cleanup_flags & CLEANUP_MAP_OBJECTS)
+ if (cleanup_flags & CLEANUP_THINGS)
{
- free_map_objects(world.map_objs);
+ free_things(world.things);
}
- if (cleanup_flags & CLEANUP_MAP_OBJECT_DEFS)
+ if (cleanup_flags & CLEANUP_THING_TYPES)
{
- free_map_object_defs(world.map_obj_defs);
+ free_thing_types(world.thing_types);
}
- if (cleanup_flags & CLEANUP_MAP_OBJECT_ACTS)
+ if (cleanup_flags & CLEANUP_THING_ACTIONS)
{
- free_map_object_actions(world.map_obj_acts);
+ free_thing_actions(world.thing_actions);
}
if (cleanup_flags & CLEANUP_IN)
{
*/
enum cleanup_flag
{
- CLEANUP_FIFO = 0x0001,
- CLEANUP_WORLDSTATE = 0x0002,
- CLEANUP_MAP_OBJECT_DEFS = 0x0004,
- CLEANUP_MAP_OBJECTS = 0x0008,
- CLEANUP_MAP_OBJECT_ACTS = 0x0010,
- CLEANUP_IN = 0x0020,
- CLEANUP_OUT = 0x0040
+ CLEANUP_FIFO = 0x0001,
+ CLEANUP_WORLDSTATE = 0x0002,
+ CLEANUP_THING_TYPES = 0x0004,
+ CLEANUP_THINGS = 0x0008,
+ CLEANUP_THING_ACTIONS = 0x0010,
+ CLEANUP_IN = 0x0020,
+ CLEANUP_OUT = 0x0040
};
/* In addition, unset_cleanup_flag() may be used to unset flags. */
*/
#include "../common/rexit.h" /* exit_err(), exit_trouble() */
#include "../common/try_malloc.h" /* try_malloc() */
-#include "cleanup.h" /* set_cleanup_flag(), CLEANUP_MAP_OBJ_DEFS,
- * CLEANUP_MAP_OBJ_ACTS
+#include "cleanup.h" /* set_cleanup_flag(), CLEANUP_THING_TYPES,
+ * CLEANUP_THING_ACTIONS
*/
-#include "map_object_actions.h" /* MapObjAct */
-#include "map_objects.h" /* MapObj, MapObjDef, struct MapObjDef */
+#include "thing_actions.h" /* ThingAction */
+#include "things.h" /* Thing, ThingType */
#include "world.h" /* world global */
-/* Flags defining state of object and action entry reading ((un-)finished /
+/* Flags defining state of thing type and action entry reading ((un-)finished /
* ready for starting the reading of a new definition etc.)
*/
enum flag
LIFEPOINTS_SET = 0x10,
CONSUMABLE_SET = 0x20,
START_N_SET = 0x40,
- READY_ACT = NAME_SET | EFFORT_SET,
- READY_OBJ = NAME_SET | CORPSE_ID_SET | SYMBOL_SET | LIFEPOINTS_SET
- | CONSUMABLE_SET | START_N_SET
+ READY_ACTION = NAME_SET | EFFORT_SET,
+ READY_THING = NAME_SET | CORPSE_ID_SET | SYMBOL_SET | LIFEPOINTS_SET
+ | CONSUMABLE_SET | START_N_SET
};
-/* What MapObjDef and MapObjAct structs have in common at their top. Use this to
- * allow same functions run over structs of both types.
+/* What ThingType and ThingAction structs have in common at their top. Use this
+ * to allow same functions run over structs of both types.
*/
struct EntryHead
{
-/* Interpret "token0" and "token1" as data to write into the MapObjAct /
- * MapObjDef DB.
+/* Interpret "token0" and "token1" as data to write into the ThingAction /
+ * ThingType DB.
*
- * Individual MapObjDef / MapObjAct DB entries are put together line by line
+ * Individual ThingType / ThingAction DB entries are put together line by line
* before being written. Writing only happens after all necessary members of an
* entry have been assembled, and when additionally a) a new entry is started by
- * a "token0" of "ACTION" or "OBJECT"; or b) "token0" is NULL.
+ * a "token0" of "ACTION" or "THINGTYPE"; or b) "token0" is NULL.
*
* Also check against the line parse_file() read tokens from having more tokens.
*/
static void write_if_entry(struct EntryHead ** entry,
struct EntryHead *** entry_p_p_p);
-/* Ensure that all .corpse_id members in the MapObjDef DB fit .id members of
- * MapObjDef DB entries.
+/* Ensure that all .corpse_id members in the ThingType DB fit .id members of
+ * ThingType DB entries.
*/
static void test_corpse_ids();
static uint8_t set_map_length(char * token0, char * comparand, char * token1);
/* Try to read tokens as members for the definition currently edited, which may
- * be "mod" or "moa". What member of which of the two is set depends on which of
+ * be "tt" or "ta". What member of which of the two is set depends on which of
* the flags has EDIT_STARTED set and on the key name in "token0". Return 1 if
* interpretation succeeds, else 0.
*
- * Note that MapObjAct entries' .name also determines their .func.
+ * Note that ThingAction entries' .name also determines their .func.
*/
static uint8_t set_members(char * token0, char * token1,
- uint8_t * object_flags, uint8_t * action_flags,
- struct MapObjDef * mod, struct MapObjAct * moa);
+ uint8_t * thing_flags, uint8_t * action_flags,
+ struct ThingType * tt, struct ThingAction * ta);
-/* If "name" fits "moa"->name, set "moa"->func to "func". (Derives MapObjAct
+/* If "name" fits "ta"->name, set "ta"->func to "func". (Derives ThingAction
* .func from .name for set_members().
*/
-static uint8_t try_func_name(struct MapObjAct * moa,
- char * name, void (* func) (struct MapObj *));
+static uint8_t try_func_name(struct ThingAction * ta,
+ char * name, void (* func) (struct Thing *));
static void tokens_into_entries(char * token0, char * token1)
{
- char * str_act = "ACTION";
- char * str_obj = "OBJECT";
+ char * str_action = "ACTION";
+ char * str_thing = "THINGTYPE";
char * str_player = "PLAYER_TYPE";
char * str_map_length = "MAP_LENGTH";
- static struct MapObjAct ** moa_p_p = &world.map_obj_acts;
- static struct MapObjDef ** mod_p_p = &world.map_obj_defs;
- static uint8_t action_flags = READY_ACT;
- static uint8_t object_flags = READY_OBJ;
- static struct EntryHead * moa = NULL;
- static struct EntryHead * mod = NULL;
- if (!token0 || !strcmp(token0, str_act) || !strcmp(token0, str_obj)
+ static struct ThingAction ** ta_p_p = &world.thing_actions;
+ static struct ThingType ** tt_p_p = &world.thing_types;
+ static uint8_t action_flags = READY_ACTION;
+ static uint8_t thing_flags = READY_THING;
+ static struct EntryHead * ta = NULL;
+ static struct EntryHead * tt = NULL;
+ if (!token0 || !strcmp(token0, str_action) || !strcmp(token0, str_thing)
|| !strcmp(token0, str_player))
{
- parse_and_reduce_to_readyflag(&action_flags, READY_ACT);
- parse_and_reduce_to_readyflag(&object_flags, READY_OBJ);
- write_if_entry(&moa, (struct EntryHead ***) &moa_p_p);
- write_if_entry(&mod, (struct EntryHead ***) &mod_p_p);
+ parse_and_reduce_to_readyflag(&action_flags, READY_ACTION);
+ parse_and_reduce_to_readyflag(&thing_flags, READY_THING);
+ write_if_entry(&ta, (struct EntryHead ***) &ta_p_p);
+ write_if_entry(&tt, (struct EntryHead ***) &tt_p_p);
}
if (token0)
{
parsetest_too_many_values();
- if (start_entry(token0, token1, str_act, &action_flags,
- sizeof(struct MapObjAct), (struct EntryHead**) &moa,
- (struct EntryHead *) world.map_obj_acts))
+ if (start_entry(token0, token1, str_action, &action_flags,
+ sizeof(struct ThingAction), (struct EntryHead**) &ta,
+ (struct EntryHead *) world.thing_actions))
{
err_line(0 == atoi(token1), "Value must not be 0.");
}
- else if (!( start_entry(token0, token1, str_obj, &object_flags,
- sizeof(struct MapObjDef),
- (struct EntryHead**) &mod,
- (struct EntryHead *) world.map_obj_defs)
+ else if (!( start_entry(token0, token1, str_thing, &thing_flags,
+ sizeof(struct ThingType),
+ (struct EntryHead**) &tt,
+ (struct EntryHead *) world.thing_types)
|| set_player_type(token0, str_player, token1)
|| set_map_length(token0, str_map_length, token1)
- || set_members(token0, token1, &object_flags, &action_flags,
- (struct MapObjDef *)mod,
- (struct MapObjAct *) moa)))
+ || set_members(token0, token1, &thing_flags, &action_flags,
+ (struct ThingType *) tt,
+ (struct ThingAction *) ta)))
{
parse_unknown_arg();
}
static void test_corpse_ids()
{
char * f_name = "test_corpse_ids()";
- char * prefix = "In the object definitions DB, one object corpse ID does "
- "not reference any known object in the DB. ID of "
- "responsible object: ";
+ char * prefix = "In the thing types DB, one thing corpse ID does not "
+ "reference any known thing type in the DB. ID of "
+ "responsible thing type: ";
size_t size = strlen(prefix) + 3 + 1; /* 3: uint8_t representation strlen */
char * err_corpse = try_malloc(size, f_name);
- struct MapObjDef * test_entry_0 = world.map_obj_defs;
+ struct ThingType * test_entry_0 = world.thing_types;
for (; test_entry_0; test_entry_0 = test_entry_0->next)
{
uint8_t corpse_id_found = 0;
- struct MapObjDef * test_entry_1 = world.map_obj_defs;
+ struct ThingType * test_entry_1 = world.thing_types;
for (; test_entry_1; test_entry_1 = test_entry_1->next)
{
if (test_entry_0->corpse_id == test_entry_1->id)
-static uint8_t set_members(char * token0, char * token1, uint8_t * object_flags,
+static uint8_t set_members(char * token0, char * token1, uint8_t * thing_flags,
uint8_t * action_flags,
- struct MapObjDef * mod, struct MapObjAct * moa)
+ struct ThingType * tt, struct ThingAction * ta)
{
if ( *action_flags & EDIT_STARTED
&& parse_val(token0, token1, "NAME", action_flags,
- NAME_SET, 's', (char *) &moa->name))
+ NAME_SET, 's', (char *) &ta->name))
{
- if (!( try_func_name(moa, "move", actor_move)
- || try_func_name(moa, "pick_up", actor_pick)
- || try_func_name(moa, "drop", actor_drop)
- || try_func_name(moa, "use", actor_use)))
+ if (!( try_func_name(ta, "move", actor_move)
+ || try_func_name(ta, "pick_up", actor_pick)
+ || try_func_name(ta, "drop", actor_drop)
+ || try_func_name(ta, "use", actor_use)))
{
- moa->func = actor_wait;
+ ta->func = actor_wait;
}
*action_flags = *action_flags | NAME_SET;
return 1;
}
- else if ( parse_val(token0, token1, "NAME", object_flags,
- NAME_SET, 's', (char *) &mod->name)
- || parse_val(token0, token1, "SYMBOL", object_flags,
- SYMBOL_SET, 'c', (char *) &mod->char_on_map)
+ else if ( parse_val(token0, token1, "NAME", thing_flags,
+ NAME_SET, 's', (char *) &tt->name)
+ || parse_val(token0, token1, "SYMBOL", thing_flags,
+ SYMBOL_SET, 'c', (char *) &tt->char_on_map)
|| parse_val(token0, token1, "EFFORT", action_flags,
- EFFORT_SET, '8', (char *) &moa->effort)
- || parse_val(token0, token1, "START_NUMBER", object_flags,
- START_N_SET, '8', (char *) &mod->start_n)
- || parse_val(token0, token1, "LIFEPOINTS", object_flags,
- LIFEPOINTS_SET, '8', (char *) &mod->lifepoints)
- || parse_val(token0, token1, "CONSUMABLE", object_flags,
- CONSUMABLE_SET, '8', (char *) &mod->consumable)
- || parse_val(token0, token1, "CORPSE_ID", object_flags,
- CORPSE_ID_SET, '8', (char *) &mod->corpse_id))
+ EFFORT_SET, '8', (char *) &ta->effort)
+ || parse_val(token0, token1, "START_NUMBER", thing_flags,
+ START_N_SET, '8', (char *) &tt->start_n)
+ || parse_val(token0, token1, "LIFEPOINTS", thing_flags,
+ LIFEPOINTS_SET, '8', (char *) &tt->lifepoints)
+ || parse_val(token0, token1, "CONSUMABLE", thing_flags,
+ CONSUMABLE_SET, '8', (char *) &tt->consumable)
+ || parse_val(token0, token1, "CORPSE_ID", thing_flags,
+ CORPSE_ID_SET, '8', (char *) &tt->corpse_id))
{
return 1;
}
-static uint8_t try_func_name(struct MapObjAct * moa, char * name,
- void (* func) (struct MapObj *))
+static uint8_t try_func_name(struct ThingAction * ta, char * name,
+ void (* func) (struct Thing *))
{
- if (0 == strcmp(moa->name, name))
+ if (0 == strcmp(ta->name, name))
{
- moa->func = func;
+ ta->func = func;
return 1;
}
return 0;
parse_file(world.path_config, tokens_into_entries);
exit_err(!world.map.length, "Map size not defined in config file.");
uint8_t player_type_is_valid = 0;
- struct MapObjDef * mod;
- for (mod = world.map_obj_defs; NULL != mod; mod = mod->next)
+ struct ThingType * tt;
+ for (tt = world.thing_types; NULL != tt; tt = tt->next)
{
- if (world.player_type == mod->id)
+ if (world.player_type == tt->id)
{
player_type_is_valid = 1;
break;
}
}
- exit_err(!player_type_is_valid, "No valid map object type set for player.");
- set_cleanup_flag(CLEANUP_MAP_OBJECT_ACTS | CLEANUP_MAP_OBJECT_DEFS);
+ exit_err(!player_type_is_valid, "No valid thing type set for player.");
+ set_cleanup_flag(CLEANUP_THING_ACTIONS | CLEANUP_THING_TYPES);
test_corpse_ids();
}
/* src/server/configfile.h
*
- * Reading in the config file of map object and map object action definitions.
+ * Reading in the config file of thing types and thing actions.
*/
#ifndef CONFIGFILE_H
-/* Parse file at world.path_config into map object and map object action
- * definitions at world.map_obj_defs and world.map_obj_acts.
+/* Parse file at world.path_config into thing type and thing action definitions
+ * at world.thing_types and world.thing_actions.
*/
extern void read_config_file();
#include "../common/rexit.h" /* exit_trouble() */
#include "../common/try_malloc.h" /* try_malloc() */
#include "map.h" /* yx_to_map_pos() */
-#include "map_objects.h" /* MapObj */
+#include "things.h" /* Thing */
#include "yx_uint8.h" /* yx_uint8 */
#include "world.h" /* global world */
-extern uint8_t * build_fov_map(struct MapObj * eye)
+extern uint8_t * build_fov_map(struct Thing * eye)
{
char * f_name = "build_fov_map()";
uint8_t radius = 2 * world.map.length;
#define FIELD_OF_VIEW_H
#include <stdint.h> /* uint8_t */
-struct MapObj;
+struct Thing;
* shadows, therefore might be ignored if HIDDEN and not cast shadows on their
* own that may slightly extend beyond the pre-established shadows they border.
*/
-extern uint8_t * build_fov_map(struct MapObj * eye);
+extern uint8_t * build_fov_map(struct Thing * eye);
#include "cleanup.h" /* set_cleanup_flag() */
#include "field_of_view.h" /* build_fov_map() */
#include "map.h" /* init_map() */
-#include "map_objects.h" /* MapObj, MapObjDef, free_map_objects(),
- * add_map_objects(), get_player()
- */
+#include "things.h" /* Thing, ThingType, free_things(), add_things(),
+ * get_player()
+ */
#include "run.h" /* obey_msg(), io_loop() */
#include "world.h" /* global world */
{
char * f_name = "remake_world()";
free(world.log);
- world.log = NULL; /* map_object_action.c's update_log() checks for this. */
+ world.log = NULL; /* thing_actions.c's update_log() checks for this. */
world.seed = seed;
- world.map_obj_count = 0;
+ world.thing_count = 0;
free(world.map.cells);
- free_map_objects(world.map_objs);
+ free_things(world.things);
world.last_update_turn = 0;
init_map();
- struct MapObjDef * mod;
- for (mod = world.map_obj_defs; NULL != mod; mod = mod->next)
+ struct ThingType * tt;
+ for (tt = world.thing_types; NULL != tt; tt = tt->next)
{
- if (world.player_type == mod->id)
+ if (world.player_type == tt->id)
{
- add_map_objects(mod->id, mod->start_n);
+ add_things(tt->id, tt->start_n);
break;
}
}
- for (mod = world.map_obj_defs; NULL != mod; mod = mod->next)
+ for (tt = world.thing_types; NULL != tt; tt = tt->next)
{
- if (world.player_type != mod->id)
+ if (world.player_type != tt->id)
{
- add_map_objects(mod->id, mod->start_n);
+ add_things(tt->id, tt->start_n);
}
}
- set_cleanup_flag(CLEANUP_MAP_OBJECTS);
- struct MapObj * mo;
- for (mo = world.map_objs; NULL != mo; mo = mo->next)
+ set_cleanup_flag(CLEANUP_THINGS);
+ struct Thing * t;
+ for (t = world.things; NULL != t; t = t->next)
{
- mo->fov_map = mo->lifepoints ? build_fov_map(mo) : NULL;
+ t->fov_map = t->lifepoints ? build_fov_map(t) : NULL;
}
if (world.turn)
{
* Unlinks a pre-existing file at world.path_record if called on a world.turn>0,
* i.e. if called after iterating through an already established game world.
*
- * Map object (action) definitions read in from server config directory are not
+ * Thing (action) definitions read in from server config directory are not
* affected. The map is populated accordingly. world.last_update_turn is set to
* 0 and world.turn to 1, so that io_round()'s criteria for updating the output
* file are triggered even when this function is called during a round 1.
#include "cleanup.h" /* set_cleanup_flag() */
#include "field_of_view.h" /* VISIBLE */
#include "map.h" /* yx_to_map_pos() */
-#include "map_objects.h" /* structs MapObj, MapObjDef, get_map_obj_def(),
- * get_player()
- */
+#include "things.h" /* Thing, ThingType, get_thing_type(), get_player() */
#include "world.h" /* global world */
static void write_value_as_line(uint32_t value, FILE * file);
/* Write to "file" player's inventory, one item name per line. End in "%\n". */
-static void write_inventory(struct MapObj * player, FILE * file);
+static void write_inventory(struct Thing * player, FILE * file);
/* Return map cells sequence as visible to the "player", with invisible cells as
- * whitespace. Super-impose over visible map cells map objects positioned there.
+ * whitespace. Super-impose over visible map cells things positioned there.
*/
-static char * build_visible_map(struct MapObj * player);
+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.
*/
-static void write_map(struct MapObj * player, FILE * file);
+static void write_map(struct Thing * player, FILE * file);
char path_tmp[strlen(world.path_worldstate) + strlen(world.tmp_suffix) + 1];
sprintf(path_tmp, "%s%s", world.path_worldstate, world.tmp_suffix);
FILE * file = try_fopen(path_tmp, "w", f_name);
- struct MapObj * player = get_player();
+ struct Thing * player = get_player();
write_value_as_line(world.turn, file);
write_value_as_line(player->lifepoints, file);
write_inventory(player, file);
-static void write_inventory(struct MapObj * player, FILE * file)
+static void write_inventory(struct Thing * player, FILE * file)
{
char * f_name = "write_inventory()";
- struct MapObj * owned = player->owns;
+ struct Thing * owned = player->owns;
if (NULL == owned)
{
char * empty = "(none)\n";
uint8_t q;
for (q = 0; NULL != owned; q++)
{
- struct MapObjDef * mod = get_map_object_def(owned->type);
- try_fwrite(mod->name, strlen(mod->name), 1, file, f_name);
+ struct ThingType * tt = get_thing_type(owned->type);
+ try_fwrite(tt->name, strlen(tt->name), 1, file, f_name);
try_fputc('\n', file, f_name);
owned = owned->next;
}
-static char * build_visible_map(struct MapObj * player)
+static char * build_visible_map(struct Thing * player)
{
char * f_name = "build_visible_map()";
uint32_t map_size = world.map.length * world.map.length;
visible_map[pos_i] = world.map.cells[pos_i];
}
}
- struct MapObj * o;
- struct MapObjDef * d;
+ struct Thing * t;
+ struct ThingType * tt;
char c;
uint8_t i;
for (i = 0; i < 2; i++)
{
- for (o = world.map_objs; o != 0; o = o->next)
+ for (t = world.things; t != 0; t = t->next)
{
- if ( player->fov_map[yx_to_map_pos(&o->pos)] & VISIBLE
- && ( (0 == i && 0 == o->lifepoints)
- || (1 == i && 0 < o->lifepoints)))
+ if ( player->fov_map[yx_to_map_pos(&t->pos)] & VISIBLE
+ && ( (0 == i && 0 == t->lifepoints)
+ || (1 == i && 0 < t->lifepoints)))
{
- d = get_map_object_def(o->type);
- c = d->char_on_map;
- visible_map[yx_to_map_pos(&o->pos)] = c;
+ tt = get_thing_type(t->type);
+ c = tt->char_on_map;
+ visible_map[yx_to_map_pos(&t->pos)] = c;
}
}
}
-static void write_map(struct MapObj * player, FILE * file)
+static void write_map(struct Thing * player, FILE * file)
{
char * f_name = "write_map()";
char * visible_map = build_visible_map(player);
*/
extern void init_map();
-/* Check if coordinate "pos" on (or beyond) world.map is accessible to map
- * object movement.
+/* Check if coordinate "pos" on (or beyond) world.map is accessible to thing
+ * movement.
*/
extern uint8_t is_passable(struct yx_uint8 pos);
+++ /dev/null
-/* src/server/map_object_actions.c */
-
-#include "map_object_actions.h"
-#include <stddef.h> /* NULL */
-#include <stdint.h> /* uint8_t, uint16_t */
-#include <stdio.h> /* sprintf() */
-#include <stdlib.h> /* free() */
-#include <string.h> /* strlen(), strcmp(), memcpy(), strncmp() */
-#include "../common/rexit.h" /* exit_err() */
-#include "../common/try_malloc.h" /* try_malloc() */
-#include "../common/yx_uint8.h" /* struct yx_uint8 */
-#include "field_of_view.h" /* build_fov_map() */
-#include "map_objects.h" /* structs MapObj, MapObjDef, get_player(),
- * set_object_position(), own_map_object(),
- * get_map_object_def()
- */
-#include "map.h" /* is_passable() */
-#include "yx_uint8.h" /* mv_yx_in_dir(), yx_uint8_cmp() */
-#include "world.h" /* global world */
-
-
-
-/* Append "text" to game log, or a "." if "text" is the same as the last one. */
-static void update_log(char * text);
-
-/* One actor "wounds" another actor, decrementing his lifepoints and, if they
- * reach zero in the process, killing it. Generates appropriate log message.
- */
-static void actor_hits_actor(struct MapObj * hitter, struct MapObj * hitted);
-
-/* Bonus stuff to actor_*() to happen if actor==player. Mostly writing of log
- * messages; _pick and _drop also decrement world.inventory_sel by 1 if >0.
- * (match_dir() is just a little helper to playerbonus_move().)
- */
-static void playerbonus_wait();
-static uint8_t match_dir(char d, char ** dsc_d, char match, char * dsc_match);
-static void playerbonus_move(char d, uint8_t passable);
-static void playerbonus_drop(uint8_t owns_none);
-static void playerbonus_pick(uint8_t picked);
-static void playerbonus_use(uint8_t no_object, uint8_t wrong_object);
-
-
-
-static void update_log(char * text)
-{
- char * f_name = "update_log()";
- uint16_t len_new = strlen(text);
- uint16_t len_old = 0;
- if (world.log)
- {
- len_old = strlen(world.log);
- uint16_t last_nl = len_old - 1;
- while (last_nl != 0)
- {
- if ('\n' == world.log[last_nl])
- {
- break;
- }
- last_nl--;
- }
- uint16_t last_stop = len_old - 1;
- while (last_stop != 0)
- {
- if ('.' == world.log[last_stop] && '.' != world.log[last_stop - 1])
- {
- break;
- }
- last_stop--;
- }
- if ( (last_stop + 1) - last_nl == (uint16_t) strlen(text)
- && 0 == strncmp(world.log + last_nl, text, strlen(text)))
- {
- text = ".";
- }
- }
- uint16_t len_whole = len_old + len_new + 1;
- char * new_text = try_malloc(len_whole, f_name);
- memcpy(new_text, world.log, len_old);
- sprintf(new_text + len_old, "%s", text);
- free(world.log);
- world.log = new_text;
-}
-
-
-
-static void actor_hits_actor(struct MapObj * hitter, struct MapObj * hitted)
-{
- struct MapObjDef * mod_hitter = get_map_object_def(hitter->type);
- struct MapObjDef * mod_hitted = get_map_object_def(hitted->type);
- struct MapObj * player = get_player();
- char * msg1 = "You";
- char * msg2 = "wound";
- char * msg3 = "you";
- if (player != hitter)
- {
- msg1 = mod_hitter->name;
- msg2 = "wounds";
- }
- if (player != hitted)
- {
- msg3 = mod_hitted->name;
- }
- uint8_t len = 1 + strlen(msg1) + 1 + strlen(msg2) + 1 + strlen(msg3) + 2;
- char msg[len];
- sprintf(msg, "\n%s %s %s.", msg1, msg2, msg3);
- update_log(msg);
- hitted->lifepoints--;
- if (0 == hitted->lifepoints)
- {
- hitted->type = mod_hitted->corpse_id;
- if (player == hitted)
- {
- update_log(" You die.");
- return;
- }
- update_log(" It dies.");
- }
-}
-
-
-
-static void playerbonus_wait()
-{
- update_log("\nYou wait.");
-}
-
-
-
-static uint8_t match_dir(char d, char ** dsc_d, char match, char * dsc_match)
-{
- if (d == match)
- {
- * dsc_d = dsc_match;
- return 1;
- }
- return 0;
-}
-
-
-
-static void playerbonus_move(char d, uint8_t passable)
-{
- char * dsc_dir = "north-east";
- if ( match_dir(d, &dsc_dir, 'd', "east")
- || match_dir(d, &dsc_dir, 'c', "south-east")
- || match_dir(d, &dsc_dir, 'x', "south-west")
- || match_dir(d, &dsc_dir, 's', "west")
- || match_dir(d, &dsc_dir, 'w', "north-west"))
- {
- ;
- }
- char * dsc_move = "You move ";
- if (0 == passable)
- {
- dsc_move = "You fail to move ";
- }
- char msg[strlen(dsc_move) + strlen (dsc_dir) + 3];
- sprintf(msg, "\n%s%s.", dsc_move, dsc_dir);
- update_log(msg);
-}
-
-
-
-static void playerbonus_drop(uint8_t owns_none)
-{
- if (0 != owns_none)
- {
- update_log("\nYou try to drop an object, but you own none.");
- return;
- }
- update_log("\nYou drop an object.");
-}
-
-
-
-static void playerbonus_pick(uint8_t picked)
-{
- if (picked)
- {
- update_log("\nYou pick up an object.");
- return;
- }
- update_log("\nYou try to pick up an object, but there is none.");
-}
-
-
-
-static void playerbonus_use(uint8_t no_object, uint8_t wrong_object)
-{
- if (no_object)
- {
- update_log("\nYou try to use an object, but you own none.");
- return;
- }
- else if (wrong_object)
- {
- update_log("\nYou try to use this object, but fail.");
- return;
- }
- update_log("\nYou consume MAGIC MEAT.");
-}
-
-
-
-extern void free_map_object_actions(struct MapObjAct * moa)
-{
- if (NULL == moa)
- {
- return;
- }
- free(moa->name);
- free_map_object_actions(moa->next);
- free(moa);
-}
-
-
-
-extern uint8_t get_moa_id_by_name(char * name)
-{
- struct MapObjAct * moa = world.map_obj_acts;
- while (NULL != moa)
- {
- if (0 == strcmp(moa->name, name))
- {
- break;
- }
- moa = moa->next;
- }
- exit_err(NULL==moa, "get_moa_id_by_name() did not find map object action.");
- return moa->id;
-}
-
-
-
-extern void actor_wait(struct MapObj * mo)
-{
- if (mo == get_player())
- {
- playerbonus_wait();
- }
-}
-
-
-
-extern void actor_move(struct MapObj * mo)
-{
- char d = mo->arg;
- struct yx_uint8 target = mv_yx_in_dir(d, mo->pos);
- struct MapObj * other_mo;
- for (other_mo = world.map_objs; other_mo != 0; other_mo = other_mo->next)
- {
- if (0 == other_mo->lifepoints || other_mo == mo)
- {
- continue;
- }
- if (yx_uint8_cmp(&target, &other_mo->pos))
- {
- actor_hits_actor(mo, other_mo);
- return;
- }
- }
- uint8_t passable = is_passable(target);
- if (passable)
- {
- set_object_position(mo, target);
- free(mo->fov_map);
- mo->fov_map = build_fov_map(mo);
- }
- if (mo == get_player())
- {
- playerbonus_move(d, passable);
- }
-}
-
-
-
-extern void actor_drop(struct MapObj * mo)
-{
- uint8_t owns_none = (NULL == mo->owns);
- if (!owns_none)
- {
- uint8_t select = mo->arg;
- struct MapObj * owned = mo->owns;
- uint8_t i = 0;
- for (; i != select; i++, owned = owned->next);
- own_map_object(&world.map_objs, &mo->owns, owned->id);
- }
- if (mo == get_player())
- {
- playerbonus_drop(owns_none);
- }
-}
-
-
-
-extern void actor_pick(struct MapObj * mo)
-{
- struct MapObj * picked = NULL;
- struct MapObj * mo_i;
- for (mo_i = world.map_objs; NULL != mo_i; mo_i = mo_i->next)
- {
- if (mo_i != mo && yx_uint8_cmp(&mo_i->pos, &mo->pos))
- {
- picked = mo_i;
- }
- }
- if (NULL != picked)
- {
- own_map_object(&mo->owns, &world.map_objs, picked->id);
- set_object_position(picked, mo->pos);
- }
- if (mo == get_player())
- {
- playerbonus_pick(NULL != picked);
- }
-}
-
-
-
-extern void actor_use(struct MapObj * mo)
-{
- uint8_t wrong_object = 1;
- uint8_t no_object = (NULL == mo->owns);
- if (!no_object)
- {
- uint8_t select = mo->arg;
- uint8_t i = 0;
- struct MapObj * selected = mo->owns;
- for (; i != select; i++, selected = selected->next);
- struct MapObjDef * mod = get_map_object_def(selected->type);
- if (mod->consumable)
- {
- wrong_object = 0;
- struct MapObj * next = selected->next;
- free(selected);
- if (0 < select)
- {
- select--;
- selected = mo->owns;
- for (i = 0; i != select; i++, selected = selected->next);
- selected->next = next;
- }
- else
- {
- mo->owns = next;
- }
- mo->lifepoints = mo->lifepoints + mod->consumable;
- }
- }
- if (mo == get_player())
- {
- playerbonus_use(no_object, wrong_object);
- }
-}
+++ /dev/null
-/* src/server/map_object_actions.h
- *
- * Actions that can be performed my map objects / "actors". Note that apart
- * from the consequences described below, each action may also trigger log
- * messages and other minor stuff if the actor is equal to the player.
- */
-
-#ifndef MAP_OBJECT_ACTIONS_H
-#define MAP_OBJECT_ACTIONS_H
-
-#include <stdint.h> /* uint8_t */
-struct MapObj;
-
-
-
-struct MapObjAct
-{
- uint8_t id; /* identifies action in MapObj.command; therefore must be >0 */
- struct MapObjAct * next;
- void (* func) (struct MapObj *); /* function called after .effort turns */
- char * name; /* human-readable identifier */
- uint8_t effort; /* how many turns the action takes */
-};
-
-
-
-/* Free MapObjAct * chain starting at "moa". */
-extern void free_map_object_actions(struct MapObjAct * moa);
-
-/* Return world.map_obj_acts MapObjAct.id for "name". */
-extern uint8_t get_moa_id_by_name(char * name);
-
-/* Actor "mo" does nothing. */
-extern void actor_wait(struct MapObj * mo);
-
-/* Actor "mo" tries to move one step in direction described by char mo->arg
- * (where noth-east is 'e', east 'd' etc.) Move either succeeds, or another
- * actor is encountered and hit (which leads ot its lifepoint decreasing by one
- * and eventually death), or the move fails due to an impassable target square.
- * On success, update object's field of view map.
- */
-extern void actor_move(struct MapObj * mo);
-
-/* Actor "mo" tries to drop from inventory object indexed by number mo->args. */
-extern void actor_drop(struct MapObj * mo);
-
-/* Actor "mo" tries to pick up topmost object from ground into its inventory. */
-extern void actor_pick(struct MapObj * mo);
-
-/* Actor "mo" tries to use inventory object indexed by number mo->args.
- * (Currently the only valid use is consuming items defined as consumable.)
- */
-extern void actor_use(struct MapObj * mo);
-
-
-
-#endif
+++ /dev/null
-/* src/server/map_objects.c */
-
-#include "map_objects.h"
-#include <stddef.h> /* NULL */
-#include <stdint.h> /* uint8_t, uint16_t, UINT16_MAX */
-#include <stdlib.h> /* free() */
-#include <string.h> /* memset(), strlen() */
-#include "../common/rexit.h" /* exit_err() */
-#include "../common/try_malloc.h" /* try_malloc() */
-#include "../common/yx_uint8.h" /* yx_uint8 struct */
-#include "map.h" /* is_passable() */
-#include "rrand.h" /* rrand() */
-#include "world.h" /* global world */
-#include "yx_uint8.h" /* yx_uint8_cmp() */
-
-
-
-/* Return pointer to map object of "id" in chain starting at "ptr". */
-static struct MapObj * get_map_object(struct MapObj * ptr, uint8_t id);
-
-/* Add object of "type" to map on passable position. Don't put actor on actor.*/
-static void add_map_object(uint8_t type);
-
-
-
-static struct MapObj * get_map_object(struct MapObj * ptr, uint8_t id)
-{
- while (1)
- {
- if (NULL == ptr || id == ptr->id)
- {
- return ptr;
- }
- struct MapObj * owned_object = get_map_object(ptr->owns, id);
- if (NULL != owned_object)
- {
- return ptr;
- }
- ptr = ptr->next;
- }
-}
-
-
-
-static void add_map_object(uint8_t type)
-{
- char * f_name = "add_map_object()";
- struct MapObjDef * mod = get_map_object_def(type);
- struct MapObj * mo = try_malloc(sizeof(struct MapObj), f_name);
- memset(mo, 0, sizeof(struct MapObj));
- mo->id = world.map_obj_count++;
- mo->type = mod->id;
- mo->lifepoints = mod->lifepoints;
- char * err = "Space to put map object on too hard to find. Map too small?";
- uint16_t i = 0;
- while (1)
- {
- struct yx_uint8 pos;
- for (pos.y = pos.x = 0; 0 == is_passable(pos); i++)
- {
- exit_err(UINT16_MAX == i, err);
- pos.y = rrand() % world.map.length;
- pos.x = rrand() % world.map.length;
- }
- struct MapObj * mo_ptr;
- uint8_t clear = 1;
- for (mo_ptr = world.map_objs; mo_ptr != NULL; mo_ptr = mo_ptr->next)
- {
- if (yx_uint8_cmp(&pos, &mo_ptr->pos) && 0 != mo_ptr->lifepoints)
- {
- clear = 0;
- break;
- }
- }
- if (1 == clear)
- {
- mo->pos = pos;
- break;
- }
- }
- struct MapObj ** mo_ptr_ptr = &world.map_objs;
- for (; NULL != * mo_ptr_ptr; mo_ptr_ptr = &(*mo_ptr_ptr)->next);
- * mo_ptr_ptr = mo;
-}
-
-
-
-extern void free_map_object_defs(struct MapObjDef * mod_start)
-{
- if (NULL == mod_start)
- {
- return;
- }
- free_map_object_defs(mod_start->next);
- free(mod_start->name);
- free(mod_start);
-}
-
-
-
-extern void add_map_objects(uint8_t type, uint8_t n)
-{
- uint8_t i;
- for (i = 0; i < n; i++)
- {
- add_map_object(type);
- }
-}
-
-
-
-extern void free_map_objects(struct MapObj * mo_start)
-{
- if (NULL == mo_start)
- {
- return;
- }
- free_map_objects(mo_start->owns);
- free_map_objects(mo_start->next);
- free(mo_start->fov_map);
- free(mo_start);
- if (mo_start == world.map_objs) /* So add_map_objects()' NULL-delimited */
- { /* map object iteration loop does not */
- world.map_objs = NULL; /* iterate over freed memory when called */
- } /* the 1st time after world re-seeding. */
-}
-
-
-
-extern void own_map_object(struct MapObj ** target, struct MapObj ** source,
- uint8_t id)
-{
- struct MapObj * mo;
- if (id == (*source)->id)
- {
- mo = * source;
- * source = mo->next;
- }
- else
- {
- struct MapObj * penult = * source;
- while (1)
- {
- if (id == penult->next->id)
- {
- break;
- }
- penult = penult->next;
- }
- mo = penult->next;
- penult->next = mo->next;
- }
- struct MapObj ** mo_ptr_ptr = target;
- for (; NULL != * mo_ptr_ptr; mo_ptr_ptr = &(*mo_ptr_ptr)->next);
- * mo_ptr_ptr = mo;
- mo->next = NULL;
-}
-
-
-
-extern struct MapObj * get_player()
-{
- return get_map_object(world.map_objs, 0);
-}
-
-
-
-extern struct MapObjDef * get_map_object_def(uint8_t id)
-{
- struct MapObjDef * mod = world.map_obj_defs;
- for (; NULL != mod && id != mod->id; mod = mod->next);
- char * err_intro = "Requested map object definition of unused ID ";
- char err[strlen(err_intro) + 3 + 1 + 1];
- sprintf(err, "%s%d.", err_intro, id);
- exit_err(NULL == mod, err);
- return mod;
-}
-
-
-
-extern void set_object_position(struct MapObj * mo, struct yx_uint8 pos)
-{
- mo->pos = pos;
- struct MapObj * owned = mo->owns;
- for (; owned != NULL; set_object_position(owned, pos), owned = owned->next);
-}
+++ /dev/null
-/* src/server/map_objects.h
- *
- * Structs for objects on the map and their type definitions, and routines to
- * initialize these and load and save them from/to files.
- */
-
-#ifndef MAP_OBJECTS_H
-#define MAP_OBJECTS_H
-
-#include <stdint.h> /* uint8_t */
-#include "../common/yx_uint8.h" /* yx_uint8 structs */
-
-
-
-struct MapObj
-{
- struct MapObj * next; /* pointer to next one in map object chain */
- struct MapObj * owns; /* chain of map objects owned / in inventory */
- struct yx_uint8 pos; /* coordinate on map */
- uint8_t * fov_map; /* map of the object's field of view */
- uint8_t id; /* individual map object's unique identifier */
- uint8_t type; /* ID of appropriate map object definition */
- uint8_t lifepoints; /* 0: object is inanimate; >0: hitpoints */
- uint8_t command; /* map object's current action; 0 if none */
- uint8_t arg; /* optional field for .command argument */
- uint8_t progress; /* turns already passed to realize .command */
-};
-
-struct MapObjDef
-{
- uint8_t id; /* map object definition identifier / sets .type */
- struct MapObjDef * next;
- char char_on_map; /* map object symbol to appear on map */
- char * name; /* string to describe object in game log */
- uint8_t corpse_id; /* type to change map object into upon destruction */
- uint8_t lifepoints; /* default start value for map object's .lifepoints */
- uint8_t consumable; /* can be eaten if !0, for so much hitpoint win */
- uint8_t start_n; /* how many of these does the map start with? */
-};
-
-
-
-/* Free map object definitions chain starting at "mod_start". */
-extern void free_map_object_defs(struct MapObjDef * mod_start);
-
-/* Add object(s) ("n": how many?) of "type" to map on random position(s). New
- * animate objects are never placed in the same square with other animate ones.
- */
-extern void add_map_objects(uint8_t type, uint8_t n);
-
-/* Free map objects in map object chain starting at "mo_start. */
-extern void free_map_objects(struct MapObj * mo_start);
-
-/* Move object of "id" from "source" inventory to "target" inventory. */
-extern void own_map_object(struct MapObj ** target, struct MapObj ** source,
- uint8_t id);
-
-/* Get pointer to the MapObj struct that represents the player. */
-extern struct MapObj * get_player();
-
-/* Get pointer to the map object definition of identifier "def_id". */
-extern struct MapObjDef * get_map_object_def(uint8_t id);
-
-/* Move not only "mo" to "pos", but also all map objects owned by it. */
-extern void set_object_position(struct MapObj * mo, struct yx_uint8 pos);
-
-
-
-#endif
#include "cleanup.h" /* unset_cleanup_flag() */
#include "init.h" /* remake_world() */
#include "io.h" /* io_round() */
-#include "map_object_actions.h" /* get_moa_id_by_name() */
-#include "map_objects.h" /* struct MapObj, get_player() */
+#include "thing_actions.h" /* get_thing_action_id_by_name() */
+#include "things.h" /* Thing, get_player() */
#include "world.h" /* global world */
*/
static void turn_over();
-/* If "msg"'s first part matches "command_name", set player's MapObj's .command
+/* If "msg"'s first part matches "command_name", set player's Thing's .command
* to the command's id and its .arg to a numerical value following in the latter
* part of "msg" (if no digits are found, use 0); then finish player's turn and
* turn game over to the NPCs via turn_over(); then return 1. Else, return 0.
static void turn_over()
{
- struct MapObj * player = get_player();
- struct MapObj * map_object = player;
+ struct Thing * player = get_player();
+ struct Thing * thing = player;
uint16_t start_turn = world.turn;
while ( 0 < player->lifepoints
|| (0 == player->lifepoints && start_turn == world.turn))
{
- if (NULL == map_object)
+ if (NULL == thing)
{
world.turn++;
- map_object = world.map_objs;
+ thing = world.things;
}
- if (0 < map_object->lifepoints)
+ if (0 < thing->lifepoints)
{
- if (0 == map_object->command)
+ if (0 == thing->command)
{
- if (map_object == player)
+ if (thing == player)
{
break;
}
- ai(map_object);
+ ai(thing);
}
- map_object->progress++;
- struct MapObjAct * moa = world.map_obj_acts;
- while (moa->id != map_object->command)
+ thing->progress++;
+ struct ThingAction * ta = world.thing_actions;
+ while (ta->id != thing->command)
{
- moa = moa->next;
+ ta = ta->next;
}
- if (map_object->progress == moa->effort)
+ if (thing->progress == ta->effort)
{
- moa->func(map_object);
- map_object->command = 0;
- map_object->progress = 0;
+ ta->func(thing);
+ thing->command = 0;
+ thing->progress = 0;
}
}
- map_object = map_object->next;
+ thing = thing->next;
}
}
{
if (!strncmp(msg, command_name, strlen(command_name)))
{
- struct MapObj * player = get_player();
+ struct Thing * player = get_player();
player->arg = atoi(&(msg[strlen(command_name)]));
- player->command = get_moa_id_by_name(command_name);
+ player->command = get_thing_action_id_by_name(command_name);
turn_over();
return 1;
}
char * f_name = "obey_msg()";
if ( apply_player_command(msg, "wait") /* TODO: Check for non-error */
|| apply_player_command(msg, "move") /* return value of a modified */
- || apply_player_command(msg, "pick_up")/* get_moa_id_by_name(); if id */
- || apply_player_command(msg, "drop") /* found, execute on it what's */
- || apply_player_command(msg, "use")); /* in apply_player_command(). */
- else
+ || apply_player_command(msg, "pick_up")/*get_thing_action_id_by_name()*/
+ || apply_player_command(msg, "drop") /* and if id found, execute on */
+ || apply_player_command(msg, "use")); /* it what's in */
+ else /* apply_player_command(). */
{
char * seed_command = "seed";
if (!strncmp(msg, seed_command, strlen(seed_command)))
--- /dev/null
+/* src/server/thing_actions.c */
+
+#include "thing_actions.h"
+#include <stddef.h> /* NULL */
+#include <stdint.h> /* uint8_t, uint16_t */
+#include <stdio.h> /* sprintf() */
+#include <stdlib.h> /* free() */
+#include <string.h> /* strlen(), strcmp(), memcpy(), strncmp() */
+#include "../common/rexit.h" /* exit_err() */
+#include "../common/try_malloc.h" /* try_malloc() */
+#include "../common/yx_uint8.h" /* struct yx_uint8 */
+#include "field_of_view.h" /* build_fov_map() */
+#include "things.h" /* structs Thing, ThingType, get_player(), own_thing(),
+ * set_thing_position(), get_thing_type()
+ */
+#include "map.h" /* is_passable() */
+#include "yx_uint8.h" /* mv_yx_in_dir(), yx_uint8_cmp() */
+#include "world.h" /* global world */
+
+
+
+/* Append "text" to game log, or a "." if "text" is the same as the last one. */
+static void update_log(char * text);
+
+/* One actor "wounds" another actor, decrementing his lifepoints and, if they
+ * reach zero in the process, killing it. Generates appropriate log message.
+ */
+static void actor_hits_actor(struct Thing * hitter, struct Thing * hitted);
+
+/* Bonus stuff to actor_*() to happen if actor==player. Mostly writing of log
+ * messages; _pick and _drop also decrement world.inventory_sel by 1 if >0.
+ * (match_dir() is just a little helper to playerbonus_move().)
+ */
+static void playerbonus_wait();
+static uint8_t match_dir(char d, char ** dsc_d, char match, char * dsc_match);
+static void playerbonus_move(char d, uint8_t passable);
+static void playerbonus_drop(uint8_t owns_none);
+static void playerbonus_pick(uint8_t picked);
+static void playerbonus_use(uint8_t no_thing, uint8_t wrong_thing);
+
+
+
+static void update_log(char * text)
+{
+ char * f_name = "update_log()";
+ uint16_t len_new = strlen(text);
+ uint16_t len_old = 0;
+ if (world.log)
+ {
+ len_old = strlen(world.log);
+ uint16_t last_nl = len_old - 1;
+ while (last_nl != 0)
+ {
+ if ('\n' == world.log[last_nl])
+ {
+ break;
+ }
+ last_nl--;
+ }
+ uint16_t last_stop = len_old - 1;
+ while (last_stop != 0)
+ {
+ if ('.' == world.log[last_stop] && '.' != world.log[last_stop - 1])
+ {
+ break;
+ }
+ last_stop--;
+ }
+ if ( (last_stop + 1) - last_nl == (uint16_t) strlen(text)
+ && 0 == strncmp(world.log + last_nl, text, strlen(text)))
+ {
+ text = ".";
+ }
+ }
+ uint16_t len_whole = len_old + len_new + 1;
+ char * new_text = try_malloc(len_whole, f_name);
+ memcpy(new_text, world.log, len_old);
+ sprintf(new_text + len_old, "%s", text);
+ free(world.log);
+ world.log = new_text;
+}
+
+
+
+static void actor_hits_actor(struct Thing * hitter, struct Thing * hitted)
+{
+ struct ThingType * tt_hitter = get_thing_type(hitter->type);
+ struct ThingType * tt_hitted = get_thing_type(hitted->type);
+ struct Thing * player = get_player();
+ char * msg1 = "You";
+ char * msg2 = "wound";
+ char * msg3 = "you";
+ if (player != hitter)
+ {
+ msg1 = tt_hitter->name;
+ msg2 = "wounds";
+ }
+ if (player != hitted)
+ {
+ msg3 = tt_hitted->name;
+ }
+ uint8_t len = 1 + strlen(msg1) + 1 + strlen(msg2) + 1 + strlen(msg3) + 2;
+ char msg[len];
+ sprintf(msg, "\n%s %s %s.", msg1, msg2, msg3);
+ update_log(msg);
+ hitted->lifepoints--;
+ if (0 == hitted->lifepoints)
+ {
+ hitted->type = tt_hitted->corpse_id;
+ if (player == hitted)
+ {
+ update_log(" You die.");
+ return;
+ }
+ update_log(" It dies.");
+ }
+}
+
+
+
+static void playerbonus_wait()
+{
+ update_log("\nYou wait.");
+}
+
+
+
+static uint8_t match_dir(char d, char ** dsc_d, char match, char * dsc_match)
+{
+ if (d == match)
+ {
+ * dsc_d = dsc_match;
+ return 1;
+ }
+ return 0;
+}
+
+
+
+static void playerbonus_move(char d, uint8_t passable)
+{
+ char * dsc_dir = "north-east";
+ if ( match_dir(d, &dsc_dir, 'd', "east")
+ || match_dir(d, &dsc_dir, 'c', "south-east")
+ || match_dir(d, &dsc_dir, 'x', "south-west")
+ || match_dir(d, &dsc_dir, 's', "west")
+ || match_dir(d, &dsc_dir, 'w', "north-west"))
+ {
+ ;
+ }
+ char * dsc_move = "You move ";
+ if (0 == passable)
+ {
+ dsc_move = "You fail to move ";
+ }
+ char msg[strlen(dsc_move) + strlen (dsc_dir) + 3];
+ sprintf(msg, "\n%s%s.", dsc_move, dsc_dir);
+ update_log(msg);
+}
+
+
+
+static void playerbonus_drop(uint8_t owns_none)
+{
+ if (0 != owns_none)
+ {
+ update_log("\nYou try to drop an object, but you own none.");
+ return;
+ }
+ update_log("\nYou drop an object.");
+}
+
+
+
+static void playerbonus_pick(uint8_t picked)
+{
+ if (picked)
+ {
+ update_log("\nYou pick up an object.");
+ return;
+ }
+ update_log("\nYou try to pick up an object, but there is none.");
+}
+
+
+
+static void playerbonus_use(uint8_t no_thing, uint8_t wrong_thing)
+{
+ if (no_thing)
+ {
+ update_log("\nYou try to use an object, but you own none.");
+ return;
+ }
+ else if (wrong_thing)
+ {
+ update_log("\nYou try to use this object, but fail.");
+ return;
+ }
+ update_log("\nYou consume MAGIC MEAT.");
+}
+
+
+
+extern void free_thing_actions(struct ThingAction * ta)
+{
+ if (NULL == ta)
+ {
+ return;
+ }
+ free(ta->name);
+ free_thing_actions(ta->next);
+ free(ta);
+}
+
+
+
+extern uint8_t get_thing_action_id_by_name(char * name)
+{
+ struct ThingAction * ta = world.thing_actions;
+ while (NULL != ta)
+ {
+ if (0 == strcmp(ta->name, name))
+ {
+ break;
+ }
+ ta = ta->next;
+ }
+ exit_err(NULL == ta, "get_thing_action_id_by_name() did not find action.");
+ return ta->id;
+}
+
+
+
+extern void actor_wait(struct Thing * t)
+{
+ if (t == get_player())
+ {
+ playerbonus_wait();
+ }
+}
+
+
+
+extern void actor_move(struct Thing * t)
+{
+ char d = t->arg;
+ struct yx_uint8 target = mv_yx_in_dir(d, t->pos);
+ struct Thing * other_t;
+ for (other_t = world.things; other_t != 0; other_t = other_t->next)
+ {
+ if (0 == other_t->lifepoints || other_t == t)
+ {
+ continue;
+ }
+ if (yx_uint8_cmp(&target, &other_t->pos))
+ {
+ actor_hits_actor(t, other_t);
+ return;
+ }
+ }
+ uint8_t passable = is_passable(target);
+ if (passable)
+ {
+ set_thing_position(t, target);
+ free(t->fov_map);
+ t->fov_map = build_fov_map(t);
+ }
+ if (t == get_player())
+ {
+ playerbonus_move(d, passable);
+ }
+}
+
+
+
+extern void actor_drop(struct Thing * t)
+{
+ uint8_t owns_none = (NULL == t->owns);
+ if (!owns_none)
+ {
+ uint8_t select = t->arg;
+ struct Thing * owned = t->owns;
+ uint8_t i = 0;
+ for (; i != select; i++, owned = owned->next);
+ own_thing(&world.things, &t->owns, owned->id);
+ }
+ if (t == get_player())
+ {
+ playerbonus_drop(owns_none);
+ }
+}
+
+
+
+extern void actor_pick(struct Thing * t)
+{
+ struct Thing * picked = NULL;
+ struct Thing * t_i;
+ for (t_i = world.things; NULL != t_i; t_i = t_i->next)
+ {
+ if (t_i != t && yx_uint8_cmp(&t_i->pos, &t->pos))
+ {
+ picked = t_i;
+ }
+ }
+ if (NULL != picked)
+ {
+ own_thing(&t->owns, &world.things, picked->id);
+ set_thing_position(picked, t->pos);
+ }
+ if (t == get_player())
+ {
+ playerbonus_pick(NULL != picked);
+ }
+}
+
+
+
+extern void actor_use(struct Thing * t)
+{
+ uint8_t wrong_thing = 1;
+ uint8_t no_thing = (NULL == t->owns);
+ if (!no_thing)
+ {
+ uint8_t select = t->arg;
+ uint8_t i = 0;
+ struct Thing * selected = t->owns;
+ for (; i != select; i++, selected = selected->next);
+ struct ThingType * tt = get_thing_type(selected->type);
+ if (tt->consumable)
+ {
+ wrong_thing = 0;
+ struct Thing * next = selected->next;
+ free(selected);
+ if (0 < select)
+ {
+ select--;
+ selected = t->owns;
+ for (i = 0; i != select; i++, selected = selected->next);
+ selected->next = next;
+ }
+ else
+ {
+ t->owns = next;
+ }
+ t->lifepoints = t->lifepoints + tt->consumable;
+ }
+ }
+ if (t == get_player())
+ {
+ playerbonus_use(no_thing, wrong_thing);
+ }
+}
--- /dev/null
+/* src/server/thing_actions.h
+ *
+ * Actions that can be performed by living things / "actors". Note that apart
+ * from the consequences described below, each action may also trigger log
+ * messages and other minor stuff if the actor is equal to the player.
+ */
+
+#ifndef THING_ACTIONS_H
+#define THING_ACTIONS_H
+
+#include <stdint.h> /* uint8_t */
+struct Thing;
+
+
+
+struct ThingAction
+{
+ uint8_t id; /* identifies action in Thing.command; therefore must be >0 */
+ struct ThingAction * next;
+ void (* func) (struct Thing *); /* function called after .effort turns */
+ char * name; /* human-readable identifier */
+ uint8_t effort; /* how many turns the action takes */
+};
+
+
+
+/* Free ThingAction * chain starting at "ta". */
+extern void free_thing_actions(struct ThingAction * ta);
+
+/* Return world.thing_actions ThingAction.id for "name". */
+extern uint8_t get_thing_action_id_by_name(char * name);
+
+/* Actor "t" does nothing. */
+extern void actor_wait(struct Thing * t);
+
+/* Actor "t" tries to move one step in direction described by char t->arg (where
+ * north-east is 'e', east 'd' etc.) Move either succeeds, or another actor is
+ * encountered and hit (which leads ot its lifepoint decreasing by one and
+ * eventually death), or the move fails due to an impassable target square. On
+ * success, update thing's field of view map.
+ */
+extern void actor_move(struct Thing * t);
+
+/* Actor "t" tries to drop from inventory thing indexed by number t->args. */
+extern void actor_drop(struct Thing * t);
+
+/* Actor "t" tries to pick up topmost thing from ground into its inventory. */
+extern void actor_pick(struct Thing * t);
+
+/* Actor "t" tries to use thing in inventory indexed by number t->args.
+ * (Currently the only valid use is consuming items defined as consumable.)
+ */
+extern void actor_use(struct Thing * t);
+
+
+
+#endif
--- /dev/null
+/* src/server/things.c */
+
+#include "things.h"
+#include <stddef.h> /* NULL */
+#include <stdint.h> /* uint8_t, uint16_t, UINT16_MAX */
+#include <stdlib.h> /* free() */
+#include <string.h> /* memset(), strlen() */
+#include "../common/rexit.h" /* exit_err() */
+#include "../common/try_malloc.h" /* try_malloc() */
+#include "../common/yx_uint8.h" /* yx_uint8 struct */
+#include "map.h" /* is_passable() */
+#include "rrand.h" /* rrand() */
+#include "world.h" /* global world */
+#include "yx_uint8.h" /* yx_uint8_cmp() */
+
+
+
+/* Return pointer to thing of "id" in chain starting at "ptr". */
+static struct Thing * get_thing(struct Thing * ptr, uint8_t id);
+
+/* Add thing of "type" to map on passable position. Don't put actor on actor. */
+static void add_thing(uint8_t type);
+
+
+
+static struct Thing * get_thing(struct Thing * ptr, uint8_t id)
+{
+ while (1)
+ {
+ if (NULL == ptr || id == ptr->id)
+ {
+ return ptr;
+ }
+ struct Thing * owned_thing = get_thing(ptr->owns, id);
+ if (NULL != owned_thing)
+ {
+ return ptr;
+ }
+ ptr = ptr->next;
+ }
+}
+
+
+
+static void add_thing(uint8_t type)
+{
+ char * f_name = "add_thing()";
+ struct ThingType * tt = get_thing_type(type);
+ struct Thing * t = try_malloc(sizeof(struct Thing), f_name);
+ memset(t, 0, sizeof(struct Thing));
+ t->id = world.thing_count++;
+ t->type = tt->id;
+ t->lifepoints = tt->lifepoints;
+ char * err = "Space to put thing on too hard to find. Map too small?";
+ uint16_t i = 0;
+ while (1)
+ {
+ struct yx_uint8 pos;
+ for (pos.y = pos.x = 0; 0 == is_passable(pos); i++)
+ {
+ exit_err(UINT16_MAX == i, err);
+ pos.y = rrand() % world.map.length;
+ pos.x = rrand() % world.map.length;
+ }
+ struct Thing * t_ptr;
+ uint8_t clear = 1;
+ for (t_ptr = world.things; t_ptr != NULL; t_ptr = t_ptr->next)
+ {
+ if (yx_uint8_cmp(&pos, &t_ptr->pos) && 0 != t_ptr->lifepoints)
+ {
+ clear = 0;
+ break;
+ }
+ }
+ if (1 == clear)
+ {
+ t->pos = pos;
+ break;
+ }
+ }
+ struct Thing ** t_ptr_ptr = &world.things;
+ for (; NULL != * t_ptr_ptr; t_ptr_ptr = &(*t_ptr_ptr)->next);
+ * t_ptr_ptr = t;
+}
+
+
+
+extern void free_thing_types(struct ThingType * tt_start)
+{
+ if (NULL == tt_start)
+ {
+ return;
+ }
+ free_thing_types(tt_start->next);
+ free(tt_start->name);
+ free(tt_start);
+}
+
+
+
+extern void add_things(uint8_t type, uint8_t n)
+{
+ uint8_t i;
+ for (i = 0; i < n; i++)
+ {
+ add_thing(type);
+ }
+}
+
+
+
+extern void free_things(struct Thing * t_start)
+{
+ if (NULL == t_start)
+ {
+ return;
+ }
+ free_things(t_start->owns);
+ free_things(t_start->next);
+ free(t_start->fov_map);
+ free(t_start);
+ if (t_start == world.things) /* So add_things()' NULL-delimited thing */
+ { /* iteration loop does not iterate over */
+ world.things = NULL; /* freed memory when called the first time */
+ } /* after world re-seeding. */
+}
+
+
+
+extern void own_thing(struct Thing ** target, struct Thing ** source,
+ uint8_t id)
+{
+ struct Thing * t;
+ if (id == (*source)->id)
+ {
+ t = * source;
+ * source = t->next;
+ }
+ else
+ {
+ struct Thing * penult = * source;
+ while (1)
+ {
+ if (id == penult->next->id)
+ {
+ break;
+ }
+ penult = penult->next;
+ }
+ t = penult->next;
+ penult->next = t->next;
+ }
+ struct Thing ** t_ptr_ptr = target;
+ for (; NULL != * t_ptr_ptr; t_ptr_ptr = &(*t_ptr_ptr)->next);
+ * t_ptr_ptr = t;
+ t->next = NULL;
+}
+
+
+
+extern struct Thing * get_player()
+{
+ return get_thing(world.things, 0);
+}
+
+
+
+extern struct ThingType * get_thing_type(uint8_t id)
+{
+ struct ThingType * tt = world.thing_types;
+ for (; NULL != tt && id != tt->id; tt = tt->next);
+ char * err_intro = "Requested thing type of unused ID ";
+ char err[strlen(err_intro) + 3 + 1 + 1];
+ sprintf(err, "%s%d.", err_intro, id);
+ exit_err(NULL == tt, err);
+ return tt;
+}
+
+
+
+extern void set_thing_position(struct Thing * t, struct yx_uint8 pos)
+{
+ t->pos = pos;
+ struct Thing * owned = t->owns;
+ for (; owned != NULL; set_thing_position(owned, pos), owned = owned->next);
+}
--- /dev/null
+/* src/server/things.h
+ *
+ * Structs for things and their type definitions, and routines to initialize
+ * these and load and save them from/to files.
+ */
+
+#ifndef THINGS_H
+#define THINGS_H
+
+#include <stdint.h> /* uint8_t */
+#include "../common/yx_uint8.h" /* yx_uint8 structs */
+
+
+
+struct Thing
+{
+ struct Thing * next; /* pointer to next one in things chain */
+ 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 id; /* individual thing's unique identifier */
+ 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 */
+ uint8_t arg; /* optional field for .command argument */
+ uint8_t progress; /* turns already passed to realize .command */
+};
+
+struct ThingType
+{
+ uint8_t id; /* thing type identifier / sets .type */
+ struct ThingType * next;
+ char char_on_map; /* thing symbol to appear on map */
+ char * name; /* string to describe thing in game log */
+ uint8_t corpse_id; /* type to change thing into upon destruction */
+ uint8_t lifepoints; /* default start value for thing's .lifepoints */
+ uint8_t consumable; /* can be eaten if !0, for so much hitpoint win */
+ uint8_t start_n; /* how many of these does the map start with? */
+};
+
+
+
+/* Free thing types chain starting at "tt_start". */
+extern void free_thing_types(struct ThingType * tt_start);
+
+/* Add thing(s) ("n": how many?) of "type" to map on random position(s). New
+ * animate things are never placed in the same square with other animate ones.
+ */
+extern void add_things(uint8_t type, uint8_t n);
+
+/* Free things in things chain starting at "t_start. */
+extern void free_things(struct Thing * t_start);
+
+/* Move thing of "id" from "source" inventory to "target" inventory. */
+extern void own_thing(struct Thing ** target, struct Thing ** source,
+ uint8_t id);
+
+/* Get pointer to the Thing struct that represents the player. */
+extern struct Thing * get_player();
+
+/* Get pointer to the thing type of identifier "def_id". */
+extern struct ThingType * get_thing_type(uint8_t id);
+
+/* Move not only "t" to "pos", but also all things owned by it. */
+extern void set_thing_position(struct Thing * t, struct yx_uint8 pos);
+
+
+
+#endif
#include <stdint.h> /* uint8_t, uint16_t, uint32_t */
#include <stdio.h> /* define FILE */
#include "../common/map.h" /* struct Map */
-struct MapObjDef;
-struct MapObjAct;
-struct MapObj;
+struct ThingType;
+struct ThingAction;
+struct Thing;
FILE * file_in; /* Input stream on file at .path_in. */
FILE * file_out; /* Output stream on file at .path_out. */
struct Map map;
- struct MapObjDef * map_obj_defs; /* Map object definitions. */
- struct MapObjAct * map_obj_acts; /* Map object action definitions. */
- struct MapObj * map_objs; /* Map objects. */
+ struct ThingType * thing_types; /* Thing type definitions. */
+ struct ThingAction * thing_actions; /* Thing action definitions. */
+ struct Thing * things; /* All physical things of the game world. */
char * log; /* Logs the game events from the player's view. */
char * server_test; /* String uniquely identifying server process. */
char * path_in; /* File to write client messages into. */
char * path_out; /* File to write server messages into. */
char * path_worldstate; /* File to represent world state to clients.*/
char * path_record; /* Record file from which to read the game history. */
- char * path_config; /* Path for map object (action) definitions file. */
+ char * path_config; /* Path for thing type / action definitions file. */
char * tmp_suffix; /* Appended to paths of files for their tmp versions. */
char * queue; /* Stores un-processed messages read from the input file. */
uint32_t queue_size;/* Length of .queue sequence of \0-terminated strings.*/
uint16_t replay; /* Turn up to which to replay game. No replay if zero. */
uint16_t turn; /* Current game turn. */
uint16_t last_update_turn; /* Last turn the .path_out file was updated. */
- uint8_t player_type; /* Map object type that player will start as. */
+ uint8_t player_type; /* Thing type that player will start as. */
uint8_t is_verbose; /* Should server send debugging info to stdout? */
- uint8_t map_obj_count; /* Counts map objects generated so far. */
+ uint8_t thing_count; /* Counts things generated so far. */
uint8_t enemy_fov; /* != 0 if non-player actors only see field of view. */
};