Source:NetHack 3.4.3/src/options.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to src/options.c from NetHack 3.4.3. To link to a particular line, write [[options.c#line123]], for example.

Top of file

/*	SCCS Id: @(#)options.c	3.4	2003/11/14	*/
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

#ifdef OPTION_LISTS_ONLY	/* (AMIGA) external program for opt lists */
#include "config.h"
#include "objclass.h"
#include "flag.h"
NEARDATA struct flag flags;	/* provide linkage */
NEARDATA struct instance_flags iflags;	/* provide linkage */
#define static
#else
#include "hack.h"
#include "tcap.h"
#include <ctype.h>
#endif

#define WINTYPELEN 16

#ifdef DEFAULT_WC_TILED_MAP
#define PREFER_TILED TRUE
#else
#define PREFER_TILED FALSE
#endif

Bool_Opt

/*
*  NOTE:  If you add (or delete) an option, please update the short
*  options help (option_help()), the long options help (dat/opthelp),
*  and the current options setting display function (doset()),
*  and also the Guidebooks.
*
*  The order matters.  If an option is a an initial substring of another
*  option (e.g. time and timed_delay) the shorter one must come first.
*/

static struct Bool_Opt
{
	const char *name;
	boolean	*addr, initvalue;
	int optflags;
} boolopt[] = {
#ifdef AMIGA
	{"altmeta", &flags.altmeta, TRUE, DISP_IN_GAME},
#else
	{"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
#endif
	{"ascii_map",     &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME},	/*WC*/
#ifdef MFLOPPY
	{"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME},
#else
	{"asksavedisk", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"autodig", &flags.autodig, FALSE, SET_IN_GAME},
	{"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
	{"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
#if defined(MICRO) && !defined(AMIGA)
	{"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE},
#else
	{"BIOS", (boolean *)0, FALSE, SET_IN_FILE},
#endif
#ifdef INSURANCE
	{"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME},
#else
	{"checkpoint", (boolean *)0, FALSE, SET_IN_FILE},
#endif
#ifdef MFLOPPY
	{"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME},
#else
	{"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
# if defined(MICRO) || defined(WIN32)
	{"color",         &iflags.wc_color,TRUE, SET_IN_GAME},		/*WC*/
# else	/* systems that support multiple terminals, many monochrome */
	{"color",         &iflags.wc_color, FALSE, SET_IN_GAME},	/*WC*/
# endif
	{"confirm",&flags.confirm, TRUE, SET_IN_GAME},
#if defined(TERMLIB) && !defined(MAC_GRAPHICS_ENV)
	{"DECgraphics", &iflags.DECgraphics, FALSE, SET_IN_GAME},
#else
	{"DECgraphics", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME},	/*WC*/
#ifdef TTY_GRAPHICS
	{"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME},
#else
	{"extmenu", (boolean *)0, FALSE, SET_IN_FILE},
#endif
#ifdef OPT_DISPMAP
	{"fast_map", &flags.fast_map, TRUE, SET_IN_GAME},
#else
	{"fast_map", (boolean *)0, TRUE, SET_IN_FILE},
#endif
	{"female", &flags.female, FALSE, DISP_IN_GAME},
	{"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME},
#ifdef AMIFLUSH
	{"flush", &flags.amiflush, FALSE, SET_IN_GAME},
#else
	{"flush", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE},
	{"help", &flags.help, TRUE, SET_IN_GAME},
	{"hilite_pet",    &iflags.wc_hilite_pet, FALSE, SET_IN_GAME},	/*WC*/
#ifdef ASCIIGRAPH
	{"IBMgraphics", &iflags.IBMgraphics, FALSE, SET_IN_GAME},
#else
	{"IBMgraphics", (boolean *)0, FALSE, SET_IN_FILE},
#endif
#ifndef MAC
	{"ignintr", &flags.ignintr, FALSE, SET_IN_GAME},
#else
	{"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"large_font", &iflags.obsolete, FALSE, SET_IN_FILE},	/* OBSOLETE */
	{"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
	{"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
	{"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME},
#ifdef MAC_GRAPHICS_ENV
	{"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME},
#else
	{"Macgraphics", (boolean *)0, FALSE, SET_IN_FILE},
#endif
#ifdef MAIL
	{"mail", &flags.biff, TRUE, SET_IN_GAME},
#else
	{"mail", (boolean *)0, TRUE, SET_IN_FILE},
#endif
#ifdef WIZARD
	/* for menu debugging only*/
	{"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
#else
	{"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME},	/*WC*/
#ifdef NEWS
	{"news", &iflags.news, TRUE, DISP_IN_GAME},
#else
	{"news", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"null", &flags.null, TRUE, SET_IN_GAME},
#ifdef MAC
	{"page_wait", &flags.page_wait, TRUE, SET_IN_GAME},
#else
	{"page_wait", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME},
	{"popup_dialog",  &iflags.wc_popup_dialog, FALSE, SET_IN_GAME},	/*WC*/
	{"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME},
	{"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME},	/*WC*/
	{"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
#if defined(MICRO) && !defined(AMIGA)
	{"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
#else
	{"rawio", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
	{"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
#ifdef WIZARD
	{"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
#else
	{"sanity_check", (boolean *)0, FALSE, SET_IN_FILE},
#endif
#ifdef EXP_ON_BOTL
	{"showexp", &flags.showexp, FALSE, SET_IN_GAME},
#else
	{"showexp", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"showrace", &iflags.showrace, FALSE, SET_IN_GAME},
#ifdef SCORE_ON_BOTL
	{"showscore", &flags.showscore, FALSE, SET_IN_GAME},
#else
	{"showscore", (boolean *)0, FALSE, SET_IN_FILE},
#endif
	{"silent", &flags.silent, TRUE, SET_IN_GAME},
	{"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE},
	{"sortpack", &flags.sortpack, TRUE, SET_IN_GAME},
	{"sound", &flags.soundok, TRUE, SET_IN_GAME},
	{"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
	{"standout", &flags.standout, FALSE, SET_IN_GAME},
	{"splash_screen",     &iflags.wc_splash_screen, TRUE, DISP_IN_GAME},	/*WC*/
	{"tiled_map",     &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME},	/*WC*/
	{"time", &flags.time, FALSE, SET_IN_GAME},
#ifdef TIMED_DELAY
	{"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
#else
	{"timed_delay", (boolean *)0, FALSE, SET_IN_GAME},
#endif
	{"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
	{"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME},
	{"travel", &iflags.travelcmd, TRUE, SET_IN_GAME},
#ifdef WIN32CON
	{"use_inverse",   &iflags.wc_inverse, TRUE, SET_IN_GAME},		/*WC*/
#else
	{"use_inverse",   &iflags.wc_inverse, FALSE, SET_IN_GAME},		/*WC*/
#endif
	{"verbose", &flags.verbose, TRUE, SET_IN_GAME},
	{"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
	{(char *)0, (boolean *)0, FALSE, 0}
};

Comp_Opt

/* compound options, for option_help() and external programs like Amiga
* frontend */
static struct Comp_Opt
{
	const char *name, *descr;
	int size;	/* for frontends and such allocating space --
			 * usually allowed size of data in game, but
			 * occasionally maximum reasonable size for
			 * typing when game maintains information in
			 * a different format */
	int optflags;
} compopt[] = {
	{ "align",    "your starting alignment (lawful, neutral, or chaotic)",
						8, DISP_IN_GAME },
	{ "align_message", "message window alignment", 20, DISP_IN_GAME }, 	/*WC*/
	{ "align_status", "status window alignment", 20, DISP_IN_GAME }, 	/*WC*/
	{ "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
	{ "boulder",  "the symbol to use for displaying boulders",
						1, SET_IN_GAME },
	{ "catname",  "the name of your (first) cat (e.g., catname:Tabby)",
						PL_PSIZ, DISP_IN_GAME },
	{ "disclose", "the kinds of information to disclose at end of game",
						sizeof(flags.end_disclose) * 2,
						SET_IN_GAME },
	{ "dogname",  "the name of your (first) dog (e.g., dogname:Fang)",
						PL_PSIZ, DISP_IN_GAME },
	{ "dungeon",  "the symbols to use in drawing the dungeon map",
						MAXDCHARS+1, SET_IN_FILE },
	{ "effects",  "the symbols to use in drawing special effects",
						MAXECHARS+1, SET_IN_FILE },
	{ "font_map", "the font to use in the map window", 40, DISP_IN_GAME },	/*WC*/
	{ "font_menu", "the font to use in menus", 40, DISP_IN_GAME },		/*WC*/
	{ "font_message", "the font to use in the message window",
						40, DISP_IN_GAME },		/*WC*/
	{ "font_size_map", "the size of the map font", 20, DISP_IN_GAME },	/*WC*/
	{ "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME },	/*WC*/
	{ "font_size_message", "the size of the message font", 20, DISP_IN_GAME },	/*WC*/
	{ "font_size_status", "the size of the status font", 20, DISP_IN_GAME },	/*WC*/
	{ "font_size_text", "the size of the text font", 20, DISP_IN_GAME },	/*WC*/
	{ "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/
	{ "font_text", "the font to use in text windows", 40, DISP_IN_GAME },	/*WC*/
	{ "fruit",    "the name of a fruit you enjoy eating",
						PL_FSIZ, SET_IN_GAME },
	{ "gender",   "your starting gender (male or female)",
						8, DISP_IN_GAME },
	{ "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
						PL_PSIZ, DISP_IN_GAME },
	{ "map_mode", "map display mode under Windows", 20, DISP_IN_GAME },	/*WC*/
	{ "menustyle", "user interface for object selection",
						MENUTYPELEN, SET_IN_GAME },
	{ "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
	{ "menu_deselect_page", "deselect all items on this page of a menu",
						4, SET_IN_FILE },
	{ "menu_first_page", "jump to the first page in a menu",
						4, SET_IN_FILE },
	{ "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME },
	{ "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
	{ "menu_invert_page", "invert all items on this page of a menu",
						4, SET_IN_FILE },
	{ "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
	{ "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
	{ "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
	{ "menu_search", "search for a menu item", 4, SET_IN_FILE },
	{ "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
	{ "menu_select_page", "select all items on this page of a menu",
						4, SET_IN_FILE },
	{ "monsters", "the symbols to use for monsters",
						MAXMCLASSES, SET_IN_FILE },
	{ "msghistory", "number of top line messages to save",
						5, DISP_IN_GAME },
# ifdef TTY_GRAPHICS
	{"msg_window", "the type of message window required",1, SET_IN_GAME},
# else
	{"msg_window", "the type of message window required", 1, SET_IN_FILE},
# endif
	{ "name",     "your character's name (e.g., name:Merlin-W)",
						PL_NSIZ, DISP_IN_GAME },
	{ "number_pad", "use the number pad", 1, SET_IN_GAME},
	{ "objects",  "the symbols to use for objects",
						MAXOCLASSES, SET_IN_FILE },
	{ "packorder", "the inventory order of the items in your pack",
						MAXOCLASSES, SET_IN_GAME },
#ifdef CHANGE_COLOR
	{ "palette",  "palette (00c/880/-fff is blue/yellow/reverse white)",
						15 , SET_IN_GAME },
# if defined(MAC)
	{ "hicolor",  "same as palette, only order is reversed",
						15, SET_IN_FILE },
# endif
#endif
	{ "pettype",  "your preferred initial pet type", 4, DISP_IN_GAME },
	{ "pickup_burden",  "maximum burden picked up before prompt",
						20, SET_IN_GAME },
	{ "pickup_types", "types of objects to pick up automatically",
						MAXOCLASSES, SET_IN_GAME },
	{ "player_selection", "choose character via dialog or prompts",
						12, DISP_IN_GAME },
	{ "race",     "your starting race (e.g., Human, Elf)",
						PL_CSIZ, DISP_IN_GAME },
	{ "role",     "your starting role (e.g., Barbarian, Valkyrie)",
						PL_CSIZ, DISP_IN_GAME },
	{ "runmode", "display frequency when `running' or `travelling'",
						sizeof "teleport", SET_IN_GAME },
	{ "scores",   "the parts of the score list you wish to see",
						32, SET_IN_GAME },
	{ "scroll_amount", "amount to scroll map when scroll_margin is reached",
						20, DISP_IN_GAME }, /*WC*/
	{ "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
#ifdef MSDOS
	{ "soundcard", "type of sound card to use", 20, SET_IN_FILE },
#endif
	{ "suppress_alert", "suppress alerts about version-specific features",
						8, SET_IN_GAME },
	{ "tile_width", "width of tiles", 20, DISP_IN_GAME},	/*WC*/
	{ "tile_height", "height of tiles", 20, DISP_IN_GAME},	/*WC*/
	{ "tile_file", "name of tile file", 70, DISP_IN_GAME},	/*WC*/
	{ "traps",    "the symbols to use in drawing traps",
						MAXTCHARS+1, SET_IN_FILE },
	{ "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
#ifdef MSDOS
	{ "video",    "method of video updating", 20, SET_IN_FILE },
#endif
#ifdef VIDEOSHADES
	{ "videocolors", "color mappings for internal screen routines",
						40, DISP_IN_GAME },
	{ "videoshades", "gray shades to map to black/gray/white",
						32, DISP_IN_GAME },
#endif
#ifdef WIN32CON
	{"subkeyvalue", "override keystroke value", 7, SET_IN_FILE},
#endif
	{ "windowcolors",  "the foreground/background colors of windows",	/*WC*/
						80, DISP_IN_GAME },
	{ "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
	{ (char *)0, (char *)0, 0, 0 }
};
#ifdef OPTION_LISTS_ONLY
#undef static

#else	/* use rest of file */

static boolean need_redraw; /* for doset() */

#if defined(TOS) && defined(TEXTCOLOR)
extern boolean colors_changed;	/* in tos.c */
#endif

#ifdef VIDEOSHADES
extern char *shade[3];		  /* in sys/msdos/video.c */
extern char ttycolors[CLR_MAX];	  /* in sys/msdos/video.c */
#endif

static char def_inv_order[MAXOCLASSES] = {
	COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
	SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
	TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
};

Menu accelerators

/*
* Default menu manipulation command accelerators.  These may _not_ be:
*
*	+ a number - reserved for counts
*	+ an upper or lower case US ASCII letter - used for accelerators
*	+ ESC - reserved for escaping the menu
*	+ NULL, CR or LF - reserved for commiting the selection(s).  NULL
*	  is kind of odd, but the tty's xwaitforspace() will return it if
*	  someone hits a <ret>.
*	+ a default object class symbol - used for object class accelerators
*
* Standard letters (for now) are:
*
*		<  back 1 page
*		>  forward 1 page
*		^  first page
*		|  last page
*		:  search
*
*		page		all
*		 ,    select	 .
*		 \    deselect	 -
*		 ~    invert	 @
*
* The command name list is duplicated in the compopt array.
*/
typedef struct {
const char *name;
char cmd;
} menu_cmd_t;

#define NUM_MENU_CMDS 11
static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
/* 0*/	{ "menu_first_page",	MENU_FIRST_PAGE },
	{ "menu_last_page",	MENU_LAST_PAGE },
	{ "menu_next_page",	MENU_NEXT_PAGE },
	{ "menu_previous_page",	MENU_PREVIOUS_PAGE },
	{ "menu_select_all",	MENU_SELECT_ALL },
/* 5*/	{ "menu_deselect_all",	MENU_UNSELECT_ALL },
	{ "menu_invert_all",	MENU_INVERT_ALL },
	{ "menu_select_page",	MENU_SELECT_PAGE },
	{ "menu_deselect_page",	MENU_UNSELECT_PAGE },
	{ "menu_invert_page",	MENU_INVERT_PAGE },
/*10*/	{ "menu_search",		MENU_SEARCH },
};
/*
* Allow the user to map incoming characters to various menu commands.
* The accelerator list must be a valid C string.
*/
#define MAX_MENU_MAPPED_CMDS 32	/* some number */
char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1];	/* exported */
static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1];
static short n_menu_mapped = 0;


static boolean initial, from_file;

STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int));
STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
STATIC_DCL void FDECL(escapes, (const char *, char *));
STATIC_DCL void FDECL(rejectoption, (const char *));
STATIC_DCL void FDECL(badoption, (const char *));
STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P));
STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P));
STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P));
STATIC_DCL int FDECL(change_inv_order, (char *));
STATIC_DCL void FDECL(oc_to_str, (char *, char *));
STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int));
STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(warning_opts, (char *,const char *));
STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int));

STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
STATIC_OVL int FDECL(wc_set_window_colors, (char *));
STATIC_OVL boolean FDECL(is_wc_option, (const char *));
STATIC_OVL boolean FDECL(wc_supported, (const char *));
STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
STATIC_OVL boolean FDECL(wc2_supported, (const char *));
#ifdef AUTOPICKUP_EXCEPTIONS
STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
#endif

match_optname

/* check whether a user-supplied option string is a proper leading
substring of a particular option name; option string might have
a colon or equals sign and arbitrary value appended to it */
boolean
match_optname(user_string, opt_name, min_length, val_allowed)
const char *user_string, *opt_name;
int min_length;
boolean val_allowed;
{
	int len = (int)strlen(user_string);

	if (val_allowed) {
	    const char *p = index(user_string, ':'),
		       *q = index(user_string, '=');

	    if (!p || (q && q < p)) p = q;
	    while(p && p > user_string && isspace(*(p-1))) p--;
	    if (p) len = (int)(p - user_string);
	}

	return (len >= min_length) && !strncmpi(opt_name, user_string, len);
}

nh_getenv

/* most environment variables will eventually be printed in an error
* message if they don't work, and most error message paths go through
* BUFSZ buffers, which could be overflowed by a maliciously long
* environment variable.  if a variable can legitimately be long, or
* if it's put in a smaller buffer, the responsible code will have to
* bounds-check itself.
*/
char *
nh_getenv(ev)
const char *ev;
{
	char *getev = getenv(ev);

	if (getev && strlen(getev) <= (BUFSZ / 2))
		return getev;
	else
		return (char *)0;
}

initoptions

void
initoptions()
{
#ifndef MAC
	char *opts;
#endif
	int i;

	/* initialize the random number generator */
	setrandom();

	/* for detection of configfile options specified multiple times */
	iflags.opt_booldup = iflags.opt_compdup = (int *)0;
	
	for (i = 0; boolopt[i].name; i++) {
		if (boolopt[i].addr)
			*(boolopt[i].addr) = boolopt[i].initvalue;
	}
	flags.end_own = FALSE;
	flags.end_top = 3;
	flags.end_around = 2;
	iflags.runmode = RUN_LEAP;
	iflags.msg_history = 20;
#ifdef TTY_GRAPHICS
	iflags.prevmsg_window = 's';
#endif
	iflags.menu_headings = ATR_INVERSE;

	/* Use negative indices to indicate not yet selected */
	flags.initrole = -1;
	flags.initrace = -1;
	flags.initgend = -1;
	flags.initalign = -1;

	/* Set the default monster and object class symbols.  Don't use */
	/* memcpy() --- sizeof char != sizeof uchar on some machines.	*/
	for (i = 0; i < MAXOCLASSES; i++)
		oc_syms[i] = (uchar) def_oc_syms[i];
	for (i = 0; i < MAXMCLASSES; i++)
		monsyms[i] = (uchar) def_monsyms[i];
	for (i = 0; i < WARNCOUNT; i++)
		warnsyms[i] = def_warnsyms[i].sym;
	iflags.bouldersym = 0;
	iflags.travelcc.x = iflags.travelcc.y = -1;
	flags.warnlevel = 1;
	flags.warntype = 0L;

/* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
	(void)memcpy((genericptr_t)flags.inv_order,
		     (genericptr_t)def_inv_order, sizeof flags.inv_order);
	flags.pickup_types[0] = '\0';
	flags.pickup_burden = MOD_ENCUMBER;

	for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
		flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
	switch_graphics(ASCII_GRAPHICS);	/* set default characters */
#if defined(UNIX) && defined(TTY_GRAPHICS)
	/*
	 * Set defaults for some options depending on what we can
	 * detect about the environment's capabilities.
	 * This has to be done after the global initialization above
	 * and before reading user-specific initialization via
	 * config file/environment variable below.
	 */
	/* this detects the IBM-compatible console on most 386 boxes */
	if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
		switch_graphics(IBM_GRAPHICS);
# ifdef TEXTCOLOR
		iflags.use_color = TRUE;
# endif
	}
#endif /* UNIX && TTY_GRAPHICS */
#if defined(UNIX) || defined(VMS)
# ifdef TTY_GRAPHICS
	/* detect whether a "vt" terminal can handle alternate charsets */
	if ((opts = nh_getenv("TERM")) &&
	    !strncmpi(opts, "vt", 2) && AS && AE &&
	    index(AS, '\016') && index(AE, '\017')) {
		switch_graphics(DEC_GRAPHICS);
	}
# endif
#endif /* UNIX || VMS */

#ifdef MAC_GRAPHICS_ENV
	switch_graphics(MAC_GRAPHICS);
#endif /* MAC_GRAPHICS_ENV */
	flags.menu_style = MENU_FULL;

	/* since this is done before init_objects(), do partial init here */
	objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
	nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
#ifndef MAC
	opts = getenv("NETHACKOPTIONS");
	if (!opts) opts = getenv("HACKOPTIONS");
	if (opts) {
		if (*opts == '/' || *opts == '\\' || *opts == '@') {
			if (*opts == '@') opts++;	/* @filename */
			/* looks like a filename */
			if (strlen(opts) < BUFSZ/2)
			    read_config_file(opts);
		} else {
			read_config_file((char *)0);
			/* let the total length of options be long;
			 * parseoptions() will check each individually
			 */
			parseoptions(opts, TRUE, FALSE);
		}
	} else
#endif
		read_config_file((char *)0);

	(void)fruitadd(pl_fruit);
	/* Remove "slime mold" from list of object names; this will	*/
	/* prevent it from being wished unless it's actually present	*/
	/* as a named (or default) fruit.  Wishing for "fruit" will	*/
	/* result in the player's preferred fruit [better than "\033"].	*/
	obj_descr[SLIME_MOLD].oc_name = "fruit";

	return;
}

nmcpy

STATIC_OVL void
nmcpy(dest, src, maxlen)
	char	*dest;
	const char *src;
	int	maxlen;
{
	int	count;

	for(count = 1; count < maxlen; count++) {
		if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
		*dest++ = *src++;
	}
	*dest = 0;
}

escapes

/*
* escapes: escape expansion for showsyms. C-style escapes understood include
* \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
* for control characters is also understood, and \[mM] followed by any of the
* previous forms or by a character has the effect of 'meta'-ing the value (so
* that the alternate character set will be enabled).
*/
STATIC_OVL void
escapes(cp, tp)
const char	*cp;
char *tp;
{
while (*cp)
{
	int	cval = 0, meta = 0;

	if (*cp == '\\' && index("mM", cp[1])) {
		meta = 1;
		cp += 2;
	}
	if (*cp == '\\' && index("0123456789xXoO", cp[1]))
	{
	    const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
	    int dcount = 0;

	    cp++;
	    if (*cp == 'x' || *cp == 'X')
		for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
		    cval = (cval * 16) + (dp - hex) / 2;
	    else if (*cp == 'o' || *cp == 'O')
		for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
		    cval = (cval * 8) + (*cp - '0');
	    else
		for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
		    cval = (cval * 10) + (*cp - '0');
	}
	else if (*cp == '\\')		/* C-style character escapes */
	{
	    switch (*++cp)
	    {
	    case '\\': cval = '\\'; break;
	    case 'n': cval = '\n'; break;
	    case 't': cval = '\t'; break;
	    case 'b': cval = '\b'; break;
	    case 'r': cval = '\r'; break;
	    default: cval = *cp;
	    }
	    cp++;
	}
	else if (*cp == '^')		/* expand control-character syntax */
	{
	    cval = (*++cp & 0x1f);
	    cp++;
	}
	else
	    cval = *cp++;
	if (meta)
	    cval |= 0x80;
	*tp++ = cval;
}
*tp = '\0';
}

rejectoption

STATIC_OVL void
rejectoption(optname)
const char *optname;
{
#ifdef MICRO
	pline("\"%s\" settable only from %s.", optname, configfile);
#else
	pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
			configfile);
#endif
}

badoption

STATIC_OVL void
badoption(opts)
const char *opts;
{
	if (!initial) {
	    if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
		option_help();
	    else
		pline("Bad syntax: %s.  Enter \"?g\" for help.", opts);
	    return;
	}
#ifdef MAC
	else return;
#endif

	if(from_file)
	    raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
	else
	    raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts);

	wait_synch();
}

string_for_opt

STATIC_OVL char *
string_for_opt(opts, val_optional)
char *opts;
boolean val_optional;
{
	char *colon, *equals;

	colon = index(opts, ':');
	equals = index(opts, '=');
	if (!colon || (equals && equals < colon)) colon = equals;

	if (!colon || !*++colon) {
		if (!val_optional) badoption(opts);
		return (char *)0;
	}
	return colon;
}

string_for_env_opt

STATIC_OVL char *
string_for_env_opt(optname, opts, val_optional)
const char *optname;
char *opts;
boolean val_optional;
{
	if(!initial) {
		rejectoption(optname);
		return (char *)0;
	}
	return string_for_opt(opts, val_optional);
}

bad_negation

STATIC_OVL void
bad_negation(optname, with_parameter)
const char *optname;
boolean with_parameter;
{
	pline_The("%s option may not %sbe negated.",
		optname,
		with_parameter ? "both have a value and " : "");
}

change_inv_order

/*
* Change the inventory order, using the given string as the new order.
* Missing characters in the new order are filled in at the end from
* the current inv_order, except for gold, which is forced to be first
* if not explicitly present.
*
* This routine returns 1 unless there is a duplicate or bad char in
* the string.
*/
STATIC_OVL int
change_inv_order(op)
char *op;
{
int oc_sym, num;
char *sp, buf[BUFSZ];

num = 0;
#ifndef GOLDOBJ
if (!index(op, GOLD_SYM))
	buf[num++] = COIN_CLASS;
#else
/*  !!!! probably unnecessary with gold as normal inventory */
#endif

for (sp = op; *sp; sp++) {
	oc_sym = def_char_to_objclass(*sp);
	/* reject bad or duplicate entries */
	if (oc_sym == MAXOCLASSES ||
		oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||
		!index(flags.inv_order, oc_sym) || index(sp+1, *sp))
	    return 0;
	/* retain good ones */
	buf[num++] = (char) oc_sym;
}
buf[num] = '\0';

/* fill in any omitted classes, using previous ordering */
for (sp = flags.inv_order; *sp; sp++)
	if (!index(buf, *sp)) {
	    buf[num++] = *sp;
	    buf[num] = '\0';	/* explicitly terminate for next index() */
	}

Strcpy(flags.inv_order, buf);
return 1;
}

graphics_opts

STATIC_OVL void
graphics_opts(opts, optype, maxlen, offset)
register char *opts;
const char *optype;
int maxlen, offset;
{
	uchar translate[MAXPCHARS+1];
	int length, i;

	if (!(opts = string_for_env_opt(optype, opts, FALSE)))
		return;
	escapes(opts, opts);

	length = strlen(opts);
	if (length > maxlen) length = maxlen;
	/* match the form obtained from PC configuration files */
	for (i = 0; i < length; i++)
		translate[i] = (uchar) opts[i];
	assign_graphics(translate, length, maxlen, offset);
}

warning_opts

STATIC_OVL void
warning_opts(opts, optype)
register char *opts;
const char *optype;
{
	uchar translate[MAXPCHARS+1];
	int length, i;

	if (!(opts = string_for_env_opt(optype, opts, FALSE)))
		return;
	escapes(opts, opts);

	length = strlen(opts);
	if (length > WARNCOUNT) length = WARNCOUNT;
	/* match the form obtained from PC configuration files */
	for (i = 0; i < length; i++)
	     translate[i] = (((i < WARNCOUNT) && opts[i]) ?
			   (uchar) opts[i] : def_warnsyms[i].sym);
	assign_warnings(translate);
}

assign_warnings

void
assign_warnings(graph_chars)
register uchar *graph_chars;
{
	int i;
	for (i = 0; i < WARNCOUNT; i++)
	    if (graph_chars[i]) warnsyms[i] = graph_chars[i];
}

feature_alert_opts

STATIC_OVL int
feature_alert_opts(op, optn)
char *op;
const char *optn;
{
	char buf[BUFSZ];
	boolean rejectver = FALSE;
	unsigned long fnv = get_feature_notice_ver(op);		/* version.c */
	if (fnv == 0L) return 0;
	if (fnv > get_current_feature_ver())
		rejectver = TRUE;
	else
		flags.suppress_alert = fnv;
	if (rejectver) {
		if (!initial)
			You_cant("disable new feature alerts for future versions.");
		else {
			Sprintf(buf,
				"\n%s=%s Invalid reference to a future version ignored",
				optn, op);
			badoption(buf);
		}
		return 0;
	}
	if (!initial) {
		Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
			FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
		pline("Feature change alerts disabled for NetHack %s features and prior.",
			buf);
	}
	return 1;
}

set_duplicate_opt_detection

void
set_duplicate_opt_detection(on_or_off)
int on_or_off;
{
	int k, *optptr;
	if (on_or_off != 0) {
		/*-- ON --*/
		if (iflags.opt_booldup)
			impossible("iflags.opt_booldup already on (memory leak)");
		iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int));
		optptr = iflags.opt_booldup;
		for (k = 0; k < SIZE(boolopt); ++k)
			*optptr++ = 0;
			
		if (iflags.opt_compdup)
			impossible("iflags.opt_compdup already on (memory leak)");
		iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int));
		optptr = iflags.opt_compdup;
		for (k = 0; k < SIZE(compopt); ++k)
			*optptr++ = 0;
	} else {
		/*-- OFF --*/
		if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup);
		iflags.opt_booldup = (int *)0;
		if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup);
		iflags.opt_compdup = (int *)0;
	} 
}

duplicate_opt_detection

STATIC_OVL void
duplicate_opt_detection(opts, bool_or_comp)
const char *opts;
int bool_or_comp;	/* 0 == boolean option, 1 == compound */
{
	int i, *optptr;
#if defined(MAC)
	/* the Mac has trouble dealing with the output of messages while
	 * processing the config file.  That should get fixed one day.
	 * For now just return.
	 */
	return;
#endif
	if ((bool_or_comp == 0) && iflags.opt_booldup && initial && from_file) {
	    for (i = 0; boolopt[i].name; i++) {
		if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
			optptr = iflags.opt_booldup + i;
			if (*optptr == 1) {
			    raw_printf(
				"\nWarning - Boolean option specified multiple times: %s.\n",
					opts);
			        wait_synch();
			}
			*optptr += 1;
			break; /* don't match multiple options */
		}
	    }
	} else if ((bool_or_comp == 1) && iflags.opt_compdup && initial && from_file) {
	    for (i = 0; compopt[i].name; i++) {
		if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) {
			optptr = iflags.opt_compdup + i;
			if (*optptr == 1) {
			    raw_printf(
				"\nWarning - compound option specified multiple times: %s.\n",
					compopt[i].name);
			        wait_synch();
			}
			*optptr += 1;
			break; /* don't match multiple options */
		}
	    }
	}
}

parseoptions

void
parseoptions(opts, tinitial, tfrom_file)
register char *opts;
boolean tinitial, tfrom_file;
{
	register char *op;
	unsigned num;
	boolean negated;
	int i;
	const char *fullname;

	initial = tinitial;
	from_file = tfrom_file;
	if ((op = index(opts, ',')) != 0) {
		*op++ = 0;
		parseoptions(op, initial, from_file);
	}
	if (strlen(opts) > BUFSZ/2) {
		badoption("option too long");
		return;
	}

	/* strip leading and trailing white space */
	while (isspace(*opts)) opts++;
	op = eos(opts);
	while (--op >= opts && isspace(*op)) *op = '\0';

	if (!*opts) return;
	negated = FALSE;
	while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
		if (*opts == '!') opts++; else opts += 2;
		negated = !negated;
	}

	/* variant spelling */

	if (match_optname(opts, "colour", 5, FALSE))
		Strcpy(opts, "color");	/* fortunately this isn't longer */

	if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */
	duplicate_opt_detection(opts, 1);	/* 1 means compound opts */

	/* special boolean options */

	if (match_optname(opts, "female", 3, FALSE)) {
		if(!initial && flags.female == negated)
			pline("That is not anatomically possible.");
		else
			flags.initgend = flags.female = !negated;
		return;
	}

	if (match_optname(opts, "male", 4, FALSE)) {
		if(!initial && flags.female != negated)
			pline("That is not anatomically possible.");
		else
			flags.initgend = flags.female = negated;
		return;
	}

#if defined(MICRO) && !defined(AMIGA)
	/* included for compatibility with old NetHack.cnf files */
	if (match_optname(opts, "IBM_", 4, FALSE)) {
		iflags.BIOS = !negated;
		return;
	}
#endif /* MICRO */

	/* compound options */

	fullname = "pettype";
	if (match_optname(opts, fullname, 3, TRUE)) {
		if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
		    if (negated) bad_negation(fullname, TRUE);
		    else switch (*op) {
			case 'd':	/* dog */
			case 'D':
			    preferred_pet = 'd';
			    break;
			case 'c':	/* cat */
			case 'C':
			case 'f':	/* feline */
			case 'F':
			    preferred_pet = 'c';
			    break;
			case 'n':	/* no pet */
			case 'N':
			    preferred_pet = 'n';
			    break;
			default:
			    pline("Unrecognized pet type '%s'.", op);
			    break;
		    }
		} else if (negated) preferred_pet = 'n';
		return;
	}

	fullname = "catname";
	if (match_optname(opts, fullname, 3, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
			nmcpy(catname, op, PL_PSIZ);
		return;
	}

	fullname = "dogname";
	if (match_optname(opts, fullname, 3, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
			nmcpy(dogname, op, PL_PSIZ);
		return;
	}

	fullname = "horsename";
	if (match_optname(opts, fullname, 5, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
			nmcpy(horsename, op, PL_PSIZ);
		return;
	}

	fullname = "number_pad";
	if (match_optname(opts, fullname, 10, TRUE)) {
		boolean compat = (strlen(opts) <= 10);
		number_pad(iflags.num_pad ? 1 : 0);
		op = string_for_opt(opts, (compat || !initial));
		if (!op) {
		    if (compat || negated || initial) {
			/* for backwards compatibility, "number_pad" without a
			   value is a synonym for number_pad:1 */
			iflags.num_pad = !negated;
			if (iflags.num_pad) iflags.num_pad_mode = 0;
		    }
		    return;
		}
		if (negated) {
		    bad_negation("number_pad", TRUE);
		    return;
		}
		if (*op == '1' || *op == '2') {
			iflags.num_pad = 1;
			if (*op == '2') iflags.num_pad_mode = 1;
			else iflags.num_pad_mode = 0;
		} else if (*op == '0') {
			iflags.num_pad = 0;
			iflags.num_pad_mode = 0;
		} else badoption(opts);
		return;
	}

	fullname = "runmode";
	if (match_optname(opts, fullname, 4, TRUE)) {
		if (negated) {
			iflags.runmode = RUN_TPORT;
		} else if ((op = string_for_opt(opts, FALSE)) != 0) {
		    if (!strncmpi(op, "teleport", strlen(op)))
			iflags.runmode = RUN_TPORT;
		    else if (!strncmpi(op, "run", strlen(op)))
			iflags.runmode = RUN_LEAP;
		    else if (!strncmpi(op, "walk", strlen(op)))
			iflags.runmode = RUN_STEP;
		    else if (!strncmpi(op, "crawl", strlen(op)))
			iflags.runmode = RUN_CRAWL;
		    else
			badoption(opts);
		}
		return;
	}

	fullname = "msghistory";
	if (match_optname(opts, fullname, 3, TRUE)) {
		op = string_for_env_opt(fullname, opts, negated);
		if ((negated && !op) || (!negated && op)) {
			iflags.msg_history = negated ? 0 : atoi(op);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}

	fullname="msg_window";
	/* msg_window:single, combo, full or reversed */
	if (match_optname(opts, fullname, 4, TRUE)) {
	/* allow option to be silently ignored by non-tty ports */
#ifdef TTY_GRAPHICS
		int tmp;
		if (!(op = string_for_opt(opts, TRUE))) {
		    tmp = negated ? 's' : 'f';
		} else {
			  if (negated) {
			  	bad_negation(fullname, TRUE);
			  	return;
				  }
		    tmp = tolower(*op);
		}
		switch (tmp) {
			case 's':	/* single message history cycle (default if negated) */
				iflags.prevmsg_window = 's';
				break;
			case 'c':	/* combination: two singles, then full page reversed */
				iflags.prevmsg_window = 'c';
				break;
			case 'f':	/* full page (default if no opts) */
				iflags.prevmsg_window = 'f';
				break;
			case 'r':	/* full page (reversed) */
				iflags.prevmsg_window = 'r';
				break;
			default:
				badoption(opts);
		}
#endif
		return;
	}

	/* WINCAP
	 * setting font options  */
	fullname = "font";
	if (!strncmpi(opts, fullname, 4))
	{
		int wintype = -1;
		char *fontopts = opts + 4;

		if (!strncmpi(fontopts, "map", 3) ||
		    !strncmpi(fontopts, "_map", 4))
			wintype = NHW_MAP;
		else if (!strncmpi(fontopts, "message", 7) ||
			 !strncmpi(fontopts, "_message", 8))
			wintype = NHW_MESSAGE;
		else if (!strncmpi(fontopts, "text", 4) ||
			 !strncmpi(fontopts, "_text", 5))
			wintype = NHW_TEXT;			
		else if (!strncmpi(fontopts, "menu", 4) ||
			 !strncmpi(fontopts, "_menu", 5))
			wintype = NHW_MENU;
		else if (!strncmpi(fontopts, "status", 6) ||
			 !strncmpi(fontopts, "_status", 7))
			wintype = NHW_STATUS;
		else if (!strncmpi(fontopts, "_size", 5)) {
			if (!strncmpi(fontopts, "_size_map", 8))
				wintype = NHW_MAP;
			else if (!strncmpi(fontopts, "_size_message", 12))
				wintype = NHW_MESSAGE;
			else if (!strncmpi(fontopts, "_size_text", 9))
				wintype = NHW_TEXT;
			else if (!strncmpi(fontopts, "_size_menu", 9))
				wintype = NHW_MENU;
			else if (!strncmpi(fontopts, "_size_status", 11))
				wintype = NHW_STATUS;
			else {
				badoption(opts);
				return;
			}
			if (wintype > 0 && !negated &&
			    (op = string_for_opt(opts, FALSE)) != 0) {
			    switch(wintype)  {
			    	case NHW_MAP:
					iflags.wc_fontsiz_map = atoi(op);
					break;
			    	case NHW_MESSAGE:
					iflags.wc_fontsiz_message = atoi(op);
					break;
			    	case NHW_TEXT:
					iflags.wc_fontsiz_text = atoi(op);
					break;
			    	case NHW_MENU:
					iflags.wc_fontsiz_menu = atoi(op);
					break;
			    	case NHW_STATUS:
					iflags.wc_fontsiz_status = atoi(op);
					break;
			    }
			}
			return;
		} else {
			badoption(opts);
		}
		if (wintype > 0 &&
		    (op = string_for_opt(opts, FALSE)) != 0) {
			wc_set_font_name(wintype, op);
#ifdef MAC
			set_font_name (wintype, op);
#endif
			return;
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
#ifdef CHANGE_COLOR
	if (match_optname(opts, "palette", 3, TRUE)
# ifdef MAC
	    || match_optname(opts, "hicolor", 3, TRUE)
# endif
							) {
	    int color_number, color_incr;

# ifdef MAC
	    if (match_optname(opts, "hicolor", 3, TRUE)) {
		if (negated) {
		    bad_negation("hicolor", FALSE);
		    return;
		}
		color_number = CLR_MAX + 4;	/* HARDCODED inverse number */
		color_incr = -1;
	    } else {
# endif
		if (negated) {
		    bad_negation("palette", FALSE);
		    return;
		}
		color_number = 0;
		color_incr = 1;
# ifdef MAC
	    }
# endif
	    if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
		char *pt = op;
		int cnt, tmp, reverse;
		long rgb;

		while (*pt && color_number >= 0) {
		    cnt = 3;
		    rgb = 0L;
		    if (*pt == '-') {
			reverse = 1;
			pt++;
		    } else {
			reverse = 0;
		    }
		    while (cnt-- > 0) {
			if (*pt && *pt != '/') {
# ifdef AMIGA
			    rgb <<= 4;
# else
			    rgb <<= 8;
# endif
			    tmp = *(pt++);
			    if (isalpha(tmp)) {
				tmp = (tmp + 9) & 0xf;	/* Assumes ASCII... */
			    } else {
				tmp &= 0xf;	/* Digits in ASCII too... */
			    }
# ifndef AMIGA
			    /* Add an extra so we fill f -> ff and 0 -> 00 */
			    rgb += tmp << 4;
# endif
			    rgb += tmp;
			}
		    }
		    if (*pt == '/') {
			pt++;
		    }
		    change_color(color_number, rgb, reverse);
		    color_number += color_incr;
		}
	    }
	    if (!initial) {
		need_redraw = TRUE;
	    }
	    return;
	}
#endif /* CHANGE_COLOR */

	if (match_optname(opts, "fruit", 2, TRUE)) {
		char empty_str = '\0';
		op = string_for_opt(opts, negated);
		if (negated) {
		    if (op) {
			bad_negation("fruit", TRUE);
			return;
		    }
		    op = &empty_str;
		    goto goodfruit;
		}
		if (!op) return;
		if (!initial) {
		    struct fruit *f;

		    num = 0;
		    for(f=ffruit; f; f=f->nextf) {
			if (!strcmp(op, f->fname)) goto goodfruit;
			num++;
		    }
		    if (num >= 100) {
			pline("Doing that so many times isn't very fruitful.");
			return;
		    }
		}
goodfruit:
		nmcpy(pl_fruit, op, PL_FSIZ);
	/* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
		if (!*pl_fruit)
		    nmcpy(pl_fruit, "slime mold", PL_FSIZ);
		if (!initial)
		    (void)fruitadd(pl_fruit);
		/* If initial, then initoptions is allowed to do it instead
		 * of here (initoptions always has to do it even if there's
		 * no fruit option at all.  Also, we don't want people
		 * setting multiple fruits in their options.)
		 */
		return;
	}

	/* graphics:string */
	fullname = "graphics";
	if (match_optname(opts, fullname, 2, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else graphics_opts(opts, fullname, MAXPCHARS, 0);
		return;
	}
	fullname = "dungeon";
	if (match_optname(opts, fullname, 2, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else graphics_opts(opts, fullname, MAXDCHARS, 0);
		return;
	}
	fullname = "traps";
	if (match_optname(opts, fullname, 2, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS);
		return;
	}
	fullname = "effects";
	if (match_optname(opts, fullname, 2, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else
		 graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS);
		return;
	}

	/* objects:string */
	fullname = "objects";
	if (match_optname(opts, fullname, 7, TRUE)) {
		int length;

		if (negated) {
		    bad_negation(fullname, FALSE);
		    return;
		}
		if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
			return;
		escapes(opts, opts);

		/*
		 * Override the default object class symbols.  The first
		 * object in the object class is the "random object".  I
		 * don't want to use 0 as an object class, so the "random
		 * object" is basically a place holder.
		 *
		 * The object class symbols have already been initialized in
		 * initoptions().
		 */
		length = strlen(opts);
		if (length >= MAXOCLASSES)
		    length = MAXOCLASSES-1;	/* don't count RANDOM_OBJECT */

		for (i = 0; i < length; i++)
		    oc_syms[i+1] = (uchar) opts[i];
		return;
	}

	/* monsters:string */
	fullname = "monsters";
	if (match_optname(opts, fullname, 8, TRUE)) {
		int length;

		if (negated) {
		    bad_negation(fullname, FALSE);
		    return;
		}
		if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
			return;
		escapes(opts, opts);

		/* Override default mon class symbols set in initoptions(). */
		length = strlen(opts);
		if (length >= MAXMCLASSES)
		    length = MAXMCLASSES-1;	/* mon class 0 unused */

		for (i = 0; i < length; i++)
		    monsyms[i+1] = (uchar) opts[i];
		return;
	}
	fullname = "warnings";
	if (match_optname(opts, fullname, 5, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else warning_opts(opts, fullname);
		return;
	}
	/* boulder:symbol */
	fullname = "boulder";
	if (match_optname(opts, fullname, 7, TRUE)) {
		int clash = 0;
		if (negated) {
		    bad_negation(fullname, FALSE);
		    return;
		}
/*		if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */
		if (!(opts = string_for_opt(opts, FALSE)))
			return;
		escapes(opts, opts);
		if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
			clash = 1;
		else if (opts[0] >= '1' && opts[0] <= '5')
			clash = 2;
		if (clash) {
			/* symbol chosen matches a used monster or warning
			   symbol which is not good - reject it*/
			pline(
		  "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
				opts[0], (clash == 1) ? "monster" : "warning");
		} else {
			/*
			 * Override the default boulder symbol.
			 */
			iflags.bouldersym = (uchar) opts[0];
		}
		if (!initial) need_redraw = TRUE;
		return;
	}

	/* name:string */
	fullname = "name";
	if (match_optname(opts, fullname, 4, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
			nmcpy(plname, op, PL_NSIZ);
		return;
	}

	/* role:string or character:string */
	fullname = "role";
	if (match_optname(opts, fullname, 4, TRUE) ||
	    match_optname(opts, (fullname = "character"), 4, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
			if ((flags.initrole = str2role(op)) == ROLE_NONE)
				badoption(opts);
			else  /* Backwards compatibility */
				nmcpy(pl_character, op, PL_NSIZ);
		}
		return;
	}

	/* race:string */
	fullname = "race";
	if (match_optname(opts, fullname, 4, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
			if ((flags.initrace = str2race(op)) == ROLE_NONE)
				badoption(opts);
			else /* Backwards compatibility */
				pl_race = *op;
		}
		return;
	}

	/* gender:string */
	fullname = "gender";
	if (match_optname(opts, fullname, 4, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
			if ((flags.initgend = str2gend(op)) == ROLE_NONE)
				badoption(opts);
			else
				flags.female = flags.initgend;
		}
		return;
	}

	/* altkeyhandler:string */
	fullname = "altkeyhandler";
	if (match_optname(opts, fullname, 4, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_opt(opts, negated))) {
#ifdef WIN32CON
		    (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
		    load_keyboard_handler();
#endif
		}
		return;
	}

	/* WINCAP
	 * align_status:[left|top|right|bottom] */
	fullname = "align_status";
	if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if (op && !negated) {
		    if (!strncmpi (op, "left", sizeof("left")-1))
			iflags.wc_align_status = ALIGN_LEFT;
		    else if (!strncmpi (op, "top", sizeof("top")-1))
			iflags.wc_align_status = ALIGN_TOP;
		    else if (!strncmpi (op, "right", sizeof("right")-1))
			iflags.wc_align_status = ALIGN_RIGHT;
		    else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
			iflags.wc_align_status = ALIGN_BOTTOM;
		    else
			badoption(opts);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	/* WINCAP
	 * align_message:[left|top|right|bottom] */
	fullname = "align_message";
	if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if (op && !negated) {
		    if (!strncmpi (op, "left", sizeof("left")-1))
			iflags.wc_align_message = ALIGN_LEFT;
		    else if (!strncmpi (op, "top", sizeof("top")-1))
			iflags.wc_align_message = ALIGN_TOP;
		    else if (!strncmpi (op, "right", sizeof("right")-1))
			iflags.wc_align_message = ALIGN_RIGHT;
		    else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
			iflags.wc_align_message = ALIGN_BOTTOM;
		    else
			badoption(opts);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	/* align:string */
	fullname = "align";
	if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
			if ((flags.initalign = str2align(op)) == ROLE_NONE)
				badoption(opts);
		return;
	}

	/* the order to list the pack */
	fullname = "packorder";
	if (match_optname(opts, fullname, 4, TRUE)) {
		if (negated) {
		    bad_negation(fullname, FALSE);
		    return;
		} else if (!(op = string_for_opt(opts, FALSE))) return;

		if (!change_inv_order(op))
			badoption(opts);
		return;
	}

	/* maximum burden picked up before prompt (Warren Cheung) */
	fullname = "pickup_burden";
	if (match_optname(opts, fullname, 8, TRUE)) {
		if (negated) {
			bad_negation(fullname, FALSE);
			return;
		} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
		    switch (tolower(*op)) {
				/* Unencumbered */
				case 'u':
					flags.pickup_burden = UNENCUMBERED;
					break;
				/* Burdened (slight encumbrance) */
				case 'b':
					flags.pickup_burden = SLT_ENCUMBER;
					break;
				/* streSsed (moderate encumbrance) */
				case 's':
					flags.pickup_burden = MOD_ENCUMBER;
					break;
				/* straiNed (heavy encumbrance) */
				case 'n':
					flags.pickup_burden = HVY_ENCUMBER;
					break;
				/* OverTaxed (extreme encumbrance) */
				case 'o':
				case 't':
					flags.pickup_burden = EXT_ENCUMBER;
					break;
				/* overLoaded */
				case 'l':
					flags.pickup_burden = OVERLOADED;
					break;
				default:
				badoption(opts);
		    }
		}
		return;
	}

	/* types of objects to pick up automatically */
	if (match_optname(opts, "pickup_types", 8, TRUE)) {
		char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
		     qbuf[QBUFSZ], abuf[BUFSZ];
		int oc_sym;
		boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;

		oc_to_str(flags.pickup_types, tbuf);
		flags.pickup_types[0] = '\0';	/* all */
		op = string_for_opt(opts, (compat || !initial));
		if (!op) {
		    if (compat || negated || initial) {
			/* for backwards compatibility, "pickup" without a
			   value is a synonym for autopickup of all types
			   (and during initialization, we can't prompt yet) */
			flags.pickup = !negated;
			return;
		    }
		    oc_to_str(flags.inv_order, ocl);
		    use_menu = TRUE;
		    if (flags.menu_style == MENU_TRADITIONAL ||
			    flags.menu_style == MENU_COMBINATION) {
			use_menu = FALSE;
			Sprintf(qbuf, "New pickup_types: [%s am] (%s)",
				ocl, *tbuf ? tbuf : "all");
			getlin(qbuf, abuf);
			op = mungspaces(abuf);
			if (abuf[0] == '\0' || abuf[0] == '\033')
			    op = tbuf;		/* restore */
			else if (abuf[0] == 'm')
			    use_menu = TRUE;
		    }
		    if (use_menu) {
			(void) choose_classes_menu("Auto-Pickup what?", 1,
						   TRUE, ocl, tbuf);
			op = tbuf;
		    }
		}
		if (negated) {
		    bad_negation("pickup_types", TRUE);
		    return;
		}
		while (*op == ' ') op++;
		if (*op != 'a' && *op != 'A') {
		    num = 0;
		    while (*op) {
			oc_sym = def_char_to_objclass(*op);
			/* make sure all are valid obj symbols occuring once */
			if (oc_sym != MAXOCLASSES &&
			    !index(flags.pickup_types, oc_sym)) {
			    flags.pickup_types[num] = (char)oc_sym;
			    flags.pickup_types[++num] = '\0';
			} else
			    badopt = TRUE;
			op++;
		    }
		    if (badopt) badoption(opts);
		}
		return;
	}
	/* WINCAP
	 * player_selection: dialog | prompts */
	fullname = "player_selection";
	if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if (op && !negated) {
		    if (!strncmpi (op, "dialog", sizeof("dialog")-1))
			iflags.wc_player_selection = VIA_DIALOG;
		    else if (!strncmpi (op, "prompt", sizeof("prompt")-1))
			iflags.wc_player_selection = VIA_PROMPTS;
		    else
		    	badoption(opts);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}

	/* things to disclose at end of game */
	if (match_optname(opts, "disclose", 7, TRUE)) {
		/*
		 * The order that the end_disclore options are stored:
		 * inventory, attribs, vanquished, genocided, conduct
		 * There is an array in flags:
		 *	end_disclose[NUM_DISCLOSURE_OPT];
		 * with option settings for the each of the following:
		 * iagvc [see disclosure_options in decl.c]:
		 * Legal setting values in that array are:
		 *	DISCLOSE_PROMPT_DEFAULT_YES  ask with default answer yes
		 *	DISCLOSE_PROMPT_DEFAULT_NO   ask with default answer no
		 *	DISCLOSE_YES_WITHOUT_PROMPT  always disclose and don't ask
		 *	DISCLOSE_NO_WITHOUT_PROMPT   never disclose and don't ask
		 *
		 * Those setting values can be used in the option
		 * string as a prefix to get the desired behaviour.
		 *
		 * For backward compatibility, no prefix is required,
		 * and the presence of a i,a,g,v, or c without a prefix
		 * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
		 */
		boolean badopt = FALSE;
		int idx, prefix_val;

		op = string_for_opt(opts, TRUE);
		if (op && negated) {
			bad_negation("disclose", TRUE);
			return;
		}
		/* "disclose" without a value means "all with prompting"
		   and negated means "none without prompting" */
		if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
			if (op && !strcmpi(op, "none")) negated = TRUE;
			for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
			    flags.end_disclose[num] = negated ?
						DISCLOSE_NO_WITHOUT_PROMPT :
						DISCLOSE_PROMPT_DEFAULT_YES;
			return;
		}

		num = 0;
		prefix_val = -1;
		while (*op && num < sizeof flags.end_disclose - 1) {
			register char c, *dop;
			static char valid_settings[] = {
				DISCLOSE_PROMPT_DEFAULT_YES,
				DISCLOSE_PROMPT_DEFAULT_NO,
				DISCLOSE_YES_WITHOUT_PROMPT,
				DISCLOSE_NO_WITHOUT_PROMPT,
				'\0'
			};
			c = lowc(*op);
			if (c == 'k') c = 'v';	/* killed -> vanquished */
			dop = index(disclosure_options, c);
			if (dop) {
				idx = dop - disclosure_options;
				if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
				    impossible("bad disclosure index %d %c",
							idx, c);
				    continue;
				}
				if (prefix_val != -1) {
				    flags.end_disclose[idx] = prefix_val;
				    prefix_val = -1;
				} else
				    flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
			} else if (index(valid_settings, c)) {
				prefix_val = c;
			} else if (c == ' ') {
				/* do nothing */
			} else
				badopt = TRUE;				
			op++;
		}
		if (badopt) badoption(opts);
		return;
	}

	/* scores:5t[op] 5a[round] o[wn] */
	if (match_optname(opts, "scores", 4, TRUE)) {
	    if (negated) {
		bad_negation("scores", FALSE);
		return;
	    }
	    if (!(op = string_for_opt(opts, FALSE))) return;

	    while (*op) {
		int inum = 1;

		if (digit(*op)) {
		    inum = atoi(op);
		    while (digit(*op)) op++;
		} else if (*op == '!') {
		    negated = !negated;
		    op++;
		}
		while (*op == ' ') op++;

		switch (*op) {
		 case 't':
		 case 'T':  flags.end_top = inum;
			    break;
		 case 'a':
		 case 'A':  flags.end_around = inum;
			    break;
		 case 'o':
		 case 'O':  flags.end_own = !negated;
			    break;
		 default:   badoption(opts);
			    return;
		}
		while (letter(*++op) || *op == ' ') continue;
		if (*op == '/') op++;
	    }
	    return;
	}

	fullname = "suppress_alert";
	if (match_optname(opts, fullname, 4, TRUE)) {
		op = string_for_opt(opts, negated);
		if (negated) bad_negation(fullname, FALSE);
		else if (op) (void) feature_alert_opts(op,fullname);
		return;
	}
	
#ifdef VIDEOSHADES
	/* videocolors:string */
	fullname = "videocolors";
	if (match_optname(opts, fullname, 6, TRUE) ||
	    match_optname(opts, "videocolours", 10, TRUE)) {
		if (negated) {
			bad_negation(fullname, FALSE);
			return;
		}
		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
			return;
		}
		if (!assign_videocolors(opts))
			badoption(opts);
		return;
	}
	/* videoshades:string */
	fullname = "videoshades";
	if (match_optname(opts, fullname, 6, TRUE)) {
		if (negated) {
			bad_negation(fullname, FALSE);
			return;
		}
		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
			return;
		}
		if (!assign_videoshades(opts))
			badoption(opts);
		return;
	}
#endif /* VIDEOSHADES */
#ifdef MSDOS
# ifdef NO_TERMS
	/* video:string -- must be after longer tests */
	fullname = "video";
	if (match_optname(opts, fullname, 5, TRUE)) {
		if (negated) {
			bad_negation(fullname, FALSE);
			return;
		}
		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
			return;
		}
		if (!assign_video(opts))
			badoption(opts);
		return;
	}
# endif /* NO_TERMS */
	/* soundcard:string -- careful not to match boolean 'sound' */
	fullname = "soundcard";
	if (match_optname(opts, fullname, 6, TRUE)) {
		if (negated) {
			bad_negation(fullname, FALSE);
			return;
		}
		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
			return;
		}
		if (!assign_soundcard(opts))
			badoption(opts);
		return;
	}
#endif /* MSDOS */

	/* WINCAP
	 * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12|
			ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */
	fullname = "map_mode";
	if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if (op && !negated) {
		    if (!strncmpi (op, "tiles", sizeof("tiles")-1))
			iflags.wc_map_mode = MAP_MODE_TILES;
		    else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII4x6;
		    else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII6x8;
		    else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII8x8;
		    else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII16x8;
		    else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII7x12;
		    else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII8x12;
		    else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII16x12;
		    else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII12x16;
		    else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII10x18;
		    else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1))
			iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
		    else
		    	badoption(opts);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	/* WINCAP
	 * scroll_amount:nn */
	fullname = "scroll_amount";
	if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if ((negated && !op) || (!negated && op)) {
			iflags.wc_scroll_amount = negated ? 1 : atoi(op);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	/* WINCAP
	 * scroll_margin:nn */
	fullname = "scroll_margin";
	if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if ((negated && !op) || (!negated && op)) {
			iflags.wc_scroll_margin = negated ? 5 : atoi(op);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	fullname = "subkeyvalue";
	if (match_optname(opts, fullname, 5, TRUE)) {
		if (negated) bad_negation(fullname, FALSE);
		else {
#if defined(WIN32CON)
			op = string_for_opt(opts, 0);
			map_subkeyvalue(op);
#endif
		}
		return;
	}
	/* WINCAP
	 * tile_width:nn */
	fullname = "tile_width";
	if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if ((negated && !op) || (!negated && op)) {
			iflags.wc_tile_width = negated ? 0 : atoi(op);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	/* WINCAP
	 * tile_file:name */
	fullname = "tile_file";
	if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) {
		if ((op = string_for_opt(opts, FALSE)) != 0) {
			if (iflags.wc_tile_file) free(iflags.wc_tile_file);
			iflags.wc_tile_file = (char *)alloc(strlen(op) + 1);
			Strcpy(iflags.wc_tile_file, op);
		}
		return;
	}
	/* WINCAP
	 * tile_height:nn */
	fullname = "tile_height";
	if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if ((negated && !op) || (!negated && op)) {
			iflags.wc_tile_height = negated ? 0 : atoi(op);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	/* WINCAP
	 * vary_msgcount:nn */
	fullname = "vary_msgcount";
	if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) {
		op = string_for_opt(opts, negated);
		if ((negated && !op) || (!negated && op)) {
			iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}
	fullname = "windowtype";
	if (match_optname(opts, fullname, 3, TRUE)) {
	    if (negated) {
		bad_negation(fullname, FALSE);
		return;
	    } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
		char buf[WINTYPELEN];
		nmcpy(buf, op, WINTYPELEN);
		choose_windows(buf);
	    }
	    return;
	}

	/* WINCAP
	 * setting window colors
* syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
*/
	fullname = "windowcolors";
	if (match_optname(opts, fullname, 7, TRUE)) {
		if ((op = string_for_opt(opts, FALSE)) != 0) {
			if (!wc_set_window_colors(op))
				badoption(opts);
		} else if (negated) bad_negation(fullname, TRUE);
		return;
	}

	/* menustyle:traditional or combo or full or partial */
	if (match_optname(opts, "menustyle", 4, TRUE)) {
		int tmp;
		boolean val_required = (strlen(opts) > 5 && !negated);

		if (!(op = string_for_opt(opts, !val_required))) {
		    if (val_required) return; /* string_for_opt gave feedback */
		    tmp = negated ? 'n' : 'f';
		} else {
		    tmp = tolower(*op);
		}
		switch (tmp) {
			case 'n':	/* none */
			case 't':	/* traditional */
				flags.menu_style = MENU_TRADITIONAL;
				break;
			case 'c':	/* combo: trad.class sel+menu */
				flags.menu_style = MENU_COMBINATION;
				break;
			case 'p':	/* partial: no class menu */
				flags.menu_style = MENU_PARTIAL;
				break;
			case 'f':	/* full: class menu + menu */
				flags.menu_style = MENU_FULL;
				break;
			default:
				badoption(opts);
		}
		return;
	}

	fullname = "menu_headings";
	if (match_optname(opts, fullname, 12, TRUE)) {
		if (negated) {
			bad_negation(fullname, FALSE);
			return;
		}
		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
			return;
		}
		if (!strcmpi(opts,"bold"))
			iflags.menu_headings = ATR_BOLD;
		else if (!strcmpi(opts,"inverse"))
			iflags.menu_headings = ATR_INVERSE;
		else if (!strcmpi(opts,"underline"))
			iflags.menu_headings = ATR_ULINE;
		else
			badoption(opts);
		return;
	}

	/* check for menu command mapping */
	for (i = 0; i < NUM_MENU_CMDS; i++) {
	    fullname = default_menu_cmd_info[i].name;
	    if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) {
		if (negated)
		    bad_negation(fullname, FALSE);
		else if ((op = string_for_opt(opts, FALSE)) != 0) {
		    int j;
		    char c, op_buf[BUFSZ];
		    boolean isbad = FALSE;

		    escapes(op, op_buf);
		    c = *op_buf;

		    if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||
			    c == ' ' || digit(c) || (letter(c) && c != '@'))
			isbad = TRUE;
		    else	/* reject default object class symbols */
			for (j = 1; j < MAXOCLASSES; j++)
			    if (c == def_oc_syms[i]) {
				isbad = TRUE;
				break;
			    }

		    if (isbad)
			badoption(opts);
		    else
			add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
		}
		return;
	    }
	}

	/* OK, if we still haven't recognized the option, check the boolean
	 * options list
	 */
	for (i = 0; boolopt[i].name; i++) {
		if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
			/* options that don't exist */
			if (!boolopt[i].addr) {
			    if (!initial && !negated)
				pline_The("\"%s\" option is not available.",
					boolopt[i].name);
			    return;
			}
			/* options that must come from config file */
			if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
			    rejectoption(boolopt[i].name);
			    return;
			}

			*(boolopt[i].addr) = !negated;

			duplicate_opt_detection(boolopt[i].name, 0);

#if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV)
			if (FALSE
# ifdef TERMLIB
				 || (boolopt[i].addr) == &iflags.DECgraphics
# endif
# ifdef ASCIIGRAPH
				 || (boolopt[i].addr) == &iflags.IBMgraphics
# endif
# ifdef MAC_GRAPHICS_ENV
				 || (boolopt[i].addr) == &iflags.MACgraphics
# endif
				) {
# ifdef REINCARNATION
			    if (!initial && Is_rogue_level(&u.uz))
				assign_rogue_graphics(FALSE);
# endif
			    need_redraw = TRUE;
# ifdef TERMLIB
			    if ((boolopt[i].addr) == &iflags.DECgraphics)
				switch_graphics(iflags.DECgraphics ?
						DEC_GRAPHICS : ASCII_GRAPHICS);
# endif
# ifdef ASCIIGRAPH
			    if ((boolopt[i].addr) == &iflags.IBMgraphics)
				switch_graphics(iflags.IBMgraphics ?
						IBM_GRAPHICS : ASCII_GRAPHICS);
# endif
# ifdef MAC_GRAPHICS_ENV
			    if ((boolopt[i].addr) == &iflags.MACgraphics)
				switch_graphics(iflags.MACgraphics ?
						MAC_GRAPHICS : ASCII_GRAPHICS);
# endif
# ifdef REINCARNATION
			    if (!initial && Is_rogue_level(&u.uz))
				assign_rogue_graphics(TRUE);
# endif
			}
#endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */

			/* only do processing below if setting with doset() */
			if (initial) return;

			if ((boolopt[i].addr) == &flags.time
#ifdef EXP_ON_BOTL
			 || (boolopt[i].addr) == &flags.showexp
#endif
#ifdef SCORE_ON_BOTL
			 || (boolopt[i].addr) == &flags.showscore
#endif
			    )
			    flags.botl = TRUE;

			else if ((boolopt[i].addr) == &flags.invlet_constant) {
			    if (flags.invlet_constant) reassign();
			}
#ifdef LAN_MAIL
			else if ((boolopt[i].addr) == &flags.biff) {
			    if (flags.biff) lan_mail_init();
			    else lan_mail_finish();
			}
#endif
			else if ((boolopt[i].addr) == &flags.lit_corridor) {
			    /*
			     * All corridor squares seen via night vision or
			     * candles & lamps change.  Update them by calling
			     * newsym() on them.  Don't do this if we are
			     * initializing the options --- the vision system
			     * isn't set up yet.
			     */
			    vision_recalc(2);		/* shut down vision */
			    vision_full_recalc = 1;	/* delayed recalc */
			}
			else if ((boolopt[i].addr) == &iflags.use_inverse ||
					(boolopt[i].addr) == &iflags.showrace ||
					(boolopt[i].addr) == &iflags.hilite_pet) {
			    need_redraw = TRUE;
			}
#ifdef TEXTCOLOR
			else if ((boolopt[i].addr) == &iflags.use_color) {
			    need_redraw = TRUE;
# ifdef TOS
			    if ((boolopt[i].addr) == &iflags.use_color
				&& iflags.BIOS) {
				if (colors_changed)
				    restore_colors();
				else
				    set_colors();
			    }
# endif
			}
#endif

			return;
		}
	}

	/* out of valid options */
	badoption(opts);
}
static NEARDATA const char *menutype[] = {
	"traditional", "combination", "partial", "full"
};

static NEARDATA const char *burdentype[] = {
	"unencumbered", "burdened", "stressed",
	"strained", "overtaxed", "overloaded"
};

static NEARDATA const char *runmodes[] = {
	"teleport", "run", "walk", "crawl"
};

oc_to_str

/*
* Convert the given string of object classes to a string of default object
* symbols.
*/
STATIC_OVL void
oc_to_str(src,dest)
char *src, *dest;
{
int i;

while ((i = (int) *src++) != 0) {
	if (i < 0 || i >= MAXOCLASSES)
	    impossible("oc_to_str:  illegal object class %d", i);
	else
	    *dest++ = def_oc_syms[i];
}
*dest = '\0';
}

add_menu_cmd_alias

/*
* Add the given mapping to the menu command map list.  Always keep the
* maps valid C strings.
*/
void
add_menu_cmd_alias(from_ch, to_ch)
char from_ch, to_ch;
{
if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
	pline("out of menu map space.");
else {
	mapped_menu_cmds[n_menu_mapped] = from_ch;
	mapped_menu_op[n_menu_mapped] = to_ch;
	n_menu_mapped++;
	mapped_menu_cmds[n_menu_mapped] = 0;
	mapped_menu_op[n_menu_mapped] = 0;
}
}

map_menu_cmd

/*
* Map the given character to its corresponding menu command.  If it
* doesn't match anything, just return the original.
*/
char
map_menu_cmd(ch)
char ch;
{
char *found = index(mapped_menu_cmds, ch);
if (found) {
	int idx = found - mapped_menu_cmds;
	ch = mapped_menu_op[idx];
}
return ch;
}

doset_add_menu

#if defined(MICRO) || defined(MAC) || defined(WIN32)
# define OPTIONS_HEADING "OPTIONS"
#else
# define OPTIONS_HEADING "NETHACKOPTIONS"
#endif

static char fmtstr_doset_add_menu[] = "%s%-15s [%s]   "; 
static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";

STATIC_OVL void
doset_add_menu(win, option, indexoffset)
winid win;			/* window to add to */
const char *option;		/* option name */
int indexoffset;		/* value to add to index in compopt[], or zero
				   if option cannot be changed */
{
const char *value = "unknown";		/* current value */
char buf[BUFSZ], buf2[BUFSZ];
anything any;
int i;

any.a_void = 0;
if (indexoffset == 0) {
	any.a_int = 0;
	value = get_compopt_value(option, buf2);
} else {
	for (i=0; compopt[i].name; i++)
	    if (strcmp(option, compopt[i].name) == 0) break;

	if (compopt[i].name) {
	    any.a_int = i + 1 + indexoffset;
	    value = get_compopt_value(option, buf2);
	} else {
	    /* We are trying to add an option not found in compopt[].
	       This is almost certainly bad, but we'll let it through anyway
	       (with a zero value, so it can't be selected). */
	    any.a_int = 0;
	}
}
/* "    " replaces "a - " -- assumes menus follow that style */
if (!iflags.menu_tab_sep)
	Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ", option, value);
else
	Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
}

doset

/* Changing options via menu by Per Liboriussen */
int
doset()
{
	char buf[BUFSZ], buf2[BUFSZ];
	int i, pass, boolcount, pick_cnt, pick_idx, opt_indx;
	boolean *bool_p;
	winid tmpwin;
	anything any;
	menu_item *pick_list;
	int indexoffset, startpass, endpass;
	boolean setinitial = FALSE, fromfile = FALSE;
	int biggest_name = 0;

	tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);

	any.a_void = 0;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
		 "Booleans (selecting will toggle value):", MENU_UNSELECTED);
	any.a_int = 0;
	/* first list any other non-modifiable booleans, then modifiable ones */
	for (pass = 0; pass <= 1; pass++)
	    for (i = 0; boolopt[i].name; i++)
		if ((bool_p = boolopt[i].addr) != 0 &&
			((boolopt[i].optflags == DISP_IN_GAME && pass == 0) ||
			 (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
		    if (bool_p == &flags.female) continue;  /* obsolete */
#ifdef WIZARD
		    if (bool_p == &iflags.sanity_check && !wizard) continue;
		    if (bool_p == &iflags.menu_tab_sep && !wizard) continue;
#endif
		    if (is_wc_option(boolopt[i].name) &&
			!wc_supported(boolopt[i].name)) continue;
		    if (is_wc2_option(boolopt[i].name) &&
			!wc2_supported(boolopt[i].name)) continue;
		    any.a_int = (pass == 0) ? 0 : i + 1;
		    if (!iflags.menu_tab_sep)
			Sprintf(buf, "%s%-13s [%s]",
			    pass == 0 ? "    " : "",
			    boolopt[i].name, *bool_p ? "true" : "false");
		    else
			Sprintf(buf, "%s\t[%s]",
			    boolopt[i].name, *bool_p ? "true" : "false");
		    add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
			     ATR_NONE, buf, MENU_UNSELECTED);
		}

	boolcount = i;
	indexoffset = boolcount;
	any.a_void = 0;
	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
		 "Compounds (selecting will prompt for new value):",
		 MENU_UNSELECTED);

	startpass = DISP_IN_GAME;
	endpass = SET_IN_GAME;

	/* spin through the options to find the biggest name
and adjust the format string accordingly if needed */
	biggest_name = 0;
	for (i = 0; compopt[i].name; i++)
		if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass &&
		    strlen(compopt[i].name) > (unsigned) biggest_name)
			biggest_name = (int) strlen(compopt[i].name);
	if (biggest_name > 30) biggest_name = 30;
	if (!iflags.menu_tab_sep)
		Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
	
	/* deliberately put `name', `role', `race', `gender' first */
	doset_add_menu(tmpwin, "name", 0);
	doset_add_menu(tmpwin, "role", 0);
	doset_add_menu(tmpwin, "race", 0);
	doset_add_menu(tmpwin, "gender", 0);

	for (pass = startpass; pass <= endpass; pass++) 
	    for (i = 0; compopt[i].name; i++)
		if (compopt[i].optflags == pass) {
		    	if (!strcmp(compopt[i].name, "name") ||
		    	    !strcmp(compopt[i].name, "role") ||
		    	    !strcmp(compopt[i].name, "race") ||
		    	    !strcmp(compopt[i].name, "gender"))
		    	    	continue;
		    	else if (is_wc_option(compopt[i].name) &&
					!wc_supported(compopt[i].name))
		    		continue;
		    	else if (is_wc2_option(compopt[i].name) &&
					!wc2_supported(compopt[i].name))
		    		continue;
		    	else
				doset_add_menu(tmpwin, compopt[i].name,
					(pass == DISP_IN_GAME) ? 0 : indexoffset);
		}
#ifdef AUTOPICKUP_EXCEPTIONS
	any.a_int = -1;
	Sprintf(buf, "autopickup exceptions (%d currently set)",
		count_ape_maps((int *)0, (int *)0));
	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);

#endif /* AUTOPICKUP_EXCEPTIONS */
#ifdef PREFIXES_IN_USE
	any.a_void = 0;
	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
		 "Variable playground locations:", MENU_UNSELECTED);
	for (i = 0; i < PREFIX_COUNT; i++)
		doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
#endif
	end_menu(tmpwin, "Set what options?");
	need_redraw = FALSE;
	if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
	    /*
	     * Walk down the selection list and either invert the booleans
	     * or prompt for new values. In most cases, call parseoptions()
	     * to take care of options that require special attention, like
	     * redraws.
	     */
	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
		opt_indx = pick_list[pick_idx].item.a_int - 1;
#ifdef AUTOPICKUP_EXCEPTIONS
		if (opt_indx == -2) {
		    special_handling("autopickup_exception",
		    			setinitial, fromfile);
		} else
#endif
		if (opt_indx < boolcount) {
		    /* boolean option */
		    Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
			    boolopt[opt_indx].name);
		    parseoptions(buf, setinitial, fromfile);
		    if (wc_supported(boolopt[opt_indx].name) ||
		    	wc2_supported(boolopt[opt_indx].name))
			preference_update(boolopt[opt_indx].name);
		} else {
		    /* compound option */
		    opt_indx -= boolcount;

		    if (!special_handling(compopt[opt_indx].name,
							setinitial, fromfile)) {
			Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
			getlin(buf, buf2);
			if (buf2[0] == '\033')
			    continue;
			Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
			/* pass the buck */
			parseoptions(buf, setinitial, fromfile);
		    }
		    if (wc_supported(compopt[opt_indx].name) ||
			wc2_supported(compopt[opt_indx].name))
			preference_update(compopt[opt_indx].name);
		}
	    }
	    free((genericptr_t)pick_list);
	    pick_list = (menu_item *)0;
	}

	destroy_nhwindow(tmpwin);
	if (need_redraw)
	    (void) doredraw();
	return 0;
}

special_handling

STATIC_OVL boolean
special_handling(optname, setinitial, setfromfile)
const char *optname;
boolean setinitial,setfromfile;
{
winid tmpwin;
anything any;
int i;
char buf[BUFSZ];
boolean retval = FALSE;

/* Special handling of menustyle, pickup_burden, pickup_types,
* disclose, runmode, msg_window, menu_headings, and number_pad options.
#ifdef AUTOPICKUP_EXCEPTIONS
* Also takes care of interactive autopickup_exception_handling changes.
#endif
*/
if (!strcmp("menustyle", optname)) {
	const char *style_name;
	menu_item *style_pick = (menu_item *)0;
tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	for (i = 0; i < SIZE(menutype); i++) {
		style_name = menutype[i];
		/* note: separate `style_name' variable used
		   to avoid an optimizer bug in VAX C V2.3 */
		any.a_int = i + 1;
		add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,
			 ATR_NONE, style_name, MENU_UNSELECTED);
}
	end_menu(tmpwin, "Select menustyle:");
	if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
		flags.menu_style = style_pick->item.a_int - 1;
		free((genericptr_t)style_pick);
}
	destroy_nhwindow(tmpwin);
retval = TRUE;
} else if (!strcmp("pickup_burden", optname)) {
	const char *burden_name, *burden_letters = "ubsntl";
	menu_item *burden_pick = (menu_item *)0;
tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	for (i = 0; i < SIZE(burdentype); i++) {
		burden_name = burdentype[i];
		any.a_int = i + 1;
		add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,
			 ATR_NONE, burden_name, MENU_UNSELECTED);
}
	end_menu(tmpwin, "Select encumbrance level:");
	if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
		flags.pickup_burden = burden_pick->item.a_int - 1;
		free((genericptr_t)burden_pick);
	}
	destroy_nhwindow(tmpwin);
	retval = TRUE;
} else if (!strcmp("pickup_types", optname)) {
	/* parseoptions will prompt for the list of types */
	parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
	retval = TRUE;
} else if (!strcmp("disclose", optname)) {
	int pick_cnt, pick_idx, opt_idx;
	menu_item *disclosure_category_pick = (menu_item *)0;
	/*
	 * The order of disclose_names[]
* must correspond to disclosure_options in decl.h
*/
	static const char *disclosure_names[] = {
		"inventory", "attributes", "vanquished", "genocides", "conduct"
	};
	int disc_cat[NUM_DISCLOSURE_OPTIONS];
	const char *disclosure_name;

tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
		disclosure_name = disclosure_names[i];
		any.a_int = i + 1;
		add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
			 ATR_NONE, disclosure_name, MENU_UNSELECTED);
		disc_cat[i] = 0;
}
	end_menu(tmpwin, "Change which disclosure options categories:");
	if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) {
	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
		opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1;
		disc_cat[opt_idx] = 1;
	    }
	    free((genericptr_t)disclosure_category_pick);
	    disclosure_category_pick = (menu_item *)0;
	}
	destroy_nhwindow(tmpwin);

	for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
	    if (disc_cat[i]) {
	    	char dbuf[BUFSZ];
		menu_item *disclosure_option_pick = (menu_item *)0;
		Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]);
	        tmpwin = create_nhwindow(NHW_MENU);
		start_menu(tmpwin);
		any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
		add_menu(tmpwin, NO_GLYPH, &any, 'a', 0,
			ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED);
		any.a_void = 0;
		any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
		add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
			ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED);
		any.a_void = 0;
		any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
		add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
			ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED);
		any.a_void = 0;
		any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
		add_menu(tmpwin, NO_GLYPH, &any, 'd', 0,
			ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED);
		end_menu(tmpwin, dbuf);
		if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) {
			flags.end_disclose[i] = disclosure_option_pick->item.a_char;
			free((genericptr_t)disclosure_option_pick);
		}
		destroy_nhwindow(tmpwin);
	    }
	}
	retval = TRUE;
} else if (!strcmp("runmode", optname)) {
	const char *mode_name;
	menu_item *mode_pick = (menu_item *)0;
	tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	for (i = 0; i < SIZE(runmodes); i++) {
		mode_name = runmodes[i];
		any.a_int = i + 1;
		add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
			 ATR_NONE, mode_name, MENU_UNSELECTED);
	}
	end_menu(tmpwin, "Select run/travel display mode:");
	if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
		iflags.runmode = mode_pick->item.a_int - 1;
		free((genericptr_t)mode_pick);
	}
	destroy_nhwindow(tmpwin);
	retval = TRUE;
} 
#ifdef TTY_GRAPHICS
else if (!strcmp("msg_window", optname)) {
	/* by Christian W. Cooper */
	menu_item *window_pick = (menu_item *)0;
	tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	any.a_char = 's';
	add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
		ATR_NONE, "single", MENU_UNSELECTED);
	any.a_char = 'c';
	add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
		ATR_NONE, "combination", MENU_UNSELECTED);
	any.a_char = 'f';
	add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
		ATR_NONE, "full", MENU_UNSELECTED);
	any.a_char = 'r';
	add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
		ATR_NONE, "reversed", MENU_UNSELECTED);
	end_menu(tmpwin, "Select message history display type:");
	if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
		iflags.prevmsg_window = window_pick->item.a_char;
		free((genericptr_t)window_pick);
	}
	destroy_nhwindow(tmpwin);
