From: Christian Heller Date: Mon, 7 Oct 2013 00:08:28 +0000 (+0200) Subject: Added primitive inventory system. Any objects may now own/contain/carry other objects. X-Git-Tag: tce~944 X-Git-Url: https://plomlompom.com/repos/%7B%7Bdb.prefix%7D%7D/%7B%7Byoutube_prefix%7D%7D%7B%7Bvideo_id%7D%7D?a=commitdiff_plain;h=657d5dbc6d362d7b20693c63b38d8d99f3d2dbbd;p=plomrogue Added primitive inventory system. Any objects may now own/contain/carry other objects. --- diff --git a/config/commands b/config/commands index 4eebf3f..ba35ecb 100644 --- a/config/commands +++ b/config/commands @@ -44,3 +44,7 @@ 45 map_c map center player 46 to_a_keywin toggle view of available keybindings 46 to_inv toggle inventory window +47 drop drop object from inventory +48 pick pick up object from ground +49 inv_d inventory selection down +50 inv_u inventory selection up diff --git a/config/windows/Win_c b/config/windows/Win_c index c354ff6..d6b2588 100644 --- a/config/windows/Win_c +++ b/config/windows/Win_c @@ -2,3 +2,6 @@ Inventory c 5 33 +100 drop +259 inv_u +258 inv_d diff --git a/config/windows/Win_m b/config/windows/Win_m index e2bdc06..a83973f 100644 --- a/config/windows/Win_m +++ b/config/windows/Win_m @@ -2,6 +2,7 @@ Map m 0 -64 +112 pick 58 wait 107 player_u 106 player_d diff --git a/src/control.c b/src/control.c index 874601b..c590539 100644 --- a/src/control.c +++ b/src/control.c @@ -15,10 +15,12 @@ * growshrink_active_window(), toggle_winconfig(), * toggle_win_height_type(), toggle_win_width_type() */ -#include "map_object_actions.h" /* for player_wait(), move_player() */ +#include "map_object_actions.h" /* for player_wait(), move_player(), + * player_drop(), player_pick() + */ #include "command_db.h" /* for is_command_id_shortdsc() */ #include "misc.h" /* for load_interface_conf(), unload_interface_conf(), - * save_interface_conf() + * save_interface_conf(), nav_inventory() */ #include "yx_uint16.h" /* for dir enum */ #include "map_objects.h" /* for get_player() */ @@ -73,13 +75,25 @@ extern void record_control(int action, struct World * world) { move_player(world, WEST); } + else if (is_command_id_shortdsc(world, action, "drop")) + { + player_drop(world); + } + else if (is_command_id_shortdsc(world, action, "pick")) + { + player_pick(world); + } } extern uint8_t player_control(int key, struct World * world) { - if (key == get_available_keycode_to_action(world, "player_u")) + if (key == get_available_keycode_to_action(world, "wait")) + { + player_wait(world); + } + else if (key == get_available_keycode_to_action(world, "player_u")) { move_player(world, NORTH); } @@ -95,9 +109,13 @@ extern uint8_t player_control(int key, struct World * world) { move_player(world, WEST); } - else if (key == get_available_keycode_to_action(world, "wait")) + else if (key == get_available_keycode_to_action(world, "drop")) { - player_wait(world); + player_drop(world); + } + else if (key == get_available_keycode_to_action(world, "pick")) + { + player_pick(world); } else { @@ -306,6 +324,14 @@ extern uint8_t meta_control(int key, struct World * world) { map_center_object(world->map, get_player(world), win_map->frame.size); } + else if (key == get_available_keycode_to_action(world, "inv_u")) + { + nav_inventory(world, 'u'); + } + else if (key == get_available_keycode_to_action(world, "inv_d")) + { + nav_inventory(world, 'd'); + } else if (key == get_available_keycode_to_action(world, "reload_conf")) { unload_interface_conf(world); diff --git a/src/draw_wins.c b/src/draw_wins.c index 1ca2c85..797864a 100644 --- a/src/draw_wins.c +++ b/src/draw_wins.c @@ -43,6 +43,16 @@ static void draw_map_objects(struct World * world, struct MapObj * start, static char * get_kb_line_and_iterate(struct World * world, struct KeyBinding ** kb_pp); +/* Draw horizontal scroll hints in "frame" at the end line or a start line of y + * value "start" if the current "y" fits one of these lines and the number of + * lines "n_owned" and the "offset" make it appropriate. + * + * Return 1 if a scroll hint was drawn, else 0. + */ +static uint8_t scroll_hint_helper(struct World * world, uint16_t start, + uint16_t y, uint16_t offset, uint16_t n_owned, + struct Frame * frame, char * f_name); + /* Draw from line "start" on config view for keybindings defined at "kb". */ static void draw_kb_view(struct World * world, struct Win * win, char * f_name, struct KeyBiData * kb, uint8_t start); @@ -234,32 +244,50 @@ static char * get_kb_line_and_iterate(struct World * world, +static uint8_t scroll_hint_helper(struct World * world, uint16_t start, + uint16_t y, uint16_t offset, uint16_t n_owned, + struct Frame * frame, char * f_name) +{ + uint8_t ret = 0; + char * err_hint = trouble_msg(world, f_name, "draw_scroll_hint()"); + if (start == y && offset > 0) + { + uint8_t test = draw_scroll_hint(frame, y, offset + 1, '^'); + exit_err(test, world, err_hint); + ret = 1; + } + else if ( frame->size.y == y + 1 + && n_owned > frame->size.y + offset - 1 - start) + { + uint8_t pos = n_owned - (offset + frame->size.y) + 2 + start; + uint8_t test = draw_scroll_hint(frame, y, pos, 'v'); + exit_err(test, world, err_hint); + ret = 1; + } + free(err_hint); + return ret; +} + + + static void draw_kb_view(struct World * world, struct Win * win, char * f_name, struct KeyBiData * kb, uint8_t start) { if (0 == kb->kbs) { draw_line(win, start, "(none)", 0, 0); + return; } - char * err_hint = trouble_msg(world, f_name, "draw_scroll_hint()"); uint16_t kb_max = get_n_of_keybs(kb->kbs) - 1; - uint16_t y, offset; + uint16_t offset; offset = center_offset(kb->select, kb_max, win->frame.size.y - 1 - start); - uint16_t y_border = win->frame.size.y + offset - 1 - start; struct KeyBinding * kb_p = get_keyb_of_n(kb->kbs, offset + (offset > 0)); + uint16_t y; for (y = start; 0 != kb_p && y < win->frame.size.y; y++) { - if (start == y && offset > 0) - { - uint8_t test = draw_scroll_hint(&win->frame, y, offset + 1, '^'); - exit_err(test, world, err_hint); - continue; - } - else if (win->frame.size.y == y + 1 && kb_max > y_border) + if (scroll_hint_helper(world, start, y, offset, kb_max, &win->frame, + f_name)) { - uint16_t pos = kb_max - (offset + win->frame.size.y) + 2 + start; - uint8_t test = draw_scroll_hint(&win->frame, y, pos, 'v'); - exit_err(test, world, err_hint); continue; } attr_t attri = 0; @@ -273,9 +301,9 @@ static void draw_kb_view(struct World * world, struct Win * win, } char * kb_line = get_kb_line_and_iterate(world, &kb_p); draw_line(win, y, kb_line, attri, 1); + free(kb_line); } - free(err_hint); } @@ -374,7 +402,39 @@ extern void draw_win_info(struct Win * win) extern void draw_win_inventory(struct Win * win) { - mvwaddstr(win->frame.curses_win, 0, 0, "(empty)"); + struct World * world = (struct World *) win->data; + struct MapObj * player = get_player(world); + if (NULL == player->owns) + { + mvwaddstr(win->frame.curses_win, 0, 0, "(empty)"); + return; + } + char * f_name = "draw_win_inventory()"; + struct MapObj * owned = player->owns; + uint8_t n_owned; + for (n_owned = 0; NULL != owned->next; owned = owned->next, n_owned++); + uint8_t offset = center_offset(world->inventory_select, n_owned, + win->frame.size.y - 1); + uint8_t i; + for (i = 0, owned = player->owns; i < offset + (offset > 0); + i++, owned = owned->next); + uint8_t y; + for (y = 0; NULL != owned && y < win->frame.size.y; y++) + { + if (scroll_hint_helper(world, 0, y, offset, n_owned, &win->frame, + f_name)) + { + continue; + } + attr_t attri = 0; + if (y == world->inventory_select - offset) + { + attri = A_REVERSE; + } + struct MapObjDef * mod = get_map_object_def(world, owned->type); + draw_line(win, y, mod->name, attri, 0); + owned = owned->next; + } } diff --git a/src/main.c b/src/main.c index 68b1ebb..90aa9dd 100644 --- a/src/main.c +++ b/src/main.c @@ -164,6 +164,9 @@ int main(int argc, char *argv[]) struct Win * win_map = get_win_by_id(&world, 'm'); map_center_object(&map, player, win_map->frame.size); + /* Initialize player's inventory selection index to start position. */ + world.inventory_select = 0; + /* Replay mode. */ int key; struct WinConf * wc; diff --git a/src/main.h b/src/main.h index 56d458b..bf86e05 100644 --- a/src/main.h +++ b/src/main.h @@ -37,6 +37,7 @@ struct World uint8_t map_obj_count; /* Counts map objects generated so far. */ 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. */ }; diff --git a/src/map_object_actions.c b/src/map_object_actions.c index 387b18a..4217145 100644 --- a/src/map_object_actions.c +++ b/src/map_object_actions.c @@ -2,8 +2,12 @@ #include "map_object_actions.h" #include /* for strlen() */ -#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() */ +#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 "main.h" /* for World struct */ @@ -83,7 +87,7 @@ extern uint8_t move_actor(struct World * world, struct MapObj * actor, } if (is_passable(world->map, target)) { - actor->pos = target; + set_object_position(actor, target); return 0; } return 1; @@ -156,3 +160,53 @@ extern char is_passable(struct Map * map, struct yx_uint16 pos) } return passable; } + + + +extern void player_drop(struct World * world) +{ + struct MapObj * player = get_player(world); + if (NULL == player->owns) + { + update_log(world, "\nYou try to drop an object, but you own none."); + } + else + { + struct MapObj * owned = player->owns; + uint8_t i = 0; + for (; i != world->inventory_select; i++, owned = owned->next); + if (0 < world->inventory_select) + { + world->inventory_select--; + } + own_map_object(&world->map_objs, &player->owns, owned->id); + update_log(world, "\nYou drop an object."); + } + turn_over(world, get_command_id(world, "drop")); +} + + + +extern void player_pick(struct World * world) +{ + struct MapObj * player = get_player(world); + struct MapObj * picked; + for (picked = world->map_objs; NULL != picked; picked = picked->next) + { + if (picked != player && yx_uint16_cmp(&picked->pos, &player->pos)) + { + break; + } + } + if (NULL == picked) + { + update_log(world, "\nYou try to pick up an object, but there is none."); + } + else + { + own_map_object(&player->owns, &world->map_objs, picked->id); + set_object_position(picked, player->pos); + update_log(world, "\nYou pick up an object."); + } + turn_over(world, get_command_id(world, "pick")); +} diff --git a/src/map_object_actions.h b/src/map_object_actions.h index 3041c9c..30bbae3 100644 --- a/src/map_object_actions.h +++ b/src/map_object_actions.h @@ -47,4 +47,12 @@ extern char is_passable(struct Map * map, struct yx_uint16 pos); +/* Make player drop to ground map ojbect indexed by world.inventory_select. */ +extern void player_drop(struct World * world); + +/* Make player pick up map object from ground. */ +extern void player_pick(struct World * world); + + + #endif diff --git a/src/map_objects.c b/src/map_objects.c index ed41d93..3745fcf 100644 --- a/src/map_objects.c +++ b/src/map_objects.c @@ -15,6 +15,60 @@ +/* Write representation of "mo" and all of the map objects it owns to "file". */ +static void write_map_object(struct World * w, FILE * file, struct MapObj * mo); + + + +/* Return pointer to map object of "id" in chain starting at "ptr". */ +static struct MapObj * get_map_object(struct MapObj * ptr, uint8_t id); + + + +static void write_map_object(struct World * w, FILE * file, struct MapObj * mo) +{ + char * f_name = "write_map_object()"; + struct MapObj * mo_ptr = mo->owns; + uint8_t i = 0; + 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); + for (mo_ptr = mo->owns; NULL != mo_ptr; mo_ptr = mo_ptr->next) + { + sprintf(line + strlen(line), " %d", mo_ptr->id); + } + line[strlen(line) + 1] = '\0'; + line[strlen(line)] = '\n'; + try_fwrite(line, strlen(line), 1, file, w, f_name); + for (mo_ptr = mo->owns; NULL != mo_ptr; mo_ptr = mo_ptr->next) + { + write_map_object(w, file, mo_ptr); + } +} + + + +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; + } +} + + + extern void init_map_object_defs(struct World * world, char * filename) { char * f_name = "init_map_object_defs()"; @@ -58,15 +112,10 @@ extern void free_map_object_defs(struct MapObjDef * mod_start) extern void write_map_objects(struct World * world, FILE * file) { - char * f_name = "write_map_objects()"; struct MapObj * mo = world->map_objs; - uint8_t size = 3 + 1 + 3 + 1 + 3 + 1 + 5 + 1 + 5 + 1; - char line[size]; while (NULL != mo) { - sprintf(line, "%d %d %d %d %d\n", - mo->id, mo->type, mo->lifepoints, mo->pos.y, mo->pos.x); - try_fwrite(line, strlen(line), 1, file, world, f_name); + write_map_object(world, file, mo); mo = mo->next; } } @@ -80,29 +129,54 @@ extern void read_map_objects(struct World * world, FILE * file, char * line, struct MapObj ** mo_ptr_ptr = &world->map_objs; char * delim = " "; struct MapObj * mo; + fpos_t pos; + exit_err(-1 == fgetpos(file, &pos), world, f_name); while (try_fgets(line, linemax + 1, file, world, f_name)) { mo = malloc(sizeof(struct MapObj)); - mo->next = NULL; - mo->id = atoi(strtok(line, delim)); + 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->owns = NULL; if (mo->id > world->map_obj_count) { world->map_obj_count = mo->id; } - 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_ptr_ptr = mo; mo_ptr_ptr = &mo->next; } + exit_err(-1 == fsetpos(file, &pos), world, f_name); + while (try_fgets(line, linemax + 1, file, world, f_name)) + { + uint8_t id = atoi(strtok(line, delim)); + strtok(NULL, delim); + strtok(NULL, delim); + strtok(NULL, delim); + strtok(NULL, delim); + char * owned = strtok(NULL, "\n"); + if (NULL != owned) + { + mo = get_map_object(world->map_objs, id); + char * owned_id = ""; + owned_id = strtok(owned, delim); + while (NULL != owned_id) + { + own_map_object(&mo->owns, &world->map_objs, + (uint8_t) atoi(owned_id)); + owned_id = strtok(NULL, delim); + } + } + } } extern void add_map_object(struct World * world, uint8_t type) { - char * f_name = "add_map_object"; + char * f_name = "add_map_object()"; struct MapObjDef * mod = get_map_object_def(world, type); struct MapObj * mo = try_malloc(sizeof(struct MapObj), world, f_name); mo->id = world->map_obj_count; @@ -130,6 +204,7 @@ extern void add_map_object(struct World * world, uint8_t type) break; } } + mo->owns = NULL; mo->next = NULL; struct MapObj ** last_ptr_ptr = &world->map_objs; struct MapObj * mo_ptr; @@ -160,27 +235,52 @@ extern void free_map_objects(struct MapObj * mo_start) { return; } + free_map_objects(mo_start->owns); free_map_objects(mo_start->next); free(mo_start); } -extern struct MapObj * get_player(struct World * world) +extern void own_map_object(struct MapObj ** target, struct MapObj ** source, + uint8_t id) { - struct MapObj * ptr = world->map_objs; - while (1) + struct MapObj * mo; + if (id == (*source)->id) { - if (NULL == ptr) - { - return ptr; - } - if (0 == ptr->id) + mo = * source; + * source = mo->next; + } + else + { + struct MapObj * penult = * source; + while (1) { - return ptr; + if (id == penult->next->id) + { + break; + } + penult = penult->next; } - ptr = ptr->next; + mo = penult->next; + penult->next = mo->next; } + struct MapObj ** last_ptr_ptr = target; + struct MapObj * mo_ptr; + while (NULL != * last_ptr_ptr) + { + mo_ptr = * last_ptr_ptr; + last_ptr_ptr = & mo_ptr->next; + } + * last_ptr_ptr = mo; + mo->next = NULL; +} + + + +extern struct MapObj * get_player(struct World * world) +{ + return get_map_object(world->map_objs, 0); } @@ -194,3 +294,15 @@ extern struct MapObjDef * get_map_object_def(struct World * w, uint8_t id) } return mod; } + + + +extern void set_object_position(struct MapObj * mo, struct yx_uint16 pos) +{ + mo->pos = pos; + struct MapObj * owned = mo->owns; + for (; owned != NULL; owned = owned->next) + { + set_object_position(owned, pos); + } +} diff --git a/src/map_objects.h b/src/map_objects.h index 5cbab7b..1489711 100644 --- a/src/map_objects.h +++ b/src/map_objects.h @@ -19,6 +19,7 @@ struct World; struct MapObj { struct MapObj * next; /* pointer to next one in map object chain */ + struct MapObj * owns; /* chain of map objects owned / in inventory */ 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 */ @@ -74,6 +75,12 @@ 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(struct World * world); @@ -84,4 +91,9 @@ extern struct MapObjDef * get_map_object_def(struct World * w, 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_uint16 pos); + + + #endif diff --git a/src/misc.c b/src/misc.c index 522af09..aa855cd 100644 --- a/src/misc.c +++ b/src/misc.c @@ -9,7 +9,7 @@ #include "readwrite.h" /* for [read/write]_uint[8/16/32][_bigendian](), * try_fopen(), try_fclose() */ -#include "map_objects.h" /* for struct MapObj, read_map_objects(), +#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() */ @@ -234,11 +234,9 @@ extern void turn_over(struct World * world, char action) extern void save_game(struct World * world) { char * f_name = "save_game()"; - char * savefile_tmp = "savefile_tmp"; char * savefile = "savefile"; FILE * file = try_fopen(savefile_tmp, "w", world, f_name); - char line[12]; sprintf(line, "%d\n", world->seed); try_fwrite(line, strlen(line), 1, file, world, f_name); @@ -247,7 +245,6 @@ extern void save_game(struct World * world) sprintf(line, "%d\n", world->score); try_fwrite(line, strlen(line), 1, file, world, f_name); write_map_objects(world, file); - try_fclose_unlink_rename(file, savefile_tmp, savefile, world, f_name); } @@ -282,3 +279,29 @@ extern struct yx_uint16 find_passable_pos(struct Map * map) } return pos; } + + + +extern void nav_inventory(struct World * world, char dir) +{ + if ('u' == dir) + { + if (world->inventory_select > 0) + { + world->inventory_select--; + } + return; + } + struct MapObj * player = get_player(world); + struct MapObj * owned = player->owns; + if (NULL == owned) + { + return; + } + uint8_t n_owned = 0; + for (; NULL != owned->next; owned = owned->next, n_owned++); + if (world->inventory_select < n_owned) + { + world->inventory_select++; + } +} diff --git a/src/misc.h b/src/misc.h index b692308..c823af6 100644 --- a/src/misc.h +++ b/src/misc.h @@ -79,4 +79,11 @@ extern struct yx_uint16 find_passable_pos(struct Map * map); +/* Navigate (as far as possible) up (dir=='u') or (else) down in player's + * inventory selection. + */ +extern void nav_inventory(struct World * world, char dir); + + + #endif