diff --git a/doc/window.doc b/doc/window.doc index 72f24fe41..3a827fbac 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -402,14 +402,56 @@ 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. See section IX for -details of where the wincap mask resides. Any preference settings -marked as being supported by having its bit set in the wincap mask -will be available for the user of your window port to set via the 'O' -command, while those not marked as supported will not appear in the -menus of the 'O' command. +details of where the wincap mask resides. -Setting of any wincap option is handled by the NetHack core option -code, you do not have to provide a parser in your window port. +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 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 DISP_IN_GAME 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 options can be altered by calling + set_wc_option_mod_status(optmask, status) +specifying the option modification status to one of SET_IN_FILE, +DISP_IN_GAME, or SET_IN_GAME. + +The setting of any wincap 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_* 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_* fields for options that the user has not specified +in his/her config file. Put another way, how does you 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_* 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 preference settings that your port can choose to support: @@ -481,10 +523,26 @@ 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. -Whenever one of these settings is adjusted (and if supported by the port -by marking it so in the wincap mask), the port is notified of a change +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 -can choose to adjust for the change or ignore it. +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_FILE) 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 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_FILE, DISP_IN_GAME, + or SET_IN_GAME (SET_IN_FILE implies that the option + is completely hidden during the game). + V. New or respecified common, high level routines diff --git a/include/extern.h b/include/extern.h index 58759288a..952161966 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1341,6 +1341,8 @@ E char FDECL(map_menu_cmd, (CHAR_P)); E void FDECL(assign_warnings, (uchar *)); E char *FDECL(nh_getenv, (const char *)); E void FDECL(set_duplicate_opt_detection, (int)); +E void FDECL(set_wc_option_mod_status, (unsigned long, int)); +E void FDECL(set_option_mod_status, (char *, int)); /* ### pager.c ### */ diff --git a/include/hack.h b/include/hack.h index 23187ec93..4e6362b03 100644 --- a/include/hack.h +++ b/include/hack.h @@ -238,6 +238,16 @@ NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ #define MENU_SELECTED TRUE #define MENU_UNSELECTED FALSE +/* + * Option flags + * Each higher number includes the characteristics of the numbers + * below it. + */ +#define SET_IN_FILE 0 /* config file option only */ +#define SET_VIA_PROG 1 /* may be set via extern program, not seen in game */ +#define DISP_IN_GAME 2 /* may be set via extern program, displayed in game */ +#define SET_IN_GAME 3 /* may be set via extern program or set in the game */ + #define FEATURE_NOTICE_VER(major,minor,patch) (((unsigned long)major << 24) | \ ((unsigned long)minor << 16) | \ ((unsigned long)patch << 8) | \ diff --git a/src/options.c b/src/options.c index 2b6a01a3e..a0c7759ef 100644 --- a/src/options.c +++ b/src/options.c @@ -24,17 +24,6 @@ NEARDATA struct instance_flags iflags; /* provide linkage */ * and also the Guidebooks. */ -/* - * Option flags - * Each higher number includes the characteristics of the numbers - * below it. - */ -#define SET_IN_FILE 0 /* config file option only, not visible in game - * or via program */ -#define SET_VIA_PROG 1 /* may be set via extern program, not seen in game */ -#define DISP_IN_GAME 2 /* may be set via extern program, displayed in game */ -#define SET_IN_GAME 3 /* may be set via extern program or set in the game */ - static struct Bool_Opt { const char *name; @@ -3058,6 +3047,64 @@ struct wc_Opt wc_options[] = { {(char *)0, 0L} }; + +/* + * If a port wants to change or ensure that the + * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is + * correct (for controlling its display in the option menu) call + * set_option_mod_status() + * with the second argument of 0,2, or 3 respectively. + */ +void +set_option_mod_status(optnam, status) +char *optnam; +int status; +{ + int k; + if (status < SET_IN_FILE || status > SET_IN_GAME) { + impossible("set_option_mod_status: status out of range %d.", status); + return; + } + for (k = 0; boolopt[k].name; k++) { + if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) { + boolopt[k].optflags = status; + return; + } + } + for (k = 0; compopt[k].name; k++) { + if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) { + compopt[k].optflags = status; + return; + } + } +} + +/* + * You can set several wc_options in one call to + * set_wc_option_mod_status() by setting + * the appropriate bits for each option that you + * are setting in the optmask argument + * prior to calling. + * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME); + */ +void +set_wc_option_mod_status(optmask, status) +unsigned long optmask; +int status; +{ + int k = 0; + if (status < SET_IN_FILE || status > SET_IN_GAME) { + impossible("set_option_mod_status: status out of range %d.", status); + return; + } + while (wc_options[k].wc_name) { + if (optmask & wc_options[k].wc_bit) { + set_option_mod_status(wc_options[k].wc_name, status); + } + k++; + } +} + STATIC_OVL boolean is_wc_option(optnam) const char *optnam;