Source:SLASH'EM 0.0.7E7F2/options.c

From NetHackWiki
Revision as of 19:28, 7 March 2008 by Kernigh bot (talk | contribs) (SLASH'EM 0.0.7E7F2/options.c moved to Source:SLASH'EM 0.0.7E7F2/options.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to options.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/options.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


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.

1.    /*	SCCS Id: @(#)options.c	3.4	2003/11/14	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #ifdef OPTION_LISTS_ONLY	/* (AMIGA) external program for opt lists */
6.    #include "config.h"
7.    #include "objclass.h"
8.    #include "flag.h"
9.    NEARDATA struct flag flags;	/* provide linkage */
10.   NEARDATA struct instance_flags iflags;	/* provide linkage */
11.   #define static
12.   #else
13.   #include "hack.h"
14.   #include "tcap.h"
15.   #include <ctype.h>
16.   #endif
17.   
18.   #if defined(GL_GRAPHICS) || defined(SDL_GRAPHICS)
19.   #include "winGL.h"  /* Sdlgl_parse_options */
20.   #endif
21.   
22.   #include "filename.h"
23.   
24.   #define WINTYPELEN 16
25.   
26.   #ifdef DEFAULT_WC_TILED_MAP
27.   #define PREFER_TILED TRUE
28.   #else
29.   #define PREFER_TILED FALSE
30.   #endif
31.   
32.   /*
33.    *  NOTE:  If you add (or delete) an option, please update the short
34.    *  options help (option_help()), the long options help (dat/opthelp),
35.    *  and the current options setting display function (doset()),
36.    *  and also the Guidebooks.
37.    *
38.    *  The order matters.  If an option is a an initial substring of another
39.    *  option (e.g. time and timed_delay) the shorter one must come first.
40.    */
41.   
42.   static struct Bool_Opt
43.   {
44.   	const char *name;
45.   	boolean	*addr, initvalue;
46.   	int optflags;
47.   } boolopt[] = {
48.   #ifdef AMIGA
49.   	{"altmeta", &flags.altmeta, TRUE, DISP_IN_GAME},
50.   #else
51.   	{"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
52.   #endif
53.   	{"ascii_map",     &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME},	/*WC*/
54.   #ifdef MFLOPPY
55.   	{"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME},
56.   #else
57.   	{"asksavedisk", (boolean *)0, FALSE, SET_IN_GAME},
58.   #endif
59.   	{"autodig", &flags.autodig, FALSE, SET_IN_GAME},
60.   	{"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
61.   	{"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
62.   #if defined(MICRO) && !defined(AMIGA)
63.   	{"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE},
64.   #else
65.   	{"BIOS", (boolean *)0, FALSE, SET_IN_FILE},
66.   #endif
67.   #ifdef INSURANCE
68.   	{"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME},
69.   #else
70.   	{"checkpoint", (boolean *)0, FALSE, SET_IN_FILE},
71.   #endif
72.   #ifdef MFLOPPY
73.   	{"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME},
74.   #else
75.   	{"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
76.   #endif
77.   	{"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
78.   # if defined(MICRO) || defined(WIN32)
79.   	{"color",         &iflags.wc_color,TRUE, SET_IN_GAME},		/*WC*/
80.   # else	/* systems that support multiple terminals, many monochrome */
81.   	{"color",         &iflags.wc_color, FALSE, SET_IN_GAME},	/*WC*/
82.   # endif
83.   	{"confirm",&flags.confirm, TRUE, SET_IN_GAME},
84.   #if defined(TERMLIB) && !defined(MAC_GRAPHICS_ENV)
85.   	{"DECgraphics", &iflags.DECgraphics, FALSE, SET_IN_GAME},
86.   #else
87.   	{"DECgraphics", (boolean *)0, FALSE, SET_IN_FILE},
88.   #endif
89.   	{"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME},	/*WC*/
90.   #ifdef TTY_GRAPHICS
91.   	{"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME},
92.   #else
93.   	{"extmenu", (boolean *)0, FALSE, SET_IN_FILE},
94.   #endif
95.   #ifdef OPT_DISPMAP
96.   	{"fast_map", &flags.fast_map, TRUE, SET_IN_GAME},
97.   #else
98.   	{"fast_map", (boolean *)0, TRUE, SET_IN_FILE},
99.   #endif
100.  	{"female", &flags.female, FALSE, DISP_IN_GAME},
101.  	{"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME},
102.  #ifdef AMIFLUSH
103.  	{"flush", &flags.amiflush, FALSE, SET_IN_GAME},
104.  #else
105.  	{"flush", (boolean *)0, FALSE, SET_IN_FILE},
106.  #endif
107.  	{"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE},
108.  	{"help", &flags.help, TRUE, SET_IN_GAME},
109.  	{"hilite_pet",    &iflags.wc_hilite_pet, FALSE, SET_IN_GAME},	/*WC*/
110.  #ifdef ASCIIGRAPH
111.  	{"IBMgraphics", &iflags.IBMgraphics, FALSE, SET_IN_GAME},
112.  #else
113.  	{"IBMgraphics", (boolean *)0, FALSE, SET_IN_FILE},
114.  #endif
115.  #ifndef MAC
116.  	{"ignintr", &flags.ignintr, FALSE, SET_IN_GAME},
117.  #else
118.  	{"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
119.  #endif
120.  #ifdef SHOW_WEIGHT
121.  	{"invweight", &flags.invweight, FALSE, SET_IN_GAME},
122.  #else
123.  	{"invweight", (boolean *)0, FALSE, SET_IN_FILE},
124.  #endif
125.  /*WAC the keep savefile option...*/
126.  #ifdef KEEP_SAVE
127.  	{"keep_savefile", &flags.keep_savefile, FALSE, SET_IN_FILE},
128.  #else
129.  	{"keep_savefile", (boolean *)0, FALSE, DISP_IN_GAME},
130.  #endif
131.  	{"large_font", &iflags.obsolete, FALSE, SET_IN_FILE},	/* OBSOLETE */
132.  	{"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
133.  	{"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
134.  	{"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME},
135.  #ifdef MAC_GRAPHICS_ENV
136.  	{"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME},
137.  #else
138.  	{"Macgraphics", (boolean *)0, FALSE, SET_IN_FILE},
139.  #endif
140.  #ifdef MAIL
141.  	{"mail", &flags.biff, TRUE, SET_IN_GAME},
142.  #else
143.  	{"mail", (boolean *)0, TRUE, SET_IN_FILE},
144.  #endif
145.  #ifdef MENU_COLOR
146.  # ifdef MICRO
147.  	{"menucolors", &iflags.use_menu_color, TRUE,  SET_IN_GAME},
148.  # else
149.  	{"menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME},
150.  # endif
151.  #else
152.  	{"menucolors", (boolean *)0, FALSE, SET_IN_GAME},
153.  #endif
154.  	{"menu_on_esc", &flags.menu_on_esc, TRUE, SET_IN_GAME},
155.  #ifdef WIZARD
156.  	/* for menu debugging only*/
157.  	{"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
158.  #else
159.  	{"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
160.  #endif
161.  #ifdef WIZARD
162.  	{"mon_polycontrol", &iflags.mon_polycontrol, FALSE, SET_IN_GAME},
163.  #else
164.  	{"mon_polycontrol", (boolean *)0, FALSE, SET_IN_FILE},
165.  #endif
166.  	{"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME},	/*WC*/
167.  #ifdef NEWS
168.  	{"news", &iflags.news, TRUE, DISP_IN_GAME},
169.  #else
170.  	{"news", (boolean *)0, FALSE, SET_IN_FILE},
171.  #endif
172.  	{"null", &flags.null, TRUE, SET_IN_GAME},
173.  #ifdef MAC
174.  	{"page_wait", &flags.page_wait, TRUE, SET_IN_GAME},
175.  #else
176.  	{"page_wait", (boolean *)0, FALSE, SET_IN_FILE},
177.  #endif
178.  	{"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME},
179.  	{"pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME},
180.  	{"popup_dialog",  &iflags.wc_popup_dialog, FALSE, SET_IN_GAME},	/*WC*/
181.  	{"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME},
182.  	{"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME},	/*WC*/
183.  	{"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
184.  	{"radar", (boolean *)0, FALSE, SET_IN_FILE},	/* OBSOLETE */
185.  #if defined(MICRO) && !defined(AMIGA)
186.  	{"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
187.  #else
188.  	{"rawio", (boolean *)0, FALSE, SET_IN_FILE},
189.  #endif
190.  	{"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
191.  	{"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
192.  #if defined(OBJ_SANITY)
193.  	{"sanity_check", &iflags.sanity_check, TRUE, SET_IN_GAME},
194.  #elif defined(WIZARD)
195.  	{"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
196.  #else
197.  	{"sanity_check", (boolean *)0, FALSE, SET_IN_FILE},
198.  #endif
199.  #ifdef EXP_ON_BOTL
200.  	{"showexp", &flags.showexp, FALSE, SET_IN_GAME},
201.  #else
202.  	{"showexp", (boolean *)0, FALSE, SET_IN_FILE},
203.  #endif
204.  	{"showrace", &iflags.showrace, FALSE, SET_IN_GAME},
205.  #ifdef SCORE_ON_BOTL
206.  	{"showscore", &flags.showscore, FALSE, SET_IN_GAME},
207.  #else
208.  	{"showscore", (boolean *)0, FALSE, SET_IN_FILE},
209.  #endif
210.  /* WAC made the [ xx pts]  dmg display optional */
211.  #ifdef SHOW_DMG
212.  	{"showdmg", &flags.showdmg, FALSE, SET_IN_GAME},
213.  #else
214.  	{"showdmg", (boolean *)0, FALSE, SET_IN_FILE},
215.  #endif
216.  #ifdef SHOW_WEIGHT
217.  	{"showweight", &flags.showweight, FALSE, SET_IN_GAME},
218.  #else
219.  	{"showweight", (boolean *)0, FALSE, SET_IN_FILE},
220.  #endif
221.  	{"silent", &flags.silent, TRUE, SET_IN_GAME},
222.  	{"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE},
223.  	{"sortpack", &flags.sortpack, TRUE, SET_IN_GAME},
224.  	{"sound", &flags.soundok, TRUE, SET_IN_GAME},
225.  	{"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
226.  	{"standout", &flags.standout, FALSE, SET_IN_GAME},
227.  	{"splash_screen",     &iflags.wc_splash_screen, TRUE, DISP_IN_GAME},	/*WC*/
228.  	{"tiled_map",     &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME},	/*WC*/
229.  	{"time", &flags.time, FALSE, SET_IN_GAME},
230.  #ifdef TIMED_DELAY
231.  	{"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
232.  #else
233.  	{"timed_delay", (boolean *)0, FALSE, SET_IN_GAME},
234.  #endif
235.  	{"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
236.  	{"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME},
237.  	{"travel", &iflags.travelcmd, TRUE, SET_IN_GAME},
238.  #ifdef WIN32CON
239.  	{"use_inverse",   &iflags.wc_inverse, TRUE, SET_IN_GAME},		/*WC*/
240.  #else
241.  	{"use_inverse",   &iflags.wc_inverse, FALSE, SET_IN_GAME},		/*WC*/
242.  #endif
243.  	{"verbose", &flags.verbose, TRUE, SET_IN_GAME},
244.  	{"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
245.  	{(char *)0, (boolean *)0, FALSE, 0}
246.  };
247.  
248.  genericptr_t nh_option_get_boolopt()
249.  {
250.      return (genericptr_t)boolopt;
251.  }
252.  
253.  /* compound options, for option_help() and external programs like Amiga
254.   * frontend */
255.  static struct Comp_Opt
256.  {
257.  	const char *name, *descr;
258.  	int size;	/* for frontends and such allocating space --
259.  			 * usually allowed size of data in game, but
260.  			 * occasionally maximum reasonable size for
261.  			 * typing when game maintains information in
262.  			 * a different format */
263.  	int optflags;
264.  } compopt[] = {
265.  	{ "align",    "your starting alignment (lawful, neutral, or chaotic)",
266.  						8, DISP_IN_GAME },
267.  	{ "align_message", "message window alignment", 20, DISP_IN_GAME }, 	/*WC*/
268.  	{ "align_status", "status window alignment", 20, DISP_IN_GAME }, 	/*WC*/
269.  	{ "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
270.  	{ "boulder",  "the symbol to use for displaying boulders",
271.  						1, SET_IN_GAME },
272.  	{ "catname",  "the name of your (first) cat (e.g., catname:Tabby)",
273.  						PL_PSIZ, DISP_IN_GAME },
274.  	{ "disclose", "the kinds of information to disclose at end of game",
275.  						sizeof(flags.end_disclose) * 2,
276.  						SET_IN_GAME },
277.  	{ "dogname",  "the name of your (first) dog (e.g., dogname:Fang)",
278.  						PL_PSIZ, DISP_IN_GAME },
279.  	{ "dungeon",  "the symbols to use in drawing the dungeon map",
280.  						MAXDCHARS+1, SET_IN_FILE },
281.  	{ "effects",  "the symbols to use in drawing special effects",
282.  						MAXECHARS+1, SET_IN_FILE },
283.  	{ "font_map", "the font to use in the map window", 40, DISP_IN_GAME },	/*WC*/
284.  	{ "font_menu", "the font to use in menus", 40, DISP_IN_GAME },		/*WC*/
285.  	{ "font_message", "the font to use in the message window",
286.  						40, DISP_IN_GAME },		/*WC*/
287.  	{ "font_size_map", "the size of the map font", 20, DISP_IN_GAME },	/*WC*/
288.  	{ "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME },	/*WC*/
289.  	{ "font_size_message", "the size of the message font", 20, DISP_IN_GAME },	/*WC*/
290.  	{ "font_size_status", "the size of the status font", 20, DISP_IN_GAME },	/*WC*/
291.  	{ "font_size_text", "the size of the text font", 20, DISP_IN_GAME },	/*WC*/
292.  	{ "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/
293.  	{ "font_text", "the font to use in text windows", 40, DISP_IN_GAME },	/*WC*/
294.  	{ "fruit",    "the name of a fruit you enjoy eating",
295.  						PL_FSIZ, SET_IN_GAME },
296.  	{ "gender",   "your starting gender (male or female)",
297.  						8, DISP_IN_GAME },
298.  	{ "ghoulname",  "the name of your (first) ghoul (e.g., ghoulname:Casper)",
299.  						PL_PSIZ, DISP_IN_GAME },
300.  	{ "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
301.  						PL_PSIZ, DISP_IN_GAME },
302.  	{ "map_mode", "map display mode under Windows", 20, DISP_IN_GAME },	/*WC*/
303.          { "menucolor", "set menu colors", PL_PSIZ, SET_IN_FILE },
304.  	{ "menustyle", "user interface for object selection",
305.  						MENUTYPELEN, SET_IN_GAME },
306.  	{ "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
307.  	{ "menu_deselect_page", "deselect all items on this page of a menu",
308.  						4, SET_IN_FILE },
309.  	{ "menu_first_page", "jump to the first page in a menu",
310.  						4, SET_IN_FILE },
311.  	{ "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME },
312.  	{ "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
313.  	{ "menu_invert_page", "invert all items on this page of a menu",
314.  						4, SET_IN_FILE },
315.  	{ "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
316.  	{ "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
317.  	{ "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
318.  	{ "menu_search", "search for a menu item", 4, SET_IN_FILE },
319.  	{ "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
320.  	{ "menu_select_page", "select all items on this page of a menu",
321.  						4, SET_IN_FILE },
322.  	{ "monsters", "the symbols to use for monsters",
323.  						MAXMCLASSES, SET_IN_FILE },
324.  	{ "msghistory", "number of top line messages to save",
325.  						5, DISP_IN_GAME },
326.  # ifdef TTY_GRAPHICS
327.  	{"msg_window", "the type of message window required",1, SET_IN_GAME},
328.  # else
329.  	{"msg_window", "the type of message window required", 1, SET_IN_FILE},
330.  # endif
331.  	{ "name",     "your character's name (e.g., name:Merlin-W)",
332.  						PL_NSIZ, DISP_IN_GAME },
333.  	{ "number_pad", "use the number pad", 1, SET_IN_GAME},
334.  	{ "objects",  "the symbols to use for objects",
335.  						MAXOCLASSES, SET_IN_FILE },
336.  	{ "packorder", "the inventory order of the items in your pack",
337.  						MAXOCLASSES, SET_IN_GAME },
338.  #ifdef CHANGE_COLOR
339.  	{ "palette",  "palette (00c/880/-fff is blue/yellow/reverse white)",
340.  						15 , SET_IN_GAME },
341.  # if defined(MAC)
342.  	{ "hicolor",  "same as palette, only order is reversed",
343.  						15, SET_IN_FILE },
344.  # endif
345.  #endif
346.  	{ "pettype",  "your preferred initial pet type", 4, DISP_IN_GAME },
347.  	{ "pickup_burden",  "maximum burden picked up before prompt",
348.  						20, SET_IN_GAME },
349.  	{ "pickup_types", "types of objects to pick up automatically",
350.  						MAXOCLASSES, SET_IN_GAME },
351.  	{ "player_selection", "choose character via dialog or prompts",
352.  						12, DISP_IN_GAME },
353.  	{ "race",     "your starting race (e.g., Human, Elf)",
354.  						PL_CSIZ, DISP_IN_GAME },
355.  	{ "role",     "your starting role (e.g., Barbarian, Valkyrie)",
356.  						PL_CSIZ, DISP_IN_GAME },
357.  	{ "runmode", "display frequency when `running' or `travelling'",
358.  						sizeof "teleport", SET_IN_GAME },
359.  	{ "scores",   "the parts of the score list you wish to see",
360.  						32, SET_IN_GAME },
361.  	{ "scroll_amount", "amount to scroll map when scroll_margin is reached",
362.  						20, DISP_IN_GAME }, /*WC*/
363.  	{ "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
364.  #ifdef MSDOS
365.  	{ "soundcard", "type of sound card to use", 20, SET_IN_FILE },
366.  #endif
367.  	{ "suppress_alert", "suppress alerts about version-specific features",
368.  						8, SET_IN_GAME },
369.  	{ "tile_width", "width of tiles", 20, DISP_IN_GAME},	/*WC*/
370.  	{ "tile_height", "height of tiles", 20, DISP_IN_GAME},	/*WC*/
371.  	{ "tile_file", "name of tile file", 70, DISP_IN_GAME},	/*WC*/
372.  	{ "tileset",  "name of predefined tileset to use",
373.  						PL_PSIZ, SET_IN_GAME },
374.  	{ "traps",    "the symbols to use in drawing traps",
375.  						MAXTCHARS+1, SET_IN_FILE },
376.  	{ "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
377.  #ifdef MSDOS
378.  	{ "video",    "method of video updating", 20, SET_IN_FILE },
379.  #endif
380.  #ifdef VIDEOSHADES
381.  	{ "videocolors", "color mappings for internal screen routines",
382.  						40, DISP_IN_GAME },
383.  #ifdef MSDOS
384.  	{ "videoshades", "gray shades to map to black/gray/white",
385.  						32, DISP_IN_GAME },
386.  #endif
387.  #endif
388.  #ifdef WIN32CON
389.  	{"subkeyvalue", "override keystroke value", 7, SET_IN_FILE},
390.  #endif
391.  	{ "windowcolors",  "the foreground/background colors of windows",	/*WC*/
392.  						80, DISP_IN_GAME },
393.  	{ "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
394.  	{ "wolfname",  "the name of your (first) wolf (e.g., wolfname:Beast)",
395.  						PL_PSIZ, DISP_IN_GAME },
396.  	{ (char *)0, (char *)0, 0, 0 }
397.  };
398.  
399.  static struct Bool_Tile_Opt
400.  {
401.  	const char *name;
402.  	unsigned long flag;
403.  	unsigned long initvalue;
404.  } booltileopt[] = {
405.  	{"transparent", TILESET_TRANSPARENT, 0},
406.  	{"pseudo3D", TILESET_PSEUDO3D, 0},
407.  	{(char *)0, 0, 0}
408.  };
409.  
410.  #ifdef OPTION_LISTS_ONLY
411.  #undef static
412.  
413.  #else	/* use rest of file */
414.  
415.  static boolean need_redraw; /* for doset() */
416.  
417.  #if defined(TOS) && defined(TEXTCOLOR)
418.  extern boolean colors_changed;	/* in tos.c */
419.  #endif
420.  
421.  #ifdef VIDEOSHADES
422.  extern char *shade[3];		  /* in sys/msdos/video.c */
423.  extern char ttycolors[CLR_MAX];	  /* in sys/msdos/video.c, win/tty/termcap.c*/
424.  #endif
425.  
426.  static char def_inv_order[MAXOCLASSES] = {
427.  	COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
428.  	SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
429.  	TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
430.  };
431.  
432.  /*
433.   * Default menu manipulation command accelerators.  These may _not_ be:
434.   *
435.   *	+ a number - reserved for counts
436.   *	+ an upper or lower case US ASCII letter - used for accelerators
437.   *	+ ESC - reserved for escaping the menu
438.   *	+ NULL, CR or LF - reserved for commiting the selection(s).  NULL
439.   *	  is kind of odd, but the tty's xwaitforspace() will return it if
440.   *	  someone hits a <ret>.
441.   *	+ a default object class symbol - used for object class accelerators
442.   *
443.   * Standard letters (for now) are:
444.   *
445.   *		<  back 1 page
446.   *		>  forward 1 page
447.   *		^  first page
448.   *		|  last page
449.   *		:  search
450.   *
451.   *		page		all
452.   *		 ,    select	 .
453.   *		 \    deselect	 -
454.   *		 ~    invert	 @
455.   *
456.   * The command name list is duplicated in the compopt array.
457.   */
458.  typedef struct {
459.      const char *name;
460.      char cmd;
461.  } menu_cmd_t;
462.  
463.  #define NUM_MENU_CMDS 11
464.  static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
465.  /* 0*/	{ "menu_first_page",	MENU_FIRST_PAGE },
466.  	{ "menu_last_page",	MENU_LAST_PAGE },
467.  	{ "menu_next_page",	MENU_NEXT_PAGE },
468.  	{ "menu_previous_page",	MENU_PREVIOUS_PAGE },
469.  	{ "menu_select_all",	MENU_SELECT_ALL },
470.  /* 5*/	{ "menu_deselect_all",	MENU_UNSELECT_ALL },
471.  	{ "menu_invert_all",	MENU_INVERT_ALL },
472.  	{ "menu_select_page",	MENU_SELECT_PAGE },
473.  	{ "menu_deselect_page",	MENU_UNSELECT_PAGE },
474.  	{ "menu_invert_page",	MENU_INVERT_PAGE },
475.  /*10*/	{ "menu_search",		MENU_SEARCH },
476.  };
477.  
478.  /*
479.   * Allow the user to map incoming characters to various menu commands.
480.   * The accelerator list must be a valid C string.
481.   */
482.  #define MAX_MENU_MAPPED_CMDS 32	/* some number */
483.         char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1];	/* exported */
484.  static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1];
485.  static short n_menu_mapped = 0;
486.  
487.  static boolean initial, from_file;
488.  
489.  STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int));
490.  STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
491.  STATIC_DCL void FDECL(escapes, (const char *, char *));
492.  STATIC_DCL void FDECL(rejectoption, (const char *));
493.  STATIC_DCL void FDECL(badoption, (const char *));
494.  STATIC_OVL void FDECL(badtileoption, (const char *));
495.  STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P));
496.  STATIC_OVL char *FDECL(string_for_tile_opt, (char *, BOOLEAN_P));
497.  STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P));
498.  STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P));
499.  STATIC_DCL int FDECL(change_inv_order, (char *));
500.  STATIC_DCL void FDECL(oc_to_str, (char *, char *));
501.  STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int));
502.  STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
503.  STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
504.  STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P));
505.  STATIC_DCL void FDECL(warning_opts, (char *,const char *));
506.  STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int));
507.  
508.  STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
509.  STATIC_OVL int FDECL(wc_set_window_colors, (char *));
510.  STATIC_OVL boolean FDECL(is_wc_option, (const char *));
511.  STATIC_OVL boolean FDECL(wc_supported, (const char *));
512.  STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
513.  STATIC_OVL boolean FDECL(wc2_supported, (const char *));
514.  #ifdef AUTOPICKUP_EXCEPTIONS
515.  STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
516.  STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
517.  #endif
518.  
519.  /* check whether a user-supplied option string is a proper leading
520.     substring of a particular option name; option string might have
521.     a colon or equals sign and arbitrary value appended to it */
522.  boolean
523.  match_optname(user_string, opt_name, min_length, val_allowed)
524.  const char *user_string, *opt_name;
525.  int min_length;
526.  boolean val_allowed;
527.  {
528.  	int len = (int)strlen(user_string);
529.  
530.  	if (val_allowed) {
531.  	    const char *p = index(user_string, ':'),
532.  		       *q = index(user_string, '=');
533.  
534.  	    if (!p || (q && q < p)) p = q;
535.  	    while(p && p > user_string && isspace(*(p-1))) p--;
536.  	    if (p) len = (int)(p - user_string);
537.  	}
538.  
539.  	return (len >= min_length) && !strncmpi(opt_name, user_string, len);
540.  }
541.  
542.  /* most environment variables will eventually be printed in an error
543.   * message if they don't work, and most error message paths go through
544.   * BUFSZ buffers, which could be overflowed by a maliciously long
545.   * environment variable.  if a variable can legitimately be long, or
546.   * if it's put in a smaller buffer, the responsible code will have to
547.   * bounds-check itself.
548.   */
549.  char *
550.  nh_getenv(ev)
551.  const char *ev;
552.  {
553.  	char *getev = getenv(ev);
554.  
555.  	if (getev && strlen(getev) <= (BUFSZ / 2))
556.  		return getev;
557.  	else
558.  		return (char *)0;
559.  }
560.  
561.  void
562.  initoptions()
563.  {
564.  #ifndef MAC
565.  	char *opts;
566.  #endif
567.  	int i;
568.  
569.  	/* initialize the random number generator */
570.  	setrandom();
571.  
572.  	/* for detection of configfile options specified multiple times */
573.  	iflags.opt_booldup = iflags.opt_compdup = (int *)0;
574.  	
575.  	for (i = 0; boolopt[i].name; i++) {
576.  		if (boolopt[i].addr)
577.  			*(boolopt[i].addr) = boolopt[i].initvalue;
578.  	}
579.  	flags.end_own = FALSE;
580.  	flags.end_top = 3;
581.  	flags.end_around = 2;
582.  	iflags.runmode = RUN_LEAP;
583.  	iflags.msg_history = 20;
584.  #ifdef TTY_GRAPHICS
585.  	iflags.prevmsg_window = 's';
586.  #endif
587.  	iflags.menu_headings = ATR_INVERSE;
588.  
589.  	/* Use negative indices to indicate not yet selected */
590.  	flags.initrole = -1;
591.  	flags.initrace = -1;
592.  	flags.initgend = -1;
593.  	flags.initalign = -1;
594.  
595.  	/* Set the default monster and object class symbols.  Don't use */
596.  	/* memcpy() --- sizeof char != sizeof uchar on some machines.	*/
597.  	for (i = 0; i < MAXOCLASSES; i++)
598.  		oc_syms[i] = (uchar) def_oc_syms[i];
599.  	for (i = 0; i < MAXMCLASSES; i++)
600.  		monsyms[i] = (uchar) def_monsyms[i];
601.  	for (i = 0; i < WARNCOUNT; i++)
602.  		warnsyms[i] = def_warnsyms[i].sym;
603.  	iflags.bouldersym = 0;
604.  	iflags.travelcc.x = iflags.travelcc.y = -1;
605.  	flags.warnlevel = 1;
606.  	flags.warntype = 0L;
607.  
608.       /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
609.  	(void)memcpy((genericptr_t)flags.inv_order,
610.  		     (genericptr_t)def_inv_order, sizeof flags.inv_order);
611.  	flags.pickup_types[0] = '\0';
612.  	flags.pickup_burden = MOD_ENCUMBER;
613.  
614.  	for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
615.  		flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
616.  	switch_graphics(ASCII_GRAPHICS);	/* set default characters */
617.  #if defined(UNIX) && defined(TTY_GRAPHICS)
618.  	/*
619.  	 * Set defaults for some options depending on what we can
620.  	 * detect about the environment's capabilities.
621.  	 * This has to be done after the global initialization above
622.  	 * and before reading user-specific initialization via
623.  	 * config file/environment variable below.
624.  	 */
625.  	/* this detects the IBM-compatible console on most 386 boxes */
626.  	if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
627.  		switch_graphics(IBM_GRAPHICS);
628.  # ifdef TEXTCOLOR
629.  		iflags.use_color = TRUE;
630.  # endif
631.  	}
632.  #endif /* UNIX && TTY_GRAPHICS */
633.  #if defined(UNIX) || defined(VMS)
634.  # ifdef TTY_GRAPHICS
635.  	/* detect whether a "vt" terminal can handle alternate charsets */
636.  	if ((opts = nh_getenv("TERM")) &&
637.  	    !strncmpi(opts, "vt", 2) && AS && AE &&
638.  	    index(AS, '\016') && index(AE, '\017')) {
639.  		switch_graphics(DEC_GRAPHICS);
640.  	}
641.  # endif
642.  #endif /* UNIX || VMS */
643.  
644.  #ifdef MAC_GRAPHICS_ENV
645.  	switch_graphics(MAC_GRAPHICS);
646.  #endif /* MAC_GRAPHICS_ENV */
647.  	flags.menu_style = MENU_FULL;
648.  
649.  	/* since this is done before init_objects(), do partial init here */
650.  	objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
651.  	nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
652.  #ifndef MAC
653.  	opts = getenv(NETHACK_ENV_OPTIONS);
654.  	if (!opts) opts = getenv("NETHACKOPTIONS");
655.  	if (!opts) opts = getenv("HACKOPTIONS");
656.  	if (opts) {
657.  		if (*opts == '/' || *opts == '\\' || *opts == '@') {
658.  			if (*opts == '@') opts++;	/* @filename */
659.  			/* looks like a filename */
660.  			if (strlen(opts) < BUFSZ/2)
661.  			    read_config_file(opts);
662.  		} else {
663.  			read_config_file((char *)0);
664.  			/* let the total length of options be long;
665.  			 * parseoptions() will check each individually
666.  			 */
667.  			parseoptions(opts, TRUE, FALSE);
668.  		}
669.  	} else
670.  #endif
671.  		read_config_file((char *)0);
672.  
673.  	(void)fruitadd(pl_fruit);
674.  	/* Remove "slime mold" from list of object names; this will	*/
675.  	/* prevent it from being wished unless it's actually present	*/
676.  	/* as a named (or default) fruit.  Wishing for "fruit" will	*/
677.  	/* result in the player's preferred fruit [better than "\033"].	*/
678.  	obj_descr[SLIME_MOLD].oc_name = "fruit";
679.  
680.  #if defined(GL_GRAPHICS) || defined(SDL_GRAPHICS)
681.  	/* -AJA- SDL/GL support.  Needs to happen after main config
682.  	 *       file has been read.
683.  	 */
684.  	opts = getenv(SDLGL_ENV_VAR);
685.  	if (opts)
686.  		Sdlgl_parse_options(opts, TRUE, FALSE);
687.  #endif
688.  
689.  	return;
690.  }
691.  
692.  STATIC_OVL void
693.  nmcpy(dest, src, maxlen)
694.  	char	*dest;
695.  	const char *src;
696.  	int	maxlen;
697.  {
698.  	int	count;
699.  
700.  	for(count = 1; count < maxlen; count++) {
701.  		if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
702.  		*dest++ = *src++;
703.  	}
704.  	*dest = 0;
705.  }
706.  
707.  /*
708.   * escapes: escape expansion for showsyms. C-style escapes understood include
709.   * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
710.   * for control characters is also understood, and \[mM] followed by any of the
711.   * previous forms or by a character has the effect of 'meta'-ing the value (so
712.   * that the alternate character set will be enabled).
713.   */
714.  STATIC_OVL void
715.  escapes(cp, tp)
716.  const char	*cp;
717.  char *tp;
718.  {
719.      while (*cp)
720.      {
721.  	int	cval = 0, meta = 0;
722.  
723.  	if (*cp == '\\' && index("mM", cp[1])) {
724.  		meta = 1;
725.  		cp += 2;
726.  	}
727.  	if (*cp == '\\' && index("0123456789xXoO", cp[1]))
728.  	{
729.  	    const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
730.  	    int dcount = 0;
731.  
732.  	    cp++;
733.  	    if (*cp == 'x' || *cp == 'X')
734.  		for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
735.  		    cval = (cval * 16) + (dp - hex) / 2;
736.  	    else if (*cp == 'o' || *cp == 'O')
737.  		for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
738.  		    cval = (cval * 8) + (*cp - '0');
739.  	    else
740.  		for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
741.  		    cval = (cval * 10) + (*cp - '0');
742.  	}
743.  	else if (*cp == '\\')		/* C-style character escapes */
744.  	{
745.  	    switch (*++cp)
746.  	    {
747.  	    case '\\': cval = '\\'; break;
748.  	    case 'n': cval = '\n'; break;
749.  	    case 't': cval = '\t'; break;
750.  	    case 'b': cval = '\b'; break;
751.  	    case 'r': cval = '\r'; break;
752.  	    default: cval = *cp;
753.  	    }
754.  	    cp++;
755.  	}
756.  	else if (*cp == '^')		/* expand control-character syntax */
757.  	{
758.  	    cval = (*++cp & 0x1f);
759.  	    cp++;
760.  	}
761.  	else
762.  	    cval = *cp++;
763.  	if (meta)
764.  	    cval |= 0x80;
765.  	*tp++ = cval;
766.      }
767.      *tp = '\0';
768.  }
769.  
770.  STATIC_OVL void
771.  rejectoption(optname)
772.  const char *optname;
773.  {
774.  #ifdef MICRO
775.  	pline("\"%s\" settable only from %s.", optname, configfile);
776.  #else
777.  	pline("%s can be set only from %s or %s.", optname,
778.  			NETHACK_ENV_OPTIONS, configfile);
779.  #endif
780.  }
781.  
782.  STATIC_OVL void
783.  badoption(opts)
784.  const char *opts;
785.  {
786.  	if (!initial) {
787.  	    if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
788.  		option_help();
789.  	    else
790.  		pline("Bad syntax: %s.  Enter \"?g\" for help.", opts);
791.  	    return;
792.  	}
793.  #ifdef MAC
794.  	else return;
795.  #endif
796.  
797.  	if(from_file)
798.  	    raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
799.  	else
800.  	    raw_printf("Bad syntax in %s: %s.", NETHACK_ENV_OPTIONS, opts);
801.  
802.  	wait_synch();
803.  }
804.  
805.  STATIC_OVL void
806.  badauthoption(opts)
807.  const char *opts;
808.  {
809.  	raw_printf("Bad syntax in AUTHENTICATION in %s: %s.", configfile, opts);
810.  	wait_synch();
811.  }
812.  
813.  STATIC_OVL void
814.  badtileoption(opts)
815.  const char *opts;
816.  {
817.  	raw_printf("Bad syntax in TILESET in %s: %s.", configfile, opts);
818.  	wait_synch();
819.  }
820.  
821.  STATIC_OVL char *
822.  string_for_opt(opts, val_optional)
823.  char *opts;
824.  boolean val_optional;
825.  {
826.  	char *colon, *equals;
827.  
828.  	colon = index(opts, ':');
829.  	equals = index(opts, '=');
830.  	if (!colon || (equals && equals < colon)) colon = equals;
831.  
832.  	if (!colon || !*++colon) {
833.  		if (!val_optional) badoption(opts);
834.  		return (char *)0;
835.  	}
836.  	return colon;
837.  }
838.  
839.  STATIC_OVL char *
840.  string_for_auth_opt(opts, val_optional)
841.  char *opts;
842.  boolean val_optional;
843.  {
844.  	char *colon = string_for_opt(opts, TRUE);
845.  	if (!colon && !val_optional) badauthoption(opts);
846.  	return colon;
847.  }
848.  
849.  STATIC_OVL char *
850.  string_for_tile_opt(opts, val_optional)
851.  char *opts;
852.  boolean val_optional;
853.  {
854.  	char *colon = string_for_opt(opts, TRUE);
855.  	if (!colon && !val_optional) badtileoption(opts);
856.  	return colon;
857.  }
858.  
859.  STATIC_OVL char *
860.  string_for_env_opt(optname, opts, val_optional)
861.  const char *optname;
862.  char *opts;
863.  boolean val_optional;
864.  {
865.  	if(!initial) {
866.  		rejectoption(optname);
867.  		return (char *)0;
868.  	}
869.  	return string_for_opt(opts, val_optional);
870.  }
871.  
872.  STATIC_OVL void
873.  bad_negation(optname, with_parameter)
874.  const char *optname;
875.  boolean with_parameter;
876.  {
877.  	pline_The("%s option may not %sbe negated.",
878.  		optname,
879.  		with_parameter ? "both have a value and " : "");
880.  }
881.  
882.  /*
883.   * Change the inventory order, using the given string as the new order.
884.   * Missing characters in the new order are filled in at the end from
885.   * the current inv_order, except for gold, which is forced to be first
886.   * if not explicitly present.
887.   *
888.   * This routine returns 1 unless there is a duplicate or bad char in
889.   * the string.
890.   */
891.  STATIC_OVL int
892.  change_inv_order(op)
893.  char *op;
894.  {
895.      int oc_sym, num;
896.      char *sp, buf[BUFSZ];
897.  
898.      num = 0;
899.  #ifndef GOLDOBJ
900.      if (!index(op, GOLD_SYM))
901.  	buf[num++] = COIN_CLASS;
902.  #else
903.      /*  !!!! probably unnecessary with gold as normal inventory */
904.  #endif
905.  
906.      for (sp = op; *sp; sp++) {
907.  	oc_sym = def_char_to_objclass(*sp);
908.  	/* reject bad or duplicate entries */
909.  	if (oc_sym == MAXOCLASSES ||
910.  		oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||
911.  		!index(flags.inv_order, oc_sym) || index(sp+1, *sp))
912.  	    return 0;
913.  	/* retain good ones */
914.  	buf[num++] = (char) oc_sym;
915.      }
916.      buf[num] = '\0';
917.  
918.      /* fill in any omitted classes, using previous ordering */
919.      for (sp = flags.inv_order; *sp; sp++)
920.  	if (!index(buf, *sp)) {
921.  	    buf[num++] = *sp;
922.  	    buf[num] = '\0';	/* explicitly terminate for next index() */
923.  	}
924.  
925.      Strcpy(flags.inv_order, buf);
926.      return 1;
927.  }
928.  
929.  STATIC_OVL void
930.  graphics_opts(opts, optype, maxlen, offset)
931.  register char *opts;
932.  const char *optype;
933.  int maxlen, offset;
934.  {
935.  	uchar translate[MAXPCHARS+1];
936.  	int length, i;
937.  
938.  	if (!(opts = string_for_env_opt(optype, opts, FALSE)))
939.  		return;
940.  	escapes(opts, opts);
941.  
942.  	length = strlen(opts);
943.  	if (length > maxlen) length = maxlen;
944.  	/* match the form obtained from PC configuration files */
945.  	for (i = 0; i < length; i++)
946.  		translate[i] = (uchar) opts[i];
947.  	assign_graphics(translate, length, maxlen, offset);
948.  }
949.  
950.  STATIC_OVL void
951.  warning_opts(opts, optype)
952.  register char *opts;
953.  const char *optype;
954.  {
955.  	uchar translate[MAXPCHARS+1];
956.  	int length, i;
957.  
958.  	if (!(opts = string_for_env_opt(optype, opts, FALSE)))
959.  		return;
960.  	escapes(opts, opts);
961.  
962.  	length = strlen(opts);
963.  	if (length > WARNCOUNT) length = WARNCOUNT;
964.  	/* match the form obtained from PC configuration files */
965.  	for (i = 0; i < length; i++)
966.  	     translate[i] = (((i < WARNCOUNT) && opts[i]) ?
967.  			   (uchar) opts[i] : def_warnsyms[i].sym);
968.  	assign_warnings(translate);
969.  }
970.  
971.  void
972.  assign_warnings(graph_chars)
973.  register uchar *graph_chars;
974.  {
975.  	int i;
976.  	for (i = 0; i < WARNCOUNT; i++)
977.  	    if (graph_chars[i]) warnsyms[i] = graph_chars[i];
978.  }
979.  
980.  STATIC_OVL int
981.  feature_alert_opts(op, optn)
982.  char *op;
983.  const char *optn;
984.  {
985.  	char buf[BUFSZ];
986.  	boolean rejectver = FALSE;
987.  	unsigned long fnv = get_feature_notice_ver(op);		/* version.c */
988.  	if (fnv == 0L) return 0;
989.  	if (fnv > get_current_feature_ver())
990.  		rejectver = TRUE;
991.  	else
992.  		flags.suppress_alert = fnv;
993.  	if (rejectver) {
994.  		if (!initial)
995.  			You_cant("disable new feature alerts for future versions.");
996.  		else {
997.  			Sprintf(buf,
998.  				"\n%s=%s Invalid reference to a future version ignored",
999.  				optn, op);
1000. 			badoption(buf);
1001. 		}
1002. 		return 0;
1003. 	}
1004. 	if (!initial) {
1005. 		Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
1006. 			FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
1007. 		pline("Feature change alerts disabled for Slash'EM %s features and prior.",
1008. 			buf);
1009. 	}
1010. 	return 1;
1011. }
1012. 
1013. void
1014. set_duplicate_opt_detection(on_or_off)
1015. int on_or_off;
1016. {
1017. 	int k, *optptr;
1018. 	if (on_or_off != 0) {
1019. 		/*-- ON --*/
1020. 		if (iflags.opt_booldup)
1021. 			impossible("iflags.opt_booldup already on (memory leak)");
1022. 		iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int));
1023. 		optptr = iflags.opt_booldup;
1024. 		for (k = 0; k < SIZE(boolopt); ++k)
1025. 			*optptr++ = 0;
1026. 			
1027. 		if (iflags.opt_compdup)
1028. 			impossible("iflags.opt_compdup already on (memory leak)");
1029. 		iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int));
1030. 		optptr = iflags.opt_compdup;
1031. 		for (k = 0; k < SIZE(compopt); ++k)
1032. 			*optptr++ = 0;
1033. 	} else {
1034. 		/*-- OFF --*/
1035. 		if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup);
1036. 		iflags.opt_booldup = (int *)0;
1037. 		if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup);
1038. 		iflags.opt_compdup = (int *)0;
1039. 	} 
1040. }
1041. 
1042. STATIC_OVL void
1043. duplicate_opt_detection(opts, bool_or_comp)
1044. const char *opts;
1045. int bool_or_comp;	/* 0 == boolean option, 1 == compound */
1046. {
1047. 	int i, *optptr;
1048. #if defined(MAC)
1049. 	/* the Mac has trouble dealing with the output of messages while
1050. 	 * processing the config file.  That should get fixed one day.
1051. 	 * For now just return.
1052. 	 */
1053. 	return;
1054. #endif
1055. 	if ((bool_or_comp == 0) && iflags.opt_booldup && initial && from_file) {
1056. 	    for (i = 0; boolopt[i].name; i++) {
1057. 		if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
1058. 			optptr = iflags.opt_booldup + i;
1059. 			if (*optptr == 1) {
1060. 			    raw_printf(
1061. 				"\nWarning - Boolean option specified multiple times: %s.\n",
1062. 					opts);
1063. 			        wait_synch();
1064. 			}
1065. 			*optptr += 1;
1066. 			break; /* don't match multiple options */
1067. 		}
1068. 	    }
1069. 	} else if ((bool_or_comp == 1) && iflags.opt_compdup && initial && from_file) {
1070. 	    for (i = 0; compopt[i].name; i++) {
1071. 		if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) {
1072. 			optptr = iflags.opt_compdup + i;
1073. 			if (*optptr == 1) {
1074. 			    raw_printf(
1075. 				"\nWarning - compound option specified multiple times: %s.\n",
1076. 					compopt[i].name);
1077. 			        wait_synch();
1078. 			}
1079. 			*optptr += 1;
1080. 			break; /* don't match multiple options */
1081. 		}
1082. 	    }
1083. 	}
1084. }
1085. 
1086. #ifdef MENU_COLOR
1087. extern struct menucoloring *menu_colorings;
1088. 
1089. static const struct {
1090.    const char *name;
1091.    const int color;
1092. } colornames[] = {
1093.    {"black", CLR_BLACK},
1094.    {"red", CLR_RED},
1095.    {"green", CLR_GREEN},
1096.    {"brown", CLR_BROWN},
1097.    {"blue", CLR_BLUE},
1098.    {"magenta", CLR_MAGENTA},
1099.    {"cyan", CLR_CYAN},
1100.    {"gray", CLR_GRAY},
1101.    {"orange", CLR_ORANGE},
1102.    {"lightgreen", CLR_BRIGHT_GREEN},
1103.    {"yellow", CLR_YELLOW},
1104.    {"lightblue", CLR_BRIGHT_BLUE},
1105.    {"lightmagenta", CLR_BRIGHT_MAGENTA},
1106.    {"lightcyan", CLR_BRIGHT_CYAN},
1107.    {"white", CLR_WHITE}
1108. };
1109. 
1110. static const struct {
1111.    const char *name;
1112.    const int attr;
1113. } attrnames[] = {
1114.      {"none", ATR_NONE},
1115.      {"bold", ATR_BOLD},
1116.      {"dim", ATR_DIM},
1117.      {"underline", ATR_ULINE},
1118.      {"blink", ATR_BLINK},
1119.      {"inverse", ATR_INVERSE}
1120. 
1121. };
1122. 
1123. /* parse '"regex_string"=color' and add it to menucoloring */
1124. boolean
1125. add_menu_coloring(str)
1126. char *str;
1127. {
1128.    int i, c = NO_COLOR, a = ATR_NONE;
1129.    struct menucoloring *tmp;
1130.    char *tmps, *cs = strchr(str, '=');
1131. #ifdef POSIX_REGEX
1132.    int errnum;
1133.    char errbuf[80];
1134. #endif
1135.    const char *err = (char *)0;
1136.    
1137.    if (!cs || !str) return FALSE;
1138.    
1139.    tmps = cs;
1140.    tmps++;
1141.    while (*tmps && isspace(*tmps)) tmps++;
1142. 
1143.    for (i = 0; i < SIZE(colornames); i++)
1144.      if (strstri(tmps, colornames[i].name) == tmps) {
1145. 	c = colornames[i].color;
1146. 	break;
1147.      }
1148.    if ((i == SIZE(colornames)) && (*tmps >= '0' && *tmps <='9'))
1149.      c = atoi(tmps);
1150.    
1151.    if (c > 15) return FALSE;
1152.    
1153.    tmps = strchr(str, '&');
1154.    if (tmps) {
1155.       tmps++;
1156.       while (*tmps && isspace(*tmps)) tmps++;
1157.       for (i = 0; i < SIZE(attrnames); i++)
1158. 	if (strstri(tmps, attrnames[i].name) == tmps) {
1159. 	   a = attrnames[i].attr;
1160. 	   break;
1161. 	}
1162.       if ((i == SIZE(attrnames)) && (*tmps >= '0' && *tmps <='9'))
1163. 	a = atoi(tmps);
1164.    }
1165.    
1166.    *cs = '\0';
1167.    tmps = str;
1168.    if ((*tmps == '"') || (*tmps == '\)) {
1169.       cs--;
1170.       while (isspace(*cs)) cs--;
1171.       if (*cs == *tmps) {
1172. 	 *cs = '\0';
1173. 	 tmps++;
1174.       }
1175.    }
1176.    
1177.    tmp = (struct menucoloring *)alloc(sizeof(struct menucoloring));
1178. #ifdef USE_REGEX_MATCH
1179. # ifdef GNU_REGEX
1180.    tmp->match.translate = 0;
1181.    tmp->match.fastmap = 0;
1182.    tmp->match.buffer = 0;
1183.    tmp->match.allocated = 0;
1184.    tmp->match.regs_allocated = REGS_FIXED;
1185.    err = re_compile_pattern(tmps, strlen(tmps), &tmp->match);
1186. # else
1187. #  ifdef POSIX_REGEX
1188.    errnum = regcomp(&tmp->match, tmps, REG_EXTENDED | REG_NOSUB);
1189.    if (errnum != 0) {                                                                                                                                                                                                               
1190.       regerror(errnum, &tmp->match, errbuf, sizeof(errbuf));
1191.       err = errbuf;
1192.    }
1193. #  endif  
1194. # endif  
1195. #else
1196.    tmp->match = (char *)alloc(strlen(tmps)+1);
1197.    (void) memcpy((genericptr_t)tmp->match, (genericptr_t)tmps, strlen(tmps)+1);
1198. #endif
1199.    if (err) {
1200.       raw_printf("\nMenucolor regex error: %s\n", err);
1201.       wait_synch();
1202.       free(tmp);
1203.       return FALSE;
1204.    } else {
1205.       tmp->next = menu_colorings;
1206.       tmp->color = c;
1207.       tmp->attr = a;
1208.       menu_colorings = tmp;
1209.       return TRUE;
1210.    }
1211. }
1212. #endif /* MENU_COLOR */
1213. 
1214. void
1215. parseoptions(opts, tinitial, tfrom_file)
1216. register char *opts;
1217. boolean tinitial, tfrom_file;
1218. {
1219. 	register char *op;
1220. 	unsigned num;
1221. 	boolean negated;
1222. 	int i;
1223. 	const char *fullname;
1224. 
1225. 	initial = tinitial;
1226. 	from_file = tfrom_file;
1227. 	if ((op = index(opts, ',')) != 0) {
1228. 		*op++ = 0;
1229. 		parseoptions(op, initial, from_file);
1230. 	}
1231. 	if (strlen(opts) > BUFSZ/2) {
1232. 		badoption("option too long");
1233. 		return;
1234. 	}
1235. 
1236. 	/* strip leading and trailing white space */
1237. 	while (isspace((int)*opts)) opts++;
1238. 	op = eos(opts);
1239. 	while (--op >= opts && isspace((int)*op)) *op = '\0';
1240. 
1241. 	if (!*opts) return;
1242. 	negated = FALSE;
1243. 	while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
1244. 		if (*opts == '!') opts++; else opts += 2;
1245. 		negated = !negated;
1246. 	}
1247. 
1248. 	/* variant spelling */
1249. 
1250. 	if (match_optname(opts, "colour", 5, FALSE))
1251. 		Strcpy(opts, "color");	/* fortunately this isn't longer */
1252. 
1253. 	if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */
1254. 	duplicate_opt_detection(opts, 1);	/* 1 means compound opts */
1255. 
1256. 	/* special boolean options */
1257. 
1258. 	if (match_optname(opts, "female", 3, FALSE)) {
1259. 		if(!initial && flags.female == negated)
1260. 			pline("That is not anatomically possible.");
1261. 		else
1262. 			flags.initgend = flags.female = !negated;
1263. 		return;
1264. 	}
1265. 
1266. 	if (match_optname(opts, "male", 4, FALSE)) {
1267. 		if(!initial && flags.female != negated)
1268. 			pline("That is not anatomically possible.");
1269. 		else
1270. 			flags.initgend = flags.female = negated;
1271. 		return;
1272. 	}
1273. 
1274. #if defined(MICRO) && !defined(AMIGA)
1275. 	/* included for compatibility with old NetHack.cnf files */
1276. 	if (match_optname(opts, "IBM_", 4, FALSE)) {
1277. 		iflags.BIOS = !negated;
1278. 		return;
1279. 	}
1280. #endif /* MICRO */
1281. 
1282. 	/* compound options */
1283. 
1284. 	fullname = "pettype";
1285. 	if (match_optname(opts, fullname, 3, TRUE)) {
1286. 		if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
1287. 		    if (negated) bad_negation(fullname, TRUE);
1288. 		    else switch (*op) {
1289. 			case 'd':	/* dog */
1290. 			case 'D':
1291. 			    preferred_pet = 'd';
1292. 			    break;
1293. 			case 'c':	/* cat */
1294. 			case 'C':
1295. 			case 'f':	/* feline */
1296. 			case 'F':
1297. 			    preferred_pet = 'c';
1298. 			    break;
1299. 			case 'n':	/* no pet */
1300. 			case 'N':
1301. 			    preferred_pet = 'n';
1302. 			    break;
1303. 			default:
1304. 			    pline("Unrecognized pet type '%s'.", op);
1305. 			    break;
1306. 		    }
1307. 		} else if (negated) preferred_pet = 'n';
1308. 		return;
1309. 	}
1310. 
1311.         fullname = "ghoulname";
1312. 	if (match_optname(opts, fullname, 3, TRUE)) {
1313. 		if (negated) bad_negation(fullname, FALSE);
1314. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1315.                         nmcpy(ghoulname, op, PL_PSIZ);
1316. 		return;
1317. 	}
1318. 
1319.         fullname = "wolfname";
1320. 	if (match_optname(opts, fullname, 3, TRUE)) {
1321. 		if (negated) bad_negation(fullname, FALSE);
1322. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1323.                         nmcpy(wolfname, op, PL_PSIZ);
1324. 		return;
1325. 	}
1326. 
1327. 	fullname = "catname";
1328. 	if (match_optname(opts, fullname, 3, TRUE)) {
1329. 		if (negated) bad_negation(fullname, FALSE);
1330. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1331. 			nmcpy(catname, op, PL_PSIZ);
1332. 		return;
1333. 	}
1334. 
1335. 	fullname = "dogname";
1336. 	if (match_optname(opts, fullname, 3, TRUE)) {
1337. 		if (negated) bad_negation(fullname, FALSE);
1338. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1339. 			nmcpy(dogname, op, PL_PSIZ);
1340. 		return;
1341. 	}
1342. 
1343. 	fullname = "horsename";
1344. 	if (match_optname(opts, fullname, 5, TRUE)) {
1345. 		if (negated) bad_negation(fullname, FALSE);
1346. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1347. 			nmcpy(horsename, op, PL_PSIZ);
1348. 		return;
1349. 	}
1350. 
1351. 	/* menucolor:"regex_string"=color */
1352. 	fullname = "menucolor";
1353. 	if (match_optname(opts, fullname, 9, TRUE)) {
1354. #ifdef MENU_COLOR
1355. 		if (negated) bad_negation(fullname, FALSE);
1356. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1357. 			if (!add_menu_coloring(op))
1358. 				badoption(opts);
1359. #endif
1360.  		return;
1361.  	}
1362. 
1363. 	fullname = "number_pad";
1364. 	if (match_optname(opts, fullname, 10, TRUE)) {
1365. 		boolean compat = (strlen(opts) <= 10);
1366. 		op = string_for_opt(opts, (compat || !initial));
1367. 		if (!op) {
1368. 		    if (compat || negated || initial) {
1369. 			/* for backwards compatibility, "number_pad" without a
1370. 			   value is a synonym for number_pad:1 */
1371. 			iflags.num_pad = !negated;
1372. 			if (iflags.num_pad) iflags.num_pad_mode = 0;
1373. 			number_pad(iflags.num_pad);
1374. 		    }
1375. 		    return;
1376. 		}
1377. 		if (negated) {
1378. 		    bad_negation("number_pad", TRUE);
1379. 		    return;
1380. 		}
1381. 		if (*op == '1' || *op == '2') {
1382. 			iflags.num_pad = 1;
1383. 			if (*op == '2') iflags.num_pad_mode = 1;
1384. 			else iflags.num_pad_mode = 0;
1385. 			number_pad(1);
1386. 		} else if (*op == '0') {
1387. 			iflags.num_pad = 0;
1388. 			iflags.num_pad_mode = 0;
1389. 			number_pad(0);
1390. 		} else badoption(opts);
1391. 		return;
1392. 	}
1393. 
1394. 	fullname = "runmode";
1395. 	if (match_optname(opts, fullname, 4, TRUE)) {
1396. 		if (negated) {
1397. 			iflags.runmode = RUN_TPORT;
1398. 		} else if ((op = string_for_opt(opts, FALSE)) != 0) {
1399. 		    if (!strncmpi(op, "teleport", strlen(op)))
1400. 			iflags.runmode = RUN_TPORT;
1401. 		    else if (!strncmpi(op, "run", strlen(op)))
1402. 			iflags.runmode = RUN_LEAP;
1403. 		    else if (!strncmpi(op, "walk", strlen(op)))
1404. 			iflags.runmode = RUN_STEP;
1405. 		    else if (!strncmpi(op, "crawl", strlen(op)))
1406. 			iflags.runmode = RUN_CRAWL;
1407. 		    else
1408. 			badoption(opts);
1409. 		}
1410. 		return;
1411. 	}
1412. 
1413. 	fullname = "msghistory";
1414. 	if (match_optname(opts, fullname, 3, TRUE)) {
1415. 		op = string_for_env_opt(fullname, opts, negated);
1416. 		if ((negated && !op) || (!negated && op)) {
1417. 			iflags.msg_history = negated ? 0 : atoi(op);
1418. 		} else if (negated) bad_negation(fullname, TRUE);
1419. 		return;
1420. 	}
1421. 
1422. 	fullname="msg_window";
1423. 	/* msg_window:single, combo, full or reversed */
1424. 	if (match_optname(opts, fullname, 4, TRUE)) {
1425. 	/* allow option to be silently ignored by non-tty ports */
1426. #ifdef TTY_GRAPHICS
1427. 		int tmp;
1428. 		if (!(op = string_for_opt(opts, TRUE))) {
1429. 		    tmp = negated ? 's' : 'f';
1430. 		} else {
1431. 			  if (negated) {
1432. 			  	bad_negation(fullname, TRUE);
1433. 			  	return;
1434. 				  }
1435. 		    tmp = tolower(*op);
1436. 		}
1437. 		switch (tmp) {
1438. 			case 's':	/* single message history cycle (default if negated) */
1439. 				iflags.prevmsg_window = 's';
1440. 				break;
1441. 			case 'c':	/* combination: two singles, then full page reversed */
1442. 				iflags.prevmsg_window = 'c';
1443. 				break;
1444. 			case 'f':	/* full page (default if no opts) */
1445. 				iflags.prevmsg_window = 'f';
1446. 				break;
1447. 			case 'r':	/* full page (reversed) */
1448. 				iflags.prevmsg_window = 'r';
1449. 				break;
1450. 			default:
1451. 				badoption(opts);
1452. 		}
1453. #endif
1454. 		return;
1455. 	}
1456. 
1457. 	/* WINCAP
1458. 	 * setting font options  */
1459. 	fullname = "font";
1460. 	if (!strncmpi(opts, fullname, 4))
1461. 	{
1462. 		int wintype = -1;
1463. 		char *fontopts = opts + 4;
1464. 
1465. 		if (!strncmpi(fontopts, "map", 3) ||
1466. 		    !strncmpi(fontopts, "_map", 4))
1467. 			wintype = NHW_MAP;
1468. 		else if (!strncmpi(fontopts, "message", 7) ||
1469. 			 !strncmpi(fontopts, "_message", 8))
1470. 			wintype = NHW_MESSAGE;
1471. 		else if (!strncmpi(fontopts, "text", 4) ||
1472. 			 !strncmpi(fontopts, "_text", 5))
1473. 			wintype = NHW_TEXT;			
1474. 		else if (!strncmpi(fontopts, "menu", 4) ||
1475. 			 !strncmpi(fontopts, "_menu", 5))
1476. 			wintype = NHW_MENU;
1477. 		else if (!strncmpi(fontopts, "status", 6) ||
1478. 			 !strncmpi(fontopts, "_status", 7))
1479. 			wintype = NHW_STATUS;
1480. 		else if (!strncmpi(fontopts, "_size", 5)) {
1481. 			if (!strncmpi(fontopts, "_size_map", 8))
1482. 				wintype = NHW_MAP;
1483. 			else if (!strncmpi(fontopts, "_size_message", 12))
1484. 				wintype = NHW_MESSAGE;
1485. 			else if (!strncmpi(fontopts, "_size_text", 9))
1486. 				wintype = NHW_TEXT;
1487. 			else if (!strncmpi(fontopts, "_size_menu", 9))
1488. 				wintype = NHW_MENU;
1489. 			else if (!strncmpi(fontopts, "_size_status", 11))
1490. 				wintype = NHW_STATUS;
1491. 			else {
1492. 				badoption(opts);
1493. 				return;
1494. 			}
1495. 			if (wintype > 0 && !negated &&
1496. 			    (op = string_for_opt(opts, FALSE)) != 0) {
1497. 			    switch(wintype)  {
1498. 			    	case NHW_MAP:
1499. 					iflags.wc_fontsiz_map = atoi(op);
1500. 					break;
1501. 			    	case NHW_MESSAGE:
1502. 					iflags.wc_fontsiz_message = atoi(op);
1503. 					break;
1504. 			    	case NHW_TEXT:
1505. 					iflags.wc_fontsiz_text = atoi(op);
1506. 					break;
1507. 			    	case NHW_MENU:
1508. 					iflags.wc_fontsiz_menu = atoi(op);
1509. 					break;
1510. 			    	case NHW_STATUS:
1511. 					iflags.wc_fontsiz_status = atoi(op);
1512. 					break;
1513. 			    }
1514. 			}
1515. 			return;
1516. 		} else {
1517. 			badoption(opts);
1518. 		}
1519. 		if (wintype > 0 &&
1520. 		    (op = string_for_opt(opts, FALSE)) != 0) {
1521. 			wc_set_font_name(wintype, op);
1522. #ifdef MAC
1523. 			set_font_name (wintype, op);
1524. #endif
1525. 			return;
1526. 		} else if (negated) bad_negation(fullname, TRUE);
1527. 		return;
1528. 	}
1529. #ifdef CHANGE_COLOR
1530. 	if (match_optname(opts, "palette", 3, TRUE)
1531. # ifdef MAC
1532. 	    || match_optname(opts, "hicolor", 3, TRUE)
1533. # endif
1534. 							) {
1535. 	    int color_number, color_incr;
1536. 
1537. # ifdef MAC
1538. 	    if (match_optname(opts, "hicolor", 3, TRUE)) {
1539. 		if (negated) {
1540. 		    bad_negation("hicolor", FALSE);
1541. 		    return;
1542. 		}
1543. 		color_number = CLR_MAX + 4;	/* HARDCODED inverse number */
1544. 		color_incr = -1;
1545. 	    } else {
1546. # endif
1547. 		if (negated) {
1548. 		    bad_negation("palette", FALSE);
1549. 		    return;
1550. 		}
1551. 		color_number = 0;
1552. 		color_incr = 1;
1553. # ifdef MAC
1554. 	    }
1555. # endif
1556. 	    if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
1557. 		char *pt = op;
1558. 		int cnt, tmp, reverse;
1559. 		long rgb;
1560. 
1561. 		while (*pt && color_number >= 0) {
1562. 		    cnt = 3;
1563. 		    rgb = 0L;
1564. 		    if (*pt == '-') {
1565. 			reverse = 1;
1566. 			pt++;
1567. 		    } else {
1568. 			reverse = 0;
1569. 		    }
1570. 		    while (cnt-- > 0) {
1571. 			if (*pt && *pt != '/') {
1572. # ifdef AMIGA
1573. 			    rgb <<= 4;
1574. # else
1575. 			    rgb <<= 8;
1576. # endif
1577. 			    tmp = *(pt++);
1578. 			    if (isalpha(tmp)) {
1579. 				tmp = (tmp + 9) & 0xf;	/* Assumes ASCII... */
1580. 			    } else {
1581. 				tmp &= 0xf;	/* Digits in ASCII too... */
1582. 			    }
1583. # ifndef AMIGA
1584. 			    /* Add an extra so we fill f -> ff and 0 -> 00 */
1585. 			    rgb += tmp << 4;
1586. # endif
1587. 			    rgb += tmp;
1588. 			}
1589. 		    }
1590. 		    if (*pt == '/') {
1591. 			pt++;
1592. 		    }
1593. 		    change_color(color_number, rgb, reverse);
1594. 		    color_number += color_incr;
1595. 		}
1596. 	    }
1597. 	    if (!initial) {
1598. 		need_redraw = TRUE;
1599. 	    }
1600. 	    return;
1601. 	}
1602. #endif /* CHANGE_COLOR */
1603. 
1604. 	if (match_optname(opts, "fruit", 2, TRUE)) {
1605. 		char empty_str = '\0';
1606. 		op = string_for_opt(opts, negated);
1607. 		if (negated) {
1608. 		    if (op) {
1609. 			bad_negation("fruit", TRUE);
1610. 			return;
1611. 		    }
1612. 		    op = &empty_str;
1613. 		    goto goodfruit;
1614. 		}
1615. 		if (!op) return;
1616. 		if (!initial) {
1617. 		    struct fruit *f;
1618. 
1619. 		    num = 0;
1620. 		    for(f=ffruit; f; f=f->nextf) {
1621. 			if (!strcmp(op, f->fname)) goto goodfruit;
1622. 			num++;
1623. 		    }
1624. 		    if (num >= 100) {
1625. 			pline("Doing that so many times isn't very fruitful.");
1626. 			return;
1627. 		    }
1628. 		}
1629. goodfruit:
1630. 		nmcpy(pl_fruit, op, PL_FSIZ);
1631. 	/* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
1632. 		if (!*pl_fruit)
1633. 		    nmcpy(pl_fruit, "slime mold", PL_FSIZ);
1634. 		if (!initial)
1635. 		    (void)fruitadd(pl_fruit);
1636. 		/* If initial, then initoptions is allowed to do it instead
1637. 		 * of here (initoptions always has to do it even if there's
1638. 		 * no fruit option at all.  Also, we don't want people
1639. 		 * setting multiple fruits in their options.)
1640. 		 */
1641. 		return;
1642. 	}
1643. 
1644. 	/* graphics:string */
1645. 	fullname = "graphics";
1646. 	if (match_optname(opts, fullname, 2, TRUE)) {
1647. 		if (negated) bad_negation(fullname, FALSE);
1648. 		else graphics_opts(opts, fullname, MAXPCHARS, 0);
1649. 		return;
1650. 	}
1651. 	fullname = "dungeon";
1652. 	if (match_optname(opts, fullname, 2, TRUE)) {
1653. 		if (negated) bad_negation(fullname, FALSE);
1654. 		else graphics_opts(opts, fullname, MAXDCHARS, 0);
1655. 		return;
1656. 	}
1657. 	fullname = "traps";
1658. 	if (match_optname(opts, fullname, 2, TRUE)) {
1659. 		if (negated) bad_negation(fullname, FALSE);
1660. 		else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS);
1661. 		return;
1662. 	}
1663. 	fullname = "effects";
1664. 	if (match_optname(opts, fullname, 2, TRUE)) {
1665. 		if (negated) bad_negation(fullname, FALSE);
1666. 		else
1667. 		 graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS);
1668. 		return;
1669. 	}
1670. 
1671. 	/* objects:string */
1672. 	fullname = "objects";
1673. 	if (match_optname(opts, fullname, 7, TRUE)) {
1674. 		int length;
1675. 
1676. 		if (negated) {
1677. 		    bad_negation(fullname, FALSE);
1678. 		    return;
1679. 		}
1680. 		if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
1681. 			return;
1682. 		escapes(opts, opts);
1683. 
1684. 		/*
1685. 		 * Override the default object class symbols.  The first
1686. 		 * object in the object class is the "random object".  I
1687. 		 * don't want to use 0 as an object class, so the "random
1688. 		 * object" is basically a place holder.
1689. 		 *
1690. 		 * The object class symbols have already been initialized in
1691. 		 * initoptions().
1692. 		 */
1693. 		length = strlen(opts);
1694. 		if (length >= MAXOCLASSES)
1695. 		    length = MAXOCLASSES-1;	/* don't count RANDOM_OBJECT */
1696. 
1697. 		for (i = 0; i < length; i++)
1698. 		    oc_syms[i+1] = (uchar) opts[i];
1699. 		return;
1700. 	}
1701. 
1702. 	/* monsters:string */
1703. 	fullname = "monsters";
1704. 	if (match_optname(opts, fullname, 8, TRUE)) {
1705. 		int length;
1706. 
1707. 		if (negated) {
1708. 		    bad_negation(fullname, FALSE);
1709. 		    return;
1710. 		}
1711. 		if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
1712. 			return;
1713. 		escapes(opts, opts);
1714. 
1715. 		/* Override default mon class symbols set in initoptions(). */
1716. 		length = strlen(opts);
1717. 		if (length >= MAXMCLASSES)
1718. 		    length = MAXMCLASSES-1;	/* mon class 0 unused */
1719. 
1720. 		for (i = 0; i < length; i++)
1721. 		    monsyms[i+1] = (uchar) opts[i];
1722. 		return;
1723. 	}
1724. 	fullname = "warnings";
1725. 	if (match_optname(opts, fullname, 5, TRUE)) {
1726. 		if (negated) bad_negation(fullname, FALSE);
1727. 		else warning_opts(opts, fullname);
1728. 		return;
1729. 	}
1730. 	/* boulder:symbol */
1731. 	fullname = "boulder";
1732. 	if (match_optname(opts, fullname, 7, TRUE)) {
1733. 		int clash = 0;
1734. 		if (negated) {
1735. 		    bad_negation(fullname, FALSE);
1736. 		    return;
1737. 		}
1738. /*		if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */
1739. 		if (!(opts = string_for_opt(opts, FALSE)))
1740. 			return;
1741. 		escapes(opts, opts);
1742. 		if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
1743. 			clash = 1;
1744. 		else if (opts[0] >= '1' && opts[0] <= '5')
1745. 			clash = 2;
1746. 		if (clash) {
1747. 			/* symbol chosen matches a used monster or warning
1748. 			   symbol which is not good - reject it*/
1749. 			pline(
1750. 		  "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
1751. 				opts[0], (clash == 1) ? "monster" : "warning");
1752. 		} else {
1753. 			/*
1754. 			 * Override the default boulder symbol.
1755. 			 */
1756. 			iflags.bouldersym = (uchar) opts[0];
1757. 		}
1758. 		if (!initial) need_redraw = TRUE;
1759. 		return;
1760. 	}
1761. 
1762. 	/* name:string */
1763. 	fullname = "name";
1764. 	if (match_optname(opts, fullname, 4, TRUE)) {
1765. 		if (negated) bad_negation(fullname, FALSE);
1766. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1767. #ifdef PROXY_GRAPHICS
1768. 		    /*
1769. 		     * Can't change player name if authentication required.
1770. 		     */
1771. 		    if (!getenv("HACKAUTHENTICATION"))
1772. #endif
1773. 			nmcpy(plname, op, PL_NSIZ);
1774. 		return;
1775. 	}
1776. 
1777. 	/* role:string or character:string */
1778. 	fullname = "role";
1779. 	if (match_optname(opts, fullname, 4, TRUE) ||
1780. 	    match_optname(opts, (fullname = "character"), 4, TRUE)) {
1781. 		if (negated) bad_negation(fullname, FALSE);
1782. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1783. 			if ((flags.initrole = str2role(op)) == ROLE_NONE)
1784. 				badoption(opts);
1785. 			else  /* Backwards compatibility */
1786. 				nmcpy(pl_character, op, PL_NSIZ);
1787. 		}
1788. 		return;
1789. 	}
1790. 
1791. 	/* race:string */
1792. 	fullname = "race";
1793. 	if (match_optname(opts, fullname, 4, TRUE)) {
1794. 		if (negated) bad_negation(fullname, FALSE);
1795. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1796. 			if ((flags.initrace = str2race(op)) == ROLE_NONE)
1797. 				badoption(opts);
1798. 			else /* Backwards compatibility */
1799. 				pl_race = *op;
1800. 		}
1801. 		return;
1802. 	}
1803. 
1804. 	/* gender:string */
1805. 	fullname = "gender";
1806. 	if (match_optname(opts, fullname, 4, TRUE)) {
1807. 		if (negated) bad_negation(fullname, FALSE);
1808. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1809. 			if ((flags.initgend = str2gend(op)) == ROLE_NONE)
1810. 				badoption(opts);
1811. 			else
1812. 				flags.female = flags.initgend;
1813. 		}
1814. 		return;
1815. 	}
1816. 
1817. 	/* altkeyhandler:string */
1818. 	fullname = "altkeyhandler";
1819. 	if (match_optname(opts, fullname, 4, TRUE)) {
1820. 		if (negated) bad_negation(fullname, FALSE);
1821. 		else if ((op = string_for_opt(opts, negated))) {
1822. #ifdef WIN32CON
1823. 		    (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
1824. 		    load_keyboard_handler();
1825. #endif
1826. 		}
1827. 		return;
1828. 	}
1829. 
1830. 	/* WINCAP
1831. 	 * align_status:[left|top|right|bottom] */
1832. 	fullname = "align_status";
1833. 	if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) {
1834. 		op = string_for_opt(opts, negated);
1835. 		if (op && !negated) {
1836. 		    if (!strncmpi (op, "left", sizeof("left")-1))
1837. 			iflags.wc_align_status = ALIGN_LEFT;
1838. 		    else if (!strncmpi (op, "top", sizeof("top")-1))
1839. 			iflags.wc_align_status = ALIGN_TOP;
1840. 		    else if (!strncmpi (op, "right", sizeof("right")-1))
1841. 			iflags.wc_align_status = ALIGN_RIGHT;
1842. 		    else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
1843. 			iflags.wc_align_status = ALIGN_BOTTOM;
1844. 		    else
1845. 			badoption(opts);
1846. 		} else if (negated) bad_negation(fullname, TRUE);
1847. 		return;
1848. 	}
1849. 	/* WINCAP
1850. 	 * align_message:[left|top|right|bottom] */
1851. 	fullname = "align_message";
1852. 	if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) {
1853. 		op = string_for_opt(opts, negated);
1854. 		if (op && !negated) {
1855. 		    if (!strncmpi (op, "left", sizeof("left")-1))
1856. 			iflags.wc_align_message = ALIGN_LEFT;
1857. 		    else if (!strncmpi (op, "top", sizeof("top")-1))
1858. 			iflags.wc_align_message = ALIGN_TOP;
1859. 		    else if (!strncmpi (op, "right", sizeof("right")-1))
1860. 			iflags.wc_align_message = ALIGN_RIGHT;
1861. 		    else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
1862. 			iflags.wc_align_message = ALIGN_BOTTOM;
1863. 		    else
1864. 			badoption(opts);
1865. 		} else if (negated) bad_negation(fullname, TRUE);
1866. 		return;
1867. 	}
1868. 	/* align:string */
1869. 	fullname = "align";
1870. 	if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) {
1871. 		if (negated) bad_negation(fullname, FALSE);
1872. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1873. 			if ((flags.initalign = str2align(op)) == ROLE_NONE)
1874. 				badoption(opts);
1875. 		return;
1876. 	}
1877. 
1878. 	/* the order to list the pack */
1879. 	fullname = "packorder";
1880. 	if (match_optname(opts, fullname, 4, TRUE)) {
1881. 		if (negated) {
1882. 		    bad_negation(fullname, FALSE);
1883. 		    return;
1884. 		} else if (!(op = string_for_opt(opts, FALSE))) return;
1885. 
1886. 		if (!change_inv_order(op))
1887. 			badoption(opts);
1888. 		return;
1889. 	}
1890. 
1891. 	/* maximum burden picked up before prompt (Warren Cheung) */
1892. 	fullname = "pickup_burden";
1893. 	if (match_optname(opts, fullname, 8, TRUE)) {
1894. 		if (negated) {
1895. 			bad_negation(fullname, FALSE);
1896. 			return;
1897. 		} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1898. 		    switch (tolower(*op)) {
1899. 				/* Unencumbered */
1900. 				case 'u':
1901. 					flags.pickup_burden = UNENCUMBERED;
1902. 					break;
1903. 				/* Burdened (slight encumbrance) */
1904. 				case 'b':
1905. 					flags.pickup_burden = SLT_ENCUMBER;
1906. 					break;
1907. 				/* streSsed (moderate encumbrance) */
1908. 				case 's':
1909. 					flags.pickup_burden = MOD_ENCUMBER;
1910. 					break;
1911. 				/* straiNed (heavy encumbrance) */
1912. 				case 'n':
1913. 					flags.pickup_burden = HVY_ENCUMBER;
1914. 					break;
1915. 				/* OverTaxed (extreme encumbrance) */
1916. 				case 'o':
1917. 				case 't':
1918. 					flags.pickup_burden = EXT_ENCUMBER;
1919. 					break;
1920. 				/* overLoaded */
1921. 				case 'l':
1922. 					flags.pickup_burden = OVERLOADED;
1923. 					break;
1924. 				default:
1925. 				badoption(opts);
1926. 		    }
1927. 		}
1928. 		return;
1929. 	}
1930. 
1931. 	/* types of objects to pick up automatically */
1932. 	if (match_optname(opts, "pickup_types", 8, TRUE)) {
1933. 		char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
1934. 		     qbuf[QBUFSZ], abuf[BUFSZ];
1935. 		int oc_sym;
1936. 		boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
1937. 
1938. 		oc_to_str(flags.pickup_types, tbuf);
1939. 		flags.pickup_types[0] = '\0';	/* all */
1940. 		op = string_for_opt(opts, (compat || !initial));
1941. 		if (!op) {
1942. 		    if (compat || negated || initial) {
1943. 			/* for backwards compatibility, "pickup" without a
1944. 			   value is a synonym for autopickup of all types
1945. 			   (and during initialization, we can't prompt yet) */
1946. 			flags.pickup = !negated;
1947. 			return;
1948. 		    }
1949. 		    oc_to_str(flags.inv_order, ocl);
1950. 		    use_menu = TRUE;
1951. 		    if (flags.menu_style == MENU_TRADITIONAL ||
1952. 			    flags.menu_style == MENU_COMBINATION) {
1953. 			use_menu = FALSE;
1954. 			Sprintf(qbuf, "New pickup_types: [%s am] (%s)",
1955. 				ocl, *tbuf ? tbuf : "all");
1956. 			getlin(qbuf, abuf);
1957. 			op = mungspaces(abuf);
1958. 			if (abuf[0] == '\0' || abuf[0] == '\033')
1959. 			    op = tbuf;		/* restore */
1960. 			else if (abuf[0] == 'm')
1961. 			    use_menu = TRUE;
1962. 		    }
1963. 		    if (use_menu) {
1964. 			(void) choose_classes_menu("Auto-Pickup what?", 1,
1965. 						   TRUE, ocl, tbuf);
1966. 			op = tbuf;
1967. 		    }
1968. 		}
1969. 		if (negated) {
1970. 		    bad_negation("pickup_types", TRUE);
1971. 		    return;
1972. 		}
1973. 		while (*op == ' ') op++;
1974. 		if (*op != 'a' && *op != 'A') {
1975. 		    num = 0;
1976. 		    while (*op) {
1977. 			oc_sym = def_char_to_objclass(*op);
1978. 			/* make sure all are valid obj symbols occuring once */
1979. 			if (oc_sym != MAXOCLASSES &&
1980. 			    !index(flags.pickup_types, oc_sym)) {
1981. 			    flags.pickup_types[num] = (char)oc_sym;
1982. 			    flags.pickup_types[++num] = '\0';
1983. 			} else
1984. 			    badopt = TRUE;
1985. 			op++;
1986. 		    }
1987. 		    if (badopt) badoption(opts);
1988. 		}
1989. 		return;
1990. 	}
1991. 	/* WINCAP
1992. 	 * player_selection: dialog | prompts */
1993. 	fullname = "player_selection";
1994. 	if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) {
1995. 		op = string_for_opt(opts, negated);
1996. 		if (op && !negated) {
1997. 		    if (!strncmpi (op, "dialog", sizeof("dialog")-1))
1998. 			iflags.wc_player_selection = VIA_DIALOG;
1999. 		    else if (!strncmpi (op, "prompt", sizeof("prompt")-1))
2000. 			iflags.wc_player_selection = VIA_PROMPTS;
2001. 		    else
2002. 		    	badoption(opts);
2003. 		} else if (negated) bad_negation(fullname, TRUE);
2004. 		return;
2005. 	}
2006. 
2007. 	/* things to disclose at end of game */
2008. 	if (match_optname(opts, "disclose", 7, TRUE)) {
2009. 		/*
2010. 		 * The order that the end_disclore options are stored:
2011. 		 * inventory, attribs, vanquished, genocided, conduct
2012. 		 * There is an array in flags:
2013. 		 *	end_disclose[NUM_DISCLOSURE_OPT];
2014. 		 * with option settings for the each of the following:
2015. 		 * iagvc [see disclosure_options in decl.c]:
2016. 		 * Legal setting values in that array are:
2017. 		 *	DISCLOSE_PROMPT_DEFAULT_YES  ask with default answer yes
2018. 		 *	DISCLOSE_PROMPT_DEFAULT_NO   ask with default answer no
2019. 		 *	DISCLOSE_YES_WITHOUT_PROMPT  always disclose and don't ask
2020. 		 *	DISCLOSE_NO_WITHOUT_PROMPT   never disclose and don't ask
2021. 		 *
2022. 		 * Those setting values can be used in the option
2023. 		 * string as a prefix to get the desired behaviour.
2024. 		 *
2025. 		 * For backward compatibility, no prefix is required,
2026. 		 * and the presence of a i,a,g,v, or c without a prefix
2027. 		 * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
2028. 		 */
2029. 		boolean badopt = FALSE;
2030. 		int idx, prefix_val;
2031. 
2032. 		op = string_for_opt(opts, TRUE);
2033. 		if (op && negated) {
2034. 			bad_negation("disclose", TRUE);
2035. 			return;
2036. 		}
2037. 		/* "disclose" without a value means "all with prompting"
2038. 		   and negated means "none without prompting" */
2039. 		if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
2040. 			if (op && !strcmpi(op, "none")) negated = TRUE;
2041. 			for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
2042. 			    flags.end_disclose[num] = negated ?
2043. 						DISCLOSE_NO_WITHOUT_PROMPT :
2044. 						DISCLOSE_PROMPT_DEFAULT_YES;
2045. 			return;
2046. 		}
2047. 
2048. 		num = 0;
2049. 		prefix_val = -1;
2050. 		while (*op && num < sizeof flags.end_disclose - 1) {
2051. 			register char c, *dop;
2052. 			static char valid_settings[] = {
2053. 				DISCLOSE_PROMPT_DEFAULT_YES,
2054. 				DISCLOSE_PROMPT_DEFAULT_NO,
2055. 				DISCLOSE_YES_WITHOUT_PROMPT,
2056. 				DISCLOSE_NO_WITHOUT_PROMPT,
2057. 				'\0'
2058. 			};
2059. 			c = lowc(*op);
2060. 			if (c == 'k') c = 'v';	/* killed -> vanquished */
2061. 			dop = index(disclosure_options, c);
2062. 			if (dop) {
2063. 				idx = dop - disclosure_options;
2064. 				if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
2065. 				    impossible("bad disclosure index %d %c",
2066. 							idx, c);
2067. 				    continue;
2068. 				}
2069. 				if (prefix_val != -1) {
2070. 				    flags.end_disclose[idx] = prefix_val;
2071. 				    prefix_val = -1;
2072. 				} else
2073. 				    flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
2074. 			} else if (index(valid_settings, c)) {
2075. 				prefix_val = c;
2076. 			} else if (c == ' ') {
2077. 				/* do nothing */
2078. 			} else
2079. 				badopt = TRUE;				
2080. 			op++;
2081. 		}
2082. 		if (badopt) badoption(opts);
2083. 		return;
2084. 	}
2085. 
2086. 	/* scores:5t[op] 5a[round] o[wn] */
2087. 	if (match_optname(opts, "scores", 4, TRUE)) {
2088. 	    if (negated) {
2089. 		bad_negation("scores", FALSE);
2090. 		return;
2091. 	    }
2092. 	    if (!(op = string_for_opt(opts, FALSE))) return;
2093. 
2094. 	    while (*op) {
2095. 		int inum = 1;
2096. 
2097. 		if (digit(*op)) {
2098. 		    inum = atoi(op);
2099. 		    while (digit(*op)) op++;
2100. 		} else if (*op == '!') {
2101. 		    negated = !negated;
2102. 		    op++;
2103. 		}
2104. 		while (*op == ' ') op++;
2105. 
2106. 		switch (*op) {
2107. 		 case 't':
2108. 		 case 'T':  flags.end_top = inum;
2109. 			    break;
2110. 		 case 'a':
2111. 		 case 'A':  flags.end_around = inum;
2112. 			    break;
2113. 		 case 'o':
2114. 		 case 'O':  flags.end_own = !negated;
2115. 			    break;
2116. 		 default:   badoption(opts);
2117. 			    return;
2118. 		}
2119. 		while (letter(*++op) || *op == ' ') continue;
2120. 		if (*op == '/') op++;
2121. 	    }
2122. 	    return;
2123. 	}
2124. 
2125. 	fullname = "suppress_alert";
2126. 	if (match_optname(opts, fullname, 4, TRUE)) {
2127. 		op = string_for_opt(opts, negated);
2128. 		if (negated) bad_negation(fullname, FALSE);
2129. 		else if (op) (void) feature_alert_opts(op,fullname);
2130. 		return;
2131. 	}
2132. 	
2133. 	fullname = "tileset";
2134. 	if (match_optname(opts, fullname, 4, TRUE)) {
2135. 		if (negated || (op = string_for_opt(opts, TRUE)) == 0)
2136. 			tileset[0] = '\0';
2137. 		else {
2138. 			/*
2139. 			 * The tileset may not be defined (yet) if we're
2140. 			 * in initial mode, otherwise it must exist.
2141. 			 */
2142. 			if (!initial) {
2143. 				int len = strlen(op);
2144. 				for(i = 0; i < no_tilesets; i++)
2145. 				    if (len == strlen(tilesets[i].name) &&
2146. 				      !strncmpi(tilesets[i].name, op, len))
2147. 					break;
2148. 				if (i == no_tilesets) {
2149. 				    pline("Tileset %s not defined.", op);
2150. 				    return;
2151. 				}
2152. 				else	/* Use canonical case */
2153. 				    strcpy(tileset, tilesets[i].name);
2154. 			}
2155. 			else
2156. 				nmcpy(tileset, op, PL_PSIZ);
2157. 		}
2158. 		if (!initial)
2159. 		    need_redraw = TRUE;
2160. 		return;
2161. 	}
2162. 	
2163. #if defined(VIDEOSHADES) && !defined(NO_TERMS)
2164. 	/* videocolors:string */
2165. 	fullname = "videocolors";
2166. 	if (match_optname(opts, fullname, 6, TRUE) ||
2167. 	    match_optname(opts, "videocolours", 10, TRUE)) {
2168. 		if (negated) {
2169. 			bad_negation(fullname, FALSE);
2170. 			return;
2171. 		}
2172. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2173. 			return;
2174. 		}
2175. 		if (!assign_videocolors(opts))
2176. 			badoption(opts);
2177. 		return;
2178. 	}
2179. # ifdef MSDOS
2180. 	/* videoshades:string */
2181. 	fullname = "videoshades";
2182. 	if (match_optname(opts, fullname, 6, TRUE)) {
2183. 		if (negated) {
2184. 			bad_negation(fullname, FALSE);
2185. 			return;
2186. 		}
2187. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2188. 			return;
2189. 		}
2190. 		if (!assign_videoshades(opts))
2191. 			badoption(opts);
2192. 		return;
2193. 	}
2194. # endif
2195. #endif /* VIDEOSHADES */
2196. #ifdef MSDOS
2197. # ifdef NO_TERMS
2198. 	/* video:string -- must be after longer tests */
2199. 	fullname = "video";
2200. 	if (match_optname(opts, fullname, 5, TRUE)) {
2201. 		if (negated) {
2202. 			bad_negation(fullname, FALSE);
2203. 			return;
2204. 		}
2205. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2206. 			return;
2207. 		}
2208. 		if (!assign_video(opts))
2209. 			badoption(opts);
2210. 		return;
2211. 	}
2212. # endif /* NO_TERMS */
2213. 	/* soundcard:string -- careful not to match boolean 'sound' */
2214. 	fullname = "soundcard";
2215. 	if (match_optname(opts, fullname, 6, TRUE)) {
2216. 		if (negated) {
2217. 			bad_negation(fullname, FALSE);
2218. 			return;
2219. 		}
2220. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2221. 			return;
2222. 		}
2223. 		if (!assign_soundcard(opts))
2224. 			badoption(opts);
2225. 		return;
2226. 	}
2227. #endif /* MSDOS */
2228. 
2229. 	/* WINCAP
2230. 	 * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12|
2231. 			ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */
2232. 	fullname = "map_mode";
2233. 	if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) {
2234. 		op = string_for_opt(opts, negated);
2235. 		if (op && !negated) {
2236. 		    if (!strncmpi (op, "tiles", sizeof("tiles")-1))
2237. 			iflags.wc_map_mode = MAP_MODE_TILES;
2238. 		    else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1))
2239. 			iflags.wc_map_mode = MAP_MODE_ASCII4x6;
2240. 		    else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1))
2241. 			iflags.wc_map_mode = MAP_MODE_ASCII6x8;
2242. 		    else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1))
2243. 			iflags.wc_map_mode = MAP_MODE_ASCII8x8;
2244. 		    else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1))
2245. 			iflags.wc_map_mode = MAP_MODE_ASCII16x8;
2246. 		    else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1))
2247. 			iflags.wc_map_mode = MAP_MODE_ASCII7x12;
2248. 		    else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1))
2249. 			iflags.wc_map_mode = MAP_MODE_ASCII8x12;
2250. 		    else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1))
2251. 			iflags.wc_map_mode = MAP_MODE_ASCII16x12;
2252. 		    else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1))
2253. 			iflags.wc_map_mode = MAP_MODE_ASCII12x16;
2254. 		    else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1))
2255. 			iflags.wc_map_mode = MAP_MODE_ASCII10x18;
2256. 		    else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1))
2257. 			iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
2258. 		    else
2259. 		    	badoption(opts);
2260. 		} else if (negated) bad_negation(fullname, TRUE);
2261. 		return;
2262. 	}
2263. 	/* WINCAP
2264. 	 * scroll_amount:nn */
2265. 	fullname = "scroll_amount";
2266. 	if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
2267. 		op = string_for_opt(opts, negated);
2268. 		if ((negated && !op) || (!negated && op)) {
2269. 			iflags.wc_scroll_amount = negated ? 1 : atoi(op);
2270. 		} else if (negated) bad_negation(fullname, TRUE);
2271. 		return;
2272. 	}
2273. 	/* WINCAP
2274. 	 * scroll_margin:nn */
2275. 	fullname = "scroll_margin";
2276. 	if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
2277. 		op = string_for_opt(opts, negated);
2278. 		if ((negated && !op) || (!negated && op)) {
2279. 			iflags.wc_scroll_margin = negated ? 5 : atoi(op);
2280. 		} else if (negated) bad_negation(fullname, TRUE);
2281. 		return;
2282. 	}
2283. 	fullname = "subkeyvalue";
2284. 	if (match_optname(opts, fullname, 5, TRUE)) {
2285. 		if (negated) bad_negation(fullname, FALSE);
2286. 		else {
2287. #if defined(WIN32CON)
2288. 			op = string_for_opt(opts, 0);
2289. 			map_subkeyvalue(op);
2290. #endif
2291. 		}
2292. 		return;
2293. 	}
2294. 	/* WINCAP
2295. 	 * tile_width:nn */
2296. 	fullname = "tile_width";
2297. 	if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) {
2298. 		op = string_for_opt(opts, negated);
2299. 		if ((negated && !op) || (!negated && op)) {
2300. 			iflags.wc_tile_width = negated ? 0 : atoi(op);
2301. 		} else if (negated) bad_negation(fullname, TRUE);
2302. 		return;
2303. 	}
2304. 	/* WINCAP
2305. 	 * tile_file:name */
2306. 	fullname = "tile_file";
2307. 	if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) {
2308. 		if ((op = string_for_opt(opts, FALSE)) != 0) {
2309. 			if (iflags.wc_tile_file) free(iflags.wc_tile_file);
2310. 			iflags.wc_tile_file = (char *)alloc(strlen(op) + 1);
2311. 			Strcpy(iflags.wc_tile_file, op);
2312. 		}
2313. 		return;
2314. 	}
2315. 	/* WINCAP
2316. 	 * tile_height:nn */
2317. 	fullname = "tile_height";
2318. 	if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) {
2319. 		op = string_for_opt(opts, negated);
2320. 		if ((negated && !op) || (!negated && op)) {
2321. 			iflags.wc_tile_height = negated ? 0 : atoi(op);
2322. 		} else if (negated) bad_negation(fullname, TRUE);
2323. 		return;
2324. 	}
2325. 	/* WINCAP
2326. 	 * vary_msgcount:nn */
2327. 	fullname = "vary_msgcount";
2328. 	if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) {
2329. 		op = string_for_opt(opts, negated);
2330. 		if ((negated && !op) || (!negated && op)) {
2331. 			iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
2332. 		} else if (negated) bad_negation(fullname, TRUE);
2333. 		return;
2334. 	}
2335. 	fullname = "windowtype";
2336. 	if (match_optname(opts, fullname, 3, TRUE)) {
2337. 	    if (negated) {
2338. 		bad_negation(fullname, FALSE);
2339. 		return;
2340. 	    } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
2341. 		char buf[WINTYPELEN];
2342. 		nmcpy(buf, op, WINTYPELEN);
2343. 		choose_windows(buf);
2344. 	    }
2345. 	    return;
2346. 	}
2347. 
2348. 	/* WINCAP
2349. 	 * setting window colors
2350.          * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
2351.          */
2352. 	fullname = "windowcolors";
2353. 	if (match_optname(opts, fullname, 7, TRUE)) {
2354. 		if ((op = string_for_opt(opts, FALSE)) != 0) {
2355. 			if (!wc_set_window_colors(op))
2356. 				badoption(opts);
2357. 		} else if (negated) bad_negation(fullname, TRUE);
2358. 		return;
2359. 	}
2360. 
2361. 	/* menustyle:traditional or combo or full or partial */
2362. 	if (match_optname(opts, "menustyle", 4, TRUE)) {
2363. 		int tmp;
2364. 		boolean val_required = (strlen(opts) > 5 && !negated);
2365. 
2366. 		if (!(op = string_for_opt(opts, !val_required))) {
2367. 		    if (val_required) return; /* string_for_opt gave feedback */
2368. 		    tmp = negated ? 'n' : 'f';
2369. 		} else {
2370. 		    tmp = tolower(*op);
2371. 		}
2372. 		switch (tmp) {
2373. 			case 'n':	/* none */
2374. 			case 't':	/* traditional */
2375. 				flags.menu_style = MENU_TRADITIONAL;
2376. 				break;
2377. 			case 'c':	/* combo: trad.class sel+menu */
2378. 				flags.menu_style = MENU_COMBINATION;
2379. 				break;
2380. 			case 'p':	/* partial: no class menu */
2381. 				flags.menu_style = MENU_PARTIAL;
2382. 				break;
2383. 			case 'f':	/* full: class menu + menu */
2384. 				flags.menu_style = MENU_FULL;
2385. 				break;
2386. 			default:
2387. 				badoption(opts);
2388. 		}
2389. 		return;
2390. 	}
2391. 
2392. 	fullname = "menu_headings";
2393. 	if (match_optname(opts, fullname, 12, TRUE)) {
2394. 		if (negated) {
2395. 			bad_negation(fullname, FALSE);
2396. 			return;
2397. 		}
2398. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2399. 			return;
2400. 		}
2401. 		if (!strcmpi(opts,"bold"))
2402. 			iflags.menu_headings = ATR_BOLD;
2403. 		else if (!strcmpi(opts,"inverse"))
2404. 			iflags.menu_headings = ATR_INVERSE;
2405. 		else if (!strcmpi(opts,"underline"))
2406. 			iflags.menu_headings = ATR_ULINE;
2407. 		else
2408. 			badoption(opts);
2409. 		return;
2410. 	}
2411. 
2412. 	/* check for menu command mapping */
2413. 	for (i = 0; i < NUM_MENU_CMDS; i++) {
2414. 	    fullname = default_menu_cmd_info[i].name;
2415. 	    if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) {
2416. 		if (negated)
2417. 		    bad_negation(fullname, FALSE);
2418. 		else if ((op = string_for_opt(opts, FALSE)) != 0) {
2419. 		    int j;
2420. 		    char c, op_buf[BUFSZ];
2421. 		    boolean isbad = FALSE;
2422. 
2423. 		    escapes(op, op_buf);
2424. 		    c = *op_buf;
2425. 
2426. 		    if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||
2427. 			    c == ' ' || digit(c) || (letter(c) && c != '@'))
2428. 			isbad = TRUE;
2429. 		    else	/* reject default object class symbols */
2430. 			for (j = 1; j < MAXOCLASSES; j++)
2431. 			    if (c == def_oc_syms[i]) {
2432. 				isbad = TRUE;
2433. 				break;
2434. 			    }
2435. 
2436. 		    if (isbad)
2437. 			badoption(opts);
2438. 		    else
2439. 			add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
2440. 		}
2441. 		return;
2442. 	    }
2443. 	}
2444. 
2445. 	/* OK, if we still haven't recognized the option, check the boolean
2446. 	 * options list
2447. 	 */
2448. 	for (i = 0; boolopt[i].name; i++) {
2449. 		if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
2450. 			/* options that don't exist */
2451. 			if (!boolopt[i].addr) {
2452. 			    if (!initial && !negated)
2453. 				pline_The("\"%s\" option is not available.",
2454. 					boolopt[i].name);
2455. 			    return;
2456. 			}
2457. 			/* options that must come from config file */
2458. 			if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
2459. 			    rejectoption(boolopt[i].name);
2460. 			    return;
2461. 			}
2462. 
2463. 			*(boolopt[i].addr) = !negated;
2464. 
2465. 			duplicate_opt_detection(boolopt[i].name, 0);
2466. 
2467. #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV)
2468. 			if (FALSE
2469. # ifdef TERMLIB
2470. 				 || (boolopt[i].addr) == &iflags.DECgraphics
2471. # endif
2472. # ifdef ASCIIGRAPH
2473. 				 || (boolopt[i].addr) == &iflags.IBMgraphics
2474. # endif
2475. # ifdef MAC_GRAPHICS_ENV
2476. 				 || (boolopt[i].addr) == &iflags.MACgraphics
2477. # endif
2478. 				) {
2479. # ifdef REINCARNATION
2480. 			    /* [ALI] GTK port may call doset() after initial
2481. 			     * but before we start a game. Prevent false match.
2482. 			     */
2483. 			    if (!initial && u.uz.dlevel &&
2484. 			      Is_rogue_level(&u.uz))
2485. 				assign_rogue_graphics(FALSE);
2486. # endif
2487. 			    need_redraw = TRUE;
2488. # ifdef TERMLIB
2489. 			    if ((boolopt[i].addr) == &iflags.DECgraphics)
2490. 				switch_graphics(iflags.DECgraphics ?
2491. 						DEC_GRAPHICS : ASCII_GRAPHICS);
2492. # endif
2493. # ifdef ASCIIGRAPH
2494. 			    if ((boolopt[i].addr) == &iflags.IBMgraphics)
2495. 				switch_graphics(iflags.IBMgraphics ?
2496. 						IBM_GRAPHICS : ASCII_GRAPHICS);
2497. # endif
2498. # ifdef MAC_GRAPHICS_ENV
2499. 			    if ((boolopt[i].addr) == &iflags.MACgraphics)
2500. 				switch_graphics(iflags.MACgraphics ?
2501. 						MAC_GRAPHICS : ASCII_GRAPHICS);
2502. # endif
2503. # ifdef REINCARNATION
2504. 			    if (!initial && u.uz.dlevel &&
2505. 			      Is_rogue_level(&u.uz))
2506. 				assign_rogue_graphics(TRUE);
2507. # endif
2508. 			}
2509. #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */
2510. 
2511. 			/* only do processing below if setting with doset() */
2512. 			if (initial) return;
2513. 
2514. 			if ((boolopt[i].addr) == &flags.time
2515. #ifdef EXP_ON_BOTL
2516. 			 || (boolopt[i].addr) == &flags.showexp
2517. #endif
2518. #ifdef SCORE_ON_BOTL
2519. 			 || (boolopt[i].addr) == &flags.showscore
2520. #endif
2521. #ifdef SHOW_WEIGHT
2522. 			 || (boolopt[i].addr) == &flags.showweight
2523. #endif
2524. 			    )
2525. 			    bot_reconfig();
2526. 
2527. 			else if ((boolopt[i].addr) == &flags.invlet_constant) {
2528. 			    if (flags.invlet_constant) reassign();
2529. 			}
2530. #ifdef LAN_MAIL
2531. 			else if ((boolopt[i].addr) == &flags.biff) {
2532. 			    if (flags.biff) lan_mail_init();
2533. 			    else lan_mail_finish();
2534. 			}
2535. #endif
2536. 			else if ((boolopt[i].addr) == &flags.lit_corridor) {
2537. 			    /*
2538. 			     * All corridor squares seen via night vision or
2539. 			     * candles & lamps change.  Update them by calling
2540. 			     * newsym() on them.  Don't do this if we are
2541. 			     * initializing the options --- the vision system
2542. 			     * isn't set up yet.
2543. 			     */
2544. 			    if (u.uz.dlevel)
2545. 			    {
2546. 			    vision_recalc(2);		/* shut down vision */
2547. 			    vision_full_recalc = 1;	/* delayed recalc */
2548. 			}
2549. 			}
2550. 			else if ((boolopt[i].addr) == &iflags.use_inverse ||
2551. 					(boolopt[i].addr) == &iflags.showrace ||
2552. 					(boolopt[i].addr) == &iflags.hilite_pet) {
2553. 			    need_redraw = TRUE;
2554. 			}
2555. #ifdef TEXTCOLOR
2556. 			else if ((boolopt[i].addr) == &iflags.use_color) {
2557. 			    need_redraw = TRUE;
2558. # ifdef TOS
2559. 			    if ((boolopt[i].addr) == &iflags.use_color
2560. 				&& iflags.BIOS) {
2561. 				if (colors_changed)
2562. 				    restore_colors();
2563. 				else
2564. 				    set_colors();
2565. 			    }
2566. # endif
2567. 			}
2568. #endif
2569.                         else if ((boolopt[i].addr) == &flags.perm_invent)
2570.                             update_inventory();
2571. 
2572. 			return;
2573. 		}
2574. 	}
2575. 
2576. 	/* out of valid options */
2577. 	badoption(opts);
2578. }
2579. 
2580. static void
2581. parseauthopt(opts)
2582. register char *opts;
2583. {
2584. 	register char *op;
2585. 	boolean negated;
2586. 	const char *fullname;
2587. 
2588. 	if (strlen(opts) > BUFSZ/2) {
2589. 		badauthoption("option too long");
2590. 		return;
2591. 	}
2592. 
2593. 	/* strip leading and trailing white space */
2594. 	while (isspace((int)*opts)) opts++;
2595. 	op = eos(opts);
2596. 	while (--op >= opts && isspace((int)*op)) *op = '\0';
2597. 
2598. 	if (!*opts) return;
2599. 	negated = FALSE;
2600. 	while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
2601. 		if (*opts == '!') opts++; else opts += 2;
2602. 		negated = !negated;
2603. 	}
2604. 
2605. 	/* compound options */
2606. 
2607.         fullname = "prog";
2608. 	if (match_optname(opts, fullname, 4, TRUE)) {
2609. 		if (negated) bad_negation(fullname, FALSE);
2610. 		else if ((op = string_for_auth_opt(opts, FALSE)) != 0)
2611.                         nmcpy(authentication.prog, op, BUFSZ);
2612. 		return;
2613. 	}
2614. 
2615.         fullname = "args";
2616. 	if (match_optname(opts, fullname, 4, TRUE)) {
2617. 		if (negated) bad_negation(fullname, FALSE);
2618. 		else if ((op = string_for_auth_opt(opts, FALSE)) != 0)
2619.                         nmcpy(authentication.args, op, BUFSZ);
2620. 		return;
2621. 	}
2622. 
2623. 	/* out of valid options */
2624. 	badauthoption(opts);
2625. }
2626. 
2627. void
2628. parseauthentication(opts)
2629. register char *opts;
2630. {
2631. 	register char *op;
2632. 
2633. 	/* Initial values */
2634. 	authentication.prog[0] = '\0';
2635. 	authentication.args[0] = '\0';
2636. 
2637. 	while ((op = index(opts, ',')) != 0) {
2638. 		*op++ = 0;
2639. 		parseauthopt(opts);
2640. 		opts = op;
2641. 	}
2642. 	parseauthopt(opts);
2643. 
2644. 	if (!authentication.prog[0] && authentication.args[0])
2645. 		badauthoption("Arguments given but no program specified.");
2646. }
2647. 
2648. static void
2649. parsetilesetopt(opts)
2650. register char *opts;
2651. {
2652. 	register char *op;
2653. 	boolean negated;
2654. 	int i;
2655. 	const char *fullname;
2656. 
2657. 	if (strlen(opts) > BUFSZ/2) {
2658. 		badtileoption("option too long");
2659. 		return;
2660. 	}
2661. 
2662. 	/* strip leading and trailing white space */
2663. 	while (isspace((int)*opts)) opts++;
2664. 	op = eos(opts);
2665. 	while (--op >= opts && isspace((int)*op)) *op = '\0';
2666. 
2667. 	if (!*opts) return;
2668. 	negated = FALSE;
2669. 	while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
2670. 		if (*opts == '!') opts++; else opts += 2;
2671. 		negated = !negated;
2672. 	}
2673. 
2674. 	/* compound options */
2675. 
2676.         fullname = "name";
2677. 	if (match_optname(opts, fullname, 4, TRUE)) {
2678. 		if (negated) bad_negation(fullname, FALSE);
2679. 		else if ((op = string_for_tile_opt(opts, FALSE)) != 0)
2680.                         nmcpy(tilesets[no_tilesets].name, op, PL_PSIZ);
2681. 		return;
2682. 	}
2683. 
2684.         fullname = "filename";
2685. 	if (match_optname(opts, fullname, 4, TRUE)) {
2686. 		if (negated) bad_negation(fullname, FALSE);
2687. 		else if ((op = string_for_tile_opt(opts, FALSE)) != 0)
2688.                         nmcpy(tilesets[no_tilesets].file, op,
2689. 			  TILESET_MAX_FILENAME);
2690. 		return;
2691. 	}
2692. 
2693. 	/* OK, if we still haven't recognized the option, check the boolean
2694. 	 * options list
2695. 	 */
2696. 	for (i = 0; booltileopt[i].name; i++) {
2697. 		if (match_optname(opts, booltileopt[i].name, 3, FALSE)) {
2698. 			if (negated)
2699. 			    tilesets[no_tilesets].flags &= ~booltileopt[i].flag;
2700. 			else
2701. 			    tilesets[no_tilesets].flags |= booltileopt[i].flag;
2702. 			return;
2703. 		}
2704. 	}
2705. 
2706. 	/* out of valid options */
2707. 	badtileoption(opts);
2708. }
2709. 
2710. void
2711. parsetileset(opts)
2712. register char *opts;
2713. {
2714. 	register char *op;
2715. 	int i;
2716. 
2717. 	if (no_tilesets >= MAXNOTILESETS) {
2718. 		badtileoption("too many tilesets");
2719. 		return;
2720. 	}
2721. 
2722. 	/* Initial values */
2723. 	tilesets[no_tilesets].name[0] = '\0';
2724. 	tilesets[no_tilesets].file[0] = '\0';
2725. 	tilesets[no_tilesets].flags = 0;
2726. 	for (i = 0; booltileopt[i].name; i++)
2727. 		tilesets[no_tilesets].flags |= booltileopt[i].initvalue;
2728. 
2729. 	while ((op = index(opts, ',')) != 0) {
2730. 		*op++ = 0;
2731. 		parsetilesetopt(opts);
2732. 		opts = op;
2733. 	}
2734. 	parsetilesetopt(opts);
2735. 
2736. 	if (tilesets[no_tilesets].name[0] == '\0' ||
2737. 	  tilesets[no_tilesets].file[0] == '\0') {
2738. 		badtileoption("Incomplete tileset definition.");
2739. 	}
2740. 	else
2741. 		no_tilesets++;
2742. }
2743. 
2744. 
2745. static NEARDATA const char *menutype[] = {
2746. 	"traditional", "combination", "partial", "full"
2747. };
2748. 
2749. static NEARDATA const char *burdentype[] = {
2750. 	"unencumbered", "burdened", "stressed",
2751. 	"strained", "overtaxed", "overloaded"
2752. };
2753. 
2754. static NEARDATA const char *runmodes[] = {
2755. 	"teleport", "run", "walk", "crawl"
2756. };
2757. 
2758. /*
2759.  * Convert the given string of object classes to a string of default object
2760.  * symbols.
2761.  */
2762. STATIC_OVL void
2763. oc_to_str(src,dest)
2764.     char *src, *dest;
2765. {
2766.     int i;
2767. 
2768.     while ((i = (int) *src++) != 0) {
2769. 	if (i < 0 || i >= MAXOCLASSES)
2770. 	    impossible("oc_to_str:  illegal object class %d", i);
2771. 	else
2772. 	    *dest++ = def_oc_syms[i];
2773.     }
2774.     *dest = '\0';
2775. }
2776. 
2777. /*
2778.  * Add the given mapping to the menu command map list.  Always keep the
2779.  * maps valid C strings.
2780.  */
2781. void
2782. add_menu_cmd_alias(from_ch, to_ch)
2783.     char from_ch, to_ch;
2784. {
2785.     if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
2786. 	pline("out of menu map space.");
2787.     else {
2788. 	mapped_menu_cmds[n_menu_mapped] = from_ch;
2789. 	mapped_menu_op[n_menu_mapped] = to_ch;
2790. 	n_menu_mapped++;
2791. 	mapped_menu_cmds[n_menu_mapped] = 0;
2792. 	mapped_menu_op[n_menu_mapped] = 0;
2793.     }
2794. }
2795. 
2796. /*
2797.  * Map the given character to its corresponding menu command.  If it
2798.  * doesn't match anything, just return the original.
2799.  */
2800. char
2801. map_menu_cmd(ch)
2802.     char ch;
2803. {
2804.     char *found = index(mapped_menu_cmds, ch);
2805.     if (found) {
2806. 	int idx = found - mapped_menu_cmds;
2807. 	ch = mapped_menu_op[idx];
2808.     }
2809.     return ch;
2810. }
2811. 
2812. 
2813. #if defined(MICRO) || defined(MAC) || defined(WIN32)
2814. # define OPTIONS_HEADING "OPTIONS"
2815. #else
2816. # define OPTIONS_HEADING NETHACK_ENV_OPTIONS
2817. #endif
2818. 
2819. static char fmtstr_doset_add_menu[] = "%s%-15s [%s]   "; 
2820. static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
2821. 
2822. STATIC_OVL void
2823. doset_add_menu(win, option, indexoffset)
2824.     winid win;			/* window to add to */
2825.     const char *option;		/* option name */
2826.     int indexoffset;		/* value to add to index in compopt[], or zero
2827. 				   if option cannot be changed */
2828. {
2829.     const char *value = "unknown";		/* current value */
2830.     char buf[BUFSZ], buf2[BUFSZ];
2831.     anything any;
2832.     int i;
2833. 
2834.     any.a_void = 0;
2835.     if (indexoffset == 0) {
2836. 	any.a_int = 0;
2837. 	value = get_compopt_value(option, buf2);
2838.     } else {
2839. 	for (i=0; compopt[i].name; i++)
2840. 	    if (strcmp(option, compopt[i].name) == 0) break;
2841. 
2842. 	if (compopt[i].name) {
2843. 	    any.a_int = i + 1 + indexoffset;
2844. 	    value = get_compopt_value(option, buf2);
2845. 	} else {
2846. 	    /* We are trying to add an option not found in compopt[].
2847. 	       This is almost certainly bad, but we'll let it through anyway
2848. 	       (with a zero value, so it can't be selected). */
2849. 	    any.a_int = 0;
2850. 	}
2851.     }
2852.     /* "    " replaces "a - " -- assumes menus follow that style */
2853.     if (!iflags.menu_tab_sep)
2854. 	Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ", option, value);
2855.     else
2856. 	Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
2857.     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
2858. }
2859. 
2860. /* Changing options via menu by Per Liboriussen */
2861. int
2862. doset()
2863. {
2864. 	char buf[BUFSZ], buf2[BUFSZ];
2865. 	int i, pass, boolcount, pick_cnt, pick_idx, opt_indx;
2866. 	boolean *bool_p;
2867. 	winid tmpwin;
2868. 	anything any;
2869. 	menu_item *pick_list;
2870. 	int indexoffset, startpass, endpass;
2871. 	boolean setinitial = FALSE, fromfile = FALSE;
2872. 	int biggest_name = 0;
2873. 
2874. 	tmpwin = create_nhwindow(NHW_MENU);
2875. 	start_menu(tmpwin);
2876. 
2877. 	any.a_void = 0;
2878.  add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2879. 		 "Booleans (selecting will toggle value):", MENU_UNSELECTED);
2880. 	any.a_int = 0;
2881. 	/* first list any other non-modifiable booleans, then modifiable ones */
2882. 	for (pass = 0; pass <= 1; pass++)
2883. 	    for (i = 0; boolopt[i].name; i++)
2884. 		if ((bool_p = boolopt[i].addr) != 0 &&
2885. 			((boolopt[i].optflags == DISP_IN_GAME && pass == 0) ||
2886. 			 (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
2887. 		    if (bool_p == &flags.female) continue;  /* obsolete */
2888. #ifdef WIZARD
2889. #ifndef OBJ_SANITY
2890. 		    if (bool_p == &iflags.sanity_check && !wizard) continue;
2891. #endif
2892. 		    if (bool_p == &iflags.menu_tab_sep && !wizard) continue;
2893. #endif
2894. 		    if (is_wc_option(boolopt[i].name) &&
2895. 			!wc_supported(boolopt[i].name)) continue;
2896. 		    if (is_wc2_option(boolopt[i].name) &&
2897. 			!wc2_supported(boolopt[i].name)) continue;
2898. 		    any.a_int = (pass == 0) ? 0 : i + 1;
2899. 		    if (!iflags.menu_tab_sep)
2900. 			Sprintf(buf, "%s%-13s [%s]",
2901. 			    pass == 0 ? "    " : "",
2902. 			    boolopt[i].name, *bool_p ? "true" : "false");
2903.  		    else
2904. 			Sprintf(buf, "%s\t[%s]",
2905. 			    boolopt[i].name, *bool_p ? "true" : "false");
2906. 		    add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
2907. 			     ATR_NONE, buf, MENU_UNSELECTED);
2908. 		}
2909. 
2910. 	boolcount = i;
2911. 	indexoffset = boolcount;
2912. 	any.a_void = 0;
2913. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2914.  add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2915. 		 "Compounds (selecting will prompt for new value):",
2916. 		 MENU_UNSELECTED);
2917. 
2918. 	startpass = DISP_IN_GAME;
2919. 	endpass = SET_IN_GAME;
2920. 
2921. 	/* spin through the options to find the biggest name
2922.            and adjust the format string accordingly if needed */
2923. 	biggest_name = 0;
2924. 	for (i = 0; compopt[i].name; i++)
2925. 		if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass &&
2926. 		    strlen(compopt[i].name) > (unsigned) biggest_name)
2927. 			biggest_name = (int) strlen(compopt[i].name);
2928. 	if (biggest_name > 30) biggest_name = 30;
2929. 	if (!iflags.menu_tab_sep)
2930. 		Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
2931. 	
2932. 	/* deliberately put `name', `role', `race', `gender' first */
2933. 	doset_add_menu(tmpwin, "name", 0);
2934. 	doset_add_menu(tmpwin, "role", 0);
2935. 	doset_add_menu(tmpwin, "race", 0);
2936. 	doset_add_menu(tmpwin, "gender", 0);
2937. 
2938. 	for (pass = startpass; pass <= endpass; pass++) 
2939. 	    for (i = 0; compopt[i].name; i++)
2940. 		if (compopt[i].optflags == pass) {
2941.  		    	if (!strcmp(compopt[i].name, "name") ||
2942. 		    	    !strcmp(compopt[i].name, "role") ||
2943. 		    	    !strcmp(compopt[i].name, "race") ||
2944. 		    	    !strcmp(compopt[i].name, "gender"))
2945. 		    	    	continue;
2946. 		    	else if (is_wc_option(compopt[i].name) &&
2947. 					!wc_supported(compopt[i].name))
2948. 		    		continue;
2949. 		    	else if (is_wc2_option(compopt[i].name) &&
2950. 					!wc2_supported(compopt[i].name))
2951. 		    		continue;
2952. 		    	else
2953. 				doset_add_menu(tmpwin, compopt[i].name,
2954. 					(pass == DISP_IN_GAME) ? 0 : indexoffset);
2955. 		}
2956. #ifdef AUTOPICKUP_EXCEPTIONS
2957. 	any.a_int = -1;
2958. 	Sprintf(buf, "autopickup exceptions (%d currently set)",
2959. 		count_ape_maps((int *)0, (int *)0));
2960. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
2961. 
2962. #endif /* AUTOPICKUP_EXCEPTIONS */
2963. #ifdef PREFIXES_IN_USE
2964. 	any.a_void = 0;
2965. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2966. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2967. 		 "Variable playground locations:", MENU_UNSELECTED);
2968. 	for (i = 0; i < PREFIX_COUNT; i++)
2969. 		doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
2970. #endif
2971. 	end_menu(tmpwin, "Set what options?");
2972. 	need_redraw = FALSE;
2973. 	if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
2974. 	    /*
2975. 	     * Walk down the selection list and either invert the booleans
2976. 	     * or prompt for new values. In most cases, call parseoptions()
2977. 	     * to take care of options that require special attention, like
2978. 	     * redraws.
2979. 	     */
2980. 	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
2981. 		opt_indx = pick_list[pick_idx].item.a_int - 1;
2982. #ifdef AUTOPICKUP_EXCEPTIONS
2983. 		if (opt_indx == -2) {
2984. 		    special_handling("autopickup_exception",
2985. 		    			setinitial, fromfile);
2986. 		} else
2987. #endif
2988. 		if (opt_indx < boolcount) {
2989. 		    /* boolean option */
2990. 		    Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
2991. 			    boolopt[opt_indx].name);
2992. 		    parseoptions(buf, setinitial, fromfile);
2993. 		    if (wc_supported(boolopt[opt_indx].name) ||
2994. 		    	wc2_supported(boolopt[opt_indx].name))
2995. 			preference_update(boolopt[opt_indx].name);
2996. 		} else {
2997. 		    /* compound option */
2998. 		    opt_indx -= boolcount;
2999. 
3000. 		    if (!special_handling(compopt[opt_indx].name,
3001. 							setinitial, fromfile)) {
3002. 			Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
3003. 			getlin(buf, buf2);
3004. 			if (buf2[0] == '\033')
3005. 			    continue;
3006. 			Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
3007. 			/* pass the buck */
3008. 			parseoptions(buf, setinitial, fromfile);
3009. 		    }
3010. 		    if (wc_supported(compopt[opt_indx].name) ||
3011. 			wc2_supported(compopt[opt_indx].name))
3012. 			preference_update(compopt[opt_indx].name);
3013. 		}
3014. 	    }
3015. 	    free((genericptr_t)pick_list);
3016. 	    pick_list = (menu_item *)0;
3017. 	}
3018. 
3019. 	destroy_nhwindow(tmpwin);
3020. 	if (need_redraw)
3021. 	    (void) doredraw();
3022. 	return 0;
3023. }
3024. 
3025. STATIC_OVL boolean
3026. special_handling(optname, setinitial, setfromfile)
3027. const char *optname;
3028. boolean setinitial,setfromfile;
3029. {
3030.     winid tmpwin;
3031.     anything any;
3032.     int i;
3033.     char buf[BUFSZ];
3034.     boolean retval = FALSE;
3035.     
3036.     /* Special handling of menustyle, pickup_burden, pickup_types,
3037.      * disclose, runmode, msg_window, menu_headings, and number_pad options.
3038. #ifdef AUTOPICKUP_EXCEPTIONS
3039.      * Also takes care of interactive autopickup_exception_handling changes.
3040. #endif
3041.      */
3042.     if (!strcmp("menustyle", optname)) {
3043. 	const char *style_name;
3044. 	menu_item *style_pick = (menu_item *)0;
3045.         tmpwin = create_nhwindow(NHW_MENU);
3046. 	start_menu(tmpwin);
3047. 	for (i = 0; i < SIZE(menutype); i++) {
3048. 		style_name = menutype[i];
3049.     		/* note: separate `style_name' variable used
3050. 		   to avoid an optimizer bug in VAX C V2.3 */
3051. 		any.a_int = i + 1;
3052. 		add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,
3053. 			 ATR_NONE, style_name, MENU_UNSELECTED);
3054.         }
3055. 	end_menu(tmpwin, "Select menustyle:");
3056. 	if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
3057. 		flags.menu_style = style_pick->item.a_int - 1;
3058. 		free((genericptr_t)style_pick);
3059.         }
3060. 	destroy_nhwindow(tmpwin);
3061.         retval = TRUE;
3062.     } else if (!strcmp("pickup_burden", optname)) {
3063. 	const char *burden_name, *burden_letters = "ubsntl";
3064. 	menu_item *burden_pick = (menu_item *)0;
3065.         tmpwin = create_nhwindow(NHW_MENU);
3066. 	start_menu(tmpwin);
3067. 	for (i = 0; i < SIZE(burdentype); i++) {
3068. 		burden_name = burdentype[i];
3069. 		any.a_int = i + 1;
3070. 		add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,
3071. 			 ATR_NONE, burden_name, MENU_UNSELECTED);
3072.         }
3073. 	end_menu(tmpwin, "Select encumbrance level:");
3074. 	if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
3075. 		flags.pickup_burden = burden_pick->item.a_int - 1;
3076. 		free((genericptr_t)burden_pick);
3077. 	}
3078. 	destroy_nhwindow(tmpwin);
3079. 	retval = TRUE;
3080.     } else if (!strcmp("pickup_types", optname)) {
3081. 	/* parseoptions will prompt for the list of types */
3082. 	parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
3083. 	retval = TRUE;
3084.     } else if (!strcmp("disclose", optname)) {
3085. 	int pick_cnt, pick_idx, opt_idx;
3086. 	menu_item *disclosure_category_pick = (menu_item *)0;
3087. 	/*
3088. 	 * The order of disclose_names[]
3089.          * must correspond to disclosure_options in decl.h
3090.          */
3091. 	static const char *disclosure_names[] = {
3092. 		"inventory", "attributes", "vanquished", "genocides", "conduct"
3093. 	};
3094. 	int disc_cat[NUM_DISCLOSURE_OPTIONS];
3095. 	const char *disclosure_name;
3096. 
3097.         tmpwin = create_nhwindow(NHW_MENU);
3098. 	start_menu(tmpwin);
3099. 	for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
3100. 		disclosure_name = disclosure_names[i];
3101. 		any.a_int = i + 1;
3102. 		add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
3103. 			 ATR_NONE, disclosure_name, MENU_UNSELECTED);
3104. 		disc_cat[i] = 0;
3105.         }
3106. 	end_menu(tmpwin, "Change which disclosure options categories:");
3107. 	if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) {
3108. 	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
3109. 		opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1;
3110. 		disc_cat[opt_idx] = 1;
3111. 	    }
3112. 	    free((genericptr_t)disclosure_category_pick);
3113. 	    disclosure_category_pick = (menu_item *)0;
3114. 	}
3115. 	destroy_nhwindow(tmpwin);
3116. 
3117. 	for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
3118. 	    if (disc_cat[i]) {
3119. 	    	char dbuf[BUFSZ];
3120. 		menu_item *disclosure_option_pick = (menu_item *)0;
3121. 		Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]);
3122. 	        tmpwin = create_nhwindow(NHW_MENU);
3123. 		start_menu(tmpwin);
3124. 		any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
3125. 		add_menu(tmpwin, NO_GLYPH, &any, 'a', 0,
3126. 			ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED);
3127. 		any.a_void = 0;
3128. 		any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
3129. 		add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
3130. 			ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED);
3131. 		any.a_void = 0;
3132. 		any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
3133. 		add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
3134. 			ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED);
3135. 		any.a_void = 0;
3136. 		any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
3137. 		add_menu(tmpwin, NO_GLYPH, &any, 'd', 0,
3138. 			ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED);
3139. 		end_menu(tmpwin, dbuf);
3140. 		if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) {
3141. 			flags.end_disclose[i] = disclosure_option_pick->item.a_char;
3142. 			free((genericptr_t)disclosure_option_pick);
3143. 		}
3144. 		destroy_nhwindow(tmpwin);
3145. 	    }
3146. 	}
3147. 	retval = TRUE;
3148.     } else if (!strcmp("runmode", optname)) {
3149. 	const char *mode_name;
3150. 	menu_item *mode_pick = (menu_item *)0;
3151. 	tmpwin = create_nhwindow(NHW_MENU);
3152. 	start_menu(tmpwin);
3153. 	for (i = 0; i < SIZE(runmodes); i++) {
3154. 		mode_name = runmodes[i];
3155. 		any.a_int = i + 1;
3156. 		add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
3157. 			 ATR_NONE, mode_name, MENU_UNSELECTED);
3158. 	}
3159. 	end_menu(tmpwin, "Select run/travel display mode:");
3160. 	if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
3161. 		iflags.runmode = mode_pick->item.a_int - 1;
3162. 		free((genericptr_t)mode_pick);
3163. 	}
3164. 	destroy_nhwindow(tmpwin);
3165. 	retval = TRUE;
3166.     } 
3167. #ifdef TTY_GRAPHICS
3168.       else if (!strcmp("msg_window", optname)) {
3169. 	/* by Christian W. Cooper */
3170. 	menu_item *window_pick = (menu_item *)0;
3171. 	tmpwin = create_nhwindow(NHW_MENU);
3172. 	start_menu(tmpwin);
3173. 	any.a_char = 's';
3174. 	add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
3175. 		ATR_NONE, "single", MENU_UNSELECTED);
3176. 	any.a_char = 'c';
3177. 	add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
3178. 		ATR_NONE, "combination", MENU_UNSELECTED);
3179. 	any.a_char = 'f';
3180. 	add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
3181. 		ATR_NONE, "full", MENU_UNSELECTED);
3182. 	any.a_char = 'r';
3183. 	add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
3184. 		ATR_NONE, "reversed", MENU_UNSELECTED);
3185. 	end_menu(tmpwin, "Select message history display type:");
3186. 	if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
3187. 		iflags.prevmsg_window = window_pick->item.a_char;
3188. 		free((genericptr_t)window_pick);
3189. 	}
3190. 	destroy_nhwindow(tmpwin);
3191.         retval = TRUE;
3192.     }
3193. #endif
3194.      else if (!strcmp("align_message", optname) ||
3195. 		!strcmp("align_status", optname)) {
3196. 	menu_item *window_pick = (menu_item *)0;
3197. 	char abuf[BUFSZ];
3198. 	boolean msg = (*(optname+6) == 'm');
3199. 
3200. 	tmpwin = create_nhwindow(NHW_MENU);
3201. 	start_menu(tmpwin);
3202. 	any.a_int = ALIGN_TOP;
3203. 	add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
3204. 		ATR_NONE, "top", MENU_UNSELECTED);
3205. 	any.a_int = ALIGN_BOTTOM;
3206. 	add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
3207. 		ATR_NONE, "bottom", MENU_UNSELECTED);
3208. 	any.a_int = ALIGN_LEFT;
3209. 	add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
3210. 		ATR_NONE, "left", MENU_UNSELECTED);
3211. 	any.a_int = ALIGN_RIGHT;
3212. 	add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
3213. 		ATR_NONE, "right", MENU_UNSELECTED);
3214. 	Sprintf(abuf, "Select %s window placement relative to the map:",
3215. 		msg ? "message" : "status");
3216. 	end_menu(tmpwin, abuf);
3217. 	if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {		
3218. 		if (msg) iflags.wc_align_message = window_pick->item.a_int;
3219. 		else iflags.wc_align_status = window_pick->item.a_int;
3220. 		free((genericptr_t)window_pick);
3221. 	}
3222. 	destroy_nhwindow(tmpwin);
3223.         retval = TRUE;
3224.     } else if (!strcmp("number_pad", optname)) {
3225. 	static const char *npchoices[3] =
3226. 		{"0 (off)", "1 (on)", "2 (on, DOS compatible)"};
3227. 	const char *npletters = "abc";
3228. 	menu_item *mode_pick = (menu_item *)0;
3229. 
3230. 	tmpwin = create_nhwindow(NHW_MENU);
3231. 	start_menu(tmpwin);
3232. 	for (i = 0; i < SIZE(npchoices); i++) {
3233. 		any.a_int = i + 1;
3234. 		add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
3235. 			 ATR_NONE, npchoices[i], MENU_UNSELECTED);
3236.         }
3237. 	end_menu(tmpwin, "Select number_pad mode:");
3238. 	if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
3239. 		int mode = mode_pick->item.a_int - 1;
3240. 		switch(mode) {
3241. 			case 2:
3242. 				iflags.num_pad = 1;
3243. 				iflags.num_pad_mode = 1;
3244. 				break;
3245. 			case 1:
3246. 				iflags.num_pad = 1;
3247. 				iflags.num_pad_mode = 0;
3248. 				break;
3249. 			case 0:
3250. 			default:
3251. 				iflags.num_pad = 0;
3252. 				iflags.num_pad_mode = 0;
3253. 		}
3254. 		free((genericptr_t)mode_pick);
3255. 		number_pad(iflags.num_pad);
3256.         }
3257. 	destroy_nhwindow(tmpwin);
3258.         retval = TRUE;
3259.     } else if (!strcmp("menu_headings", optname)) {
3260. 	static const char *mhchoices[3] = {"bold", "inverse", "underline"};
3261. 	const char *npletters = "biu";
3262. 	menu_item *mode_pick = (menu_item *)0;
3263. 
3264. 	tmpwin = create_nhwindow(NHW_MENU);
3265. 	start_menu(tmpwin);
3266. 	for (i = 0; i < SIZE(mhchoices); i++) {
3267. 		any.a_int = i + 1;
3268. 		add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
3269. 			 ATR_NONE, mhchoices[i], MENU_UNSELECTED);
3270.         }
3271. 	end_menu(tmpwin, "How to highlight menu headings:");
3272. 	if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
3273. 		int mode = mode_pick->item.a_int - 1;
3274. 		switch(mode) {
3275. 			case 2:
3276. 				iflags.menu_headings = ATR_ULINE;
3277. 				break;
3278. 			case 0:
3279. 				iflags.menu_headings = ATR_BOLD;
3280. 				break;
3281. 			case 1:
3282. 			default:
3283. 				iflags.menu_headings = ATR_INVERSE;
3284. 		}
3285. 		free((genericptr_t)mode_pick);
3286.         }
3287. 	destroy_nhwindow(tmpwin);
3288.         retval = TRUE;
3289. #ifdef AUTOPICKUP_EXCEPTIONS
3290.     } else if (!strcmp("autopickup_exception", optname)) {
3291.     	boolean retval;
3292. 	int pick_cnt, pick_idx, opt_idx, pass;
3293. 	int totalapes = 0, numapes[2] = {0,0};
3294. 	menu_item *pick_list = (menu_item *)0;
3295. 	anything any;
3296. 	char apebuf[BUFSZ];
3297. 	struct autopickup_exception *ape;
3298. 	static const char *action_titles[] = {
3299. 		"a", "add new autopickup exception",
3300. 		"l", "list autopickup exceptions",
3301. 		"r", "remove existing autopickup exception",
3302. 		"e", "exit this menu",
3303. 	};
3304. ape_again:
3305. 	opt_idx = 0;
3306. 	totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
3307. 	tmpwin = create_nhwindow(NHW_MENU);
3308. 	start_menu(tmpwin);
3309. 	any.a_int = 0;
3310. 	for (i = 0; i < SIZE(action_titles) ; i += 2) {
3311. 		any.a_int++;
3312. 		if (!totalapes && (i >= 2 && i < 6)) continue;
3313. 		add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i],
3314. 		      0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED);
3315.         }
3316. 	end_menu(tmpwin, "Do what?");
3317. 	if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
3318. 		for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
3319. 			opt_idx = pick_list[pick_idx].item.a_int - 1;
3320. 		}
3321. 		free((genericptr_t)pick_list);
3322. 		pick_list = (menu_item *)0;
3323. 	}
3324. 	destroy_nhwindow(tmpwin);
3325. 	if (pick_cnt < 1) return FALSE;
3326. 
3327. 	if (opt_idx == 0) {	/* add new */
3328. 		getlin("What new autopickup exception pattern?", &apebuf[1]);
3329. 		if (apebuf[1] == '\033') return FALSE;
3330. 		apebuf[0] = '"';
3331. 		Strcat(apebuf,"\"");
3332. 		add_autopickup_exception(apebuf);
3333. 		goto ape_again;
3334. 	} else if (opt_idx == 3) {
3335. 		retval = TRUE;
3336. 	} else {	/* remove */
3337. 		tmpwin = create_nhwindow(NHW_MENU);
3338. 		start_menu(tmpwin);
3339. 		for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
3340. 		    if (numapes[pass] == 0) continue;
3341. 		    ape = iflags.autopickup_exceptions[pass];
3342. 		    any.a_void = 0;
3343. 		    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3344. 				(pass == 0) ? "Never pickup" : "Always pickup",
3345. 				MENU_UNSELECTED);
3346. 		    for (i = 0; i < numapes[pass] && ape; i++) {
3347. 			any.a_void = (opt_idx == 1) ? 0 : ape;
3348. 			Sprintf(apebuf, "\"%s\"", ape->pattern);
3349. 			add_menu(tmpwin, NO_GLYPH, &any,
3350. 				0, 0, ATR_NONE, apebuf, MENU_UNSELECTED);
3351. 			ape = ape->next;
3352. 		    }
3353. 		}
3354. 		Sprintf(apebuf, "%s autopickup exceptions",
3355. 			(opt_idx == 1) ? "List of" : "Remove which");
3356. 		end_menu(tmpwin, apebuf);
3357. 		pick_cnt = select_menu(tmpwin,
3358. 					(opt_idx == 1) ?  PICK_NONE : PICK_ANY,
3359. 					&pick_list);
3360. 		if (pick_cnt > 0) {
3361. 	    	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
3362. 			remove_autopickup_exception(
3363. 			 (struct autopickup_exception *)pick_list[pick_idx].item.a_void);
3364. 	        }
3365. 	        free((genericptr_t)pick_list);
3366. 	        pick_list = (menu_item *)0;
3367. 		destroy_nhwindow(tmpwin);
3368. 		goto ape_again;
3369. 	}
3370. 	retval = TRUE;
3371. #endif /* AUTOPICKUP_EXCEPTIONS */
3372.     }
3373.     return retval;
3374. }
3375. 
3376. #define rolestring(val,array,field) ((val >= 0) ? array[val].field : \
3377. 				     (val == ROLE_RANDOM) ? randomrole : none)
3378. 
3379. /* This is ugly. We have all the option names in the compopt[] array,
3380.    but we need to look at each option individually to get the value. */
3381. STATIC_OVL const char *
3382. get_compopt_value(optname, buf)
3383. const char *optname;
3384. char *buf;
3385. {
3386. 	char ocl[MAXOCLASSES+1];
3387. 	static const char none[] = "(none)", randomrole[] = "random",
3388. 		     to_be_done[] = "(to be done)",
3389. 		     defopt[] = "default",
3390. 		     defbrief[] = "def";
3391. 	int i;
3392. 
3393. 	buf[0] = '\0';
3394. 	if (!strcmp(optname,"align_message"))
3395. 		Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP     ? "top" :
3396. 				   iflags.wc_align_message == ALIGN_LEFT    ? "left" :
3397. 				   iflags.wc_align_message == ALIGN_BOTTOM  ? "bottom" :
3398. 				   iflags.wc_align_message == ALIGN_RIGHT   ? "right" :
3399. 				   defopt);
3400. 	else if (!strcmp(optname,"align_status"))
3401. 		Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP     ? "top" :
3402. 				   iflags.wc_align_status == ALIGN_LEFT    ? "left" :
3403. 				   iflags.wc_align_status == ALIGN_BOTTOM  ? "bottom" :
3404. 				   iflags.wc_align_status == ALIGN_RIGHT   ? "right" :
3405. 				   defopt);
3406. 	else if (!strcmp(optname,"align"))
3407. 		Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
3408. #ifdef WIN32CON
3409. 	else if (!strcmp(optname,"altkeyhandler"))
3410. 		Sprintf(buf, "%s", iflags.altkeyhandler[0] ?
3411. 			iflags.altkeyhandler : "default");
3412. #endif
3413. 	else if (!strcmp(optname, "boulder"))
3414. 		Sprintf(buf, "%c", iflags.bouldersym ?
3415. 			iflags.bouldersym : oc_syms[(int)objects[BOULDER].oc_class]);
3416. 	else if (!strcmp(optname, "catname")) 
3417. 		Sprintf(buf, "%s", catname[0] ? catname : none );
3418. 	else if (!strcmp(optname, "disclose")) {
3419. 		for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
3420. 			char topt[2];
3421. 			if (i) Strcat(buf," ");
3422. 			topt[1] = '\0';
3423. 			topt[0] = flags.end_disclose[i];
3424. 			Strcat(buf, topt);
3425. 			topt[0] = disclosure_options[i];
3426. 			Strcat(buf, topt);
3427. 		}
3428. 	}
3429. 	else if (!strcmp(optname, "dogname")) 
3430. 		Sprintf(buf, "%s", dogname[0] ? dogname : none );
3431. 	else if (!strcmp(optname, "dungeon"))
3432. 		Sprintf(buf, "%s", to_be_done);
3433. 	else if (!strcmp(optname, "effects"))
3434. 		Sprintf(buf, "%s", to_be_done);
3435. 	else if (!strcmp(optname, "font_map"))
3436. 		Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
3437. 	else if (!strcmp(optname, "font_message"))
3438. 		Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt);
3439. 	else if (!strcmp(optname, "font_status"))
3440. 		Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt);
3441. 	else if (!strcmp(optname, "font_menu"))
3442. 		Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
3443. 	else if (!strcmp(optname, "font_text"))
3444. 		Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt);
3445. 	else if (!strcmp(optname, "font_size_map")) {
3446. 		if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map);
3447. 		else Strcpy(buf, defopt);
3448. 	}
3449. 	else if (!strcmp(optname, "font_size_message")) {
3450. 		if (iflags.wc_fontsiz_message) Sprintf(buf, "%d",
3451. 							iflags.wc_fontsiz_message);
3452. 		else Strcpy(buf, defopt);
3453. 	}
3454. 	else if (!strcmp(optname, "font_size_status")) {
3455. 		if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status);
3456. 		else Strcpy(buf, defopt);
3457. 	}
3458. 	else if (!strcmp(optname, "font_size_menu")) {
3459. 		if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
3460. 		else Strcpy(buf, defopt);
3461. 	}
3462. 	else if (!strcmp(optname, "font_size_text")) {
3463. 		if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text);
3464. 		else Strcpy(buf, defopt);
3465. 	}
3466. 	else if (!strcmp(optname, "fruit")) 
3467. 		Sprintf(buf, "%s", pl_fruit);
3468. 	else if (!strcmp(optname, "gender"))
3469. 		Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
3470. 	else if (!strcmp(optname, "ghoulname")) 
3471. 		Sprintf(buf, "%s", ghoulname[0] ? ghoulname : none );
3472. 	else if (!strcmp(optname, "horsename")) 
3473. 		Sprintf(buf, "%s", horsename[0] ? horsename : none);
3474. 	else if (!strcmp(optname, "map_mode"))
3475. 		Sprintf(buf, "%s",
3476. 			iflags.wc_map_mode == MAP_MODE_TILES      ? "tiles" :
3477. 			iflags.wc_map_mode == MAP_MODE_ASCII4x6   ? "ascii4x6" :
3478. 			iflags.wc_map_mode == MAP_MODE_ASCII6x8   ? "ascii6x8" :
3479. 			iflags.wc_map_mode == MAP_MODE_ASCII8x8   ? "ascii8x8" :
3480. 			iflags.wc_map_mode == MAP_MODE_ASCII16x8  ? "ascii16x8" :
3481. 			iflags.wc_map_mode == MAP_MODE_ASCII7x12  ? "ascii7x12" :
3482. 			iflags.wc_map_mode == MAP_MODE_ASCII8x12  ? "ascii8x12" :
3483. 			iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" :
3484. 			iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" :
3485. 			iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" :
3486. 			iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ?
3487. 			"fit_to_screen" : defopt);
3488. 	else if (!strcmp(optname, "menustyle")) 
3489. 		Sprintf(buf, "%s", menutype[(int)flags.menu_style] );
3490. 	else if (!strcmp(optname, "menu_deselect_all"))
3491. 		Sprintf(buf, "%s", to_be_done);
3492. 	else if (!strcmp(optname, "menu_deselect_page"))
3493. 		Sprintf(buf, "%s", to_be_done);
3494. 	else if (!strcmp(optname, "menu_first_page"))
3495. 		Sprintf(buf, "%s", to_be_done);
3496. 	else if (!strcmp(optname, "menu_invert_all"))
3497. 		Sprintf(buf, "%s", to_be_done);
3498. 	else if (!strcmp(optname, "menu_headings")) {
3499. 		Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ?
3500. 			"bold" :   (iflags.menu_headings == ATR_INVERSE) ?
3501. 			"inverse" :   (iflags.menu_headings == ATR_ULINE) ?
3502. 			"underline" : "unknown");
3503. 	}
3504. 	else if (!strcmp(optname, "menu_invert_page"))
3505. 		Sprintf(buf, "%s", to_be_done);
3506. 	else if (!strcmp(optname, "menu_last_page"))
3507. 		Sprintf(buf, "%s", to_be_done);
3508. 	else if (!strcmp(optname, "menu_next_page"))
3509. 		Sprintf(buf, "%s", to_be_done);
3510. 	else if (!strcmp(optname, "menu_previous_page"))
3511. 		Sprintf(buf, "%s", to_be_done);
3512. 	else if (!strcmp(optname, "menu_search"))
3513. 		Sprintf(buf, "%s", to_be_done);
3514. 	else if (!strcmp(optname, "menu_select_all"))
3515. 		Sprintf(buf, "%s", to_be_done);
3516. 	else if (!strcmp(optname, "menu_select_page"))
3517. 		Sprintf(buf, "%s", to_be_done);
3518. 	else if (!strcmp(optname, "monsters"))
3519. 		Sprintf(buf, "%s", to_be_done);
3520. 	else if (!strcmp(optname, "msghistory"))
3521. 		Sprintf(buf, "%u", iflags.msg_history);
3522. #ifdef TTY_GRAPHICS
3523. 	else if (!strcmp(optname, "msg_window"))
3524. 		Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
3525. 					(iflags.prevmsg_window=='c') ? "combination" :
3526. 					(iflags.prevmsg_window=='f') ? "full" : "reversed");
3527. #endif
3528. 	else if (!strcmp(optname, "name"))
3529. 		Sprintf(buf, "%s", plname);
3530. 	else if (!strcmp(optname, "number_pad"))
3531. 		Sprintf(buf, "%s",
3532. 			(!iflags.num_pad) ? "0=off" :
3533. 			(iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on");
3534. 	else if (!strcmp(optname, "objects"))
3535. 		Sprintf(buf, "%s", to_be_done);
3536. 	else if (!strcmp(optname, "packorder")) {
3537. 		oc_to_str(flags.inv_order, ocl);
3538. 		Sprintf(buf, "%s", ocl);
3539. 	     }
3540. #ifdef CHANGE_COLOR
3541. 	else if (!strcmp(optname, "palette")) 
3542. 		Sprintf(buf, "%s", get_color_string());
3543. #endif
3544. 	else if (!strcmp(optname, "pettype")) 
3545. 		Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" :
3546. 				(preferred_pet == 'd') ? "dog" :
3547. 				(preferred_pet == 'n') ? "none" : "random");
3548. 	else if (!strcmp(optname, "pickup_burden"))
3549. 		Sprintf(buf, "%s", burdentype[flags.pickup_burden] );
3550. 	else if (!strcmp(optname, "pickup_types")) {
3551. 		oc_to_str(flags.pickup_types, ocl);
3552. 		Sprintf(buf, "%s", ocl[0] ? ocl : "all" );
3553. 	     }
3554. 	else if (!strcmp(optname, "race"))
3555. 		Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
3556. 	else if (!strcmp(optname, "role"))
3557. 		Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
3558. 	else if (!strcmp(optname, "runmode"))
3559. 		Sprintf(buf, "%s", runmodes[iflags.runmode]);
3560. 	else if (!strcmp(optname, "scores")) {
3561. 		Sprintf(buf, "%d top/%d around%s", flags.end_top,
3562. 				flags.end_around, flags.end_own ? "/own" : "");
3563. 	}
3564. 	else if (!strcmp(optname, "scroll_amount")) {
3565. 		if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
3566. 		else Strcpy(buf, defopt);
3567. 	}
3568. 	else if (!strcmp(optname, "scroll_margin")) {
3569. 		if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
3570. 		else Strcpy(buf, defopt);
3571. 	}
3572. 	else if (!strcmp(optname, "player_selection"))
3573. 		Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
3574. #ifdef MSDOS
3575. 	else if (!strcmp(optname, "soundcard"))
3576. 		Sprintf(buf, "%s", to_be_done);
3577. #endif
3578. 	else if (!strcmp(optname, "suppress_alert")) {
3579. 	    if (flags.suppress_alert == 0L)
3580. 		Strcpy(buf, none);
3581. 	    else
3582. 		Sprintf(buf, "%lu.%lu.%lu",
3583. 			FEATURE_NOTICE_VER_MAJ,
3584. 			FEATURE_NOTICE_VER_MIN,
3585. 			FEATURE_NOTICE_VER_PATCH);
3586. 	}
3587. 	else if (!strcmp(optname, "tile_file"))
3588. 		Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
3589. 	else if (!strcmp(optname, "tile_height")) {
3590. 		if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height);
3591. 		else Strcpy(buf, defopt);
3592. 	}
3593. 	else if (!strcmp(optname, "tile_width")) {
3594. 		if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width);
3595. 		else Strcpy(buf, defopt);
3596. 	}
3597. 	else if (!strcmp(optname, "tileset")) 
3598. 		Sprintf(buf, "%s", tileset[0] ? tileset : none );
3599. 	else if (!strcmp(optname, "traps"))
3600. 		Sprintf(buf, "%s", to_be_done);
3601. 	else if (!strcmp(optname, "vary_msgcount")) {
3602. 		if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount);
3603. 		else Strcpy(buf, defopt);
3604. 	}
3605. #ifdef MSDOS
3606. 	else if (!strcmp(optname, "video"))
3607. 		Sprintf(buf, "%s", to_be_done);
3608. #endif
3609. #ifdef VIDEOSHADES
3610. # ifdef MSDOS
3611. 	else if (!strcmp(optname, "videoshades"))
3612. 		Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]);
3613. 	else if (!strcmp(optname, "videocolors"))
3614. 		Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
3615. 			ttycolors[CLR_RED], ttycolors[CLR_GREEN],
3616. 			ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
3617. 			ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
3618. 			ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
3619. 			ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
3620. 			ttycolors[CLR_BRIGHT_MAGENTA],
3621. 			ttycolors[CLR_BRIGHT_CYAN]);
3622. # else
3623. 	else if (!strcmp(optname, "videocolors"))
3624. 		Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
3625. 			ttycolors[CLR_RED], ttycolors[CLR_GREEN],
3626. 			ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
3627. 			ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN], 
3628. 			ttycolors[CLR_GRAY], ttycolors[CLR_BLACK],
3629. 			ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
3630. 			ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
3631. 			ttycolors[CLR_BRIGHT_MAGENTA], 
3632. 			ttycolors[CLR_BRIGHT_CYAN], ttycolors[CLR_WHITE]);
3633. # endif /* MSDOS */
3634. #endif /* VIDEOSHADES */
3635. 	else if (!strcmp(optname, "windowtype"))
3636. 		Sprintf(buf, "%s", windowprocs.name);
3637. 	else if (!strcmp(optname, "windowcolors"))
3638. 		Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s",
3639. 			iflags.wc_foregrnd_menu    ? iflags.wc_foregrnd_menu : defbrief,
3640. 			iflags.wc_backgrnd_menu    ? iflags.wc_backgrnd_menu : defbrief,
3641. 			iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief,
3642. 			iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief,
3643. 			iflags.wc_foregrnd_status  ? iflags.wc_foregrnd_status : defbrief,
3644. 			iflags.wc_backgrnd_status  ? iflags.wc_backgrnd_status : defbrief,
3645. 			iflags.wc_foregrnd_text    ? iflags.wc_foregrnd_text : defbrief,
3646. 			iflags.wc_backgrnd_text    ? iflags.wc_backgrnd_text : defbrief);
3647. 	else if (!strcmp(optname, "wolfname")) 
3648. 		Sprintf(buf, "%s", wolfname[0] ? wolfname : none );
3649. #ifdef PREFIXES_IN_USE
3650. 	else {
3651. 	    for (i = 0; i < PREFIX_COUNT; ++i)
3652. 		if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
3653. 			Sprintf(buf, "%s", fqn_prefix[i]);
3654. 	}
3655. #endif
3656. 
3657. 	if (buf[0]) return buf;
3658. 	else return "unknown";
3659. }
3660. 
3661. int
3662. dotogglepickup()
3663. {
3664. 	char buf[BUFSZ], ocl[MAXOCLASSES+1];
3665. 
3666. 	flags.pickup = !flags.pickup;
3667. 	if (flags.pickup) {
3668. 	    oc_to_str(flags.pickup_types, ocl);
3669. 	    Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
3670. #ifdef AUTOPICKUP_EXCEPTIONS
3671. 			(iflags.autopickup_exceptions[AP_LEAVE] ||
3672. 			 iflags.autopickup_exceptions[AP_GRAB]) ?
3673. 			 ((count_ape_maps((int *)0, (int *)0) == 1) ?
3674. 			    ", with one exception" : ", with some exceptions") :
3675. #endif
3676. 			"");
3677. 	} else {
3678. 	    Strcpy(buf, "OFF");
3679. 	}
3680. 	pline("Autopickup: %s.", buf);
3681. 	return 0;
3682. }
3683. 
3684. #ifdef AUTOPICKUP_EXCEPTIONS
3685. int
3686. add_autopickup_exception(mapping)
3687. const char *mapping;
3688. {
3689. 	struct autopickup_exception *ape, **apehead;
3690. 	char text[256], *text2;
3691. 	int textsize = 0;
3692. 	boolean grab = FALSE;
3693. 
3694. 	if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
3695. 		text2 = &text[0];
3696. 		if (*text2 == '<') {		/* force autopickup */
3697. 			grab = TRUE;
3698. 			++text2;
3699. 		} else if (*text2 == '>') {	/* default - Do not pickup */
3700. 			grab = FALSE;
3701. 			++text2;
3702. 		}
3703. 		textsize = strlen(text2);
3704. 		apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] :
3705. 				   &iflags.autopickup_exceptions[AP_LEAVE];
3706. 		ape = (struct autopickup_exception *)
3707. 				alloc(sizeof(struct autopickup_exception));
3708. 		ape->pattern = (char *) alloc(textsize+1);
3709. 		Strcpy(ape->pattern, text2);
3710. 		ape->grab = grab;
3711. 		if (!*apehead) ape->next = (struct autopickup_exception *)0;
3712. 		else ape->next = *apehead;
3713. 		*apehead = ape;
3714. 	} else {
3715. 	    raw_print("syntax error in AUTOPICKUP_EXCEPTION");
3716. 	    return 0;
3717. 	}
3718. 	return 1;
3719. }
3720. 
3721. STATIC_OVL void
3722. remove_autopickup_exception(whichape)
3723. struct autopickup_exception *whichape;
3724. {
3725.     struct autopickup_exception *ape, *prev = 0;
3726.     int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
3727. 
3728.     for (ape = iflags.autopickup_exceptions[chain]; ape;) {
3729. 	if (ape == whichape) {
3730. 	    struct autopickup_exception *freeape = ape;
3731. 	    ape = ape->next;
3732. 	    if (prev) prev->next = ape;
3733. 	    else iflags.autopickup_exceptions[chain] = ape;
3734. 	    free(freeape->pattern);
3735. 	    free(freeape);
3736. 	} else {
3737. 	    prev = ape;
3738. 	    ape = ape->next;
3739. 	}
3740.     }
3741. }
3742. 
3743. STATIC_OVL int
3744. count_ape_maps(leave, grab)
3745. int *leave, *grab;
3746. {
3747. 	struct autopickup_exception *ape;
3748. 	int pass, totalapes, numapes[2] = {0,0};
3749. 
3750. 	for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
3751. 		ape = iflags.autopickup_exceptions[pass];
3752. 		while(ape) {
3753. 			ape = ape->next;
3754. 			numapes[pass]++;
3755. 		}
3756. 	}
3757. 	totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
3758. 	if (leave) *leave = numapes[AP_LEAVE];
3759. 	if (grab) *grab = numapes[AP_GRAB];
3760. 	return totalapes;
3761. }
3762. 
3763. void
3764. free_autopickup_exceptions()
3765. {
3766. 	struct autopickup_exception *ape;
3767. 	int pass;
3768. 
3769. 	for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
3770. 		while((ape = iflags.autopickup_exceptions[pass]) != 0) {
3771. 			free(ape->pattern);
3772. 			iflags.autopickup_exceptions[pass] = ape->next;
3773. 			free(ape);
3774. 		}
3775. 	}
3776. }
3777. #endif /* AUTOPICKUP_EXCEPTIONS */
3778. 
3779. /* data for option_help() */
3780. static const char *opt_intro[] = {
3781. 	"",
3782. 	"                 SlashEM Options Help:",
3783. 	"",
3784. #define CONFIG_SLOT 3	/* fill in next value at run-time */
3785. 	(char *)0,
3786. #define ENV_SLOT 4	/* substitute variable name in next value at run-time */
3787. #if !defined(MICRO) && !defined(MAC)
3788. 	"or use `%s=\"<options>\"' in your environment",
3789. #endif
3790. 	"(<options> is a list of options separated by commas)",
3791. #ifdef VMS
3792.   	"-- for example, $ DEFINE %s \"noautopickup,fruit:kumquat\"",
3793. #endif
3794. 	"or press \"O\" while playing and use the menu.",
3795. 	"",
3796.  "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
3797. 	(char *)0
3798. };
3799. 
3800. static const char *opt_epilog[] = {
3801. 	"",
3802.  "Some of the options can be set only before the game is started; those",
3803. 	"items will not be selectable in the 'O' command's menu.",
3804. 	(char *)0
3805. };
3806. 
3807. void
3808. option_help()
3809. {
3810.     char buf[BUFSZ], buf2[BUFSZ];
3811.     register int i;
3812.     winid datawin;
3813. 
3814.     datawin = create_nhwindow(NHW_TEXT);
3815.     Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
3816.     opt_intro[CONFIG_SLOT] = (const char *) buf;
3817.     for (i = 0; opt_intro[i]; i++)
3818. 	if (i==ENV_SLOT)
3819. 	{
3820. 	    Sprintf(buf2, opt_intro[ENV_SLOT], NETHACK_ENV_OPTIONS);
3821. 	    putstr(datawin, 0, buf2);;
3822. 	}
3823. 	else
3824. 	putstr(datawin, 0, opt_intro[i]);
3825. 
3826.     /* Boolean options */
3827.     for (i = 0; boolopt[i].name; i++) {
3828. 	if (boolopt[i].addr) {
3829. #ifdef WIZARD
3830. #ifndef OBJ_SANITY
3831. 	    if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue;
3832. #endif
3833. 	    if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue;
3834. #endif
3835. 	    next_opt(datawin, boolopt[i].name);
3836. 	}
3837.     }
3838.     next_opt(datawin, "");
3839. 
3840.     /* Compound options */
3841.     putstr(datawin, 0, "Compound options:");
3842.     for (i = 0; compopt[i].name; i++) {
3843. 	Sprintf(buf2, "`%s'", compopt[i].name);
3844. 	Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
3845. 		compopt[i+1].name ? ',' : '.');
3846. 	putstr(datawin, 0, buf);
3847.     }
3848. 
3849.     for (i = 0; opt_epilog[i]; i++)
3850. 	putstr(datawin, 0, opt_epilog[i]);
3851. 
3852.     display_nhwindow(datawin, FALSE);
3853.     destroy_nhwindow(datawin);
3854.     return;
3855. }
3856. 
3857. /*
3858.  * prints the next boolean option, on the same line if possible, on a new
3859.  * line if not. End with next_opt("").
3860.  */
3861. void
3862. next_opt(datawin, str)
3863. winid datawin;
3864. const char *str;
3865. {
3866. 	static char *buf = 0;
3867. 	int i;
3868. 	char *s;
3869. 
3870. 	if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0';
3871. 
3872. 	if (!*str) {
3873. 		s = eos(buf);
3874. 		if (s > &buf[1] && s[-2] == ',')
3875. 		    Strcpy(s - 2, ".");	/* replace last ", " */
3876. 		i = COLNO;	/* (greater than COLNO - 2) */
3877. 	} else {
3878. 		i = strlen(buf) + strlen(str) + 2;
3879. 	}
3880. 
3881. 	if (i > COLNO - 2) { /* rule of thumb */
3882. 		putstr(datawin, 0, buf);
3883. 		buf[0] = 0;
3884. 	}
3885. 	if (*str) {
3886. 		Strcat(buf, str);
3887. 		Strcat(buf, ", ");
3888. 	} else {
3889. 		putstr(datawin, 0, str);
3890. 		free(buf),  buf = 0;
3891. 	}
3892. 	return;
3893. }
3894. 
3895. /* Returns the fid of the fruit type; if that type already exists, it
3896.  * returns the fid of that one; if it does not exist, it adds a new fruit
3897.  * type to the chain and returns the new one.
3898.  */
3899. int
3900. fruitadd(str)
3901. char *str;
3902. {
3903. 	register int i;
3904. 	register struct fruit *f;
3905. 	struct fruit *lastf = 0;
3906. 	int highest_fruit_id = 0;
3907. 	char buf[PL_FSIZ];
3908. 	boolean user_specified = (str == pl_fruit);
3909. 	/* if not user-specified, then it's a fruit name for a fruit on
3910. 	 * a bones level...
3911. 	 */
3912. 
3913. 	/* Note: every fruit has an id (spe for fruit objects) of at least
3914. 	 * 1; 0 is an error.
3915. 	 */
3916. 	if (user_specified) {
3917. 		/* disallow naming after other foods (since it'd be impossible
3918. 		 * to tell the difference)
3919. 		 */
3920. 
3921. 		boolean found = FALSE, numeric = FALSE;
3922. 
3923. 		for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;
3924. 						i++) {
3925. 			if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
3926. 				found = TRUE;
3927. 				break;
3928. 			}
3929. 		}
3930. 		{
3931. 		    char *c;
3932. 
3933. 		    c = pl_fruit;
3934. 
3935. 		    for(c = pl_fruit; *c >= '0' && *c <= '9'; c++)
3936. 			;
3937. 		    if (isspace(*c) || *c == 0) numeric = TRUE;
3938. 		}
3939. 		if (found || numeric ||
3940. 		    !strncmp(str, "cursed ", 7) ||
3941. 		    !strncmp(str, "uncursed ", 9) ||
3942. 		    !strncmp(str, "blessed ", 8) ||
3943. 		    !strncmp(str, "partly eaten ", 13) ||
3944. 		    (!strncmp(str, "tin of ", 7) &&
3945. 			(!strcmp(str+7, "spinach") ||
3946. 			 name_to_mon(str+7) >= LOW_PM)) ||
3947. 		    !strcmp(str, "empty tin") ||
3948. 		    ((!strncmp(eos(str)-7," corpse",7) ||
3949. 			    !strncmp(eos(str)-4, " egg",4)) &&
3950. 			name_to_mon(str) >= LOW_PM))
3951. 			{
3952. 				Strcpy(buf, pl_fruit);
3953. 				Strcpy(pl_fruit, "candied ");
3954. 				nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
3955. 		}
3956. 	}
3957. 	for(f=ffruit; f; f = f->nextf) {
3958. 		lastf = f;
3959. 		if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
3960. 		if(!strncmp(str, f->fname, PL_FSIZ))
3961. 			goto nonew;
3962. 	}
3963. 	/* if adding another fruit would overflow spe, use a random
3964. 	   fruit instead... we've got a lot to choose from. */
3965. 	if (highest_fruit_id >= 127) return rnd(127);
3966. 	highest_fruit_id++;
3967. 	f = newfruit();
3968. 	if (ffruit) lastf->nextf = f;
3969. 	else ffruit = f;
3970. 	Strcpy(f->fname, str);
3971. 	f->fid = highest_fruit_id;
3972. 	f->nextf = 0;
3973. nonew:
3974. 	if (user_specified) current_fruit = highest_fruit_id;
3975. 	return f->fid;
3976. }
3977. 
3978. /*
3979.  * This is a somewhat generic menu for taking a list of NetHack style
3980.  * class choices and presenting them via a description
3981.  * rather than the traditional NetHack characters.
3982.  * (Benefits users whose first exposure to NetHack is via tiles).
3983.  *
3984.  * prompt
3985.  *	     The title at the top of the menu.
3986.  *
3987.  * category: 0 = monster class
3988.  *           1 = object  class
3989.  *
3990.  * way
3991.  *	     FALSE = PICK_ONE, TRUE = PICK_ANY
3992.  *
3993.  * class_list
3994.  *	     a null terminated string containing the list of choices.
3995.  *
3996.  * class_selection
3997.  *	     a null terminated string containing the selected characters.
3998.  *
3999.  * Returns number selected.
4000.  */
4001. int
4002. choose_classes_menu(prompt, category, way, class_list, class_select)
4003. const char *prompt;
4004. int category;
4005. boolean way;
4006. char *class_list;
4007. char *class_select;
4008. {
4009.     menu_item *pick_list = (menu_item *)0;
4010.     winid win;
4011.     anything any;
4012.     char buf[BUFSZ];
4013.     int i, n;
4014.     int ret;
4015.     int next_accelerator, accelerator;
4016. 
4017.     if (class_list == (char *)0 || class_select == (char *)0) return 0;
4018.     accelerator = 0;
4019.     next_accelerator = 'a';
4020.     any.a_void = 0;
4021.     win = create_nhwindow(NHW_MENU);
4022.     start_menu(win);
4023.     while (*class_list) {
4024. 	const char *text;
4025. 	boolean selected;
4026. 
4027. 	text = (char *)0;
4028. 	selected = FALSE;
4029. 	switch (category) {
4030. 		case 0:
4031. 			text = monexplain[def_char_to_monclass(*class_list)];
4032. 			accelerator = *class_list;
4033. 			Sprintf(buf, "%s", text);
4034. 			break;
4035. 		case 1:
4036. 			text = objexplain[def_char_to_objclass(*class_list)];
4037. 			accelerator = next_accelerator;
4038. 			Sprintf(buf, "%c  %s", *class_list, text);
4039. 			break;
4040. 		default:
4041. 			impossible("choose_classes_menu: invalid category %d",
4042. 					category);
4043. 	}
4044. 	if (way && *class_select) {	/* Selections there already */
4045. 		if (index(class_select, *class_list)) {
4046. 			selected = TRUE;
4047. 		}
4048. 	}
4049. 	any.a_int = *class_list;
4050. 	add_menu(win, NO_GLYPH, &any, accelerator,
4051. 		  category ? *class_list : 0,
4052. 		  ATR_NONE, buf, selected);
4053. 	++class_list;
4054. 	if (category > 0) {
4055. 		++next_accelerator;
4056. 		if (next_accelerator == ('z' + 1)) next_accelerator = 'A';
4057. 		if (next_accelerator == ('Z' + 1)) break;
4058. 	}
4059.     }
4060.     end_menu(win, prompt);
4061.     n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
4062.     destroy_nhwindow(win);
4063.     if (n > 0) {
4064. 	for (i = 0; i < n; ++i)
4065. 	    *class_select++ = (char)pick_list[i].item.a_int;
4066. 	free((genericptr_t)pick_list);
4067. 	ret = n;
4068.     } else if (n == -1) {
4069. 	class_select = eos(class_select);
4070. 	ret = -1;
4071.     } else
4072. 	ret = 0;
4073.     *class_select = '\0';
4074.     return ret;
4075. }
4076. 
4077. struct wc_Opt wc_options[] = {
4078. 	{"ascii_map", WC_ASCII_MAP},
4079. 	{"color", WC_COLOR},
4080. 	{"eight_bit_tty", WC_EIGHT_BIT_IN},
4081. 	{"hilite_pet", WC_HILITE_PET},
4082. 	{"popup_dialog", WC_POPUP_DIALOG},
4083. 	{"player_selection", WC_PLAYER_SELECTION},
4084. 	{"preload_tiles", WC_PRELOAD_TILES},
4085. 	{"tiled_map", WC_TILED_MAP},
4086. 	{"tile_file", WC_TILE_FILE},
4087. 	{"tile_width", WC_TILE_WIDTH},
4088. 	{"tile_height", WC_TILE_HEIGHT},
4089. 	{"use_inverse", WC_INVERSE},
4090. 	{"align_message", WC_ALIGN_MESSAGE},
4091. 	{"align_status", WC_ALIGN_STATUS},
4092. 	{"font_map", WC_FONT_MAP},
4093. 	{"font_menu", WC_FONT_MENU},
4094. 	{"font_message",WC_FONT_MESSAGE},
4095. #if 0
4096. 	{"perm_invent",WC_PERM_INVENT},
4097. #endif
4098. 	{"font_size_map", WC_FONTSIZ_MAP},
4099. 	{"font_size_menu", WC_FONTSIZ_MENU},
4100. 	{"font_size_message", WC_FONTSIZ_MESSAGE},
4101. 	{"font_size_status", WC_FONTSIZ_STATUS},
4102. 	{"font_size_text", WC_FONTSIZ_TEXT},
4103. 	{"font_status", WC_FONT_STATUS},
4104. 	{"font_text", WC_FONT_TEXT},
4105. 	{"map_mode", WC_MAP_MODE},
4106. 	{"scroll_amount", WC_SCROLL_AMOUNT},
4107. 	{"scroll_margin", WC_SCROLL_MARGIN},
4108. 	{"splash_screen", WC_SPLASH_SCREEN},
4109. 	{"vary_msgcount",WC_VARY_MSGCOUNT},
4110. 	{"windowcolors", WC_WINDOWCOLORS},
4111. 	{"mouse_support", WC_MOUSE_SUPPORT},
4112. 	{(char *)0, 0L}
4113. };
4114. 
4115. struct wc_Opt wc2_options[] = {
4116. 	{"fullscreen", WC2_FULLSCREEN},
4117. 	{"softkeyboard", WC2_SOFTKEYBOARD},
4118. 	{"wraptext", WC2_WRAPTEXT},
4119. 	{(char *)0, 0L}
4120. };
4121. 
4122. 
4123. /*
4124.  * If a port wants to change or ensure that the
4125.  * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
4126.  * correct (for controlling its display in the option menu) call
4127.  * set_option_mod_status()
4128.  * with the second argument of 0,2, or 3 respectively.
4129.  */
4130. void
4131. set_option_mod_status(optnam, status)
4132. const char *optnam;
4133. int status;
4134. {
4135. 	int k;
4136. 	if (status < SET_IN_FILE || status > SET_IN_GAME) {
4137. 		impossible("set_option_mod_status: status out of range %d.",
4138. 			   status);
4139. 		return;
4140. 	}
4141. 	for (k = 0; boolopt[k].name; k++) {
4142. 		if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
4143. 			boolopt[k].optflags = status;
4144. 			return;
4145. 		}
4146. 	}
4147. 	for (k = 0; compopt[k].name; k++) {
4148. 		if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
4149. 			compopt[k].optflags = status;
4150. 			return;
4151. 		}
4152. 	}
4153. }
4154. 
4155. /*
4156.  * You can set several wc_options in one call to
4157.  * set_wc_option_mod_status() by setting
4158.  * the appropriate bits for each option that you
4159.  * are setting in the optmask argument
4160.  * prior to calling.
4161.  *    example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME);
4162.  */
4163. void
4164. set_wc_option_mod_status(optmask, status)
4165. unsigned long optmask;
4166. int status;
4167. {
4168. 	int k = 0;
4169. 	if (status < SET_IN_FILE || status > SET_IN_GAME) {
4170. 		impossible("set_wc_option_mod_status: status out of range %d.",
4171. 			   status);
4172. 		return;
4173. 	}
4174. 	while (wc_options[k].wc_name) {
4175. 		if (optmask & wc_options[k].wc_bit) {
4176. 			set_option_mod_status(wc_options[k].wc_name, status);
4177. 		}
4178. 		k++;
4179. 	}
4180. }
4181. 
4182. STATIC_OVL boolean
4183. is_wc_option(optnam)
4184. const char *optnam;
4185. {
4186. 	int k = 0;
4187. 	while (wc_options[k].wc_name) {
4188. 		if (strcmp(wc_options[k].wc_name, optnam) == 0)
4189. 			return TRUE;
4190. 		k++;
4191. 	}
4192. 	return FALSE;
4193. }
4194. 
4195. STATIC_OVL boolean
4196. wc_supported(optnam)
4197. const char *optnam;
4198. {
4199. 	int k = 0;
4200. 	while (wc_options[k].wc_name) {
4201. 		if (!strcmp(wc_options[k].wc_name, optnam) &&
4202. 		    (windowprocs.wincap & wc_options[k].wc_bit))
4203. 			return TRUE;
4204. 		k++;
4205. 	}
4206. 	return FALSE;
4207. }
4208. 
4209. 
4210. /*
4211.  * You can set several wc2_options in one call to
4212.  * set_wc2_option_mod_status() by setting
4213.  * the appropriate bits for each option that you
4214.  * are setting in the optmask argument
4215.  * prior to calling.
4216.  *    example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE);
4217.  */
4218. 
4219. void
4220. set_wc2_option_mod_status(optmask, status)
4221. unsigned long optmask;
4222. int status;
4223. {
4224. 	int k = 0;
4225. 	if (status < SET_IN_FILE || status > SET_IN_GAME) {
4226. 		impossible("set_wc2_option_mod_status: status out of range %d.",
4227. 			   status);
4228. 		return;
4229. 	}
4230. 	while (wc2_options[k].wc_name) {
4231. 		if (optmask & wc2_options[k].wc_bit) {
4232. 			set_option_mod_status(wc2_options[k].wc_name, status);
4233. 		}
4234. 		k++;
4235. 	}
4236. }
4237. 
4238. STATIC_OVL boolean
4239. is_wc2_option(optnam)
4240. const char *optnam;
4241. {
4242. 	int k = 0;
4243. 	while (wc2_options[k].wc_name) {
4244. 		if (strcmp(wc2_options[k].wc_name, optnam) == 0)
4245. 			return TRUE;
4246. 		k++;
4247. 	}
4248. 	return FALSE;
4249. }
4250. 
4251. STATIC_OVL boolean
4252. wc2_supported(optnam)
4253. const char *optnam;
4254. {
4255. 	int k = 0;
4256. 	while (wc2_options[k].wc_name) {
4257. 		if (!strcmp(wc2_options[k].wc_name, optnam) &&
4258. 		    (windowprocs.wincap2 & wc2_options[k].wc_bit))
4259. 			return TRUE;
4260. 		k++;
4261. 	}
4262. 	return FALSE;
4263. }
4264. 
4265. 
4266. STATIC_OVL void
4267. wc_set_font_name(wtype, fontname)
4268. int wtype;
4269. char *fontname;
4270. {
4271. 	char **fn = (char **)0;
4272. 	if (!fontname) return;
4273. 	switch(wtype) {
4274. 	    case NHW_MAP:
4275. 	    		fn = &iflags.wc_font_map;
4276. 			break;
4277. 	    case NHW_MESSAGE:
4278. 	    		fn = &iflags.wc_font_message;
4279. 			break;
4280. 	    case NHW_TEXT:
4281. 	    		fn = &iflags.wc_font_text;
4282. 			break;
4283. 	    case NHW_MENU:
4284. 	    		fn = &iflags.wc_font_menu;
4285. 			break;
4286. 	    case NHW_STATUS:
4287. 	    		fn = &iflags.wc_font_status;
4288. 			break;
4289. 	    default:
4290. 	    		return;
4291. 	}
4292. 	if (fn) {
4293. 		if (*fn) free(*fn);
4294. 		*fn = (char *)alloc(strlen(fontname) + 1);
4295. 		Strcpy(*fn, fontname);
4296. 	}
4297. 	return;
4298. }
4299. 
4300. STATIC_OVL int
4301. wc_set_window_colors(op)
4302. char *op;
4303. {
4304. 	/* syntax:
4305. 	 *  menu white/black message green/yellow status white/blue text white/black
4306. 	 */
4307. 
4308. 	int j;
4309. 	char buf[BUFSZ];
4310. 	char *wn, *tfg, *tbg, *newop;
4311. 	static const char *wnames[] = { "menu", "message", "status", "text" };
4312. 	static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
4313. 	static char **fgp[] = {
4314. 		&iflags.wc_foregrnd_menu,
4315. 		&iflags.wc_foregrnd_message,
4316. 		&iflags.wc_foregrnd_status,
4317. 		&iflags.wc_foregrnd_text
4318. 	};
4319. 	static char **bgp[] = {
4320. 		&iflags.wc_backgrnd_menu,
4321. 		&iflags.wc_backgrnd_message,
4322. 		&iflags.wc_backgrnd_status,
4323. 		&iflags.wc_backgrnd_text
4324. 	};
4325. 
4326. 	Strcpy(buf, op);
4327. 	newop = mungspaces(buf);
4328. 	while (newop && *newop) {
4329. 
4330. 		wn = tfg = tbg = (char *)0;
4331. 
4332. 		/* until first non-space in case there's leading spaces - before colorname*/
4333. 		while(*newop && isspace(*newop)) newop++;
4334. 		if (*newop) wn = newop;
4335. 		else return 0;
4336. 
4337. 		/* until first space - colorname*/
4338. 		while(*newop && !isspace(*newop)) newop++;
4339. 		if (*newop) *newop = '\0';
4340. 		else return 0;
4341. 		newop++;
4342. 
4343. 		/* until first non-space - before foreground*/
4344. 		while(*newop && isspace(*newop)) newop++;
4345. 		if (*newop) tfg = newop;
4346. 		else return 0;
4347. 
4348. 		/* until slash - foreground */
4349. 		while(*newop && *newop != '/') newop++;
4350. 		if (*newop) *newop = '\0';
4351. 		else return 0;
4352. 		newop++;
4353. 
4354. 		/* until first non-space (in case there's leading space after slash) - before background */
4355. 		while(*newop && isspace(*newop)) newop++;
4356. 		if (*newop) tbg = newop;
4357. 		else return 0;
4358. 
4359. 		/* until first space - background */
4360. 		while(*newop && !isspace(*newop)) newop++;
4361. 		if (*newop) *newop++ = '\0';
4362. 
4363. 		for (j = 0; j < 4; ++j) {
4364. 			if (!strcmpi(wn, wnames[j]) ||
4365. 			    !strcmpi(wn, shortnames[j])) {
4366. 				if (tfg && !strstri(tfg, " ")) {
4367. 					if (*fgp[j]) free(*fgp[j]);
4368. 					*fgp[j] = (char *)alloc(strlen(tfg) + 1);
4369. 					Strcpy(*fgp[j], tfg);
4370. 				}
4371. 				if (tbg && !strstri(tbg, " ")) {
4372. 					if (*bgp[j]) free(*bgp[j]);
4373. 					*bgp[j] = (char *)alloc(strlen(tbg) + 1);
4374. 					Strcpy(*bgp[j], tbg);
4375. 				}
4376.  				break;
4377. 			}
4378. 		}
4379. 	}
4380. 	return 1;
4381. }
4382. 
4383. #endif	/* OPTION_LISTS_ONLY */
4384. /*options.c*/