retval = TRUE;
}
#endif
else if (!strcmp("align_message", optname) ||
		!strcmp("align_status", optname)) {
	menu_item *window_pick = (menu_item *)0;
	char abuf[BUFSZ];
	boolean msg = (*(optname+6) == 'm');

	tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	any.a_int = ALIGN_TOP;
	add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
		ATR_NONE, "top", MENU_UNSELECTED);
	any.a_int = ALIGN_BOTTOM;
	add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
		ATR_NONE, "bottom", MENU_UNSELECTED);
	any.a_int = ALIGN_LEFT;
	add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
		ATR_NONE, "left", MENU_UNSELECTED);
	any.a_int = ALIGN_RIGHT;
	add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
		ATR_NONE, "right", MENU_UNSELECTED);
	Sprintf(abuf, "Select %s window placement relative to the map:",
		msg ? "message" : "status");
	end_menu(tmpwin, abuf);
	if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {		
		if (msg) iflags.wc_align_message = window_pick->item.a_int;
		else iflags.wc_align_status = window_pick->item.a_int;
		free((genericptr_t)window_pick);
	}
	destroy_nhwindow(tmpwin);
retval = TRUE;
} else if (!strcmp("number_pad", optname)) {
	static const char *npchoices[3] =
		{"0 (off)", "1 (on)", "2 (on, DOS compatible)"};
	const char *npletters = "abc";
	menu_item *mode_pick = (menu_item *)0;

	tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	for (i = 0; i < SIZE(npchoices); i++) {
		any.a_int = i + 1;
		add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
			 ATR_NONE, npchoices[i], MENU_UNSELECTED);
}
	end_menu(tmpwin, "Select number_pad mode:");
	if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
		int mode = mode_pick->item.a_int - 1;
		switch(mode) {
			case 2:
				iflags.num_pad = 1;
				iflags.num_pad_mode = 1;
				break;
			case 1:
				iflags.num_pad = 1;
				iflags.num_pad_mode = 0;
				break;
			case 0:
			default:
				iflags.num_pad = 0;
				iflags.num_pad_mode = 0;
		}
		free((genericptr_t)mode_pick);
}
	destroy_nhwindow(tmpwin);
