From 2dccba703435158681552b8a8aefccab79eb13f3 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 18 Nov 2013 04:22:17 +0100 Subject: [PATCH] Each map object action now take different numbers of turns to complete. Re-wrote large parts of map object actions system, player control and turn_over() for this. --- config/map_object_actions | 5 + src/command_db.c | 2 +- src/control.c | 180 +++++++++++++--------- src/main.c | 4 + src/main.h | 5 +- src/map.c | 12 ++ src/map.h | 5 + src/map_object_actions.c | 315 +++++++++++++++++++++++++------------- src/map_object_actions.h | 61 ++++---- src/map_objects.c | 22 ++- src/map_objects.h | 3 + src/misc.c | 47 ++++-- src/rexit.c | 7 +- src/rexit.h | 9 +- 14 files changed, 448 insertions(+), 229 deletions(-) create mode 100644 config/map_object_actions diff --git a/config/map_object_actions b/config/map_object_actions new file mode 100644 index 0000000..1ed03ea --- /dev/null +++ b/config/map_object_actions @@ -0,0 +1,5 @@ +0 1 wait +1 3 move +2 10 pick_up +3 3 drop +4 30 use diff --git a/src/command_db.c b/src/command_db.c index 34db4dc..c0aa523 100644 --- a/src/command_db.c +++ b/src/command_db.c @@ -79,7 +79,7 @@ extern char * get_command_longdsc(char * dsc_short) extern void init_command_db() { char * f_name = "init_command_db()"; - char * err_s = "Trouble in init_cmds() with textfile_sizes()."; + char * err_s = "Trouble in init_command_db() with textfile_sizes()."; char * path = "config/commands"; FILE * file = try_fopen(path, "r", f_name); diff --git a/src/control.c b/src/control.c index cb5ed3b..502f84a 100644 --- a/src/control.c +++ b/src/control.c @@ -2,6 +2,7 @@ #include "control.h" #include /* for uint8_t */ +#include /* for strcmp() */ #include "windows.h" /* for cycle_active_win(), shift_active_win(), struct Win, * struct WinMeta */ @@ -15,26 +16,35 @@ * growshrink_active_window(),toggle_winconfig(), * toggle_win_height_type(), toggle_win_width_type() */ -#include "map_object_actions.h" /* for player_wait(), move_player(), - * player_drop(), player_pick() +#include "map_object_actions.h" /* for struct MapObjAct, actor_wait(), + * actor_move(), actor_drop(), actor_pick(), + * actor_pick() */ #include "command_db.h" /* for is_command_id_shortdsc() */ #include "misc.h" /* for reload_interface_conf(), save_interface_conf(), - * nav_inventory() + * nav_inventory(), turn_over() */ +#include "map_objects.h" /* for get_player() */ -/* If "cmd" (either (type = "i") command or (type = "k") keybinding identifier) - * matches "match" in is_cmd_id_shortdsc() or get_available_keycode_to_action(), - * execute "f" with provided char arguments and return 1; else only return 0. +/* If "cmd" matches "match" in get_available_keycode_to_action(), execute "f" + * with provided char arguments and return 1; else only return 0. */ -static uint8_t try_cmd_0args(char type, int cmd, char * match, void (* f) ()); -static uint8_t try_cmd_1args(char type, int cmd, char * match, - void (* f) (char), char c); -static uint8_t try_cmd_2args(char type, int cmd, char * match, +static uint8_t try_cmd_0args(int cmd, char * match, void (* f) ()); +static uint8_t try_cmd_1args(int cmd, char * match, void (* f) (char), char c); +static uint8_t try_cmd_2args(int cmd, char * match, void (* f) (char, char), char c1, char c2); +/* try_player_cmd() helper, returns world.map_obj_acts action id for "name". */ +static uint8_t get_moa_id_by_name(char * name); + +/* If "action" is id of command named "match", set player->arg, ->command and + * call turn_over(). + */ +static uint8_t try_player_cmd(int action, char * match, char * command, + uint8_t arg); + /* Return pointer to global keybindings or to keybindings for wingeometry config * (c = "g") or winkeys config (c = "k") or active window's keybindings ("w"). */ @@ -46,10 +56,9 @@ static void wrap_mv_kb_mod(char c1, char c2); -static uint8_t try_cmd_0args(char type, int cmd, char * match, void (* f) ()) +static uint8_t try_cmd_0args(int cmd, char * match, void (* f) ()) { - if ( ('k' == type && cmd == get_available_keycode_to_action(match)) - || ('i' == type && is_command_id_shortdsc(cmd, match))) + if (cmd == get_available_keycode_to_action(match)) { f(); return 1; @@ -59,11 +68,9 @@ static uint8_t try_cmd_0args(char type, int cmd, char * match, void (* f) ()) -static uint8_t try_cmd_1args(char type, int cmd, char * match, - void (* f) (char), char c) +static uint8_t try_cmd_1args(int cmd, char * match, void (* f) (char), char c) { - if ( ('k' == type && cmd == get_available_keycode_to_action(match)) - || ('i' == type && is_command_id_shortdsc(cmd, match))) + if (cmd == get_available_keycode_to_action(match)) { f(c); return 1; @@ -73,11 +80,10 @@ static uint8_t try_cmd_1args(char type, int cmd, char * match, -static uint8_t try_cmd_2args(char type, int cmd, char * match, +static uint8_t try_cmd_2args(int cmd, char * match, void (* f) (char, char), char c1, char c2) { - if ( ('k' == type && cmd == get_available_keycode_to_action(match)) - || ('i' == type && is_command_id_shortdsc(cmd, match))) + if (cmd == get_available_keycode_to_action(match)) { f(c1, c2); return 1; @@ -87,6 +93,39 @@ static uint8_t try_cmd_2args(char type, int cmd, char * match, +static 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_name() did not find map object action."); + return moa->id; +} + + + +static uint8_t try_player_cmd(int action, char * match, char * command, + uint8_t arg) +{ + if (is_command_id_shortdsc(action, match)) + { + struct MapObj * player = get_player(); + player->arg = arg; + player->command = get_moa_id_by_name(command); + turn_over(get_command_id(match)); + return 1; + } + return 0; +} + + + static struct KeyBiData * select_keybidata_pointer(char c) { struct KeyBiData * kbd; @@ -166,16 +205,17 @@ extern uint8_t player_control_by_key(int key) + extern uint8_t player_control_by_id(int action) { - if ( try_cmd_0args('i', action, "wait", player_wait) - || try_cmd_0args('i', action, "drop", player_drop) - || try_cmd_0args('i', action, "pick", player_pick) - || try_cmd_0args('i', action, "use", player_use) - || try_cmd_1args('i', action, "player_u", move_player, 'N') - || try_cmd_1args('i', action, "player_d", move_player, 'S') - || try_cmd_1args('i', action, "player_r", move_player, 'E') - || try_cmd_1args('i', action, "player_l", move_player, 'W')) + if ( try_player_cmd(action, "wait", "wait", 0) + || try_player_cmd(action, "drop", "drop", world.inventory_select) + || try_player_cmd(action, "pick", "pick_up", 0) + || try_player_cmd(action, "use", "use", world.inventory_select) + || try_player_cmd(action, "player_u", "move", 'N') + || try_player_cmd(action, "player_d", "move", 'S') + || try_player_cmd(action, "player_r", "move", 'E') + || try_player_cmd(action, "player_l", "move", 'W')) { return 1; } @@ -186,14 +226,14 @@ extern uint8_t player_control_by_id(int action) extern uint8_t wingeom_control(int key) { - if ( try_cmd_0args('k', key, "to_height_t", toggle_win_height_type) - || try_cmd_0args('k', key, "to_width_t", toggle_win_width_type) - || try_cmd_1args('k', key, "grow_h", growshrink_active_window, '*') - || try_cmd_1args('k', key, "shri_h", growshrink_active_window, '_') - || try_cmd_1args('k', key, "grow_v", growshrink_active_window, '+') - || try_cmd_1args('k', key, "shri_v", growshrink_active_window, '-') - || try_cmd_1args('k', key, "shift_f", shift_active_win, 'f') - || try_cmd_1args('k', key, "shift_b", shift_active_win, 'b')) + if ( try_cmd_0args(key, "to_height_t", toggle_win_height_type) + || try_cmd_0args(key, "to_width_t", toggle_win_width_type) + || try_cmd_1args(key, "grow_h", growshrink_active_window, '*') + || try_cmd_1args(key, "shri_h", growshrink_active_window, '_') + || try_cmd_1args(key, "grow_v", growshrink_active_window, '+') + || try_cmd_1args(key, "shri_v", growshrink_active_window, '-') + || try_cmd_1args(key, "shift_f", shift_active_win, 'f') + || try_cmd_1args(key, "shift_b", shift_active_win, 'b')) { return 1; } @@ -204,9 +244,9 @@ extern uint8_t wingeom_control(int key) extern uint8_t winkeyb_control(int key) { - if ( try_cmd_1args('k', key, "w_keys_m", wrap_mod_selected_keyb, 'w') - || try_cmd_2args('k', key, "w_keys_u", wrap_mv_kb_mod, 'w', 'u') - || try_cmd_2args('k', key, "w_keys_d", wrap_mv_kb_mod, 'w', 'd')) + if ( try_cmd_1args(key, "w_keys_m", wrap_mod_selected_keyb, 'w') + || try_cmd_2args(key, "w_keys_u", wrap_mv_kb_mod, 'w', 'u') + || try_cmd_2args(key, "w_keys_d", wrap_mv_kb_mod, 'w', 'd')) { return 1; } @@ -219,37 +259,37 @@ extern uint8_t meta_control(int key) { uint8_t ret = (key == get_available_keycode_to_action("quit")); if ( (0 == ret) - && ( try_cmd_0args('k', key, "winconf", toggle_winconfig) - || try_cmd_0args('k', key, "reload_conf", reload_interface_conf) - || try_cmd_0args('k', key, "save_conf", save_interface_conf) - || try_cmd_0args('k', key, "map_c", map_center) - || try_cmd_1args('k', key, "scrl_r", scroll_pad, '+') - || try_cmd_1args('k', key, "scrl_l", scroll_pad, '-') - || try_cmd_1args('k', key, "to_a_keywin", toggle_window, 'k') - || try_cmd_1args('k', key, "to_g_keywin", toggle_window, '0') - || try_cmd_1args('k', key, "to_wg_keywin", toggle_window, '1') - || try_cmd_1args('k', key, "to_wk_keywin", toggle_window, '2') - || try_cmd_1args('k', key, "to_mapwin", toggle_window, 'm') - || try_cmd_1args('k', key, "to_infowin", toggle_window, 'i') - || try_cmd_1args('k', key, "to_inv", toggle_window, 'c') - || try_cmd_1args('k', key, "to_logwin", toggle_window, 'l') - || try_cmd_1args('k', key, "cyc_win_f", cycle_active_win, 'f') - || try_cmd_1args('k', key, "cyc_win_b", cycle_active_win, 'b') - || try_cmd_1args('k', key, "g_keys_m", wrap_mod_selected_keyb, 'G') - || try_cmd_1args('k', key, "wg_keys_m", wrap_mod_selected_keyb, 'g') - || try_cmd_1args('k', key, "wk_keys_m", wrap_mod_selected_keyb, 'k') - || try_cmd_1args('k', key, "inv_u", nav_inventory, 'u') - || try_cmd_1args('k', key, "inv_d", nav_inventory, 'd') - || try_cmd_1args('k', key, "map_u", map_scroll, 'N') - || try_cmd_1args('k', key, "map_d", map_scroll, 'S') - || try_cmd_1args('k', key, "map_r", map_scroll, 'E') - || try_cmd_1args('k', key, "map_l", map_scroll, 'W') - || try_cmd_2args('k', key, "g_keys_u", wrap_mv_kb_mod, 'G', 'u') - || try_cmd_2args('k', key, "g_keys_d", wrap_mv_kb_mod, 'G', 'd') - || try_cmd_2args('k', key, "wg_keys_u", wrap_mv_kb_mod, 'g', 'u') - || try_cmd_2args('k', key, "wg_keys_d", wrap_mv_kb_mod, 'g', 'd') - || try_cmd_2args('k', key, "wk_keys_u", wrap_mv_kb_mod, 'k', 'u') - || try_cmd_2args('k', key, "wk_keys_d", wrap_mv_kb_mod, 'k', 'd'))) + && ( try_cmd_0args(key, "winconf", toggle_winconfig) + || try_cmd_0args(key, "reload_conf", reload_interface_conf) + || try_cmd_0args(key, "save_conf", save_interface_conf) + || try_cmd_0args(key, "map_c", map_center) + || try_cmd_1args(key, "scrl_r", scroll_pad, '+') + || try_cmd_1args(key, "scrl_l", scroll_pad, '-') + || try_cmd_1args(key, "to_a_keywin", toggle_window, 'k') + || try_cmd_1args(key, "to_g_keywin", toggle_window, '0') + || try_cmd_1args(key, "to_wg_keywin", toggle_window, '1') + || try_cmd_1args(key, "to_wk_keywin", toggle_window, '2') + || try_cmd_1args(key, "to_mapwin", toggle_window, 'm') + || try_cmd_1args(key, "to_infowin", toggle_window, 'i') + || try_cmd_1args(key, "to_inv", toggle_window, 'c') + || try_cmd_1args(key, "to_logwin", toggle_window, 'l') + || try_cmd_1args(key, "cyc_win_f", cycle_active_win, 'f') + || try_cmd_1args(key, "cyc_win_b", cycle_active_win, 'b') + || try_cmd_1args(key, "g_keys_m", wrap_mod_selected_keyb, 'G') + || try_cmd_1args(key, "wg_keys_m", wrap_mod_selected_keyb, 'g') + || try_cmd_1args(key, "wk_keys_m", wrap_mod_selected_keyb, 'k') + || try_cmd_1args(key, "inv_u", nav_inventory, 'u') + || try_cmd_1args(key, "inv_d", nav_inventory, 'd') + || try_cmd_1args(key, "map_u", map_scroll, 'N') + || try_cmd_1args(key, "map_d", map_scroll, 'S') + || try_cmd_1args(key, "map_r", map_scroll, 'E') + || try_cmd_1args(key, "map_l", map_scroll, 'W') + || try_cmd_2args(key, "g_keys_u", wrap_mv_kb_mod, 'G', 'u') + || try_cmd_2args(key, "g_keys_d", wrap_mv_kb_mod, 'G', 'd') + || try_cmd_2args(key, "wg_keys_u", wrap_mv_kb_mod, 'g', 'u') + || try_cmd_2args(key, "wg_keys_d", wrap_mv_kb_mod, 'g', 'd') + || try_cmd_2args(key, "wk_keys_u", wrap_mv_kb_mod, 'k', 'u') + || try_cmd_2args(key, "wk_keys_d", wrap_mv_kb_mod, 'k', 'd'))) { ; } diff --git a/src/main.c b/src/main.c index 88d90d2..86f8507 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,7 @@ #include "control.h" /* for control_by_id(), player_control(), * get_available_keycode_to_action() */ +#include "map_object_actions.h" /* for init_map_object_actions() */ @@ -37,8 +38,11 @@ int main(int argc, char *argv[]) char * f_name = "main()"; world.turn = 0; /* Turns to 1 when map and objects are initalized. */ + /* Initialize commands and map object actions. */ init_command_db(); set_cleanup_flag(CLEANUP_COMMAND_DB); + init_map_object_actions(); + set_cleanup_flag(CLEANUP_MAPOBJACTS); /* Check for corrupted savefile / recordfile savings. */ char * recordfile = "record"; diff --git a/src/main.h b/src/main.h index e4d62e2..687dfc8 100644 --- a/src/main.h +++ b/src/main.h @@ -14,6 +14,7 @@ struct Win; struct Map; struct MapObjDef; struct MapObj; +struct MapObjAct; @@ -36,8 +37,8 @@ struct World struct MapObjDef * map_obj_defs; /* Map object type definitions chain. */ struct MapObj * map_objs; /* Pointer to map objects chain start. */ uint8_t inventory_select; /* Player's inventory selection index. */ - uint8_t old_inventory_select; /* Temporarily stores for recordfile */ -} world; /* writing inventory selection index. */ + struct MapObjAct * map_obj_acts; /* Pointer to map object actions chain. */ +} world; diff --git a/src/map.c b/src/map.c index 45cd2e1..1615818 100644 --- a/src/map.c +++ b/src/map.c @@ -97,3 +97,15 @@ extern void map_center() struct Win * win_map = get_win_by_id('m'); win_map->center = player->pos; } + + + +extern uint8_t is_passable(struct Map * map, struct yx_uint16 pos) +{ + uint8_t passable = 0; + if (0 <= pos.x && pos.x < map->size.x && 0 <= pos.y && pos.y < map->size.y) + { + passable = (('.' == map->cells[pos.y * map->size.x + pos.x])); + } + return passable; +} diff --git a/src/map.h b/src/map.h index 6a39e35..a1d607a 100644 --- a/src/map.h +++ b/src/map.h @@ -37,6 +37,11 @@ extern void map_scroll(char d); /* Center map on player. */ extern void map_center(); +/* Check if coordinate pos on (or beyond) map is accessible to map object + * movement. + */ +extern uint8_t is_passable(struct Map * map, struct yx_uint16 pos); + #endif diff --git a/src/map_object_actions.c b/src/map_object_actions.c index 9d1721e..1d3139f 100644 --- a/src/map_object_actions.c +++ b/src/map_object_actions.c @@ -1,25 +1,53 @@ /* map_object_actions.c */ #include "map_object_actions.h" -#include /* for strlen() */ +#include /* for uint8_t */ +#include /* for strlen(), strcmp() */ #include "yx_uint16.h" /* for yx_uint16 struct, mv_yx_in_dir(), * yx_uint16_cmp() */ #include "map_objects.h" /* for MapObj, MapObjDef structs, get_player(), * set_object_position(), own_map_object() */ -#include "misc.h" /* for update_log(), turn_over() */ -#include "map.h" /* for Map struct */ +#include "misc.h" /* for update_log(), try_malloc() */ +#include "map.h" /* for is_passable() */ #include "main.h" /* for world global */ -#include "command_db.h" /* for get_command_id() */ +#include "readwrite.h" /* for try_fopen(), try_fclose(), get_linemax() */ +#include "rexit.h" /* for exit_err() */ +/* If "name" fits "moa"->name, set "moa"->func to "func". */ +static uint8_t try_func_name(struct MapObjAct * moa, + char * name, void (* func) (struct MapObj *)); + /* 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_select by 1 if >0. + */ +static void playerbonus_wait(); +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 uint8_t try_func_name(struct MapObjAct * moa, + char * name, void (* func) (struct MapObj *)) +{ + if (0 == strcmp(moa->name, name)) + { + moa->func = func; + return 1; + } + return 0; +} + static void actor_hits_actor(struct MapObj * hitter, struct MapObj * hitted) @@ -64,189 +92,262 @@ static void actor_hits_actor(struct MapObj * hitter, struct MapObj * hitted) -extern uint8_t move_actor(struct MapObj * actor, char d) +static void playerbonus_wait() { - struct yx_uint16 target = mv_yx_in_dir(d, actor->pos); - struct MapObj * other_actor; - for (other_actor = world.map_objs; - other_actor != 0; - other_actor = other_actor->next) - { - if (0 == other_actor->lifepoints || other_actor == actor) - { - continue; - } - if (yx_uint16_cmp(&target, &other_actor->pos)) - { - actor_hits_actor(actor, other_actor); - return 2; - } - } - if (is_passable(world.map, target)) - { - set_object_position(actor, target); - return 0; - } - return 1; + update_log("\nYou wait."); } -extern void move_player(char d) +static void playerbonus_move(char d, uint8_t passable) { - char * dsc_dir; - char * action_dsc_prototype = "player_"; - uint8_t len_action_dsc_prototype = strlen(action_dsc_prototype); - char action_dsc[len_action_dsc_prototype + 2]; - memcpy(action_dsc, action_dsc_prototype, len_action_dsc_prototype); - if ('N' == d) - { - dsc_dir = "north"; - action_dsc[len_action_dsc_prototype] = 'u'; - } - else if ('E' == d) + char * dsc_dir = "north"; + if ('E' == d) { dsc_dir = "east" ; - action_dsc[len_action_dsc_prototype] = 'r'; } else if ('S' == d) { dsc_dir = "south"; - action_dsc[len_action_dsc_prototype] = 'd'; } else if ('W' == d) { dsc_dir = "west" ; - action_dsc[len_action_dsc_prototype] = 'l'; } - action_dsc[len_action_dsc_prototype + 1] = '\0'; - uint8_t res = move_actor(get_player(), d); - if (1 >= res) + char * dsc_move = "You move "; + if (0 == passable) { - char * dsc_move = "You fail to move "; - if (0 == res) - { - dsc_move = "You move "; - } - char msg[strlen(dsc_move) + strlen (dsc_dir) + 3]; - sprintf(msg, "\n%s%s.", dsc_move, dsc_dir); - update_log(msg); + dsc_move = "You fail to move "; } - turn_over(get_command_id(action_dsc)); + char msg[strlen(dsc_move) + strlen (dsc_dir) + 3]; + sprintf(msg, "\n%s%s.", dsc_move, dsc_dir); + update_log(msg); } -extern void player_wait() +static void playerbonus_drop(uint8_t owns_none) { - update_log("\nYou wait."); - turn_over(get_command_id("wait")); + if (0 != owns_none) + { + update_log("\nYou try to drop an object, but you own none."); + } + else + { + update_log("\nYou drop an object."); + if (0 < world.inventory_select) + { + world.inventory_select--; + } + } } -extern char is_passable(struct Map * map, struct yx_uint16 pos) +static void playerbonus_pick(uint8_t picked) { - uint8_t passable = 0; - if (0 <= pos.x && pos.x < map->size.x && 0 <= pos.y && pos.y < map->size.y) + if (picked) { - passable = (('.' == map->cells[pos.y * map->size.x + pos.x])); + update_log("\nYou pick up an object."); + } + else + { + update_log("\nYou try to pick up an object, but there is none."); } - return passable; } -extern void player_drop() +static void playerbonus_use(uint8_t no_object, uint8_t wrong_object) { - struct MapObj * player = get_player(); - if (NULL == player->owns) + if (no_object) { - update_log("\nYou try to drop an object, but you own none."); - world.old_inventory_select = 0; + update_log("\nYou try to use an object, but you own none."); + } + else if (wrong_object) + { + update_log("\nYou try to use this object, but fail."); } else { - world.old_inventory_select = world.inventory_select; - struct MapObj * owned = player->owns; - uint8_t i = 0; - for (; i != world.inventory_select; i++, owned = owned->next); + update_log("\nYou consume MAGIC MEAT."); if (0 < world.inventory_select) { world.inventory_select--; } - own_map_object(&world.map_objs, &player->owns, owned->id); - update_log("\nYou drop an object."); } - turn_over(get_command_id("drop")); } -extern void player_pick() +extern void init_map_object_actions() { - struct MapObj * player = get_player(); - struct MapObj * picked; - for (picked = world.map_objs; NULL != picked; picked = picked->next) + char * f_name = "init_map_object_actions()"; + + char * path = "config/map_object_actions"; + FILE * file = try_fopen(path, "r", f_name); + uint16_t linemax = get_linemax(file, f_name); + char line[linemax + 1]; + + struct MapObjAct ** moa_ptr_ptr = &world.map_obj_acts; + char * delim = " "; + while (fgets(line, linemax + 1, file)) { - if (picked != player && yx_uint16_cmp(&picked->pos, &player->pos)) + if ('\n' == line[0] || 0 == line[0]) { break; } + struct MapObjAct * moa = try_malloc(sizeof(struct MapObjAct), f_name); + moa->id = atoi(strtok(line, delim)); + moa->effort = atoi(strtok(NULL, delim)); + char * funcname = strtok(NULL, "\n"); + uint8_t len_name = strlen(funcname) + 1; + moa->name = try_malloc(len_name, f_name); + memcpy(moa->name, funcname, len_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))) + { + moa->func = actor_wait; + } + moa->next = NULL; + * moa_ptr_ptr = moa; + moa_ptr_ptr = &moa->next; } - if (NULL == picked) + try_fclose(file, f_name); +} + + + +extern void free_map_object_actions(struct MapObjAct * moa) +{ + if (NULL == moa) { - update_log("\nYou try to pick up an object, but there is none."); + return; } - else + free(moa->name); + free_map_object_actions(moa->next); + free(moa); +} + + + +extern void actor_wait(struct MapObj * mo) +{ + if (mo == get_player()) { - own_map_object(&player->owns, &world.map_objs, picked->id); - set_object_position(picked, player->pos); - update_log("\nYou pick up an object."); + playerbonus_wait(); } - turn_over(get_command_id("pick")); } -extern void player_use() +extern void actor_move(struct MapObj * mo) { - struct MapObj * player = get_player(); - if (NULL == player->owns) + char d = mo->arg; + struct yx_uint16 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) { - update_log("\nYou try to use an object, but you own none."); - world.old_inventory_select = 0; + if (0 == other_mo->lifepoints || other_mo == mo) + { + continue; + } + if (yx_uint16_cmp(&target, &other_mo->pos)) + { + actor_hits_actor(mo, other_mo); + return; + } } - else + uint8_t passable = is_passable(world.map, target); + if (passable) + { + set_object_position(mo, target); + } + 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; - struct MapObj * selected = player->owns; - for (; i != world.inventory_select; i++, selected = selected->next); + 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; + for (picked = world.map_objs; NULL != picked; picked = picked->next) + { + if (picked != mo && yx_uint16_cmp(&picked->pos, &mo->pos)) + { + break; + } + } + 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 (!strcmp("MAGIC MEAT", mod->name)) { + wrong_object = 0; struct MapObj * next = selected->next; free(selected); - if (0 < world.inventory_select) + if (0 < select) { - world.old_inventory_select = world.inventory_select; - world.inventory_select--; - for (i = 0, selected = player->owns; - i != world.inventory_select; + select--; + for (i = 0, selected = mo->owns; + i != select; i++, selected = selected->next); selected->next = next; } else { - player->owns = next; + mo->owns = next; } - player->lifepoints++; - update_log("\nYou consume MAGIC MEAT."); - } - else - { - update_log("\nYou try to use this object, but fail."); + mo->lifepoints++; } } - turn_over(get_command_id("use")); + if (mo == get_player()) + { + playerbonus_use(no_object, wrong_object); + } } diff --git a/src/map_object_actions.h b/src/map_object_actions.h index 7cc9843..e981228 100644 --- a/src/map_object_actions.h +++ b/src/map_object_actions.h @@ -1,48 +1,55 @@ /* map_object_actions.h * - * Routines for the actions available to map objects. + * 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 "yx_uint16.h" /* for yx_uint16 coordinates */ -struct Map; +#include /* for uint8_t */ struct MapObj; -/* Try to move "actor" one step in direction "d" (where east is 'E', north 'N' - * etc.) and handle the consequences: either the move succeeds, or another actor - * is encountered and hit (which leads to its lifepoint decreasing by one and - * potentially its death), or the target square is not passable, the move fails. - */ -extern uint8_t move_actor(struct MapObj * actor, char d); +struct MapObjAct +{ + struct MapObjAct * next; + uint8_t id; /* unique id of map object action */ + char * name; /* human-readable identifier */ + uint8_t effort; /* how many turn the action takes */ + void (* func) (struct MapObj *); /* function called after .effort turns */ +}; -/* Wrapper for using move_actor() on the MapObj representing the player; updates - * the game log with appropriate messages on the move attempt and its results; - * turns over to turn_over() when finished. - */ -extern void move_player(char d); -/* Make player wait one turn, i.e. only update_log with a "you wait" message - * and turn control over to the enemy. - */ -extern void player_wait(); -/* Check if coordinate pos on (or beyond) map is accessible to map object - * movement. +/* Init MapObjAct chain at world.map_obj_acts from config/map_object_actions. */ +extern void init_map_object_actions(); + +/* Free MapObjAct * chain starting at "moa". */ +extern void free_map_object_actions(struct MapObjAct * moa); + +/* 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 east is 'E', north 'N') 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. */ -extern char is_passable(struct Map * map, struct yx_uint16 pos); +extern void actor_move(struct MapObj * mo); -/* Make player drop to ground map ojbect indexed by world.inventory_select. */ -extern void player_drop(); +/* Actor "mo" tries to drop from inventory object indexed by number mo->args. */ +extern void actor_drop(struct MapObj * mo); -/* Make player pick up map object from ground. */ -extern void player_pick(); +/* Actor "mo" tries to pick up object from ground into its inventory. */ +extern void actor_pick(struct MapObj * mo); -/* Make player use object indexed by world.inventory_select. */ -extern void player_use(); +/* Actor "mo" tries to use inventory object indexed by number mo->args. + * (Currently the only valid use is consuming "MAGIC MEAT". + */ +extern void actor_use(struct MapObj * mo); diff --git a/src/map_objects.c b/src/map_objects.c index d114c5b..0107aff 100644 --- a/src/map_objects.c +++ b/src/map_objects.c @@ -31,8 +31,9 @@ static void write_map_object(FILE * file, struct MapObj * mo) for (; NULL != mo_ptr; mo_ptr = mo_ptr->next, i++); uint8_t size = 3+1 + 3+1 + 3+1 + 5+1 + 5 + ((1+3)*i) + 1 + 1; char line[size]; - sprintf(line, "%d %d %d %d %d", - mo->id, mo->type, mo->lifepoints, mo->pos.y, mo->pos.x); + sprintf(line, "%d %d %d %d %d %d %d %d", + mo->id, mo->type, mo->lifepoints, mo->pos.y, mo->pos.x, + mo->progress, mo->command, mo->arg); for (mo_ptr = mo->owns; NULL != mo_ptr; mo_ptr = mo_ptr->next) { sprintf(line + strlen(line), " %d", mo_ptr->id); @@ -130,13 +131,16 @@ extern void read_map_objects(FILE * file, char * line, int linemax) exit_err(-1 == fgetpos(file, &pos), f_name); while (try_fgets(line, linemax + 1, file, f_name)) { - mo = malloc(sizeof(struct MapObj)); + mo = try_malloc(sizeof(struct MapObj), f_name); mo->next = NULL; mo->id = atoi(strtok(line, delim)); mo->type = atoi(strtok(NULL, delim)); mo->lifepoints = atoi(strtok(NULL, delim)); mo->pos.y = atoi(strtok(NULL, delim)); mo->pos.x = atoi(strtok(NULL, delim)); + mo->progress = atoi(strtok(NULL, delim));; + mo->command = atoi(strtok(NULL, delim));; + mo->arg = atoi(strtok(NULL, delim));; mo->owns = NULL; if (mo->id > world.map_obj_count) { @@ -149,10 +153,11 @@ extern void read_map_objects(FILE * file, char * line, int linemax) while (try_fgets(line, linemax + 1, file, f_name)) { uint8_t id = atoi(strtok(line, delim)); - strtok(NULL, delim); - strtok(NULL, delim); - strtok(NULL, delim); - strtok(NULL, delim); + uint8_t i; + for (i = 0; i < 7; i++) + { + strtok(NULL, delim); + } char * owned = strtok(NULL, "\n"); if (NULL != owned) { @@ -199,6 +204,9 @@ extern void add_map_object(uint8_t type) break; } } + mo->progress = 0; + mo->command = 0; + mo->arg = 0; mo->owns = NULL; mo->next = NULL; struct MapObj ** last_ptr_ptr = &world.map_objs; diff --git a/src/map_objects.h b/src/map_objects.h index 6342f4b..2bd1bec 100644 --- a/src/map_objects.h +++ b/src/map_objects.h @@ -21,6 +21,9 @@ struct MapObj uint8_t type; /* ID of appropriate map object definition */ uint8_t lifepoints; /* 0: object is inanimate; >0: hitpoints */ struct yx_uint16 pos; /* coordinate on map */ + uint8_t command; /* command map object tries to realize now*/ + uint8_t arg; /* optional field for command argument */ + uint8_t progress; /* turns already passed to realize .command */ }; struct MapObjDef diff --git a/src/misc.c b/src/misc.c index 48ced07..4e6527d 100644 --- a/src/misc.c +++ b/src/misc.c @@ -12,8 +12,8 @@ #include "map_objects.h" /* for struct MapObj, get_player(), read_map_objects(), * write_map_objects() */ -#include "map_object_actions.h" /* for is_passable(), move_actor() */ -#include "map.h" /* for Map struct */ +#include "map_object_actions.h" /* for struct MapObjAct */ +#include "map.h" /* for Map struct, is_passable() */ #include "main.h" /* for world global */ #include "yx_uint16.h" /* for yx_uint16 struct */ #include "rrand.h" /* for rrand(), rrand_seed() */ @@ -225,21 +225,48 @@ extern void turn_over(char action) if ( is_command_id_shortdsc(action, "drop") || is_command_id_shortdsc(action, "use")) { - uint8_t inventory_select = world.old_inventory_select; - exit_err(write_uint8(inventory_select, file_new), err_write); + exit_err(write_uint8(world.inventory_select, file_new), err_write); } try_fclose_unlink_rename(file_new, recordfile_tmp, recordfile, f_name); } - world.turn++; rrand_seed(world.seed * world.turn); - struct MapObj * monster; - for (monster = world.map_objs; monster != 0; monster = monster->next) + + struct MapObj * player = get_player(); + struct MapObj * map_object = player; + uint8_t first_round = 1; + while (0 < player->lifepoints) { - if (0 < monster->lifepoints && 0 != monster->id) + if (NULL == map_object) { - char * sel = "\0NSEW"; - move_actor(monster, sel[rrand() % 5]); + world.turn++; + map_object = world.map_objs; + } + if (0 < map_object->lifepoints) /* map_object is animate. */ + { + if (0 == first_round && 0 == map_object->progress) + { + if (map_object == player) + { + break; + } + char * sel = "NSEW"; + map_object->command = 1; + map_object->arg = sel[rrand() % 4]; + } + first_round = 0; + map_object->progress++; + struct MapObjAct * moa = world.map_obj_acts; + while (moa->id != map_object->command) + { + moa = moa->next; + } + if (map_object->progress == moa->effort) + { + moa->func(map_object); + map_object->progress = 0; + } } + map_object = map_object->next; } } diff --git a/src/rexit.c b/src/rexit.c index 84664a8..0b673af 100644 --- a/src/rexit.c +++ b/src/rexit.c @@ -13,6 +13,7 @@ #include "windows.h" /* for Win struct, free_win(), free_winmeta() */ #include "map_objects.h" /* for free_map_objects, free_map_object_defs() */ #include "misc.h" /* for unload_interface_conf() */ +#include "map_object_actions.h" /* for free_map_object_actions() */ @@ -44,13 +45,17 @@ static void cleanup() { free_command_db(); } + if (cleanup_flags & CLEANUP_MAPOBJACTS) + { + free_map_object_actions(world.map_obj_acts); + } if (cleanup_flags & CLEANUP_MAP) { free(world.map->cells); } if (cleanup_flags & CLEANUP_INTERFACE_CONF) { - unload_interface_conf(/*&world*/); + unload_interface_conf(); } if (cleanup_flags & CLEANUP_WIN_META) { diff --git a/src/rexit.h b/src/rexit.h index 47a9993..459fcb9 100644 --- a/src/rexit.h +++ b/src/rexit.h @@ -23,10 +23,11 @@ enum cleanup_flag CLEANUP_MAP = 0x0002, CLEANUP_LOG = 0x0004, CLEANUP_COMMAND_DB = 0x0008, - CLEANUP_MAP_OBJECTS = 0x0010, - CLEANUP_MAP_OBJECT_DEFS = 0x0020, - CLEANUP_WIN_META = 0x0040, - CLEANUP_INTERFACE_CONF = 0x0080 + CLEANUP_MAPOBJACTS = 0x0010, + CLEANUP_MAP_OBJECTS = 0x0020, + CLEANUP_MAP_OBJECT_DEFS = 0x0040, + CLEANUP_WIN_META = 0x0080, + CLEANUP_INTERFACE_CONF = 0x0100 }; extern void set_cleanup_flag(enum cleanup_flag flag); -- 2.30.2