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
c
5
33
+100 drop
+259 inv_u
+258 inv_d
m
0
-64
+112 pick
58 wait
107 player_u
106 player_d
* 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() */
{
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);
}
{
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
{
{
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);
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);
+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;
}
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);
}
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;
+ }
}
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;
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. */
};
#include "map_object_actions.h"
#include <string.h> /* 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 */
}
if (is_passable(world->map, target))
{
- actor->pos = target;
+ set_object_position(actor, target);
return 0;
}
return 1;
}
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"));
+}
+/* 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
+/* 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()";
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;
}
}
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;
break;
}
}
+ mo->owns = NULL;
mo->next = NULL;
struct MapObj ** last_ptr_ptr = &world->map_objs;
struct MapObj * mo_ptr;
{
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);
}
}
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);
+ }
+}
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 */
+/* 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);
+/* 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
#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() */
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);
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);
}
}
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++;
+ }
+}
+/* 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