retval = TRUE;
} else if (!strcmp("menu_headings", optname)) {
	static const char *mhchoices[3] = {"bold", "inverse", "underline"};
	const char *npletters = "biu";
	menu_item *mode_pick = (menu_item *)0;

	tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	for (i = 0; i < SIZE(mhchoices); i++) {
		any.a_int = i + 1;
		add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
			 ATR_NONE, mhchoices[i], MENU_UNSELECTED);
}
	end_menu(tmpwin, "How to highlight menu headings:");
	if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
		int mode = mode_pick->item.a_int - 1;
		switch(mode) {
			case 2:
				iflags.menu_headings = ATR_ULINE;
				break;
			case 0:
				iflags.menu_headings = ATR_BOLD;
				break;
			case 1:
			default:
				iflags.menu_headings = ATR_INVERSE;
		}
		free((genericptr_t)mode_pick);
}
	destroy_nhwindow(tmpwin);
retval = TRUE;
#ifdef AUTOPICKUP_EXCEPTIONS
} else if (!strcmp("autopickup_exception", optname)) {
	boolean retval;
	int pick_cnt, pick_idx, opt_idx, pass;
	int totalapes = 0, numapes[2] = {0,0};
	menu_item *pick_list = (menu_item *)0;
	anything any;
	char apebuf[BUFSZ];
	struct autopickup_exception *ape;
	static const char *action_titles[] = {
		"a", "add new autopickup exception",
		"l", "list autopickup exceptions",
		"r", "remove existing autopickup exception",
		"e", "exit this menu",
	};
ape_again:
	opt_idx = 0;
	totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
	tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	any.a_int = 0;
	for (i = 0; i < SIZE(action_titles) ; i += 2) {
		any.a_int++;
		if (!totalapes && (i >= 2 && i < 6)) continue;
		add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i],
		      0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED);
}
	end_menu(tmpwin, "Do what?");
	if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
		for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
			opt_idx = pick_list[pick_idx].item.a_int - 1;
		}
		free((genericptr_t)pick_list);
		pick_list = (menu_item *)0;
	}
	destroy_nhwindow(tmpwin);
	if (pick_cnt < 1) return FALSE;

	if (opt_idx == 0) {	/* add new */
		getlin("What new autopickup exception pattern?", &apebuf[1]);
		if (apebuf[1] == '\033') return FALSE;
		apebuf[0] = '"';
		Strcat(apebuf,"\"");
		add_autopickup_exception(apebuf);
		goto ape_again;
	} else if (opt_idx == 3) {
		retval = TRUE;
	} else {	/* remove */
		tmpwin = create_nhwindow(NHW_MENU);
		start_menu(tmpwin);
		for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
		    if (numapes[pass] == 0) continue;
		    ape = iflags.autopickup_exceptions[pass];
		    any.a_void = 0;
		    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
				(pass == 0) ? "Never pickup" : "Always pickup",
				MENU_UNSELECTED);
		    for (i = 0; i < numapes[pass] && ape; i++) {
			any.a_void = (opt_idx == 1) ? 0 : ape;
			Sprintf(apebuf, "\"%s\"", ape->pattern);
			add_menu(tmpwin, NO_GLYPH, &any,
				0, 0, ATR_NONE, apebuf, MENU_UNSELECTED);
			ape = ape->next;
		    }
		}
		Sprintf(apebuf, "%s autopickup exceptions",
			(opt_idx == 1) ? "List of" : "Remove which");
		end_menu(tmpwin, apebuf);
		pick_cnt = select_menu(tmpwin,
					(opt_idx == 1) ?  PICK_NONE : PICK_ANY,
					&pick_list);
		if (pick_cnt > 0) {
	    	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
			remove_autopickup_exception(
			 (struct autopickup_exception *)pick_list[pick_idx].item.a_void);
	        }
	        free((genericptr_t)pick_list);
	        pick_list = (menu_item *)0;
		destroy_nhwindow(tmpwin);
		goto ape_again;
	}
	retval = TRUE;
