From: nhmall Date: Thu, 9 Jun 2022 04:43:35 +0000 (-0400) Subject: a couple of argrath pull requests X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0ba9278b6973a7244446bce7fb232d0cde7b26dd;p=nethack a couple of argrath pull requests Closes #777 https://github.com/NetHack/NetHack/pull/777 Closes #793 https://github.com/NetHack/NetHack/pull/793 --- diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 9c42db911..bc9481d83 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1831,6 +1831,8 @@ lua: instance cleanup should not be applied to classes (by ToxicFrog) fix memory leaks related to selection_new() (pr #782 by argrath) wished-for doors in wizmode always vertical (pr #788 by entrez) vampire shapeshifting in a door (pr #794 by entrez) +split "act_on_act" into separate function (pr #777 by argrath) +unnecessary null-check on parsesymbols() (pr #793 by argrath) Code Cleanup and Reorganization diff --git a/doc/window2.txt b/doc/window2.txt new file mode 100644 index 000000000..025a41b66 --- /dev/null +++ b/doc/window2.txt @@ -0,0 +1,1167 @@ +NetHack 3.7 window.txt $NHDT-Date: 1643491505 2022/01/29 21:25:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ + +Introduction + +This file documents the support for various windowing systems in +NetHack. The support is through a standard interface, separating the +main NetHack code from window-system specific code. The implementation +supports multiple window systems in the same binary. Even if you only +wish to support one window-port on your port, you will need to follow +the instructions in Section IX to get a compilable binary. + +Copyright 2003, David Cohrs +NetHack may be freely redistributed. See license for details. + +Contents: + I. Window Types and Terminology + II. Interface Specification + III. Global variables + IV. WINCAP preferences support + V. New or respecified common, high level routines + VI. Game startup + VII. Conventions + VIII. Implementation and Multi-window support + IX. WINCHAIN + +I. Window Types and Terminology + +There are 4 basic window types, used to call create_nhwindow(): + + NHW_MESSAGE (top line) + NHW_MAP (main dungeon) + NHW_MENU (inventory or other "corner" windows) + NHW_TEXT (help/text, full screen paged window) + +The tty window-port also uses NHW_BASE (the base display) internally. + +(The genl_status_* routines use NHW_STATUS for backward compatibility + when displaying status information on the bottom lines. New code + should not use NHW_STATUS. NHW_STATUS will be phased out over time.) + +NHW_MENU windows can be used for either menu or text display. Their +basic feature is that for the tty-port, if the window is small enough, +it appears in the corner of the tty display instead of overwriting +the whole screen. The first call to add information to the window +will decide if it is going to be used to display a menu or text. +If start_menu() is called, then it will be used as a menu. If +putstr() is called, it will be used as text. Once decided, there +is no turning back. For the tty-port, if the data is too large for +a single screen then the data is paged (with --more--) between pages. +Only NHW_MENU type windows can be used for menus. + +NHW_TEXT windows are used to display a large amount of textual data. +This is the type of window one would use for displaying a help file, +for example. In the tty window-port, windows of type NHW_TEXT can +page using the DEF_PAGER, if DEF_PAGER is defined. There exists an +assumption that the font for text windows is monospaced. The help +files are all formatted accordingly. + +"window" is always of type winid. This is currently implemented as an +integer, but doesn't necessarily have to be done that way. There are +a few fixed window names that are known throughout the code: + + WIN_MESSAGE (top line) + WIN_MAP (main dungeon) + WIN_INVEN (inventory) + +Other windows are created and destroyed as needed. + +(The genl_status_* routines use WIN_STATUS for backward compatibility + when displaying status information on the bottom lines. New code + should not use WIN_STATUS, or assume its presence. NHW_STATUS will + be phased out over time.) + +"Port" in this document refers to a CPU/OS/hardware platform (UNIX, MSDOS +TOS, etc.) "window-port" refers to the windowing platform. This is +orthogonal (e.g. UNIX might use either a tty window-port or an X11 +window-port). + + +II. Interface Specification + +All functions below are void unless otherwise noted. + +A. Low-level routines: + +raw_print(str) -- Print directly to a screen, or otherwise guarantee that + the user sees str. raw_print() appends a newline to str. + It need not recognize ASCII control characters. This is + used during startup (before windowing system initialization + -- maybe this means only error startup messages are raw), + for error messages, and maybe other "msg" uses. E.g. + updating status for micros (i.e, "saving"). +raw_print_bold(str) + -- Like raw_print(), but prints in bold/standout (if possible). +curs(window, x, y) + -- Next output to window will start at (x,y), also moves + displayable cursor to (x,y). For backward compatibility, + 1 <= x < cols, 0 <= y < rows, where cols and rows are + the size of window. + -- For variable sized windows, like the old status window, the + behavior when curs() is called outside the window's limits + is unspecified. The mac port wraps to 0, with the status + window being 2 lines high and 80 columns wide. + -- Still used by curs_on_u(), obsolete status updates, + screen locating (identify, teleport). + -- NHW_MESSAGE, NHW_MENU and NHW_TEXT windows do not + currently support curs in the tty window-port. +putstr(window, attr, str) + -- Print str on the window with the given attribute. Only + printable ASCII characters (040-0126) must be supported. + Multiple putstr()s are output on separate lines. Attributes + can be one of + ATR_NONE (or 0) + ATR_ULINE + ATR_BOLD + ATR_BLINK + ATR_INVERSE + If a window-port does not support all of these, it may map + unsupported attributes to a supported one (e.g. map them + all to ATR_INVERSE). putstr() may compress spaces out of + str, break str, or truncate str, if necessary for the + display. Where putstr() breaks a line, it has to clear + to end-of-line. + -- putstr should be implemented such that if two putstr()s + are done consecutively the user will see the first and + then the second. In the tty port, pline() achieves this + by calling more() or displaying both on the same line. +putmixed(window, attr, str) + -- Print str on the window with the given attribute. In + addition to printable ASCII characters (040-0126), + sequences of encoded glyph values are supported. + The glyph encoding sequence is \GXXXXNNNN, where: + XXXX is a hexadecimal value. The value must match + the randomly generated value for the current + game in progress in order to be decoded. + The value for the game in progress is stored in + context.rndencode. This field minimizes + unintentional decoding of player-supplied strings + such as pet names, etc. + NNNN is a hexadecimal value representing the glyph. + If a window port does not yet support special handling of + the glyph value, it can use genl_putmixed (windows.c) + which converts the encoded glyph into a character symbol. + + Multiple putmixed()s are output on separate lines. + Attributes can be one of + ATR_NONE (or 0) + ATR_ULINE + ATR_BOLD + ATR_BLINK + ATR_INVERSE + If a window-port does not support all of these, it may map + unsupported attributes to a supported one (e.g. map them + all to ATR_INVERSE). putmixed() may compress spaces out of + str, break str, or truncate str, if necessary for the + display. Where putmixed() breaks a line, it has to clear + to end-of-line. + -- putstr should be implemented such that if two putmixed()s + are done consecutively the user will see the first and + then the second. +get_nh_event() -- Does window event processing (e.g. exposure events). + A noop for the tty and X window-ports. +int nhgetch() -- Returns a single character input from the user. + -- In the tty window-port, nhgetch() assumes that tgetch() + will be the routine the OS provides to read a character. + Returned character _must_ be non-zero and it must be + non meta-zero too (zero with the meta-bit set). + -- If platform uses it, should check program_state.done_hup + and immediately return ASCII 033 (escape) if it is. + This is required if the window-port supports SAFERHANGUP. + -- ASCII 033 must also be returned rather than EOF (applies + mainly to the tty window-port). + -- The program_state.done_hup flag can be set asynchronously + when SAFERHANGUP is defined and in that case, nhgetch() + needs to detect that the value of program_state.done_hup + changed and also return ASCII 033 in this case. +int nh_poskey(int *x, int *y, int *mod) + -- Returns a single character input from the user or a + positioning event (perhaps from a mouse). If the + return value is non-zero, a character was typed, else, + a position in the MAP window is returned in x, y and mod. + mod may be one of + + CLICK_1 /* mouse click type 1 */ + CLICK_2 /* mouse click type 2 */ + + The different click types can map to whatever the + hardware supports. If no mouse is supported, this + routine always returns a non-zero character. + -- Otherwise follows the same behavior as nhgetch(). + +B. High-level routines: + +print_glyph(window, x, y, glyphinfo, bkglyphinfo) + -- Print a glyph found within the glyphinfo at (x,y) on the + given window. The glyphs within the glyph_info struct are + integers and can be mapped to whatever the window- + port wants (symbol, font, color, attributes, ...there's + a 1-1 map between glyphs and distinct things on the map). + -- bkglyphinfo contains a background glyph for potential use + by some graphical or tiled environments to allow the + depiction to fall against a background consistent with the + grid around x,y. If bkglyphinfo->glyph is NO_GLYPH, then + the parameter should be ignored (do nothing with it). + -- glyph_info struct fields: + int glyph; /* the display entity */ + int color; /* color for window ports not using a tile */ + int ttychar; /* the character mapping for the original tty + * interface. Most or all window ports wanted + * and used this for various things so it is + * provided in 3.7+ */ + short int symidx; /* offset into syms array */ + unsigned glyphflags; /* more detail about the entity */ + + +char yn_function(const char *ques, const char *choices, char default) + -- Print a prompt made up of ques, choices and default. + Read a single character response that is contained in + choices or default. If choices is NULL, all possible + inputs are accepted and returned. This overrides + everything else. The choices are expected to be in + lower case. Entering ESC always maps to 'q', or 'n', + in that order, if present in choices, otherwise it maps + to default. Entering any other quit character (SPACE, + RETURN, NEWLINE) maps to default. + -- If the choices string contains ESC, then anything after + it is an acceptable response, but the ESC and whatever + follows is not included in the prompt. + -- If the choices string contains a '#' then accept a count. + Place this value in the global "yn_number" and return '#'. + -- This uses the top line in the tty window-port, other + ports might use a popup. + -- If choices is NULL, all possible inputs are accepted and + returned, preserving case (upper or lower.) This means that + if the calling function needs an exact match, it must handle + user input correctness itself. + -- ques should not be more than QBUFSZ-1 characters long. +getlin(const char *ques, char *input) + -- Prints ques as a prompt and reads a single line of text, + up to a newline. The string entered is returned without the + newline. ESC is used to cancel, in which case the string + "\033\000" is returned. + -- getlin() must call flush_screen(1) before doing anything. + -- This uses the top line in the tty window-port, other + ports might use a popup. + -- getlin() can assume the input buffer is at least BUFSZ + bytes in size and must truncate inputs to fit, including + the nul character. +int get_ext_cmd(void) + -- Get an extended command in a window-port specific way. + An index into extcmdlist[] is returned on a successful + selection, -1 otherwise. +player_selection() + -- Do a window-port specific player type selection. If + player_selection() offers a Quit option, it is its + responsibility to clean up and terminate the process. + You need to fill in pl_character[0]. +display_file(str, boolean complain) + -- Display the file named str. Complain about missing files + iff complain is TRUE. +update_inventory(arg) + -- For an argument of 0: + -- Indicate to the window port that the inventory has + been changed. + -- Merely calls display_inventory() for window-ports + that leave the window up, otherwise empty. + -- or for a non-zero argument: + -- Prompts the user for a menu scrolling action and + executes that. + -- May repeat until user finishes (typically by using + or but interface may use other means). +doprev_message() + -- Display previous messages. Used by the ^P command. + -- On the tty-port this scrolls WIN_MESSAGE back one line. + +update_positionbar(char *features) + -- Optional, POSITIONBAR must be defined. Provide some + additional information for use in a horizontal + position bar (most useful on clipped displays). + Features is a series of char pairs. The first char + in the pair is a symbol and the second char is the + column where it is currently located. + A '<' is used to mark an upstairs, a '>' + for a downstairs, and an '@' for the current player + location. A zero char marks the end of the list. + + +C. Window Utility Routines + +init_nhwindows(int* argcp, char** argv) + -- Initialize the windows used by NetHack. This can also + create the standard windows listed at the top, but does + not display them. + -- Any commandline arguments relevant to the windowport + should be interpreted, and *argcp and *argv should + be changed to remove those arguments. + -- When the message window is created, the variable + iflags.window_inited needs to be set to TRUE. Otherwise + all plines() will be done via raw_print(). + ** Why not have init_nhwindows() create all of the "standard" + ** windows? Or at least all but WIN_INFO? -dean +exit_nhwindows(str) + -- Exits the window system. This should dismiss all windows, + except the "window" used for raw_print(). str is printed + if possible. +window = create_nhwindow(type) + -- Create a window of type "type." +clear_nhwindow(window) + -- Clear the given window, when appropriate. +display_nhwindow(window, boolean blocking) + -- Display the window on the screen. If there is data + pending for output in that window, it should be sent. + If blocking is TRUE, display_nhwindow() will not + return until the data has been displayed on the screen, + and acknowledged by the user where appropriate. + -- All calls are blocking in the tty window-port. + -- Calling display_nhwindow(WIN_MESSAGE,???) will do a + --more--, if necessary, in the tty window-port. +destroy_nhwindow(window) + -- Destroy will dismiss the window if the window has not + already been dismissed. +start_menu(window, unsigned long mbehavior) + -- Start using window as a menu. You must call start_menu() + before add_menu(). After calling start_menu() you may not + putstr() to the window. Only windows of type NHW_MENU may + be used for menus. + -- mbehavior allows flags to be passed to alter the appearance + and/or behavior of the menu. +add_menu(windid window, glyphinfo, const anything identifier, char accelerator, + char groupacc, int attr, char *str, + unsigned itemflags) + -- Add a text line str to the given menu window. If identifier + is 0, then the line cannot be selected (e.g. a title). + Otherwise, identifier is the value returned if the line is + selected. Accelerator is a keyboard key that can be used + to select the line. If the accelerator of a selectable + item is 0, the window system is free to select its own + accelerator. It is up to the window-port to make the + accelerator visible to the user (e.g. put "a - " in front + of str). The value attr is the same as in putstr(). + -- glyphinfo (glyph_info type) may optionally contain a glyph + to accompany the line. If a window port cannot + or does not want to display it, this is OK. If there is no + glyph provided, then the value of glyphinfo->glyph will + be NO_GLYPH. + -- All accelerators should be in the range [A-Za-z], + but there are a few exceptions such as the tty player + selection code which uses '*'. + -- It is expected that callers do not mix accelerator + choices. Either all selectable items have an accelerator + or let the window system pick them. Don't do both. + -- Groupacc is a group accelerator. It may be any character + outside of the standard accelerator (see above) or a + number. If 0, the item is unaffected by any group + accelerator. If this accelerator conflicts with + the menu command (or their user defined aliases), it loses. + The menu commands and aliases take care not to interfere + with the default object class symbols. + -- itemflags on this item (such as MENU_ITEMFLAGS_SELECTED etc.). + +end_menu(window, prompt) + -- Stop adding entries to the menu and flushes the window + to the screen (brings to front?). Prompt is a prompt + to give the user. If prompt is NULL, no prompt will + be printed. + ** This probably shouldn't flush the window any more (if + ** it ever did). That should be select_menu's job. -dean +int select_menu(windid window, int how, menu_item **selected) + -- Return the number of items selected; 0 if none were chosen, + -1 when explicitly cancelled. If items were selected, then + selected is filled in with an allocated array of menu_item + structures, one for each selected line. The caller must + free this array when done with it. The "count" field + of selected is a user supplied count. If the user did + not supply a count, then the count field is filled with + -1 (meaning all). A count of zero is equivalent to not + being selected and should not be in the list. If no items + were selected, then selected is NULL'ed out. How is the + mode of the menu. Three valid values are PICK_NONE, + PICK_ONE, and PICK_ANY, meaning: nothing is selectable, + only one thing is selectable, and any number valid items + may selected. If how is PICK_NONE, this function should + never return anything but 0 or -1. + -- You may call select_menu() on a window multiple times -- + the menu is saved until start_menu() or destroy_nhwindow() + is called on the window. + -- Note that NHW_MENU windows need not have select_menu() + called for them. There is no way of knowing whether + select_menu() will be called for the window at + create_nhwindow() time. +char message_menu(char let, int how, const char *mesg) + -- tty-specific hack to allow single line context-sensitive + help to behave compatibly with multi-line help menus. + -- This should only be called when a prompt is active; it + sends `mesg' to the message window. For tty, it forces + a --More-- prompt and enables `let' as a viable keystroke + for dismissing that prompt, so that the original prompt + can be answered from the message line "help menu". + -- Return value is either `let', '\0' (no selection was made), + or '\033' (explicit cancellation was requested). + -- Interfaces which issue prompts and messages to separate + windows typically won't need this functionality, so can + substitute genl_message_menu (windows.c) instead. + +D. Status Display Routines + +status_init() -- core calls this to notify the window port that a status + display is required. The window port should perform + the necessary initialization in here, allocate memory, etc. +status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable) + -- notifies the window port which fields it is authorized to + display. + -- This may be called at any time, and is used + to disable as well as enable fields, depending on the + value of the final argument (TRUE = enable). + -- fldindex could be one of the following from botl.h: + BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, + BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, + BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, + BL_LEVELDESC, BL_EXP, BL_CONDITION + -- There are MAXBLSTATS status fields (from botl.h) +status_update(int fldindex, genericptr_t ptr, int chg, int percentage, \ + int color, long *colormasks) + -- update the value of a status field. + -- the fldindex identifies which field is changing and + is an integer index value from botl.h + -- fldindex could be any one of the following from botl.h: + BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, + BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, + BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, + BL_LEVELDESC, BL_EXP, BL_CONDITION + -- fldindex could also be BL_FLUSH (-1), which is not really + a field index, but is a special trigger to tell the + windowport that it should output all changes received + to this point. It marks the end of a bot() cycle. + -- fldindex could also be BL_RESET (-2), which is not really + a field index, but is a special advisory to to tell the + windowport that it should redisplay all its status fields, + even if no changes have been presented to it. + -- ptr is usually a "char *", unless fldindex is BL_CONDITION. + If fldindex is BL_CONDITION, then ptr is a long value with + any or none of the following bits set (from botl.h): + BL_MASK_BAREH 0x00000001L + BL_MASK_BLIND 0x00000002L + BL_MASK_BUSY 0x00000004L + BL_MASK_CONF 0x00000008L + BL_MASK_DEAF 0x00000010L + BL_MASK_ELF_IRON 0x00000020L + BL_MASK_FLY 0x00000040L + BL_MASK_FOODPOIS 0x00000080L + BL_MASK_GLOWHANDS 0x00000100L + BL_MASK_GRAB 0x00000200L + BL_MASK_HALLU 0x00000400L + BL_MASK_HELD 0x00000800L + BL_MASK_ICY 0x00001000L + BL_MASK_INLAVA 0x00002000L + BL_MASK_LEV 0x00004000L + BL_MASK_PARLYZ 0x00008000L + BL_MASK_RIDE 0x00010000L + BL_MASK_SLEEPING 0x00020000L + BL_MASK_SLIME 0x00040000L + BL_MASK_SLIPPERY 0x00080000L + BL_MASK_STONE 0x00100000L + BL_MASK_STRNGL 0x00200000L + BL_MASK_STUN 0x00400000L + BL_MASK_SUBMERGED 0x00800000L + BL_MASK_TERMILL 0x01000000L + BL_MASK_TETHERED 0x02000000L + BL_MASK_TRAPPED 0x04000000L + BL_MASK_UNCONSC 0x08000000L + BL_MASK_WOUNDEDL 0x10000000L + BL_MASK_HOLDING 0x20000000L + -- The value passed for BL_GOLD includes a leading + symbol for GOLD "$:nnn". If the window port needs to use + the textual gold amount without the leading "$:" the port + will have to add 2 to the passed "ptr" for the BL_GOLD case. + -- color is an unsigned int. + int & 0x00FF = color CLR_* + int >> 8 = attribute (if any) + + This contains the color and attribute that the field should + be displayed in. + + This is relevant for everything except BL_CONDITION. + If fldindex is BL_CONDITION, this parameter should be + ignored, as condition hilighting is done via the next + colormasks parameter instead. + + -- colormasks - pointer to cond_hilites[] array of colormasks. + Only relevant for BL_CONDITION fldindex. The window port + should ignore this parameter for other fldindex values. + + Each condition bit must only ever appear in one of the + CLR_ array members, but can appear in multiple HL_ATTCLR_ + offsets (because more than one attribute can co-exist). + + For the user's chosen set of BL_MASK_ condition bits, + They are stored internally in the cond_hilites[] array, + at the array offset aligned to the color those condition + bits should display in. + + For example, if the user has chosen to display strngl + and stone and termill in red and inverse, + + BL_MASK_SLIME 0x00000002 + BL_MASK_STRNGL 0x00000004 + BL_MASK_TERMILL 0x00000010 + + The bitmask corresponding to those conditions is + 0x00000016 (or 00010110 in binary) and the color + is at offset 1 (CLR_RED). + + Here is how that is stored in the cond_hilites[] array: + + +------+----------------------+--------------------+ + |array | | | + |offset| macro for indexing | bitmask | + |------+----------------------+--------------------+ + | 0 | CLR_BLACK | | + +------+----------------------+--------------------+ + | 1 | CLR_RED | 00010110 | + +------+----------------------+--------------------+ + | 2 | CLR_GREEN | | + +------+----------------------+--------------------+ + | 3 | CLR_BROWN | | + +------+----------------------+--------------------+ + | 4 | CLR_BLUE | | + +------+----------------------+--------------------+ + | 5 | CLR_MAGENTA | | + +------+----------------------+--------------------+ + | 6 | CLR_CYAN | | + +------+----------------------+--------------------+ + | 7 | CLR_GRAY | | + +------+----------------------+--------------------+ + | 8 | NO_COLOR | | + +------+----------------------+--------------------+ + | 9 | CLR_ORANGE | | + +------+----------------------+--------------------+ + | 10 | CLR_BRIGHT_GREEN | | + +------+----------------------+--------------------+ + | 11 | CLR_BRIGHT_YELLOW | | + +------+----------------------+--------------------+ + | 12 | CLR_BRIGHT_BLUE | | + +------+----------------------+--------------------+ + | 13 | CLR_BRIGHT_MAGENTA | | + +------+----------------------+--------------------+ + | 14 | CLR_BRIGHT_CYAN | | + +------+----------------------+--------------------+ + | 15 | CLR_WHITE | | + +------+----------------------+--------------------+ + | 16 | HL_ATTCLR_DIM | | CLR_MAX + +------+----------------------+--------------------+ + | 17 | HL_ATTCLR_BLINK | | + +------+----------------------+--------------------+ + | 18 | HL_ATTCLR_ULINE | | + +------+----------------------+--------------------+ + | 19 | HL_ATTCLR_INVERSE | 00010110 | + +------+----------------------+--------------------+ + | 20 | HL_ATTCLR_BOLD | | + +------+----------------------+--------------------+ + | 21 | beyond array boundary| | BL_ATTCLR_MAX + + The window port can AND (&) the bits passed in the + ptr argument to status_update() with any non-zero + entries in the cond_hilites[] array to determine + the color and attributes for displaying the + condition on the screen for the user. + + If the bit for a particular condition does not + appear in any of the cond_hilites[] array offsets, + that condition should be displayed in the default + color and attributes. + +status_finish() -- called when it is time for the window port to tear down + the status display and free allocated memory, etc. + + +E. Misc. Routines + +make_sound(???) -- To be determined later. THIS IS CURRENTLY UN-IMPLEMENTED. +nhbell() -- Beep at user. [This will exist at least until sounds are + redone, since sounds aren't attributable to windows anyway.] +mark_synch() -- Don't go beyond this point in I/O on any channel until + all channels are caught up to here. Can be an empty call + for the moment +wait_synch() -- Wait until all pending output is complete (*flush*() for + streams goes here). + -- May also deal with exposure events etc. so that the + display is OK when return from wait_synch(). +delay_output() -- Causes a visible delay of 50ms in the output. + Conceptually, this is similar to wait_synch() followed + by a nap(50ms), but allows asynchronous operation. +askname() -- Ask the user for a player name. +cliparound(x, y)-- Make sure that the user is more-or-less centered on the + screen if the playing area is larger than the screen. + -- This function is only defined if CLIPPING is defined. +number_pad(state) + -- Initialize the number pad to the given state. +suspend_nhwindows(str) + -- Prepare the window to be suspended. +resume_nhwindows() + -- Restore the windows after being suspended. +can_suspend() -- Tell the core if the window system will allow the game + to be suspended now. If unconditionally yes or no, use + genl_can_suspend_yes() or genl_can_suspend_no(). + +start_screen() -- Only used on Unix tty ports, but must be declared for + completeness. Sets up the tty to work in full-screen + graphics mode. Look at win/tty/termcap.c for an + example. If your window-port does not need this function + just declare an empty function. +end_screen() -- Only used on Unix tty ports, but must be declared for + completeness. The complement of start_screen(). + +outrip(winid, int, time_t) + -- The tombstone code. If you want the traditional code use + genl_outrip for the value and check the #if in rip.c. + +preference_update(preference) + -- The player has just changed one of the wincap preference + settings, and the NetHack core is notifying your window + port of that change. If your window-port is capable of + dynamically adjusting to the change then it should do so. + Your window-port will only be notified of a particular + change if it indicated that it wants to be by setting the + corresponding bit in the wincap mask. + +getmsghistory(init) + -- This is used to preserve message history between games by + obtaining the messages from the window port so that the + core can put them into the savefile. + The routine is called repeatedly from the core save routine, + and the window port routine is expected to successively + return each message that it wants the game to store in the + savefile, starting with the oldest message first, finishing + with the most recent. + If init is TRUE, start over again from most recent message. + +putmsghistory(msg) + -- This is the counterpart to getmsghistory() for restores + used to reload the port's message recall buffer. + The routine is called repeatedly from the core restore + routine, starting with the oldest message first, and + finishing with the most recent one that it read from the + savefile. The window port routine is expected to load the + message recall buffers in such a way that the ordering + remains correct. The window port routine should make no + assumptions about how + many messages are forthcoming, nor should it assume that + another message will follow this one, so it must be careful + to keep all pointers/indexes intact at the end of each call. + If the window port receives more messages that can fit in + its buffers, it is expected to scroll away the oldest from + its buffers, much like it would with new messages being + produced. + + +III. Global variables + +The following global variables are defined in decl.c and must be used by +the window interface to the rest of NetHack. + +char toplines[BUFSZ] Contains the last message printed to the WIN_MESSAGE + window, used by Norep(). +winid WIN_MESSAGE, WIN_MAP, WIN_INVEN + The three standard windows. + There is also a window called WIN_STATUS that is used + only for backward compatibility in the genl_status_* + set of generic status display functions. +char *AE, *AS; Checked in options.c to see if we should load and + switch to DECGraphics symset. It is #ifdefed VMS + and UNIX. +int LI, CO; Set in sys/unix/ioctl.c. + +The following appears to be Unix specific. Other ports using the tty +window-port should also declare this variable in one of your sys/*.c files. + +short ospeed; Set and declared in sys/unix/unixtty.c (don't + know about other sys files). + +The following global variable is defined in options.c. It equates a +list of wincap option names with their associated bit-mask [see +section IV WINCAP preferences support]. The array is zero-terminated. + +struct wc_Opt wc_options[]; + One entry for each available WINCAP option. + Each entry has a wc_name field and a wc_bit + field. + +IV. WINCAP preferences support + +Starting with NetHack 3.4.0, the window interface was enhanced to provide +a common way of setting window port user preferences from the config file, +and from the command line for some settings. + +The wincap preference settings all have their underlying values stored +in iflags fields. The names of the wincap related fields are all pre- +fixed with wc_ or wc2_ to make it easy to identify them. Your window +port can access the fields directly. + +Your window port identifies what options it will react to and support +by setting bits in the window_procs wincap mask and/or wincap2 mask. +Your window port can also fill in the color-availability table for +the window port, has_color[CLR_MAX] to flag the colors it supports +1 it does, or 0 it doesn't. [CLR_MAX is 16 as of 3.6.3.] + +See section IX for details of where the wincap masks reside. + +Two things control whether any preference setting appears in the +'O' command options menu during the game: + 1. The option must be marked as being supported by having its + bit set in the window_procs wincap or wincap2 mask. + 2. The option must have its optflag field set to set_in_game in order + to be able to set the option, or marked set_gameview if you just + want to reveal what the option is set to. +Both conditions must be true to be able to see or set the option from +within NetHack. + +The default values for the optflag field for all the options are +hard-coded into the option in options.c. The default value for +the wc_ options can be altered by calling + set_wc_option_mod_status(optmask, status) +The default value for the wc2_ options can be altered by calling + set_wc2_option_mod_status(optmask, status) +In each case, set the option modification status to one of set_in_config, +set_gameview, or set_in_game. + +The setting of any wincap or wincap2 option is handled by the NetHack +core option processing code. You do not have to provide a parser in +your window port, nor should you set the values for the +iflags.wc_* and iflags.wc2_* fields directly within the port code. +The port code should honor whatever values were put there by the core +when processing options, either in the config file, or by the 'O' command. + +You may be wondering what values your window port will find in the +iflags.wc_* and iflags.wc2_* fields for options that the user has not +specified in his/her config file. Put another way, how does your port code +tell if an option has not been set? The next paragraph explains that. + +If the core does not set an option, it will still be initialized +to its default value. Those default values for the +iflags.wc_* and iflags.wc_* fields are: + + o All boolean fields are initialized to the starting + value specified for that option in the boolopt array in + options.c. The window-port should respect that setting + unless it has a very good reason for not doing so. + o All int fields are initialized to zero. Zero is not a valid + setting for any of the int options, so if your port code + encounters a zero there, it can assume that the preference + option was not specified. In that case, the window-port code + should use a default setting that the port is comfortable with. + It should write the default setting back into the iflags.wc_* + field. That is the only time that your window-port could should + update those fields. + o All "char *" fields will be null pointers. Be sure to check for + that in your window-port code before using such a pointer, or + you'll end up triggering a nasty fault. + +Here are the wincap and wincap2 preference settings that your port can choose +to support: + + wincap + +--------------------+--------------------+--------------------+--------+ + | | | iflags field | data | + | player option | bit in wincap mask | for value | type | + |--------------------+--------------------+--------------------+--------+ + | align_message | WC_ALIGN_MESSAGE | wc_align_message |int | + | align_status | WC_ALIGN_STATUS | wc_align_status |int | + | ascii_map | WC_ASCII_MAP | wc_ascii_map |boolean | + | color | WC_COLOR | wc_color |boolean | + | eight_bit_tty | WC_EIGHT_BIT_IN | wc_eight_bit_input |boolean | + | font_map | WC_FONT_MAP | wc_font_map |char * | + | font_menu | WC_FONT_MENU | wc_font_menu |char * | + | font_message | WC_FONT_MESSAGE | wc_font_message |char * | + | font_status | WC_FONT_STATUS | wc_font_status |char * | + | font_text | WC_FONT_TEXT | wc_font_text |char * | + | font_size_map | WC_FONTSIZ_MAP | wc_fontsiz_map |int | + | font_size_menu | WC_FONTSIZ_MENU | wc_fontsiz_menu |int | + | font_size_message | WC_FONTSIZ_MESSAGE | wc_fontsiz_message |int | + | font_size_status | WC_FONTSIZ_STATUS | wc_fontsiz_status |int | + | font_size_text | WC_FONTSIZ_TEXT | wc_fontsiz_text |int | + | hilite_pet | WC_HILITE_PET | wc_hilite_pet |boolean | + | map_mode | WC_MAP_MODE | wc_map_mode |int | + | perm_invent | WC_PERM_INVENT | wc_perm_invent |boolean | + | player_selection | WC_PLAYER_SELECTION| wc_player_selection|int | + | popup_dialog | WC_POPUP_DIALOG | wc_popup_dialog |boolean | + | preload_tiles | WC_PRELOAD_TILES | wc_preload_tiles |boolean | + | scroll_amount | WC_SCROLL_AMOUNT | wc_scroll_amount |int | + | scroll_margin | WC_SCROLL_MARGIN | wc_scroll_margin |int | + | splash_screen | WC_SPLASH_SCREEN | wc_splash_screen |boolean | + | tiled_map | WC_TILED_MAP | wc_tiled_map |boolean | + | tile_width | WC_TILE_WIDTH | wc_tile_width |int | + | tile_height | WC_TILE_HEIGHT | wc_tile_height |int | + | tile_file | WC_TILE_FILE | wc_tile_file |char * | + | use_inverse | WC_INVERSE | wc_inverse |boolean | + | vary_msgcount | WC_VARY_MSGCOUNT | wc_vary_msgcount |int | + | windowcolors | WC_WINDOWCOLORS | wc_foregrnd_menu |char * | + | | | wc_backgrnd_menu |char * | + | | | wc_foregrnd_message|char * | + | | | wc_backgrnd_message|char * | + | | | wc_foregrnd_status |char * | + | | | wc_backgrnd_status |char * | + | | | wc_foregrnd_text |char * | + | | | wc_backgrnd_text |char * | + | mouse | WC_MOUSE_SUPPORT | wc_mouse_support |boolean | + +--------------------+--------------------+--------------------+--------+ + + wincap2 + +--------------------+--------------------+--------------------+--------+ + | | | iflags field | data | + | player option | bit in wincap mask | for value | type | + |--------------------+--------------------+--------------------+--------+ + | fullscreen | WC2_FULLSCREEN | wc2_fullscreen |boolean | + | guicolor | WC2_GUICOLOR | wc2_guicolor |boolean | + | hilite_status | WC2_HILITE_STATUS | wc2_hilite_status |strings | + | hitpointbar | WC2_HITPOINTBAR | wc2_hitpointbar |boolean | + | menu_shift_left | WC2_MENU_SHIFT | n/a |char | + | menu_shift_right | WC2_MENU_SHIFT | n/a |char | + | petattr | WC2_PETATTR | wc2_petattr |int | + | selectsaved | WC2_SELECTSAVED | wc2_selectsaved |boolean | + | softkeyboard | WC2_SOFTKEYBOARD | wc2_softkeyboard |boolean | + | statuslines | WC2_STATUSLINES | wc2_statuslines |int | + | term_cols | WC2_TERM_SIZE | wc2_term_cols |int | + | term_rows | WC2_TERM_SIZE | wc2_term_rows |int | + | use_darkgray | WC2_DARKGRAY | wc2_darkgray |boolean | + | windowborders | WC2_WINDOWBORDERS | wc2_windowborders |int | + | wraptext | WC2_WRAPTEXT | wc2_wraptext |boolean | + +--------------------+--------------------+--------------------+--------+ + + more wincap2 for STATUS_HILITES support and control + +--------------------------------- +---------------------------+ + | To inform the game engine | | + | that the window port is equipped | bit to set in wincap mask | + | to receive the following in its | | + | x_status_update() routine | | + |----------------------------------+---------------------------+ + | BL_FLUSH to render buffered | WC2_FLUSH_STATUS | + | field changes now | | + |----------------------------------+---------------------------+ + | BL_RESET to indicate that all | WC2_RESET_STATUS | + | fields should be redone | | + +----------------------------------+---------------------------+ + + additional wincap2 flag bits for supported putstr() attributes + +----------------------------------+---------------------------+ + | avoid putting message into | WC2_SUPPRESS_HIST | + | recall history | | + | draw extra attention to message | WC2_URGENT_MESG | + +----------------------------------+---------------------------+ + +align_message -- where to place message window (top, bottom, left, right) +align_status -- where to place status display (top, bottom, left, right). +ascii_map -- port should display an ascii map if it can. +color -- port should display color if it can. +eight_bit_tty -- port should allow eight bit input. +font_map -- port should use a font by this name for map window. +font_menu -- port should use a font by this name for menu windows. +font_message -- port should use a font by this name for message window. +font_size_map -- port should use this size font for the map window. +font_size_menu -- port should use this size font for menu windows. +font_size_message + -- port should use this size font for the message window. +font_size_status-- port should use this size font for the status display. +font_size_text -- port should use this size font for text windows. +font_status -- port should use a font by this name for status display. +font_text -- port should use a font by this name for text windows. +fullscreen -- port should try to use the whole screen. +hilite_pet -- port should mark pets in some special way on the map. +hitpointbar -- port should show a graphical bar representing hit points +map_mode -- port should display the map in the manner specified. +player_selection + -- dialog or prompts for choosing character. +popup_dialog -- port should pop up dialog boxes for input. +preload_tiles -- port should preload tiles into memory. +scroll_amount -- scroll this amount when scroll_margin is reached. +scroll_margin -- port should scroll the display when the hero or cursor + is this number of cells away from the edge of the window. +selectsaved -- if port can display a menu of the user's saved games do so. +softkeyboard -- handhelds should display an on-screen keyboard if possible. +splash_screen -- port should/should not display an opening splashscreen. +term_cols -- Terminal should size itself to specified width, if possible. +term_rows -- Terminal should size to specified height, if possible. +tiled_map -- port should display a tiled map if it can. +tile_width -- port should display tiles with this width or round to + closest if it can. +tile_height -- port should display tiles with this height or round to + closest if it can. +tile_file -- open this alternative tile file. The file name is likely to + be window-port or platform specific. +use_inverse -- port should display inverse when NetHack asks for it. +vary_msgcount -- port should display this number of messages at a time in + the message window. +windowborders -- port should display borders around main NetHack windows. + Can be set to (1) on, (2) off, or (3) auto. +windowcolors + -- port should use these colors for window foreground/background + colors. Syntax: + menu fore/back message fore/back status fore/back text fore/back +wraptext -- port should wrap long lines of text if they don't fit in + the visible area of the window +mouse_support -- port should enable mouse support if possible + +Whenever one of these settings is adjusted, the port is notified of a change +to the setting by calling the port's preference_update() routine. The port +is only notified if it has indicated that it supports that option by setting +the option's bit in the port's wincap mask. The port can choose to adjust +for the change to an option that it receives notification about, or ignore it. +The former approach is recommended. If you don't want to deal with a +user-initiated setting change, then the port should call +set_wc_option_mod_status(mask, set_in_config) to make the option invisible to +the user. + +Functions available for the window port to call: + +set_wc_option_mod_status(optmask, status) + -- Adjust the optflag field for a set of wincap options to + specify whether the port wants the option to appear + in the 'O' command options menu, The second parameter, + "status" can be set to set_in_config, set_gameview, + or set_in_game (set_in_config implies that the option + is completely hidden during the game). + +set_wc2_option_mod_status(optmask, status) + -- Adjust the optflag field for a set of wincap2 options to + specify whether the port wants the option to appear + in the 'O' command options menu, The second parameter, + "status" can be set to set_in_config, set_gameview, + or set_in_game (set_in_config implies that the option + is completely hidden during the game). + +set_option_mod_status(optnam, status) + -- Adjust the optflag field for one of the core options + that is not part of the wincap suite. A port might use + this to override the default initialization setting for + status specified in options.c. Note that you have to + specify the option by name and that you can only set + one option per call unlike set_wc_option_mod_status(). + + +Adding a new wincap option: + +To add a new wincap option, please follow all these steps: + 1. Add the option to the wincap preference settings table above. Since + wincap is full, your option will likely target wincap2 field. + 2. Add the description to the paragraph below the chart. + 3. Add the WC_ or WC2_ to the bit list in include/winprocs.h + (in wincap2 if there is no room in wincap). + 4. Add the wc_ or wc2_ field(s) to the iflags structure in flag.h. + 5. Add the name and value to wc_options[] or wc2_options[] in options.c + 6. Add an appropriate parser to parseoptions() in options.c. + 7. Add code to display current value to get_compopt_value() in options.c. + 8. Document the option in Guidebook.mn and Guidebook.tex. + 9. Add the bit name to the OR'd values in your window port's winprocs struct + wincap mask if your port supports the option. + +V. New or respecified common, high level routines + +These are not part of the interface, but mentioned here for your information. + +char display_inventory(lets, want_reply) + -- Calls a start_menu()/add_menu()/select_menu() sequence. + It returns the item selected, or '\0' if none is selected. + Returns '\033' if the menu was canceled. +raw_printf(str, ...) + -- Like raw_print(), but accepts arguments like printf(). This + routine processes the arguments and then calls raw_print(). + -- The mac version #defines error raw_printf. I think this + is a reasonable thing to do for most ports. +pline(str, ...) + -- Prints a string to WIN_MESSAGE using a printf() interface. + It has the variants You(), Your(), Norep(), and others + in pline.c which all use the same mechanism. pline() + requires the variable "char toplines[]" be defined; Every + putstr() on WIN_MESSAGE must copy str to toplines[] for use + by Norep() and pline(). If the window system is not active + (!iflags.window_inited) pline() uses raw_print(). + +VI. Game startup + +The following is the general order in which calls from main() should be made, +as they relate to the window system. The actual code may differ, but the +order of the calls should be the same. + + +choose_windows(DEFAULT_WINDOW_SYS) /* choose a default window system */ +initoptions() /* read the resource file */ +init_nhwindows() /* initialize the window system */ +process_options(argc, argv) /* process command line options or equiv */ +if(save file is present) { + display_gamewindows() /* create & display the game windows */ + dorestore() /* restore old game; pline()s are OK */ +} else { + player_selection() /* select a player type using a window */ + display_gamewindows() /* create & display the game windows */ +} +pline("Hello, welcome..."); + +Choose_windows() is a common routine, and calling it in main() is necessary +to initialize the function pointer table to _something_ so that calls to +raw_print() will not fail. Choose_windows() should be called almost +immediately upon entering main(). Look at unixmain.c for an example. +Choose_windows will call an (optional) ini_routine with a single argument +of WININIT to allow any needed setup. Because choose_windows() may be called +multiple times during argument and option processing, to handle the case where +ini_routines have side effects that need to be undone, the old ini_routine (if +any) will be called with an argument of WININIT_UNDO before the new +ini_routine (if any) is called (with WININIT). + +Display_gamewindows() is a common routine that displays the two standard +game windows (WIN_MESSAGE, WIN_MAP), and the status display. It is normally +called just before the "Hello, welcome" message. + +Process_options() is currently still unique to each port. There may be need +in the future to make it possible to replace this on a per window-port basis. + + +VII. Conventions + +init_nhwindows() is expected to display a gee-whiz banner window, including +the Copyright message. It is recommended that the COPYRIGHT_BANNER_A macro +from patchlevel.h, COPYRIGHT_BANNER_B from patchlevel.h, +nomakedefs.copyright_banner_c internal global variable, and +COPYRIGHT_BANNER_D macros from patchlevel.h be used for constructing the +Copyright message. +COPYRIGHT_BANNER_A is a quoted string that has NetHack copyright declaration, +COPYRIGHT_BANNER_B is a quoted string that states who the copyright belongs to, +nomakedefs.copyright_banner_c is a quoted string produced at runtime that +includes version and build information, and +COPYRIGHT_BANNER_D simply says "See License for details." +Be sure to #include "patchlevel.h" to define these macros. Using +the macros will prevent having to update the Copyright information in each +window-port prior to each release. + +Ports (MSDOS, TOS, MAC, etc) _may_ use window-port specific routines in +their port specific files, _AT_THEIR_OWN_RISK_. Since "port" and +"window-port" are orthogonal, you make your "port" code less portable by +using "window-port" specific routines. Every effort should be made to +use window-port interface routines, unless there is something port +specific that is better suited (e.g. msmsg() for MSDOS). + +The tty window-port is contained in win/tty, the X window port is contained +in win/X11. The files in these directories contain _only_ window port code, +and may be replaced completely by other window ports. + + +VIII. Implementation and Multi-window support + +NetHack 3.2 and higher support multiple window systems in the same binary. +When writing a new window-port, you need to follow the following guidelines: + +1) Pick a unique prefix to identify your window-port. For example, the tty + window port uses "tty"; the X11 window-port uses "X11". +2) When declaring your interface function, precede the function names with + your unique prefix. E.g: + + void tty_init_nhwindows() + { + /* code for initializing windows in the tty port */ + } + + When calling window functions from within your port code, we suggest + calling the prefixed version to avoid unnecessary overhead. However, + you may safely call the non-prefixed version (e.g. putstr() rather than + tty_putstr()) as long as you #include "hack.h". If you do not + include hack.h and use the non-prefixed names, you will get compile + or link-time errors. + + We also suggest declaring all functions and port-specific data with + this prefix to avoid unexpected overlaps with other window-ports. + The tty and X11 ports do not currently follow this suggestion, but do + use separate non-overlapping convention for naming data and internal + functions. + +3) Declare a structure, "struct window_procs prefix_procs", (with your + prefix instead of "prefix") and fill in names of all of your + interface functions. The first entry in this structure is the name + of your window-port, which should be the prefix. The second entry + is the wincap mask that identifies what window port preference + settings your port will react to and support. The other entries + are the function addresses. + + Assuming that you followed the convention in (2), you can safely copy + the structure definition from an existing window-port and just change + the prefixes. That will guarantee that you get the order of your + initializations correct (not all compilers will catch out-of-order + function pointer declarations). + +4) Add a #define to config.h identifying your window-port in the + "Windowing systems" section. Follow the "prefix_GRAPHICS" convention + for your window-port. + +5) Add your prefix to the list of valid prefixes listed in the "Known + systems are" comment. + +6) Edit makedefs.c and add a string for your windowing system to window_opts + inside an #ifdef prefix_GRAPHICS. + +7) Edit windows.c and add an external reference to your prefix_procs inside + an #ifdef prefix_GRAPHICS. Also add an entry to the win_choices + structure for your window-port of the form: + + #ifdef prefix_GRAPHICS + { &prefix_procs, prefix_init_function }, + #endif + + The init_function is necessary for some compilers and systems to force + correct linking. If your system does not need such massaging, you + may put a null pointer here. + + You should declare prefix_procs and prefix_init_function as extern's + in your win*.h file, and #include that file at the beginning of + windows.c, also inside an #ifdef prefix_GRAPHICS. Some win*.h files + are rather sensitive, and you might have to duplicate your + prefix_procs and prefix_init_function's instead of including win*.h. + The tty port includes wintty.h, the X11 port duplicates the declarations. + +8) If your port uses Makefile.src, add the .c and .o files and an + appropriate comment in the section on "WINSRC" and "WINOBJ". See + Makefile.src for the style to use. If you don't use Makefile.src, + we suggest using a similar convention for the make-equivalent used + on your system. Also add your new source and binaries to WINSRC and + WINOBJ (if you want the NetHack binary to include them, that is). + +9) Look at your port's portmain.c (the file containing main()) and make + sure that all of the calls match the requirements laid out in + Section VII. + +Now, proceed with compilation and installation as usual. Don't forget +to edit Makefile.src (or its equivalent) and config.h to set the +window-ports you want in your binary, the default window-port to use, +and the .o's needed to build a valid game. + +One caveat. Unfortunately, if you incorrectly specify the +DEFAULT_WINDOW_SYS, NetHack will dump core (or whatever) without +printing any message, because raw_print() cannot function without first +setting the window-port. + + +IX. WINCHAIN + +WINCHAIN is an optional facility that allows the SYSCF_FILE to specify a +series of processors that will see each call from the core to the window +port (and the resulting return chain). Processors are specified one at a +time from the start of the chain (the core end) towards the window port as: + OPTIONS=windowchain:+PROC +where PROC is the name of the processor to add to the chain. The '+' is +required and is part of the name of the processor (this distinguishes +processors from window ports; in addition the '-' character is reserved for +WINCHAIN internals). + +If WINCHAIN is not compiled into the NetHack binary, there is no overhead. + +If WINCHAIN is compiled into the NetHack binary but not used, overhead is +limited to one function call during game setup and a trivial amount of data. + +Note that raw_print* calls will not go through the chain until initialization +is complete (when *main.c calls commit_windowchain()). + +The only processor currently available is '+trace' which is a debugging +facility for window ports. See the code in win/chain/wc_trace.c for +details on where to find the log file and how to write to it from other parts +of the code. + +A processor may be specified more than once; this is expected to be most +useful for surrounding a processor being developed with before and after +calls to +trace.