# NetHack 4 Network Protocol
This is a description of the NetHack 4 networking protocol.
Note: This page tends to get out of date quickly. A much more up-to-date version can be found here.
The protocol is based on JSON. Each client command and each server response is a single, valid JSON object in UTF8 encoding.

Contents

1 Basics
2 Interaction
3 Client commands

3.1 auth
3.2 register
3.3 describe_pos
3.4 exit_game
3.5 get_commands
3.6 get_obj_commands
3.7 get_drawing_info
3.8 get_options
3.9 set_option
3.10 get_roles
3.11 get_topten
3.12 list_games
3.13 create_game
3.14 play_game
3.15 set_email
3.16 set_password
3.17 shutdown

4 Server requests

4.1 server_cancel
4.2 request_command
4.3 display_menu
4.4 display_objects
4.5 getdir
4.6 getline
4.7 getpos
4.8 query_key
4.9 yn
4.10 load_progress
4.11 server_error

5 Display elements

5.1 delay_output
5.2 display_buffer
5.3 level_changed
5.4 list_items
5.5 outrip
5.6 pause
5.7 print_message
5.8 print_message_nonblocking
5.9 raw_print
5.10 update_screen
5.11 update_status

Basics
The protocol is based on JSON.  Each command and each response is a single,
valid JSON object in UTF8 encoding. The server will insert a NUL character
between each command it sends, to allow clients to easily determine where one
ends and the next starts (NUL cannot appear in a JSON encoding). The client
does not currently insert such NULs. (TODO: It probably should, and the server
should probably respect them, in case the client needs to send `exit_game`
immediately after another command, without waiting for a response in between.)
The server protocol is an enhancement of the protocol used by a window port to
connect to a local game; the two are very similar, and so this documentation
may also be consulted to gain some amount of understanding of the behaviour of
a windowport.  There are a few commands that are specific to server use,
though, such as `auth`, and the API for map updates is different.  For a full
explanation of the various protocols in use, see `doc/mainloop.txt`.
The following types are all special cases of integers:

All enumerated types
bitflags
boolean
charcode
connid
coordinate
gameid

Interaction
Once the client has connected to the server, it must send either an `auth` or
a `register` command.  If the client sends a successful `register` command, a
following `auth` command is not necessary.  When the client is authenticated
any other command may be sent to the server.
Normal flow is driven by the client and/or server sending commands and
receiving responses to them; a command can be sent from the client to the
server, or (more rarely) the other way round.  (Server commands are sent if
the server needs more information to fulfil a client command, or to inform the
client of unusual conditions, such as a retroactive cancel of a command in
progress.)  Server commands and responses can also carry an attached `display`
element with map updates (see later in this document).
In general, a command might be sent/received by the client and/or server at
any point after the authentication.  It is thus incorrect for a client to
block on user input, because it might have to handle a server command that
arrives unexpectedly.
It is also incorrect to block on the response to a command, because a command
might be followed up by another command rather than a response.  It is
acceptable, however, for the client to ignore user input after sending a
command, until either a command or a response is received; whenever a command
is sent, the client can assume that the server will react to it in some way,
either via responding or via sending a followup command.
70	Commands and responses are always well-nested; if a response is sent, it will
be to the most recent unresponded command sent by the other end of the
connection.  Additionally, messages usually alternate between client and
server.  Currently, the only exception to this is the `cancel_server_request`
command that the server uses to countermand a server request; it can be sent
by the server even if the previous message was also sent by the server.

Client commands
These commands are sent by the client, expecting a response from the server.

auth
Either `auth` or `register` must always be the first command sent, and no
other commands may be sent until the original `auth` or `register` command
receives a response.
This command is specific to client/server communication, and is not used for
local play.  It specifies which user is making the connection.
Upon creating a new connection, there will be no game loaded: `play_game` will
need to be used before commands that require a game to be loaded will work
(and those commands can only be given to follow up server requests that follow
up the `play_game` call).
Command arguments:

`string username`: the username of the user who is making the connection
`string password`: the password of the user who is making the connection
Response arguments:

`enum authresult return`: whether the connection succeeded:
[`NO_CONNECTION` = 0: not sent by the server, simulated by the client
library if the connection fails]

`AUTH_FAILED_UNKNOWN_USER` = 1: the given user does not exist
`AUTH_FAILED_BAD_PASSWORD` = 2: the given password is wrong
`AUTH_SUCCESS_NEW` = 3: a new connection was created
`int[3] version`: the version number of the server
[0] The major version number (if it's not 4, this document is probably
inaccurate)

[1] The minor version number (changes when save compatibility breaks)
[2] The patchlevel version number (changes when a release is made that
does not break save compatibility)
TODO: What happens if this command is sent when a connection already exists?

register
Like `auth`, except it requires a nonexistent rather than existing username,
and will create an account.  This cannot re-establish an existing connection,
for obvious reasons.
Command arguments:

`string username`: the username for the new account
`string password`: the password to register the account with
`string email`: (optional) an email address to store in the database; the
server admin can use this for password reset requests, etc.
Response arguments: same as `auth`, except `AUTH_FAILED_UNKNOWN_USER` means
that the user account already exists.

describe_pos
Returns farlook information for a given map square.  This command may only be
meaningfully sent while a game is running, and corresponds to the
`nh_describe_pos` API call in libnethack.  If the game is not running, all
string values in the response will be the null string, `objcount` will be -1,
and `in` will be false.
Command arguments:

`boolean is_in`: Whether to return the `in` element in the response
`coordinate x`: x coordinate of the map square to farlook
`coordinate y`: y coordinate of the map square to farlook
Response arguments:

`string bgdesc`: a description of the background
`boolean feature_described`: true if `bgdesc` is redundant to other fields
`string effectdesc`: a description of an effect
`boolean in`: true if an object is "in" rather than "on" the background
`string invisdesc`: a description of a remembered invisible monster
`string mondesc`: a description of a monster
`int objcount`: the number of object stacks on the square
`string objdesc`: a description of an object
`string trapdesc`: a description of a trap
Strings in the response are zero-length if they would describe something that
does not exist on the map square given by (x,y) (or that the character is
unaware of), e.g. `trapdesc` for a square with no known trap.  Otherwise, they
describe the map square given by (x,y).

exit_game
Causes the game to stop running, either via saving/suspending it, or via
quitting it.  `EXIT_SAVE` is equivalent to just dropping the connection in
terms of its user-visible effect, but is kinder on server resources than
dropping the connection would be.  This command can be sent if there is no
running game, but does nothing but return true in that situation.  It
corresponds to the `nh_exit_game` API call in libnethack.
178	If the game is running, this API call will typically return via `play_game`
response (see the documentation for `play_game`) rather than directly
(especially if it needs to get out of multiple nested contexts; it can be sent
at any time while the game is running and there is some server request pending
that the client could respond to).  Obviously, it must return directly if
there is no game running.
Command arguments:

`enum nh_exit_types exit_type`: what sort of exit to perform
`EXIT_SAVE` = 0: detach from the game and drop the connection; the
save file remains intact

`EXIT_QUIT` = 1: delete the game's save file and enter the game over
sequence

`EXIT_PANIC` = 2: like `EXIT_SAVE`, but record that there was a
problem in the panic log

`EXIT_RESTART` = 3: like `EXIT_SAVE`, but the client will be told to
immediately reload the game (`CLIENT_RESTART`); clients use this to
change between play, watch and replay modes
Response arguments:

`boolean return`: true if the game exited (whether due to a save, to a
quit, or to the process being panicked), or if no game was running; false
if the user cancelled the exit; true is rarely going to be observable
except in error conditions or if no game is running.

get_commands
This command lists which commands exist and can be used in a `request_command`
response, and corresponds to the `nh_get_commands` API call in libnethack.
In addition to information about the commands, it also returns default
keybindings for them; clients can choose to respect or ignore these.  This
means that minor changes to the game's commands can be made without needing to
alter clients.
This command can be used even when the game is not running; whether there is a
running game or not, it will return all commands that can be used by the user,
including debug mode commands. The client may want to hide debug mode commands
from non-debug-mode games.
Command arguments: none
Response arguments:

`struct nh_cmd_desc[] cmdlist`: a list of the commands that exist:
`string name`: the name of the command (`command` in
`request_command`);

`string desc`: a human-readable description of the command;
`unsigned flags`: information about the command, a bitmask of:
`CMD_ARG_DIR` = 1: the command can accept a direction argument;
`CMD_ARG_POS` = 2: the command can accept a position argument;
`CMD_ARG_OBJ` = 4: the command can accept an inventory object
argument;

`CMD_ARG_STR` = 8: the command can accept a string argument;
`CMD_ARG_SPELL` = 16: the command can accept a spell argument;
`CMD_ARG_LIMIT` = 32: the command can accept a numeric argument
that specifies a reduced maximum for things like multishot or item
stack size;

`CMD_EXT` = 1024: it is recommended that by default, this command
should be available as an extended command (via `#`);

`CMD_MOVE` = 2048: this is a movement command (and thus it is not
unreasonable to be able to keybind to individual direction
arguments to this command);

`CMD_HELP` = 4096: it is recommended that by default, this command
should be available via the help menu on `?`;

`CMD_NOTIME` = 8192: this command makes no changes to the
gamestate, and thus can be used while watching or replaying a
game;

`CMD_DEBUG` = 16384: this command is only available in debug mode;
`CMD_INTERNAL` = 32768: although commands with this flag set exist,
they are never returned from `nh_get_commands`.

`charcode def`: a default keybinding for this command (ASCII,
control-ASCII, meta-ASCII);

`charcode alt`: another, lower-priority, default keybinding for this
command

get_obj_commands
Requests a list of reasonable commands for use with a specified inventory
item.  (TODO: This is missing a check on whether the game is running.)  This
command is intended for use in response to an item being selected from the
inventory menu, itemactions-style; it will give more specific explanations of
what the commands do than `get_commands` does, because it is specialised to
one object.
Command arguments:

`charcode invlet`: The inventory letter of the item to get commands for.
Response arguments: the same as `get_commands`.
Note that unlike `get_commands`, which can recommend control- or meta-modified
keys for its keybindings, `get_obj_commands` favours capital and lowercase
letters only, so that its keybindings can easily be placed in a menu.  This
means that the recommended keybindings may not be identical to those produced
via `get_commands`.

get_drawing_info
Requests information about what drawable entities exist in the game: most code
that communicates display information will return indexes into lists, and this
function returns those lists.  It contains both API names, and default ASCII
representations (these need to be available to the server anyway so that it
can produce dumplogs, so it may as well communicate these to the client in
case it wants to use them).  It is reasonable to call this even when the game
is not running.  This command corresponds to the `nh_get_drawing_info` API
call in libnethack.
TODO: Sending an array and its length separately over JSON is always a bad
idea; what if they don't match? There's currently a `int num_*` for each
`struct nh_symdef[]` in the response arguments, but I removed the
documentation for them in preparation for fixing this rather major issue.
Command arguments: none
Response arguments:

`int feature_offset`:
`struct nh_symdef[] bgelements`: Backgrounds.
`struct nh_symdef[] effects`: Effects.
`struct nh_symdef[] explsyms`: Explosion shape/locations.
`struct nh_symdef[] expltypes`: Explosion appearances.
`struct nh_symdef[] invis`: Memory of invisible monsters.
`struct nh_symdef[] monsters`: Monsters.
`struct nh_symdef[] objects`: Items.
`struct nh_symdef[] swallowsyms`: The inside of an engulfing monster.
`struct nh_symdef[] traps`: Traps.
`struct nh_symdef[] warnings`: Warning symbols.
`struct nh_symdef[] zapsyms`: Zap shape/locations.
`struct nh_symdef[] zaptypes`: Zap appearances.
where `struct nh_symdef[]` is defined as follows (and sent as an array, with
its fields in this order):

`string name`: The API name of a drawable entity.  Explosions and zaps
have two API names; one for the shape and location within the shape (the
`*syms` list), one for the appearance (the `*types` list).  Other drawable
entities have just the one API name.  Clients should feel free to hardcode
overrides for specific API names.  (Note that an API name is not always
the same as a tile name; use the functions in tilesequence.c if you need
to convert, e.g. to discover a tile number for a given API name.)

`charcode character`: A recommended ASCII representation of this drawable
entity.  Clients can use this as a fallback if they encounter an
unrecognised API name.

`colourcode colour`: A recommended color for this drawable entity.
When using the recommended ASCII representations, for explosions and zaps
(which have two API names), the character should be taken from the
shape/location field, and the color from the appearance field.

get_options
Currently under revision.  TODO: When we decide what the API call actually
does, document it properly.
Command arguments:

`enum nh_option_list list`: what sort of options to list
(values, semantics under revision)
Response arguments:

`struct nh_option_desc[] options`:
`string name`: short name of the option
`string helptxt`: long desription of the option
`enum nh_opttype type`: what type of values the option takes:
`OPTTYPE_BOOL` = 0: booleans;
`OPTTYPE_INT` = 1: integers;
`OPTTYPE_ENUM` = 2: a fixed list of possibilities;
`OPTTYPE_STRING` = 3: strings;
`OPTTYPE_AUTOPICKUP_RULES` = 4: lists of autopickup rules
`union nh_optvalue value`: the value (or default value? under revision)
of the option

`union _ desc`: the legal values for the option:
`nil` for `OPTTYPE_BOOL`;
`struct {int min, int max}` for `OPTTYPE_INT`;
list of strings for `OPTTYPE_ENUM`;
an integer for strings (reflecting the maximum length);
list of strings for autopickup rules (TODO: figure out what format
these are in)
An autopickup rule has the following structure:

`enum autopickup action`: what action to take upon encountering this item:
`AP_GRAB` = 0: pick it up regardless of `pickup_types`;
`AP_LEAVE` = 1: leave it on the ground regardless of `pickup_types`.
`enum nh_bucstatus buc`: a filter against beatitude:
`B_UNKNOWN` = 0: match only items with unknown beatitude;
`B_BLESSED` = 1: match only blessed items;
`B_UNCURSED` = 2: match only non-blessed non-cursed items;
`B_CURSED` = 3: match only cursed items;
`B_DONT_CARE` = 4: do not filter items based on beatitude
`int oclass`: an object class of items to match
`string pattern`: a regular expression that matches items

set_option
Changes a (non-interface) option on the server.  This corresponds to the
`nh_set_option` API call in libnethack.  TODO: This command should only be
runnable if a followup to `request_command` is legal, except possibly for
setting birth options; this needs more thought.
Command arguments:

`boolean isstr`: if true, allows sending the option value as a string
regardless of the option's actual type (the server will parse it into an
appropriate value for the option); if false, the client has already parsed
the option

`string name`: the name of the option to set
`union nh_optvalue value`: the value for the option, in a format depending
on the option's type and whether `isstr` is set (a string, integer, or
list of autopickup rules).
Response arguments:

`struct nh_option_desc option`: TODO: work out if we need this and what
its semantics are

`int return`: an integer treated as a boolean; nonzero if the option value
given was reasonable, zero if it was unreasonable (and thus the server did
not try to set it)

get_roles
Requests information on what roles, races, genders, and alignments exist in
the game, and what combinations of them are legal.  This command corresponds to
the `nh_get_roles` API call in libnethack.
TODO: This API is inherently prone to buffer length mismatches.  There should
not be separate `num_` fields.
Command arguments: none
Response arguments:

`string[] alignnames`: the list of alignments that exist
`string[] gendnames`: the list of genders that exist
`string[] racenames`: the list of races that exist
`string[] rolenames_f`: the list of roles that exist, using female names
such as "Cavewoman" (TODO: if a role has no separate female name, are
these a copy of the male name, or NULL?)

`string[] rolenames_m`: the list of roles that exit, using male names such
as "Caveman"

`int[] matrix`: Information on which combinations of role, race, gender,
and alignment are legal; each possible combination (legal or illegal) has
an entry in the list, at an index that can be calculated via the macro
`nh_cm_idx()`

`int num_aligns`: length of `alignnames`
`int num_genders`: length of `gendnames`
`int num_races`: length of `racenames`
`int num_roles`: length of `rolenames_[f,m]`

get_topten
Requests entries from the high score table.
Command arguments:

`int around`: if there has been at least one game previously on this
connection (even if it was re-established), and the most recent such game
has since reached game over (death/quit/escape/ascension), and `player`
was playing, list this many games near that game on the high score table;
otherwise this value is ignored

`boolean own`: whether to list all games of the given `player` name or not
`string player`: the player name for `own` and `around`; a null string
will automatically pick the appropriate player for the most recent game
for use with `around`

`int top`: list this many games at the top of the table
Response arguments:

`string msg`: an appropriate heading for the high score table; if `around`
matches, this will talk about the most recent game (e.g. telling the
player what position on the list they are, or explaining that wizard mode
games are not eligible for the high score table); otherwise, this will be
an error message (if any), or else the null string