#endif /* AUTOPICKUP_EXCEPTIONS */
}
return retval;
}

get_compopbt_value

#define rolestring(val,array,field) ((val >= 0) ? array[val].field : \
				     (val == ROLE_RANDOM) ? randomrole : none)

/* This is ugly. We have all the option names in the compopt[] array,
but we need to look at each option individually to get the value. */
STATIC_OVL const char *
get_compopt_value(optname, buf)
const char *optname;
char *buf;
{
	char ocl[MAXOCLASSES+1];
	static const char none[] = "(none)", randomrole[] = "random",
		     to_be_done[] = "(to be done)",
		     defopt[] = "default",
		     defbrief[] = "def";
	int i;

	buf[0] = '\0';
	if (!strcmp(optname,"align_message"))
		Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP     ? "top" :
				   iflags.wc_align_message == ALIGN_LEFT    ? "left" :
				   iflags.wc_align_message == ALIGN_BOTTOM  ? "bottom" :
				   iflags.wc_align_message == ALIGN_RIGHT   ? "right" :
				   defopt);
	else if (!strcmp(optname,"align_status"))
		Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP     ? "top" :
				   iflags.wc_align_status == ALIGN_LEFT    ? "left" :
				   iflags.wc_align_status == ALIGN_BOTTOM  ? "bottom" :
				   iflags.wc_align_status == ALIGN_RIGHT   ? "right" :
				   defopt);
	else if (!strcmp(optname,"align"))
		Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
