OSDN Git Service

patch artifact
[jnethack/source.git] / src / options.c
1 /* NetHack 3.6  options.c       $NHDT-Date: 1448241657 2015/11/23 01:20:57 $  $NHDT-Branch: master $:$NHDT-Revision: 1.243 $ */
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 #ifdef SYSFLAGS
11 NEARDATA struct sysflag sysflags; /* provide linkage */
12 #endif
13 NEARDATA struct instance_flags iflags; /* provide linkage */
14 #define static
15 #else
16 #include "hack.h"
17 #include "tcap.h"
18 #include <ctype.h>
19 #endif
20
21 #define BACKWARD_COMPAT
22 #define WINTYPELEN 16
23
24 #ifdef DEFAULT_WC_TILED_MAP
25 #define PREFER_TILED TRUE
26 #else
27 #define PREFER_TILED FALSE
28 #endif
29
30 #define MESSAGE_OPTION 1
31 #define STATUS_OPTION 2
32 #define MAP_OPTION 3
33 #define MENU_OPTION 4
34 #define TEXT_OPTION 5
35
36 #define PILE_LIMIT_DFLT 5
37
38 /*
39  *  NOTE:  If you add (or delete) an option, please update the short
40  *  options help (option_help()), the long options help (dat/opthelp),
41  *  and the current options setting display function (doset()),
42  *  and also the Guidebooks.
43  *
44  *  The order matters.  If an option is a an initial substring of another
45  *  option (e.g. time and timed_delay) the shorter one must come first.
46  */
47
48 static struct Bool_Opt {
49     const char *name;
50     boolean *addr, initvalue;
51     int optflags;
52 } boolopt[] = {
53     { "acoustics", &flags.acoustics, TRUE, SET_IN_GAME },
54 #if defined(SYSFLAGS) && defined(AMIGA)
55     /* Amiga altmeta causes Alt+key to be converted into Meta+key by
56        low level nethack code; on by default, can be toggled off if
57        Alt+key is needed for some ASCII chars on non-ASCII keyboard */
58     { "altmeta", &sysflags.altmeta, TRUE, DISP_IN_GAME },
59 #else
60 #ifdef ALTMETA
61     /* non-Amiga altmeta causes nethack's top level command loop to treat
62        two character sequence "ESC c" as M-c, for terminals or emulators
63        which send "ESC c" when Alt+c is pressed; off by default, enabling
64        this can potentially make trouble if user types ESC when nethack
65        is honoring this conversion request (primarily after starting a
66        count prefix prior to a command and then deciding to cancel it) */
67     { "altmeta", &iflags.altmeta, FALSE, SET_IN_GAME },
68 #else
69     { "altmeta", (boolean *) 0, TRUE, DISP_IN_GAME },
70 #endif
71 #endif
72     { "ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME }, /*WC*/
73 #if defined(SYSFLAGS) && defined(MFLOPPY)
74     { "asksavedisk", &sysflags.asksavedisk, FALSE, SET_IN_GAME },
75 #else
76     { "asksavedisk", (boolean *) 0, FALSE, SET_IN_FILE },
77 #endif
78     { "autodig", &flags.autodig, FALSE, SET_IN_GAME },
79     { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME },
80     { "autopickup", &flags.pickup, TRUE, SET_IN_GAME },
81     { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME },
82 #if defined(MICRO) && !defined(AMIGA)
83     { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE },
84 #else
85     { "BIOS", (boolean *) 0, FALSE, SET_IN_FILE },
86 #endif
87     { "blind", &u.uroleplay.blind, FALSE, DISP_IN_GAME },
88     { "bones", &flags.bones, TRUE, SET_IN_FILE },
89 #ifdef INSURANCE
90     { "checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME },
91 #else
92     { "checkpoint", (boolean *) 0, FALSE, SET_IN_FILE },
93 #endif
94 #ifdef MFLOPPY
95     { "checkspace", &iflags.checkspace, TRUE, SET_IN_GAME },
96 #else
97     { "checkspace", (boolean *) 0, FALSE, SET_IN_FILE },
98 #endif
99     { "clicklook", &iflags.clicklook, FALSE, SET_IN_GAME },
100     { "cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME },
101 #if defined(MICRO) || defined(WIN32)
102     { "color", &iflags.wc_color, TRUE, SET_IN_GAME }, /*WC*/
103 #else /* systems that support multiple terminals, many monochrome */
104     { "color", &iflags.wc_color, FALSE, SET_IN_GAME }, /*WC*/
105 #endif
106     { "confirm", &flags.confirm, TRUE, SET_IN_GAME },
107     { "dark_room", &flags.dark_room, TRUE, SET_IN_GAME },
108     { "eight_bit_tty", &iflags.wc_eight_bit_input, FALSE,
109       SET_IN_GAME }, /*WC*/
110 #ifdef TTY_GRAPHICS
111     { "extmenu", &iflags.extmenu, FALSE, SET_IN_GAME },
112 #else
113     { "extmenu", (boolean *) 0, FALSE, SET_IN_FILE },
114 #endif
115 #ifdef OPT_DISPMAP
116     { "fast_map", &flags.fast_map, TRUE, SET_IN_GAME },
117 #else
118     { "fast_map", (boolean *) 0, TRUE, SET_IN_FILE },
119 #endif
120     { "female", &flags.female, FALSE, DISP_IN_GAME },
121     { "fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME },
122 #if defined(SYSFLAGS) && defined(AMIFLUSH)
123     { "flush", &sysflags.amiflush, FALSE, SET_IN_GAME },
124 #else
125     { "flush", (boolean *) 0, FALSE, SET_IN_FILE },
126 #endif
127     { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE },
128     { "help", &flags.help, TRUE, SET_IN_GAME },
129     { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/
130     { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME },
131 #ifndef MAC
132     { "ignintr", &flags.ignintr, FALSE, SET_IN_GAME },
133 #else
134     { "ignintr", (boolean *) 0, FALSE, SET_IN_FILE },
135 #endif
136     { "implicit_uncursed", &iflags.implicit_uncursed, TRUE, SET_IN_GAME },
137     { "large_font", &iflags.obsolete, FALSE, SET_IN_FILE }, /* OBSOLETE */
138     { "legacy", &flags.legacy, TRUE, DISP_IN_GAME },
139     { "lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME },
140     { "lootabc", &flags.lootabc, FALSE, SET_IN_GAME },
141 #ifdef MAIL
142     { "mail", &flags.biff, TRUE, SET_IN_GAME },
143 #else
144     { "mail", (boolean *) 0, TRUE, SET_IN_FILE },
145 #endif
146     { "mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME },
147     { "menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME },
148     /* for menu debugging only*/
149     { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME },
150     { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME },
151     { "mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME }, /*WC*/
152 #ifdef NEWS
153     { "news", &iflags.news, TRUE, DISP_IN_GAME },
154 #else
155     { "news", (boolean *) 0, FALSE, SET_IN_FILE },
156 #endif
157     { "nudist", &u.uroleplay.nudist, FALSE, DISP_IN_GAME },
158     { "null", &flags.null, TRUE, SET_IN_GAME },
159 #if defined(SYSFLAGS) && defined(MAC)
160     { "page_wait", &sysflags.page_wait, TRUE, SET_IN_GAME },
161 #else
162     { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE },
163 #endif
164     { "perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME },
165     { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME },
166     { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME },   /*WC*/
167     { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/
168     { "pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME },
169 #if defined(MICRO) && !defined(AMIGA)
170     { "rawio", &iflags.rawio, FALSE, DISP_IN_GAME },
171 #else
172     { "rawio", (boolean *) 0, FALSE, SET_IN_FILE },
173 #endif
174     { "rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME },
175 #ifdef RLECOMP
176     { "rlecomp", &iflags.rlecomp,
177 #if defined(COMPRESS) || defined(ZLIB_COMP)
178       FALSE,
179 #else
180       TRUE,
181 #endif
182       DISP_IN_GAME },
183 #endif
184     { "safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME },
185     { "sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME },
186     { "selectsaved", &iflags.wc2_selectsaved, TRUE, DISP_IN_GAME }, /*WC*/
187     { "showexp", &flags.showexp, FALSE, SET_IN_GAME },
188     { "showrace", &flags.showrace, FALSE, SET_IN_GAME },
189 #ifdef SCORE_ON_BOTL
190     { "showscore", &flags.showscore, FALSE, SET_IN_GAME },
191 #else
192     { "showscore", (boolean *) 0, FALSE, SET_IN_FILE },
193 #endif
194     { "silent", &flags.silent, TRUE, SET_IN_GAME },
195     { "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE },
196     { "sortpack", &flags.sortpack, TRUE, SET_IN_GAME },
197     { "sparkle", &flags.sparkle, TRUE, SET_IN_GAME },
198     { "splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME }, /*WC*/
199     { "standout", &flags.standout, FALSE, SET_IN_GAME },
200 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
201     { "statushilites", &iflags.use_status_hilites, TRUE, SET_IN_GAME },
202 #else
203     { "statushilites", &iflags.use_status_hilites, FALSE, DISP_IN_GAME },
204 #endif
205     { "tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME }, /*WC*/
206     { "time", &flags.time, FALSE, SET_IN_GAME },
207 #ifdef TIMED_DELAY
208     { "timed_delay", &flags.nap, TRUE, SET_IN_GAME },
209 #else
210     { "timed_delay", (boolean *) 0, FALSE, SET_IN_GAME },
211 #endif
212     { "tombstone", &flags.tombstone, TRUE, SET_IN_GAME },
213     { "toptenwin", &iflags.toptenwin, FALSE, SET_IN_GAME },
214     { "travel", &flags.travelcmd, TRUE, SET_IN_GAME },
215     { "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE },
216 #ifdef WIN32
217     { "use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME }, /*WC*/
218 #else
219     { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/
220 #endif
221     { "verbose", &flags.verbose, TRUE, SET_IN_GAME },
222     { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME },
223 #ifdef ZEROCOMP
224     { "zerocomp", &iflags.zerocomp,
225 #if defined(COMPRESS) || defined(ZLIB_COMP)
226       FALSE,
227 #else
228       TRUE,
229 #endif
230       DISP_IN_GAME },
231 #endif
232     { (char *) 0, (boolean *) 0, FALSE, 0 }
233 };
234
235 /* compound options, for option_help() and external programs like Amiga
236  * frontend */
237 static struct Comp_Opt {
238     const char *name, *descr;
239     int size; /* for frontends and such allocating space --
240                * usually allowed size of data in game, but
241                * occasionally maximum reasonable size for
242                * typing when game maintains information in
243                * a different format */
244     int optflags;
245 } compopt[] = {
246 /*JP
247     { "align", "your starting alignment (lawful, neutral, or chaotic)", 8,
248 */
249     { "align",    "\83Q\81[\83\80\83X\83^\81[\83g\8e\9e\82Ì\91®\90« (lawful, neutral, or chaotic\82Ì\82¢\82¸\82ê\82©)", 8,
250       DISP_IN_GAME },
251 #if 0 /*JP*/
252     { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
253 #else
254     { "align_message", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82Ì\91µ\82¦", 20, DISP_IN_GAME }, /*WC*/
255 #endif
256 #if 0 /*JP*/
257     { "align_status", "status window alignment", 20, DISP_IN_GAME },   /*WC*/
258 #else
259     { "align_status", "\8fó\8bµ\83E\83B\83\93\83h\83E\82Ì\91µ\82¦", 20, DISP_IN_GAME }, /*WC*/
260 #endif
261 /*JP
262     { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
263 */
264     { "altkeyhandler", "ALT\83L\81[\83n\83\93\83h\83\89", 20, DISP_IN_GAME },
265 #ifdef BACKWARD_COMPAT
266 /*JP
267     { "boulder", "deprecated (use S_boulder in sym file instead)", 1,
268 */
269     { "boulder",  "\8b\90\8aâ\82ð\95\\8e¦\82·\82é\83V\83\93\83{\83\8b\95\8e\9a", 1,
270       SET_IN_FILE },
271 #endif
272 /*JP
273     { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
274 */
275     { "catname",  "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\94L\82Ì\96¼\91O (\97á catname:\82½\82Ü)",
276       PL_PSIZ, DISP_IN_GAME },
277 /*JP
278     { "disclose", "the kinds of information to disclose at end of game",
279 */
280     { "disclose", "\83Q\81[\83\80\8fI\97¹\8e\9e\82É\8c©\82é\8fî\95ñ\82Ì\8eí\97Þ",
281       sizeof(flags.end_disclose) * 2, SET_IN_GAME },
282 /*JP
283     { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ,
284 */
285     { "dogname",  "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\8c¢\82Ì\96¼\91O (\97á dogname:\83|\83`)", PL_PSIZ,
286       DISP_IN_GAME },
287 /*JP
288     { "dungeon", "the symbols to use in drawing the dungeon map",
289 */
290     { "dungeon",  "\83_\83\93\83W\83\87\83\93\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a",
291       MAXDCHARS + 1, SET_IN_FILE },
292 /*JP
293     { "effects", "the symbols to use in drawing special effects",
294 */
295     { "effects",  "\93Á\8eê\8cø\89Ê\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a",
296       MAXECHARS + 1, SET_IN_FILE },
297 /*JP
298     { "font_map", "the font to use in the map window", 40,
299 */
300     { "font_map", "\83}\83b\83v\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
301       DISP_IN_GAME },                                              /*WC*/
302 #if 0 /*JP*/
303     { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
304 #else
305     { "font_menu", "\83\81\83j\83\85\81[\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40, DISP_IN_GAME }, /*WC*/
306 #endif
307 /*JP
308     { "font_message", "the font to use in the message window", 40,
309 */
310     { "font_message", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
311       DISP_IN_GAME },                                                  /*WC*/
312 #if 0 /*JP*/
313     { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
314 #else
315     { "font_size_map", "\83}\83b\83v\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20, DISP_IN_GAME }, /*WC*/
316 #endif
317 /*JP
318     { "font_size_menu", "the size of the menu font", 20,
319 */
320     { "font_size_menu", "\83\81\83j\83\85\81[\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
321       DISP_IN_GAME }, /*WC*/
322 /*JP
323     { "font_size_message", "the size of the message font", 20,
324 */
325     { "font_size_message", "\83\81\83b\83Z\81[\83W\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
326       DISP_IN_GAME }, /*WC*/
327 /*JP
328     { "font_size_status", "the size of the status font", 20,
329 */
330     { "font_size_status", "\8fó\8bµ\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
331       DISP_IN_GAME }, /*WC*/
332 /*JP
333     { "font_size_text", "the size of the text font", 20,
334 */
335     { "font_size_text", "\83e\83L\83X\83g\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
336       DISP_IN_GAME }, /*WC*/
337 /*JP
338     { "font_status", "the font to use in status window", 40,
339 */
340     { "font_status", "\8fó\8bµ\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
341       DISP_IN_GAME }, /*WC*/
342 /*JP
343     { "font_text", "the font to use in text windows", 40,
344 */
345     { "font_text", "\83e\83L\83X\83g\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
346       DISP_IN_GAME }, /*WC*/
347 /*JP
348     { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME },
349 */
350     { "fruit", "\8dD\95¨\82Ì\89Ê\95¨\82Ì\96¼\91O", PL_FSIZ, SET_IN_GAME },
351 /*JP
352     { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME },
353 */
354     { "gender", "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\90«\95Ê(male \82Ü\82½\82Í female)", 8, DISP_IN_GAME },
355 /*JP
356     { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
357 */
358     { "horsename", "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\94n\82Ì\96¼\91O (\97á ghoulname:\83V\83\8b\83o\81[)",
359       PL_PSIZ, DISP_IN_GAME },
360 #if 0 /*JP*/
361     { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
362 #else
363     { "map_mode", "\83E\83B\83\93\83h\83E\95\\8e¦\8e\9e\82Ì\83}\83b\83v\82Ì\95\\8e¦\83\82\81[\83h", 20, DISP_IN_GAME }, /*WC*/
364 #endif
365 /*JP
366     { "menustyle", "user interface for object selection", MENUTYPELEN,
367 */
368     { "menustyle", "\83I\83u\83W\83F\83N\83g\82ð\91I\91ð\82·\82é\82Æ\82«\82Ì\83\86\81[\83U\81[\83C\83\93\83^\83t\83F\81[\83X", MENUTYPELEN,
369       SET_IN_GAME },
370 /*JP
371     { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
372 */
373     { "menu_deselect_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\94ñ\91I\91ð", 4, SET_IN_FILE },
374 /*JP
375     { "menu_deselect_page", "deselect all items on this page of a menu", 4,
376 */
377     { "menu_deselect_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\83y\81[\83W\82Ì\83A\83C\83e\83\80\82ð\94ñ\91I\91ð", 4,
378       SET_IN_FILE },
379 /*JP
380     { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE },
381 */
382     { "menu_first_page", "\83\81\83j\83\85\81[\82Ì\8dÅ\8f\89\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
383 /*JP
384     { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME },
385 */
386     { "menu_headings", "\8b­\92²\81C\94½\93]\82Ü\82½\82Í\89º\90ü\82Å\8eí\97Þ\82ð\95\\8e¦\82·\82é", 9, SET_IN_GAME },
387 /*JP
388     { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
389 */
390     { "menu_invert_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\94½\93]", 4, SET_IN_FILE },
391 /*JP
392     { "menu_invert_page", "invert all items on this page of a menu", 4,
393 */
394     { "menu_invert_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\83y\81[\83W\82Ì\83A\83C\83e\83\80\82ð\94½\93]",
395       SET_IN_FILE },
396 /*JP
397     { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
398 */
399     { "menu_last_page", "\83\81\83j\83\85\81[\82Ì\8dÅ\8cã\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
400 /*JP
401     { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
402 */
403     { "menu_next_page", "\8e\9f\82Ì\83\81\83j\83\85\81[\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
404 /*JP
405     { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
406 */
407     { "menu_previous_page", "\91O\82Ì\83\81\83j\83\85\81[\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
408 /*JP
409     { "menu_search", "search for a menu item", 4, SET_IN_FILE },
410 */
411     { "menu_search", "\83\81\83j\83\85\81[\82Ì\8c\9f\8dõ", 4, SET_IN_FILE },
412 /*JP
413     { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
414 */
415     { "menu_select_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\91I\91ð", 4, SET_IN_FILE },
416 /*JP
417     { "menu_select_page", "select all items on this page of a menu", 4,
418 */
419     { "menu_select_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\91I\91ð", 4,
420       SET_IN_FILE },
421 /*JP
422     { "monsters", "the symbols to use for monsters", MAXMCLASSES,
423 */
424     { "monsters", "\83\82\83\93\83X\83^\81[\82É\8eg\97p\82³\82ê\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXMCLASSES,
425       SET_IN_FILE },
426 /*JP
427     { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME },
428 */
429     { "msghistory", "\90æ\93ª\8ds\82É\95\\8e¦\82³\82ê\82½\83\81\83b\83Z\81[\83W\97\9a\97ð\82Ì\95Û\91\90\94", 5, DISP_IN_GAME },
430 #ifdef TTY_GRAPHICS
431 /*JP
432     { "msg_window", "the type of message window required", 1, SET_IN_GAME },
433 */
434     {"msg_window", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82Ì\83^\83C\83v\82ð\90Ý\92è",1, SET_IN_GAME },
435 #else
436 /*JP
437     { "msg_window", "the type of message window required", 1, SET_IN_FILE },
438 */
439     {"msg_window", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82Ì\83^\83C\83v\82ð\90Ý\92è", 1, SET_IN_FILE },
440 #endif
441 /*JP
442     { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ,
443 */
444     { "name", "\82 \82È\82½\82Ì\96¼\91O (\97á name:\83}\81[\83\8a\83\93-W)", PL_NSIZ,
445       DISP_IN_GAME },
446 /*JP
447     { "number_pad", "use the number pad for movement", 1, SET_IN_GAME },
448 */
449     { "number_pad", "\83i\83\93\83o\81[\83p\83b\83h\82ð\8eg\97p\82·\82é", 1, SET_IN_GAME },
450 /*JP
451     { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE },
452 */
453     { "objects",  "\83A\83C\83e\83\80\82É\8eg\97p\82³\82ê\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXOCLASSES, SET_IN_FILE },
454 /*JP
455     { "packorder", "the inventory order of the items in your pack",
456 */
457     { "packorder", "\94w\95\89\82¢\91Ü\93à\82Ì\95¨\82Ì\8f\87\94Ô",
458       MAXOCLASSES, SET_IN_GAME },
459 #ifdef CHANGE_COLOR
460     { "palette",
461 #ifndef WIN32
462 /*JP
463       "palette (00c/880/-fff is blue/yellow/reverse white)", 15,
464 */
465       "\83p\83\8c\83b\83g (00c/880/-fff\82Í\82»\82ê\82¼\82ê\90Â/\89©/\94½\93]\94\92\82ð\8e¦\82·)", 15,
466       SET_IN_GAME },
467 #else
468 /*JP
469       "palette (adjust an RGB color in palette (color-R-G-B)", 15,
470 */
471       "\83p\83\8c\83b\83g (\83p\83\8c\83b\83g\82ÌRGB\90F\82ð\92²\90®\82·\82é (\90F-R-G-B)", 15,
472       SET_IN_FILE },
473 #endif
474 #if defined(MAC)
475 /*JP
476     { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE },
477 */
478     { "hicolor",  "\83p\83\8c\83b\83g\82ª\93¯\82\82Æ\82«\81A\8ew\8e¦\82µ\82½\82à\82Ì\82¾\82¯\94½\93]\82³\82¹\82é", 15, SET_IN_FILE },
479 #endif
480 #endif
481     { "paranoid_confirmation", "extra prompting in certain situations", 28,
482       SET_IN_GAME },
483 /*JP
484     { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
485 */
486     { "pettype",  "\82 \82È\82½\82Ì\91I\91ð\82µ\82½\8f\89\8aú\83y\83b\83g\82Ì\8eí\97Þ", 4, DISP_IN_GAME },
487 /*JP
488     { "pickup_burden", "maximum burden picked up before prompt", 20,
489 */
490     { "pickup_burden",  "\8fE\82¤\82Æ\82«\82É\8dÅ\91å\89×\8fd\82É\82È\82é\8eè\91O\82Å\8am\94F\82·\82é", 20,
491       SET_IN_GAME },
492 /*JP
493     { "pickup_types", "types of objects to pick up automatically",
494 */
495     { "pickup_types", "\8e©\93®\82Å\8fE\82¢\82 \82°\82é\95¨\82Ì\83V\83\93\83{\83\8b",
496       MAXOCLASSES, SET_IN_GAME },
497     { "pile_limit", "threshold for \"there are many objects here\"", 24,
498       SET_IN_GAME },
499     { "playmode", "normal play, non-scoring explore mode, or debug mode", 8,
500       DISP_IN_GAME },
501 /*JP
502     { "player_selection", "choose character via dialog or prompts", 12,
503 */
504     { "player_selection", "\83L\83\83\83\89\83N\83^\81[\91I\91ð\82É\83_\83C\83A\83\8d\83O\82â\8am\94F\89æ\96Ê\82ð\8eg\82¤", 12,
505       DISP_IN_GAME },
506 /*JP
507     { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ,
508 */
509     { "race",     "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\8eí\91° (\97á Human, Elf)", PL_CSIZ,
510       DISP_IN_GAME },
511 /*JP
512     { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ,
513 */
514     { "role",     "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\90E\8bÆ (\97á Barbarian, Valkyrie)", PL_CSIZ,
515       DISP_IN_GAME },
516 /*JP
517     { "runmode", "display frequency when `running' or `travelling'",
518 */
519     { "runmode", "\83g\83\89\83x\83\8b\83R\83}\83\93\83h\93\99\82Å\82Ì\98A\91±\88Ú\93®\8e\9e\82Ì\95`\89æ\95p\93x",
520       sizeof "teleport", SET_IN_GAME },
521 /*JP
522     { "scores", "the parts of the score list you wish to see", 32,
523 */
524     { "scores",   "\83Q\81[\83\80\8fI\97¹\8e\9e\82É\8c©\82é\83X\83R\83A\82Ì\8eí\97Þ", 32,
525       SET_IN_GAME },
526 /*JP
527     { "scroll_amount", "amount to scroll map when scroll_margin is reached",
528 */
529     { "scroll_amount", "scroll_margin\82É\93Í\82¢\82½\82Æ\82«\82Ì\83}\83b\83v\83X\83N\83\8d\81[\83\8b\97Ê",
530       20, DISP_IN_GAME }, /*WC*/
531 /*JP
532     { "scroll_margin", "scroll map when this far from the edge", 20,
533 */
534     { "scroll_margin", "\83}\83b\83v\92[\82©\82ç\82Ì\83}\83b\83v\83X\83N\83\8d\81[\83\8b\8aJ\8en\8b\97\97£", 20,
535       DISP_IN_GAME }, /*WC*/
536     { "sortloot", "sort object selection lists by description", 4,
537       SET_IN_GAME },
538 #ifdef MSDOS
539 /*JP
540     { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
541 */
542     { "soundcard", "\8eg\97p\82µ\82Ä\82¢\82é\83T\83E\83\93\83h\83J\81[\83h\82Ì\8eí\97Þ", 20, SET_IN_FILE },
543 #endif
544     { "symset", "load a set of display symbols from the symbols file", 70,
545       SET_IN_GAME },
546     { "roguesymset",
547       "load a set of rogue display symbols from the symbols file", 70,
548       SET_IN_GAME },
549 /*JP
550     { "suppress_alert", "suppress alerts about version-specific features", 8,
551 */
552     { "suppress_alert", "\83o\81[\83W\83\87\83\93\8aÔ\82Ì\88á\82¢\82É\8aÖ\82·\82é\8cx\8d\90\83\81\83b\83Z\81[\83W\82Ì\96³\8cø\89»", 8,
553       SET_IN_GAME },
554 #if 0 /*JP*/
555     { "tile_width", "width of tiles", 20, DISP_IN_GAME },   /*WC*/
556 #else
557     { "tile_width", "\83^\83C\83\8b\82Ì\95\9d", 20, DISP_IN_GAME }, /*WC*/
558 #endif
559 #if 0 /*JP*/
560     { "tile_height", "height of tiles", 20, DISP_IN_GAME }, /*WC*/
561 #else
562     { "tile_height", "\83^\83C\83\8b\82Ì\8d\82\82³", 20, DISP_IN_GAME }, /*WC*/
563 #endif
564 #if 0 /*JP*/
565     { "tile_file", "name of tile file", 70, DISP_IN_GAME }, /*WC*/
566 #else
567     { "tile_file", "\83^\83C\83\8b\83t\83@\83C\83\8b\82Ì\96¼\91O", 70, DISP_IN_GAME }, /*WC*/
568 #endif
569 /*JP
570     { "traps", "the symbols to use in drawing traps", MAXTCHARS + 1,
571 */
572     { "traps", "ã©\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXTCHARS + 1,
573       SET_IN_FILE },
574 /*JP
575     { "vary_msgcount", "show more old messages at a time", 20,
576 */
577     { "vary_msgcount", "\88ê\93x\82É\95\\8e¦\82·\82é\83\81\83b\83Z\81[\83W\82Ì\90\94", 20,
578       DISP_IN_GAME }, /*WC*/
579 #ifdef MSDOS
580 /*JP
581     { "video", "method of video updating", 20, SET_IN_FILE },
582 */
583     { "video", "\8eg\97p\82·\82é\83r\83f\83I\83\82\81[\83h\82ð\90Ý\92è\82·\82é", 20, SET_IN_FILE },
584 #endif
585 #ifdef VIDEOSHADES
586 /*JP
587     { "videocolors", "color mappings for internal screen routines", 40,
588 */
589     { "videocolors", "\93à\91 \83X\83N\83\8a\81[\83\93\83\8b\81[\83`\83\93\97p\82Ì\83J\83\89\81[\83}\83b\83v\82ð\97p\82¢\82é", 40,
590       DISP_IN_GAME },
591 /*JP
592     { "videoshades", "gray shades to map to black/gray/white", 32,
593 */
594     { "videoshades", "\95\\8e¦\82É\83O\83\8c\83C\83X\83P\81[\83\8b\82ð\97p\82¢\82é", 32,
595       DISP_IN_GAME },
596 #endif
597 #ifdef WIN32
598 /*JP
599     { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE },
600 */
601     {"subkeyvalue", "\83L\81[\83}\83b\83s\83\93\83O\82ð\95Ï\8dX\82·\82é", 7, SET_IN_FILE },
602 #endif
603 #if 0 /*JP*/
604     { "windowcolors", "the foreground/background colors of windows", /*WC*/
605 #else
606     { "windowcolors",  "\83E\83B\83\93\83h\83E\82ð\8ew\92è\82µ\82½\91O\8ci\90F/\94w\8ci\90F\82Å\95\\8e¦\82·\82é", /*WC*/
607 #endif
608       80, DISP_IN_GAME },
609 /*JP
610     { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
611 */
612     { "windowtype", "\8eg\97p\82·\82é\83E\83C\83\93\83h\83E\83V\83X\83e\83\80", WINTYPELEN, DISP_IN_GAME },
613 #ifdef WINCHAIN
614     { "windowchain", "window processor to use", WINTYPELEN, SET_IN_SYS },
615 #endif
616 #ifdef BACKWARD_COMPAT
617     { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE },
618     { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE },
619 #ifdef MAC_GRAPHICS_ENV
620     { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE },
621 #endif
622 #endif
623 #if 1 /*JP*/
624     { "kcode", "\92[\96\96\82Ì\8a¿\8e\9a\83R\81[\83h,", 4, SET_IN_FILE },
625 #endif
626     { (char *) 0, (char *) 0, 0, 0 }
627 };
628
629 #ifdef OPTION_LISTS_ONLY
630 #undef static
631
632 #else /* use rest of file */
633
634 extern struct symparse loadsyms[];
635 static boolean need_redraw; /* for doset() */
636
637 #if defined(TOS) && defined(TEXTCOLOR)
638 extern boolean colors_changed;  /* in tos.c */
639 #endif
640
641 #ifdef VIDEOSHADES
642 extern char *shade[3];          /* in sys/msdos/video.c */
643 extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
644 #endif
645
646 static char def_inv_order[MAXOCLASSES] = {
647     COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
648     SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
649     TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
650 };
651
652 /*
653  * Default menu manipulation command accelerators.  These may _not_ be:
654  *
655  *      + a number - reserved for counts
656  *      + an upper or lower case US ASCII letter - used for accelerators
657  *      + ESC - reserved for escaping the menu
658  *      + NULL, CR or LF - reserved for commiting the selection(s).  NULL
659  *        is kind of odd, but the tty's xwaitforspace() will return it if
660  *        someone hits a <ret>.
661  *      + a default object class symbol - used for object class accelerators
662  *
663  * Standard letters (for now) are:
664  *
665  *              <  back 1 page
666  *              >  forward 1 page
667  *              ^  first page
668  *              |  last page
669  *              :  search
670  *
671  *              page            all
672  *               ,    select     .
673  *               \    deselect   -
674  *               ~    invert     @
675  *
676  * The command name list is duplicated in the compopt array.
677  */
678 typedef struct {
679     const char *name;
680     char cmd;
681 } menu_cmd_t;
682
683 #define NUM_MENU_CMDS 11
684 static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
685 /* 0*/  { "menu_first_page", MENU_FIRST_PAGE },
686         { "menu_last_page", MENU_LAST_PAGE },
687         { "menu_next_page", MENU_NEXT_PAGE },
688         { "menu_previous_page", MENU_PREVIOUS_PAGE },
689         { "menu_select_all", MENU_SELECT_ALL },
690 /* 5*/  { "menu_deselect_all", MENU_UNSELECT_ALL },
691         { "menu_invert_all", MENU_INVERT_ALL },
692         { "menu_select_page", MENU_SELECT_PAGE },
693         { "menu_deselect_page", MENU_UNSELECT_PAGE },
694         { "menu_invert_page", MENU_INVERT_PAGE },
695 /*10*/  { "menu_search", MENU_SEARCH },
696 };
697
698 /*
699  * Allow the user to map incoming characters to various menu commands.
700  * The accelerator list must be a valid C string.
701  */
702 #define MAX_MENU_MAPPED_CMDS 32 /* some number */
703 char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */
704 static char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1];
705 static short n_menu_mapped = 0;
706
707 static boolean initial, from_file;
708
709 STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int));
710 STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
711 STATIC_DCL void FDECL(escapes, (const char *, char *));
712 STATIC_DCL void FDECL(rejectoption, (const char *));
713 STATIC_DCL void FDECL(badoption, (const char *));
714 STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P));
715 STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
716 STATIC_DCL void FDECL(bad_negation, (const char *, BOOLEAN_P));
717 STATIC_DCL int FDECL(change_inv_order, (char *));
718 STATIC_DCL void FDECL(oc_to_str, (char *, char *));
719 STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
720 STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
721 STATIC_DCL boolean FDECL(special_handling, (const char *,
722                                             BOOLEAN_P, BOOLEAN_P));
723 STATIC_DCL void FDECL(warning_opts, (char *, const char *));
724 STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int));
725 STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int));
726
727 STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
728 STATIC_OVL int FDECL(wc_set_window_colors, (char *));
729 STATIC_OVL boolean FDECL(is_wc_option, (const char *));
730 STATIC_OVL boolean FDECL(wc_supported, (const char *));
731 STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
732 STATIC_OVL boolean FDECL(wc2_supported, (const char *));
733 STATIC_DCL void FDECL(remove_autopickup_exception,
734                       (struct autopickup_exception *));
735 STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
736 STATIC_DCL const char *FDECL(attr2attrname, (int));
737 STATIC_DCL int NDECL(query_color);
738 STATIC_DCL int NDECL(query_msgtype);
739 STATIC_DCL int FDECL(query_attr, (const char *));
740 STATIC_DCL const char * FDECL(msgtype2name, (int));
741 STATIC_DCL boolean FDECL(msgtype_add, (int, char *));
742 STATIC_DCL void FDECL(free_one_msgtype, (int));
743 STATIC_DCL int NDECL(msgtype_count);
744 STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
745 STATIC_DCL void FDECL(free_one_menu_coloring, (int));
746 STATIC_DCL int NDECL(count_menucolors);
747 STATIC_DCL int FDECL(handle_add_list_remove, (const char *, int));
748
749 void
750 reglyph_darkroom()
751 {
752     xchar x, y;
753
754     for (x = 0; x < COLNO; x++)
755         for (y = 0; y < ROWNO; y++) {
756             struct rm *lev = &levl[x][y];
757
758             if (!flags.dark_room || !iflags.use_color
759                 || Is_rogue_level(&u.uz)) {
760                 if (lev->glyph == cmap_to_glyph(S_darkroom))
761                     lev->glyph = lev->waslit ? cmap_to_glyph(S_room)
762                                              : cmap_to_glyph(S_stone);
763             } else {
764                 if (lev->glyph == cmap_to_glyph(S_room) && lev->seenv
765                     && lev->waslit && !cansee(x, y))
766                     lev->glyph = cmap_to_glyph(S_darkroom);
767                 else if (lev->glyph == cmap_to_glyph(S_stone)
768                          && lev->typ == ROOM && lev->seenv && !cansee(x, y))
769                     lev->glyph = cmap_to_glyph(S_darkroom);
770             }
771         }
772     if (flags.dark_room && iflags.use_color)
773         showsyms[S_darkroom] = showsyms[S_room];
774     else
775         showsyms[S_darkroom] = showsyms[S_stone];
776 }
777
778 /* check whether a user-supplied option string is a proper leading
779    substring of a particular option name; option string might have
780    a colon or equals sign and arbitrary value appended to it */
781 boolean
782 match_optname(user_string, opt_name, min_length, val_allowed)
783 const char *user_string, *opt_name;
784 int min_length;
785 boolean val_allowed;
786 {
787     int len = (int) strlen(user_string);
788
789     if (val_allowed) {
790         const char *p = index(user_string, ':'),
791                    *q = index(user_string, '=');
792
793         if (!p || (q && q < p))
794             p = q;
795         while (p && p > user_string && isspace((uchar) * (p - 1)))
796             p--;
797         if (p)
798             len = (int) (p - user_string);
799     }
800
801     return (boolean) (len >= min_length
802                       && !strncmpi(opt_name, user_string, len));
803 }
804
805 /* most environment variables will eventually be printed in an error
806  * message if they don't work, and most error message paths go through
807  * BUFSZ buffers, which could be overflowed by a maliciously long
808  * environment variable.  If a variable can legitimately be long, or
809  * if it's put in a smaller buffer, the responsible code will have to
810  * bounds-check itself.
811  */
812 char *
813 nh_getenv(ev)
814 const char *ev;
815 {
816     char *getev = getenv(ev);
817
818     if (getev && strlen(getev) <= (BUFSZ / 2))
819         return getev;
820     else
821         return (char *) 0;
822 }
823
824 /* process options, possibly including SYSCF */
825 void
826 initoptions()
827 {
828     initoptions_init();
829 #ifdef SYSCF
830 /* someday there may be other SYSCF alternatives besides text file */
831 #ifdef SYSCF_FILE
832     /* If SYSCF_FILE is specified, it _must_ exist... */
833     assure_syscf_file();
834     /* ... and _must_ parse correctly. */
835     if (!read_config_file(SYSCF_FILE, SET_IN_SYS)) {
836         raw_printf("Error(s) found in SYSCF_FILE, quitting.");
837         terminate(EXIT_FAILURE);
838     }
839     /*
840      * TODO [maybe]: parse the sysopt entries which are space-separated
841      * lists of usernames into arrays with one name per element.
842      */
843 #endif
844 #endif
845     initoptions_finish();
846 }
847
848 void
849 initoptions_init()
850 {
851 #if defined(UNIX) || defined(VMS)
852     char *opts;
853 #endif
854     int i;
855
856     /* set up the command parsing */
857     reset_commands(TRUE); /* init */
858
859     /* initialize the random number generator */
860     setrandom();
861
862     /* for detection of configfile options specified multiple times */
863     iflags.opt_booldup = iflags.opt_compdup = (int *) 0;
864
865     for (i = 0; boolopt[i].name; i++) {
866         if (boolopt[i].addr)
867             *(boolopt[i].addr) = boolopt[i].initvalue;
868     }
869 #if defined(COMPRESS) || defined(ZLIB_COMP)
870     set_savepref("externalcomp");
871     set_restpref("externalcomp");
872 #ifdef RLECOMP
873     set_savepref("!rlecomp");
874     set_restpref("!rlecomp");
875 #endif
876 #else
877 #ifdef ZEROCOMP
878     set_savepref("zerocomp");
879     set_restpref("zerocomp");
880 #endif
881 #ifdef RLECOMP
882     set_savepref("rlecomp");
883     set_restpref("rlecomp");
884 #endif
885 #endif
886 #ifdef SYSFLAGS
887     Strcpy(sysflags.sysflagsid, "sysflags");
888     sysflags.sysflagsid[9] = (char) sizeof(struct sysflag);
889 #endif
890     flags.end_own = FALSE;
891     flags.end_top = 3;
892     flags.end_around = 2;
893     flags.paranoia_bits = PARANOID_PRAY; /* old prayconfirm=TRUE */
894     flags.pile_limit = PILE_LIMIT_DFLT;  /* 5 */
895     flags.runmode = RUN_LEAP;
896     iflags.msg_history = 20;
897 #ifdef TTY_GRAPHICS
898     iflags.prevmsg_window = 's';
899 #endif
900     iflags.menu_headings = ATR_INVERSE;
901
902     /* hero's role, race, &c haven't been chosen yet */
903     flags.initrole = flags.initrace = flags.initgend = flags.initalign =
904         ROLE_NONE;
905
906     /* Set the default monster and object class symbols. */
907     init_symbols();
908     for (i = 0; i < WARNCOUNT; i++)
909         warnsyms[i] = def_warnsyms[i].sym;
910     iflags.bouldersym = 0;
911
912     iflags.travelcc.x = iflags.travelcc.y = -1;
913
914     /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
915     (void) memcpy((genericptr_t) flags.inv_order,
916                   (genericptr_t) def_inv_order, sizeof flags.inv_order);
917     flags.pickup_types[0] = '\0';
918     flags.pickup_burden = MOD_ENCUMBER;
919     flags.sortloot = 'l'; /* sort only loot by default */
920
921     for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
922         flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
923     switch_symbols(FALSE); /* set default characters */
924 #if defined(UNIX) && defined(TTY_GRAPHICS)
925     /*
926      * Set defaults for some options depending on what we can
927      * detect about the environment's capabilities.
928      * This has to be done after the global initialization above
929      * and before reading user-specific initialization via
930      * config file/environment variable below.
931      */
932     /* this detects the IBM-compatible console on most 386 boxes */
933     if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
934         if (!symset[PRIMARY].name)
935             load_symset("IBMGraphics", PRIMARY);
936         if (!symset[ROGUESET].name)
937             load_symset("RogueIBM", ROGUESET);
938         switch_symbols(TRUE);
939 #ifdef TEXTCOLOR
940         iflags.use_color = TRUE;
941 #endif
942     }
943 #endif /* UNIX && TTY_GRAPHICS */
944 #if defined(UNIX) || defined(VMS)
945 #ifdef TTY_GRAPHICS
946     /* detect whether a "vt" terminal can handle alternate charsets */
947     if ((opts = nh_getenv("TERM"))
948         /* [could also check "xterm" which emulates vtXXX by default] */
949         && !strncmpi(opts, "vt", 2)
950         && AS && AE && index(AS, '\016') && index(AE, '\017')) {
951         if (!symset[PRIMARY].name)
952             load_symset("DECGraphics", PRIMARY);
953         switch_symbols(TRUE);
954     }
955 #endif
956 #endif /* UNIX || VMS */
957
958 #ifdef MAC_GRAPHICS_ENV
959     if (!symset[PRIMARY].name)
960         load_symset("MACGraphics", PRIMARY);
961     switch_symbols(TRUE);
962 #endif /* MAC_GRAPHICS_ENV */
963     flags.menu_style = MENU_FULL;
964
965     /* since this is done before init_objects(), do partial init here */
966     objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
967     nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
968 }
969
970 void
971 initoptions_finish()
972 {
973 #ifndef MAC
974     char *opts = getenv("NETHACKOPTIONS");
975
976     if (!opts)
977         opts = getenv("HACKOPTIONS");
978     if (opts) {
979         if (*opts == '/' || *opts == '\\' || *opts == '@') {
980             if (*opts == '@')
981                 opts++; /* @filename */
982             /* looks like a filename */
983             if (strlen(opts) < BUFSZ / 2)
984                 read_config_file(opts, SET_IN_FILE);
985         } else {
986             read_config_file((char *) 0, SET_IN_FILE);
987             /* let the total length of options be long;
988              * parseoptions() will check each individually
989              */
990             parseoptions(opts, TRUE, FALSE);
991         }
992     } else
993 #endif
994         read_config_file((char *) 0, SET_IN_FILE);
995
996     (void) fruitadd(pl_fruit, (struct fruit *) 0);
997     /*
998      * Remove "slime mold" from list of object names.  This will
999      * prevent it from being wished unless it's actually present
1000      * as a named (or default) fruit.  Wishing for "fruit" will
1001      * result in the player's preferred fruit [better than "\033"].
1002      */
1003     obj_descr[SLIME_MOLD].oc_name = "fruit";
1004
1005     if (iflags.bouldersym)
1006         update_bouldersym();
1007     reglyph_darkroom();
1008     return;
1009 }
1010
1011 STATIC_OVL void
1012 nmcpy(dest, src, maxlen)
1013 char *dest;
1014 const char *src;
1015 int maxlen;
1016 {
1017     int count;
1018
1019     for (count = 1; count < maxlen; count++) {
1020         if (*src == ',' || *src == '\0')
1021             break; /*exit on \0 terminator*/
1022         *dest++ = *src++;
1023     }
1024     *dest = 0;
1025 }
1026
1027 /*
1028  * escapes(): escape expansion for showsyms.  C-style escapes understood
1029  * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
1030  * The ^-prefix for control characters is also understood, and \[mM]
1031  * has the effect of 'meta'-ing the value which follows (so that the
1032  * alternate character set will be enabled).
1033  *
1034  * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
1035  * prior to terminating '\0' would pull that '\0' into the output and then
1036  * keep processing past it, potentially overflowing the output buffer.
1037  * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
1038  * output and stop there; trailing \M will fall through to \<other> and
1039  * yield 'M', then stop.  Any \X or \O followed by something other than
1040  * an appropriate digit will also fall through to \<other> and yield 'X'
1041  * or 'O', plus stop if the non-digit is end-of-string.
1042  */
1043 STATIC_OVL void
1044 escapes(cp, tp)
1045 const char *cp;
1046 char *tp;
1047 {
1048     static NEARDATA const char oct[] = "01234567", dec[] = "0123456789",
1049                                hex[] = "00112233445566778899aAbBcCdDeEfF";
1050     const char *dp;
1051     int cval, meta, dcount;
1052
1053     while (*cp) {
1054         /* \M has to be followed by something to do meta conversion,
1055            otherwise it will just be \M which ultimately yields 'M' */
1056         meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]);
1057         if (meta)
1058             cp += 2;
1059
1060         cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
1061         if ((*cp != '\\' && *cp != '^') || !cp[1]) {
1062             /* simple character, or nothing left for \ or ^ to escape */
1063             cval = *cp++;
1064         } else if (*cp == '^') { /* expand control-character syntax */
1065             cval = (*++cp & 0x1f);
1066             ++cp;
1067             /* remaining cases are all for backslash and we know cp[1] is not
1068              * \0 */
1069         } else if (index(dec, cp[1])) {
1070             ++cp; /* move past backslash to first digit */
1071             do {
1072                 cval = (cval * 10) + (*cp - '0');
1073             } while (*++cp && index(dec, *cp) && ++dcount < 3);
1074         } else if ((cp[1] == 'o' || cp[1] == 'O') && cp[2]
1075                    && index(oct, cp[2])) {
1076             cp += 2; /* move past backslash and 'O' */
1077             do {
1078                 cval = (cval * 8) + (*cp - '0');
1079             } while (*++cp && index(oct, *cp) && ++dcount < 3);
1080         } else if ((cp[1] == 'x' || cp[1] == 'X') && cp[2]
1081                    && (dp = index(hex, cp[2])) != 0) {
1082             cp += 2; /* move past backslash and 'X' */
1083             do {
1084                 cval = (cval * 16) + ((int) (dp - hex) / 2);
1085             } while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2);
1086         } else { /* C-style character escapes */
1087             switch (*++cp) {
1088             case '\\':
1089                 cval = '\\';
1090                 break;
1091             case 'n':
1092                 cval = '\n';
1093                 break;
1094             case 't':
1095                 cval = '\t';
1096                 break;
1097             case 'b':
1098                 cval = '\b';
1099                 break;
1100             case 'r':
1101                 cval = '\r';
1102                 break;
1103             default:
1104                 cval = *cp;
1105             }
1106             ++cp;
1107         }
1108
1109         if (meta)
1110             cval |= 0x80;
1111         *tp++ = (char) cval;
1112     }
1113     *tp = '\0';
1114 }
1115
1116 STATIC_OVL void
1117 rejectoption(optname)
1118 const char *optname;
1119 {
1120 #ifdef MICRO
1121     pline("\"%s\" settable only from %s.", optname, lastconfigfile);
1122 #else
1123     pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
1124           lastconfigfile);
1125 #endif
1126 }
1127
1128 STATIC_OVL void
1129 badoption(opts)
1130 const char *opts;
1131 {
1132     if (!initial) {
1133         if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
1134             option_help();
1135         else
1136             pline("Bad syntax: %s.  Enter \"?g\" for help.", opts);
1137         return;
1138     }
1139 #ifdef MAC
1140     else
1141         return;
1142 #endif
1143
1144     if (from_file)
1145         raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", lastconfigfile,
1146 #ifdef WIN32
1147                     "\n",
1148 #else
1149                     "",
1150 #endif
1151                     opts);
1152     else
1153         raw_printf("Bad syntax in NETHACKOPTIONS: %s%s.\n",
1154 #ifdef WIN32
1155                     "\n",
1156 #else
1157                     "",
1158 #endif
1159                     opts);
1160     wait_synch();
1161 }
1162
1163 STATIC_OVL char *
1164 string_for_opt(opts, val_optional)
1165 char *opts;
1166 boolean val_optional;
1167 {
1168     char *colon, *equals;
1169
1170     colon = index(opts, ':');
1171     equals = index(opts, '=');
1172     if (!colon || (equals && equals < colon))
1173         colon = equals;
1174
1175     if (!colon || !*++colon) {
1176         if (!val_optional)
1177             badoption(opts);
1178         return (char *) 0;
1179     }
1180     return colon;
1181 }
1182
1183 STATIC_OVL char *
1184 string_for_env_opt(optname, opts, val_optional)
1185 const char *optname;
1186 char *opts;
1187 boolean val_optional;
1188 {
1189     if (!initial) {
1190         rejectoption(optname);
1191         return (char *) 0;
1192     }
1193     return string_for_opt(opts, val_optional);
1194 }
1195
1196 STATIC_OVL void
1197 bad_negation(optname, with_parameter)
1198 const char *optname;
1199 boolean with_parameter;
1200 {
1201     pline_The("%s option may not %sbe negated.", optname,
1202               with_parameter ? "both have a value and " : "");
1203 }
1204
1205 /*
1206  * Change the inventory order, using the given string as the new order.
1207  * Missing characters in the new order are filled in at the end from
1208  * the current inv_order, except for gold, which is forced to be first
1209  * if not explicitly present.
1210  *
1211  * This routine returns 1 unless there is a duplicate or bad char in
1212  * the string.
1213  */
1214 STATIC_OVL int
1215 change_inv_order(op)
1216 char *op;
1217 {
1218     int oc_sym, num;
1219     char *sp, buf[BUFSZ];
1220
1221     num = 0;
1222     /*  !!!! probably unnecessary with gold as normal inventory */
1223
1224     for (sp = op; *sp; sp++) {
1225         oc_sym = def_char_to_objclass(*sp);
1226         /* reject bad or duplicate entries */
1227         if (oc_sym == MAXOCLASSES || oc_sym == RANDOM_CLASS
1228             || oc_sym == ILLOBJ_CLASS || !index(flags.inv_order, oc_sym)
1229             || index(sp + 1, *sp))
1230             return 0;
1231         /* retain good ones */
1232         buf[num++] = (char) oc_sym;
1233     }
1234     buf[num] = '\0';
1235
1236     /* fill in any omitted classes, using previous ordering */
1237     for (sp = flags.inv_order; *sp; sp++)
1238         if (!index(buf, *sp)) {
1239             buf[num++] = *sp;
1240             buf[num] = '\0'; /* explicitly terminate for next index() */
1241         }
1242
1243     Strcpy(flags.inv_order, buf);
1244     return 1;
1245 }
1246
1247 STATIC_OVL void
1248 warning_opts(opts, optype)
1249 register char *opts;
1250 const char *optype;
1251 {
1252     uchar translate[WARNCOUNT];
1253     int length, i;
1254
1255     if (!(opts = string_for_env_opt(optype, opts, FALSE)))
1256         return;
1257     escapes(opts, opts);
1258
1259     length = (int) strlen(opts);
1260     /* match the form obtained from PC configuration files */
1261     for (i = 0; i < WARNCOUNT; i++)
1262         translate[i] = (i >= length) ? 0
1263                                      : opts[i] ? (uchar) opts[i]
1264                                                : def_warnsyms[i].sym;
1265     assign_warnings(translate);
1266 }
1267
1268 void
1269 assign_warnings(graph_chars)
1270 register uchar *graph_chars;
1271 {
1272     int i;
1273
1274     for (i = 0; i < WARNCOUNT; i++)
1275         if (graph_chars[i])
1276             warnsyms[i] = graph_chars[i];
1277 }
1278
1279 STATIC_OVL int
1280 feature_alert_opts(op, optn)
1281 char *op;
1282 const char *optn;
1283 {
1284     char buf[BUFSZ];
1285     boolean rejectver = FALSE;
1286     unsigned long fnv = get_feature_notice_ver(op); /* version.c */
1287
1288     if (fnv == 0L)
1289         return 0;
1290     if (fnv > get_current_feature_ver())
1291         rejectver = TRUE;
1292     else
1293         flags.suppress_alert = fnv;
1294     if (rejectver) {
1295         if (!initial) {
1296             You_cant("disable new feature alerts for future versions.");
1297         } else {
1298             Sprintf(buf,
1299                     "\n%s=%s Invalid reference to a future version ignored",
1300                     optn, op);
1301             badoption(buf);
1302         }
1303         return 0;
1304     }
1305     if (!initial) {
1306         Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
1307                 FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
1308         pline(
1309           "Feature change alerts disabled for NetHack %s features and prior.",
1310               buf);
1311     }
1312     return 1;
1313 }
1314
1315 void
1316 set_duplicate_opt_detection(on_or_off)
1317 int on_or_off;
1318 {
1319     int k, *optptr;
1320
1321     if (on_or_off != 0) {
1322         /*-- ON --*/
1323         if (iflags.opt_booldup)
1324             impossible("iflags.opt_booldup already on (memory leak)");
1325         iflags.opt_booldup = (int *) alloc(SIZE(boolopt) * sizeof(int));
1326         optptr = iflags.opt_booldup;
1327         for (k = 0; k < SIZE(boolopt); ++k)
1328             *optptr++ = 0;
1329
1330         if (iflags.opt_compdup)
1331             impossible("iflags.opt_compdup already on (memory leak)");
1332         iflags.opt_compdup = (int *) alloc(SIZE(compopt) * sizeof(int));
1333         optptr = iflags.opt_compdup;
1334         for (k = 0; k < SIZE(compopt); ++k)
1335             *optptr++ = 0;
1336     } else {
1337         /*-- OFF --*/
1338         if (iflags.opt_booldup)
1339             free((genericptr_t) iflags.opt_booldup);
1340         iflags.opt_booldup = (int *) 0;
1341         if (iflags.opt_compdup)
1342             free((genericptr_t) iflags.opt_compdup);
1343         iflags.opt_compdup = (int *) 0;
1344     }
1345 }
1346
1347 STATIC_OVL boolean
1348 duplicate_opt_detection(opts, iscompound)
1349 const char *opts;
1350 int iscompound; /* 0 == boolean option, 1 == compound */
1351 {
1352     int i, *optptr;
1353
1354     if (!iscompound && iflags.opt_booldup && initial && from_file) {
1355         for (i = 0; boolopt[i].name; i++) {
1356             if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
1357                 optptr = iflags.opt_booldup + i;
1358                 *optptr += 1;
1359                 if (*optptr > 1)
1360                     return TRUE;
1361                 else
1362                     return FALSE;
1363             }
1364         }
1365     } else if (iscompound && iflags.opt_compdup && initial && from_file) {
1366         for (i = 0; compopt[i].name; i++) {
1367             if (match_optname(opts, compopt[i].name, strlen(compopt[i].name),
1368                               TRUE)) {
1369                 optptr = iflags.opt_compdup + i;
1370                 *optptr += 1;
1371                 if (*optptr > 1)
1372                     return TRUE;
1373                 else
1374                     return FALSE;
1375             }
1376         }
1377     }
1378     return FALSE;
1379 }
1380
1381 STATIC_OVL void
1382 complain_about_duplicate(opts, iscompound)
1383 const char *opts;
1384 int iscompound; /* 0 == boolean option, 1 == compound */
1385 {
1386 #ifdef MAC
1387     /* the Mac has trouble dealing with the output of messages while
1388      * processing the config file.  That should get fixed one day.
1389      * For now just return.
1390      */
1391 #else /* !MAC */
1392     raw_printf("\nWarning - %s option specified multiple times: %s.\n",
1393                iscompound ? "compound" : "boolean", opts);
1394     wait_synch();
1395 #endif /* ?MAC */
1396     return;
1397 }
1398
1399 /* paranoia[] - used by parseoptions() and special_handling() */
1400 STATIC_VAR const struct paranoia_opts {
1401     int flagmask;        /* which paranoid option */
1402     const char *argname; /* primary name */
1403     int argMinLen;       /* minimum number of letters to match */
1404     const char *synonym; /* alternate name (optional) */
1405     int synMinLen;
1406     const char *explain; /* for interactive menu */
1407 } paranoia[] = {
1408     /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
1409        takes precedence and "all" isn't present in the interactive menu,
1410        and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
1411        (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
1412        is just a synonym for "Confirm") */
1413     { PARANOID_CONFIRM, "Confirm", 1, "Paranoia", 2,
1414       "for \"yes\" confirmations, require \"no\" to reject" },
1415     { PARANOID_QUIT, "quit", 1, "explore", 1,
1416       "yes vs y to quit or to enter explore mode" },
1417     { PARANOID_DIE, "die", 1, "death", 2,
1418       "yes vs y to die (explore mode or debug mode)" },
1419     { PARANOID_BONES, "bones", 1, 0, 0,
1420       "yes vs y to save bones data when dying in debug mode" },
1421     { PARANOID_HIT, "attack", 1, "hit", 1,
1422       "yes vs y to attack a peaceful monster" },
1423     { PARANOID_PRAY, "pray", 1, 0, 0,
1424       "y to pray (supersedes old \"prayconfirm\" option)" },
1425     { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1,
1426       "always pick from inventory for Remove and Takeoff" },
1427     { PARANOID_BREAKWAND, "wand", 1, "breakwand", 2,
1428       "yes vs y to break a wand" },
1429     /* for config file parsing; interactive menu skips these */
1430     { 0, "none", 4, 0, 0, 0 }, /* require full word match */
1431     { ~0, "all", 3, 0, 0, 0 }, /* ditto */
1432 };
1433
1434 extern struct menucoloring *menu_colorings;
1435
1436 static const struct {
1437     const char *name;
1438     const int color;
1439 } colornames[] = {
1440     { "black", CLR_BLACK },
1441     { "red", CLR_RED },
1442     { "green", CLR_GREEN },
1443     { "brown", CLR_BROWN },
1444     { "blue", CLR_BLUE },
1445     { "magenta", CLR_MAGENTA },
1446     { "cyan", CLR_CYAN },
1447     { "gray", CLR_GRAY },
1448     { "grey", CLR_GRAY },
1449     { "orange", CLR_ORANGE },
1450     { "light green", CLR_BRIGHT_GREEN },
1451     { "yellow", CLR_YELLOW },
1452     { "light blue", CLR_BRIGHT_BLUE },
1453     { "light magenta", CLR_BRIGHT_MAGENTA },
1454     { "light cyan", CLR_BRIGHT_CYAN },
1455     { "white", CLR_WHITE }
1456 };
1457
1458 static const struct {
1459     const char *name;
1460     const int attr;
1461 } attrnames[] = {
1462     { "none", ATR_NONE },
1463     { "bold", ATR_BOLD },
1464     { "dim", ATR_DIM },
1465     { "underline", ATR_ULINE },
1466     { "blink", ATR_BLINK },
1467     { "inverse", ATR_INVERSE }
1468 };
1469
1470 const char *
1471 clr2colorname(clr)
1472 int clr;
1473 {
1474     int i;
1475
1476     for (i = 0; i < SIZE(colornames); i++)
1477         if (colornames[i].color == clr)
1478             return colornames[i].name;
1479     return (char *) 0;
1480 }
1481
1482 const char *
1483 attr2attrname(attr)
1484 int attr;
1485 {
1486     int i;
1487
1488     for (i = 0; i < SIZE(attrnames); i++)
1489         if (attrnames[i].attr == attr)
1490             return attrnames[i].name;
1491     return (char *) 0;
1492 }
1493
1494 int
1495 query_color()
1496 {
1497     winid tmpwin;
1498     anything any;
1499     int i, pick_cnt;
1500     menu_item *picks = (menu_item *) 0;
1501
1502     tmpwin = create_nhwindow(NHW_MENU);
1503     start_menu(tmpwin);
1504     any = zeroany;
1505     for (i = 0; i < SIZE(colornames); i++) {
1506         if (!strcmp(colornames[i].name, "grey"))
1507             continue;
1508         any.a_int = i + 1;
1509         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name,
1510                  MENU_UNSELECTED);
1511     }
1512     end_menu(tmpwin, "Pick a color");
1513     pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1514     destroy_nhwindow(tmpwin);
1515     if (pick_cnt > 0) {
1516         i = colornames[picks->item.a_int - 1].color;
1517         free((genericptr_t) picks);
1518         return i;
1519     }
1520     return -1;
1521 }
1522
1523 int
1524 query_attr(prompt)
1525 const char *prompt;
1526 {
1527     winid tmpwin;
1528     anything any;
1529     int i, pick_cnt;
1530     menu_item *picks = (menu_item *) 0;
1531
1532     tmpwin = create_nhwindow(NHW_MENU);
1533     start_menu(tmpwin);
1534     any = zeroany;
1535     for (i = 0; i < SIZE(attrnames); i++) {
1536         any.a_int = i + 1;
1537         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr,
1538                  attrnames[i].name, MENU_UNSELECTED);
1539     }
1540     end_menu(tmpwin, prompt ? prompt : "Pick an attribute");
1541     pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1542     destroy_nhwindow(tmpwin);
1543     if (pick_cnt > 0) {
1544         i = attrnames[picks->item.a_int - 1].attr;
1545         free((genericptr_t) picks);
1546         return i;
1547     }
1548     return -1;
1549 }
1550
1551 static const struct {
1552     const char *name;
1553     const xchar msgtyp;
1554     const char *descr;
1555 } msgtype_names[] = {
1556     { "show", MSGTYP_NORMAL, "Show message normally" },
1557     { "hide", MSGTYP_NOSHOW, "Hide message" },
1558     { "noshow", MSGTYP_NOSHOW, NULL },
1559     { "stop", MSGTYP_STOP, "Prompt for more after the message" },
1560     { "more", MSGTYP_STOP, NULL },
1561     { "norep", MSGTYP_NOREP, "Do not repeat the message" }
1562 };
1563
1564 const char *
1565 msgtype2name(typ)
1566 int typ;
1567 {
1568     int i;
1569
1570     for (i = 0; i < SIZE(msgtype_names); i++)
1571         if (msgtype_names[i].descr && msgtype_names[i].msgtyp == typ)
1572             return msgtype_names[i].name;
1573     return (char *) 0;
1574 }
1575
1576 int
1577 query_msgtype()
1578 {
1579     winid tmpwin;
1580     anything any;
1581     int i, pick_cnt;
1582     menu_item *picks = (menu_item *) 0;
1583
1584     tmpwin = create_nhwindow(NHW_MENU);
1585     start_menu(tmpwin);
1586     any = zeroany;
1587     for (i = 0; i < SIZE(msgtype_names); i++)
1588         if (msgtype_names[i].descr) {
1589             any.a_int = msgtype_names[i].msgtyp + 1;
1590             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1591                  msgtype_names[i].descr, MENU_UNSELECTED);
1592         }
1593     end_menu(tmpwin, "How to show the message");
1594     pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1595     destroy_nhwindow(tmpwin);
1596     if (pick_cnt > 0) {
1597         i = picks->item.a_int - 1;
1598         free((genericptr_t) picks);
1599         return i;
1600     }
1601     return -1;
1602 }
1603
1604 boolean
1605 msgtype_add(typ, pattern)
1606 int typ;
1607 char *pattern;
1608 {
1609     struct plinemsg_type *tmp
1610               = (struct plinemsg_type *) alloc(sizeof (struct plinemsg_type));
1611
1612     if (!tmp)
1613         return FALSE;
1614     tmp->msgtype = typ;
1615     tmp->regex = regex_init();
1616     if (!regex_compile(pattern, tmp->regex)) {
1617         static const char *re_error = "MSGTYPE regex error";
1618
1619         if (!iflags.window_inited)
1620             raw_printf("\n%s: %s\n", re_error, regex_error_desc(tmp->regex));
1621         else
1622             pline("%s: %s", re_error, regex_error_desc(tmp->regex));
1623         wait_synch();
1624         regex_free(tmp->regex);
1625         free((genericptr_t) tmp);
1626         return FALSE;
1627     }
1628     tmp->pattern = dupstr(pattern);
1629     tmp->next = plinemsg_types;
1630     plinemsg_types = tmp;
1631     return TRUE;
1632 }
1633
1634 void
1635 msgtype_free()
1636 {
1637     struct plinemsg_type *tmp, *tmp2 = 0;
1638
1639     for (tmp = plinemsg_types; tmp; tmp = tmp2) {
1640         tmp2 = tmp->next;
1641         free((genericptr_t) tmp->pattern);
1642         regex_free(tmp->regex);
1643         free((genericptr_t) tmp);
1644     }
1645     plinemsg_types = (struct plinemsg_type *) 0;
1646 }
1647
1648 void
1649 free_one_msgtype(idx)
1650 int idx; /* 0 .. */
1651 {
1652     struct plinemsg_type *tmp = plinemsg_types;
1653     struct plinemsg_type *prev = NULL;
1654
1655     while (tmp) {
1656         if (idx == 0) {
1657             struct plinemsg_type *next = tmp->next;
1658
1659             regex_free(tmp->regex);
1660             free((genericptr_t) tmp->pattern);
1661             free((genericptr_t) tmp);
1662             if (prev)
1663                 prev->next = next;
1664             else
1665                 plinemsg_types = next;
1666             return;
1667         }
1668         idx--;
1669         prev = tmp;
1670         tmp = tmp->next;
1671     }
1672 }
1673
1674 int
1675 msgtype_type(msg)
1676 const char *msg;
1677 {
1678     struct plinemsg_type *tmp = plinemsg_types;
1679
1680     while (tmp) {
1681         if (regex_match(msg, tmp->regex))
1682             return tmp->msgtype;
1683         tmp = tmp->next;
1684     }
1685     return MSGTYP_NORMAL;
1686 }
1687
1688 int
1689 msgtype_count()
1690 {
1691     int c = 0;
1692     struct plinemsg_type *tmp = plinemsg_types;
1693
1694     while (tmp) {
1695         c++;
1696         tmp = tmp->next;
1697     }
1698     return c;
1699 }
1700
1701 boolean
1702 msgtype_parse_add(str)
1703 char *str;
1704 {
1705     char pattern[256];
1706     char msgtype[11];
1707
1708     if (sscanf(str, "%10s \"%255[^\"]\"", msgtype, pattern) == 2) {
1709         int typ = -1;
1710         int i;
1711
1712         for (i = 0; i < SIZE(msgtype_names); i++)
1713             if (!strncmpi(msgtype_names[i].name, msgtype, strlen(msgtype))) {
1714                 typ = msgtype_names[i].msgtyp;
1715                 break;
1716             }
1717         if (typ != -1)
1718             return msgtype_add(typ, pattern);
1719     }
1720     return FALSE;
1721 }
1722
1723 boolean
1724 add_menu_coloring_parsed(str, c, a)
1725 char *str;
1726 int c, a;
1727 {
1728     static const char re_error[] = "Menucolor regex error";
1729     struct menucoloring *tmp;
1730
1731     if (!str)
1732         return FALSE;
1733     tmp = (struct menucoloring *) alloc(sizeof (struct menucoloring));
1734     tmp->match = regex_init();
1735     if (!regex_compile(str, tmp->match)) {
1736         if (!iflags.window_inited)
1737             raw_printf("\n%s: %s\n", re_error, regex_error_desc(tmp->match));
1738         else
1739             pline("%s: %s", re_error, regex_error_desc(tmp->match));
1740         wait_synch();
1741         regex_free(tmp->match);
1742         free(tmp);
1743         return FALSE;
1744     } else {
1745         tmp->next = menu_colorings;
1746         tmp->origstr = dupstr(str);
1747         tmp->color = c;
1748         tmp->attr = a;
1749         menu_colorings = tmp;
1750         return TRUE;
1751     }
1752 }
1753
1754 /* parse '"regex_string"=color&attr' and add it to menucoloring */
1755 boolean
1756 add_menu_coloring(str)
1757 char *str;
1758 {
1759     int i, c = NO_COLOR, a = ATR_NONE;
1760     char *tmps, *cs, *amp;
1761
1762     if (!str || (cs = index(str, '=')) == 0)
1763         return FALSE;
1764
1765     tmps = cs + 1; /* advance past '=' */
1766     mungspaces(tmps);
1767     if ((amp = index(tmps, '&')) != 0)
1768         *amp = '\0';
1769
1770     /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
1771        (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
1772        also copes with trailing space; mungspaces removed any leading space */
1773     for (i = 0; i < SIZE(colornames); i++)
1774         if (fuzzymatch(tmps, colornames[i].name, " -_", TRUE)) {
1775             c = colornames[i].color;
1776             break;
1777         }
1778     if (i == SIZE(colornames) && (*tmps >= '0' && *tmps <= '9'))
1779         c = atoi(tmps);
1780
1781     if (c > 15)
1782         return FALSE;
1783
1784     if (amp) {
1785         tmps = amp + 1; /* advance past '&' */
1786         /* unlike colors, none of he attribute names has any embedded spaces,
1787            but use of fuzzymatch() allows us ignore the presence of leading
1788            and/or trailing (and also embedded) spaces in the user's string;
1789            dash and underscore skipping could be omitted but does no harm */
1790         for (i = 0; i < SIZE(attrnames); i++)
1791             if (fuzzymatch(tmps, attrnames[i].name, " -_", TRUE)) {
1792                 a = attrnames[i].attr;
1793                 break;
1794             }
1795         if (i == SIZE(attrnames) && (*tmps >= '0' && *tmps <= '9'))
1796             a = atoi(tmps);
1797     }
1798
1799     /* the regexp portion here has not been condensed by mungspaces() */
1800     *cs = '\0';
1801     tmps = str;
1802     if (*tmps == '"' || *tmps == '\'') {
1803         cs--;
1804         while (isspace((uchar) *cs))
1805             cs--;
1806         if (*cs == *tmps) {
1807             *cs = '\0';
1808             tmps++;
1809         }
1810     }
1811
1812     return add_menu_coloring_parsed(tmps, c, a);
1813 }
1814
1815 boolean
1816 get_menu_coloring(str, color, attr)
1817 char *str;
1818 int *color, *attr;
1819 {
1820     struct menucoloring *tmpmc;
1821
1822     if (iflags.use_menu_color)
1823         for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next)
1824             if (regex_match(str, tmpmc->match)) {
1825                 *color = tmpmc->color;
1826                 *attr = tmpmc->attr;
1827                 return TRUE;
1828             }
1829     return FALSE;
1830 }
1831
1832 void
1833 free_menu_coloring()
1834 {
1835     struct menucoloring *tmp = menu_colorings;
1836
1837     while (tmp) {
1838         struct menucoloring *tmp2 = tmp->next;
1839
1840         regex_free(tmp->match);
1841         free((genericptr_t) tmp->origstr);
1842         free((genericptr_t) tmp);
1843         tmp = tmp2;
1844     }
1845 }
1846
1847 void
1848 free_one_menu_coloring(idx)
1849 int idx; /* 0 .. */
1850 {
1851     struct menucoloring *tmp = menu_colorings;
1852     struct menucoloring *prev = NULL;
1853
1854     while (tmp) {
1855         if (idx == 0) {
1856             struct menucoloring *next = tmp->next;
1857
1858             regex_free(tmp->match);
1859             free((genericptr_t) tmp->origstr);
1860             free((genericptr_t) tmp);
1861             if (prev)
1862                 prev->next = next;
1863             else
1864                 menu_colorings = next;
1865             return;
1866         }
1867         idx--;
1868         prev = tmp;
1869         tmp = tmp->next;
1870     }
1871 }
1872
1873 int
1874 count_menucolors()
1875 {
1876     int count = 0;
1877     struct menucoloring *tmp = menu_colorings;
1878
1879     while (tmp) {
1880         count++;
1881         tmp = tmp->next;
1882     }
1883     return count;
1884 }
1885
1886 void
1887 parseoptions(opts, tinitial, tfrom_file)
1888 register char *opts;
1889 boolean tinitial, tfrom_file;
1890 {
1891     register char *op;
1892     unsigned num;
1893     boolean negated, val_negated, duplicate;
1894     int i;
1895     const char *fullname;
1896
1897     initial = tinitial;
1898     from_file = tfrom_file;
1899     if ((op = index(opts, ',')) != 0) {
1900         *op++ = 0;
1901         parseoptions(op, initial, from_file);
1902     }
1903     if (strlen(opts) > BUFSZ / 2) {
1904         badoption("option too long");
1905         return;
1906     }
1907
1908     /* strip leading and trailing white space */
1909     while (isspace((uchar) *opts))
1910         opts++;
1911     op = eos(opts);
1912     while (--op >= opts && isspace((uchar) *op))
1913         *op = '\0';
1914
1915     if (!*opts)
1916         return;
1917     negated = FALSE;
1918     while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
1919         if (*opts == '!')
1920             opts++;
1921         else
1922             opts += 2;
1923         negated = !negated;
1924     }
1925
1926     /* variant spelling */
1927
1928     if (match_optname(opts, "colour", 5, FALSE))
1929         Strcpy(opts, "color"); /* fortunately this isn't longer */
1930
1931     /* special boolean options */
1932
1933     if (match_optname(opts, "female", 3, FALSE)) {
1934         if (duplicate_opt_detection(opts, 0))
1935             complain_about_duplicate(opts, 0);
1936         if (!initial && flags.female == negated)
1937             pline("That is not anatomically possible.");
1938         else
1939             flags.initgend = flags.female = !negated;
1940         return;
1941     }
1942
1943     if (match_optname(opts, "male", 4, FALSE)) {
1944         if (duplicate_opt_detection(opts, 0))
1945             complain_about_duplicate(opts, 0);
1946         if (!initial && flags.female != negated)
1947             pline("That is not anatomically possible.");
1948         else
1949             flags.initgend = flags.female = negated;
1950         return;
1951     }
1952
1953 #if defined(MICRO) && !defined(AMIGA)
1954     /* included for compatibility with old NetHack.cnf files */
1955     if (match_optname(opts, "IBM_", 4, FALSE)) {
1956         iflags.BIOS = !negated;
1957         return;
1958     }
1959 #endif /* MICRO */
1960
1961     /* compound options */
1962
1963     /* This first batch can be duplicated if their values are negated */
1964
1965     /* align:string */
1966     fullname = "align";
1967     if (match_optname(opts, fullname, sizeof("align") - 1, TRUE)) {
1968         if (negated) {
1969             bad_negation(fullname, FALSE);
1970         } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1971             val_negated = FALSE;
1972             while ((*op == '!') || !strncmpi(op, "no", 2)) {
1973                 if (*op == '!')
1974                     op++;
1975                 else
1976                     op += 2;
1977                 val_negated = !val_negated;
1978             }
1979             if (val_negated) {
1980                 if (!setrolefilter(op))
1981                     badoption(opts);
1982             } else {
1983                 if (duplicate_opt_detection(opts, 1))
1984                     complain_about_duplicate(opts, 1);
1985                 if ((flags.initalign = str2align(op)) == ROLE_NONE)
1986                     badoption(opts);
1987             }
1988         }
1989         return;
1990     }
1991
1992     /* role:string or character:string */
1993     fullname = "role";
1994     if (match_optname(opts, fullname, 4, TRUE)
1995         || match_optname(opts, (fullname = "character"), 4, TRUE)) {
1996         if (negated) {
1997             bad_negation(fullname, FALSE);
1998         } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1999             val_negated = FALSE;
2000             while ((*op == '!') || !strncmpi(op, "no", 2)) {
2001                 if (*op == '!')
2002                     op++;
2003                 else
2004                     op += 2;
2005                 val_negated = !val_negated;
2006             }
2007             if (val_negated) {
2008                 if (!setrolefilter(op))
2009                     badoption(opts);
2010             } else {
2011                 if (duplicate_opt_detection(opts, 1))
2012                     complain_about_duplicate(opts, 1);
2013                 if ((flags.initrole = str2role(op)) == ROLE_NONE)
2014                     badoption(opts);
2015                 else /* Backwards compatibility */
2016                     nmcpy(pl_character, op, PL_NSIZ);
2017             }
2018         }
2019         return;
2020     }
2021
2022     /* race:string */
2023     fullname = "race";
2024     if (match_optname(opts, fullname, 4, TRUE)) {
2025         if (negated) {
2026             bad_negation(fullname, FALSE);
2027         } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
2028             val_negated = FALSE;
2029             while ((*op == '!') || !strncmpi(op, "no", 2)) {
2030                 if (*op == '!')
2031                     op++;
2032                 else
2033                     op += 2;
2034                 val_negated = !val_negated;
2035             }
2036             if (val_negated) {
2037                 if (!setrolefilter(op))
2038                     badoption(opts);
2039             } else {
2040                 if (duplicate_opt_detection(opts, 1))
2041                     complain_about_duplicate(opts, 1);
2042                 if ((flags.initrace = str2race(op)) == ROLE_NONE)
2043                     badoption(opts);
2044                 else /* Backwards compatibility */
2045                     pl_race = *op;
2046             }
2047         }
2048         return;
2049     }
2050
2051     /* gender:string */
2052     fullname = "gender";
2053     if (match_optname(opts, fullname, 4, TRUE)) {
2054         if (negated) {
2055             bad_negation(fullname, FALSE);
2056         } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
2057             val_negated = FALSE;
2058             while ((*op == '!') || !strncmpi(op, "no", 2)) {
2059                 if (*op == '!')
2060                     op++;
2061                 else
2062                     op += 2;
2063                 val_negated = !val_negated;
2064             }
2065             if (val_negated) {
2066                 if (!setrolefilter(op))
2067                     badoption(opts);
2068             } else {
2069                 if (duplicate_opt_detection(opts, 1))
2070                     complain_about_duplicate(opts, 1);
2071                 if ((flags.initgend = str2gend(op)) == ROLE_NONE)
2072                     badoption(opts);
2073                 else
2074                     flags.female = flags.initgend;
2075             }
2076         }
2077         return;
2078     }
2079
2080     /* We always check for duplicates on the remaining compound options,
2081        although individual option processing can choose to complain or not */
2082
2083     duplicate =
2084         duplicate_opt_detection(opts, 1); /* 1 means check compounds */
2085
2086     fullname = "pettype";
2087     if (match_optname(opts, fullname, 3, TRUE)) {
2088         if (duplicate)
2089             complain_about_duplicate(opts, 1);
2090         if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
2091             if (negated)
2092                 bad_negation(fullname, TRUE);
2093             else
2094                 switch (lowc(*op)) {
2095                 case 'd': /* dog */
2096                     preferred_pet = 'd';
2097                     break;
2098                 case 'c': /* cat */
2099                 case 'f': /* feline */
2100                     preferred_pet = 'c';
2101                     break;
2102                 case 'h': /* horse */
2103                 case 'q': /* quadruped */
2104                     /* avoids giving "unrecognized type of pet" but
2105                        pet_type(dog.c) won't actually honor this */
2106                     preferred_pet = 'h';
2107                     break;
2108                 case 'n': /* no pet */
2109                     preferred_pet = 'n';
2110                     break;
2111                 case '*': /* random */
2112                     preferred_pet = '\0';
2113                     break;
2114                 default:
2115 #if 0 /*JP*/
2116                     pline("Unrecognized pet type '%s'.", op);
2117 #else
2118                     pline("'%s'\82Í\83y\83b\83g\82Ì\8eí\97Þ\82Æ\82µ\82Ä\8eó\82¯\95t\82¯\82ç\82ê\82Ü\82¹\82ñ\81D", op);
2119 #endif
2120                     break;
2121                 }
2122         } else if (negated)
2123             preferred_pet = 'n';
2124         return;
2125     }
2126
2127     fullname = "catname";
2128     if (match_optname(opts, fullname, 3, TRUE)) {
2129         if (duplicate)
2130             complain_about_duplicate(opts, 1);
2131         if (negated)
2132             bad_negation(fullname, FALSE);
2133         else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
2134             nmcpy(catname, op, PL_PSIZ);
2135         sanitize_name(catname);
2136         return;
2137     }
2138
2139     fullname = "dogname";
2140     if (match_optname(opts, fullname, 3, TRUE)) {
2141         if (duplicate)
2142             complain_about_duplicate(opts, 1);
2143         if (negated)
2144             bad_negation(fullname, FALSE);
2145         else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
2146             nmcpy(dogname, op, PL_PSIZ);
2147         sanitize_name(dogname);
2148         return;
2149     }
2150
2151     fullname = "horsename";
2152     if (match_optname(opts, fullname, 5, TRUE)) {
2153         if (duplicate)
2154             complain_about_duplicate(opts, 1);
2155         if (negated)
2156             bad_negation(fullname, FALSE);
2157         else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
2158             nmcpy(horsename, op, PL_PSIZ);
2159         sanitize_name(horsename);
2160         return;
2161     }
2162
2163     fullname = "number_pad";
2164     if (match_optname(opts, fullname, 10, TRUE)) {
2165         boolean compat = (strlen(opts) <= 10);
2166
2167         if (duplicate)
2168             complain_about_duplicate(opts, 1);
2169         op = string_for_opt(opts, (compat || !initial));
2170         if (!op) {
2171             if (compat || negated || initial) {
2172                 /* for backwards compatibility, "number_pad" without a
2173                    value is a synonym for number_pad:1 */
2174                 iflags.num_pad = !negated;
2175                 iflags.num_pad_mode = 0;
2176             }
2177         } else if (negated) {
2178             bad_negation("number_pad", TRUE);
2179             return;
2180         } else {
2181             int mode = atoi(op);
2182
2183             if (mode < -1 || mode > 4 || (mode == 0 && *op != '0')) {
2184                 badoption(opts);
2185                 return;
2186             } else if (mode <= 0) {
2187                 iflags.num_pad = FALSE;
2188                 /* German keyboard; y and z keys swapped */
2189                 iflags.num_pad_mode = (mode < 0); /* 0 or 1 */
2190             } else {                              /* mode > 0 */
2191                 iflags.num_pad = TRUE;
2192                 iflags.num_pad_mode = 0;
2193                 /* PC Hack / MSDOS compatibility */
2194                 if (mode == 2 || mode == 4)
2195                     iflags.num_pad_mode |= 1;
2196                 /* phone keypad layout */
2197                 if (mode == 3 || mode == 4)
2198                     iflags.num_pad_mode |= 2;
2199             }
2200         }
2201         reset_commands(FALSE);
2202         number_pad(iflags.num_pad ? 1 : 0);
2203         return;
2204     }
2205
2206     fullname = "roguesymset";
2207     if (match_optname(opts, fullname, 7, TRUE)) {
2208         if (duplicate)
2209             complain_about_duplicate(opts, 1);
2210         if (negated) {
2211             bad_negation(fullname, FALSE);
2212         } else if ((op = string_for_opt(opts, FALSE)) != 0) {
2213             symset[ROGUESET].name = dupstr(op);
2214             if (!read_sym_file(ROGUESET)) {
2215                 clear_symsetentry(ROGUESET, TRUE);
2216                 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2217                            op, SYMBOLS);
2218                 wait_synch();
2219             } else {
2220                 if (!initial && Is_rogue_level(&u.uz))
2221                     assign_graphics(ROGUESET);
2222                 need_redraw = TRUE;
2223             }
2224         }
2225         return;
2226     }
2227
2228     fullname = "symset";
2229     if (match_optname(opts, fullname, 6, TRUE)) {
2230         if (duplicate)
2231             complain_about_duplicate(opts, 1);
2232         if (negated) {
2233             bad_negation(fullname, FALSE);
2234         } else if ((op = string_for_opt(opts, FALSE)) != 0) {
2235             symset[PRIMARY].name = dupstr(op);
2236             if (!read_sym_file(PRIMARY)) {
2237                 clear_symsetentry(PRIMARY, TRUE);
2238                 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2239                            op, SYMBOLS);
2240                 wait_synch();
2241             } else {
2242                 switch_symbols(TRUE);
2243                 need_redraw = TRUE;
2244             }
2245         }
2246         return;
2247     }
2248
2249     fullname = "runmode";
2250     if (match_optname(opts, fullname, 4, TRUE)) {
2251         if (duplicate)
2252             complain_about_duplicate(opts, 1);
2253         if (negated) {
2254             flags.runmode = RUN_TPORT;
2255         } else if ((op = string_for_opt(opts, FALSE)) != 0) {
2256             if (!strncmpi(op, "teleport", strlen(op)))
2257                 flags.runmode = RUN_TPORT;
2258             else if (!strncmpi(op, "run", strlen(op)))
2259                 flags.runmode = RUN_LEAP;
2260             else if (!strncmpi(op, "walk", strlen(op)))
2261                 flags.runmode = RUN_STEP;
2262             else if (!strncmpi(op, "crawl", strlen(op)))
2263                 flags.runmode = RUN_CRAWL;
2264             else
2265                 badoption(opts);
2266         }
2267         return;
2268     }
2269
2270     /* menucolor:"regex_string"=color */
2271     fullname = "menucolor";
2272     if (match_optname(opts, fullname, 9, TRUE)) {
2273         if (negated)
2274             bad_negation(fullname, FALSE);
2275         else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
2276             if (!add_menu_coloring(op))
2277                 badoption(opts);
2278         return;
2279     }
2280
2281     fullname = "msghistory";
2282     if (match_optname(opts, fullname, 3, TRUE)) {
2283         if (duplicate)
2284             complain_about_duplicate(opts, 1);
2285         op = string_for_env_opt(fullname, opts, negated);
2286         if ((negated && !op) || (!negated && op)) {
2287             iflags.msg_history = negated ? 0 : atoi(op);
2288         } else if (negated)
2289             bad_negation(fullname, TRUE);
2290         return;
2291     }
2292
2293     fullname = "msg_window";
2294     /* msg_window:single, combo, full or reversed */
2295     if (match_optname(opts, fullname, 4, TRUE)) {
2296 /* allow option to be silently ignored by non-tty ports */
2297 #ifdef TTY_GRAPHICS
2298         int tmp;
2299
2300         if (duplicate)
2301             complain_about_duplicate(opts, 1);
2302         if (!(op = string_for_opt(opts, TRUE))) {
2303             tmp = negated ? 's' : 'f';
2304         } else {
2305             if (negated) {
2306                 bad_negation(fullname, TRUE);
2307                 return;
2308             }
2309             tmp = tolower(*op);
2310         }
2311         switch (tmp) {
2312         case 's': /* single message history cycle (default if negated) */
2313             iflags.prevmsg_window = 's';
2314             break;
2315         case 'c': /* combination: two singles, then full page reversed */
2316             iflags.prevmsg_window = 'c';
2317             break;
2318         case 'f': /* full page (default if no opts) */
2319             iflags.prevmsg_window = 'f';
2320             break;
2321         case 'r': /* full page (reversed) */
2322             iflags.prevmsg_window = 'r';
2323             break;
2324         default:
2325             badoption(opts);
2326         }
2327 #endif
2328         return;
2329     }
2330
2331     /* WINCAP
2332      * setting font options  */
2333     fullname = "font";
2334     if (!strncmpi(opts, fullname, 4)) {
2335         int opttype = -1;
2336         char *fontopts = opts + 4;
2337
2338         if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4))
2339             opttype = MAP_OPTION;
2340         else if (!strncmpi(fontopts, "message", 7)
2341                  || !strncmpi(fontopts, "_message", 8))
2342             opttype = MESSAGE_OPTION;
2343         else if (!strncmpi(fontopts, "text", 4)
2344                  || !strncmpi(fontopts, "_text", 5))
2345             opttype = TEXT_OPTION;
2346         else if (!strncmpi(fontopts, "menu", 4)
2347                  || !strncmpi(fontopts, "_menu", 5))
2348             opttype = MENU_OPTION;
2349         else if (!strncmpi(fontopts, "status", 6)
2350                  || !strncmpi(fontopts, "_status", 7))
2351             opttype = STATUS_OPTION;
2352         else if (!strncmpi(fontopts, "_size", 5)) {
2353             if (!strncmpi(fontopts, "_size_map", 8))
2354                 opttype = MAP_OPTION;
2355             else if (!strncmpi(fontopts, "_size_message", 12))
2356                 opttype = MESSAGE_OPTION;
2357             else if (!strncmpi(fontopts, "_size_text", 9))
2358                 opttype = TEXT_OPTION;
2359             else if (!strncmpi(fontopts, "_size_menu", 9))
2360                 opttype = MENU_OPTION;
2361             else if (!strncmpi(fontopts, "_size_status", 11))
2362                 opttype = STATUS_OPTION;
2363             else {
2364                 badoption(opts);
2365                 return;
2366             }
2367             if (duplicate)
2368                 complain_about_duplicate(opts, 1);
2369             if (opttype > 0 && !negated
2370                 && (op = string_for_opt(opts, FALSE)) != 0) {
2371                 switch (opttype) {
2372                 case MAP_OPTION:
2373                     iflags.wc_fontsiz_map = atoi(op);
2374                     break;
2375                 case MESSAGE_OPTION:
2376                     iflags.wc_fontsiz_message = atoi(op);
2377                     break;
2378                 case TEXT_OPTION:
2379                     iflags.wc_fontsiz_text = atoi(op);
2380                     break;
2381                 case MENU_OPTION:
2382                     iflags.wc_fontsiz_menu = atoi(op);
2383                     break;
2384                 case STATUS_OPTION:
2385                     iflags.wc_fontsiz_status = atoi(op);
2386                     break;
2387                 }
2388             }
2389             return;
2390         } else {
2391             badoption(opts);
2392         }
2393         if (opttype > 0 && (op = string_for_opt(opts, FALSE)) != 0) {
2394             wc_set_font_name(opttype, op);
2395 #ifdef MAC
2396             set_font_name(opttype, op);
2397 #endif
2398             return;
2399         } else if (negated)
2400             bad_negation(fullname, TRUE);
2401         return;
2402     }
2403 #ifdef CHANGE_COLOR
2404     if (match_optname(opts, "palette", 3, TRUE)
2405 #ifdef MAC
2406         || match_optname(opts, "hicolor", 3, TRUE)
2407 #endif
2408             ) {
2409         int color_number, color_incr;
2410
2411 #ifndef WIN32
2412         if (duplicate)
2413             complain_about_duplicate(opts, 1);
2414 #endif
2415 #ifdef MAC
2416         if (match_optname(opts, "hicolor", 3, TRUE)) {
2417             if (negated) {
2418                 bad_negation("hicolor", FALSE);
2419                 return;
2420             }
2421             color_number = CLR_MAX + 4; /* HARDCODED inverse number */
2422             color_incr = -1;
2423         } else {
2424 #endif
2425             if (negated) {
2426                 bad_negation("palette", FALSE);
2427                 return;
2428             }
2429             color_number = 0;
2430             color_incr = 1;
2431 #ifdef MAC
2432         }
2433 #endif
2434 #ifdef WIN32
2435         op = string_for_opt(opts, TRUE);
2436         if (!alternative_palette(op))
2437             badoption(opts);
2438 #else
2439         if ((op = string_for_opt(opts, FALSE)) != (char *) 0) {
2440             char *pt = op;
2441             int cnt, tmp, reverse;
2442             long rgb;
2443
2444             while (*pt && color_number >= 0) {
2445                 cnt = 3;
2446                 rgb = 0L;
2447                 if (*pt == '-') {
2448                     reverse = 1;
2449                     pt++;
2450                 } else {
2451                     reverse = 0;
2452                 }
2453                 while (cnt-- > 0) {
2454                     if (*pt && *pt != '/') {
2455 #ifdef AMIGA
2456                         rgb <<= 4;
2457 #else
2458                         rgb <<= 8;
2459 #endif
2460                         tmp = *(pt++);
2461                         if (isalpha(tmp)) {
2462                             tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
2463                         } else {
2464                             tmp &= 0xf; /* Digits in ASCII too... */
2465                         }
2466 #ifndef AMIGA
2467                         /* Add an extra so we fill f -> ff and 0 -> 00 */
2468                         rgb += tmp << 4;
2469 #endif
2470                         rgb += tmp;
2471                     }
2472                 }
2473                 if (*pt == '/') {
2474                     pt++;
2475                 }
2476                 change_color(color_number, rgb, reverse);
2477                 color_number += color_incr;
2478             }
2479         }
2480 #endif /* !WIN32 */
2481         if (!initial) {
2482             need_redraw = TRUE;
2483         }
2484         return;
2485     }
2486 #endif /* CHANGE_COLOR */
2487
2488     if (match_optname(opts, "fruit", 2, TRUE)) {
2489         struct fruit *forig = 0;
2490         char empty_str = '\0';
2491
2492         if (duplicate)
2493             complain_about_duplicate(opts, 1);
2494         op = string_for_opt(opts, negated);
2495         if (negated) {
2496             if (op) {
2497                 bad_negation("fruit", TRUE);
2498                 return;
2499             }
2500             op = &empty_str;
2501             goto goodfruit;
2502         }
2503         if (!op)
2504             return;
2505         if (!initial) {
2506             struct fruit *f;
2507
2508             num = 0;
2509             for (f = ffruit; f; f = f->nextf) {
2510                 if (!strcmp(op, f->fname))
2511                     break;
2512                 num++;
2513             }
2514             if (!flags.made_fruit) {
2515                 for (forig = ffruit; forig; forig = forig->nextf) {
2516                     if (!strcmp(pl_fruit, forig->fname)) {
2517                         break;
2518                     }
2519                 }
2520             }
2521             if (!forig && num >= 100) {
2522 /*JP
2523                 pline("Doing that so many times isn't very fruitful.");
2524 */
2525                 pline("\82»\82ñ\82È\82É\89½\89ñ\82à\82â\82Á\82Ä\82à\82Ù\82Æ\82ñ\82Ç\88Ó\96¡\82Í\82È\82¢\81D");
2526                 return;
2527             }
2528         }
2529     goodfruit:
2530         nmcpy(pl_fruit, op, PL_FSIZ);
2531         sanitize_name(pl_fruit);
2532         /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
2533         if (!*pl_fruit)
2534             nmcpy(pl_fruit, "slime mold", PL_FSIZ);
2535         if (!initial) {
2536             (void) fruitadd(pl_fruit, forig);
2537             pline("Fruit is now \"%s\".", pl_fruit);
2538         }
2539         /* If initial, then initoptions is allowed to do it instead
2540          * of here (initoptions always has to do it even if there's
2541          * no fruit option at all.  Also, we don't want people
2542          * setting multiple fruits in their options.)
2543          */
2544         return;
2545     }
2546
2547     fullname = "warnings";
2548     if (match_optname(opts, fullname, 5, TRUE)) {
2549         if (duplicate)
2550             complain_about_duplicate(opts, 1);
2551         if (negated)
2552             bad_negation(fullname, FALSE);
2553         else
2554             warning_opts(opts, fullname);
2555         return;
2556     }
2557
2558 #ifdef BACKWARD_COMPAT
2559     /* boulder:symbol */
2560     fullname = "boulder";
2561     if (match_optname(opts, fullname, 7, TRUE)) {
2562         int clash = 0;
2563         if (duplicate)
2564             complain_about_duplicate(opts, 1);
2565         if (negated) {
2566             bad_negation(fullname, FALSE);
2567             return;
2568         }
2569         /* if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
2570          */
2571         if (!(opts = string_for_opt(opts, FALSE)))
2572             return;
2573         escapes(opts, opts);
2574         if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
2575             clash = 1;
2576         else if (opts[0] >= '1' && opts[0] <= '5')
2577             clash = 2;
2578         if (clash) {
2579             /* symbol chosen matches a used monster or warning
2580                symbol which is not good - reject it*/
2581             pline(
2582                 "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
2583                 opts[0], (clash == 1) ? "monster" : "warning");
2584         } else {
2585             /*
2586              * Override the default boulder symbol.
2587              */
2588             iflags.bouldersym = (uchar) opts[0];
2589         }
2590         if (!initial)
2591             need_redraw = TRUE;
2592         return;
2593     }
2594 #endif
2595
2596     /* name:string */
2597     fullname = "name";
2598     if (match_optname(opts, fullname, 4, TRUE)) {
2599         if (duplicate)
2600             complain_about_duplicate(opts, 1);
2601         if (negated)
2602             bad_negation(fullname, FALSE);
2603         else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
2604             nmcpy(plname, op, PL_NSIZ);
2605         return;
2606     }
2607
2608     /* altkeyhandler:string */
2609     fullname = "altkeyhandler";
2610     if (match_optname(opts, fullname, 4, TRUE)) {
2611         if (duplicate)
2612             complain_about_duplicate(opts, 1);
2613         if (negated) {
2614             bad_negation(fullname, FALSE);
2615         } else if ((op = string_for_opt(opts, negated)) != 0) {
2616 #ifdef WIN32
2617             (void) strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
2618             load_keyboard_handler();
2619 #endif
2620         }
2621         return;
2622     }
2623
2624     /* WINCAP
2625      * align_status:[left|top|right|bottom] */
2626     fullname = "align_status";
2627     if (match_optname(opts, fullname, sizeof("align_status") - 1, TRUE)) {
2628         op = string_for_opt(opts, negated);
2629         if (op && !negated) {
2630             if (!strncmpi(op, "left", sizeof("left") - 1))
2631                 iflags.wc_align_status = ALIGN_LEFT;
2632             else if (!strncmpi(op, "top", sizeof("top") - 1))
2633                 iflags.wc_align_status = ALIGN_TOP;
2634             else if (!strncmpi(op, "right", sizeof("right") - 1))
2635                 iflags.wc_align_status = ALIGN_RIGHT;
2636             else if (!strncmpi(op, "bottom", sizeof("bottom") - 1))
2637                 iflags.wc_align_status = ALIGN_BOTTOM;
2638             else
2639                 badoption(opts);
2640         } else if (negated)
2641             bad_negation(fullname, TRUE);
2642         return;
2643     }
2644     /* WINCAP
2645      * align_message:[left|top|right|bottom] */
2646     fullname = "align_message";
2647     if (match_optname(opts, fullname, sizeof("align_message") - 1, TRUE)) {
2648         if (duplicate)
2649             complain_about_duplicate(opts, 1);
2650         op = string_for_opt(opts, negated);
2651         if (op && !negated) {
2652             if (!strncmpi(op, "left", sizeof("left") - 1))
2653                 iflags.wc_align_message = ALIGN_LEFT;
2654             else if (!strncmpi(op, "top", sizeof("top") - 1))
2655                 iflags.wc_align_message = ALIGN_TOP;
2656             else if (!strncmpi(op, "right", sizeof("right") - 1))
2657                 iflags.wc_align_message = ALIGN_RIGHT;
2658             else if (!strncmpi(op, "bottom", sizeof("bottom") - 1))
2659                 iflags.wc_align_message = ALIGN_BOTTOM;
2660             else
2661                 badoption(opts);
2662         } else if (negated)
2663             bad_negation(fullname, TRUE);
2664         return;
2665     }
2666     /* the order to list the pack */
2667     fullname = "packorder";
2668     if (match_optname(opts, fullname, 4, TRUE)) {
2669         if (duplicate)
2670             complain_about_duplicate(opts, 1);
2671         if (negated) {
2672             bad_negation(fullname, FALSE);
2673             return;
2674         } else if (!(op = string_for_opt(opts, FALSE)))
2675             return;
2676
2677         if (!change_inv_order(op))
2678             badoption(opts);
2679         return;
2680     }
2681
2682     /* user can change required response for some prompts (quit, die, hit),
2683        or add an extra prompt (pray, Remove) that isn't ordinarily there */
2684     fullname = "paranoid_confirmation";
2685     if (match_optname(opts, fullname, 8, TRUE)) {
2686         /* at present we don't complain about duplicates for this
2687            option, but we do throw away the old settings whenever
2688            we process a new one [clearing old flags is essential
2689            for handling default paranoid_confirm:pray sanely] */
2690         flags.paranoia_bits = 0; /* clear all */
2691         if (negated) {
2692             flags.paranoia_bits = 0; /* [now redundant...] */
2693         } else if ((op = string_for_opt(opts, TRUE)) != 0) {
2694             char *pp, buf[BUFSZ];
2695
2696             op = mungspaces(strcpy(buf, op));
2697             for (;;) {
2698                 /* We're looking to parse
2699                    "paranoid_confirm:whichone wheretwo whothree"
2700                    and "paranoid_confirm:" prefix has already
2701                    been stripped off by the time we get here */
2702                 pp = index(op, ' ');
2703                 if (pp)
2704                     *pp = '\0';
2705                 /* we aren't matching option names but match_optname
2706                    does what we want once we've broken the space
2707                    delimited aggregate into separate tokens */
2708                 for (i = 0; i < SIZE(paranoia); ++i) {
2709                     if (match_optname(op, paranoia[i].argname,
2710                                       paranoia[i].argMinLen, FALSE)
2711                         || (paranoia[i].synonym
2712                             && match_optname(op, paranoia[i].synonym,
2713                                              paranoia[i].synMinLen, FALSE))) {
2714                         if (paranoia[i].flagmask)
2715                             flags.paranoia_bits |= paranoia[i].flagmask;
2716                         else /* 0 == "none", so clear all */
2717                             flags.paranoia_bits = 0;
2718                         break;
2719                     }
2720                 }
2721                 if (i == SIZE(paranoia)) {
2722                     /* didn't match anything, so arg is bad;
2723                        any flags already set will stay set */
2724                     badoption(opts);
2725                     break;
2726                 }
2727                 /* move on to next token */
2728                 if (pp)
2729                     op = pp + 1;
2730                 else
2731                     break; /* no next token */
2732             }              /* for(;;) */
2733         }
2734         return;
2735     }
2736
2737     /* accept deprecated boolean; superseded by paranoid_confirm:pray */
2738     fullname = "prayconfirm";
2739     if (match_optname(opts, fullname, 4, FALSE)) {
2740         if (negated)
2741             flags.paranoia_bits &= ~PARANOID_PRAY;
2742         else
2743             flags.paranoia_bits |= PARANOID_PRAY;
2744         return;
2745     }
2746
2747     /* maximum burden picked up before prompt (Warren Cheung) */
2748     fullname = "pickup_burden";
2749     if (match_optname(opts, fullname, 8, TRUE)) {
2750         if (duplicate)
2751             complain_about_duplicate(opts, 1);
2752         if (negated) {
2753             bad_negation(fullname, FALSE);
2754             return;
2755         } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
2756             switch (tolower(*op)) {
2757             /* Unencumbered */
2758             case 'u':
2759                 flags.pickup_burden = UNENCUMBERED;
2760                 break;
2761             /* Burdened (slight encumbrance) */
2762             case 'b':
2763                 flags.pickup_burden = SLT_ENCUMBER;
2764                 break;
2765             /* streSsed (moderate encumbrance) */
2766             case 's':
2767                 flags.pickup_burden = MOD_ENCUMBER;
2768                 break;
2769             /* straiNed (heavy encumbrance) */
2770             case 'n':
2771                 flags.pickup_burden = HVY_ENCUMBER;
2772                 break;
2773             /* OverTaxed (extreme encumbrance) */
2774             case 'o':
2775             case 't':
2776                 flags.pickup_burden = EXT_ENCUMBER;
2777                 break;
2778             /* overLoaded */
2779             case 'l':
2780                 flags.pickup_burden = OVERLOADED;
2781                 break;
2782             default:
2783                 badoption(opts);
2784             }
2785         }
2786         return;
2787     }
2788
2789     /* types of objects to pick up automatically */
2790     if (match_optname(opts, "pickup_types", 8, TRUE)) {
2791         char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], qbuf[QBUFSZ],
2792             abuf[BUFSZ];
2793         int oc_sym;
2794         boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
2795
2796         if (duplicate)
2797             complain_about_duplicate(opts, 1);
2798         oc_to_str(flags.pickup_types, tbuf);
2799         flags.pickup_types[0] = '\0'; /* all */
2800         op = string_for_opt(opts, (compat || !initial));
2801         if (!op) {
2802             if (compat || negated || initial) {
2803                 /* for backwards compatibility, "pickup" without a
2804                    value is a synonym for autopickup of all types
2805                    (and during initialization, we can't prompt yet) */
2806                 flags.pickup = !negated;
2807                 return;
2808             }
2809             oc_to_str(flags.inv_order, ocl);
2810             use_menu = TRUE;
2811             if (flags.menu_style == MENU_TRADITIONAL
2812                 || flags.menu_style == MENU_COMBINATION) {
2813                 use_menu = FALSE;
2814 #if 0 /*JP*/
2815                 Sprintf(qbuf, "New pickup_types: [%s am] (%s)", ocl,
2816                         *tbuf ? tbuf : "all");
2817 #else
2818                 Sprintf(qbuf, "\90V\82µ\82¢pickup_type\82ð\93ü\97Í\82µ\82Ä\82­\82¾\82³\82¢\81F[%s am] (%s)", ocl,
2819                         *tbuf ? tbuf : "all");
2820 #endif
2821                 getlin(qbuf, abuf);
2822                 op = mungspaces(abuf);
2823                 if (abuf[0] == '\0' || abuf[0] == '\033')
2824                     op = tbuf; /* restore */
2825                 else if (abuf[0] == 'm')
2826                     use_menu = TRUE;
2827             }
2828             if (use_menu) {
2829 #if 0 /*JP*/
2830                 (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE, ocl,
2831                                            tbuf);
2832 #else
2833                 (void) choose_classes_menu("\82Ç\82ê\82ð\8e©\93®\8fE\82¢\82É\90Ý\92è\82·\82é\81H", 1, TRUE, ocl,
2834                                            tbuf);
2835 #endif
2836                 op = tbuf;
2837             }
2838         }
2839         if (negated) {
2840             bad_negation("pickup_types", TRUE);
2841             return;
2842         }
2843         while (*op == ' ')
2844             op++;
2845         if (*op != 'a' && *op != 'A') {
2846             num = 0;
2847             while (*op) {
2848                 oc_sym = def_char_to_objclass(*op);
2849                 /* make sure all are valid obj symbols occurring once */
2850                 if (oc_sym != MAXOCLASSES
2851                     && !index(flags.pickup_types, oc_sym)) {
2852                     flags.pickup_types[num] = (char) oc_sym;
2853                     flags.pickup_types[++num] = '\0';
2854                 } else
2855                     badopt = TRUE;
2856                 op++;
2857             }
2858             if (badopt)
2859                 badoption(opts);
2860         }
2861         return;
2862     }
2863
2864     /* pile limit: when walking over objects, number which triggers
2865        "there are several/many objects here" instead of listing them */
2866     fullname = "pile_limit";
2867     if (match_optname(opts, fullname, 4, TRUE)) {
2868         if (duplicate)
2869             complain_about_duplicate(opts, 1);
2870         op = string_for_opt(opts, negated);
2871         if ((negated && !op) || (!negated && op))
2872             flags.pile_limit = negated ? 0 : atoi(op);
2873         else if (negated)
2874             bad_negation(fullname, TRUE);
2875         else /* !op */
2876             flags.pile_limit = PILE_LIMIT_DFLT;
2877         /* sanity check */
2878         if (flags.pile_limit < 0)
2879             flags.pile_limit = PILE_LIMIT_DFLT;
2880         return;
2881     }
2882
2883     /* play mode: normal, explore/discovery, or debug/wizard */
2884     fullname = "playmode";
2885     if (match_optname(opts, fullname, 4, TRUE)) {
2886         if (duplicate)
2887             complain_about_duplicate(opts, 1);
2888         if (negated)
2889             bad_negation(fullname, FALSE);
2890         if (duplicate || negated)
2891             return;
2892         op = string_for_opt(opts, TRUE);
2893         if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) {
2894             wizard = discover = FALSE;
2895         } else if (!strncmpi(op, "explore", 6)
2896                    || !strncmpi(op, "discovery", 6)) {
2897             wizard = FALSE, discover = TRUE;
2898         } else if (!strncmpi(op, "debug", 5) || !strncmpi(op, "wizard", 6)) {
2899             wizard = TRUE, discover = FALSE;
2900         } else {
2901             raw_printf("Invalid value for \"%s\":%s.", fullname, op);
2902         }
2903         return;
2904     }
2905
2906     /* WINCAP
2907      * player_selection: dialog | prompts */
2908     fullname = "player_selection";
2909     if (match_optname(opts, fullname, sizeof("player_selection") - 1, TRUE)) {
2910         if (duplicate)
2911             complain_about_duplicate(opts, 1);
2912         op = string_for_opt(opts, negated);
2913         if (op && !negated) {
2914             if (!strncmpi(op, "dialog", sizeof("dialog") - 1))
2915                 iflags.wc_player_selection = VIA_DIALOG;
2916             else if (!strncmpi(op, "prompt", sizeof("prompt") - 1))
2917                 iflags.wc_player_selection = VIA_PROMPTS;
2918             else
2919                 badoption(opts);
2920         } else if (negated)
2921             bad_negation(fullname, TRUE);
2922         return;
2923     }
2924
2925     /* things to disclose at end of game */
2926     if (match_optname(opts, "disclose", 7, TRUE)) {
2927         /*
2928          * The order that the end_disclose options are stored:
2929          *      inventory, attribs, vanquished, genocided,
2930          *      conduct, overview.
2931          * There is an array in flags:
2932          *      end_disclose[NUM_DISCLOSURE_OPT];
2933          * with option settings for the each of the following:
2934          * iagvc [see disclosure_options in decl.c]:
2935          * Legal setting values in that array are:
2936          *      DISCLOSE_PROMPT_DEFAULT_YES  ask with default answer yes
2937          *      DISCLOSE_PROMPT_DEFAULT_NO   ask with default answer no
2938          *      DISCLOSE_YES_WITHOUT_PROMPT  always disclose and don't ask
2939          *      DISCLOSE_NO_WITHOUT_PROMPT   never disclose and don't ask
2940          *
2941          * Those setting values can be used in the option
2942          * string as a prefix to get the desired behaviour.
2943          *
2944          * For backward compatibility, no prefix is required,
2945          * and the presence of a i,a,g,v, or c without a prefix
2946          * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
2947          */
2948         boolean badopt = FALSE;
2949         int idx, prefix_val;
2950
2951         if (duplicate)
2952             complain_about_duplicate(opts, 1);
2953         op = string_for_opt(opts, TRUE);
2954         if (op && negated) {
2955             bad_negation("disclose", TRUE);
2956             return;
2957         }
2958         /* "disclose" without a value means "all with prompting"
2959            and negated means "none without prompting" */
2960         if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
2961             if (op && !strcmpi(op, "none"))
2962                 negated = TRUE;
2963             for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
2964                 flags.end_disclose[num] = negated
2965                                               ? DISCLOSE_NO_WITHOUT_PROMPT
2966                                               : DISCLOSE_PROMPT_DEFAULT_YES;
2967             return;
2968         }
2969
2970         num = 0;
2971         prefix_val = -1;
2972         while (*op && num < sizeof flags.end_disclose - 1) {
2973             static char valid_settings[] = {
2974                 DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO,
2975                 DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT, '\0'
2976             };
2977             register char c, *dop;
2978
2979             c = lowc(*op);
2980             if (c == 'k')
2981                 c = 'v'; /* killed -> vanquished */
2982             if (c == 'd')
2983                 c = 'o'; /* dungeon -> overview */
2984             dop = index(disclosure_options, c);
2985             if (dop) {
2986                 idx = (int) (dop - disclosure_options);
2987                 if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
2988                     impossible("bad disclosure index %d %c", idx, c);
2989                     continue;
2990                 }
2991                 if (prefix_val != -1) {
2992                     flags.end_disclose[idx] = prefix_val;
2993                     prefix_val = -1;
2994                 } else
2995                     flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
2996             } else if (index(valid_settings, c)) {
2997                 prefix_val = c;
2998             } else if (c == ' ') {
2999                 ; /* do nothing */
3000             } else
3001                 badopt = TRUE;
3002             op++;
3003         }
3004         if (badopt)
3005             badoption(opts);
3006         return;
3007     }
3008 #if 1 /*JP*/
3009     if (!strncmpi(opts, "kcode", 3)){
3010         if ((op = string_for_env_opt("kcode", opts, FALSE)) != 0){
3011             setkcode(*op);
3012         }
3013         return;
3014     }
3015 #endif
3016
3017     /* scores:5t[op] 5a[round] o[wn] */
3018     if (match_optname(opts, "scores", 4, TRUE)) {
3019         if (duplicate)
3020             complain_about_duplicate(opts, 1);
3021         if (negated) {
3022             bad_negation("scores", FALSE);
3023             return;
3024         }
3025         if (!(op = string_for_opt(opts, FALSE)))
3026             return;
3027
3028         while (*op) {
3029             int inum = 1;
3030
3031             if (digit(*op)) {
3032                 inum = atoi(op);
3033                 while (digit(*op))
3034                     op++;
3035             } else if (*op == '!') {
3036                 negated = !negated;
3037                 op++;
3038             }
3039             while (*op == ' ')
3040                 op++;
3041
3042             switch (*op) {
3043             case 't':
3044             case 'T':
3045                 flags.end_top = inum;
3046                 break;
3047             case 'a':
3048             case 'A':
3049                 flags.end_around = inum;
3050                 break;
3051             case 'o':
3052             case 'O':
3053                 flags.end_own = !negated;
3054                 break;
3055             default:
3056                 badoption(opts);
3057                 return;
3058             }
3059             while (letter(*++op) || *op == ' ')
3060                 continue;
3061             if (*op == '/')
3062                 op++;
3063         }
3064         return;
3065     }
3066
3067     fullname = "sortloot";
3068     if (match_optname(opts, fullname, 4, TRUE)) {
3069         op = string_for_env_opt(fullname, opts, FALSE);
3070         if (op) {
3071             switch (tolower(*op)) {
3072             case 'n':
3073             case 'l':
3074             case 'f':
3075                 flags.sortloot = tolower(*op);
3076                 break;
3077             default:
3078                 badoption(opts);
3079                 return;
3080             }
3081         }
3082         return;
3083     }
3084
3085     fullname = "suppress_alert";
3086     if (match_optname(opts, fullname, 4, TRUE)) {
3087         if (duplicate)
3088             complain_about_duplicate(opts, 1);
3089         op = string_for_opt(opts, negated);
3090         if (negated)
3091             bad_negation(fullname, FALSE);
3092         else if (op)
3093             (void) feature_alert_opts(op, fullname);
3094         return;
3095     }
3096
3097 #ifdef VIDEOSHADES
3098     /* videocolors:string */
3099     fullname = "videocolors";
3100     if (match_optname(opts, fullname, 6, TRUE)
3101         || match_optname(opts, "videocolours", 10, TRUE)) {
3102         if (duplicate)
3103             complain_about_duplicate(opts, 1);
3104         if (negated) {
3105             bad_negation(fullname, FALSE);
3106             return;
3107         } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
3108             return;
3109         }
3110         if (!assign_videocolors(opts))
3111             badoption(opts);
3112         return;
3113     }
3114     /* videoshades:string */
3115     fullname = "videoshades";
3116     if (match_optname(opts, fullname, 6, TRUE)) {
3117         if (duplicate)
3118             complain_about_duplicate(opts, 1);
3119         if (negated) {
3120             bad_negation(fullname, FALSE);
3121             return;
3122         } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
3123             return;
3124         }
3125         if (!assign_videoshades(opts))
3126             badoption(opts);
3127         return;
3128     }
3129 #endif /* VIDEOSHADES */
3130 #ifdef MSDOS
3131 #ifdef NO_TERMS
3132     /* video:string -- must be after longer tests */
3133     fullname = "video";
3134     if (match_optname(opts, fullname, 5, TRUE)) {
3135         if (duplicate)
3136             complain_about_duplicate(opts, 1);
3137         if (negated) {
3138             bad_negation(fullname, FALSE);
3139             return;
3140         } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
3141             return;
3142         }
3143         if (!assign_video(opts))
3144             badoption(opts);
3145         return;
3146     }
3147 #endif /* NO_TERMS */
3148     /* soundcard:string -- careful not to match boolean 'sound' */
3149     fullname = "soundcard";
3150     if (match_optname(opts, fullname, 6, TRUE)) {
3151         if (duplicate)
3152             complain_about_duplicate(opts, 1);
3153         if (negated) {
3154             bad_negation(fullname, FALSE);
3155             return;
3156         } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
3157             return;
3158         }
3159         if (!assign_soundcard(opts))
3160             badoption(opts);
3161         return;
3162     }
3163 #endif /* MSDOS */
3164
3165     /* WINCAP
3166      *
3167      *  map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|
3168      *            ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen]
3169      */
3170     fullname = "map_mode";
3171     if (match_optname(opts, fullname, sizeof("map_mode") - 1, TRUE)) {
3172         if (duplicate)
3173             complain_about_duplicate(opts, 1);
3174         op = string_for_opt(opts, negated);
3175         if (op && !negated) {
3176             if (!strncmpi(op, "tiles", sizeof("tiles") - 1))
3177                 iflags.wc_map_mode = MAP_MODE_TILES;
3178             else if (!strncmpi(op, "ascii4x6", sizeof("ascii4x6") - 1))
3179                 iflags.wc_map_mode = MAP_MODE_ASCII4x6;
3180             else if (!strncmpi(op, "ascii6x8", sizeof("ascii6x8") - 1))
3181                 iflags.wc_map_mode = MAP_MODE_ASCII6x8;
3182             else if (!strncmpi(op, "ascii8x8", sizeof("ascii8x8") - 1))
3183                 iflags.wc_map_mode = MAP_MODE_ASCII8x8;
3184             else if (!strncmpi(op, "ascii16x8", sizeof("ascii16x8") - 1))
3185                 iflags.wc_map_mode = MAP_MODE_ASCII16x8;
3186             else if (!strncmpi(op, "ascii7x12", sizeof("ascii7x12") - 1))
3187                 iflags.wc_map_mode = MAP_MODE_ASCII7x12;
3188             else if (!strncmpi(op, "ascii8x12", sizeof("ascii8x12") - 1))
3189                 iflags.wc_map_mode = MAP_MODE_ASCII8x12;
3190             else if (!strncmpi(op, "ascii16x12", sizeof("ascii16x12") - 1))
3191                 iflags.wc_map_mode = MAP_MODE_ASCII16x12;
3192             else if (!strncmpi(op, "ascii12x16", sizeof("ascii12x16") - 1))
3193                 iflags.wc_map_mode = MAP_MODE_ASCII12x16;
3194             else if (!strncmpi(op, "ascii10x18", sizeof("ascii10x18") - 1))
3195                 iflags.wc_map_mode = MAP_MODE_ASCII10x18;
3196             else if (!strncmpi(op, "fit_to_screen",
3197                                sizeof("fit_to_screen") - 1))
3198                 iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
3199             else
3200                 badoption(opts);
3201         } else if (negated)
3202             bad_negation(fullname, TRUE);
3203         return;
3204     }
3205     /* WINCAP
3206      * scroll_amount:nn */
3207     fullname = "scroll_amount";
3208     if (match_optname(opts, fullname, sizeof("scroll_amount") - 1, TRUE)) {
3209         if (duplicate)
3210             complain_about_duplicate(opts, 1);
3211         op = string_for_opt(opts, negated);
3212         if ((negated && !op) || (!negated && op)) {
3213             iflags.wc_scroll_amount = negated ? 1 : atoi(op);
3214         } else if (negated)
3215             bad_negation(fullname, TRUE);
3216         return;
3217     }
3218     /* WINCAP
3219      * scroll_margin:nn */
3220     fullname = "scroll_margin";
3221     if (match_optname(opts, fullname, sizeof("scroll_margin") - 1, TRUE)) {
3222         if (duplicate)
3223             complain_about_duplicate(opts, 1);
3224         op = string_for_opt(opts, negated);
3225         if ((negated && !op) || (!negated && op)) {
3226             iflags.wc_scroll_margin = negated ? 5 : atoi(op);
3227         } else if (negated)
3228             bad_negation(fullname, TRUE);
3229         return;
3230     }
3231     fullname = "subkeyvalue";
3232     if (match_optname(opts, fullname, 5, TRUE)) {
3233         /* no duplicate complaint here */
3234         if (negated) {
3235             bad_negation(fullname, FALSE);
3236         } else {
3237 #if defined(WIN32)
3238             op = string_for_opt(opts, 0);
3239             map_subkeyvalue(op);
3240 #endif
3241         }
3242         return;
3243     }
3244     /* WINCAP
3245      * tile_width:nn */
3246     fullname = "tile_width";
3247     if (match_optname(opts, fullname, sizeof("tile_width") - 1, TRUE)) {
3248         if (duplicate)
3249             complain_about_duplicate(opts, 1);
3250         op = string_for_opt(opts, negated);
3251         if ((negated && !op) || (!negated && op)) {
3252             iflags.wc_tile_width = negated ? 0 : atoi(op);
3253         } else if (negated)
3254             bad_negation(fullname, TRUE);
3255         return;
3256     }
3257     /* WINCAP
3258      * tile_file:name */
3259     fullname = "tile_file";
3260     if (match_optname(opts, fullname, sizeof("tile_file") - 1, TRUE)) {
3261         if (duplicate)
3262             complain_about_duplicate(opts, 1);
3263         if ((op = string_for_opt(opts, FALSE)) != 0) {
3264             if (iflags.wc_tile_file)
3265                 free(iflags.wc_tile_file);
3266             iflags.wc_tile_file = (char *) alloc(strlen(op) + 1);
3267             Strcpy(iflags.wc_tile_file, op);
3268         }
3269         return;
3270     }
3271     /* WINCAP
3272      * tile_height:nn */
3273     fullname = "tile_height";
3274     if (match_optname(opts, fullname, sizeof("tile_height") - 1, TRUE)) {
3275         if (duplicate)
3276             complain_about_duplicate(opts, 1);
3277         op = string_for_opt(opts, negated);
3278         if ((negated && !op) || (!negated && op)) {
3279             iflags.wc_tile_height = negated ? 0 : atoi(op);
3280         } else if (negated)
3281             bad_negation(fullname, TRUE);
3282         return;
3283     }
3284     /* WINCAP
3285      * vary_msgcount:nn */
3286     fullname = "vary_msgcount";
3287     if (match_optname(opts, fullname, sizeof("vary_msgcount") - 1, TRUE)) {
3288         if (duplicate)
3289             complain_about_duplicate(opts, 1);
3290         op = string_for_opt(opts, negated);
3291         if ((negated && !op) || (!negated && op)) {
3292             iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
3293         } else if (negated)
3294             bad_negation(fullname, TRUE);
3295         return;
3296     }
3297     fullname = "windowtype";
3298     if (match_optname(opts, fullname, 3, TRUE)) {
3299         if (duplicate)
3300             complain_about_duplicate(opts, 1);
3301         if (negated) {
3302             bad_negation(fullname, FALSE);
3303             return;
3304         } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
3305             char buf[WINTYPELEN];
3306             nmcpy(buf, op, WINTYPELEN);
3307             choose_windows(buf);
3308         }
3309         return;
3310     }
3311 #ifdef WINCHAIN
3312     fullname = "windowchain";
3313     if (match_optname(opts, fullname, 3, TRUE)) {
3314         if (negated) {
3315             bad_negation(fullname, FALSE);
3316             return;
3317         } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
3318             char buf[WINTYPELEN];
3319             nmcpy(buf, op, WINTYPELEN);
3320             addto_windowchain(buf);
3321         }
3322         return;
3323     }
3324 #endif
3325
3326     /* WINCAP
3327      * setting window colors
3328      * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
3329      */
3330     fullname = "windowcolors";
3331     if (match_optname(opts, fullname, 7, TRUE)) {
3332         if (duplicate)
3333             complain_about_duplicate(opts, 1);
3334         if ((op = string_for_opt(opts, FALSE)) != 0) {
3335             if (!wc_set_window_colors(op))
3336                 badoption(opts);
3337         } else if (negated)
3338             bad_negation(fullname, TRUE);
3339         return;
3340     }
3341
3342     /* menustyle:traditional or combination or full or partial */
3343     if (match_optname(opts, "menustyle", 4, TRUE)) {
3344         int tmp;
3345         boolean val_required = (strlen(opts) > 5 && !negated);
3346
3347         if (duplicate)
3348             complain_about_duplicate(opts, 1);
3349         if (!(op = string_for_opt(opts, !val_required))) {
3350             if (val_required)
3351                 return; /* string_for_opt gave feedback */
3352             tmp = negated ? 'n' : 'f';
3353         } else {
3354             tmp = tolower(*op);
3355         }
3356         switch (tmp) {
3357         case 'n': /* none */
3358         case 't': /* traditional */
3359             flags.menu_style = MENU_TRADITIONAL;
3360             break;
3361         case 'c': /* combo: trad.class sel+menu */
3362             flags.menu_style = MENU_COMBINATION;
3363             break;
3364         case 'p': /* partial: no class menu */
3365             flags.menu_style = MENU_PARTIAL;
3366             break;
3367         case 'f': /* full: class menu + menu */
3368             flags.menu_style = MENU_FULL;
3369             break;
3370         default:
3371             badoption(opts);
3372         }
3373         return;
3374     }
3375
3376     fullname = "menu_headings";
3377     if (match_optname(opts, fullname, 12, TRUE)) {
3378         if (duplicate)
3379             complain_about_duplicate(opts, 1);
3380         if (negated) {
3381             bad_negation(fullname, FALSE);
3382             return;
3383         } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
3384             return;
3385         }
3386         for (i = 0; i < SIZE(attrnames); i++)
3387             if (!strcmpi(opts, attrnames[i].name)) {
3388                 iflags.menu_headings = attrnames[i].attr;
3389                 return;
3390             }
3391         badoption(opts);
3392         return;
3393     }
3394
3395     /* check for menu command mapping */
3396     for (i = 0; i < NUM_MENU_CMDS; i++) {
3397         fullname = default_menu_cmd_info[i].name;
3398         if (duplicate)
3399             complain_about_duplicate(opts, 1);
3400         if (match_optname(opts, fullname, (int) strlen(fullname), TRUE)) {
3401             if (negated) {
3402                 bad_negation(fullname, FALSE);
3403             } else if ((op = string_for_opt(opts, FALSE)) != 0) {
3404                 int j;
3405                 char c, op_buf[BUFSZ];
3406                 boolean isbad = FALSE;
3407
3408                 escapes(op, op_buf);
3409                 c = *op_buf;
3410
3411                 if (c == 0 || c == '\r' || c == '\n' || c == '\033'
3412                     || c == ' ' || digit(c) || (letter(c) && c != '@'))
3413                     isbad = TRUE;
3414                 else /* reject default object class symbols */
3415                     for (j = 1; j < MAXOCLASSES; j++)
3416                         if (c == def_oc_syms[i].sym) {
3417                             isbad = TRUE;
3418                             break;
3419                         }
3420
3421                 if (isbad)
3422                     badoption(opts);
3423                 else
3424                     add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
3425             }
3426             return;
3427         }
3428     }
3429 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
3430     /* hilite fields in status prompt */
3431     if (match_optname(opts, "hilite_status", 13, TRUE)) {
3432         if (duplicate)
3433             complain_about_duplicate(opts, 1);
3434         op = string_for_opt(opts, TRUE);
3435         if (op && negated) {
3436             clear_status_hilites(tfrom_file);
3437             return;
3438         } else if (!op) {
3439             /* a value is mandatory */
3440             badoption(opts);
3441             return;
3442         }
3443         if (!set_status_hilites(op, tfrom_file))
3444             badoption(opts);
3445         return;
3446     }
3447 #endif
3448
3449 #if defined(BACKWARD_COMPAT)
3450     fullname = "DECgraphics";
3451     if (match_optname(opts, fullname, 3, TRUE)) {
3452         boolean badflag = FALSE;
3453
3454         if (duplicate)
3455             complain_about_duplicate(opts, 1);
3456         if (!negated) {
3457             /* There is no rogue level DECgraphics-specific set */
3458             if (symset[PRIMARY].name) {
3459                 badflag = TRUE;
3460             } else {
3461                 symset[PRIMARY].name = dupstr(fullname);
3462                 if (!read_sym_file(PRIMARY)) {
3463                     badflag = TRUE;
3464                     clear_symsetentry(PRIMARY, TRUE);
3465                 } else
3466                     switch_symbols(TRUE);
3467             }
3468             if (badflag) {
3469                 pline("Failure to load symbol set %s.", fullname);
3470                 wait_synch();
3471             }
3472         }
3473         return;
3474     }
3475     fullname = "IBMgraphics";
3476     if (match_optname(opts, fullname, 3, TRUE)) {
3477         const char *sym_name = fullname;
3478         boolean badflag = FALSE;
3479
3480         if (duplicate)
3481             complain_about_duplicate(opts, 1);
3482         if (!negated) {
3483             for (i = 0; i < NUM_GRAPHICS; ++i) {
3484                 if (symset[i].name) {
3485                     badflag = TRUE;
3486                 } else {
3487                     if (i == ROGUESET)
3488                         sym_name = "RogueIBM";
3489                     symset[i].name = dupstr(sym_name);
3490                     if (!read_sym_file(i)) {
3491                         badflag = TRUE;
3492                         clear_symsetentry(i, TRUE);
3493                         break;
3494                     }
3495                 }
3496             }
3497             if (badflag) {
3498                 pline("Failure to load symbol set %s.", sym_name);
3499                 wait_synch();
3500             } else {
3501                 switch_symbols(TRUE);
3502                 if (!initial && Is_rogue_level(&u.uz))
3503                     assign_graphics(ROGUESET);
3504             }
3505         }
3506         return;
3507     }
3508 #endif
3509 #ifdef MAC_GRAPHICS_ENV
3510     fullname = "MACgraphics";
3511     if (match_optname(opts, fullname, 3, TRUE)) {
3512         boolean badflag = FALSE;
3513
3514         if (duplicate)
3515             complain_about_duplicate(opts, 1);
3516         if (!negated) {
3517             if (symset[PRIMARY].name) {
3518                 badflag = TRUE;
3519             } else {
3520                 symset[PRIMARY].name = dupstr(fullname);
3521                 if (!read_sym_file(PRIMARY)) {
3522                     badflag = TRUE;
3523                     clear_symsetentry(PRIMARY, TRUE);
3524                 }
3525             }
3526             if (badflag) {
3527                 pline("Failure to load symbol set %s.", fullname);
3528                 wait_synch();
3529             } else {
3530                 switch_symbols(TRUE);
3531                 if (!initial && Is_rogue_level(&u.uz))
3532                     assign_graphics(ROGUESET);
3533             }
3534         }
3535         return;
3536     }
3537 #endif
3538
3539     /* OK, if we still haven't recognized the option, check the boolean
3540      * options list
3541      */
3542     for (i = 0; boolopt[i].name; i++) {
3543         if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
3544             /* options that don't exist */
3545             if (!boolopt[i].addr) {
3546                 if (!initial && !negated)
3547                     pline_The("\"%s\" option is not available.",
3548                               boolopt[i].name);
3549                 return;
3550             }
3551             /* options that must come from config file */
3552             if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
3553                 rejectoption(boolopt[i].name);
3554                 return;
3555             }
3556
3557             *(boolopt[i].addr) = !negated;
3558
3559             /* 0 means boolean opts */
3560             if (duplicate_opt_detection(boolopt[i].name, 0))
3561                 complain_about_duplicate(boolopt[i].name, 0);
3562
3563 #ifdef RLECOMP
3564             if ((boolopt[i].addr) == &iflags.rlecomp) {
3565                 if (*boolopt[i].addr)
3566                     set_savepref("rlecomp");
3567                 else
3568                     set_savepref("!rlecomp");
3569             }
3570 #endif
3571 #ifdef ZEROCOMP
3572             if ((boolopt[i].addr) == &iflags.zerocomp) {
3573                 if (*boolopt[i].addr)
3574                     set_savepref("zerocomp");
3575                 else
3576                     set_savepref("externalcomp");
3577             }
3578 #endif
3579             /* only do processing below if setting with doset() */
3580             if (initial)
3581                 return;
3582
3583             if ((boolopt[i].addr) == &flags.time
3584                 || (boolopt[i].addr) == &flags.showexp
3585 #ifdef SCORE_ON_BOTL
3586                 || (boolopt[i].addr) == &flags.showscore
3587 #endif
3588                 ) {
3589 #ifdef STATUS_VIA_WINDOWPORT
3590                 status_initialize(REASSESS_ONLY);
3591 #endif
3592                 context.botl = TRUE;
3593             } else if ((boolopt[i].addr) == &flags.invlet_constant) {
3594                 if (flags.invlet_constant)
3595                     reassign();
3596             } else if (((boolopt[i].addr) == &flags.lit_corridor)
3597                        || ((boolopt[i].addr) == &flags.dark_room)) {
3598                 /*
3599                  * All corridor squares seen via night vision or
3600                  * candles & lamps change.  Update them by calling
3601                  * newsym() on them.  Don't do this if we are
3602                  * initializing the options --- the vision system
3603                  * isn't set up yet.
3604                  */
3605                 vision_recalc(2);       /* shut down vision */
3606                 vision_full_recalc = 1; /* delayed recalc */
3607                 if (iflags.use_color)
3608                     need_redraw = TRUE; /* darkroom refresh */
3609             } else if ((boolopt[i].addr) == &iflags.use_inverse
3610                        || (boolopt[i].addr) == &flags.showrace
3611                        || (boolopt[i].addr) == &iflags.hilite_pet) {
3612                 need_redraw = TRUE;
3613 #ifdef TEXTCOLOR
3614             } else if ((boolopt[i].addr) == &iflags.use_color) {
3615                 need_redraw = TRUE;
3616 #ifdef TOS
3617                 if ((boolopt[i].addr) == &iflags.use_color && iflags.BIOS) {
3618                     if (colors_changed)
3619                         restore_colors();
3620                     else
3621                         set_colors();
3622                 }
3623 #endif
3624 #endif /* TEXTCOLOR */
3625             }
3626             return;
3627         }
3628     }
3629
3630     /* out of valid options */
3631     badoption(opts);
3632 }
3633
3634 static NEARDATA const char *menutype[] = { "traditional", "combination",
3635                                            "full", "partial" };
3636
3637 static NEARDATA const char *burdentype[] = { "unencumbered", "burdened",
3638                                              "stressed",     "strained",
3639                                              "overtaxed",    "overloaded" };
3640
3641 static NEARDATA const char *runmodes[] = { "teleport", "run", "walk",
3642                                            "crawl" };
3643
3644 static NEARDATA const char *sortltype[] = { "none", "loot", "full" };
3645
3646 /*
3647  * Convert the given string of object classes to a string of default object
3648  * symbols.
3649  */
3650 STATIC_OVL void
3651 oc_to_str(src, dest)
3652 char *src, *dest;
3653 {
3654     int i;
3655
3656     while ((i = (int) *src++) != 0) {
3657         if (i < 0 || i >= MAXOCLASSES)
3658             impossible("oc_to_str:  illegal object class %d", i);
3659         else
3660             *dest++ = def_oc_syms[i].sym;
3661     }
3662     *dest = '\0';
3663 }
3664
3665 /*
3666  * Add the given mapping to the menu command map list.  Always keep the
3667  * maps valid C strings.
3668  */
3669 void
3670 add_menu_cmd_alias(from_ch, to_ch)
3671 char from_ch, to_ch;
3672 {
3673     if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) {
3674         pline("out of menu map space.");
3675     } else {
3676         mapped_menu_cmds[n_menu_mapped] = from_ch;
3677         mapped_menu_op[n_menu_mapped] = to_ch;
3678         n_menu_mapped++;
3679         mapped_menu_cmds[n_menu_mapped] = 0;
3680         mapped_menu_op[n_menu_mapped] = 0;
3681     }
3682 }
3683
3684 /*
3685  * Map the given character to its corresponding menu command.  If it
3686  * doesn't match anything, just return the original.
3687  */
3688 char
3689 map_menu_cmd(ch)
3690 char ch;
3691 {
3692     char *found = index(mapped_menu_cmds, ch);
3693     if (found) {
3694         int idx = (int) (found - mapped_menu_cmds);
3695         ch = mapped_menu_op[idx];
3696     }
3697     return ch;
3698 }
3699
3700 #if defined(MICRO) || defined(MAC) || defined(WIN32)
3701 #define OPTIONS_HEADING "OPTIONS"
3702 #else
3703 #define OPTIONS_HEADING "NETHACKOPTIONS"
3704 #endif
3705
3706 static char fmtstr_doset_add_menu[] = "%s%-15s [%s]   ";
3707 static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
3708
3709 STATIC_OVL void
3710 doset_add_menu(win, option, indexoffset)
3711 winid win;          /* window to add to */
3712 const char *option; /* option name */
3713 int indexoffset;    /* value to add to index in compopt[], or zero
3714                        if option cannot be changed */
3715 {
3716     const char *value = "unknown"; /* current value */
3717     char buf[BUFSZ], buf2[BUFSZ];
3718     anything any;
3719     int i;
3720
3721     any = zeroany;
3722     if (indexoffset == 0) {
3723         any.a_int = 0;
3724         value = get_compopt_value(option, buf2);
3725     } else {
3726         for (i = 0; compopt[i].name; i++)
3727             if (strcmp(option, compopt[i].name) == 0)
3728                 break;
3729
3730         if (compopt[i].name) {
3731             any.a_int = i + 1 + indexoffset;
3732             value = get_compopt_value(option, buf2);
3733         } else {
3734             /* We are trying to add an option not found in compopt[].
3735                This is almost certainly bad, but we'll let it through anyway
3736                (with a zero value, so it can't be selected). */
3737             any.a_int = 0;
3738         }
3739     }
3740     /* "    " replaces "a - " -- assumes menus follow that style */
3741     if (!iflags.menu_tab_sep)
3742         Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ", option,
3743                 value);
3744     else
3745         Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
3746     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3747 }
3748
3749 /* Changing options via menu by Per Liboriussen */
3750 int
3751 doset()
3752 {
3753     char buf[BUFSZ], buf2[BUFSZ];
3754     int i = 0, pass, boolcount, pick_cnt, pick_idx, opt_indx;
3755     boolean *bool_p;
3756     winid tmpwin;
3757     anything any;
3758     menu_item *pick_list;
3759     int indexoffset, startpass, endpass;
3760     boolean setinitial = FALSE, fromfile = FALSE;
3761     int biggest_name = 0;
3762     const char *n_currently_set = "(%d currently set)";
3763
3764     tmpwin = create_nhwindow(NHW_MENU);
3765     start_menu(tmpwin);
3766
3767     any = zeroany;
3768     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3769 /*JP
3770              "Booleans (selecting will toggle value):", MENU_UNSELECTED);
3771 */
3772              "\90^\8bU\83I\83v\83V\83\87\83\93 (\91I\91ð\82·\82é\82Æ\92l\82ª\90Ø\82è\91Ö\82í\82è\82Ü\82·)\81F", MENU_UNSELECTED);
3773     any.a_int = 0;
3774     /* first list any other non-modifiable booleans, then modifiable ones */
3775     for (pass = 0; pass <= 1; pass++)
3776         for (i = 0; boolopt[i].name; i++)
3777             if ((bool_p = boolopt[i].addr) != 0
3778                 && ((boolopt[i].optflags == DISP_IN_GAME && pass == 0)
3779                     || (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
3780                 if (bool_p == &flags.female)
3781                     continue; /* obsolete */
3782                 if (bool_p == &iflags.sanity_check && !wizard)
3783                     continue;
3784                 if (bool_p == &iflags.menu_tab_sep && !wizard)
3785                     continue;
3786                 if (is_wc_option(boolopt[i].name)
3787                     && !wc_supported(boolopt[i].name))
3788                     continue;
3789                 if (is_wc2_option(boolopt[i].name)
3790                     && !wc2_supported(boolopt[i].name))
3791                     continue;
3792                 any.a_int = (pass == 0) ? 0 : i + 1;
3793                 if (!iflags.menu_tab_sep)
3794                     Sprintf(buf, "%s%-17s [%s]", pass == 0 ? "    " : "",
3795                             boolopt[i].name, *bool_p ? "true" : "false");
3796                 else
3797                     Sprintf(buf, "%s\t[%s]", boolopt[i].name,
3798                             *bool_p ? "true" : "false");
3799                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
3800                          MENU_UNSELECTED);
3801             }
3802
3803     boolcount = i;
3804     indexoffset = boolcount;
3805     any = zeroany;
3806     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3807 #if 0 /*JP*/
3808     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3809              "Compounds (selecting will prompt for new value):",
3810              MENU_UNSELECTED);
3811 #else
3812     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3813              "\95\8e\9a\97ñ\83I\83v\83V\83\87\83\93 (\91I\91ð\82·\82é\82Æ\90V\82µ\82¢\92l\82Ì\93ü\97Í\82ð\8b\81\82ß\82Ü\82·)\81F",
3814              MENU_UNSELECTED);
3815 #endif
3816
3817 #ifdef notyet /* SYSCF */
3818     /* XXX I think this is still fragile.  Fixing initial/from_file and/or
3819      changing
3820      the SET_* etc to bitmaps will let me make this better. */
3821     if (wizard)
3822         startpass = SET_IN_SYS;
3823     else
3824 #endif
3825         startpass = DISP_IN_GAME;
3826     endpass = SET_IN_GAME;
3827
3828     /* spin through the options to find the biggest name
3829        and adjust the format string accordingly if needed */
3830     biggest_name = 0;
3831     for (i = 0; compopt[i].name; i++)
3832         if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass
3833             && strlen(compopt[i].name) > (unsigned) biggest_name)
3834             biggest_name = (int) strlen(compopt[i].name);
3835     if (biggest_name > 30)
3836         biggest_name = 30;
3837     if (!iflags.menu_tab_sep)
3838         Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
3839
3840     /* deliberately put `playmode', `name', `role', `race', `gender' first
3841        (also alignment if anything ever comes before it in compopt[]) */
3842     doset_add_menu(tmpwin, "playmode", 0);
3843     doset_add_menu(tmpwin, "name", 0);
3844     doset_add_menu(tmpwin, "role", 0);
3845     doset_add_menu(tmpwin, "race", 0);
3846     doset_add_menu(tmpwin, "gender", 0);
3847
3848     for (pass = startpass; pass <= endpass; pass++)
3849         for (i = 0; compopt[i].name; i++)
3850             if (compopt[i].optflags == pass) {
3851                 if (!strcmp(compopt[i].name, "playmode")
3852                     || !strcmp(compopt[i].name, "name")
3853                     || !strcmp(compopt[i].name, "role")
3854                     || !strcmp(compopt[i].name, "race")
3855                     || !strcmp(compopt[i].name, "gender"))
3856                     continue;
3857                 else if (is_wc_option(compopt[i].name)
3858                          && !wc_supported(compopt[i].name))
3859                     continue;
3860                 else if (is_wc2_option(compopt[i].name)
3861                          && !wc2_supported(compopt[i].name))
3862                     continue;
3863                 else
3864                     doset_add_menu(tmpwin, compopt[i].name,
3865                                    (pass == DISP_IN_GAME) ? 0 : indexoffset);
3866             }
3867     any.a_int = -4;
3868     Sprintf(buf2, n_currently_set, msgtype_count());
3869     Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ",
3870             "message types", buf2);
3871     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3872     any.a_int = -3;
3873     Sprintf(buf2, n_currently_set, count_menucolors());
3874     Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ",
3875             "menucolors", buf2);
3876     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3877 #ifdef STATUS_VIA_WINDOWPORT
3878 #ifdef STATUS_HILITES
3879     any.a_int = -2;
3880     get_status_hilites(buf2, 60);
3881     if (!*buf2)
3882         Sprintf(buf2, "%s", "(none)");
3883     if (!iflags.menu_tab_sep)
3884         Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ",
3885                 "status_hilites", buf2);
3886     else
3887         Sprintf(buf, fmtstr_doset_add_menu_tab, "status_hilites", buf2);
3888     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3889 #endif
3890 #endif
3891     any.a_int = -1;
3892     Sprintf(buf2, n_currently_set, count_ape_maps((int *) 0, (int *) 0));
3893     Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : "    ",
3894             "autopickup exceptions", buf2);
3895     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3896 #ifdef PREFIXES_IN_USE
3897     any = zeroany;
3898     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3899     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3900              "Variable playground locations:", MENU_UNSELECTED);
3901     for (i = 0; i < PREFIX_COUNT; i++)
3902         doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
3903 #endif
3904 /*JP
3905     end_menu(tmpwin, "Set what options?");
3906 */
3907     end_menu(tmpwin, "\82Ç\82Ì\83I\83v\83V\83\87\83\93\82ð\90Ý\92è\82µ\82Ü\82·\82©\81H");
3908     need_redraw = FALSE;
3909     if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
3910         /*
3911          * Walk down the selection list and either invert the booleans
3912          * or prompt for new values. In most cases, call parseoptions()
3913          * to take care of options that require special attention, like
3914          * redraws.
3915          */
3916         for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
3917             opt_indx = pick_list[pick_idx].item.a_int - 1;
3918             if (opt_indx == -2) {
3919                 /* -2 due to -1 offset for select_menu() */
3920                 (void) special_handling("autopickup_exception", setinitial,
3921                                         fromfile);
3922 #ifdef STATUS_VIA_WINDOWPORT
3923 #ifdef STATUS_HILITES
3924             } else if (opt_indx == -3) {
3925                 /* -3 due to -1 offset for select_menu() */
3926                 if (!status_hilite_menu()) {
3927                     pline("Bad status hilite(s) specified.");
3928                 } else {
3929                     if (wc2_supported("status_hilites"))
3930                         preference_update("status_hilites");
3931                 }
3932 #endif
3933 #endif
3934             } else if (opt_indx == -4) {
3935                     (void) special_handling("menucolors", setinitial,
3936                                             fromfile);
3937             } else if (opt_indx == -5) {
3938                     (void) special_handling("msgtype", setinitial, fromfile);
3939             } else if (opt_indx < boolcount) {
3940                 /* boolean option */
3941                 Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
3942                         boolopt[opt_indx].name);
3943                 parseoptions(buf, setinitial, fromfile);
3944                 if (wc_supported(boolopt[opt_indx].name)
3945                     || wc2_supported(boolopt[opt_indx].name))
3946                     preference_update(boolopt[opt_indx].name);
3947             } else {
3948                 /* compound option */
3949                 opt_indx -= boolcount;
3950
3951                 if (!special_handling(compopt[opt_indx].name, setinitial,
3952                                       fromfile)) {
3953 /*JP
3954                     Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
3955 */
3956                     Sprintf(buf, "%s\82É\89½\82ð\90Ý\92è\82·\82é\81H", compopt[opt_indx].name);
3957                     getlin(buf, buf2);
3958                     if (buf2[0] == '\033')
3959                         continue;
3960                     Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
3961                     /* pass the buck */
3962                     parseoptions(buf, setinitial, fromfile);
3963                 }
3964                 if (wc_supported(compopt[opt_indx].name)
3965                     || wc2_supported(compopt[opt_indx].name))
3966                     preference_update(compopt[opt_indx].name);
3967             }
3968         }
3969         free((genericptr_t) pick_list);
3970         pick_list = (menu_item *) 0;
3971     }
3972
3973     destroy_nhwindow(tmpwin);
3974     if (need_redraw) {
3975         reglyph_darkroom();
3976         (void) doredraw();
3977     }
3978     return 0;
3979 }
3980
3981 int
3982 handle_add_list_remove(optname, numtotal)
3983 const char *optname;
3984 int numtotal;
3985 {
3986     winid tmpwin;
3987     anything any;
3988     int i, pick_cnt, pick_idx, opt_idx;
3989     menu_item *pick_list = (menu_item *) 0;
3990     static const struct action {
3991         char letr;
3992         const char *desc;
3993     } action_titles[] = {
3994 #if 0 /*JP*/
3995         { 'a', "add new %s" },         /* [0] */
3996 #else
3997         { 'a', "\90V\82µ\82¢%s\82ð\92Ç\89Á" },     /* [0] */
3998 #endif
3999 #if 0 /*JP*/
4000         { 'l', "list %s" },            /* [1] */
4001 #else
4002         { 'l', "%s\82ð\88ê\97\97\95\\8e¦" },       /* [1] */
4003 #endif
4004 #if 0 /*JP*/
4005         { 'r', "remove existing %s" }, /* [2] */
4006 #else
4007         { 'r', "\8aù\82É\82 \82é%s\82ð\8dí\8f\9c" },   /* [2] */
4008 #endif
4009 #if 0 /*JP*/
4010         { 'x', "exit this menu" },     /* [3] */
4011 #else
4012         { 'x', "\82±\82Ì\83\81\83j\83\85\81[\82ð\95Â\82\82é" }, /* [3] */
4013 #endif
4014     };
4015
4016     opt_idx = 0;
4017     tmpwin = create_nhwindow(NHW_MENU);
4018     start_menu(tmpwin);
4019     any = zeroany;
4020     for (i = 0; i < SIZE(action_titles); i++) {
4021         char tmpbuf[BUFSZ];
4022         any.a_int++;
4023         /* omit list and remove if there aren't any yet */
4024         if (!numtotal && (i == 1 || i == 2))
4025             continue;
4026         Sprintf(tmpbuf, action_titles[i].desc,
4027                 (i == 1) ? makeplural(optname) : optname);
4028         add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, 0, ATR_NONE,
4029                  tmpbuf,
4030 #if 0 /* this ought to work but doesn't... */
4031                  (action_titles[i].letr == 'x') ? MENU_SELECTED :
4032 #endif
4033                  MENU_UNSELECTED);
4034     }
4035 /*JP
4036     end_menu(tmpwin, "Do what?");
4037 */
4038     end_menu(tmpwin, "\82Ç\82¤\82·\82é\81H");
4039     if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
4040         for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
4041             opt_idx = pick_list[pick_idx].item.a_int - 1;
4042         }
4043         free((genericptr_t) pick_list);
4044         pick_list = (menu_item *) 0;
4045     }
4046     destroy_nhwindow(tmpwin);
4047
4048     if (pick_cnt < 1)
4049         opt_idx = 3; /* none selected, exit menu */
4050     return opt_idx;
4051 }
4052
4053 struct symsetentry *symset_list = 0; /* files.c will populate this with
4054                                               list of available sets */
4055
4056 STATIC_OVL boolean
4057 special_handling(optname, setinitial, setfromfile)
4058 const char *optname;
4059 boolean setinitial, setfromfile;
4060 {
4061     winid tmpwin;
4062     anything any;
4063     int i;
4064     char buf[BUFSZ];
4065
4066     /* Special handling of menustyle, pickup_burden, pickup_types,
4067      * disclose, runmode, msg_window, menu_headings, sortloot,
4068      * and number_pad options.
4069      * Also takes care of interactive autopickup_exception_handling changes.
4070      */
4071     if (!strcmp("menustyle", optname)) {
4072         const char *style_name;
4073         menu_item *style_pick = (menu_item *) 0;
4074         tmpwin = create_nhwindow(NHW_MENU);
4075         start_menu(tmpwin);
4076         any = zeroany;
4077         for (i = 0; i < SIZE(menutype); i++) {
4078             style_name = menutype[i];
4079             /* note: separate `style_name' variable used
4080                to avoid an optimizer bug in VAX C V2.3 */
4081             any.a_int = i + 1;
4082             add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, ATR_NONE,
4083                      style_name, MENU_UNSELECTED);
4084         }
4085 /*JP
4086         end_menu(tmpwin, "Select menustyle:");
4087 */
4088         end_menu(tmpwin, "\83\81\83j\83\85\81[\83X\83^\83C\83\8b\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
4089         if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
4090             flags.menu_style = style_pick->item.a_int - 1;
4091             free((genericptr_t) style_pick);
4092         }
4093         destroy_nhwindow(tmpwin);
4094     } else if (!strcmp("paranoid_confirmation", optname)) {
4095         menu_item *paranoia_picks = (menu_item *) 0;
4096
4097         tmpwin = create_nhwindow(NHW_MENU);
4098         start_menu(tmpwin);
4099         any = zeroany;
4100         for (i = 0; paranoia[i].flagmask != 0; ++i) {
4101             if (paranoia[i].flagmask == PARANOID_BONES && !wizard)
4102                 continue;
4103             any.a_int = paranoia[i].flagmask;
4104             add_menu(tmpwin, NO_GLYPH, &any, *paranoia[i].argname, 0,
4105                      ATR_NONE, paranoia[i].explain,
4106                      (flags.paranoia_bits & paranoia[i].flagmask)
4107                          ? MENU_SELECTED
4108                          : MENU_UNSELECTED);
4109         }
4110         end_menu(tmpwin, "Actions requiring extra confirmation:");
4111         i = select_menu(tmpwin, PICK_ANY, &paranoia_picks);
4112         if (i >= 0) {
4113             /* player didn't cancel; we reset all the paranoia options
4114                here even if there were no items picked, since user
4115                could have toggled off preselected ones to end up with 0 */
4116             flags.paranoia_bits = 0;
4117             if (i > 0) {
4118                 /* at least 1 item set, either preselected or newly picked */
4119                 while (--i >= 0)
4120                     flags.paranoia_bits |= paranoia_picks[i].item.a_int;
4121                 free((genericptr_t) paranoia_picks);
4122             }
4123         }
4124         destroy_nhwindow(tmpwin);
4125     } else if (!strcmp("pickup_burden", optname)) {
4126         const char *burden_name, *burden_letters = "ubsntl";
4127         menu_item *burden_pick = (menu_item *) 0;
4128
4129         tmpwin = create_nhwindow(NHW_MENU);
4130         start_menu(tmpwin);
4131         any = zeroany;
4132         for (i = 0; i < SIZE(burdentype); i++) {
4133             burden_name = burdentype[i];
4134             any.a_int = i + 1;
4135             add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, ATR_NONE,
4136                      burden_name, MENU_UNSELECTED);
4137         }
4138 /*JP
4139         end_menu(tmpwin, "Select encumbrance level:");
4140 */
4141         end_menu(tmpwin, "\8cx\8d\90\82ð\8fo\82·\89×\8fd\83\8c\83x\83\8b\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
4142         if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
4143             flags.pickup_burden = burden_pick->item.a_int - 1;
4144             free((genericptr_t) burden_pick);
4145         }
4146         destroy_nhwindow(tmpwin);
4147     } else if (!strcmp("pickup_types", optname)) {
4148         /* parseoptions will prompt for the list of types */
4149         parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
4150     } else if (!strcmp("disclose", optname)) {
4151         /* order of disclose_names[] must correspond to
4152            disclosure_options in decl.c */
4153         static const char *disclosure_names[] = {
4154             "inventory", "attributes", "vanquished",
4155             "genocides", "conduct",    "overview",
4156         };
4157         int disc_cat[NUM_DISCLOSURE_OPTIONS];
4158         int pick_cnt, pick_idx, opt_idx;
4159         menu_item *disclosure_pick = (menu_item *) 0;
4160
4161         tmpwin = create_nhwindow(NHW_MENU);
4162         start_menu(tmpwin);
4163         any = zeroany;
4164         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
4165             Sprintf(buf, "%-12s[%c%c]", disclosure_names[i],
4166                     flags.end_disclose[i], disclosure_options[i]);
4167             any.a_int = i + 1;
4168             add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
4169                      ATR_NONE, buf, MENU_UNSELECTED);
4170             disc_cat[i] = 0;
4171         }
4172 /*JP
4173         end_menu(tmpwin, "Change which disclosure options categories:");
4174 */
4175         end_menu(tmpwin, "\82Ç\82Ì\83J\83e\83S\83\8a\82Ì\95\\8e¦\8fî\95ñ\83I\83v\83V\83\87\83\93\82ð\95Ï\8dX\82µ\82Ü\82·\82©\81F");
4176         pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_pick);
4177         if (pick_cnt > 0) {
4178             for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
4179                 opt_idx = disclosure_pick[pick_idx].item.a_int - 1;
4180                 disc_cat[opt_idx] = 1;
4181             }
4182             free((genericptr_t) disclosure_pick);
4183             disclosure_pick = (menu_item *) 0;
4184         }
4185         destroy_nhwindow(tmpwin);
4186
4187         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
4188             if (disc_cat[i]) {
4189 /*JP
4190                 Sprintf(buf, "Disclosure options for %s:",
4191 */
4192                 Sprintf(buf, "%s\82Ì\8fo\97Í\8c`\8e®\81F",
4193                         disclosure_names[i]);
4194                 tmpwin = create_nhwindow(NHW_MENU);
4195                 start_menu(tmpwin);
4196                 any = zeroany;
4197                 /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
4198                 any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
4199                 add_menu(tmpwin, NO_GLYPH, &any, 'a', any.a_char, ATR_NONE,
4200 /*JP
4201                          "Never disclose, without prompting",
4202 */
4203                          "\8am\94F\82¹\82¸\82É\8fo\97Í\82à\82µ\82È\82¢",
4204                          MENU_UNSELECTED);
4205                 any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
4206                 add_menu(tmpwin, NO_GLYPH, &any, 'b', any.a_char, ATR_NONE,
4207 /*JP
4208                          "Always disclose, without prompting",
4209 */
4210                          "\8am\94F\82¹\82¸\82É\8fo\97Í\82·\82é",
4211                          MENU_UNSELECTED);
4212                 any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
4213                 add_menu(tmpwin, NO_GLYPH, &any, 'c', any.a_char, ATR_NONE,
4214 /*JP
4215                          "Prompt, with default answer of \"No\"",
4216 */
4217                          "\8am\94F\82·\82é\81C\83f\83t\83H\83\8b\83g\82Í\81u\8fo\97Í\82µ\82È\82¢\81v",
4218                          MENU_UNSELECTED);
4219                 any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
4220                 add_menu(tmpwin, NO_GLYPH, &any, 'd', any.a_char, ATR_NONE,
4221 /*JP
4222                          "Prompt, with default answer of \"Yes\"",
4223 */
4224                          "\8am\94F\82·\82é\81C\83f\83t\83H\83\8b\83g\82Í\81u\8fo\97Í\82·\82é\81v",
4225                          MENU_UNSELECTED);
4226                 end_menu(tmpwin, buf);
4227                 if (select_menu(tmpwin, PICK_ONE, &disclosure_pick) > 0) {
4228                     flags.end_disclose[i] = disclosure_pick->item.a_char;
4229                     free((genericptr_t) disclosure_pick);
4230                 }
4231                 destroy_nhwindow(tmpwin);
4232             }
4233         }
4234     } else if (!strcmp("runmode", optname)) {
4235         const char *mode_name;
4236         menu_item *mode_pick = (menu_item *) 0;
4237
4238         tmpwin = create_nhwindow(NHW_MENU);
4239         start_menu(tmpwin);
4240         any = zeroany;
4241         for (i = 0; i < SIZE(runmodes); i++) {
4242             mode_name = runmodes[i];
4243             any.a_int = i + 1;
4244             add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, ATR_NONE,
4245                      mode_name, MENU_UNSELECTED);
4246         }
4247 /*JP
4248         end_menu(tmpwin, "Select run/travel display mode:");
4249 */
4250         end_menu(tmpwin, "\91\96\8ds/\83g\83\89\83x\83\8b\82Ì\95\\8e¦\83\82\81[\83h\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
4251         if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
4252             flags.runmode = mode_pick->item.a_int - 1;
4253             free((genericptr_t) mode_pick);
4254         }
4255         destroy_nhwindow(tmpwin);
4256     } else if (!strcmp("msg_window", optname)) {
4257 #ifdef TTY_GRAPHICS
4258         /* by Christian W. Cooper */
4259         menu_item *window_pick = (menu_item *) 0;
4260
4261         tmpwin = create_nhwindow(NHW_MENU);
4262         start_menu(tmpwin);
4263         any = zeroany;
4264         any.a_char = 's';
4265         add_menu(tmpwin, NO_GLYPH, &any, 's', 0, ATR_NONE, "single",
4266                  MENU_UNSELECTED);
4267         any.a_char = 'c';
4268         add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE, "combination",
4269                  MENU_UNSELECTED);
4270         any.a_char = 'f';
4271         add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, ATR_NONE, "full",
4272                  MENU_UNSELECTED);
4273         any.a_char = 'r';
4274         add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "reversed",
4275                  MENU_UNSELECTED);
4276 /*JP
4277         end_menu(tmpwin, "Select message history display type:");
4278 */
4279         end_menu(tmpwin, "\83\81\83b\83Z\81[\83W\97\9a\97ð\82Ì\95\\8e¦\95û\96@\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
4280         if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
4281             iflags.prevmsg_window = window_pick->item.a_char;
4282             free((genericptr_t) window_pick);
4283         }
4284         destroy_nhwindow(tmpwin);
4285 #endif
4286     } else if (!strcmp("sortloot", optname)) {
4287         const char *sortl_name;
4288         menu_item *sortl_pick = (menu_item *) 0;
4289
4290         tmpwin = create_nhwindow(NHW_MENU);
4291         start_menu(tmpwin);
4292         any = zeroany;
4293         for (i = 0; i < SIZE(sortltype); i++) {
4294             sortl_name = sortltype[i];
4295             any.a_char = *sortl_name;
4296             add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE,
4297                      sortl_name, MENU_UNSELECTED);
4298         }
4299         end_menu(tmpwin, "Select loot sorting type:");
4300         if (select_menu(tmpwin, PICK_ONE, &sortl_pick) > 0) {
4301             flags.sortloot = sortl_pick->item.a_char;
4302             free((genericptr_t) sortl_pick);
4303         }
4304         destroy_nhwindow(tmpwin);
4305     } else if (!strcmp("align_message", optname)
4306                || !strcmp("align_status", optname)) {
4307         menu_item *window_pick = (menu_item *) 0;
4308         char abuf[BUFSZ];
4309         boolean msg = (*(optname + 6) == 'm');
4310
4311         tmpwin = create_nhwindow(NHW_MENU);
4312         start_menu(tmpwin);
4313         any = zeroany;
4314         any.a_int = ALIGN_TOP;
4315         add_menu(tmpwin, NO_GLYPH, &any, 't', 0, ATR_NONE, "top",
4316                  MENU_UNSELECTED);
4317         any.a_int = ALIGN_BOTTOM;
4318         add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE, "bottom",
4319                  MENU_UNSELECTED);
4320         any.a_int = ALIGN_LEFT;
4321         add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, ATR_NONE, "left",
4322                  MENU_UNSELECTED);
4323         any.a_int = ALIGN_RIGHT;
4324         add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "right",
4325                  MENU_UNSELECTED);
4326 #if 0 /*JP*/
4327         Sprintf(abuf, "Select %s window placement relative to the map:",
4328                 msg ? "message" : "status");
4329 #else
4330         Sprintf(abuf, "%s\83E\83B\83\93\83h\83E\82Ì\83}\83b\83v\82É\91Î\82·\82é\95\\8e¦\88Ê\92u\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F",
4331                 msg ? "\83\81\83b\83Z\81[\83W" : "\8fó\91Ô");
4332 #endif
4333         end_menu(tmpwin, abuf);
4334         if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
4335             if (msg)
4336                 iflags.wc_align_message = window_pick->item.a_int;
4337             else
4338                 iflags.wc_align_status = window_pick->item.a_int;
4339             free((genericptr_t) window_pick);
4340         }
4341         destroy_nhwindow(tmpwin);
4342     } else if (!strcmp("number_pad", optname)) {
4343         static const char *npchoices[] = {
4344 /*JP
4345             " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
4346 */
4347             "0 (\96³\8cø)", "1 (\97L\8cø)", "2 (\97L\8cø\81CMSDOS\8cÝ\8a·)",
4348 /*JP
4349             " 3 (on, phone-style digit layout)",
4350 */
4351             " 3 (\97L\8cø\81C\93d\98b\8e®\82Ì\90\94\8e\9a\94z\92u)",
4352 /*JP
4353             " 4 (on, phone-style layout, MSDOS compatible)",
4354 */
4355             " 4 (\97L\8cø\81C\93d\98b\8e®\82Ì\94z\92u\81CMSDOS \8cÝ\8a·)",
4356 /*JP
4357             "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
4358 */
4359             "-1 (\96³\8cø\81C'z' \82Å\8d\8fã\82É\88Ú\93®\81C'y' \82Å\8fñ\82ð\90U\82é)"
4360         };
4361         menu_item *mode_pick = (menu_item *) 0;
4362
4363         tmpwin = create_nhwindow(NHW_MENU);
4364         start_menu(tmpwin);
4365         any = zeroany;
4366         for (i = 0; i < SIZE(npchoices); i++) {
4367             any.a_int = i + 1;
4368             add_menu(tmpwin, NO_GLYPH, &any, 'a' + i, 0, ATR_NONE,
4369                      npchoices[i], MENU_UNSELECTED);
4370         }
4371 /*JP
4372         end_menu(tmpwin, "Select number_pad mode:");
4373 */
4374         end_menu(tmpwin, "number_pad\83\82\81[\83h\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
4375         if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
4376             switch (mode_pick->item.a_int - 1) {
4377             case 0:
4378                 iflags.num_pad = FALSE;
4379                 iflags.num_pad_mode = 0;
4380                 break;
4381             case 1:
4382                 iflags.num_pad = TRUE;
4383                 iflags.num_pad_mode = 0;
4384                 break;
4385             case 2:
4386                 iflags.num_pad = TRUE;
4387                 iflags.num_pad_mode = 1;
4388                 break;
4389             case 3:
4390                 iflags.num_pad = TRUE;
4391                 iflags.num_pad_mode = 2;
4392                 break;
4393             case 4:
4394                 iflags.num_pad = TRUE;
4395                 iflags.num_pad_mode = 3;
4396                 break;
4397             /* last menu choice: number_pad == -1 */
4398             case 5:
4399                 iflags.num_pad = FALSE;
4400                 iflags.num_pad_mode = 1;
4401                 break;
4402             }
4403             reset_commands(FALSE);
4404             number_pad(iflags.num_pad ? 1 : 0);
4405             free((genericptr_t) mode_pick);
4406         }
4407         destroy_nhwindow(tmpwin);
4408     } else if (!strcmp("menu_headings", optname)) {
4409 /*JP
4410         int mhattr = query_attr("How to highlight menu headings:");
4411 */
4412         int mhattr = query_attr("\83\81\83j\83\85\81[\83w\83b\83_\82Ì\8b­\92²\95û\96@\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
4413
4414         if (mhattr != -1)
4415             iflags.menu_headings = mhattr;
4416     } else if (!strcmp("msgtype", optname)) {
4417         int opt_idx, nmt, mttyp;
4418         char mtbuf[BUFSZ];
4419
4420     msgtypes_again:
4421         nmt = msgtype_count();
4422         opt_idx = handle_add_list_remove("message type", nmt);
4423         if (opt_idx == 3) {
4424             ; /* done--fall through to function exit */
4425         } else if (opt_idx == 0) { /* add new */
4426             getlin("What new message pattern?", mtbuf);
4427             if (*mtbuf == '\033' || !*mtbuf)
4428                 goto msgtypes_again;
4429             mttyp = query_msgtype();
4430             if (mttyp == -1)
4431                 goto msgtypes_again;
4432             if (!msgtype_add(mttyp, mtbuf)) {
4433                 pline("Error adding the message type.");
4434                 wait_synch();
4435                 goto msgtypes_again;
4436             }
4437         } else { /* list or remove */
4438             int pick_idx, pick_cnt;
4439             int mt_idx;
4440             menu_item *pick_list = (menu_item *) 0;
4441             struct plinemsg_type *tmp = plinemsg_types;
4442
4443             tmpwin = create_nhwindow(NHW_MENU);
4444             start_menu(tmpwin);
4445             any = zeroany;
4446             mt_idx = 0;
4447             while (tmp) {
4448                 const char *mtype = msgtype2name(tmp->msgtype);
4449
4450                 any.a_int = ++mt_idx;
4451                 Sprintf(mtbuf, "%-5s \"%s\"", mtype, tmp->pattern);
4452                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mtbuf,
4453                          MENU_UNSELECTED);
4454                 tmp = tmp->next;
4455             }
4456             Sprintf(mtbuf, "%s message types",
4457                     (opt_idx == 1) ? "List of" : "Remove which");
4458             end_menu(tmpwin, mtbuf);
4459             pick_cnt = select_menu(tmpwin,
4460                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
4461                                    &pick_list);
4462             if (pick_cnt > 0) {
4463                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
4464                     free_one_msgtype(pick_list[pick_idx].item.a_int - 1
4465                                            - pick_idx);
4466                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
4467             }
4468             destroy_nhwindow(tmpwin);
4469             if (pick_cnt >= 0)
4470                 goto msgtypes_again;
4471         }
4472     } else if (!strcmp("menucolors", optname)) {
4473         int opt_idx, nmc, mcclr, mcattr;
4474         char mcbuf[BUFSZ];
4475
4476     menucolors_again:
4477         nmc = count_menucolors();
4478         opt_idx = handle_add_list_remove("menucolor", nmc);
4479         if (opt_idx == 3) {
4480             ;                      /* done--fall through to function exit */
4481         } else if (opt_idx == 0) { /* add new */
4482             getlin("What new menucolor pattern?", mcbuf);
4483             if (*mcbuf == '\033' || !*mcbuf)
4484                 goto menucolors_again;
4485             mcclr = query_color();
4486             if (mcclr == -1)
4487                 goto menucolors_again;
4488             mcattr = query_attr(NULL);
4489             if (mcattr == -1)
4490                 goto menucolors_again;
4491             if (!add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) {
4492                 pline("Error adding the menu color.");
4493                 wait_synch();
4494                 goto menucolors_again;
4495             }
4496         } else { /* list or remove */
4497             int pick_idx, pick_cnt;
4498             int mc_idx;
4499             menu_item *pick_list = (menu_item *) 0;
4500             struct menucoloring *tmp = menu_colorings;
4501
4502             tmpwin = create_nhwindow(NHW_MENU);
4503             start_menu(tmpwin);
4504             any = zeroany;
4505             mc_idx = 0;
4506             while (tmp) {
4507                 const char *sattr = attr2attrname(tmp->attr);
4508                 const char *sclr = clr2colorname(tmp->color);
4509
4510                 any.a_int = (++mc_idx);
4511                 Sprintf(mcbuf, "\"%s\"=%s%s%s", tmp->origstr, sclr,
4512                         (tmp->attr != ATR_NONE) ? " & " : "",
4513                         (tmp->attr != ATR_NONE) ? sattr : "");
4514                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mcbuf,
4515                          MENU_UNSELECTED);
4516                 tmp = tmp->next;
4517             }
4518             Sprintf(mcbuf, "%s menu colors",
4519                     (opt_idx == 1) ? "List of" : "Remove which");
4520             end_menu(tmpwin, mcbuf);
4521             pick_cnt = select_menu(tmpwin,
4522                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
4523                                    &pick_list);
4524             if (pick_cnt > 0) {
4525                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
4526                     free_one_menu_coloring(pick_list[pick_idx].item.a_int - 1
4527                                            - pick_idx);
4528                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
4529             }
4530             destroy_nhwindow(tmpwin);
4531             if (pick_cnt >= 0)
4532                 goto menucolors_again;
4533         }
4534     } else if (!strcmp("autopickup_exception", optname)) {
4535         int opt_idx, pass, totalapes = 0, numapes[2] = { 0, 0 };
4536         char apebuf[1 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */
4537         struct autopickup_exception *ape;
4538
4539     ape_again:
4540         totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
4541         opt_idx = handle_add_list_remove("autopickup exception", totalapes);
4542         if (opt_idx == 3) {
4543             ;                      /* done--fall through to function exit */
4544         } else if (opt_idx == 0) { /* add new */
4545 /*JP
4546             getlin("What new autopickup exception pattern?", &apebuf[1]);
4547 */
4548             getlin("\90V\82µ\82¢\8e©\93®\8fE\82¢\97á\8aO\82Ì\83p\83^\81[\83\93\82ð\93ü\97Í\82µ\82Ä\82­\82¾\82³\82¢\81F", &apebuf[1]);
4549             mungspaces(&apebuf[1]); /* regularize whitespace */
4550             if (apebuf[1] == '\033') {
4551                 ; /* fall through to function exit */
4552             } else {
4553                 if (apebuf[1]) {
4554                     apebuf[0] = '\"';
4555                     /* guarantee room for \" prefix and \"\0 suffix;
4556                        -2 is good enough for apebuf[] but -3 makes
4557                        sure the whole thing fits within normal BUFSZ */
4558                     apebuf[sizeof apebuf - 3] = '\0';
4559                     Strcat(apebuf, "\"");
4560                     add_autopickup_exception(apebuf);
4561                 }
4562                 goto ape_again;
4563             }
4564         } else { /* list or remove */
4565             int pick_idx, pick_cnt;
4566             menu_item *pick_list = (menu_item *) 0;
4567
4568             tmpwin = create_nhwindow(NHW_MENU);
4569             start_menu(tmpwin);
4570             for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
4571                 if (numapes[pass] == 0)
4572                     continue;
4573                 ape = iflags.autopickup_exceptions[pass];
4574                 any = zeroany;
4575                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
4576 /*JP
4577                          (pass == 0) ? "Never pickup" : "Always pickup",
4578 */
4579                          (pass == 0) ? "\8fí\82É\8fE\82í\82È\82¢" : "\8fí\82É\8fE\82¤",
4580                          MENU_UNSELECTED);
4581                 for (i = 0; i < numapes[pass] && ape; i++) {
4582                     any.a_void = (opt_idx == 1) ? 0 : ape;
4583                     Sprintf(apebuf, "\"%s\"", ape->pattern);
4584                     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf,
4585                              MENU_UNSELECTED);
4586                     ape = ape->next;
4587                 }
4588             }
4589 #if 0 /*JP*/
4590             Sprintf(apebuf, "%s autopickup exceptions",
4591                     (opt_idx == 1) ? "List of" : "Remove which");
4592 #else
4593             Sprintf(apebuf, "%s\8e©\93®\8fE\82¢\97á\8aO%s",
4594                     (opt_idx == 1) ? "" : "\82Ç\82Ì",
4595                     (opt_idx == 1) ? "\82Ì\88ê\97\97" : "\82ð\8dí\8f\9c\82µ\82Ü\82·\82©\81H");
4596 #endif
4597             end_menu(tmpwin, apebuf);
4598             pick_cnt = select_menu(tmpwin,
4599                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
4600                                    &pick_list);
4601             if (pick_cnt > 0) {
4602                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
4603                     remove_autopickup_exception(
4604                                          (struct autopickup_exception *)
4605                                              pick_list[pick_idx].item.a_void);
4606                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
4607             }
4608             destroy_nhwindow(tmpwin);
4609             if (pick_cnt >= 0)
4610                 goto ape_again;
4611         }
4612     } else if (!strcmp("symset", optname)
4613                || !strcmp("roguesymset", optname)) {
4614         menu_item *symset_pick = (menu_item *) 0;
4615         boolean primaryflag = (*optname == 's'),
4616                 rogueflag = (*optname == 'r'),
4617                 ready_to_switch = FALSE,
4618                 nothing_to_do = FALSE;
4619         char *symset_name, fmtstr[20];
4620         struct symsetentry *sl;
4621         int res, which_set, setcount = 0, chosen = -2;
4622
4623         if (rogueflag)
4624             which_set = ROGUESET;
4625         else
4626             which_set = PRIMARY;
4627
4628         /* clear symset[].name as a flag to read_sym_file() to build list */
4629         symset_name = symset[which_set].name;
4630         symset[which_set].name = (char *) 0;
4631         symset_list = (struct symsetentry *) 0;
4632
4633         res = read_sym_file(which_set);
4634         if (res && symset_list) {
4635             char symsetchoice[BUFSZ];
4636             int let = 'a', biggest = 0, thissize = 0;
4637
4638             sl = symset_list;
4639             while (sl) {
4640                 /* check restrictions */
4641                 if ((!rogueflag && sl->rogue)
4642                     || (!primaryflag && sl->primary)) {
4643                     sl = sl->next;
4644                     continue;
4645                 }
4646                 setcount++;
4647                 /* find biggest name */
4648                 if (sl->name)
4649                     thissize = strlen(sl->name);
4650                 if (thissize > biggest)
4651                     biggest = thissize;
4652                 sl = sl->next;
4653             }
4654             if (!setcount) {
4655                 pline("There are no appropriate %ssymbol sets available.",
4656                       (rogueflag) ? "rogue level "
4657                                   : (primaryflag) ? "primary " : "");
4658                 return TRUE;
4659             }
4660
4661             Sprintf(fmtstr, "%%-%ds %%s", biggest + 5);
4662             tmpwin = create_nhwindow(NHW_MENU);
4663             start_menu(tmpwin);
4664             any = zeroany;
4665             any.a_int = 1;
4666             add_menu(tmpwin, NO_GLYPH, &any, let++, 0, ATR_NONE,
4667                      "Default Symbols", MENU_UNSELECTED);
4668
4669             sl = symset_list;
4670             while (sl) {
4671                 /* check restrictions */
4672                 if ((!rogueflag && sl->rogue)
4673                     || (!primaryflag && sl->primary)) {
4674                     sl = sl->next;
4675                     continue;
4676                 }
4677                 if (sl->name) {
4678                     any.a_int = sl->idx + 2;
4679                     Sprintf(symsetchoice, fmtstr, sl->name,
4680                             sl->desc ? sl->desc : "");
4681                     add_menu(tmpwin, NO_GLYPH, &any, let, 0, ATR_NONE,
4682                              symsetchoice, MENU_UNSELECTED);
4683                     if (let == 'z')
4684                         let = 'A';
4685                     else
4686                         let++;
4687                 }
4688                 sl = sl->next;
4689             }
4690             end_menu(tmpwin, "Select symbol set:");
4691             if (select_menu(tmpwin, PICK_ONE, &symset_pick) > 0) {
4692                 chosen = symset_pick->item.a_int - 2;
4693                 free((genericptr_t) symset_pick);
4694             }
4695             destroy_nhwindow(tmpwin);
4696
4697             if (chosen > -1) {
4698                 /* chose an actual symset name from file */
4699                 sl = symset_list;
4700                 while (sl) {
4701                     if (sl->idx == chosen) {
4702                         if (symset_name) {
4703                             free((genericptr_t) symset_name);
4704                             symset_name = (char *) 0;
4705                         }
4706                         /* free the now stale attributes */
4707                         clear_symsetentry(which_set, TRUE);
4708
4709                         /* transfer only the name of the symbol set */
4710                         symset[which_set].name = dupstr(sl->name);
4711                         ready_to_switch = TRUE;
4712                         break;
4713                     }
4714                     sl = sl->next;
4715                 }
4716             } else if (chosen == -1) {
4717                 /* explicit selection of defaults */
4718                 /* free the now stale symset attributes */
4719                 if (symset_name) {
4720                     free((genericptr_t) symset_name);
4721                     symset_name = (char *) 0;
4722                 }
4723                 clear_symsetentry(which_set, TRUE);
4724             } else
4725                 nothing_to_do = TRUE;
4726         } else if (!res) {
4727             /* The symbols file could not be accessed */
4728             pline("Unable to access \"%s\" file.", SYMBOLS);
4729             return TRUE;
4730         } else if (!symset_list) {
4731             /* The symbols file was empty */
4732             pline("There were no symbol sets found in \"%s\".", SYMBOLS);
4733             return TRUE;
4734         }
4735
4736         /* clean up */
4737         while (symset_list) {
4738             sl = symset_list;
4739             if (sl->name)
4740                 free((genericptr_t) sl->name);
4741             sl->name = (char *) 0;
4742
4743             if (sl->desc)
4744                 free((genericptr_t) sl->desc);
4745             sl->desc = (char *) 0;
4746
4747             symset_list = sl->next;
4748             free((genericptr_t) sl);
4749         }
4750
4751         if (nothing_to_do)
4752             return TRUE;
4753
4754         if (!symset[which_set].name && symset_name)
4755             symset[which_set].name = symset_name; /* not dupstr() here */
4756
4757         /* Set default symbols and clear the handling value */
4758         if (rogueflag)
4759             init_r_symbols();
4760         else
4761             init_l_symbols();
4762
4763         if (symset[which_set].name) {
4764             if (read_sym_file(which_set)) {
4765                 ready_to_switch = TRUE;
4766             } else {
4767                 clear_symsetentry(which_set, TRUE);
4768                 return TRUE;
4769             }
4770         }
4771
4772         if (ready_to_switch)
4773             switch_symbols(TRUE);
4774
4775         if (Is_rogue_level(&u.uz)) {
4776             if (rogueflag)
4777                 assign_graphics(ROGUESET);
4778         } else if (!rogueflag)
4779             assign_graphics(PRIMARY);
4780         need_redraw = TRUE;
4781         return TRUE;
4782
4783     } else {
4784         /* didn't match any of the special options */
4785         return FALSE;
4786     }
4787     return TRUE;
4788 }
4789
4790 #define rolestring(val, array, field) \
4791     ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none)
4792
4793 /* This is ugly. We have all the option names in the compopt[] array,
4794    but we need to look at each option individually to get the value. */
4795 STATIC_OVL const char *
4796 get_compopt_value(optname, buf)
4797 const char *optname;
4798 char *buf;
4799 {
4800     char ocl[MAXOCLASSES + 1];
4801 #if 0 /*JP*/
4802     static const char none[] = "(none)", randomrole[] = "random",
4803                       to_be_done[] = "(to be done)", defopt[] = "default",
4804                       defbrief[] = "def";
4805 #else
4806     static const char none[] = "(\82È\82µ)", randomrole[] = "\83\89\83\93\83_\83\80",
4807                       to_be_done[] = "(\96¢\90Ý\92è)", defopt[] = "\83f\83t\83H\83\8b\83g",
4808                       defbrief[] = "def";
4809 #endif
4810     int i;
4811
4812     buf[0] = '\0';
4813     if (!strcmp(optname, "align_message"))
4814 #if 0 /*JP*/
4815         Sprintf(buf, "%s",
4816                 iflags.wc_align_message == ALIGN_TOP
4817                     ? "top"
4818                     : iflags.wc_align_message == ALIGN_LEFT
4819                           ? "left"
4820                           : iflags.wc_align_message == ALIGN_BOTTOM
4821                                 ? "bottom"
4822                                 : iflags.wc_align_message == ALIGN_RIGHT
4823                                       ? "right"
4824                                       : defopt);
4825 #else
4826         Sprintf(buf, "%s",
4827                 iflags.wc_align_message == ALIGN_TOP
4828                     ? "\8fã\91¤"
4829                     : iflags.wc_align_message == ALIGN_LEFT
4830                           ? "\8d\91¤"
4831                           : iflags.wc_align_message == ALIGN_BOTTOM
4832                                 ? "\89º\91¤"
4833                                 : iflags.wc_align_message == ALIGN_RIGHT
4834                                       ? "\89E\91¤" : defopt);
4835 #endif
4836     else if (!strcmp(optname, "align_status"))
4837 #if 0 /*JP*/
4838         Sprintf(buf, "%s",
4839                 iflags.wc_align_status == ALIGN_TOP
4840                     ? "top"
4841                     : iflags.wc_align_status == ALIGN_LEFT
4842                           ? "left"
4843                           : iflags.wc_align_status == ALIGN_BOTTOM
4844                                 ? "bottom"
4845                                 : iflags.wc_align_status == ALIGN_RIGHT
4846                                       ? "right"
4847                                       : defopt);
4848 #else
4849         Sprintf(buf, "%s",
4850                 iflags.wc_align_status == ALIGN_TOP
4851                     ? "\8fã\91¤"
4852                     : iflags.wc_align_status == ALIGN_LEFT
4853                           ? "\8d\91¤"
4854                           : iflags.wc_align_status == ALIGN_BOTTOM
4855                                 ? "\89º\91¤"
4856                                 : iflags.wc_align_status == ALIGN_RIGHT
4857                                       ? "\89E\91¤"
4858                                       : defopt);
4859 #endif
4860     else if (!strcmp(optname, "align"))
4861         Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
4862 #ifdef WIN32
4863     else if (!strcmp(optname, "altkeyhandler"))
4864         Sprintf(buf, "%s",
4865 /*JP
4866                 iflags.altkeyhandler[0] ? iflags.altkeyhandler : "default");
4867 */
4868                 iflags.altkeyhandler[0] ? iflags.altkeyhandler : defopt);
4869 #endif
4870 #ifdef BACKWARD_COMPAT
4871     else if (!strcmp(optname, "boulder"))
4872         Sprintf(buf, "%c",
4873                 iflags.bouldersym
4874                     ? iflags.bouldersym
4875                     : showsyms[(int) objects[BOULDER].oc_class + SYM_OFF_O]);
4876 #endif
4877     else if (!strcmp(optname, "catname"))
4878         Sprintf(buf, "%s", catname[0] ? catname : none);
4879     else if (!strcmp(optname, "disclose"))
4880         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
4881             if (i)
4882                 (void) strkitten(buf, ' ');
4883             (void) strkitten(buf, flags.end_disclose[i]);
4884             (void) strkitten(buf, disclosure_options[i]);
4885         }
4886     else if (!strcmp(optname, "dogname"))
4887         Sprintf(buf, "%s", dogname[0] ? dogname : none);
4888     else if (!strcmp(optname, "dungeon"))
4889         Sprintf(buf, "%s", to_be_done);
4890     else if (!strcmp(optname, "effects"))
4891         Sprintf(buf, "%s", to_be_done);
4892     else if (!strcmp(optname, "font_map"))
4893         Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
4894     else if (!strcmp(optname, "font_message"))
4895         Sprintf(buf, "%s",
4896                 iflags.wc_font_message ? iflags.wc_font_message : defopt);
4897     else if (!strcmp(optname, "font_status"))
4898         Sprintf(buf, "%s",
4899                 iflags.wc_font_status ? iflags.wc_font_status : defopt);
4900     else if (!strcmp(optname, "font_menu"))
4901         Sprintf(buf, "%s",
4902                 iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
4903     else if (!strcmp(optname, "font_text"))
4904         Sprintf(buf, "%s",
4905                 iflags.wc_font_text ? iflags.wc_font_text : defopt);
4906     else if (!strcmp(optname, "font_size_map")) {
4907         if (iflags.wc_fontsiz_map)
4908             Sprintf(buf, "%d", iflags.wc_fontsiz_map);
4909         else
4910             Strcpy(buf, defopt);
4911     } else if (!strcmp(optname, "font_size_message")) {
4912         if (iflags.wc_fontsiz_message)
4913             Sprintf(buf, "%d", iflags.wc_fontsiz_message);
4914         else
4915             Strcpy(buf, defopt);
4916     } else if (!strcmp(optname, "font_size_status")) {
4917         if (iflags.wc_fontsiz_status)
4918             Sprintf(buf, "%d", iflags.wc_fontsiz_status);
4919         else
4920             Strcpy(buf, defopt);
4921     } else if (!strcmp(optname, "font_size_menu")) {
4922         if (iflags.wc_fontsiz_menu)
4923             Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
4924         else
4925             Strcpy(buf, defopt);
4926     } else if (!strcmp(optname, "font_size_text")) {
4927         if (iflags.wc_fontsiz_text)
4928             Sprintf(buf, "%d", iflags.wc_fontsiz_text);
4929         else
4930             Strcpy(buf, defopt);
4931     } else if (!strcmp(optname, "fruit"))
4932         Sprintf(buf, "%s", pl_fruit);
4933     else if (!strcmp(optname, "gender"))
4934         Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
4935     else if (!strcmp(optname, "horsename"))
4936         Sprintf(buf, "%s", horsename[0] ? horsename : none);
4937     else if (!strcmp(optname, "map_mode"))
4938         Sprintf(buf, "%s",
4939                 iflags.wc_map_mode == MAP_MODE_TILES
4940                   ? "tiles"
4941                   : iflags.wc_map_mode == MAP_MODE_ASCII4x6
4942                      ? "ascii4x6"
4943                      : iflags.wc_map_mode == MAP_MODE_ASCII6x8
4944                         ? "ascii6x8"
4945                         : iflags.wc_map_mode == MAP_MODE_ASCII8x8
4946                            ? "ascii8x8"
4947                            : iflags.wc_map_mode == MAP_MODE_ASCII16x8
4948                               ? "ascii16x8"
4949                               : iflags.wc_map_mode == MAP_MODE_ASCII7x12
4950                                  ? "ascii7x12"
4951                                  : iflags.wc_map_mode == MAP_MODE_ASCII8x12
4952                                     ? "ascii8x12"
4953                                     : iflags.wc_map_mode
4954                                       == MAP_MODE_ASCII16x12
4955                                        ? "ascii16x12"
4956                                        : iflags.wc_map_mode
4957                                          == MAP_MODE_ASCII12x16
4958                                           ? "ascii12x16"
4959                                           : iflags.wc_map_mode
4960                                             == MAP_MODE_ASCII10x18
4961                                              ? "ascii10x18"
4962                                              : iflags.wc_map_mode
4963                                                == MAP_MODE_ASCII_FIT_TO_SCREEN
4964                                                 ? "fit_to_screen"
4965                                                 : defopt);
4966     else if (!strcmp(optname, "menustyle"))
4967         Sprintf(buf, "%s", menutype[(int) flags.menu_style]);
4968     else if (!strcmp(optname, "menu_deselect_all"))
4969         Sprintf(buf, "%s", to_be_done);
4970     else if (!strcmp(optname, "menu_deselect_page"))
4971         Sprintf(buf, "%s", to_be_done);
4972     else if (!strcmp(optname, "menu_first_page"))
4973         Sprintf(buf, "%s", to_be_done);
4974     else if (!strcmp(optname, "menu_invert_all"))
4975         Sprintf(buf, "%s", to_be_done);
4976     else if (!strcmp(optname, "menu_headings"))
4977         Sprintf(buf, "%s", attr2attrname(iflags.menu_headings));
4978     else if (!strcmp(optname, "menu_invert_page"))
4979         Sprintf(buf, "%s", to_be_done);
4980     else if (!strcmp(optname, "menu_last_page"))
4981         Sprintf(buf, "%s", to_be_done);
4982     else if (!strcmp(optname, "menu_next_page"))
4983         Sprintf(buf, "%s", to_be_done);
4984     else if (!strcmp(optname, "menu_previous_page"))
4985         Sprintf(buf, "%s", to_be_done);
4986     else if (!strcmp(optname, "menu_search"))
4987         Sprintf(buf, "%s", to_be_done);
4988     else if (!strcmp(optname, "menu_select_all"))
4989         Sprintf(buf, "%s", to_be_done);
4990     else if (!strcmp(optname, "menu_select_page"))
4991         Sprintf(buf, "%s", to_be_done);
4992     else if (!strcmp(optname, "monsters")) {
4993         Sprintf(buf, "%s", to_be_done);
4994     } else if (!strcmp(optname, "msghistory")) {
4995         Sprintf(buf, "%u", iflags.msg_history);
4996 #ifdef TTY_GRAPHICS
4997     } else if (!strcmp(optname, "msg_window")) {
4998         Sprintf(buf, "%s", (iflags.prevmsg_window == 's')
4999                                ? "single"
5000                                : (iflags.prevmsg_window == 'c')
5001                                      ? "combination"
5002                                      : (iflags.prevmsg_window == 'f')
5003                                            ? "full"
5004                                            : "reversed");
5005 #endif
5006     } else if (!strcmp(optname, "name")) {
5007         Sprintf(buf, "%s", plname);
5008     } else if (!strcmp(optname, "number_pad")) {
5009         static const char *numpadmodes[] = {
5010 /*JP
5011             "0=off", "1=on", "2=on, MSDOS compatible",
5012 */
5013             "0=\96³\8cø", "1=\97L\8cø", "2=\97L\8cø\81CDOS\8cÝ\8a·",
5014 /*JP
5015             "3=on, phone-style layout",
5016 */
5017             "3=\97L\8cø\81C\93d\98b\8e®\82Ì\90\94\8e\9a\94z\92u",
5018 /*JP
5019             "4=on, phone layout, MSDOS compatible",
5020 */
5021             "4=\97L\8cø\81C\93d\98b\8e®\82Ì\94z\92u\81CMSDOS \8cÝ\8a·",
5022 #if 0 /*JP*/
5023             "-1=off, y & z swapped", /*[5]*/
5024 #else
5025             "-1=\96³\8cø\81Cy\82Æz\82ð\93ü\82ê\91Ö\82¦", /*[5]*/
5026 #endif
5027         };
5028         int indx = Cmd.num_pad
5029                        ? (Cmd.phone_layout ? (Cmd.pcHack_compat ? 4 : 3)
5030                                            : (Cmd.pcHack_compat ? 2 : 1))
5031                        : Cmd.swap_yz ? 5 : 0;
5032
5033         Strcpy(buf, numpadmodes[indx]);
5034     } else if (!strcmp(optname, "objects")) {
5035         Sprintf(buf, "%s", to_be_done);
5036     } else if (!strcmp(optname, "packorder")) {
5037         oc_to_str(flags.inv_order, ocl);
5038         Sprintf(buf, "%s", ocl);
5039 #ifdef CHANGE_COLOR
5040     } else if (!strcmp(optname, "palette")) {
5041         Sprintf(buf, "%s", get_color_string());
5042 #endif
5043     } else if (!strcmp(optname, "paranoid_confirmation")) {
5044         char tmpbuf[QBUFSZ];
5045
5046         tmpbuf[0] = '\0';
5047         if (ParanoidConfirm)
5048             Strcat(tmpbuf, " Confirm");
5049         if (ParanoidQuit)
5050             Strcat(tmpbuf, " quit");
5051         if (ParanoidDie)
5052             Strcat(tmpbuf, " die");
5053         if (ParanoidBones)
5054             Strcat(tmpbuf, " bones");
5055         if (ParanoidHit)
5056             Strcat(tmpbuf, " attack");
5057         if (ParanoidPray)
5058             Strcat(tmpbuf, " pray");
5059         if (ParanoidRemove)
5060             Strcat(tmpbuf, " Remove");
5061         Strcpy(buf, tmpbuf[0] ? &tmpbuf[1] : "none");
5062     } else if (!strcmp(optname, "pettype")) {
5063 #if 0 /*JP*/
5064         Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat"
5065                            : (preferred_pet == 'd') ? "dog"
5066                              : (preferred_pet == 'h') ? "horse"
5067                                : (preferred_pet == 'n') ? "none"
5068                                  : "random");
5069 #else
5070         Sprintf(buf, "%s", (preferred_pet == 'c') ? "\94L"
5071                            : (preferred_pet == 'd') ? "\8c¢"
5072                              : (preferred_pet == 'h') ? "\94n"
5073                                : (preferred_pet == 'n') ? "\82È\82µ"
5074                                  : "\83\89\83\93\83_\83\80");
5075 #endif
5076     } else if (!strcmp(optname, "pickup_burden")) {
5077         Sprintf(buf, "%s", burdentype[flags.pickup_burden]);
5078     } else if (!strcmp(optname, "pickup_types")) {
5079         oc_to_str(flags.pickup_types, ocl);
5080         Sprintf(buf, "%s", ocl[0] ? ocl : "all");
5081     } else if (!strcmp(optname, "pile_limit")) {
5082         Sprintf(buf, "%d", flags.pile_limit);
5083     } else if (!strcmp(optname, "playmode")) {
5084         Strcpy(buf, wizard ? "debug" : discover ? "explore" : "normal");
5085     } else if (!strcmp(optname, "race")) {
5086         Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
5087     } else if (!strcmp(optname, "roguesymset")) {
5088         Sprintf(buf, "%s",
5089                 symset[ROGUESET].name ? symset[ROGUESET].name : "default");
5090         if (currentgraphics == ROGUESET && symset[ROGUESET].name)
5091             Strcat(buf, ", active");
5092     } else if (!strcmp(optname, "role")) {
5093         Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
5094     } else if (!strcmp(optname, "runmode")) {
5095         Sprintf(buf, "%s", runmodes[flags.runmode]);
5096     } else if (!strcmp(optname, "scores")) {
5097         Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around,
5098                 flags.end_own ? "/own" : "");
5099     } else if (!strcmp(optname, "scroll_amount")) {
5100         if (iflags.wc_scroll_amount)
5101             Sprintf(buf, "%d", iflags.wc_scroll_amount);
5102         else
5103             Strcpy(buf, defopt);
5104     } else if (!strcmp(optname, "scroll_margin")) {
5105         if (iflags.wc_scroll_margin)
5106             Sprintf(buf, "%d", iflags.wc_scroll_margin);
5107         else
5108             Strcpy(buf, defopt);
5109     } else if (!strcmp(optname, "sortloot")) {
5110         for (i = 0; i < SIZE(sortltype); i++)
5111             if (flags.sortloot == sortltype[i][0]) {
5112                 Strcpy(buf, sortltype[i]);
5113                 break;
5114             }
5115     } else if (!strcmp(optname, "player_selection")) {
5116 #if 0 /*JP*/
5117         Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
5118 #else
5119         Sprintf(buf, "%s\93ü\97Í", iflags.wc_player_selection ? "\83v\83\8d\83\93\83v\83g" : "\83_\83C\83A\83\8d\83O");
5120 #endif
5121 #ifdef MSDOS
5122     } else if (!strcmp(optname, "soundcard")) {
5123         Sprintf(buf, "%s", to_be_done);
5124 #endif
5125     } else if (!strcmp(optname, "suppress_alert")) {
5126         if (flags.suppress_alert == 0L)
5127             Strcpy(buf, none);
5128         else
5129             Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
5130                     FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
5131     } else if (!strcmp(optname, "symset")) {
5132         Sprintf(buf, "%s",
5133                 symset[PRIMARY].name ? symset[PRIMARY].name : "default");
5134         if (currentgraphics == PRIMARY && symset[PRIMARY].name)
5135             Strcat(buf, ", active");
5136     } else if (!strcmp(optname, "tile_file")) {
5137         Sprintf(buf, "%s",
5138                 iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
5139     } else if (!strcmp(optname, "tile_height")) {
5140         if (iflags.wc_tile_height)
5141             Sprintf(buf, "%d", iflags.wc_tile_height);
5142         else
5143             Strcpy(buf, defopt);
5144     } else if (!strcmp(optname, "tile_width")) {
5145         if (iflags.wc_tile_width)
5146             Sprintf(buf, "%d", iflags.wc_tile_width);
5147         else
5148             Strcpy(buf, defopt);
5149     } else if (!strcmp(optname, "traps")) {
5150         Sprintf(buf, "%s", to_be_done);
5151     } else if (!strcmp(optname, "vary_msgcount")) {
5152         if (iflags.wc_vary_msgcount)
5153             Sprintf(buf, "%d", iflags.wc_vary_msgcount);
5154         else
5155             Strcpy(buf, defopt);
5156 #ifdef MSDOS
5157     } else if (!strcmp(optname, "video")) {
5158         Sprintf(buf, "%s", to_be_done);
5159 #endif
5160 #ifdef VIDEOSHADES
5161     } else if (!strcmp(optname, "videoshades")) {
5162         Sprintf(buf, "%s-%s-%s", shade[0], shade[1], shade[2]);
5163     } else if (!strcmp(optname, "videocolors")) {
5164         Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
5165                 ttycolors[CLR_RED], ttycolors[CLR_GREEN],
5166                 ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
5167                 ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
5168                 ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
5169                 ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
5170                 ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]);
5171 #endif /* VIDEOSHADES */
5172     } else if (!strcmp(optname, "windowtype")) {
5173         Sprintf(buf, "%s", windowprocs.name);
5174     } else if (!strcmp(optname, "windowcolors")) {
5175         Sprintf(
5176             buf, "%s/%s %s/%s %s/%s %s/%s",
5177             iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
5178             iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
5179             iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message
5180                                        : defbrief,
5181             iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message
5182                                        : defbrief,
5183             iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
5184             iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
5185             iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
5186             iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
5187 #ifdef PREFIXES_IN_USE
5188     } else {
5189         for (i = 0; i < PREFIX_COUNT; ++i)
5190             if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
5191                 Sprintf(buf, "%s", fqn_prefix[i]);
5192 #endif
5193     }
5194
5195     if (buf[0])
5196         return buf;
5197     else
5198 /*JP
5199         return "unknown";
5200 */
5201         return "\95s\96¾";
5202 }
5203
5204 int
5205 dotogglepickup()
5206 {
5207     char buf[BUFSZ], ocl[MAXOCLASSES + 1];
5208
5209     flags.pickup = !flags.pickup;
5210     if (flags.pickup) {
5211         oc_to_str(flags.pickup_types, ocl);
5212 #if 0 /*JP*/
5213         Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
5214                 (iflags.autopickup_exceptions[AP_LEAVE]
5215                  || iflags.autopickup_exceptions[AP_GRAB])
5216                     ? ((count_ape_maps((int *) 0, (int *) 0) == 1)
5217                            ? ", with one exception"
5218                            : ", with some exceptions")
5219                     : "");
5220 #else
5221         Sprintf(buf, "%s\83A\83C\83e\83\80\82É\82Â\82¢\82Ä\83I\83\93%s", ocl[0] ? ocl : "\91S\82Ä\82Ì",
5222                 (iflags.autopickup_exceptions[AP_LEAVE]
5223                  || iflags.autopickup_exceptions[AP_GRAB])
5224                     ? "\81C\97á\8aO\82 \82è"
5225                     : "");
5226 #endif
5227     } else {
5228 /*JP
5229         Strcpy(buf, "OFF");
5230 */
5231         Strcpy(buf, "\83I\83t");
5232     }
5233 /*JP
5234     pline("Autopickup: %s.", buf);
5235 */
5236     pline("\8e©\93®\8fE\82¢\81F%s\81D", buf);
5237     return 0;
5238 }
5239
5240 int
5241 add_autopickup_exception(mapping)
5242 const char *mapping;
5243 {
5244     struct autopickup_exception *ape, **apehead;
5245     char text[256], *text2;
5246     boolean grab = FALSE;
5247
5248     if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
5249         text2 = &text[0];
5250         if (*text2 == '<') { /* force autopickup */
5251             grab = TRUE;
5252             ++text2;
5253         } else if (*text2 == '>') { /* default - Do not pickup */
5254             grab = FALSE;
5255             ++text2;
5256         }
5257         apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB]
5258                          : &iflags.autopickup_exceptions[AP_LEAVE];
5259         ape = (struct autopickup_exception *) alloc(
5260                                         sizeof (struct autopickup_exception));
5261         ape->regex = regex_init();
5262         if (!regex_compile(text2, ape->regex)) {
5263             raw_print("regex error in AUTOPICKUP_EXCEPTION");
5264             regex_free(ape->regex);
5265             free((genericptr_t) ape);
5266             return 0;
5267         }
5268         ape->pattern = (char *) alloc(strlen(text2) + 1);
5269         strcpy(ape->pattern, text2);
5270         ape->grab = grab;
5271         ape->next = *apehead;
5272         *apehead = ape;
5273     } else {
5274         raw_print("syntax error in AUTOPICKUP_EXCEPTION");
5275         return 0;
5276     }
5277     return 1;
5278 }
5279
5280 STATIC_OVL void
5281 remove_autopickup_exception(whichape)
5282 struct autopickup_exception *whichape;
5283 {
5284     struct autopickup_exception *ape, *prev = 0;
5285     int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
5286
5287     for (ape = iflags.autopickup_exceptions[chain]; ape;) {
5288         if (ape == whichape) {
5289             struct autopickup_exception *freeape = ape;
5290
5291             ape = ape->next;
5292             if (prev)
5293                 prev->next = ape;
5294             else
5295                 iflags.autopickup_exceptions[chain] = ape;
5296             regex_free(freeape->regex);
5297             free((genericptr_t) freeape->pattern);
5298             free((genericptr_t) freeape);
5299         } else {
5300             prev = ape;
5301             ape = ape->next;
5302         }
5303     }
5304 }
5305
5306 STATIC_OVL int
5307 count_ape_maps(leave, grab)
5308 int *leave, *grab;
5309 {
5310     struct autopickup_exception *ape;
5311     int pass, totalapes, numapes[2] = { 0, 0 };
5312
5313     for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
5314         ape = iflags.autopickup_exceptions[pass];
5315         while (ape) {
5316             ape = ape->next;
5317             numapes[pass]++;
5318         }
5319     }
5320     totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
5321     if (leave)
5322         *leave = numapes[AP_LEAVE];
5323     if (grab)
5324         *grab = numapes[AP_GRAB];
5325     return totalapes;
5326 }
5327
5328 void
5329 free_autopickup_exceptions()
5330 {
5331     struct autopickup_exception *ape;
5332     int pass;
5333
5334     for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
5335         while ((ape = iflags.autopickup_exceptions[pass]) != 0) {
5336             regex_free(ape->regex);
5337             free((genericptr_t) ape->pattern);
5338             iflags.autopickup_exceptions[pass] = ape->next;
5339             free((genericptr_t) ape);
5340         }
5341     }
5342 }
5343
5344 /* bundle some common usage into one easy-to-use routine */
5345 int
5346 load_symset(s, which_set)
5347 const char *s;
5348 int which_set;
5349 {
5350     clear_symsetentry(which_set, TRUE);
5351
5352     if (symset[which_set].name)
5353         free((genericptr_t) symset[which_set].name);
5354     symset[which_set].name = dupstr(s);
5355
5356     if (read_sym_file(which_set)) {
5357         switch_symbols(TRUE);
5358     } else {
5359         clear_symsetentry(which_set, TRUE);
5360         return 0;
5361     }
5362     return 1;
5363 }
5364
5365 void
5366 free_symsets()
5367 {
5368     clear_symsetentry(PRIMARY, TRUE);
5369     clear_symsetentry(ROGUESET, TRUE);
5370
5371     /* symset_list is cleaned up as soon as it's used, so we shouldn't
5372        have to anything about it here */
5373     /* assert( symset_list == NULL ); */
5374 }
5375
5376 /* Parse the value of a SYMBOLS line from a config file */
5377 void
5378 parsesymbols(opts)
5379 register char *opts;
5380 {
5381     int val;
5382     char *op, *symname, *strval;
5383     struct symparse *symp;
5384
5385     if ((op = index(opts, ',')) != 0) {
5386         *op++ = 0;
5387         parsesymbols(op);
5388     }
5389
5390     /* S_sample:string */
5391     symname = opts;
5392     strval = index(opts, ':');
5393     if (!strval)
5394         strval = index(opts, '=');
5395     if (!strval)
5396         return;
5397     *strval++ = '\0';
5398
5399     /* strip leading and trailing white space from symname and strval */
5400     mungspaces(symname);
5401     mungspaces(strval);
5402
5403     symp = match_sym(symname);
5404     if (!symp)
5405         return;
5406
5407     if (symp->range && symp->range != SYM_CONTROL) {
5408         val = sym_val(strval);
5409         update_l_symset(symp, val);
5410     }
5411 }
5412
5413 struct symparse *
5414 match_sym(buf)
5415 char *buf;
5416 {
5417     size_t len = strlen(buf);
5418     const char *p = index(buf, ':'), *q = index(buf, '=');
5419     struct symparse *sp = loadsyms;
5420
5421     if (!p || (q && q < p))
5422         p = q;
5423     if (p) {
5424         /* note: there will be at most one space before the '='
5425            because caller has condensed buf[] with mungspaces() */
5426         if (p > buf && p[-1] == ' ')
5427             p--;
5428         len = (int) (p - buf);
5429     }
5430     while (sp->range) {
5431         if ((len >= strlen(sp->name)) && !strncmpi(buf, sp->name, len))
5432             return sp;
5433         sp++;
5434     }
5435     return (struct symparse *) 0;
5436 }
5437
5438 int
5439 sym_val(strval)
5440 char *strval;
5441 {
5442     char buf[QBUFSZ];
5443     buf[0] = '\0';
5444     escapes(strval, buf);
5445     return (int) *buf;
5446 }
5447
5448 /* data for option_help() */
5449 static const char *opt_intro[] = {
5450 /*JP
5451     "", "                 NetHack Options Help:", "",
5452 */
5453     "", "               NetHack\83I\83v\83V\83\87\83\93\83w\83\8b\83v\81F", "",
5454 #define CONFIG_SLOT 3 /* fill in next value at run-time */
5455     (char *) 0,
5456 #if !defined(MICRO) && !defined(MAC)
5457 /*JP
5458     "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
5459 */
5460     "\82Ü\82½\82Í\8aÂ\8b«\95Ï\90\94\82É`NETHACKOPTIONS=\"<options>\"'\82Æ\92è\8b`\82Å\82«\82Ü\82·",
5461 #endif
5462 /*JP
5463     "(<options> is a list of options separated by commas)",
5464 */
5465     "(<options>\82Í\83J\83\93\83}\82Å\8bæ\90Ø\82Á\82½\83I\83v\83V\83\87\83\93\82Å\82·)",
5466 #ifdef VMS
5467 /*JP
5468     "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
5469 */
5470     "-- \97á\82¦\82Î\8e\9f\82Ì\82æ\82¤\82É\82µ\82Ü\82·\81F$ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
5471 #endif
5472 /*JP
5473     "or press \"O\" while playing and use the menu.", "",
5474 */
5475     "\82à\82µ\82­\82Í\83Q\81[\83\80\83v\83\8c\83C\92\86\82É\"O\"\83{\83^\83\93\82ð\89\9f\82·\82±\82Æ\82Å\90Ý\92è\89Â\94\\82Å\82·\81D",
5476 /*JP
5477  "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
5478 */
5479  "\90^\8bU\92l\83I\83v\83V\83\87\83\93 (\94Û\92è\82Ì\92l\82ð\8ew\92è\82·\82é\8fê\8d\87\81C'!'\82à\82µ\82­\82Í\"no\"\82ð\90æ\93ª\82É\95t\89Á\82µ\82Ü\82·):",
5480     (char *) 0
5481 };
5482
5483 static const char *opt_epilog[] = {
5484     "",
5485 /*JP
5486     "Some of the options can be set only before the game is started; those",
5487 */
5488     "\83I\83v\83V\83\87\83\93\82É\82Í\83Q\81[\83\80\8aJ\8en\91O\82Ì\82Ý\82É\82µ\82©\90Ý\92è\82Å\82«\82È\82¢\82à\82Ì\82ª\82 \82è\82Ü\82·\81D",
5489 /*JP
5490     "items will not be selectable in the 'O' command's menu.", (char *) 0
5491 */
5492     "\82»\82ê\82ç\82Í'O'\83R\83}\83\93\83h\82Ì\83\81\83j\83\85\81[\82Å\82Í\91I\91ð\82·\82é\82±\82Æ\82ª\82Å\82«\82Ü\82¹\82ñ\81D", (char *) 0
5493 };
5494
5495 void
5496 option_help()
5497 {
5498     char buf[BUFSZ], buf2[BUFSZ];
5499     register int i;
5500     winid datawin;
5501
5502     datawin = create_nhwindow(NHW_TEXT);
5503 /*JP
5504     Sprintf(buf, "Set options as OPTIONS=<options> in %s", lastconfigfile);
5505 */
5506     Sprintf(buf, "\83I\83v\83V\83\87\83\93\82Í%s\82Ì\92\86\82ÅOPTIONS=<options>\82Æ\90Ý\92è\82µ\82Ü\82·", lastconfigfile);
5507     opt_intro[CONFIG_SLOT] = (const char *) buf;
5508     for (i = 0; opt_intro[i]; i++)
5509         putstr(datawin, 0, opt_intro[i]);
5510
5511     /* Boolean options */
5512     for (i = 0; boolopt[i].name; i++) {
5513         if (boolopt[i].addr) {
5514             if (boolopt[i].addr == &iflags.sanity_check && !wizard)
5515                 continue;
5516             if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard)
5517                 continue;
5518             next_opt(datawin, boolopt[i].name);
5519         }
5520     }
5521     next_opt(datawin, "");
5522
5523     /* Compound options */
5524 /*JP
5525     putstr(datawin, 0, "Compound options:");
5526 */
5527     putstr(datawin, 0, "\95\8e\9a\97ñ\83I\83v\83V\83\87\83\93:");
5528     for (i = 0; compopt[i].name; i++) {
5529         Sprintf(buf2, "`%s'", compopt[i].name);
5530         Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
5531                 compopt[i + 1].name ? ',' : '.');
5532         putstr(datawin, 0, buf);
5533     }
5534
5535     for (i = 0; opt_epilog[i]; i++)
5536         putstr(datawin, 0, opt_epilog[i]);
5537
5538     display_nhwindow(datawin, FALSE);
5539     destroy_nhwindow(datawin);
5540     return;
5541 }
5542
5543 /*
5544  * prints the next boolean option, on the same line if possible, on a new
5545  * line if not. End with next_opt("").
5546  */
5547 void
5548 next_opt(datawin, str)
5549 winid datawin;
5550 const char *str;
5551 {
5552     static char *buf = 0;
5553     int i;
5554     char *s;
5555
5556     if (!buf)
5557         *(buf = (char *) alloc(BUFSZ)) = '\0';
5558
5559     if (!*str) {
5560         s = eos(buf);
5561         if (s > &buf[1] && s[-2] == ',')
5562             Strcpy(s - 2, "."); /* replace last ", " */
5563         i = COLNO;              /* (greater than COLNO - 2) */
5564     } else {
5565         i = strlen(buf) + strlen(str) + 2;
5566     }
5567
5568     if (i > COLNO - 2) { /* rule of thumb */
5569         putstr(datawin, 0, buf);
5570         buf[0] = 0;
5571     }
5572     if (*str) {
5573         Strcat(buf, str);
5574         Strcat(buf, ", ");
5575     } else {
5576         putstr(datawin, 0, str);
5577         free((genericptr_t) buf), buf = 0;
5578     }
5579     return;
5580 }
5581
5582 /* Returns the fid of the fruit type; if that type already exists, it
5583  * returns the fid of that one; if it does not exist, it adds a new fruit
5584  * type to the chain and returns the new one.
5585  * If replace_fruit is sent in, replace the fruit in the chain rather than
5586  * adding a new entry--for user specified fruits only.
5587  */
5588 int
5589 fruitadd(str, replace_fruit)
5590 char *str;
5591 struct fruit *replace_fruit;
5592 {
5593     register int i;
5594     register struct fruit *f;
5595     int highest_fruit_id = 0;
5596     char buf[PL_FSIZ], altname[PL_FSIZ];
5597     boolean user_specified = (str == pl_fruit);
5598     /* if not user-specified, then it's a fruit name for a fruit on
5599      * a bones level...
5600      */
5601
5602     /* Note: every fruit has an id (kept in obj->spe) of at least 1;
5603      * 0 is an error.
5604      */
5605     if (user_specified) {
5606         boolean found = FALSE, numeric = FALSE;
5607
5608         /* force fruit to be singular; this handling is not
5609            needed--or wanted--for fruits from bones because
5610            they already received it in their original game */
5611         nmcpy(pl_fruit, makesingular(str), PL_FSIZ);
5612         /* assert( str == pl_fruit ); */
5613
5614         /* disallow naming after other foods (since it'd be impossible
5615          * to tell the difference)
5616          */
5617
5618         for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) {
5619             if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
5620                 found = TRUE;
5621                 break;
5622             }
5623         }
5624         {
5625             char *c;
5626
5627             c = pl_fruit;
5628
5629             for (c = pl_fruit; *c >= '0' && *c <= '9'; c++)
5630                 ;
5631             if (isspace((uchar) *c) || *c == 0)
5632                 numeric = TRUE;
5633         }
5634         if (found || numeric || !strncmp(str, "cursed ", 7)
5635             || !strncmp(str, "uncursed ", 9) || !strncmp(str, "blessed ", 8)
5636             || !strncmp(str, "partly eaten ", 13)
5637             || (!strncmp(str, "tin of ", 7)
5638                 && (!strcmp(str + 7, "spinach")
5639                     || name_to_mon(str + 7) >= LOW_PM))
5640             || !strcmp(str, "empty tin")
5641             || ((str_end_is(str, " corpse")
5642                  || str_end_is(str, " egg"))
5643                 && name_to_mon(str) >= LOW_PM)) {
5644             Strcpy(buf, pl_fruit);
5645             Strcpy(pl_fruit, "candied ");
5646             nmcpy(pl_fruit + 8, buf, PL_FSIZ - 8);
5647         }
5648         *altname = '\0';
5649         /* This flag indicates that a fruit has been made since the
5650          * last time the user set the fruit.  If it hasn't, we can
5651          * safely overwrite the current fruit, preventing the user from
5652          * setting many fruits in a row and overflowing.
5653          * Possible expansion: check for specific fruit IDs, not for
5654          * any fruit.
5655          */
5656         flags.made_fruit = FALSE;
5657         if (replace_fruit) {
5658             for (f = ffruit; f; f = f->nextf) {
5659                 if (f == replace_fruit) {
5660                     copynchars(f->fname, str, PL_FSIZ - 1);
5661                     goto nonew;
5662                 }
5663             }
5664         }
5665     } else {
5666         /* not user_supplied, so assumed to be from bones */
5667         copynchars(altname, str, PL_FSIZ - 1);
5668         sanitize_name(altname);
5669         flags.made_fruit = TRUE; /* for safety.  Any fruit name added from a
5670                                     bones level should exist anyway. */
5671     }
5672     for (f = ffruit; f; f = f->nextf) {
5673         if (f->fid > highest_fruit_id)
5674             highest_fruit_id = f->fid;
5675         if (!strncmp(str, f->fname, PL_FSIZ - 1)
5676             || (*altname && !strcmp(altname, f->fname)))
5677             goto nonew;
5678     }
5679     /* if adding another fruit would overflow spe, use a random
5680        fruit instead... we've got a lot to choose from.
5681        current_fruit remains as is. */
5682     if (highest_fruit_id >= 127)
5683         return rnd(127);
5684
5685     f = newfruit();
5686     copynchars(f->fname, *altname ? altname : str, PL_FSIZ - 1);
5687     f->fid = ++highest_fruit_id;
5688     /* we used to go out of our way to add it at the end of the list,
5689        but the order is arbitrary so use simpler insertion at start */
5690     f->nextf = ffruit;
5691     ffruit = f;
5692 nonew:
5693     if (user_specified)
5694         context.current_fruit = f->fid;
5695     return f->fid;
5696 }
5697
5698 /*
5699  * This is a somewhat generic menu for taking a list of NetHack style
5700  * class choices and presenting them via a description
5701  * rather than the traditional NetHack characters.
5702  * (Benefits users whose first exposure to NetHack is via tiles).
5703  *
5704  * prompt
5705  *           The title at the top of the menu.
5706  *
5707  * category: 0 = monster class
5708  *           1 = object  class
5709  *
5710  * way
5711  *           FALSE = PICK_ONE, TRUE = PICK_ANY
5712  *
5713  * class_list
5714  *           a null terminated string containing the list of choices.
5715  *
5716  * class_selection
5717  *           a null terminated string containing the selected characters.
5718  *
5719  * Returns number selected.
5720  */
5721 int
5722 choose_classes_menu(prompt, category, way, class_list, class_select)
5723 const char *prompt;
5724 int category;
5725 boolean way;
5726 char *class_list;
5727 char *class_select;
5728 {
5729     menu_item *pick_list = (menu_item *) 0;
5730     winid win;
5731     anything any;
5732     char buf[BUFSZ];
5733     int i, n;
5734     int ret;
5735     int next_accelerator, accelerator;
5736
5737     if (class_list == (char *) 0 || class_select == (char *) 0)
5738         return 0;
5739     accelerator = 0;
5740     next_accelerator = 'a';
5741     any = zeroany;
5742     win = create_nhwindow(NHW_MENU);
5743     start_menu(win);
5744     while (*class_list) {
5745         const char *text;
5746         boolean selected;
5747
5748         text = (char *) 0;
5749         selected = FALSE;
5750         switch (category) {
5751         case 0:
5752             text = def_monsyms[def_char_to_monclass(*class_list)].explain;
5753             accelerator = *class_list;
5754             Sprintf(buf, "%s", text);
5755             break;
5756         case 1:
5757             text = def_oc_syms[def_char_to_objclass(*class_list)].explain;
5758             accelerator = next_accelerator;
5759             Sprintf(buf, "%c  %s", *class_list, text);
5760             break;
5761         default:
5762             impossible("choose_classes_menu: invalid category %d", category);
5763         }
5764         if (way && *class_select) { /* Selections there already */
5765             if (index(class_select, *class_list)) {
5766                 selected = TRUE;
5767             }
5768         }
5769         any.a_int = *class_list;
5770         add_menu(win, NO_GLYPH, &any, accelerator, category ? *class_list : 0,
5771                  ATR_NONE, buf, selected);
5772         ++class_list;
5773         if (category > 0) {
5774             ++next_accelerator;
5775             if (next_accelerator == ('z' + 1))
5776                 next_accelerator = 'A';
5777             if (next_accelerator == ('Z' + 1))
5778                 break;
5779         }
5780     }
5781     end_menu(win, prompt);
5782     n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
5783     destroy_nhwindow(win);
5784     if (n > 0) {
5785         for (i = 0; i < n; ++i)
5786             *class_select++ = (char) pick_list[i].item.a_int;
5787         free((genericptr_t) pick_list);
5788         ret = n;
5789     } else if (n == -1) {
5790         class_select = eos(class_select);
5791         ret = -1;
5792     } else
5793         ret = 0;
5794     *class_select = '\0';
5795     return ret;
5796 }
5797
5798 struct wc_Opt wc_options[] = { { "ascii_map", WC_ASCII_MAP },
5799                                { "color", WC_COLOR },
5800                                { "eight_bit_tty", WC_EIGHT_BIT_IN },
5801                                { "hilite_pet", WC_HILITE_PET },
5802                                { "popup_dialog", WC_POPUP_DIALOG },
5803                                { "player_selection", WC_PLAYER_SELECTION },
5804                                { "preload_tiles", WC_PRELOAD_TILES },
5805                                { "tiled_map", WC_TILED_MAP },
5806                                { "tile_file", WC_TILE_FILE },
5807                                { "tile_width", WC_TILE_WIDTH },
5808                                { "tile_height", WC_TILE_HEIGHT },
5809                                { "use_inverse", WC_INVERSE },
5810                                { "align_message", WC_ALIGN_MESSAGE },
5811                                { "align_status", WC_ALIGN_STATUS },
5812                                { "font_map", WC_FONT_MAP },
5813                                { "font_menu", WC_FONT_MENU },
5814                                { "font_message", WC_FONT_MESSAGE },
5815 #if 0
5816                                {"perm_invent", WC_PERM_INVENT},
5817 #endif
5818                                { "font_size_map", WC_FONTSIZ_MAP },
5819                                { "font_size_menu", WC_FONTSIZ_MENU },
5820                                { "font_size_message", WC_FONTSIZ_MESSAGE },
5821                                { "font_size_status", WC_FONTSIZ_STATUS },
5822                                { "font_size_text", WC_FONTSIZ_TEXT },
5823                                { "font_status", WC_FONT_STATUS },
5824                                { "font_text", WC_FONT_TEXT },
5825                                { "map_mode", WC_MAP_MODE },
5826                                { "scroll_amount", WC_SCROLL_AMOUNT },
5827                                { "scroll_margin", WC_SCROLL_MARGIN },
5828                                { "splash_screen", WC_SPLASH_SCREEN },
5829                                { "vary_msgcount", WC_VARY_MSGCOUNT },
5830                                { "windowcolors", WC_WINDOWCOLORS },
5831                                { "mouse_support", WC_MOUSE_SUPPORT },
5832                                { (char *) 0, 0L } };
5833
5834 struct wc_Opt wc2_options[] = { { "fullscreen", WC2_FULLSCREEN },
5835                                 { "softkeyboard", WC2_SOFTKEYBOARD },
5836                                 { "wraptext", WC2_WRAPTEXT },
5837                                 { "use_darkgray", WC2_DARKGRAY },
5838 #ifdef STATUS_VIA_WINDOWPORT
5839                                 { "hilite_status", WC2_HILITE_STATUS },
5840 #endif
5841                                 { (char *) 0, 0L } };
5842
5843 /*
5844  * If a port wants to change or ensure that the SET_IN_SYS,
5845  * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
5846  * correct (for controlling its display in the option menu) call
5847  * set_option_mod_status()
5848  * with the appropriate second argument.
5849  */
5850 void
5851 set_option_mod_status(optnam, status)
5852 const char *optnam;
5853 int status;
5854 {
5855     int k;
5856
5857     if (SET__IS_VALUE_VALID(status)) {
5858         impossible("set_option_mod_status: status out of range %d.", status);
5859         return;
5860     }
5861     for (k = 0; boolopt[k].name; k++) {
5862         if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
5863             boolopt[k].optflags = status;
5864             return;
5865         }
5866     }
5867     for (k = 0; compopt[k].name; k++) {
5868         if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
5869             compopt[k].optflags = status;
5870             return;
5871         }
5872     }
5873 }
5874
5875 /*
5876  * You can set several wc_options in one call to
5877  * set_wc_option_mod_status() by setting
5878  * the appropriate bits for each option that you
5879  * are setting in the optmask argument
5880  * prior to calling.
5881  *    example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN,
5882  * SET_IN_GAME);
5883  */
5884 void
5885 set_wc_option_mod_status(optmask, status)
5886 unsigned long optmask;
5887 int status;
5888 {
5889     int k = 0;
5890
5891     if (SET__IS_VALUE_VALID(status)) {
5892         impossible("set_wc_option_mod_status: status out of range %d.",
5893                    status);
5894         return;
5895     }
5896     while (wc_options[k].wc_name) {
5897         if (optmask & wc_options[k].wc_bit) {
5898             set_option_mod_status(wc_options[k].wc_name, status);
5899         }
5900         k++;
5901     }
5902 }
5903
5904 STATIC_OVL boolean
5905 is_wc_option(optnam)
5906 const char *optnam;
5907 {
5908     int k = 0;
5909
5910     while (wc_options[k].wc_name) {
5911         if (strcmp(wc_options[k].wc_name, optnam) == 0)
5912             return TRUE;
5913         k++;
5914     }
5915     return FALSE;
5916 }
5917
5918 STATIC_OVL boolean
5919 wc_supported(optnam)
5920 const char *optnam;
5921 {
5922     int k = 0;
5923
5924     while (wc_options[k].wc_name) {
5925         if (!strcmp(wc_options[k].wc_name, optnam)
5926             && (windowprocs.wincap & wc_options[k].wc_bit))
5927             return TRUE;
5928         k++;
5929     }
5930     return FALSE;
5931 }
5932
5933 /*
5934  * You can set several wc2_options in one call to
5935  * set_wc2_option_mod_status() by setting
5936  * the appropriate bits for each option that you
5937  * are setting in the optmask argument
5938  * prior to calling.
5939  *    example:
5940  * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
5941  * SET_IN_FILE);
5942  */
5943
5944 void
5945 set_wc2_option_mod_status(optmask, status)
5946 unsigned long optmask;
5947 int status;
5948 {
5949     int k = 0;
5950
5951     if (SET__IS_VALUE_VALID(status)) {
5952         impossible("set_wc2_option_mod_status: status out of range %d.",
5953                    status);
5954         return;
5955     }
5956     while (wc2_options[k].wc_name) {
5957         if (optmask & wc2_options[k].wc_bit) {
5958             set_option_mod_status(wc2_options[k].wc_name, status);
5959         }
5960         k++;
5961     }
5962 }
5963
5964 STATIC_OVL boolean
5965 is_wc2_option(optnam)
5966 const char *optnam;
5967 {
5968     int k = 0;
5969
5970     while (wc2_options[k].wc_name) {
5971         if (strcmp(wc2_options[k].wc_name, optnam) == 0)
5972             return TRUE;
5973         k++;
5974     }
5975     return FALSE;
5976 }
5977
5978 STATIC_OVL boolean
5979 wc2_supported(optnam)
5980 const char *optnam;
5981 {
5982     int k = 0;
5983
5984     while (wc2_options[k].wc_name) {
5985         if (!strcmp(wc2_options[k].wc_name, optnam)
5986             && (windowprocs.wincap2 & wc2_options[k].wc_bit))
5987             return TRUE;
5988         k++;
5989     }
5990     return FALSE;
5991 }
5992
5993 STATIC_OVL void
5994 wc_set_font_name(opttype, fontname)
5995 int opttype;
5996 char *fontname;
5997 {
5998     char **fn = (char **) 0;
5999
6000     if (!fontname)
6001         return;
6002     switch (opttype) {
6003     case MAP_OPTION:
6004         fn = &iflags.wc_font_map;
6005         break;
6006     case MESSAGE_OPTION:
6007         fn = &iflags.wc_font_message;
6008         break;
6009     case TEXT_OPTION:
6010         fn = &iflags.wc_font_text;
6011         break;
6012     case MENU_OPTION:
6013         fn = &iflags.wc_font_menu;
6014         break;
6015     case STATUS_OPTION:
6016         fn = &iflags.wc_font_status;
6017         break;
6018     default:
6019         return;
6020     }
6021     if (fn) {
6022         if (*fn)
6023             free((genericptr_t) *fn);
6024         *fn = dupstr(fontname);
6025     }
6026     return;
6027 }
6028
6029 STATIC_OVL int
6030 wc_set_window_colors(op)
6031 char *op;
6032 {
6033     /* syntax:
6034      *  menu white/black message green/yellow status white/blue text
6035      * white/black
6036      */
6037     int j;
6038     char buf[BUFSZ];
6039     char *wn, *tfg, *tbg, *newop;
6040     static const char *wnames[] = { "menu", "message", "status", "text" };
6041     static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
6042     static char **fgp[] = { &iflags.wc_foregrnd_menu,
6043                             &iflags.wc_foregrnd_message,
6044                             &iflags.wc_foregrnd_status,
6045                             &iflags.wc_foregrnd_text };
6046     static char **bgp[] = { &iflags.wc_backgrnd_menu,
6047                             &iflags.wc_backgrnd_message,
6048                             &iflags.wc_backgrnd_status,
6049                             &iflags.wc_backgrnd_text };
6050
6051     Strcpy(buf, op);
6052     newop = mungspaces(buf);
6053     while (newop && *newop) {
6054         wn = tfg = tbg = (char *) 0;
6055
6056         /* until first non-space in case there's leading spaces - before
6057          * colorname*/
6058         if (*newop == ' ')
6059             newop++;
6060         if (*newop)
6061             wn = newop;
6062         else
6063             return 0;
6064
6065         /* until first space - colorname*/
6066         while (*newop && *newop != ' ')
6067             newop++;
6068         if (*newop)
6069             *newop = '\0';
6070         else
6071             return 0;
6072         newop++;
6073
6074         /* until first non-space - before foreground*/
6075         if (*newop == ' ')
6076             newop++;
6077         if (*newop)
6078             tfg = newop;
6079         else
6080             return 0;
6081
6082         /* until slash - foreground */
6083         while (*newop && *newop != '/')
6084             newop++;
6085         if (*newop)
6086             *newop = '\0';
6087         else
6088             return 0;
6089         newop++;
6090
6091         /* until first non-space (in case there's leading space after slash) -
6092          * before background */
6093         if (*newop == ' ')
6094             newop++;
6095         if (*newop)
6096             tbg = newop;
6097         else
6098             return 0;
6099
6100         /* until first space - background */
6101         while (*newop && *newop != ' ')
6102             newop++;
6103         if (*newop)
6104             *newop++ = '\0';
6105
6106         for (j = 0; j < 4; ++j) {
6107             if (!strcmpi(wn, wnames[j]) || !strcmpi(wn, shortnames[j])) {
6108                 if (tfg && !strstri(tfg, " ")) {
6109                     if (*fgp[j])
6110                         free((genericptr_t) *fgp[j]);
6111                     *fgp[j] = dupstr(tfg);
6112                 }
6113                 if (tbg && !strstri(tbg, " ")) {
6114                     if (*bgp[j])
6115                         free((genericptr_t) *bgp[j]);
6116                     *bgp[j] = dupstr(tbg);
6117                 }
6118                 break;
6119             }
6120         }
6121     }
6122     return 1;
6123 }
6124
6125 /* set up for wizard mode if player or save file has requested to it;
6126    called from port-specific startup code to handle `nethack -D' or
6127    OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
6128    restoring a game which was saved in wizard mode */
6129 void
6130 set_playmode()
6131 {
6132     if (wizard) {
6133         if (authorize_wizard_mode())
6134             Strcpy(plname, "wizard");
6135         else
6136             wizard = FALSE; /* not allowed or not available */
6137         /* force explore mode if we didn't make it into wizard mode */
6138         discover = !wizard;
6139         iflags.deferred_X = FALSE;
6140     }
6141     /* don't need to do anything special for explore mode or normal play */
6142 }
6143
6144 #endif /* OPTION_LISTS_ONLY */
6145
6146 /*options.c*/