`struct nh_topten_entry[] toplist`: the requested high score table
`int birthdate`: seconds since the epoch that the game started (TODO:
Y2038 issue!)

`string death`: the reason that the player died
`int deathdate`: seconds since the epoch that the game ended
`int deaths`: the number of times the player lifesaved, plus one if they
eventually died permanently

`int end_how`: an internal code for the basic cause of death (drowning,
starving, etc.); this is currently not in any publicly accessible header
(TODO: which is probably a mistake), but is in libnethack's hack.h

`string entrytxt`: a formatted representation of this high score entry
that can be output directly in a fixed-width font

`boolean highlight`: true if this entry is the one that `around` is
measuring around

`int hp`: the character's current hitpoints at death
`int maxhp`: the character's maximum hitpoints at death
`int maxlvl`: the deepest dungeon level the character reached
`int moves`: the number of turns the charater spent
`string name`: the name of the character
`string plalign`: the character's alignment
`string plgend`: the character's gender
`string plrace`: the character's race
`string plrole`: the character's role
`int points`: the number of points the game scored
`int rank`: the position of this game within the high score table (1 for
first place, 2 for second place, etc.); can be 0 or negative for games
that are disqualified from the high score table (due to, for instance,
playing in debug mode)

`int ver_major`: the major version number of the engine this game was
played on

`int ver_minor`: the minor version number of the engine this game was
played on

`int patchlevel`: the patchlevel version number of the engine this game
was played on

list_games
Lists current and/or completed games on the server.
TODO: what format are plgend, etc., in? Abbreviation? Full name?
Command arguments:

`boolean completed`: list only completed games if true, only current games
if false

`int limit`: the maximum number of games to list
`boolean show_all`: if true, list games for which user who authenticated
this connection has read but not write access; if false, only list games
to which the user has write access
Response arguments:

`struct nhnet_game[] games`: the information about the games selected by
the arguments:

`int gameid`: a value that can be given to `play_game` to connect to
this game

`enum nh_game_modes playmode`: any special rules that might apply to
this game:

`MODE_NORMAL` = 0: there is nothing special about this game;
`MODE_EXPLORE` = 1: this game is in non-scoring discovery mode;
`MODE_WIZARD` = 2: this game is in debug mode.
`string plname`: the name of this game's player
`string game_status`: a textual description of the current state of
the game (death reason for a completed game, location of the character
in the dungeon for an incomplete game)

`string plalign`: the alignment of this game's character
`string plgend`: the gender of this game's character
`string plrace`: the race of this game's character
`string plrole`: the role of this game's character
`enum nh_log_status status`: the status of this game's save file:
`LS_SAVED` = 0: an ordinary save file, nobody playing/replaying
`LS_DONE` = 1: game over: quit, died, ascended, etc.
`LS_IN_PROGRESS` = 2: someone is playing/watching/replaying this
game

`LS_INVALID` = -1: something is badly wrong with the save file
`LS_CRASHED` = -2: the save file needs manual recovery
create_game
Creates a new save file, that can subsequently be opened with `play_game` in
order to start a new game.  This mostly corresponds to the `nh_create_game`
API call in libnethack (although it has a slightly different calling
convention).
Command arguments:

`struct nh_option_desc[] options`: the options this game should initially
be created with (including game mode, character, and character name); any
options omitted wil be filled in with defaults
Response arguments:

`int gameid`: The game ID, for use with future `play_game` calls; if this
is -1, the game creation failed

play_game
Attaches to a game, causing that game to be loaded if it isn't already.  If
the game allows read access for the user the connection is authenticated as,
and the game is not completed, the user will be able to play, watch, and/or
replay the game.  Otherwise, the user will only be able to watch and replay
the game.  The `play_game` call does not respond until the gameplay is over
(or immediately, if an error happens); rather, the server will respond with a
number of followup commands to handle the user interaction side of the
gameplay itself.
This corresponds to the `nh_play_game` API call in libnethack.
Note that a `play_game` response may happen at any time after a unresponded
`play_game` command, even if there are unresponded requests in the meantime.
(This corresponds to a `longjmp` back to `nh_play_game` in the libnethack
API.)  The unresponded requests simply vanish, and the client should act as
though they never happened (removing menus that they opened from the screen,
forgetting messages, etc.).  This can happen in a few different situations:

If the client requests a save or quit (via `exit_game`), perhaps while a
prompt is open;

If something goes wrong and the server needs to rewind the save file
mid-turn;

During network play, if the network connection breaks or times out on the
server, the client API code simulates this to transparently reconnect the
connection, even though it isn't actually sent over the network.
Command arguments:

`int gameid`: A value returned from `list_games` or `create_game`
representing a game to attach to

`enum followmode followmode`: How to load the game:
`FM_PLAY` = 0: play the game
`FM_WATCH` = 1: watch a game (like playing, but read-only)
`FM_REPLAY` = 2: replay the game from the start (also read-only)
(`FM_RECOVERQUIT` = 3: go through the game over sequence of a completed
game again (leaving bones, xlogfile entries, etc.); this is disallowed
in network play for security reasons, but exists in the local API)
Response arguments:

`enum nh_play_status return`: what happen in the attempt to restore the game:
`GAME_DETACHED` = 0: the game was restored successfully; eventually,
the client requested to stop playing, and the game still exists

`GAME_OVER` = 1: the game was restored successfully; eventually, the
game ended through the death of the character or some similarly
permanent means; this return value is only sent to one process (the
one that sent the input causing the game to end)

`GAME_ALREADY_OVER` = 2: the game was restored successfully, but
either it had already ended (and thus was loaded in replay mode), or
else it ended while attached but some other process sent the input
that caused the game to end

`RESTART_PLAY` = 3: something happened that forced the server to jump
back to `play_game`; the client should in most cases immediately call
`play_game` with the same argument