#ifdef WIN32CON
	else if (!strcmp(optname,"altkeyhandler"))
		Sprintf(buf, "%s", iflags.altkeyhandler[0] ?
			iflags.altkeyhandler : "default");
#endif
	else if (!strcmp(optname, "boulder"))
		Sprintf(buf, "%c", iflags.bouldersym ?
			iflags.bouldersym : oc_syms[(int)objects[BOULDER].oc_class]);
	else if (!strcmp(optname, "catname")) 
		Sprintf(buf, "%s", catname[0] ? catname : none );
	else if (!strcmp(optname, "disclose")) {
		for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
			char topt[2];
			if (i) Strcat(buf," ");
			topt[1] = '\0';
			topt[0] = flags.end_disclose[i];
			Strcat(buf, topt);
			topt[0] = disclosure_options[i];
			Strcat(buf, topt);
		}
	}
	else if (!strcmp(optname, "dogname")) 
		Sprintf(buf, "%s", dogname[0] ? dogname : none );
	else if (!strcmp(optname, "dungeon"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "effects"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "font_map"))
		Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
	else if (!strcmp(optname, "font_message"))
		Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt);
	else if (!strcmp(optname, "font_status"))
		Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt);
	else if (!strcmp(optname, "font_menu"))
		Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
	else if (!strcmp(optname, "font_text"))
		Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt);
	else if (!strcmp(optname, "font_size_map")) {
		if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "font_size_message")) {
		if (iflags.wc_fontsiz_message) Sprintf(buf, "%d",
							iflags.wc_fontsiz_message);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "font_size_status")) {
		if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "font_size_menu")) {
		if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "font_size_text")) {
		if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "fruit")) 
		Sprintf(buf, "%s", pl_fruit);
	else if (!strcmp(optname, "gender"))
		Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
	else if (!strcmp(optname, "horsename")) 
		Sprintf(buf, "%s", horsename[0] ? horsename : none);
	else if (!strcmp(optname, "map_mode"))
		Sprintf(buf, "%s",
			iflags.wc_map_mode == MAP_MODE_TILES      ? "tiles" :
			iflags.wc_map_mode == MAP_MODE_ASCII4x6   ? "ascii4x6" :
			iflags.wc_map_mode == MAP_MODE_ASCII6x8   ? "ascii6x8" :
			iflags.wc_map_mode == MAP_MODE_ASCII8x8   ? "ascii8x8" :
			iflags.wc_map_mode == MAP_MODE_ASCII16x8  ? "ascii16x8" :
			iflags.wc_map_mode == MAP_MODE_ASCII7x12  ? "ascii7x12" :
			iflags.wc_map_mode == MAP_MODE_ASCII8x12  ? "ascii8x12" :
			iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" :
			iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" :
			iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" :
			iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ?
			"fit_to_screen" : defopt);
	else if (!strcmp(optname, "menustyle")) 
		Sprintf(buf, "%s", menutype[(int)flags.menu_style] );
	else if (!strcmp(optname, "menu_deselect_all"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_deselect_page"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_first_page"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_invert_all"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_headings")) {
		Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ?
			"bold" :   (iflags.menu_headings == ATR_INVERSE) ?
			"inverse" :   (iflags.menu_headings == ATR_ULINE) ?
			"underline" : "unknown");
	}
	else if (!strcmp(optname, "menu_invert_page"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_last_page"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_next_page"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_previous_page"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_search"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_select_all"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "menu_select_page"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "monsters"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "msghistory"))
		Sprintf(buf, "%u", iflags.msg_history);
#ifdef TTY_GRAPHICS
	else if (!strcmp(optname, "msg_window"))
		Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
					(iflags.prevmsg_window=='c') ? "combination" :
					(iflags.prevmsg_window=='f') ? "full" : "reversed");
#endif
	else if (!strcmp(optname, "name"))
		Sprintf(buf, "%s", plname);
	else if (!strcmp(optname, "number_pad"))
		Sprintf(buf, "%s",
			(!iflags.num_pad) ? "0=off" :
			(iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on");
	else if (!strcmp(optname, "objects"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "packorder")) {
		oc_to_str(flags.inv_order, ocl);
		Sprintf(buf, "%s", ocl);
	     }
#ifdef CHANGE_COLOR
	else if (!strcmp(optname, "palette")) 
		Sprintf(buf, "%s", get_color_string());
#endif
	else if (!strcmp(optname, "pettype")) 
		Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" :
				(preferred_pet == 'd') ? "dog" :
				(preferred_pet == 'n') ? "none" : "random");
	else if (!strcmp(optname, "pickup_burden"))
		Sprintf(buf, "%s", burdentype[flags.pickup_burden] );
	else if (!strcmp(optname, "pickup_types")) {
		oc_to_str(flags.pickup_types, ocl);
		Sprintf(buf, "%s", ocl[0] ? ocl : "all" );
	     }
	else if (!strcmp(optname, "race"))
		Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
	else if (!strcmp(optname, "role"))
		Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
	else if (!strcmp(optname, "runmode"))
		Sprintf(buf, "%s", runmodes[iflags.runmode]);
	else if (!strcmp(optname, "scores")) {
		Sprintf(buf, "%d top/%d around%s", flags.end_top,
				flags.end_around, flags.end_own ? "/own" : "");
	}
	else if (!strcmp(optname, "scroll_amount")) {
		if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "scroll_margin")) {
		if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "player_selection"))
		Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
