From 258e57c1621533e206610453047d829cc8aa13fe Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Sat, 6 Dec 2014 06:34:32 +0100 Subject: [PATCH] Add "look" mode to query things on any cell via new THINGS_HERE command. --- SERVER_COMMANDS | 7 +- confclient/commands | 3 + confclient/interface_conf | 3 +- confclient/single_wins/info | 2 +- confclient/single_wins/inventory | 2 +- confclient/single_wins/log | 2 +- confclient/single_wins/map | 2 +- .../single_wins/{standing_on => things_here} | 2 +- src/client/cleanup.c | 2 +- src/client/control.c | 11 +- src/client/draw_wins.c | 55 ++++++---- src/client/io.c | 28 +++-- src/client/io.h | 8 +- src/client/main.c | 2 +- src/client/map.c | 100 +++++++++++++++++- src/client/map.h | 10 ++ src/client/world.h | 6 +- src/server/run.c | 32 +++--- 18 files changed, 203 insertions(+), 74 deletions(-) rename confclient/single_wins/{standing_on => things_here} (98%) diff --git a/SERVER_COMMANDS b/SERVER_COMMANDS index b9e3cd2..dba4b95 100644 --- a/SERVER_COMMANDS +++ b/SERVER_COMMANDS @@ -53,9 +53,10 @@ Write "PONG" line to ./server/out file. QUIT Shut down server. -STACK -Write line-by-line list of items the player stands on into ./server/out file, -enclosed by two lines "THINGS_BELOW_PLAYER START" and "THINGS_BELOW_PLAYER END". +THINGS_HERE [0 to 255] [0 to 255] +Write line-by-line list of items at y position of first argument, x position of +second argument into ./server/out file, enclosed by two lines "THINGS_HERE START" +and "THINGS_HERE END". Player commands --------------- diff --git a/confclient/commands b/confclient/commands index b8b9387..e64bdf5 100644 --- a/confclient/commands +++ b/confclient/commands @@ -187,3 +187,6 @@ DESCRIPTION 'window keybinding keys' COMMAND to_autofocus DESCRIPTION 'toggle auto-center' + +COMMAND to_look +DESCRIPTION 'toggle look mode' diff --git a/confclient/interface_conf b/confclient/interface_conf index d2b02e6..2cc3648 100644 --- a/confclient/interface_conf +++ b/confclient/interface_conf @@ -74,7 +74,7 @@ KEY 258 inv_d KEY 117 use WINDOW s -NAME 'Standing on' +NAME 'Things here' BREAK 1 WIDTH 14 HEIGHT -12 @@ -111,3 +111,4 @@ KEY 260 map_l KEY 261 map_r KEY 46 map_c KEY 70 to_autofocus +KEY 108 to_look diff --git a/confclient/single_wins/info b/confclient/single_wins/info index 4999883..78a63f9 100644 --- a/confclient/single_wins/info +++ b/confclient/single_wins/info @@ -92,7 +92,7 @@ KEY 258 inv_d KEY 117 use WINDOW s -NAME 'Standing on' +NAME 'Things here' BREAK 1 WIDTH 14 HEIGHT -12 diff --git a/confclient/single_wins/inventory b/confclient/single_wins/inventory index 067b27d..b831f50 100644 --- a/confclient/single_wins/inventory +++ b/confclient/single_wins/inventory @@ -84,7 +84,7 @@ KEY 259 keyb_uk KEY 10 keyb_mk WINDOW s -NAME 'Standing on' +NAME 'Things here' BREAK 1 WIDTH 14 HEIGHT -12 diff --git a/confclient/single_wins/log b/confclient/single_wins/log index 81eea84..40b9be4 100644 --- a/confclient/single_wins/log +++ b/confclient/single_wins/log @@ -92,7 +92,7 @@ KEY 258 inv_d KEY 117 use WINDOW s -NAME 'Standing on' +NAME 'Things here' BREAK 1 WIDTH 14 HEIGHT -12 diff --git a/confclient/single_wins/map b/confclient/single_wins/map index d9d6e38..56e7f34 100644 --- a/confclient/single_wins/map +++ b/confclient/single_wins/map @@ -96,7 +96,7 @@ KEY 258 inv_d KEY 117 use WINDOW s -NAME 'Standing on' +NAME 'Things here' BREAK 1 WIDTH 14 HEIGHT -12 diff --git a/confclient/single_wins/standing_on b/confclient/single_wins/things_here similarity index 98% rename from confclient/single_wins/standing_on rename to confclient/single_wins/things_here index 59ee7b4..ea87f9f 100644 --- a/confclient/single_wins/standing_on +++ b/confclient/single_wins/things_here @@ -87,7 +87,7 @@ KEY 258 inv_d KEY 117 use WINDOW s -NAME 'Standing on' +NAME 'Things here' BREAK 1 WIDTH 0 HEIGHT 0 diff --git a/src/client/cleanup.c b/src/client/cleanup.c index d889ae9..4db02a2 100644 --- a/src/client/cleanup.c +++ b/src/client/cleanup.c @@ -26,7 +26,7 @@ extern void cleanup() free(world.map.cells); free(world.mem_map); free(world.log); - free(world.things_below_player); + free(world.things_here); free(world.queue); free(world.player_inventory); if (cleanup_flags & CLEANUP_INTERFACE) diff --git a/src/client/control.c b/src/client/control.c index 5d90919..76d69ac 100644 --- a/src/client/control.c +++ b/src/client/control.c @@ -17,7 +17,9 @@ #include "keybindings.h" /* get_command_to_keycode(), get_keycode_to_command(), * mod_selected_keyb(), move_keyb_selection() */ -#include "map.h" /* map_scroll(), map_center(), toggle_autofocus() */ +#include "map.h" /* map_scroll(), map_center(), toggle_autofocus(), + * toggle_lookmode(), lookmode_nav() + */ #include "wincontrol.h" /* shift_active_win(), resize_active_win(), * toggle_win_size_type(), toggle_window(), * cycle_active_win(), scroll_v_screen(), @@ -166,6 +168,7 @@ static uint8_t try_client_commands(struct Command * command) || try_1args(command, "shift_b", shift_active_win, 'b') || try_0args(command, "reload_conf", reload_interface_conf) || try_0args(command, "save_conf", save_interface_conf) + || try_0args(command, "to_look", toggle_lookmode) || try_kb_manip(command->dsc_short)); } @@ -263,7 +266,7 @@ extern uint8_t try_key(uint16_t key) } if (command) { - if (try_server_commands(command)) + if (world.look && lookmode_nav(command->dsc_short)) { return 1; } @@ -271,6 +274,10 @@ extern uint8_t try_key(uint16_t key) { return 1; } + else if (try_server_commands(command)) + { + return 1; + } else if (!strcmp("quit", command->dsc_short)) { return 2; diff --git a/src/client/draw_wins.c b/src/client/draw_wins.c index 63fb8a0..594b707 100644 --- a/src/client/draw_wins.c +++ b/src/client/draw_wins.c @@ -65,6 +65,9 @@ static char * get_keyname_to_command(char * command_name); static char * winconf_geom_helper(struct Win * win, char axis, char * sep, char * newlines, char * value_prefix); +/* Draw map cell "c" into win "w" at position "y"/"x" with attribute "a". */ +static void draw_mapcell(struct Win * w, char c, uint8_t y, uint8_t x,attr_t a); + static void try_resize_winmap(struct Win * win, int new_size_y, int new_size_x) @@ -336,6 +339,17 @@ static char * winconf_geom_helper(struct Win * win, char axis, char * sep, +static void draw_mapcell(struct Win * w, char c, uint8_t y, uint8_t x, attr_t a) +{ + set_ch_on_yx(w, y, x * 2 + (y % 2), c | a); + if (x + (y % 2) < world.map.length) + { + set_ch_on_yx(w, y, x * 2 + (y % 2) + 1, ' ' | a); + } +} + + + extern void draw_win_log(struct Win * win) { if (!world.log) @@ -349,43 +363,40 @@ extern void draw_win_log(struct Win * win) extern void draw_win_map(struct Win * win) { + uint16_t x, y; init_pair(1, COLOR_WHITE, COLOR_BLUE); init_pair(2, COLOR_BLUE, COLOR_BLACK); - attr_t attr_fov = 0; attr_t attr_mem = COLOR_PAIR(2); attr_t attr_sha = COLOR_PAIR(1); try_resize_winmap(win, world.map.length, world.map.length * 2); - uint16_t x, y, z; - for (y = 0, z = 0; y < world.map.length; y++) + for (y = 0; y < world.map.length; y++) { for (x = 0; x < world.map.length; x++) { - attr_t attr_c = ' ' == world.mem_map[z] ? attr_sha : attr_mem; - chtype c = world.mem_map[z] | attr_c; - set_ch_on_yx(win, y, x * 2 + (y % 2), c); - if (x + (y % 2) < world.map.length) - { - set_ch_on_yx(win, y, x * 2 + (y % 2) + 1, ' ' | attr_c); - } - z++; + attr_t a=' '==world.mem_map[y*world.map.length+x]?attr_sha:attr_mem; + char c = world.mem_map[y*world.map.length + x]; + draw_mapcell(win, c, y, x, a); } } - for (y = 0, z = 0; y < world.map.length; y++) + for (y = 0; y < world.map.length; y++) { for (x = 0; x < world.map.length; x++) { - if (' ' != world.map.cells[z]) + if (' ' != world.map.cells[y*world.map.length + x]) { - chtype c = world.map.cells[z] | attr_fov; - set_ch_on_yx(win, y, x * 2 + (y % 2), c); - if (x + (y % 2) < world.map.length) - { - set_ch_on_yx(win, y, x * 2 + (y % 2) + 1, ' ' | attr_fov); - } + char c = world.map.cells[y*world.map.length + x]; + draw_mapcell(win, c, y, x, 0); } - z++; } } + if (world.look) + { + y = world.look_pos.y; + x = world.look_pos.x; + char c = world.map.cells[y * world.map.length + x]; + c = ' ' == c ? world.mem_map[y * world.map.length + x] : c; + draw_mapcell(win, c, y, x, A_REVERSE); + } } @@ -436,9 +447,9 @@ extern void draw_win_inventory(struct Win * win) extern void draw_win_terrain_stack(struct Win * win) { - if (world.things_below_player) + if (world.things_here) { - add_text_with_linebreaks(win, world.things_below_player); + add_text_with_linebreaks(win, world.things_here); } } diff --git a/src/client/io.c b/src/client/io.c index a46f91f..45a1de7 100644 --- a/src/client/io.c +++ b/src/client/io.c @@ -259,31 +259,31 @@ static void nl_append_string(char * append, char ** string) static uint8_t read_queue() { - static uint8_t things_below_player_parsing = 0; + static uint8_t things_here_parsing = 0; uint8_t ret = 0; char * msg; while (NULL != (msg = get_message_from_queue(&world.queue))) { char * log_prefix = "LOG "; - if (!strcmp(msg, "THINGS_BELOW_PLAYER START")) + if (!strcmp(msg, "THINGS_HERE START")) { ret = 1; - things_below_player_parsing = 1; - free(world.things_below_player); - world.things_below_player = NULL; + things_here_parsing = 1; + free(world.things_here); + world.things_here = NULL; } - else if (!strcmp(msg, "THINGS_BELOW_PLAYER END")) + else if (!strcmp(msg, "THINGS_HERE END")) { - things_below_player_parsing = 0; - if (!world.things_below_player) + things_here_parsing = 0; + if (!world.things_here) { - nl_append_string("(nothing)", &world.things_below_player); + nl_append_string("(none known)", &world.things_here); } } - else if (things_below_player_parsing) + else if (things_here_parsing) { ret = 1; - nl_append_string(msg, &world.things_below_player); + nl_append_string(msg, &world.things_here); } else if (!strncmp(msg, log_prefix, strlen(log_prefix))) { @@ -298,9 +298,7 @@ static uint8_t read_queue() } else if (!strcmp(msg, "WORLD_UPDATED")) { - free(world.things_below_player); - world.things_below_player = NULL; - send("STACK"); + query_mapcell(); } free(msg); } @@ -338,7 +336,7 @@ extern char * io_loop() } if (change_in_client || read_worldstate() || read_queue()) { - if (world.turn != last_focused_turn && world.focus_each_turn) + if (world.turn != last_focused_turn && world.autofocus) { last_focused_turn = world.turn; map_center(); diff --git a/src/client/io.h b/src/client/io.h index 36d04c6..041ed67 100644 --- a/src/client/io.h +++ b/src/client/io.h @@ -30,10 +30,10 @@ extern void send(char * msg); * appropriate quit message to write to stdout when the client winds down. Call * reset_windows() on receiving a SIGWINCH. Abort on assumed server death if the * server's out file does not get updated, even on PING requests. Re-focus map - * view on player if world.focus_each_turn is set. Messages from the out file - * are put together on the queue first, from which only complete (\n-delimited) - * messages are read. Queues of messages are worked through completely / emptied - * before any re-drawing or further server polling happens. + * view on player if world.autofocus is set. Messages from the out file are put + * together on the queue first, from which only complete (\n-delimited) messages + * are read. Queues of messages are worked through completely / emptied before + * any re-drawing or further server polling happens. */ extern char * io_loop(); diff --git a/src/client/main.c b/src/client/main.c index 2c1fbf4..acb592b 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -56,7 +56,7 @@ int main(int argc, char * argv[]) keypad(world.winDB.t_screen, TRUE); init_command_db(); /* The command DB needs to be initialized before */ load_interface_conf(); /* the interface, whose keybindings depend on it. */ - world.focus_each_turn = 1; + world.autofocus = 1; /* Set handler for terminal window resizing. */ struct sigaction act; diff --git a/src/client/map.c b/src/client/map.c index e08e7b3..75dd6de 100644 --- a/src/client/map.c +++ b/src/client/map.c @@ -7,6 +7,13 @@ #include "map.h" #include /* uint8_t */ +#include /* free() */ +#include /* sprintf() */ +#include /* strlen(), strncmp() */ +#include "../common/try_malloc.h" /* try_malloc() */ +#include "../common/rexit.h" /* exit_trouble() */ +#include "../common/yx_uint8.h" /* yx_uint8 */ +#include "io.h" /* send() */ #include "windows.h" /* struct Win, center_offset(), get_win_by_id() */ #include "world.h" /* for global world */ @@ -14,7 +21,7 @@ extern void map_scroll(char d) { - world.focus_each_turn = 0; + world.autofocus = 0; struct Win * win = get_win_by_id('m'); uint16_t offset; if (('8' == d || '2' == d) && world.map.length > win->frame_size.y) @@ -48,13 +55,98 @@ extern void map_scroll(char d) extern void map_center() { struct Win * win_map = get_win_by_id('m'); - win_map->center.y = world.player_pos.y; - win_map->center.x = world.player_pos.x * 2 + (world.player_pos.y % 2); + struct yx_uint8 pos = world.look ? world.look_pos : world.player_pos; + win_map->center.y = pos.y; + win_map->center.x = pos.x * 2 + (pos.y % 2); } extern void toggle_autofocus() { - world.focus_each_turn = world.focus_each_turn ? 0 : 1; + world.autofocus = world.autofocus ? 0 : 1; +} + + + +extern void toggle_lookmode() +{ + if (!world.look) + { + world.look_pos = world.player_pos; + world.look = 1; + } + else + { + world.look = 0; + } + query_mapcell(); +} + + + +extern uint8_t lookmode_nav(char * command) +{ + char * prefix = "move_"; + uint8_t len_pref = strlen(prefix); + if (!strncmp(prefix, command, len_pref) && strlen(command) - 1 == len_pref) + { + uint8_t open_north = world.look_pos.y > 0; + uint8_t open_south = world.look_pos.y < world.map.length - 1; + uint8_t open_west = world.look_pos.x > 0; + uint8_t open_east = world.look_pos.x < world.map.length - 1; + uint8_t indent = world.look_pos.y % 2; + if ('s' == command[len_pref]) + { + world.look_pos.x = world.look_pos.x - open_west; + } + else if ('d' == command[len_pref]) + { + world.look_pos.x = world.look_pos.x + open_east; + } + else if ('w' == command[len_pref]) + { + world.look_pos.y = world.look_pos.y - open_north; + world.look_pos.x = world.look_pos.x - !indent * open_west; + } + else if ('e' == command[len_pref]) + { + world.look_pos.y = world.look_pos.y - open_north; + world.look_pos.x = world.look_pos.x + indent * open_east; + } + else if ('x' == command[len_pref]) + { + world.look_pos.y = world.look_pos.y + open_south; + world.look_pos.x = world.look_pos.x - !indent * open_west; + } + else if ('c' == command[len_pref]) + { + world.look_pos.y = world.look_pos.y + open_south; + world.look_pos.x = world.look_pos.x + indent * open_east; + } + else + { + return 0; + } + map_center(); + query_mapcell(); + return 1; + } + return 0; +} + + + +extern void query_mapcell() +{ + free(world.things_here); + world.things_here = NULL; + char * stack = "THINGS_HERE"; + char * stack_query = try_malloc(strlen(stack) +1+3 +1+3 +1, __func__); + uint8_t y = world.look ? world.look_pos.y : world.player_pos.y; + uint8_t x = world.look ? world.look_pos.x : world.player_pos.x; + int test = sprintf(stack_query, "%s %d %d", stack, y, x); + exit_trouble(test < 0, __func__, "sprintf"); + send(stack_query); + free(stack_query); } diff --git a/src/client/map.h b/src/client/map.h index bd919d8..4b1eb8d 100644 --- a/src/client/map.h +++ b/src/client/map.h @@ -10,6 +10,7 @@ #ifndef MAP_H_CLIENT #define MAP_H_CLIENT +#include /* uint8_t */ /* Try changing map window's focus into direction "d" (north = "N" etc.). Unset @@ -23,6 +24,15 @@ extern void map_center(); /* Toggle world.focus_each_turn (auto-centering of map on player each turn). */ extern void toggle_autofocus(); +/* Toggle world.look (moving look cursor instead of player over map). */ +extern void toggle_lookmode(); + +/* Read "command" as look cursor move command, act on it.*/ +extern uint8_t lookmode_nav(char * command); + +/* Send THINGS_HERE query message to server.*/ +extern void query_mapcell(); + #endif diff --git a/src/client/world.h b/src/client/world.h index e907922..19497d2 100644 --- a/src/client/world.h +++ b/src/client/world.h @@ -33,19 +33,21 @@ struct World struct Map map; /* game map geometry and content of player's map view */ time_t last_update; /* used for comparison with worldstate file's mtime */ char * log; /* log of player's activities */ - char * things_below_player; /* list of things below the player */ + char * things_here; /* list of things below the player */ char * path_interface; /* path of interface configuration file */ char * path_commands; /* path of commands config file */ char * player_inventory; /* one-item-per-line string list of owned items */ char * mem_map; /* map cells of player's map memory */ char * queue; /* stores un-processed messages read from the input file */ struct yx_uint8 player_pos; /* coordinates of player on map */ + struct yx_uint8 look_pos; /* coordinates of look cursor */ uint16_t turn; /* world/game turn */ uint8_t halfdelay; /* how long to wait for getch() input in io_loop() */ uint8_t player_inventory_select; /* index of selected item in inventory */ uint8_t player_lifepoints; /* how alive the player is */ uint8_t winch; /* if set, SIGWINCH was registered; trigger reset_windows()*/ - uint8_t focus_each_turn; /* if !0, re-focus map on player each new turn */ + uint8_t autofocus; /* if !0, re-focus map each new turn / look focus move */ + uint8_t look; /* if set, move look cursor over map intead of player */ }; diff --git a/src/server/run.c b/src/server/run.c index a1bf343..339a849 100644 --- a/src/server/run.c +++ b/src/server/run.c @@ -10,12 +10,13 @@ #include /* NULL */ #include /* uint8_t, uint16_t, uint32_t, int16_t */ #include /* FILE, printf(), fflush() */ -#include /* free() */ +#include /* atoi(), free() */ #include /* strlen(), strcmp(), strncmp(), strdup() */ #include /* time_t, time() */ #include /* access() */ #include "../common/parse_file.h" /* set_err_line_options(), token_from_line(), - * err_line(), err_line_inc(), parse_val() + * err_line(), err_line_inc(), parse_val(), + * parestest_int() */ #include "../common/readwrite.h" /* try_fopen(), try_fcose(), try_fwrite(), * try_fgets(), textfile_width(), try_fputc(), @@ -207,23 +208,26 @@ static uint8_t parse_command_meta(char * tok0) send_to_outfile("PONG\n", 1); return 1; } - if (!strcmp("STACK", tok0)) + if (!strcmp("THINGS_HERE", tok0)) { - send_to_outfile("THINGS_BELOW_PLAYER START\n", 1); - struct Thing * player = get_player(); - struct Thing * t; - for (t = world.things; t; t = t->next) + char * tok1 = token_from_line(NULL); + char * tok2 = token_from_line(NULL); + if (!parsetest_int(tok1, '8') && !parsetest_int(tok2, '8')) { - if ( t->pos.y == player->pos.y && t->pos.x == player->pos.x - && t != player) + send_to_outfile("THINGS_HERE START\n", 1); + struct Thing * t; + for (t = world.things; t; t = t->next) { - struct ThingType * tt = get_thing_type(t->type); - send_to_outfile(tt->name, 0); - send_to_outfile("\n", 1); + if (t->pos.y == atoi(tok1) && t->pos.x == atoi(tok2)) + { + struct ThingType * tt = get_thing_type(t->type); + send_to_outfile(tt->name, 0); + send_to_outfile("\n", 1); + } } + send_to_outfile("THINGS_HERE END\n", 1); + return 1; } - send_to_outfile("THINGS_BELOW_PLAYER END\n", 1); - return 1; } return 0; } -- 2.30.2