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
---------------
COMMAND to_autofocus
DESCRIPTION 'toggle auto-center'
+
+COMMAND to_look
+DESCRIPTION 'toggle look mode'
KEY 117 use
WINDOW s
-NAME 'Standing on'
+NAME 'Things here'
BREAK 1
WIDTH 14
HEIGHT -12
KEY 261 map_r
KEY 46 map_c
KEY 70 to_autofocus
+KEY 108 to_look
KEY 117 use
WINDOW s
-NAME 'Standing on'
+NAME 'Things here'
BREAK 1
WIDTH 14
HEIGHT -12
KEY 10 keyb_mk
WINDOW s
-NAME 'Standing on'
+NAME 'Things here'
BREAK 1
WIDTH 14
HEIGHT -12
KEY 117 use
WINDOW s
-NAME 'Standing on'
+NAME 'Things here'
BREAK 1
WIDTH 14
HEIGHT -12
KEY 117 use
WINDOW s
-NAME 'Standing on'
+NAME 'Things here'
BREAK 1
WIDTH 14
HEIGHT -12
+++ /dev/null
-
-KEYBINDINGS 'global'
-KEY 81 quit
-KEY 265 to_mapwin
-KEY 266 to_infowin
-KEY 267 to_inv
-KEY 268 to_terrain
-KEY 269 to_logwin
-KEY 270 to_g_keywin
-KEY 271 to_wg_keywin
-KEY 272 to_wk_keywin
-KEY 87 winconf
-KEY 62 cyc_win_f
-KEY 60 cyc_win_b
-KEY 262 scrl_l
-KEY 360 scrl_r
-KEY 82 reload_conf
-KEY 67 save_conf
-KEY 97 ai
-KEY 112 pick
-KEY 58 wait
-KEY 101 move_e
-KEY 100 move_d
-KEY 99 move_c
-KEY 120 move_x
-KEY 115 move_s
-KEY 119 move_w
-KEY 46 map_c
-KEY 68 drop
-KEY 117 use
-KEY 70 to_autofocus
-
-KEYBINDINGS 'wingeom'
-KEY 258 shift_f
-KEY 259 shift_b
-KEY 42 grow_h
-KEY 95 shri_h
-KEY 43 grow_v
-KEY 45 shri_v
-KEY 98 to_break
-KEY 121 to_height_t
-KEY 120 to_width_t
-
-KEYBINDINGS 'winkeys'
-KEY 258 keyb_dw
-KEY 259 keyb_uw
-KEY 10 keyb_mw
-
-WIN_ORDER 's'
-WIN_FOCUS 's'
-
-WINDOW 0
-NAME 'Set global keys'
-BREAK 0
-WIDTH 22
-HEIGHT 7
-KEY 258 keyb_dG
-KEY 259 keyb_uG
-KEY 10 keyb_mG
-
-WINDOW 1
-NAME 'Set window geometry keys'
-BREAK 0
-WIDTH 29
-HEIGHT 9
-KEY 258 keyb_dg
-KEY 259 keyb_ug
-KEY 10 keyb_mg
-
-WINDOW 2
-NAME 'Set window keybinding keys'
-BREAK 0
-WIDTH 29
-HEIGHT 3
-KEY 258 keyb_dk
-KEY 259 keyb_uk
-KEY 10 keyb_mk
-
-WINDOW c
-NAME 'Inventory'
-BREAK 1
-WIDTH 14
-HEIGHT 11
-KEY 68 drop
-KEY 259 inv_u
-KEY 258 inv_d
-KEY 117 use
-
-WINDOW s
-NAME 'Standing on'
-BREAK 1
-WIDTH 0
-HEIGHT 0
-
-WINDOW i
-NAME 'Info'
-BREAK 2
-WIDTH -38
-HEIGHT 1
-
-WINDOW l
-NAME 'Log'
-BREAK 0
-WIDTH 22
-HEIGHT -8
-
-WINDOW m
-NAME 'Map'
-BREAK 0
-WIDTH -38
-HEIGHT -2
-KEY 97 ai
-KEY 112 pick
-KEY 58 wait
-KEY 101 move_e
-KEY 100 move_d
-KEY 99 move_c
-KEY 120 move_x
-KEY 115 move_s
-KEY 119 move_w
-KEY 259 map_u
-KEY 258 map_d
-KEY 260 map_l
-KEY 261 map_r
-KEY 46 map_c
-KEY 70 to_autofocus
--- /dev/null
+
+KEYBINDINGS 'global'
+KEY 81 quit
+KEY 265 to_mapwin
+KEY 266 to_infowin
+KEY 267 to_inv
+KEY 268 to_terrain
+KEY 269 to_logwin
+KEY 270 to_g_keywin
+KEY 271 to_wg_keywin
+KEY 272 to_wk_keywin
+KEY 87 winconf
+KEY 62 cyc_win_f
+KEY 60 cyc_win_b
+KEY 262 scrl_l
+KEY 360 scrl_r
+KEY 82 reload_conf
+KEY 67 save_conf
+KEY 97 ai
+KEY 112 pick
+KEY 58 wait
+KEY 101 move_e
+KEY 100 move_d
+KEY 99 move_c
+KEY 120 move_x
+KEY 115 move_s
+KEY 119 move_w
+KEY 46 map_c
+KEY 68 drop
+KEY 117 use
+KEY 70 to_autofocus
+
+KEYBINDINGS 'wingeom'
+KEY 258 shift_f
+KEY 259 shift_b
+KEY 42 grow_h
+KEY 95 shri_h
+KEY 43 grow_v
+KEY 45 shri_v
+KEY 98 to_break
+KEY 121 to_height_t
+KEY 120 to_width_t
+
+KEYBINDINGS 'winkeys'
+KEY 258 keyb_dw
+KEY 259 keyb_uw
+KEY 10 keyb_mw
+
+WIN_ORDER 's'
+WIN_FOCUS 's'
+
+WINDOW 0
+NAME 'Set global keys'
+BREAK 0
+WIDTH 22
+HEIGHT 7
+KEY 258 keyb_dG
+KEY 259 keyb_uG
+KEY 10 keyb_mG
+
+WINDOW 1
+NAME 'Set window geometry keys'
+BREAK 0
+WIDTH 29
+HEIGHT 9
+KEY 258 keyb_dg
+KEY 259 keyb_ug
+KEY 10 keyb_mg
+
+WINDOW 2
+NAME 'Set window keybinding keys'
+BREAK 0
+WIDTH 29
+HEIGHT 3
+KEY 258 keyb_dk
+KEY 259 keyb_uk
+KEY 10 keyb_mk
+
+WINDOW c
+NAME 'Inventory'
+BREAK 1
+WIDTH 14
+HEIGHT 11
+KEY 68 drop
+KEY 259 inv_u
+KEY 258 inv_d
+KEY 117 use
+
+WINDOW s
+NAME 'Things here'
+BREAK 1
+WIDTH 0
+HEIGHT 0
+
+WINDOW i
+NAME 'Info'
+BREAK 2
+WIDTH -38
+HEIGHT 1
+
+WINDOW l
+NAME 'Log'
+BREAK 0
+WIDTH 22
+HEIGHT -8
+
+WINDOW m
+NAME 'Map'
+BREAK 0
+WIDTH -38
+HEIGHT -2
+KEY 97 ai
+KEY 112 pick
+KEY 58 wait
+KEY 101 move_e
+KEY 100 move_d
+KEY 99 move_c
+KEY 120 move_x
+KEY 115 move_s
+KEY 119 move_w
+KEY 259 map_u
+KEY 258 map_d
+KEY 260 map_l
+KEY 261 map_r
+KEY 46 map_c
+KEY 70 to_autofocus
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)
#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(),
|| 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));
}
}
if (command)
{
- if (try_server_commands(command))
+ if (world.look && lookmode_nav(command->dsc_short))
{
return 1;
}
{
return 1;
}
+ else if (try_server_commands(command))
+ {
+ return 1;
+ }
else if (!strcmp("quit", command->dsc_short))
{
return 2;
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)
+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)
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);
+ }
}
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);
}
}
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)))
{
}
else if (!strcmp(msg, "WORLD_UPDATED"))
{
- free(world.things_below_player);
- world.things_below_player = NULL;
- send("STACK");
+ query_mapcell();
}
free(msg);
}
}
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();
* 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();
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;
#include "map.h"
#include <stdint.h> /* uint8_t */
+#include <stdlib.h> /* free() */
+#include <stdio.h> /* sprintf() */
+#include <string.h> /* 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 */
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)
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);
}
#ifndef MAP_H_CLIENT
#define MAP_H_CLIENT
+#include <stdint.h> /* uint8_t */
/* Try changing map window's focus into direction "d" (north = "N" etc.). Unset
/* 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
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 */
};
#include <stddef.h> /* NULL */
#include <stdint.h> /* uint8_t, uint16_t, uint32_t, int16_t */
#include <stdio.h> /* FILE, printf(), fflush() */
-#include <stdlib.h> /* free() */
+#include <stdlib.h> /* atoi(), free() */
#include <string.h> /* strlen(), strcmp(), strncmp(), strdup() */
#include <time.h> /* time_t, time() */
#include <unistd.h> /* 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(),
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;
}