#ifdef MSDOS
	else if (!strcmp(optname, "soundcard"))
		Sprintf(buf, "%s", to_be_done);
#endif
	else if (!strcmp(optname, "suppress_alert")) {
	    if (flags.suppress_alert == 0L)
		Strcpy(buf, none);
	    else
		Sprintf(buf, "%lu.%lu.%lu",
			FEATURE_NOTICE_VER_MAJ,
			FEATURE_NOTICE_VER_MIN,
			FEATURE_NOTICE_VER_PATCH);
	}
	else if (!strcmp(optname, "tile_file"))
		Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
	else if (!strcmp(optname, "tile_height")) {
		if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "tile_width")) {
		if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width);
		else Strcpy(buf, defopt);
	}
	else if (!strcmp(optname, "traps"))
		Sprintf(buf, "%s", to_be_done);
	else if (!strcmp(optname, "vary_msgcount")) {
		if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount);
		else Strcpy(buf, defopt);
	}
#ifdef MSDOS
	else if (!strcmp(optname, "video"))
		Sprintf(buf, "%s", to_be_done);
#endif
#ifdef VIDEOSHADES
	else if (!strcmp(optname, "videoshades"))
		Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]);
	else if (!strcmp(optname, "videocolors"))
		Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
			ttycolors[CLR_RED], ttycolors[CLR_GREEN],
			ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
			ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
			ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
			ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
			ttycolors[CLR_BRIGHT_MAGENTA],
			ttycolors[CLR_BRIGHT_CYAN]);