`CLIENT_RESTART` = 4: ditto, but on the request of the client, which
can react to it how it likes

`REPLAY_FINISHED` = 5: the game is still going, but cannot continue in
replay mode because the end was reached; a client can reconnect in
play or watch mode if it likes

`ERR_BAD_ARGS` = 6: the game did not start because the given game ID
does not exist

`ERR_BAD_FILE` = 7: the game did not start because the given game ID
corresponds to a file on disk that cannot be read

`ERR_IN_PROGRESS` = 8: it is impossible to attach to the game due to
locking issues; on POSIXy OSes, this should only happen if the file is
being recovered manually, but on some OSes this may happen if anyone
else is currently playing the game

`ERR_RESTORE_FAILED` = 9: the game is completely corrupted and needs
manual recovery

`ERR_RECOVER_REFUSED` = 10: the game is partially corrupted, and the
user chose not to rewind it when prompted about whether to rewind it

(`ERR_NETWORK_ERROR` = 11: never sent over the network, but the
client library simulates this return value if it has to detach the
game due to network issues and cannot subsequently re-attach it, thus
clients using the client library may see it)

set_email
Change the email address associated with the authenticated user.  (This
address is not used by the game, but is available to server admins in case
they need to verify a user's identity, e.g. for a password reset request.)
Command arguments:

`string email`: the new email address
Response arguments:

`boolean return`: true if the email address change succeeded

set_password
Change the password associated with the authenticated user.  The same password
will be required by future `auth` requests.
Command arguments:

`string password`: the new password (sent in plaintext, unless the
connection is encrypted some other way)
Response arguments:

`boolean return`: true if the password change succeeded

shutdown
Exits the server process responsible for dealing with this client process and
closes the connection.  (If there is an active game, the server will attempt
to save it before exiting).
Command arguments: none
Response arguments:

`int return`: Always 1.

Server requests
These requests are sent by the server, expecting a response from the client.
Normally they will only be sent as followups to a response from the client;
the only exceptions are `server_error` and `server_cancel`, which can be sent
at any time (except to interrupt the request half of a server request or
response half of a server response, in which case they will be delayed until
the server is done sending its current request/response).

server_cancel
Sending an `nh_play_game` response can be used by the server to retroactively
wipe out the state of a connection, e.g. to handle save file recovery, or a
mid-turn save.  However, sometimes the server only wants to countermand one
request; the typical example is when watching a game which opened a menu, and
then the player being watched makes a selection from the menu (in which case
the server needs to, effectively, undo the opening of the menu).
In this case, the server will send a `server_cancel` request.  The client
should treat any response-requiring server request it is currently processing,
or the next such request if it is not currently processing such a request, as
being cancelled by the server, and should thus give the appropriate
"cancelled by server" response to that request.
In the local API (rather than the network API), in which `libnethack` links
directly against an interface, the `server_cancel` request can be sent at
absolutely any time at all; this includes such inconvenient times as "in the
middle of allocating memory", or "in the middle of another request"; this is
"async-signal" timing.  Doing this over the network would be impossible to
parse (the closest equivalent would be TCP urgent data, which can interrupt an
existing data stream in such a way that both can be distinguishd, but is
limited to one byte and thus hard to fit JSON in).  Instead, the network API
will delay making a `server_cancel` request until it has finished sending any
current request, if possible.  Clients nonetheless need to make arrangements
to handle this request in the middle of accepting input from the user (which
is its entire purpose); for instance, if blocking on the keyboard because
their interface wants a keypress in order to handle whatever input request is
being made at the time, they will need to block on a network socket at the
same time in order to be able to handle a possible cancel.
Be aware of possible race conditions: if the client finishes processing a
request just as the server tries to cancel it, then the server will end up
accidentally cancelling its next request instead.  This is why "client
cancelled" and "server cancelled" responses look different: so if the server
spuriously cancels a request, it can just send the request again, rather than
interpreting the client as having cancelled the request intentionally.
No response to the `server_cancel` call should be sent; the server has no use
for it, and is not equipped for arbitrarily inconveniently timed responses.
Request arguments: none
Response arguments: no response

request_command
This request is sent by the server when the player's character is able to send
a new command.  The client should respond with a game command, possibly
following up with network API command in order to help decide which command to
respond with.
Request arguments:

`boolean debug`: whether debug-mode commands are a reasonable response to
the prompt

`boolean completed`: false if the client is in the middle of a multi-turn
command (whether it was interrupted by a monster or the like, or whether
the server's just giving the client the chance to interrupt); true if the
previous command completed or there was no previous command

`boolean interrupted`: true if the character is aware of danger that might
cause a player to want to abort their current action (or not repeat a
repeated action); this is independent of `completed`
Response arguments:

`string command`: what the player wants to tell their character to do;
this should be a string returned by `get_commands`, or else one of the
following internal-use commands:

`"welcome"`: Display the "Welcome [back] to NetHack!" message; this
should be sent spontaneously by the client as the first command if the
game was restored due to player action (rather than due to a network
timeout or the like), rather than in response to user input

`"repeat"`: Continue a multiple-turn command, or repeat the last
command in other circumstances; clients will typically want to send
this without further user interaction if `completed` and `interrupted`
are both false, but may allow the user to override this if they wish

`"servercancel"`: Sent as a response if the server cancelled the API
call using a `server_cancel` call

`struct nh_cmd_arg arg`: a set of arguments to the command (any subset of
the arguments that `nh_get_command` specified were acceptable)

`enum nh_direction d`: [optional] a direction argument
`DIR_W` = 0: west (`h`, `4`)
`DIR_NW` = 1: northwest (`y`, `7`)
`DIR_N` = 2: north (`k`, `8`)
`DIR_NE` = 3: northeast (`u`, `9`)
`DIR_E` = 4: east (`l`, `6`)
`DIR_SE` = 5: southeast (`n`, `3`)
`DIR_S` = 6: south (`j`, `2`)
`DIR_SW` = 7: southwest (`b`, `1`)
`DIR_UP` = 8: up (`&lt;`)
`DIR_DOWN` = 9: down (`&gt;`)
`DIR_SELF` = 10: at self (`.` or `s`)
`charcode invlet`: [optional] an inventory letter
`coordinate x`: [optional] an x coordinate
`coordinate y`: [optional] a y coordinate
`string str`: [optional] a string
`charcode spelllet`: [optional] a spell letter
`int limit`: [optional] the amount to limit the command to
display_menu
Requests the client to display a menu to the user (either simply for display,
or to allow them to make a selection), until the user makes a selection or the
server cancels the request using a `play_game` response.
Request arguments:

`enum nh_pick_type how`: a specification of how many items the user can
choose from the menu:     

`PICK_NONE` = 0: the user cannot select items, the menu is purely used
to present information to the user;

`PICK_ONE` = 1: the user can pick one item from the menu;
`PICK_ANY` = 2: the user can pick zero or more items from the menu
`struct nh_menuitem[] items`: the menu items:
`charcode accel`: a recommended accelerator for this menu entry
`string caption`: the text of the menu entry
`charcode group_accel`: a secondary recommended accelerator (which may
apply to more than one entry; if it does, a `PICK_ANY` menu should
toggle all entries with the `group_accel` if the user presses it)

`int id`: a value to return in the `display_menu` response; if `id`
and `accel` are both 0, then the item is unselectable

`enum nh_menuitem_role role`: what sort of entry this is:
`MI_TEXT`: a line of text that is logically grouped together even
if it runs across multiple menu entries;

`MI_NORMAL`: a normal menu item;
`MI_HEADING`: a heading
`boolean selected`: whether this menu item should be selected by
default (in a `PICK_ANY` menu, where choosing an item does not close
the menu, choosing an item should toggle its selection state)

`enum placement_hint plhint`: a suggestion for a sensibleplcae on the
screen to place this menu, and styling for the menu (TODO: many of these
are unimplemented in nhcurses):

`PLHINT_ANYWHERE` = 0: no suggested location;
`PLHINT_LEFT` = 1: towards the left side of the screen;
`PLHINT_RIGHT` = 2: towards the right side of the screen;
`PLHINT_URGENT` = 3: appropriate styling for an important message;
`PLHINT_INFO` = 4: appropriate styling for an informational message;
`PLHINT_ONELINER` = 5: in the message area;
`PLHINT_CONTAINER` = 6: an appropriate location for container
contents;

`PLHINT_INVENTORY` = 7: over the inventory area (if any)
`string title`: the title of the menu
Response arguments:

`int[] results`: a list of the `id` of all selected items after the menu
was closed; this should be empty for `PICK_NONE` or if the menu was
cancelled via server or client, empty or a single element for `PICK_ONE`,
and any subset of elements for `PICK_ANY`,

`enum nh_client_response howclosed`: an explanation of how the menu was
closed:

`NHCR_ACCEPTED` = 0: pressing Return (or similar), scrolling off the
end, or (for `PICK_ONE`) selecting an item;

`NHCR_CLIENT_CANCEL` = 1: pressing Escape (or similar)
`NHCR_SERVER_CANCEL` = 5: by a `server_cancel` request

display_objects
A variant of `display_menu` specialised for inventory menus.  It provides extra
information and allows the user to specify partial stacks of items in addition
to full stacks.
Request arguments: same as `display_menu`, except for `items`:

`struct nh_objitem[] items`: the menu items (sent as an array, not an
object, with elements in the order shown here):

`string caption`: as in `display_menu`
`int id`: as in `display_menu`
`enum nh_menuitem_role role`: as in `display_menu`
`int count`: the number of objects in the stack
`int otype`: the obfuscated object type; I think this is an index into
the `objects[]` returned from `get_drawing_info`, but I'm not sure

`int oclass`: the object class (are these listed anywhere public?)
`int weight`: the object's weight, negative numbers means unknown
`enum nh_bucstatus buc`: the object's beatitude:
`B_UNKNOWN` = 0: unknown beatitude;
`B_BLESSED` = 1: blessed;
`B_UNCURSED` = 2: neither blessed nor cursed;
`B_CURSED` = 3: cursed
`charcode accel`: as in `display_menu`
`charcode group_accel`: as in `display_menu`
`boolean worn`: true if the object is equipped
Response arguments:

`struct nh_objresult[] pick_list`: a list of all selected items after the
menu ws closed, as with `display_menu`, but with more information:

`int id`: the `id` specified for this item in the request
`int count`: the size of a partial stack specified for this item, or
-1 to select the entire stack; should be -1, or between 1 and the stack
size minus 1

`enum nh_client_response howclosed`: as in `display_menu`

getdir
Requests a direction from the user (can be cancelled by the user, or the
server via a `play_game` response).
Request arguments:

`string query`: a message to print along with the direction request (the
generic message is along the lines of "In which direction?", but the
message is often more specific, similar to "Zap your wand in which
direction?").

`boolean restricted`: if true, the client should act as though diagonal
directions do not exist for the purpose of its help text (applies when the
player is polymorphed into a grid bug)
Response arguments:

`enum nh_direction return`: The selected direction:
`DIR_W` = 0: west (`h`, `4`)
`DIR_NW` = 1: northwest (`y`, `7`)
`DIR_N` = 2: north (`k`, `8`)
`DIR_NE` = 3: northeast (`u`, `9`)
`DIR_E` = 4: east (`l`, `6`)
`DIR_SE` = 5: southeast (`n`, `3`)
`DIR_S` = 6: south (`j`, `2`)
`DIR_SW` = 7: southwest (`b`, `1`)
`DIR_UP` = 8: up (`&lt;`)
`DIR_DOWN` = 9: down (`&gt;`)
`DIR_SELF` = 10: at self (`.` or `s`)
`DIR_NONE` = -1: the user cancelled the prompt
`DIR_SERVERCANCEL` = -2: the server cancelled the prompt

getline
Requests a line of input from the user (can be cancelled by the user, or the
server via a `play_game` response).
Request arguments:

`string query`: The prompt to display along with the request for a line.
Response arguments:

`string line`: The line of input from the user. Is the null string if the
null string was entered, a single ESC character (hex 1B) if the user
cancelled the prompt, a single ASCII 28 character (hex 1C) if the server
cancelled the prompt, or otherwise the user's input.

getpos
Requests a map location from the user (can be cancelled by the user, or the
server via a `play_game` response).
Request arguments:

`boolean force`: if true, the client should make it difficult for the user
to cancel the prompt (TODO: the idea behind thies option is bad)

`string goal`: a description of what the user is supposd to select
`coordinate x`: the x coordinate to originally place the cursor at
`coordinate y`: the y coordinate to originally place the cursor at
Response arguments:

`enum nh_client_response return`: information on how the prompt was closed:
`NHCR_ACCEPTED` = 0: the user accepted the location using the most
ordinary input (usually `.`);

`NHCR_CLIENT_CANCEL` = 1: the user cancelled the location prompt
(e.g. via ESC);

`NHCR_CONTINUE` = 2: the user accepted the location, requesting to
continue choosing locations (normally accomplished via `,`);

`NHCR_MOREINFO` = 3: the user accepted the location, requesting more
information about it (normally accomplished via `:`);

`NHCR_MOREINFO_CONTINUE` = 4: a combination of the two previous cases
(normally accomplished via `;`);

`NHCR_SERVER_CANCEL` = 5: the server cancelled the prompt.
`coordinate x`: the x coordinate chosen by the user
`coordinate y`: the y coordinate chosen by the user

query_key
Inputs one ASCII code from the user, potentially with a repeat count
beforehand.  This is used for inventory queries, and in a few other cases.  As
always, can be cancelled by the user or the server.
Request arguments:

`boolean allow_count`: whether to allow a repeat count
`enum nh_query_key_flags flags`: information about the reason for the
query:

`NQKF_INVENTORY_ITEM` = 0: an item from inventory
`NQKF_INVENTORY_ITEM_NULLABLE` = 1: an item from inventory or "-" to
mean bare hands, no item, etc.

`NQKF_INVENTORY_OR_FLOOR` = 2: an item from inventory or "," to mean an
item on the floor

`NQKF_SYMBOL` = 3: an object or monster symbol
`NQKF_LETTER_REASSIGNMENT` = 4: a new inventory or spell letter
`string query`: what prompt to display to the user
Response arguments:

`int count`: the repeat count, -1 if none was given; this is supplied
even if `allow_count` is false, but is always -1 in that case and should
be ignored

`charcode return`: the key the user pressed; this is ESC if cancelled by
the user, ASCII 28 if cancelled by the server

yn
Requests the user to choose from a short list of choices represented by ASCII
characters.  As always, can be cancelled by the user or the server.
Request arguments:

`string query`: the prompt to print to the user
`string set`: a list of appropriate responses; if ESC is included in the
list, it does not mean that ESC is an appropriate response, but rather, it
means that all responses after the ESC should be hidden from the user

`charcode def`: the default value to return in the case of a user cancel
(this will be shown to the user in many interfaces)
Response arguments:

`charcode return`: the choice the user chose; this is `def` if cancelled
by the user, ASCII 28 if cancelled by the server

load_progress
Sent by the server periodically during time-consuming background operations in
order to prevent the connection dropping.  This will never have a display list
attached.
Request arguments:

`int progress`: a number from 0 to 10000, proportional to the estimated
length of the background operation
Response arguments: no response is sent for this message

server_error
Called by the server if something goes unrecoverably wrong.  The server closes
the connection immediately after sending this, so sending a response is futile
and not particularly useful.  (For the same sort of message directed in the
opposite direction, see `exit_game`.)
Request arguments:

`boolean error`: true if the error is caused by something that the client
did, false if the error is internal to the server

`string message`: a description of what went wrong, which can be displayed
to the user
No response.

Display elements
Any message sent by the server, whether as a request or a response, might have
a `display` element attached, which specifies updates to the map.  The
exceptions are `auth`, `register`, and `cancel_server_request`, which never
carry map data.  The `display` element is an array of elements to draw; each
element can be one of the below types.

delay_output
Specifies that the client should wait for a short time at this point before
doing any further rendering.
Arguments: `nil`.

display_buffer
Specifies that the client should display text to the user.  (The text may be
quite long, and should be word-wrapped and tab-expanded.)
Arguments: an object:

`string buf`: the text to display
`boolean trymove`: appears to be unused

level_changed
Specifies that the client should change its level display mode.
TODO: make this an enum.
Arguments: an integer:

`LDM_DEFAULT` = 0: normal display;
`LDM_HELL` = 1: display appropriate for Gehennom;
`LDM_QUEST` = 2: display appropriate for the Quest;
`LDM_MINES` = 3: display appropriate for the Mines;
`LDM_SOKOBAN` = 4: display appropriate for Sokoban;
`LDM_ROGUE` = 5: display appropriate for the Rogue level;
`LDM_KNOX` = 6: display appropriate for Fort Ludios

list_items
Specifies a list of items in inventory or on the floor.
TODO: The API of this is vulnerable to length mismatches.
Arguments: an object:

`int icount`: length of `items`
`boolean invent`: true means that this list is the player's inventory;
false means that this list is the list of items on the ground

`struct nh_objitem[] items`: the list of items about which the client is
being informed

outrip
Shows an appropriate message to reflect character death (and similar
game-over situations like ascension).
TODO: The API of this is vulnerable to length mismatches.
Arguments: an object:

`int gold`: amount of gold upon death
`int how`: as `end_how` in `get_topten`
`int icount`: length of `items`
`struct nh_menuitem[] items`: list of messages to print; only the
`caption` field is used. TODO: There has to be a better API for this!

`string killbuf`: the cause of the game over
`string name`: the name of the character whose game ended
`boolean tombstone`: true to request the drawing of a tombstone graphic;
false presents the information entirely as text

`int year`: a year to draw on the tombstone

pause
Wait for user input in order to give the user a chance to read messages or
look at the map.
TODO: This has a pretty weird interaction with server cancel requests.  It
should probably be made a server request, not a display element.
Arguments: an `enum nh_pause_reason`:

`P_MESSAGE` = 0: give the user a chance to read the message area
`P_MAP` = 1: give the user a chance to look at the map

print_message
Print a message in the message area.
TODO: This API is badly designed and has caused several bugs.
Arguments: an object:

`string msg`: the message to print
`int turn`: the turn on which the message was sent

print_message_nonblocking
Print a message in the message area.  This message is not important enough to
ensure that the user sees it, and the client should aim to prevent this
forcing a --More-- or similar.
Arguments: as print_message

raw_print
Display a message to the user, attempting to bypass the standard rendering and
just displaying the message directly on a console, perhaps after the program
exits.  (This is typically used to make a record of error messages.)
Arguments: a string, the message to print

update_screen
Change what is displayed at a particular map location.
Arguments: an object:

`mapdelta dbuf`: the map delta, in compressed form (see below)
`coordinate ux`: the character's x location
`coordinate uy`: the character's y location
A map delta can be an integer 0 if nothing at all has changed.  Otherwise it
is a list of column deltas.  A column delta of 0 means that column is empty,
and 1 means it is unchanged since last time.  Otherwise a column delta is a
list of cell deltas.  Again, 0 means empty, 1 means unchanged.  Otherwise the
cell delta is an `int[10]`, mostly of indexes into the arrays returned by
`get_drawing_info`:

[0] encoded effect number: the encoding is quite complex, see `draw_map`
in `libnethack/src/map.c` for an example on how to decode it; it
eventually decodes into offsets into `effects`, `zapsyms`, `zaptypes`,
`swallowsyms`, `explsyms`, and/or `expltypes`

[1] index into `bgelements`
[2] index into `traps`
[3] index into `objects`
[4] index into `monsters`, representing the monster associated with an
object (e.g. "lichen" for "lichen corpse")

[5] index into `monsters`, representing a monster on that square
[6] a bitmask that represents details of a monster on the square:
`MON_TAME` = 1: the monster is tame
`MON_RIDDEN` = 2: this monster has the player riding it
`MON_DETECTED` = 4: this monster is seen via monster detection
`MON_WARNING` = 8: this is a warning symbol, not a monster
`MON_PEACEFUL` = 16: the monster is peaceful
[7] a bitmask that represents any branding of the square:
`NH_BRANDING_STEPPED` = 1: the player has stepped on the square
`NH_BRANDING_LOCKED` = 2: the player knows this door is locked
`NH_BRANDING_UNLOCKED` = 4: the player knows this door is unlocked
`NH_BRANDING_TRAPPED` = 8: the player knows this square is trapped
`NH_BRANDING_UNTRAPPED` = 16: the player knows this door is untrapped
[8] index into `invis`
[9] a boolean, not an int; true if the character can see this square
Indexes have 1 added to them, so that 0 can represent the lack of the
appropriate sort of drawable entity on the square.

update_status
Updates the character's status information.
Arguments: an object:

`int ac`: the character's AC (10 = unarmored, lower is better)
`int align`: the character's alignment (TODO: what format?)
`boolean can_enhance`: true if the #enhance command is usable
`int ch`: the character's Charisma stat
`int co`: the character's Constitution stat
`charcode coinsym`: the character to use to represent money
`int cur_monnum`: the species the character is polymorphed into (an index
into `monsters` returned from `get_drawing_info`)

`int dx`: the character's Dexterity stat
`int en`: the character's current Pw
`int enmax`: the character's maximum Pw
`int gold`: the character's gold in open inventory
`int hp`: the character's current HP
`int hpmax`: the character's maximum HP
`int in`: the character's Intelligence stat
`int level`: the character's experience level
`string level_desc`: a textual description of the character's current
dungeon level

`int max_rank_sz`: the maximum possible width of a character's
professional title, given their role, even if they change gender or level

`int monnum`: the species that the character is naturally (an index
into `monsters` returned from `get_drawing_info`)

`int moves`: the number of turns this game has lasted (1 for the first
turn)

`int plname`: the character's name
`string rank`: the character's professional title
`string racename`: the character's unpolymorphed race (`human`, `dwarf`,
etc.)

`string gender`: the character's unpolymorphed gender (`male`, `female`,
`neuter`); this is affected by permanent gender changes, but not by
polymorphing into a male/female-only monster

`string rolename`: the character's current role (`Archaeologist`, etc.)
`int score`: the character's current score
`int st`: the integer part of the character's Strength stat
`int st_extra`: the fractional part of the character's Strength stat
`string[] statusitems`: a list of status lights currently affecting the
character

`int wi`: the character's Wisdom stat
`int x`: the character's x coordinate
`int xp`: the character's total number of gained experience points (minus
any lost to level drain)

`int y`: the character's y coordinate
`int z`: the character's z coordinate