#endif /* VIDEOSHADES */
	else if (!strcmp(optname, "windowtype"))
		Sprintf(buf, "%s", windowprocs.name);
	else if (!strcmp(optname, "windowcolors"))
		Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s",
			iflags.wc_foregrnd_menu    ? iflags.wc_foregrnd_menu : defbrief,
			iflags.wc_backgrnd_menu    ? iflags.wc_backgrnd_menu : defbrief,
			iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief,
			iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief,
			iflags.wc_foregrnd_status  ? iflags.wc_foregrnd_status : defbrief,
			iflags.wc_backgrnd_status  ? iflags.wc_backgrnd_status : defbrief,
			iflags.wc_foregrnd_text    ? iflags.wc_foregrnd_text : defbrief,
			iflags.wc_backgrnd_text    ? iflags.wc_backgrnd_text : defbrief);
#ifdef PREFIXES_IN_USE
	else {
	    for (i = 0; i < PREFIX_COUNT; ++i)
		if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
			Sprintf(buf, "%s", fqn_prefix[i]);
	}
#endif

	if (buf[0]) return buf;
	else return "unknown";
}

dotogglepickup

int
dotogglepickup()
{
	char buf[BUFSZ], ocl[MAXOCLASSES+1];

	flags.pickup = !flags.pickup;
	if (flags.pickup) {
	    oc_to_str(flags.pickup_types, ocl);
	    Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
#ifdef AUTOPICKUP_EXCEPTIONS
			(iflags.autopickup_exceptions[AP_LEAVE] ||
			 iflags.autopickup_exceptions[AP_GRAB]) ?
			 ((count_ape_maps((int *)0, (int *)0) == 1) ?
			    ", with one exception" : ", with some exceptions") :
#endif
			"");
	} else {
	    Strcpy(buf, "OFF");
	}
	pline("Autopickup: %s.", buf);
	return 0;
}

add_autopickup_exception

#ifdef AUTOPICKUP_EXCEPTIONS
int
add_autopickup_exception(mapping)
const char *mapping;
{
	struct autopickup_exception *ape, **apehead;
	char text[256], *text2;
	int textsize = 0;
	boolean grab = FALSE;

	if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
		text2 = &text[0];
		if (*text2 == '<') {		/* force autopickup */
			grab = TRUE;
			++text2;
		} else if (*text2 == '>') {	/* default - Do not pickup */
			grab = FALSE;
			++text2;
		}
		textsize = strlen(text2);
		apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] :
				   &iflags.autopickup_exceptions[AP_LEAVE];
		ape = (struct autopickup_exception *)
				alloc(sizeof(struct autopickup_exception));
		ape->pattern = (char *) alloc(textsize+1);
		Strcpy(ape->pattern, text2);
		ape->grab = grab;
		if (!*apehead) ape->next = (struct autopickup_exception *)0;
		else ape->next = *apehead;
		*apehead = ape;
	} else {
	    raw_print("syntax error in AUTOPICKUP_EXCEPTION");
	    return 0;
	}
	return 1;
}

remove_autopickuo_exception

STATIC_OVL void
remove_autopickup_exception(whichape)
struct autopickup_exception *whichape;
{
struct autopickup_exception *ape, *prev = 0;
int chain = whichape->grab ? AP_GRAB : AP_LEAVE;

for (ape = iflags.autopickup_exceptions[chain]; ape;) {
	if (ape == whichape) {
	    struct autopickup_exception *freeape = ape;
	    ape = ape->next;
	    if (prev) prev->next = ape;
	    else iflags.autopickup_exceptions[chain] = ape;
	    free(freeape->pattern);
	    free(freeape);
	} else {
	    prev = ape;
	    ape = ape->next;
	}
}
}

count_ape_maps

STATIC_OVL int
count_ape_maps(leave, grab)
int *leave, *grab;
{
	struct autopickup_exception *ape;
	int pass, totalapes, numapes[2] = {0,0};

	for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
		ape = iflags.autopickup_exceptions[pass];
		while(ape) {
			ape = ape->next;
			numapes[pass]++;
		}
	}
	totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
	if (leave) *leave = numapes[AP_LEAVE];
	if (grab) *grab = numapes[AP_GRAB];
	return totalapes;
}

free_autopickup_exceptions

void
free_autopickup_exceptions()
{
	struct autopickup_exception *ape;
	int pass;

	for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
		while((ape = iflags.autopickup_exceptions[pass]) != 0) {
			free(ape->pattern);
			iflags.autopickup_exceptions[pass] = ape->next;
			free(ape);
		}
	}
}
#endif /* AUTOPICKUP_EXCEPTIONS */

option_help

/* data for option_help() */
static const char *opt_intro[] = {
	"",
	"                 NetHack Options Help:",
	"",
#define CONFIG_SLOT 3	/* fill in next value at run-time */
	(char *)0,
#if !defined(MICRO) && !defined(MAC)
	"or use `NETHACKOPTIONS=\"<options>\"' in your environment",
#endif
	"(<options> is a list of options separated by commas)",
#ifdef VMS
	"-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
#endif
	"or press \"O\" while playing and use the menu.",
	"",
"Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
	(char *)0
};

static const char *opt_epilog[] = {
	"",
"Some of the options can be set only before the game is started; those",
	"items will not be selectable in the 'O' command's menu.",
	(char *)0
};

void
option_help()
{
char buf[BUFSZ], buf2[BUFSZ];
register int i;
winid datawin;

datawin = create_nhwindow(NHW_TEXT);
Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
opt_intro[CONFIG_SLOT] = (const char *) buf;
for (i = 0; opt_intro[i]; i++)
	putstr(datawin, 0, opt_intro[i]);

/* Boolean options */
for (i = 0; boolopt[i].name; i++) {
	if (boolopt[i].addr) {
#ifdef WIZARD
	    if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue;
	    if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue;
#endif
	    next_opt(datawin, boolopt[i].name);
	}
}
next_opt(datawin, "");

/* Compound options */
putstr(datawin, 0, "Compound options:");
for (i = 0; compopt[i].name; i++) {
	Sprintf(buf2, "`%s'", compopt[i].name);
	Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
		compopt[i+1].name ? ',' : '.');
	putstr(datawin, 0, buf);
}

for (i = 0; opt_epilog[i]; i++)
	putstr(datawin, 0, opt_epilog[i]);

display_nhwindow(datawin, FALSE);
destroy_nhwindow(datawin);
return;
}

next_opt

/*
* prints the next boolean option, on the same line if possible, on a new
* line if not. End with next_opt("").
*/
void
next_opt(datawin, str)
winid datawin;
const char *str;
{
	static char *buf = 0;
	int i;
	char *s;

	if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0';

	if (!*str) {
		s = eos(buf);
		if (s > &buf[1] && s[-2] == ',')
		    Strcpy(s - 2, ".");	/* replace last ", " */
		i = COLNO;	/* (greater than COLNO - 2) */
	} else {
		i = strlen(buf) + strlen(str) + 2;
	}

	if (i > COLNO - 2) { /* rule of thumb */
		putstr(datawin, 0, buf);
		buf[0] = 0;
	}
	if (*str) {
		Strcat(buf, str);
		Strcat(buf, ", ");
	} else {
		putstr(datawin, 0, str);
		free(buf),  buf = 0;
	}
	return;
}

fruitadd

/* Returns the fid of the fruit type; if that type already exists, it
* returns the fid of that one; if it does not exist, it adds a new fruit
* type to the chain and returns the new one.
*/
int
fruitadd(str)
char *str;
{
	register int i;
	register struct fruit *f;
	struct fruit *lastf = 0;
	int highest_fruit_id = 0;
	char buf[PL_FSIZ];
	boolean user_specified = (str == pl_fruit);
	/* if not user-specified, then it's a fruit name for a fruit on
	 * a bones level...
	 */

	/* Note: every fruit has an id (spe for fruit objects) of at least
	 * 1; 0 is an error.
	 */
	if (user_specified) {
		/* disallow naming after other foods (since it'd be impossible
		 * to tell the difference)
		 */

		boolean found = FALSE, numeric = FALSE;

		for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;
						i++) {
			if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
				found = TRUE;
				break;
			}
		}
		{
		    char *c;

		    c = pl_fruit;

		    for(c = pl_fruit; *c >= '0' && *c <= '9'; c++)
			;
		    if (isspace(*c) || *c == 0) numeric = TRUE;
		}
		if (found || numeric ||
		    !strncmp(str, "cursed ", 7) ||
		    !strncmp(str, "uncursed ", 9) ||
		    !strncmp(str, "blessed ", 8) ||
		    !strncmp(str, "partly eaten ", 13) ||
		    (!strncmp(str, "tin of ", 7) &&
			(!strcmp(str+7, "spinach") ||
			 name_to_mon(str+7) >= LOW_PM)) ||
		    !strcmp(str, "empty tin") ||
		    ((!strncmp(eos(str)-7," corpse",7) ||
			    !strncmp(eos(str)-4, " egg",4)) &&
			name_to_mon(str) >= LOW_PM))
			{
				Strcpy(buf, pl_fruit);
				Strcpy(pl_fruit, "candied ");
				nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
		}
	}
	for(f=ffruit; f; f = f->nextf) {
		lastf = f;
		if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
		if(!strncmp(str, f->fname, PL_FSIZ))
			goto nonew;
	}
	/* if adding another fruit would overflow spe, use a random
	   fruit instead... we've got a lot to choose from. */
	if (highest_fruit_id >= 127) return rnd(127);
	highest_fruit_id++;
	f = newfruit();
	if (ffruit) lastf->nextf = f;
	else ffruit = f;
	Strcpy(f->fname, str);
	f->fid = highest_fruit_id;
	f->nextf = 0;
nonew:
	if (user_specified) current_fruit = highest_fruit_id;
	return f->fid;
}

choose_classes_menu

/*
* This is a somewhat generic menu for taking a list of NetHack style
* class choices and presenting them via a description
* rather than the traditional NetHack characters.
* (Benefits users whose first exposure to NetHack is via tiles).
*
* prompt
*	     The title at the top of the menu.
*
* category: 0 = monster class
*           1 = object  class
*
* way
*	     FALSE = PICK_ONE, TRUE = PICK_ANY
*
* class_list
*	     a null terminated string containing the list of choices.
*
* class_selection
*	     a null terminated string containing the selected characters.
*
* Returns number selected.
*/
int
choose_classes_menu(prompt, category, way, class_list, class_select)
const char *prompt;
int category;
boolean way;
char *class_list;
char *class_select;
{
menu_item *pick_list = (menu_item *)0;
winid win;
anything any;
char buf[BUFSZ];
int i, n;
int ret;
int next_accelerator, accelerator;

if (class_list == (char *)0 || class_select == (char *)0) return 0;
accelerator = 0;
next_accelerator = 'a';
any.a_void = 0;
win = create_nhwindow(NHW_MENU);
start_menu(win);
while (*class_list) {
	const char *text;
	boolean selected;

	text = (char *)0;
	selected = FALSE;
	switch (category) {
		case 0:
			text = monexplain[def_char_to_monclass(*class_list)];
			accelerator = *class_list;
			Sprintf(buf, "%s", text);
			break;
		case 1:
			text = objexplain[def_char_to_objclass(*class_list)];
			accelerator = next_accelerator;
			Sprintf(buf, "%c  %s", *class_list, text);
			break;
		default:
			impossible("choose_classes_menu: invalid category %d",
					category);
	}
	if (way && *class_select) {	/* Selections there already */
		if (index(class_select, *class_list)) {
			selected = TRUE;
		}
	}
	any.a_int = *class_list;
	add_menu(win, NO_GLYPH, &any, accelerator,
		  category ? *class_list : 0,
		  ATR_NONE, buf, selected);
	++class_list;
	if (category > 0) {
		++next_accelerator;
		if (next_accelerator == ('z' + 1)) next_accelerator = 'A';
		if (next_accelerator == ('Z' + 1)) break;
	}
}
end_menu(win, prompt);
n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
destroy_nhwindow(win);
if (n > 0) {
	for (i = 0; i < n; ++i)
	    *class_select++ = (char)pick_list[i].item.a_int;
	free((genericptr_t)pick_list);
	ret = n;
} else if (n == -1) {
	class_select = eos(class_select);
	ret = -1;
} else
	ret = 0;
*class_select = '\0';
return ret;
}
struct wc_Opt wc_options[] = {
	{"ascii_map", WC_ASCII_MAP},
	{"color", WC_COLOR},
	{"eight_bit_tty", WC_EIGHT_BIT_IN},
	{"hilite_pet", WC_HILITE_PET},
	{"popup_dialog", WC_POPUP_DIALOG},
	{"player_selection", WC_PLAYER_SELECTION},
	{"preload_tiles", WC_PRELOAD_TILES},
	{"tiled_map", WC_TILED_MAP},
	{"tile_file", WC_TILE_FILE},
	{"tile_width", WC_TILE_WIDTH},
	{"tile_height", WC_TILE_HEIGHT},
	{"use_inverse", WC_INVERSE},
	{"align_message", WC_ALIGN_MESSAGE},
	{"align_status", WC_ALIGN_STATUS},
	{"font_map", WC_FONT_MAP},
	{"font_menu", WC_FONT_MENU},
	{"font_message",WC_FONT_MESSAGE},
#if 0
	{"perm_invent",WC_PERM_INVENT},
#endif
	{"font_size_map", WC_FONTSIZ_MAP},
	{"font_size_menu", WC_FONTSIZ_MENU},
	{"font_size_message", WC_FONTSIZ_MESSAGE},
	{"font_size_status", WC_FONTSIZ_STATUS},
	{"font_size_text", WC_FONTSIZ_TEXT},
	{"font_status", WC_FONT_STATUS},
	{"font_text", WC_FONT_TEXT},
	{"map_mode", WC_MAP_MODE},
	{"scroll_amount", WC_SCROLL_AMOUNT},
	{"scroll_margin", WC_SCROLL_MARGIN},
	{"splash_screen", WC_SPLASH_SCREEN},
	{"vary_msgcount",WC_VARY_MSGCOUNT},
	{"windowcolors", WC_WINDOWCOLORS},
	{"mouse_support", WC_MOUSE_SUPPORT},
	{(char *)0, 0L}
};

struct wc_Opt wc2_options[] = {
	{"fullscreen", WC2_FULLSCREEN},
	{"softkeyboard", WC2_SOFTKEYBOARD},
	{"wraptext", WC2_WRAPTEXT},
	{(char *)0, 0L}
};

set_option_mod_status

/*
* 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)
const 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;
		}
	}
}

set_wc_option_mod_status

/*
* 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_wc_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++;
	}
}

is_wc_option

STATIC_OVL boolean
is_wc_option(optnam)
const char *optnam;
{
	int k = 0;
	while (wc_options[k].wc_name) {
		if (strcmp(wc_options[k].wc_name, optnam) == 0)
			return TRUE;
		k++;
	}
	return FALSE;
}

wc_supported

STATIC_OVL boolean
wc_supported(optnam)
const char *optnam;
{
	int k = 0;
	while (wc_options[k].wc_name) {
		if (!strcmp(wc_options[k].wc_name, optnam) &&
		    (windowprocs.wincap & wc_options[k].wc_bit))
			return TRUE;
		k++;
	}
	return FALSE;
}

set_wc2_option_mod_status

/*
* You can set several wc2_options in one call to
* set_wc2_option_mod_status() by setting
* the appropriate bits for each option that you
* are setting in the optmask argument
* prior to calling.
*    example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE);
*/

void
set_wc2_option_mod_status(optmask, status)
unsigned long optmask;
int status;
{
	int k = 0;
	if (status < SET_IN_FILE || status > SET_IN_GAME) {
		impossible("set_wc2_option_mod_status: status out of range %d.",
			   status);
		return;
	}
	while (wc2_options[k].wc_name) {
		if (optmask & wc2_options[k].wc_bit) {
			set_option_mod_status(wc2_options[k].wc_name, status);
		}
		k++;
	}
}

is_wc2_option

STATIC_OVL boolean
is_wc2_option(optnam)
const char *optnam;
{
	int k = 0;
	while (wc2_options[k].wc_name) {
		if (strcmp(wc2_options[k].wc_name, optnam) == 0)
			return TRUE;
		k++;
	}
	return FALSE;
}

wc2_supported

STATIC_OVL boolean
wc2_supported(optnam)
const char *optnam;
{
	int k = 0;
	while (wc2_options[k].wc_name) {
		if (!strcmp(wc2_options[k].wc_name, optnam) &&
		    (windowprocs.wincap2 & wc2_options[k].wc_bit))
			return TRUE;
		k++;
	}
	return FALSE;
}

wc_set_font_name

STATIC_OVL void
wc_set_font_name(wtype, fontname)
int wtype;
char *fontname;
{
	char **fn = (char **)0;
	if (!fontname) return;
	switch(wtype) {
	    case NHW_MAP:
	    		fn = &iflags.wc_font_map;
			break;
	    case NHW_MESSAGE:
	    		fn = &iflags.wc_font_message;
			break;
	    case NHW_TEXT:
	    		fn = &iflags.wc_font_text;
			break;
	    case NHW_MENU:
	    		fn = &iflags.wc_font_menu;
			break;
	    case NHW_STATUS:
	    		fn = &iflags.wc_font_status;
			break;
	    default:
	    		return;
	}
	if (fn) {
		if (*fn) free(*fn);
		*fn = (char *)alloc(strlen(fontname) + 1);
		Strcpy(*fn, fontname);
	}
	return;
}

wc_set_window_colors

STATIC_OVL int
wc_set_window_colors(op)
char *op;
{
	/* syntax:
	 *  menu white/black message green/yellow status white/blue text white/black
	 */

	int j;
	char buf[BUFSZ];
	char *wn, *tfg, *tbg, *newop;
	static const char *wnames[] = { "menu", "message", "status", "text" };
	static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
	static char **fgp[] = {
		&iflags.wc_foregrnd_menu,
		&iflags.wc_foregrnd_message,
		&iflags.wc_foregrnd_status,
		&iflags.wc_foregrnd_text
	};
	static char **bgp[] = {
		&iflags.wc_backgrnd_menu,
		&iflags.wc_backgrnd_message,
		&iflags.wc_backgrnd_status,
		&iflags.wc_backgrnd_text
	};

	Strcpy(buf, op);
	newop = mungspaces(buf);
	while (newop && *newop) {

		wn = tfg = tbg = (char *)0;

		/* until first non-space in case there's leading spaces - before colorname*/
		while(*newop && isspace(*newop)) newop++;
		if (*newop) wn = newop;
		else return 0;

		/* until first space - colorname*/
		while(*newop && !isspace(*newop)) newop++;
		if (*newop) *newop = '\0';
		else return 0;
		newop++;

		/* until first non-space - before foreground*/
		while(*newop && isspace(*newop)) newop++;
		if (*newop) tfg = newop;
		else return 0;

		/* until slash - foreground */
		while(*newop && *newop != '/') newop++;
		if (*newop) *newop = '\0';
		else return 0;
		newop++;

		/* until first non-space (in case there's leading space after slash) - before background */
		while(*newop && isspace(*newop)) newop++;
		if (*newop) tbg = newop;
		else return 0;

		/* until first space - background */
		while(*newop && !isspace(*newop)) newop++;
		if (*newop) *newop++ = '\0';

		for (j = 0; j < 4; ++j) {
			if (!strcmpi(wn, wnames[j]) ||
			    !strcmpi(wn, shortnames[j])) {
				if (tfg && !strstri(tfg, " ")) {
					if (*fgp[j]) free(*fgp[j]);
					*fgp[j] = (char *)alloc(strlen(tfg) + 1);
					Strcpy(*fgp[j], tfg);
				}
				if (tbg && !strstri(tbg, " ")) {
					if (*bgp[j]) free(*bgp[j]);
					*bgp[j] = (char *)alloc(strlen(tbg) + 1);
					Strcpy(*bgp[j], tbg);
				}
				break;
			}
		}
	}
	return 1;
}

#endif	/* OPTION_LISTS_ONLY */

/*options.c*/