OSDN Git Service

c40b6159b1805ebdd44664d36f175e7bdb5efac0
[jnethack/source.git] / src / options.c
1 /* NetHack 3.6  options.c       $NHDT-Date: 1578996303 2020/01/14 10:05:03 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.396 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2008. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2022            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */
12 #include "config.h"
13 #include "objclass.h"
14 #include "flag.h"
15 NEARDATA struct flag flags; /* provide linkage */
16 #ifdef SYSFLAGS
17 NEARDATA struct sysflag sysflags; /* provide linkage */
18 #endif
19 NEARDATA struct instance_flags iflags; /* provide linkage */
20 #define static
21 #else
22 #include "hack.h"
23 #include "tcap.h"
24 #include <ctype.h>
25 #endif
26
27 #define BACKWARD_COMPAT
28
29 #ifdef DEFAULT_WC_TILED_MAP
30 #define PREFER_TILED TRUE
31 #else
32 #define PREFER_TILED FALSE
33 #endif
34
35 #ifdef CURSES_GRAPHICS
36 extern int curses_read_attrs(const char *attrs);
37 extern char *curses_fmt_attrs(char *);
38 #endif
39
40 enum window_option_types {
41     MESSAGE_OPTION = 1,
42     STATUS_OPTION,
43     MAP_OPTION,
44     MENU_OPTION,
45     TEXT_OPTION
46 };
47
48 #define PILE_LIMIT_DFLT 5
49
50 static char empty_optstr[] = { '\0' };
51
52 /*
53  *  NOTE:  If you add (or delete) an option, please update the short
54  *  options help (option_help()), the long options help (dat/opthelp),
55  *  and the current options setting display function (doset()),
56  *  and also the Guidebooks.
57  *
58  *  The order matters.  If an option is a an initial substring of another
59  *  option (e.g. time and timed_delay) the shorter one must come first.
60  */
61
62 static struct Bool_Opt {
63     const char *name;
64     boolean *addr, initvalue;
65     int optflags;
66 } boolopt[] = {
67     { "acoustics", &flags.acoustics, TRUE, SET_IN_GAME },
68 #if defined(SYSFLAGS) && defined(AMIGA)
69     /* Amiga altmeta causes Alt+key to be converted into Meta+key by
70        low level nethack code; on by default, can be toggled off if
71        Alt+key is needed for some ASCII chars on non-ASCII keyboard */
72     { "altmeta", &sysflags.altmeta, TRUE, DISP_IN_GAME },
73 #else
74 #ifdef ALTMETA
75     /* non-Amiga altmeta causes nethack's top level command loop to treat
76        two character sequence "ESC c" as M-c, for terminals or emulators
77        which send "ESC c" when Alt+c is pressed; off by default, enabling
78        this can potentially make trouble if user types ESC when nethack
79        is honoring this conversion request (primarily after starting a
80        count prefix prior to a command and then deciding to cancel it) */
81     { "altmeta", &iflags.altmeta, FALSE, SET_IN_GAME },
82 #else
83     { "altmeta", (boolean *) 0, TRUE, DISP_IN_GAME },
84 #endif
85 #endif
86     { "ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME }, /*WC*/
87 #if defined(SYSFLAGS) && defined(MFLOPPY)
88     { "asksavedisk", &sysflags.asksavedisk, FALSE, SET_IN_GAME },
89 #else
90     { "asksavedisk", (boolean *) 0, FALSE, SET_IN_FILE },
91 #endif
92     { "autodescribe", &iflags.autodescribe, TRUE, SET_IN_GAME },
93     { "autodig", &flags.autodig, FALSE, SET_IN_GAME },
94     { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME },
95     { "autopickup", &flags.pickup, TRUE, SET_IN_GAME },
96     { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME },
97 #if defined(MICRO) && !defined(AMIGA)
98     { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE },
99 #else
100     { "BIOS", (boolean *) 0, FALSE, SET_IN_FILE },
101 #endif
102     { "blind", &u.uroleplay.blind, FALSE, DISP_IN_GAME },
103     { "bones", &flags.bones, TRUE, SET_IN_FILE },
104 #ifdef INSURANCE
105     { "checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME },
106 #else
107     { "checkpoint", (boolean *) 0, FALSE, SET_IN_FILE },
108 #endif
109 #ifdef MFLOPPY
110     { "checkspace", &iflags.checkspace, TRUE, SET_IN_GAME },
111 #else
112     { "checkspace", (boolean *) 0, FALSE, SET_IN_FILE },
113 #endif
114     { "clicklook", &iflags.clicklook, FALSE, SET_IN_GAME },
115     { "cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME },
116 #if defined(MICRO) || defined(WIN32) || defined(CURSES_GRAPHICS)
117     { "color", &iflags.wc_color, TRUE, SET_IN_GAME }, /* on/off: use WC or not */
118 #else /* systems that support multiple terminals, many monochrome */
119     { "color", &iflags.wc_color, FALSE, SET_IN_GAME },
120 #endif
121     { "confirm", &flags.confirm, TRUE, SET_IN_GAME },
122     { "dark_room", &flags.dark_room, TRUE, SET_IN_GAME },
123     { "eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME }, /*WC*/
124 #if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS) || defined(X11_GRAPHICS)
125     { "extmenu", &iflags.extmenu, FALSE, SET_IN_GAME },
126 #else
127     { "extmenu", (boolean *) 0, FALSE, SET_IN_FILE },
128 #endif
129 #ifdef OPT_DISPMAP
130     { "fast_map", &flags.fast_map, TRUE, SET_IN_GAME },
131 #else
132     { "fast_map", (boolean *) 0, TRUE, SET_IN_FILE },
133 #endif
134     { "female", &flags.female, FALSE, DISP_IN_GAME },
135     { "fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME },
136 #if defined(SYSFLAGS) && defined(AMIFLUSH)
137     { "flush", &sysflags.amiflush, FALSE, SET_IN_GAME },
138 #else
139     { "flush", (boolean *) 0, FALSE, SET_IN_FILE },
140 #endif
141     { "force_invmenu", &iflags.force_invmenu, FALSE, SET_IN_GAME },
142     { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE }, /*WC2*/
143     { "goldX", &iflags.goldX, FALSE, SET_IN_GAME },
144     { "guicolor", &iflags.wc2_guicolor, TRUE, SET_IN_GAME}, /*WC2*/
145     { "help", &flags.help, TRUE, SET_IN_GAME },
146     { "herecmd_menu", &iflags.herecmd_menu, FALSE, SET_IN_GAME },
147     { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/
148     { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME },
149     { "hitpointbar", &iflags.wc2_hitpointbar, FALSE, SET_IN_GAME }, /*WC2*/
150 #ifndef MAC
151     { "ignintr", &flags.ignintr, FALSE, SET_IN_GAME },
152 #else
153     { "ignintr", (boolean *) 0, FALSE, SET_IN_FILE },
154 #endif
155     { "implicit_uncursed", &iflags.implicit_uncursed, TRUE, SET_IN_GAME },
156     { "large_font", &iflags.obsolete, FALSE, SET_IN_FILE }, /* OBSOLETE */
157     { "legacy", &flags.legacy, TRUE, DISP_IN_GAME },
158     { "lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME },
159     { "lootabc", &flags.lootabc, FALSE, SET_IN_GAME },
160 #ifdef MAIL
161     { "mail", &flags.biff, TRUE, SET_IN_GAME },
162 #else
163     { "mail", (boolean *) 0, TRUE, SET_IN_FILE },
164 #endif
165     { "mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME },
166     { "menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME },
167     /* for menu debugging only*/
168     { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_WIZGAME },
169     { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME },
170 #ifdef TTY_GRAPHICS
171     { "menu_overlay", &iflags.menu_overlay, TRUE, SET_IN_GAME },
172 #else
173     { "menu_overlay", (boolean *) 0, FALSE, SET_IN_FILE },
174 #endif
175     { "monpolycontrol", &iflags.mon_polycontrol, FALSE, SET_IN_WIZGAME },
176 #ifdef NEWS
177     { "news", &iflags.news, TRUE, DISP_IN_GAME },
178 #else
179     { "news", (boolean *) 0, FALSE, SET_IN_FILE },
180 #endif
181     { "nudist", &u.uroleplay.nudist, FALSE, DISP_IN_GAME },
182     { "null", &flags.null, TRUE, SET_IN_GAME },
183 #if defined(SYSFLAGS) && defined(MAC)
184     { "page_wait", &sysflags.page_wait, TRUE, SET_IN_GAME },
185 #else
186     { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE },
187 #endif
188     /* moved perm_invent from flags to iflags and out of save file in 3.6.2 */
189     { "perm_invent", &iflags.perm_invent, FALSE, SET_IN_GAME },
190     { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME },
191     { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME },   /*WC*/
192     { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/
193     { "pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME },
194 #if defined(MICRO) && !defined(AMIGA)
195     { "rawio", &iflags.rawio, FALSE, DISP_IN_GAME },
196 #else
197     { "rawio", (boolean *) 0, FALSE, SET_IN_FILE },
198 #endif
199     { "rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME },
200 #ifdef RLECOMP
201     { "rlecomp", &iflags.rlecomp,
202 #if defined(COMPRESS) || defined(ZLIB_COMP)
203       FALSE,
204 #else
205       TRUE,
206 #endif
207       DISP_IN_GAME },
208 #endif
209     { "safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME },
210     { "sanity_check", &iflags.sanity_check, FALSE, SET_IN_WIZGAME },
211     { "selectsaved", &iflags.wc2_selectsaved, TRUE, DISP_IN_GAME }, /*WC*/
212     { "showexp", &flags.showexp, FALSE, SET_IN_GAME },
213     { "showrace", &flags.showrace, FALSE, SET_IN_GAME },
214 #ifdef SCORE_ON_BOTL
215     { "showscore", &flags.showscore, FALSE, SET_IN_GAME },
216 #else
217     { "showscore", (boolean *) 0, FALSE, SET_IN_FILE },
218 #endif
219     { "silent", &flags.silent, TRUE, SET_IN_GAME },
220     { "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE }, /*WC2*/
221     { "sortpack", &flags.sortpack, TRUE, SET_IN_GAME },
222     { "sparkle", &flags.sparkle, TRUE, SET_IN_GAME },
223     { "splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME }, /*WC*/
224     { "standout", &flags.standout, FALSE, SET_IN_GAME },
225     { "status_updates", &iflags.status_updates, TRUE, DISP_IN_GAME },
226     { "tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME }, /*WC*/
227     { "time", &flags.time, FALSE, SET_IN_GAME },
228 #ifdef TIMED_DELAY
229     { "timed_delay", &flags.nap, TRUE, SET_IN_GAME },
230 #else
231     { "timed_delay", (boolean *) 0, FALSE, SET_IN_GAME },
232 #endif
233     { "tombstone", &flags.tombstone, TRUE, SET_IN_GAME },
234     { "toptenwin", &iflags.toptenwin, FALSE, SET_IN_GAME },
235     { "travel", &flags.travelcmd, TRUE, SET_IN_GAME },
236 #ifdef DEBUG
237     { "travel_debug", &iflags.trav_debug, FALSE, SET_IN_WIZGAME }, /*hack.c*/
238 #endif
239     { "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE }, /*WC2*/
240 #ifdef WIN32
241     { "use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME }, /*WC*/
242 #else
243     { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/
244 #endif
245     { "verbose", &flags.verbose, TRUE, SET_IN_GAME },
246 #ifdef TTY_TILES_ESCCODES
247     { "vt_tiledata", &iflags.vt_tiledata, FALSE, SET_IN_FILE },
248 #else
249     { "vt_tiledata", (boolean *) 0, FALSE, SET_IN_FILE },
250 #endif
251     { "whatis_menu", &iflags.getloc_usemenu, FALSE, SET_IN_GAME },
252     { "whatis_moveskip", &iflags.getloc_moveskip, FALSE, SET_IN_GAME },
253     { "wizweight", &iflags.wizweight, FALSE, SET_IN_WIZGAME },
254     { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME }, /*WC2*/
255 #ifdef ZEROCOMP
256     { "zerocomp", &iflags.zerocomp,
257 #if defined(COMPRESS) || defined(ZLIB_COMP)
258       FALSE,
259 #else
260       TRUE,
261 #endif
262       DISP_IN_GAME },
263 #endif
264     { (char *) 0, (boolean *) 0, FALSE, 0 }
265 };
266
267 /* compound options, for option_help() and external programs like Amiga
268  * frontend */
269 static struct Comp_Opt {
270     const char *name, *descr;
271     int size; /* for frontends and such allocating space --
272                * usually allowed size of data in game, but
273                * occasionally maximum reasonable size for
274                * typing when game maintains information in
275                * a different format */
276     int optflags;
277 } compopt[] = {
278 /*JP
279     { "align", "your starting alignment (lawful, neutral, or chaotic)", 8,
280 */
281     { "align",    "\83Q\81[\83\80\83X\83^\81[\83g\8e\9e\82Ì\91®\90« (lawful, neutral, or chaotic\82Ì\82¢\82¸\82ê\82©)", 8,
282       DISP_IN_GAME },
283 #if 0 /*JP:T*/
284     { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
285 #else
286     { "align_message", "\83\81\83b\83Z\81[\83W\83E\83B\83\93\83h\83E\82Ì\91µ\82¦", 20, DISP_IN_GAME }, /*WC*/
287 #endif
288 #if 0 /*JP:T*/
289     { "align_status", "status window alignment", 20, DISP_IN_GAME },   /*WC*/
290 #else
291     { "align_status", "\8fó\8bµ\83E\83B\83\93\83h\83E\82Ì\91µ\82¦", 20, DISP_IN_GAME }, /*WC*/
292 #endif
293 /*JP
294     { "altkeyhandler", "alternate key handler", 20, SET_IN_GAME },
295 */
296     { "altkeyhandler", "ALT\83L\81[\83n\83\93\83h\83\89", 20, SET_IN_GAME },
297 #ifdef BACKWARD_COMPAT
298 /*JP
299     { "boulder", "deprecated (use S_boulder in sym file instead)", 1,
300 */
301     { "boulder",  "\8b\90\8aâ\82ð\95\\8e¦\82·\82é\83V\83\93\83{\83\8b\95\8e\9a", 1,
302       SET_IN_GAME },
303 #endif
304 /*JP
305     { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
306 */
307     { "catname",  "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\94L\82Ì\96¼\91O (\97á catname:\82½\82Ü)",
308       PL_PSIZ, DISP_IN_GAME },
309 /*JP
310     { "disclose", "the kinds of information to disclose at end of game",
311 */
312     { "disclose", "\83Q\81[\83\80\8fI\97¹\8e\9e\82É\8c©\82é\8fî\95ñ\82Ì\8eí\97Þ",
313       sizeof flags.end_disclose * 2, SET_IN_GAME },
314 /*JP
315     { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ,
316 */
317     { "dogname",  "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\8c¢\82Ì\96¼\91O (\97á dogname:\83|\83`)", PL_PSIZ,
318       DISP_IN_GAME },
319 /*JP
320     { "dungeon", "the symbols to use in drawing the dungeon map",
321 */
322     { "dungeon",  "\83_\83\93\83W\83\87\83\93\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a",
323       MAXDCHARS + 1, SET_IN_FILE },
324 /*JP
325     { "effects", "the symbols to use in drawing special effects",
326 */
327     { "effects",  "\93Á\8eê\8cø\89Ê\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a",
328       MAXECHARS + 1, SET_IN_FILE },
329 /*JP
330     { "font_map", "the font to use in the map window", 40,
331 */
332     { "font_map", "\83}\83b\83v\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
333       DISP_IN_GAME },                                              /*WC*/
334 #if 0 /*JP:T*/
335     { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
336 #else
337     { "font_menu", "\83\81\83j\83\85\81[\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40, DISP_IN_GAME }, /*WC*/
338 #endif
339 /*JP
340     { "font_message", "the font to use in the message window", 40,
341 */
342     { "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,
343       DISP_IN_GAME },                                                  /*WC*/
344 #if 0 /*JP:T*/
345     { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
346 #else
347     { "font_size_map", "\83}\83b\83v\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20, DISP_IN_GAME }, /*WC*/
348 #endif
349 /*JP
350     { "font_size_menu", "the size of the menu font", 20,
351 */
352     { "font_size_menu", "\83\81\83j\83\85\81[\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
353       DISP_IN_GAME }, /*WC*/
354 /*JP
355     { "font_size_message", "the size of the message font", 20,
356 */
357     { "font_size_message", "\83\81\83b\83Z\81[\83W\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
358       DISP_IN_GAME }, /*WC*/
359 /*JP
360     { "font_size_status", "the size of the status font", 20,
361 */
362     { "font_size_status", "\8fó\8bµ\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
363       DISP_IN_GAME }, /*WC*/
364 /*JP
365     { "font_size_text", "the size of the text font", 20,
366 */
367     { "font_size_text", "\83e\83L\83X\83g\83t\83H\83\93\83g\82Ì\83T\83C\83Y", 20,
368       DISP_IN_GAME }, /*WC*/
369 /*JP
370     { "font_status", "the font to use in status window", 40,
371 */
372     { "font_status", "\8fó\8bµ\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
373       DISP_IN_GAME }, /*WC*/
374 /*JP
375     { "font_text", "the font to use in text windows", 40,
376 */
377     { "font_text", "\83e\83L\83X\83g\83E\83B\83\93\83h\83E\82É\8eg\97p\82·\82é\83t\83H\83\93\83g", 40,
378       DISP_IN_GAME }, /*WC*/
379 /*JP
380     { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME },
381 */
382     { "fruit", "\8dD\95¨\82Ì\89Ê\95¨\82Ì\96¼\91O", PL_FSIZ, SET_IN_GAME },
383 /*JP
384     { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME },
385 */
386     { "gender", "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\90«\95Ê(male \82Ü\82½\82Í female)", 8, DISP_IN_GAME },
387 /*JP
388     { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
389 */
390     { "horsename", "\96`\8c¯\82ð\8b\9f\82É\82·\82é(\8dÅ\8f\89\82Ì)\94n\82Ì\96¼\91O (\97á ghoulname:\83V\83\8b\83o\81[)",
391       PL_PSIZ, DISP_IN_GAME },
392 #if 0 /*JP:T*/
393     { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
394 #else
395     { "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*/
396 #endif
397 /*JP
398     { "menustyle", "user interface for object selection", MENUTYPELEN,
399 */
400     { "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,
401       SET_IN_GAME },
402 /*JP
403     { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
404 */
405     { "menu_deselect_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\94ñ\91I\91ð", 4, SET_IN_FILE },
406 /*JP
407     { "menu_deselect_page", "deselect all items on this page of a menu", 4,
408 */
409     { "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,
410       SET_IN_FILE },
411 /*JP
412     { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE },
413 */
414     { "menu_first_page", "\83\81\83j\83\85\81[\82Ì\8dÅ\8f\89\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
415 /*JP
416     { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME },
417 */
418     { "menu_headings", "\8b­\92²\81C\94½\93]\82Ü\82½\82Í\89º\90ü\82Å\8eí\97Þ\82ð\95\\8e¦\82·\82é", 9, SET_IN_GAME },
419 /*JP
420     { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
421 */
422     { "menu_invert_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\94½\93]", 4, SET_IN_FILE },
423 /*JP
424     { "menu_invert_page", "invert all items on this page of a menu", 4,
425 */
426     { "menu_invert_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\83y\81[\83W\82Ì\83A\83C\83e\83\80\82ð\94½\93]",
427       SET_IN_FILE },
428 /*JP
429     { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
430 */
431     { "menu_last_page", "\83\81\83j\83\85\81[\82Ì\8dÅ\8cã\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
432 /*JP
433     { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
434 */
435     { "menu_next_page", "\8e\9f\82Ì\83\81\83j\83\85\81[\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
436 /*JP
437     { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
438 */
439     { "menu_previous_page", "\91O\82Ì\83\81\83j\83\85\81[\82Ì\83y\81[\83W\82Ö", 4, SET_IN_FILE },
440 /*JP
441     { "menu_search", "search for a menu item", 4, SET_IN_FILE },
442 */
443     { "menu_search", "\83\81\83j\83\85\81[\82Ì\8c\9f\8dõ", 4, SET_IN_FILE },
444 /*JP
445     { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
446 */
447     { "menu_select_all", "\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\91I\91ð", 4, SET_IN_FILE },
448 /*JP
449     { "menu_select_page", "select all items on this page of a menu", 4,
450 */
451     { "menu_select_page", "\8c»\8dÝ\95\\8e¦\82³\82ê\82Ä\82¢\82é\91S\82Ä\82Ì\83A\83C\83e\83\80\82ð\91I\91ð", 4,
452       SET_IN_FILE },
453 /*JP
454     { "monsters", "the symbols to use for monsters", MAXMCLASSES,
455 */
456     { "monsters", "\83\82\83\93\83X\83^\81[\82É\8eg\97p\82³\82ê\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXMCLASSES,
457       SET_IN_FILE },
458 /*JP
459     { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME },
460 */
461     { "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 },
462 #if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
463 /*JP
464     { "msg_window", "the type of message window required", 1, SET_IN_GAME },
465 */
466     { "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 },
467 #else
468 /*JP
469     { "msg_window", "the type of message window required", 1, SET_IN_FILE },
470 */
471     { "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 },
472 #endif
473 /*JP
474     { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ,
475 */
476     { "name", "\82 \82È\82½\82Ì\96¼\91O (\97á name:\83}\81[\83\8a\83\93-W)", PL_NSIZ,
477       DISP_IN_GAME },
478 /*JP
479     { "mouse_support", "game receives click info from mouse", 0, SET_IN_GAME },
480 */
481     { "mouse_support", "\83Q\81[\83\80\82ª\83}\83E\83X\82©\82ç\82Ì\83N\83\8a\83b\83N\8fî\95ñ\82ð\8eó\82¯\8eæ\82é", 0, SET_IN_GAME },
482 /*JP
483     { "number_pad", "use the number pad for movement", 1, SET_IN_GAME },
484 */
485     { "number_pad", "\83i\83\93\83o\81[\83p\83b\83h\82ð\8eg\97p\82·\82é", 1, SET_IN_GAME },
486 /*JP
487     { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE },
488 */
489     { "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 },
490 /*JP
491     { "packorder", "the inventory order of the items in your pack",
492 */
493     { "packorder", "\94w\95\89\82¢\91Ü\93à\82Ì\95¨\82Ì\8f\87\94Ô",
494       MAXOCLASSES, SET_IN_GAME },
495 #ifdef CHANGE_COLOR
496     { "palette",
497 #ifndef WIN32
498 /*JP
499       "palette (00c/880/-fff is blue/yellow/reverse white)", 15, SET_IN_GAME
500 */
501       "\83p\83\8c\83b\83g (00c/880/-fff\82Í\82»\82ê\82¼\82ê\90Â/\89©/\94½\93]\94\92\82ð\8e¦\82·)", 15, SET_IN_GAME
502 #else
503 /*JP
504       "palette (adjust an RGB color in palette (color-R-G-B)", 15, SET_IN_FILE
505 */
506       "\83p\83\8c\83b\83g (\83p\83\8c\83b\83g\82ÌRGB\90F\82ð\92²\90®\82·\82é (\90F-R-G-B)", 15, SET_IN_FILE
507 #endif
508     },
509 #if defined(MAC)
510 /*JP
511     { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE },
512 */
513     { "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 },
514 #endif
515 #endif
516 #if 0 /*JP:T*/
517     { "paranoid_confirmation", "extra prompting in certain situations", 28,
518       SET_IN_GAME },
519 #else
520     { "paranoid_confirmation", "\88ê\95\94\82Ì\8fó\8bµ\82Å\92Ç\89Á\82Ì\8am\94F\82ð\82·\82é", 28,
521       SET_IN_GAME },
522 #endif
523 /*JP
524     { "petattr",  "attributes for highlighting pets", 88, SET_IN_GAME },
525 */
526     { "petattr",  "\83y\83b\83g\82ð\83n\83C\83\89\83C\83g\82·\82é\82½\82ß\82Ì\91®\90«", 88, SET_IN_GAME },
527 /*JP
528     { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
529 */
530     { "pettype",  "\82 \82È\82½\82Ì\91I\91ð\82µ\82½\8f\89\8aú\83y\83b\83g\82Ì\8eí\97Þ", 4, DISP_IN_GAME },
531 /*JP
532     { "pickup_burden", "maximum burden picked up before prompt", 20,
533 */
534     { "pickup_burden",  "\8fE\82¤\82Æ\82«\82É\8dÅ\91å\89×\8fd\82É\82È\82é\8eè\91O\82Å\8am\94F\82·\82é", 20,
535       SET_IN_GAME },
536 /*JP
537     { "pickup_types", "types of objects to pick up automatically",
538 */
539     { "pickup_types", "\8e©\93®\82Å\8fE\82¢\82 \82°\82é\95¨\82Ì\83V\83\93\83{\83\8b",
540       MAXOCLASSES, SET_IN_GAME },
541 #if 0 /*JP:T*/
542     { "pile_limit", "threshold for \"there are many objects here\"", 24,
543       SET_IN_GAME },
544 #else
545     { "pile_limit", "\81u\82±\82±\82É\82Í\82½\82­\82³\82ñ\82Ì\82à\82Ì\82ª\82 \82é\81v\82Ì\82µ\82«\82¢\92l", 24,
546       SET_IN_GAME },
547 #endif
548 #if 0 /*JP:T*/
549     { "playmode", "normal play, non-scoring explore mode, or debug mode", 8,
550       DISP_IN_GAME },
551 #else
552     { "playmode", "\92Ê\8fí\83\82\81[\83h\81C\92T\8c\9f\83\82\81[\83h\81C\83f\83o\83b\83O\83\82\81[\83h\82Ì\82¢\82¸\82ê\82©", 8,
553       DISP_IN_GAME },
554 #endif
555 /*JP
556     { "player_selection", "choose character via dialog or prompts", 12,
557 */
558     { "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,
559       DISP_IN_GAME },
560 /*JP
561     { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ,
562 */
563     { "race",     "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\8eí\91° (\97á Human, Elf)", PL_CSIZ,
564       DISP_IN_GAME },
565 /*JP
566     { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ,
567 */
568     { "role",     "\83Q\81[\83\80\8aJ\8en\8e\9e\82Ì\90E\8bÆ (\97á Barbarian, Valkyrie)", PL_CSIZ,
569       DISP_IN_GAME },
570 /*JP
571     { "runmode", "display frequency when `running' or `travelling'",
572 */
573     { "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",
574       sizeof "teleport", SET_IN_GAME },
575 /*JP
576     { "scores", "the parts of the score list you wish to see", 32,
577 */
578     { "scores",   "\83Q\81[\83\80\8fI\97¹\8e\9e\82É\8c©\82é\83X\83R\83A\82Ì\8eí\97Þ", 32,
579       SET_IN_GAME },
580 /*JP
581     { "scroll_amount", "amount to scroll map when scroll_margin is reached",
582 */
583     { "scroll_amount", "scroll_margin\82É\93Í\82¢\82½\82Æ\82«\82Ì\83}\83b\83v\83X\83N\83\8d\81[\83\8b\97Ê",
584       20, DISP_IN_GAME }, /*WC*/
585 /*JP
586     { "scroll_margin", "scroll map when this far from the edge", 20,
587 */
588     { "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,
589       DISP_IN_GAME }, /*WC*/
590 /*JP
591     { "sortloot", "sort object selection lists by description", 4,
592 */
593     { "sortloot", "\95¨\91Ì\91I\91ð\83\8a\83X\83g\82ð\90à\96¾\82Å\83\\81[\83g\82·\82é", 4,
594       SET_IN_GAME },
595 #ifdef MSDOS
596 /*JP
597     { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
598 */
599     { "soundcard", "\8eg\97p\82µ\82Ä\82¢\82é\83T\83E\83\93\83h\83J\81[\83h\82Ì\8eí\97Þ", 20, SET_IN_FILE },
600 #endif
601     { "statushilites",
602 #ifdef STATUS_HILITES
603 #if 0 /*JP:T*/
604       "0=no status highlighting, N=show highlights for N turns",
605 #else
606       "0=\83X\83e\81[\83^\83X\83n\83C\83\89\83C\83g\82È\82µ\81CN\83^\81[\83\93\96\88\82É\83n\83C\83\89\83C\83g\95\\8e¦",
607 #endif
608       20, SET_IN_GAME
609 #else
610 /*JP
611     "highlight control", 20, SET_IN_FILE
612 */
613     "\83n\83C\83\89\83C\83g\82Ì\90§\8cä", 20, SET_IN_FILE
614 #endif
615     },
616     { "statuslines",
617 #ifdef CURSES_GRAPHICS
618 /*JP
619       "2 or 3 lines for horizontal (bottom or top) status display",
620 */
621       "\90\82\92¼(\89º\82©\8fã)\82Ì\83X\83e\81[\83^\83X\95\\8e¦\82É2,3\8ds\8eg\82¤",
622       20, SET_IN_GAME
623 #else
624 /*JP
625       "2 or 3 lines for status display",
626 */
627       "\83X\83e\81[\83^\83X\95\\8e¦\82É2,3\8ds\8eg\82¤",
628       20, SET_IN_FILE
629 #endif
630     }, /*WC2*/
631 #if 0 /*JP:T*/
632     { "symset", "load a set of display symbols from the symbols file", 70,
633       SET_IN_GAME },
634 #else
635     { "symset", "symbols\83t\83@\83C\83\8b\82©\82ç\95\\8e¦\83V\83\93\83{\83\8b\82Ì\90Ý\92è\82ð\93Ç\82Ý\8d\9e\82Þ", 70,
636       SET_IN_GAME },
637 #endif
638 #if 0 /*JP:T*/
639     { "roguesymset",
640       "load a set of rogue display symbols from the symbols file", 70,
641       SET_IN_GAME },
642 #else
643     { "roguesymset",
644       "symbols\83t\83@\83C\83\8b\82©\82ç\83\8d\81[\83O\83\8c\83x\83\8b\82Ì\95\\8e¦\83V\83\93\83{\83\8b\82Ì\90Ý\92è\82ð\93Ç\82Ý\8d\9e\82Þ", 70,
645       SET_IN_GAME },
646 #endif
647 #ifdef WIN32
648 /*JP
649     { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE },
650 */
651     { "subkeyvalue", "\83L\81[\83}\83b\83s\83\93\83O\82ð\95Ï\8dX\82·\82é", 7, SET_IN_FILE },
652 #endif
653 /*JP
654     { "suppress_alert", "suppress alerts about version-specific features", 8,
655 */
656     { "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,
657       SET_IN_GAME },
658     /* term_cols,term_rows -> WC2_TERM_SIZE (6: room to format 1..32767) */
659 #if 0 /*JP*/
660     { "term_cols", "number of columns", 6, SET_IN_FILE }, /*WC2*/
661 #else
662     { "term_cols", "\8c\85\90\94", 6, SET_IN_FILE }, /*WC2*/
663 #endif
664 #if 0 /*JP*/
665     { "term_rows", "number of rows", 6, SET_IN_FILE }, /*WC2*/
666 #else
667     { "term_rows", "\8ds\90\94", 6, SET_IN_FILE }, /*WC2*/
668 #endif
669 #if 0 /*JP:T*/
670     { "tile_width", "width of tiles", 20, DISP_IN_GAME },   /*WC*/
671 #else
672     { "tile_width", "\83^\83C\83\8b\82Ì\95\9d", 20, DISP_IN_GAME },   /*WC*/
673 #endif
674 #if 0 /*JP:T*/
675     { "tile_height", "height of tiles", 20, DISP_IN_GAME }, /*WC*/
676 #else
677     { "tile_height", "\83^\83C\83\8b\82Ì\8d\82\82³", 20, DISP_IN_GAME }, /*WC*/
678 #endif
679 #if 0 /*JP:T*/
680     { "tile_file", "name of tile file", 70, DISP_IN_GAME }, /*WC*/
681 #else
682     { "tile_file", "\83^\83C\83\8b\83t\83@\83C\83\8b\82Ì\96¼\91O", 70, DISP_IN_GAME }, /*WC*/
683 #endif
684 /*JP
685     { "traps", "the symbols to use in drawing traps", MAXTCHARS + 1,
686 */
687     { "traps", "ã©\82ð\95`\89æ\82·\82é\83V\83\93\83{\83\8b\95\8e\9a", MAXTCHARS + 1,
688       SET_IN_FILE },
689 /*JP
690     { "vary_msgcount", "show more old messages at a time", 20,
691 */
692     { "vary_msgcount", "\88ê\93x\82É\95\\8e¦\82·\82é\83\81\83b\83Z\81[\83W\82Ì\90\94", 20,
693       DISP_IN_GAME }, /*WC*/
694 #ifdef MSDOS
695 /*JP
696     { "video", "method of video updating", 20, SET_IN_FILE },
697 */
698     { "video", "\8eg\97p\82·\82é\83r\83f\83I\83\82\81[\83h\82ð\90Ý\92è\82·\82é", 20, SET_IN_FILE },
699 #endif
700 #ifdef VIDEOSHADES
701 /*JP
702     { "videocolors", "color mappings for internal screen routines", 40,
703 */
704     { "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,
705       DISP_IN_GAME },
706 /*JP
707     { "videoshades", "gray shades to map to black/gray/white", 32,
708 */
709     { "videoshades", "\95\\8e¦\82É\83O\83\8c\83C\83X\83P\81[\83\8b\82ð\97p\82¢\82é", 32,
710       DISP_IN_GAME },
711 #endif
712 #if 0 /*JP:T*/
713     { "whatis_coord", "show coordinates when auto-describing cursor position",
714       1, SET_IN_GAME },
715 #else
716     { "whatis_coord", "\83J\81[\83\\83\8b\88Ê\92u\82ð\8e©\93®\90à\96¾\82·\82é\82Æ\82«\82É\8dÀ\95W\82ð\95\\8e¦\82·\82é",
717       1, SET_IN_GAME },
718 #endif
719 #if 0 /*JP:T*/
720     { "whatis_filter",
721       "filter coordinate locations when targeting next or previous",
722       1, SET_IN_GAME },
723 #else
724     { "whatis_filter",
725       "\8e\9f\82â\8eè\91O\82ð\83^\81[\83Q\83b\83g\82·\82é\82Æ\82«\82É\8dÀ\95W\88Ê\92u\82ð\83t\83B\83\8b\83^\82·\82é",
726       1, SET_IN_GAME },
727 #endif
728     { "windowborders", "0 (off), 1 (on), 2 (auto)", 9, SET_IN_GAME }, /*WC2*/
729 #if 0 /*JP:T*/
730     { "windowcolors", "the foreground/background colors of windows", /*WC*/
731       80, DISP_IN_GAME },
732 #else
733     { "windowcolors", "\83E\83B\83\93\83h\83E\82ð\8ew\92è\82µ\82½\91O\8ci\90F/\94w\8ci\90F\82Å\95\\8e¦\82·\82é", /*WC*/
734       80, DISP_IN_GAME },
735 #endif
736 /*JP
737     { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
738 */
739     { "windowtype", "\8eg\97p\82·\82é\83E\83C\83\93\83h\83E\83V\83X\83e\83\80", WINTYPELEN, DISP_IN_GAME },
740 #ifdef WINCHAIN
741 /*JP
742     { "windowchain", "window processor to use", WINTYPELEN, SET_IN_SYS },
743 */
744     { "windowchain", "\8eg\97p\82·\82é\83E\83B\83\93\83h\83E\83v\83\8d\83Z\83b\83T", WINTYPELEN, SET_IN_SYS },
745 #endif
746 #ifdef BACKWARD_COMPAT
747 /*JP
748     { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE },
749 */
750     { "DECgraphics", "DECGraphics\95\\8e¦\83V\83\93\83{\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ", 70, SET_IN_FILE },
751 /*JP
752     { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE },
753 */
754     { "IBMgraphics", "IBMGraphics\95\\8e¦\83V\83\93\83{\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ", 70, SET_IN_FILE },
755 #ifdef CURSES_GRAPHICS
756 /*JP
757     { "cursesgraphics", "load curses display symbols", 70, SET_IN_FILE },
758 */
759     { "cursesgraphics", "curses\95\\8e¦\83V\83\93\83{\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ", 70, SET_IN_FILE },
760 #endif
761 #ifdef MAC_GRAPHICS_ENV
762 /*JP
763     { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE },
764 */
765     { "Macgraphics", "MACGraphics\95\\8e¦\83V\83\93\83{\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ", 70, SET_IN_FILE },
766 #endif
767 #endif
768 #if 1 /*JP*/
769     { "kcode", "\92[\96\96\82Ì\8a¿\8e\9a\83R\81[\83h,", 4, SET_IN_FILE },
770 #endif
771     { (char *) 0, (char *) 0, 0, 0 }
772 };
773
774 #ifdef OPTION_LISTS_ONLY
775 #undef static
776
777 #else /* use rest of file */
778
779 extern char configfile[]; /* for messages */
780
781 extern struct symparse loadsyms[];
782 static boolean need_redraw; /* for doset() */
783
784 #if defined(TOS) && defined(TEXTCOLOR)
785 extern boolean colors_changed;  /* in tos.c */
786 #endif
787
788 #ifdef VIDEOSHADES
789 extern char *shade[3];          /* in sys/msdos/video.c */
790 extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
791 #endif
792
793 static char def_inv_order[MAXOCLASSES] = {
794     COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
795     SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
796     TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
797 };
798
799 /*
800  * Default menu manipulation command accelerators.  These may _not_ be:
801  *
802  *      + a number - reserved for counts
803  *      + an upper or lower case US ASCII letter - used for accelerators
804  *      + ESC - reserved for escaping the menu
805  *      + NULL, CR or LF - reserved for commiting the selection(s).  NULL
806  *        is kind of odd, but the tty's xwaitforspace() will return it if
807  *        someone hits a <ret>.
808  *      + a default object class symbol - used for object class accelerators
809  *
810  * Standard letters (for now) are:
811  *
812  *              <  back 1 page
813  *              >  forward 1 page
814  *              ^  first page
815  *              |  last page
816  *              :  search
817  *
818  *              page            all
819  *               ,    select     .
820  *               \    deselect   -
821  *               ~    invert     @
822  *
823  * The command name list is duplicated in the compopt array.
824  */
825 typedef struct {
826     const char *name;
827     char cmd;
828     const char *desc;
829 } menu_cmd_t;
830
831 static const menu_cmd_t default_menu_cmd_info[] = {
832 /*JP
833  { "menu_first_page", MENU_FIRST_PAGE, "Go to first page" },
834 */
835  { "menu_first_page", MENU_FIRST_PAGE, "\90æ\93ª\83y\81[\83W\82É\88Ú\93®" },
836 /*JP
837  { "menu_last_page", MENU_LAST_PAGE, "Go to last page" },
838 */
839  { "menu_last_page", MENU_LAST_PAGE, "\8dÅ\8fI\83y\81[\83W\82É\88Ú\93®" },
840 /*JP
841  { "menu_next_page", MENU_NEXT_PAGE, "Go to next page" },
842 */
843  { "menu_next_page", MENU_NEXT_PAGE, "\8e\9f\82Ì\83y\81[\83W\82É\88Ú\93®" },
844 /*JP
845  { "menu_previous_page", MENU_PREVIOUS_PAGE, "Go to previous page" },
846 */
847  { "menu_previous_page", MENU_PREVIOUS_PAGE, "\91O\82Ì\83y\81[\83W\82É\88Ú\93®" },
848 /*JP
849  { "menu_select_all", MENU_SELECT_ALL, "Select all items" },
850 */
851  { "menu_select_all", MENU_SELECT_ALL, "\91S\82Ä\82Ì\8d\80\96Ú\82ð\91I\91ð" },
852 /*JP
853  { "menu_deselect_all", MENU_UNSELECT_ALL, "Unselect all items" },
854 */
855  { "menu_deselect_all", MENU_UNSELECT_ALL, "\91S\82Ä\82Ì\8d\80\96Ú\82ð\91I\91ð\89ð\8f\9c" },
856 /*JP
857  { "menu_invert_all", MENU_INVERT_ALL, "Invert selection" },
858 */
859  { "menu_invert_all", MENU_INVERT_ALL, "\91I\91ð\82ð\94½\93]" },
860 /*JP
861  { "menu_select_page", MENU_SELECT_PAGE, "Select items in current page" },
862 */
863  { "menu_select_page", MENU_SELECT_PAGE, "\8c»\8dÝ\82Ì\83y\81[\83W\82Ì\8d\80\96Ú\82ð\91I\91ð" },
864  { "menu_deselect_page", MENU_UNSELECT_PAGE,
865 /*JP
866    "Unselect items in current page" },
867 */
868    "\8c»\8dÝ\82Ì\83y\81[\83W\82Ì\8d\80\96Ú\82ð\91I\91ð\89ð\8f\9c" },
869 /*JP
870  { "menu_invert_page", MENU_INVERT_PAGE, "Invert current page selection" },
871 */
872  { "menu_invert_page", MENU_INVERT_PAGE, "\8c»\8dÝ\82Ì\83y\81[\83W\82Ì\91I\91ð\82ð\94½\93]" },
873 /*JP
874  { "menu_search", MENU_SEARCH, "Search and toggle matching items" },
875 */
876  { "menu_search", MENU_SEARCH, "\8c\9f\8dõ\82µ\82Ä\83}\83b\83`\83\93\83O\82µ\82½\8d\80\96Ú\82ð\83g\83O\83\8b" },
877 };
878
879 /*
880  * Allow the user to map incoming characters to various menu commands.
881  * The accelerator list must be a valid C string.
882  */
883 #define MAX_MENU_MAPPED_CMDS 32 /* some number */
884 char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */
885 static char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1];
886 static short n_menu_mapped = 0;
887
888 static boolean initial, from_file;
889
890 STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
891 STATIC_DCL void FDECL(escapes, (const char *, char *));
892 STATIC_DCL void FDECL(rejectoption, (const char *));
893 STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P));
894 STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
895 STATIC_DCL void FDECL(bad_negation, (const char *, BOOLEAN_P));
896 STATIC_DCL int FDECL(change_inv_order, (char *));
897 STATIC_DCL boolean FDECL(warning_opts, (char *, const char *));
898 STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
899 STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int));
900 STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int));
901
902 STATIC_DCL const char *FDECL(attr2attrname, (int));
903 STATIC_DCL const char * FDECL(msgtype2name, (int));
904 STATIC_DCL int NDECL(query_msgtype);
905 STATIC_DCL boolean FDECL(msgtype_add, (int, char *));
906 STATIC_DCL void FDECL(free_one_msgtype, (int));
907 STATIC_DCL int NDECL(msgtype_count);
908 STATIC_DCL boolean FDECL(test_regex_pattern, (const char *, const char *));
909 STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
910 STATIC_DCL void FDECL(free_one_menu_coloring, (int));
911 STATIC_DCL int NDECL(count_menucolors);
912 STATIC_DCL boolean FDECL(parse_role_opts, (BOOLEAN_P, const char *,
913                                            char *, char **));
914
915 STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int));
916 STATIC_DCL void FDECL(opts_add_others, (winid, const char *, int,
917                                         char *, int));
918 STATIC_DCL int FDECL(handle_add_list_remove, (const char *, int));
919 STATIC_DCL boolean FDECL(special_handling, (const char *,
920                                             BOOLEAN_P, BOOLEAN_P));
921 STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
922 STATIC_DCL void FDECL(remove_autopickup_exception,
923                       (struct autopickup_exception *));
924
925 STATIC_DCL boolean FDECL(is_wc_option, (const char *));
926 STATIC_DCL boolean FDECL(wc_supported, (const char *));
927 STATIC_DCL boolean FDECL(is_wc2_option, (const char *));
928 STATIC_DCL boolean FDECL(wc2_supported, (const char *));
929 STATIC_DCL void FDECL(wc_set_font_name, (int, char *));
930 STATIC_DCL int FDECL(wc_set_window_colors, (char *));
931
932 void
933 reglyph_darkroom()
934 {
935     xchar x, y;
936
937     for (x = 0; x < COLNO; x++)
938         for (y = 0; y < ROWNO; y++) {
939             struct rm *lev = &levl[x][y];
940
941             if (!flags.dark_room || !iflags.use_color
942                 || Is_rogue_level(&u.uz)) {
943                 if (lev->glyph == cmap_to_glyph(S_darkroom))
944                     lev->glyph = lev->waslit ? cmap_to_glyph(S_room)
945                                              : cmap_to_glyph(S_stone);
946             } else {
947                 if (lev->glyph == cmap_to_glyph(S_room) && lev->seenv
948                     && lev->waslit && !cansee(x, y))
949                     lev->glyph = cmap_to_glyph(S_darkroom);
950                 else if (lev->glyph == cmap_to_glyph(S_stone)
951                          && lev->typ == ROOM && lev->seenv && !cansee(x, y))
952                     lev->glyph = cmap_to_glyph(S_darkroom);
953             }
954         }
955     if (flags.dark_room && iflags.use_color)
956         showsyms[S_darkroom] = showsyms[S_room];
957     else
958         showsyms[S_darkroom] = showsyms[S_stone];
959 }
960
961 /* check whether a user-supplied option string is a proper leading
962    substring of a particular option name; option string might have
963    a colon or equals sign and arbitrary value appended to it */
964 boolean
965 match_optname(user_string, opt_name, min_length, val_allowed)
966 const char *user_string, *opt_name;
967 int min_length;
968 boolean val_allowed;
969 {
970     int len = (int) strlen(user_string);
971
972     if (val_allowed) {
973         const char *p = index(user_string, ':'),
974                    *q = index(user_string, '=');
975
976         if (!p || (q && q < p))
977             p = q;
978         if (p) {
979             /* 'user_string' hasn't necessarily been through mungspaces()
980                so might have tabs or consecutive spaces */
981             while (p > user_string && isspace((uchar) *(p - 1)))
982                 p--;
983             len = (int) (p - user_string);
984         }
985     }
986
987     return (boolean) (len >= min_length
988                       && !strncmpi(opt_name, user_string, len));
989 }
990
991 /* most environment variables will eventually be printed in an error
992  * message if they don't work, and most error message paths go through
993  * BUFSZ buffers, which could be overflowed by a maliciously long
994  * environment variable.  If a variable can legitimately be long, or
995  * if it's put in a smaller buffer, the responsible code will have to
996  * bounds-check itself.
997  */
998 char *
999 nh_getenv(ev)
1000 const char *ev;
1001 {
1002     char *getev = getenv(ev);
1003
1004     if (getev && strlen(getev) <= (BUFSZ / 2))
1005         return getev;
1006     else
1007         return (char *) 0;
1008 }
1009
1010 /* process options, possibly including SYSCF */
1011 void
1012 initoptions()
1013 {
1014     initoptions_init();
1015 #ifdef SYSCF
1016 /* someday there may be other SYSCF alternatives besides text file */
1017 #ifdef SYSCF_FILE
1018     /* If SYSCF_FILE is specified, it _must_ exist... */
1019     assure_syscf_file();
1020     config_error_init(TRUE, SYSCF_FILE, FALSE);
1021
1022     /* ... and _must_ parse correctly. */
1023     if (!read_config_file(SYSCF_FILE, SET_IN_SYS)) {
1024         if (config_error_done() && !iflags.initoptions_noterminate)
1025             nh_terminate(EXIT_FAILURE);
1026     }
1027     config_error_done();
1028     /*
1029      * TODO [maybe]: parse the sysopt entries which are space-separated
1030      * lists of usernames into arrays with one name per element.
1031      */
1032 #endif
1033 #endif /* SYSCF */
1034     initoptions_finish();
1035 }
1036
1037 void
1038 initoptions_init()
1039 {
1040 #if (defined(UNIX) || defined(VMS)) && defined(TTY_GRAPHICS)
1041     char *opts;
1042 #endif
1043     int i;
1044
1045     /* set up the command parsing */
1046     reset_commands(TRUE); /* init */
1047
1048     /* initialize the random number generator(s) */
1049     init_random(rn2);
1050     init_random(rn2_on_display_rng);
1051
1052     /* for detection of configfile options specified multiple times */
1053     iflags.opt_booldup = iflags.opt_compdup = (int *) 0;
1054
1055     for (i = 0; boolopt[i].name; i++) {
1056         if (boolopt[i].addr)
1057             *(boolopt[i].addr) = boolopt[i].initvalue;
1058     }
1059 #if defined(COMPRESS) || defined(ZLIB_COMP)
1060     set_savepref("externalcomp");
1061     set_restpref("externalcomp");
1062 #ifdef RLECOMP
1063     set_savepref("!rlecomp");
1064     set_restpref("!rlecomp");
1065 #endif
1066 #else
1067 #ifdef ZEROCOMP
1068     set_savepref("zerocomp");
1069     set_restpref("zerocomp");
1070 #endif
1071 #ifdef RLECOMP
1072     set_savepref("rlecomp");
1073     set_restpref("rlecomp");
1074 #endif
1075 #endif
1076 #ifdef SYSFLAGS
1077     Strcpy(sysflags.sysflagsid, "sysflags");
1078     sysflags.sysflagsid[9] = (char) sizeof (struct sysflag);
1079 #endif
1080     flags.end_own = FALSE;
1081     flags.end_top = 3;
1082     flags.end_around = 2;
1083     flags.paranoia_bits = PARANOID_PRAY; /* old prayconfirm=TRUE */
1084     flags.pile_limit = PILE_LIMIT_DFLT;  /* 5 */
1085     flags.runmode = RUN_LEAP;
1086     iflags.msg_history = 20;
1087     /* msg_window has conflicting defaults for multi-interface binary */
1088 #ifdef TTY_GRAPHICS
1089     iflags.prevmsg_window = 's';
1090 #else
1091 #ifdef CURSES_GRAPHICS
1092     iflags.prevmsg_window = 'r';
1093 #endif
1094 #endif
1095     iflags.menu_headings = ATR_INVERSE;
1096     iflags.getpos_coords = GPCOORDS_NONE;
1097
1098     /* hero's role, race, &c haven't been chosen yet */
1099     flags.initrole = flags.initrace = flags.initgend = flags.initalign
1100         = ROLE_NONE;
1101
1102     init_ov_primary_symbols();
1103     init_ov_rogue_symbols();
1104     /* Set the default monster and object class symbols. */
1105     init_symbols();
1106     for (i = 0; i < WARNCOUNT; i++)
1107         warnsyms[i] = def_warnsyms[i].sym;
1108
1109     /* for "special achievement" tracking (see obj.h,
1110        create_object(sp_lev.c), addinv_core1(invent.c) */
1111     iflags.mines_prize_type = LUCKSTONE;
1112     iflags.soko_prize_type1 = BAG_OF_HOLDING;
1113     iflags.soko_prize_type2 = AMULET_OF_REFLECTION;
1114
1115     /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
1116     (void) memcpy((genericptr_t) flags.inv_order,
1117                   (genericptr_t) def_inv_order, sizeof flags.inv_order);
1118     flags.pickup_types[0] = '\0';
1119     flags.pickup_burden = MOD_ENCUMBER;
1120     flags.sortloot = 'l'; /* sort only loot by default */
1121
1122     for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
1123         flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
1124     switch_symbols(FALSE); /* set default characters */
1125     init_rogue_symbols();
1126 #if 0 /*JP*//*\83V\83\93\83{\83\8b\82Ì\8e©\93®\90Ý\92è\82Í\8aQ\82ª\91å\82«\82¢\82Ì\82Å\83R\83\81\83\93\83g\83A\83E\83g*/
1127 #if defined(UNIX) && defined(TTY_GRAPHICS)
1128     /*
1129      * Set defaults for some options depending on what we can
1130      * detect about the environment's capabilities.
1131      * This has to be done after the global initialization above
1132      * and before reading user-specific initialization via
1133      * config file/environment variable below.
1134      */
1135     /* this detects the IBM-compatible console on most 386 boxes */
1136     if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
1137         if (!symset[PRIMARY].explicitly)
1138             load_symset("IBMGraphics", PRIMARY);
1139         if (!symset[ROGUESET].explicitly)
1140             load_symset("RogueIBM", ROGUESET);
1141         switch_symbols(TRUE);
1142 #ifdef TEXTCOLOR
1143         iflags.use_color = TRUE;
1144 #endif
1145     }
1146 #endif /* UNIX && TTY_GRAPHICS */
1147 #if defined(UNIX) || defined(VMS)
1148 #ifdef TTY_GRAPHICS
1149     /* detect whether a "vt" terminal can handle alternate charsets */
1150     if ((opts = nh_getenv("TERM"))
1151         /* [could also check "xterm" which emulates vtXXX by default] */
1152         && !strncmpi(opts, "vt", 2)
1153         && AS && AE && index(AS, '\016') && index(AE, '\017')) {
1154         if (!symset[PRIMARY].explicitly)
1155             load_symset("DECGraphics", PRIMARY);
1156         switch_symbols(TRUE);
1157     }
1158 #endif
1159 #endif /* UNIX || VMS */
1160
1161 #if defined(MSDOS) || defined(WIN32)
1162     /* Use IBM defaults. Can be overridden via config file */
1163     if (!symset[PRIMARY].explicitly)
1164         load_symset("IBMGraphics_2", PRIMARY);
1165     if (!symset[ROGUESET].explicitly)
1166         load_symset("RogueEpyx", ROGUESET);
1167 #endif
1168 #ifdef MAC_GRAPHICS_ENV
1169     if (!symset[PRIMARY].explicitly)
1170         load_symset("MACGraphics", PRIMARY);
1171     switch_symbols(TRUE);
1172 #endif /* MAC_GRAPHICS_ENV */
1173 #endif
1174     flags.menu_style = MENU_FULL;
1175
1176     iflags.wc_align_message = ALIGN_TOP;
1177     iflags.wc_align_status = ALIGN_BOTTOM;
1178     /* used by tty and curses */
1179     iflags.wc2_statuslines = 2;
1180     /* only used by curses */
1181     iflags.wc2_windowborders = 2; /* 'Auto' */
1182
1183     /* since this is done before init_objects(), do partial init here */
1184     objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
1185     nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
1186 }
1187
1188 void
1189 initoptions_finish()
1190 {
1191     nhsym sym = 0;
1192 #ifndef MAC
1193     char *opts = getenv("NETHACKOPTIONS");
1194
1195     if (!opts)
1196         opts = getenv("HACKOPTIONS");
1197     if (opts) {
1198         if (*opts == '/' || *opts == '\\' || *opts == '@') {
1199             if (*opts == '@')
1200                 opts++; /* @filename */
1201             /* looks like a filename */
1202             if (strlen(opts) < BUFSZ / 2) {
1203                 config_error_init(TRUE, opts, CONFIG_ERROR_SECURE);
1204                 read_config_file(opts, SET_IN_FILE);
1205                 config_error_done();
1206             }
1207         } else {
1208             config_error_init(TRUE, (char *) 0, FALSE);
1209             read_config_file((char *) 0, SET_IN_FILE);
1210             config_error_done();
1211             /* let the total length of options be long;
1212              * parseoptions() will check each individually
1213              */
1214             config_error_init(FALSE, "NETHACKOPTIONS", FALSE);
1215             (void) parseoptions(opts, TRUE, FALSE);
1216             config_error_done();
1217         }
1218     } else
1219 #endif /* !MAC */
1220     /*else*/ {
1221         config_error_init(TRUE, (char *) 0, FALSE);
1222         read_config_file((char *) 0, SET_IN_FILE);
1223         config_error_done();
1224     }
1225
1226     (void) fruitadd(pl_fruit, (struct fruit *) 0);
1227     /*
1228      * Remove "slime mold" from list of object names.  This will
1229      * prevent it from being wished unless it's actually present
1230      * as a named (or default) fruit.  Wishing for "fruit" will
1231      * result in the player's preferred fruit [better than "\033"].
1232      */
1233     obj_descr[SLIME_MOLD].oc_name = "fruit";
1234
1235     sym = get_othersym(SYM_BOULDER,
1236                 Is_rogue_level(&u.uz) ? ROGUESET : PRIMARY);
1237     if (sym)
1238         showsyms[SYM_BOULDER + SYM_OFF_X] = sym;
1239     reglyph_darkroom();
1240
1241 #ifdef STATUS_HILITES
1242     /*
1243      * A multi-interface binary might only support status highlighting
1244      * for some of the interfaces; check whether we asked for it but are
1245      * using one which doesn't.
1246      *
1247      * Option processing can take place before a user-decided WindowPort
1248      * is even initialized, so check for that too.
1249      */
1250     if (!WINDOWPORT("safe-startup")) {
1251         if (iflags.hilite_delta && !wc2_supported("statushilites")) {
1252             raw_printf("Status highlighting not supported for %s interface.",
1253                        windowprocs.name);
1254             iflags.hilite_delta = 0;
1255         }
1256     }
1257 #endif
1258     return;
1259 }
1260
1261 /* copy up to maxlen-1 characters; 'dest' must be able to hold maxlen;
1262    treat comma as alternate end of 'src' */
1263 STATIC_OVL void
1264 nmcpy(dest, src, maxlen)
1265 char *dest;
1266 const char *src;
1267 int maxlen;
1268 {
1269     int count;
1270
1271     for (count = 1; count < maxlen; count++) {
1272         if (*src == ',' || *src == '\0')
1273             break; /*exit on \0 terminator*/
1274         *dest++ = *src++;
1275     }
1276     *dest = '\0';
1277 }
1278
1279 /*
1280  * escapes(): escape expansion for showsyms.  C-style escapes understood
1281  * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
1282  * (Note: unlike in C, leading digit 0 is not used to indicate octal;
1283  * the letter o (either upper or lower case) is used for that.
1284  * The ^-prefix for control characters is also understood, and \[mM]
1285  * has the effect of 'meta'-ing the value which follows (so that the
1286  * alternate character set will be enabled).
1287  *
1288  * X     normal key X
1289  * ^X    control-X
1290  * \mX   meta-X
1291  *
1292  * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
1293  * prior to terminating '\0' would pull that '\0' into the output and then
1294  * keep processing past it, potentially overflowing the output buffer.
1295  * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
1296  * output and stop there; trailing \M will fall through to \<other> and
1297  * yield 'M', then stop.  Any \X or \O followed by something other than
1298  * an appropriate digit will also fall through to \<other> and yield 'X'
1299  * or 'O', plus stop if the non-digit is end-of-string.
1300  */
1301 STATIC_OVL void
1302 escapes(cp, tp)
1303 const char *cp; /* might be 'tp', updating in place */
1304 char *tp; /* result is never longer than 'cp' */
1305 {
1306     static NEARDATA const char oct[] = "01234567", dec[] = "0123456789",
1307                                hex[] = "00112233445566778899aAbBcCdDeEfF";
1308     const char *dp;
1309     int cval, meta, dcount;
1310
1311     while (*cp) {
1312         /* \M has to be followed by something to do meta conversion,
1313            otherwise it will just be \M which ultimately yields 'M' */
1314         meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]);
1315         if (meta)
1316             cp += 2;
1317
1318         cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
1319         if ((*cp != '\\' && *cp != '^') || !cp[1]) {
1320             /* simple character, or nothing left for \ or ^ to escape */
1321             cval = *cp++;
1322         } else if (*cp == '^') { /* expand control-character syntax */
1323             cval = (*++cp & 0x1f);
1324             ++cp;
1325
1326         /* remaining cases are all for backslash; we know cp[1] is not \0 */
1327         } else if (index(dec, cp[1])) {
1328             ++cp; /* move past backslash to first digit */
1329             do {
1330                 cval = (cval * 10) + (*cp - '0');
1331             } while (*++cp && index(dec, *cp) && ++dcount < 3);
1332         } else if ((cp[1] == 'o' || cp[1] == 'O') && cp[2]
1333                    && index(oct, cp[2])) {
1334             cp += 2; /* move past backslash and 'O' */
1335             do {
1336                 cval = (cval * 8) + (*cp - '0');
1337             } while (*++cp && index(oct, *cp) && ++dcount < 3);
1338         } else if ((cp[1] == 'x' || cp[1] == 'X') && cp[2]
1339                    && (dp = index(hex, cp[2])) != 0) {
1340             cp += 2; /* move past backslash and 'X' */
1341             do {
1342                 cval = (cval * 16) + ((int) (dp - hex) / 2);
1343             } while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2);
1344         } else { /* C-style character escapes */
1345             switch (*++cp) {
1346             case '\\':
1347                 cval = '\\';
1348                 break;
1349             case 'n':
1350                 cval = '\n';
1351                 break;
1352             case 't':
1353                 cval = '\t';
1354                 break;
1355             case 'b':
1356                 cval = '\b';
1357                 break;
1358             case 'r':
1359                 cval = '\r';
1360                 break;
1361             default:
1362                 cval = *cp;
1363             }
1364             ++cp;
1365         }
1366
1367         if (meta)
1368             cval |= 0x80;
1369         *tp++ = (char) cval;
1370     }
1371     *tp = '\0';
1372 }
1373
1374 STATIC_OVL void
1375 rejectoption(optname)
1376 const char *optname;
1377 {
1378 #ifdef MICRO
1379     pline("\"%s\" settable only from %s.", optname, configfile);
1380 #else
1381     pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
1382           configfile);
1383 #endif
1384 }
1385
1386 /*
1387
1388 # errors:
1389 OPTIONS=aaaaaaaaaa[ more than 247 (255 - 8 for 'OPTIONS=') total ]aaaaaaaaaa
1390 OPTIONS
1391 OPTIONS=
1392 MSGTYPE=stop"You swap places with "
1393 MSGTYPE=st.op "You swap places with "
1394 MSGTYPE=stop "You swap places with \"
1395 MENUCOLOR=" blessed "green&none
1396 MENUCOLOR=" holy " = green&reverse
1397 MENUCOLOR=" cursed " = red&uline
1398 MENUCOLOR=" unholy " = reed
1399 OPTIONS=!legacy:true,fooo
1400 OPTIONS=align:!pin
1401 OPTIONS=gender
1402
1403 */
1404
1405 STATIC_OVL char *
1406 string_for_opt(opts, val_optional)
1407 char *opts;
1408 boolean val_optional;
1409 {
1410     char *colon, *equals;
1411
1412     colon = index(opts, ':');
1413     equals = index(opts, '=');
1414     if (!colon || (equals && equals < colon))
1415         colon = equals;
1416
1417     if (!colon || !*++colon) {
1418         if (!val_optional)
1419 /*JP
1420             config_error_add("Missing parameter for '%s'", opts);
1421 */
1422             config_error_add("'%s'\82Ì\88ø\90\94\82ª\82 \82è\82Ü\82¹\82ñ", opts);
1423         return empty_optstr;
1424     }
1425     return colon;
1426 }
1427
1428 STATIC_OVL char *
1429 string_for_env_opt(optname, opts, val_optional)
1430 const char *optname;
1431 char *opts;
1432 boolean val_optional;
1433 {
1434     if (!initial) {
1435         rejectoption(optname);
1436         return empty_optstr;
1437     }
1438     return string_for_opt(opts, val_optional);
1439 }
1440
1441 STATIC_OVL void
1442 bad_negation(optname, with_parameter)
1443 const char *optname;
1444 boolean with_parameter;
1445 {
1446 #if 0 /*JP:T*/
1447     pline_The("%s option may not %sbe negated.", optname,
1448               with_parameter ? "both have a value and " : "");
1449 #else
1450     pline_The("%s\83I\83v\83V\83\87\83\93\82Í\94Û\92è%s\82Å\82«\82È\82¢\81D", optname,
1451               with_parameter ? "\82Æ\92l\8ew\92è\82Ì\97¼\95û\82Í" : "");
1452 #endif
1453 }
1454
1455 /*
1456  * Change the inventory order, using the given string as the new order.
1457  * Missing characters in the new order are filled in at the end from
1458  * the current inv_order, except for gold, which is forced to be first
1459  * if not explicitly present.
1460  *
1461  * This routine returns 1 unless there is a duplicate or bad char in
1462  * the string.
1463  */
1464 STATIC_OVL int
1465 change_inv_order(op)
1466 char *op;
1467 {
1468     int oc_sym, num;
1469     char *sp, buf[QBUFSZ];
1470     int retval = 1;
1471
1472     num = 0;
1473     if (!index(op, GOLD_SYM))
1474         buf[num++] = COIN_CLASS;
1475
1476     for (sp = op; *sp; sp++) {
1477         boolean fail = FALSE;
1478         oc_sym = def_char_to_objclass(*sp);
1479         /* reject bad or duplicate entries */
1480         if (oc_sym == MAXOCLASSES) { /* not an object class char */
1481             config_error_add("Not an object class '%c'", *sp);
1482             retval = 0;
1483             fail = TRUE;
1484         } else if (!index(flags.inv_order, oc_sym)) {
1485             /* VENOM_CLASS, RANDOM_CLASS, and ILLOBJ_CLASS are excluded
1486                because they aren't in def_inv_order[] so don't make it
1487                into flags.inv_order, hence always fail this index() test */
1488             config_error_add("Object class '%c' not allowed", *sp);
1489             retval = 0;
1490             fail = TRUE;
1491         } else if (index(sp + 1, *sp)) {
1492             config_error_add("Duplicate object class '%c'", *sp);
1493             retval = 0;
1494             fail = TRUE;
1495         }
1496         /* retain good ones */
1497         if (!fail)
1498             buf[num++] = (char) oc_sym;
1499     }
1500     buf[num] = '\0';
1501
1502     /* fill in any omitted classes, using previous ordering */
1503     for (sp = flags.inv_order; *sp; sp++)
1504         if (!index(buf, *sp))
1505             (void) strkitten(&buf[num++], *sp);
1506     buf[MAXOCLASSES - 1] = '\0';
1507
1508     Strcpy(flags.inv_order, buf);
1509     return retval;
1510 }
1511
1512 STATIC_OVL boolean
1513 warning_opts(opts, optype)
1514 register char *opts;
1515 const char *optype;
1516 {
1517     uchar translate[WARNCOUNT];
1518     int length, i;
1519
1520     if ((opts = string_for_env_opt(optype, opts, FALSE)) == empty_optstr)
1521         return FALSE;
1522     escapes(opts, opts);
1523
1524     length = (int) strlen(opts);
1525     /* match the form obtained from PC configuration files */
1526     for (i = 0; i < WARNCOUNT; i++)
1527         translate[i] = (i >= length) ? 0
1528                                      : opts[i] ? (uchar) opts[i]
1529                                                : def_warnsyms[i].sym;
1530     assign_warnings(translate);
1531     return TRUE;
1532 }
1533
1534 void
1535 assign_warnings(graph_chars)
1536 register uchar *graph_chars;
1537 {
1538     int i;
1539
1540     for (i = 0; i < WARNCOUNT; i++)
1541         if (graph_chars[i])
1542             warnsyms[i] = graph_chars[i];
1543 }
1544
1545 STATIC_OVL int
1546 feature_alert_opts(op, optn)
1547 char *op;
1548 const char *optn;
1549 {
1550     char buf[BUFSZ];
1551     unsigned long fnv = get_feature_notice_ver(op); /* version.c */
1552
1553     if (fnv == 0L)
1554         return 0;
1555     if (fnv > get_current_feature_ver()) {
1556         if (!initial) {
1557 /*JP
1558             You_cant("disable new feature alerts for future versions.");
1559 */
1560             You_cant("\8f«\97\88\82Ì\83o\81[\83W\83\87\83\93\82Ì\8b@\94\\8cx\8d\90\82ð\96³\8cø\82É\82·\82é\82±\82Æ\82Í\82Å\82«\82È\82¢\81D");
1561         } else {
1562             config_error_add(
1563                         "%s=%s Invalid reference to a future version ignored",
1564                              optn, op);
1565         }
1566         return 0;
1567     }
1568
1569     flags.suppress_alert = fnv;
1570     if (!initial) {
1571         Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
1572                 FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
1573 #if 0 /*JP:T*/
1574         pline(
1575           "Feature change alerts disabled for NetHack %s features and prior.",
1576               buf);
1577 #else
1578         pline(
1579           "NetHack %s \88È\91O\82Ì\8b@\94\\82É\91Î\82·\82é\8b@\94\\95Ï\8dX\8cx\8d\90\82ð\96³\8cø\82É\82µ\82½\81D",
1580               buf);
1581 #endif
1582     }
1583     return 1;
1584 }
1585
1586 void
1587 set_duplicate_opt_detection(on_or_off)
1588 int on_or_off;
1589 {
1590     int k, *optptr;
1591
1592     if (on_or_off != 0) {
1593         /*-- ON --*/
1594         if (iflags.opt_booldup)
1595             impossible("iflags.opt_booldup already on (memory leak)");
1596         iflags.opt_booldup = (int *) alloc(SIZE(boolopt) * sizeof (int));
1597         optptr = iflags.opt_booldup;
1598         for (k = 0; k < SIZE(boolopt); ++k)
1599             *optptr++ = 0;
1600
1601         if (iflags.opt_compdup)
1602             impossible("iflags.opt_compdup already on (memory leak)");
1603         iflags.opt_compdup = (int *) alloc(SIZE(compopt) * sizeof (int));
1604         optptr = iflags.opt_compdup;
1605         for (k = 0; k < SIZE(compopt); ++k)
1606             *optptr++ = 0;
1607     } else {
1608         /*-- OFF --*/
1609         if (iflags.opt_booldup)
1610             free((genericptr_t) iflags.opt_booldup);
1611         iflags.opt_booldup = (int *) 0;
1612         if (iflags.opt_compdup)
1613             free((genericptr_t) iflags.opt_compdup);
1614         iflags.opt_compdup = (int *) 0;
1615     }
1616 }
1617
1618 STATIC_OVL boolean
1619 duplicate_opt_detection(opts, iscompound)
1620 const char *opts;
1621 int iscompound; /* 0 == boolean option, 1 == compound */
1622 {
1623     int i, *optptr;
1624
1625     if (!iscompound && iflags.opt_booldup && initial && from_file) {
1626         for (i = 0; boolopt[i].name; i++) {
1627             if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
1628                 optptr = iflags.opt_booldup + i;
1629                 *optptr += 1;
1630                 if (*optptr > 1)
1631                     return TRUE;
1632                 else
1633                     return FALSE;
1634             }
1635         }
1636     } else if (iscompound && iflags.opt_compdup && initial && from_file) {
1637         for (i = 0; compopt[i].name; i++) {
1638             if (match_optname(opts, compopt[i].name, strlen(compopt[i].name),
1639                               TRUE)) {
1640                 optptr = iflags.opt_compdup + i;
1641                 *optptr += 1;
1642                 if (*optptr > 1)
1643                     return TRUE;
1644                 else
1645                     return FALSE;
1646             }
1647         }
1648     }
1649     return FALSE;
1650 }
1651
1652 STATIC_OVL void
1653 complain_about_duplicate(opts, iscompound)
1654 const char *opts;
1655 int iscompound; /* 0 == boolean option, 1 == compound */
1656 {
1657 #ifdef MAC
1658     /* the Mac has trouble dealing with the output of messages while
1659      * processing the config file.  That should get fixed one day.
1660      * For now just return.
1661      */
1662 #else /* !MAC */
1663 #if 0 /*JP:T*/
1664     config_error_add("%s option specified multiple times: %s",
1665                      iscompound ? "compound" : "boolean", opts);
1666 #else
1667     config_error_add("%s\83I\83v\83V\83\87\83\93\82ª\95¡\90\94\89ñ\8ew\92è\82³\82ê\82Ä\82¢\82Ü\82·\81F%s",
1668                      iscompound ? "\95¡\8d\87" : "\90^\8bU\92l", opts);
1669 #endif
1670 #endif /* ?MAC */
1671     return;
1672 }
1673
1674 /* paranoia[] - used by parseoptions() and special_handling() */
1675 STATIC_VAR const struct paranoia_opts {
1676     int flagmask;        /* which paranoid option */
1677     const char *argname; /* primary name */
1678     int argMinLen;       /* minimum number of letters to match */
1679     const char *synonym; /* alternate name (optional) */
1680     int synMinLen;
1681     const char *explain; /* for interactive menu */
1682 } paranoia[] = {
1683     /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
1684        takes precedence and "all" isn't present in the interactive menu,
1685        and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
1686        (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
1687        is just a synonym for "Confirm"); "b"ones vs "br"eak-wand, the
1688        latter requires at least two letters; "e"at vs "ex"plore,
1689        "cont"inue eating vs "C"onfirm; "wand"-break vs "Were"-change,
1690        both require at least two letters during config processing and use
1691        case-senstivity for 'O's interactive menu */
1692     { PARANOID_CONFIRM, "Confirm", 1, "Paranoia", 2,
1693 /*JP
1694       "for \"yes\" confirmations, require \"no\" to reject" },
1695 */
1696       "\"yes\"\82ð\8am\94F\82·\82é\82Æ\82«\82É\81C\8b\91\94Û\82·\82é\82Æ\82«\82É\82Í\"no\"\82ª\95K\97v" },
1697     { PARANOID_QUIT, "quit", 1, "explore", 2,
1698 /*JP
1699       "yes vs y to quit or to enter explore mode" },
1700 */
1701       "\8fI\97¹\82Ü\82½\82Í\92T\8c\9f\83\82\81[\83h\82É\93ü\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1702     { PARANOID_DIE, "die", 1, "death", 2,
1703 /*JP
1704       "yes vs y to die (explore mode or debug mode)" },
1705 */
1706       "(\92T\8c\9f\83\82\81[\83h\82©\83f\83o\83b\83O\83\82\81[\83h\82Å)\8e\80\82Ê\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1707     { PARANOID_BONES, "bones", 1, 0, 0,
1708 /*JP
1709       "yes vs y to save bones data when dying in debug mode" },
1710 */
1711       "\83f\83o\83b\83O\83\82\81[\83h\82Å\8e\80\82ñ\82Å\8d\9c\83f\81[\83^\82ð\95Û\91\82·\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1712     { PARANOID_HIT, "attack", 1, "hit", 1,
1713 /*JP
1714       "yes vs y to attack a peaceful monster" },
1715 */
1716       "\97F\8dD\93I\89ö\95¨\82ð\8dU\8c\82\82·\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1717     { PARANOID_BREAKWAND, "wand-break", 2, "break-wand", 2,
1718 /*JP
1719       "yes vs y to break a wand via (a)pply" },
1720 */
1721       "(a)pply\82Å\8fñ\82ð\90Ü\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1722     { PARANOID_EATING, "eat", 1, "continue", 4,
1723 /*JP
1724       "yes vs y to continue eating after first bite when satiated" },
1725 */
1726       "\96\9e\95 \82Ì\8e\9e\82É\88ê\8cû\90H\82×\82½\8cã\90H\82×\91±\82¯\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1727     { PARANOID_WERECHANGE, "Were-change", 2, (const char *) 0, 0,
1728 /*JP
1729       "yes vs y to change form when lycanthropy is controllable" },
1730 */
1731       "\8fb\89»\95a\82ª\90§\8cä\89Â\94\\82È\8fê\8d\87\82É\95Ï\89»\82·\82é\82Æ\82«\82Éy\82Å\82Í\82È\82­yes" },
1732     { PARANOID_PRAY, "pray", 1, 0, 0,
1733 /*JP
1734       "y to pray (supersedes old \"prayconfirm\" option)" },
1735 */
1736       "\8bF\82é\82Æ\82«\82Éy\82ª\95K\97v(\8cÃ\82¢\"prayconfirm\"\83I\83v\83V\83\87\83\93\82ð\8fã\8f\91\82«\82·\82é)" },
1737     { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1,
1738 /*JP
1739       "always pick from inventory for Remove and Takeoff" },
1740 */
1741       "Remove\82ÆTakeoff\82Å\8fí\82É\8e\9d\82¿\95¨\88ê\97\97\82©\82ç\91I\82Ô" },
1742     /* for config file parsing; interactive menu skips these */
1743     { 0, "none", 4, 0, 0, 0 }, /* require full word match */
1744     { ~0, "all", 3, 0, 0, 0 }, /* ditto */
1745 };
1746
1747 extern struct menucoloring *menu_colorings;
1748
1749 static const struct {
1750     const char *name;
1751     const int color;
1752 } colornames[] = {
1753     { "black", CLR_BLACK },
1754     { "red", CLR_RED },
1755     { "green", CLR_GREEN },
1756     { "brown", CLR_BROWN },
1757     { "blue", CLR_BLUE },
1758     { "magenta", CLR_MAGENTA },
1759     { "cyan", CLR_CYAN },
1760     { "gray", CLR_GRAY },
1761     { "orange", CLR_ORANGE },
1762     { "light green", CLR_BRIGHT_GREEN },
1763     { "yellow", CLR_YELLOW },
1764     { "light blue", CLR_BRIGHT_BLUE },
1765     { "light magenta", CLR_BRIGHT_MAGENTA },
1766     { "light cyan", CLR_BRIGHT_CYAN },
1767     { "white", CLR_WHITE },
1768     { "no color", NO_COLOR },
1769     { NULL, CLR_BLACK }, /* everything after this is an alias */
1770     { "transparent", NO_COLOR },
1771     { "purple", CLR_MAGENTA },
1772     { "light purple", CLR_BRIGHT_MAGENTA },
1773     { "bright purple", CLR_BRIGHT_MAGENTA },
1774     { "grey", CLR_GRAY },
1775     { "bright red", CLR_ORANGE },
1776     { "bright green", CLR_BRIGHT_GREEN },
1777     { "bright blue", CLR_BRIGHT_BLUE },
1778     { "bright magenta", CLR_BRIGHT_MAGENTA },
1779     { "bright cyan", CLR_BRIGHT_CYAN }
1780 };
1781
1782 static const struct {
1783     const char *name;
1784     const int attr;
1785 } attrnames[] = {
1786     { "none", ATR_NONE },
1787     { "bold", ATR_BOLD },
1788     { "dim", ATR_DIM },
1789     { "underline", ATR_ULINE },
1790     { "blink", ATR_BLINK },
1791     { "inverse", ATR_INVERSE },
1792     { NULL, ATR_NONE }, /* everything after this is an alias */
1793     { "normal", ATR_NONE },
1794     { "uline", ATR_ULINE },
1795     { "reverse", ATR_INVERSE },
1796 };
1797
1798 const char *
1799 clr2colorname(clr)
1800 int clr;
1801 {
1802     int i;
1803
1804     for (i = 0; i < SIZE(colornames); i++)
1805         if (colornames[i].name && colornames[i].color == clr)
1806             return colornames[i].name;
1807     return (char *) 0;
1808 }
1809
1810 int
1811 match_str2clr(str)
1812 char *str;
1813 {
1814     int i, c = CLR_MAX;
1815
1816     /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
1817        (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
1818        also copes with trailing space; caller has removed any leading space */
1819     for (i = 0; i < SIZE(colornames); i++)
1820         if (colornames[i].name
1821             && fuzzymatch(str, colornames[i].name, " -_", TRUE)) {
1822             c = colornames[i].color;
1823             break;
1824         }
1825     if (i == SIZE(colornames) && digit(*str))
1826         c = atoi(str);
1827
1828     if (c < 0 || c >= CLR_MAX) {
1829         config_error_add("Unknown color '%.60s'", str);
1830         c = CLR_MAX; /* "none of the above" */
1831     }
1832
1833     return c;
1834 }
1835
1836 STATIC_OVL const char *
1837 attr2attrname(attr)
1838 int attr;
1839 {
1840     int i;
1841
1842     for (i = 0; i < SIZE(attrnames); i++)
1843         if (attrnames[i].attr == attr)
1844             return attrnames[i].name;
1845     return (char *) 0;
1846 }
1847
1848 int
1849 match_str2attr(str, complain)
1850 const char *str;
1851 boolean complain;
1852 {
1853     int i, a = -1;
1854
1855     for (i = 0; i < SIZE(attrnames); i++)
1856         if (attrnames[i].name
1857             && fuzzymatch(str, attrnames[i].name, " -_", TRUE)) {
1858             a = attrnames[i].attr;
1859             break;
1860         }
1861
1862     if (a == -1 && complain)
1863         config_error_add("Unknown text attribute '%.50s'", str);
1864
1865     return a;
1866 }
1867
1868 int
1869 query_color(prompt)
1870 const char *prompt;
1871 {
1872     winid tmpwin;
1873     anything any;
1874     int i, pick_cnt;
1875     menu_item *picks = (menu_item *) 0;
1876
1877     tmpwin = create_nhwindow(NHW_MENU);
1878     start_menu(tmpwin);
1879     any = zeroany;
1880     for (i = 0; i < SIZE(colornames); i++) {
1881         if (!colornames[i].name)
1882             break;
1883         any.a_int = i + 1;
1884         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name,
1885                  (colornames[i].color == NO_COLOR) ? MENU_SELECTED
1886                                                    : MENU_UNSELECTED);
1887     }
1888     end_menu(tmpwin, (prompt && *prompt) ? prompt : "Pick a color");
1889     pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1890     destroy_nhwindow(tmpwin);
1891     if (pick_cnt > 0) {
1892         i = colornames[picks[0].item.a_int - 1].color;
1893         /* pick_cnt==2: explicitly picked something other than the
1894            preselected entry */
1895         if (pick_cnt == 2 && i == NO_COLOR)
1896             i = colornames[picks[1].item.a_int - 1].color;
1897         free((genericptr_t) picks);
1898         return i;
1899     } else if (pick_cnt == 0) {
1900         /* pick_cnt==0: explicitly picking preselected entry toggled it off */
1901         return NO_COLOR;
1902     }
1903     return -1;
1904 }
1905
1906 /* ask about highlighting attribute; for menu headers and menu
1907    coloring patterns, only one attribute at a time is allowed;
1908    for status highlighting, multiple attributes are allowed [overkill;
1909    life would be much simpler if that were restricted to one also...] */
1910 int
1911 query_attr(prompt)
1912 const char *prompt;
1913 {
1914     winid tmpwin;
1915     anything any;
1916     int i, pick_cnt;
1917     menu_item *picks = (menu_item *) 0;
1918     boolean allow_many = (prompt && !strncmpi(prompt, "Choose", 6));
1919     int default_attr = ATR_NONE;
1920
1921     if (prompt && strstri(prompt, "menu headings"))
1922         default_attr = iflags.menu_headings;
1923     tmpwin = create_nhwindow(NHW_MENU);
1924     start_menu(tmpwin);
1925     any = zeroany;
1926     for (i = 0; i < SIZE(attrnames); i++) {
1927         if (!attrnames[i].name)
1928             break;
1929         any.a_int = i + 1;
1930         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr,
1931                  attrnames[i].name,
1932                  (attrnames[i].attr == default_attr) ? MENU_SELECTED
1933                                                      : MENU_UNSELECTED);
1934     }
1935     end_menu(tmpwin, (prompt && *prompt) ? prompt : "Pick an attribute");
1936     pick_cnt = select_menu(tmpwin, allow_many ? PICK_ANY : PICK_ONE, &picks);
1937     destroy_nhwindow(tmpwin);
1938     if (pick_cnt > 0) {
1939         int j, k = 0;
1940
1941         if (allow_many) {
1942             /* PICK_ANY, with one preselected entry (ATR_NONE) which
1943                should be excluded if any other choices were picked */
1944             for (i = 0; i < pick_cnt; ++i) {
1945                 j = picks[i].item.a_int - 1;
1946                 if (attrnames[j].attr != ATR_NONE || pick_cnt == 1) {
1947                     switch (attrnames[j].attr) {
1948                     case ATR_DIM:
1949                         k |= HL_DIM;
1950                         break;
1951                     case ATR_BLINK:
1952                         k |= HL_BLINK;
1953                         break;
1954                     case ATR_ULINE:
1955                         k |= HL_ULINE;
1956                         break;
1957                     case ATR_INVERSE:
1958                         k |= HL_INVERSE;
1959                         break;
1960                     case ATR_BOLD:
1961                         k |= HL_BOLD;
1962                         break;
1963                     case ATR_NONE:
1964                         k = HL_NONE;
1965                         break;
1966                     }
1967                 }
1968             }
1969         } else {
1970             /* PICK_ONE, but might get 0 or 2 due to preselected entry */
1971             j = picks[0].item.a_int - 1;
1972             /* pick_cnt==2: explicitly picked something other than the
1973                preselected entry */
1974             if (pick_cnt == 2 && attrnames[j].attr == default_attr)
1975                 j = picks[1].item.a_int - 1;
1976             k = attrnames[j].attr;
1977         }
1978         free((genericptr_t) picks);
1979         return k;
1980     } else if (pick_cnt == 0 && !allow_many) {
1981         /* PICK_ONE, preselected entry explicitly chosen */
1982         return default_attr;
1983     }
1984     /* either ESC to explicitly cancel (pick_cnt==-1) or
1985        PICK_ANY with preselected entry toggled off and nothing chosen */
1986     return -1;
1987 }
1988
1989 static const struct {
1990     const char *name;
1991     xchar msgtyp;
1992     const char *descr;
1993 } msgtype_names[] = {
1994 /*JP
1995     { "show", MSGTYP_NORMAL, "Show message normally" },
1996 */
1997     { "show", MSGTYP_NORMAL, "\92Ê\8fí\92Ê\82è\83\81\83b\83Z\81[\83W\82ð\95\\8e¦\82·\82é" },
1998 /*JP
1999     { "hide", MSGTYP_NOSHOW, "Hide message" },
2000 */
2001     { "hide", MSGTYP_NOSHOW, "\83\81\83b\83Z\81[\83W\82ð\95\\8e¦\82µ\82È\82¢" },
2002     { "noshow", MSGTYP_NOSHOW, NULL },
2003 /*JP
2004     { "stop", MSGTYP_STOP, "Prompt for more after the message" },
2005 */
2006     { "stop", MSGTYP_STOP, "more\83v\83\8d\83\93\83v\83g\82Å\91Ò\82Â" },
2007     { "more", MSGTYP_STOP, NULL },
2008 /*JP
2009     { "norep", MSGTYP_NOREP, "Do not repeat the message" }
2010 */
2011     { "norep", MSGTYP_NOREP, "\82±\82Ì\83\81\83b\83Z\81[\83W\82Í\8cJ\82è\95Ô\82³\82È\82¢" }
2012 };
2013
2014 STATIC_OVL const char *
2015 msgtype2name(typ)
2016 int typ;
2017 {
2018     int i;
2019
2020     for (i = 0; i < SIZE(msgtype_names); i++)
2021         if (msgtype_names[i].descr && msgtype_names[i].msgtyp == typ)
2022             return msgtype_names[i].name;
2023     return (char *) 0;
2024 }
2025
2026 STATIC_OVL int
2027 query_msgtype()
2028 {
2029     winid tmpwin;
2030     anything any;
2031     int i, pick_cnt;
2032     menu_item *picks = (menu_item *) 0;
2033
2034     tmpwin = create_nhwindow(NHW_MENU);
2035     start_menu(tmpwin);
2036     any = zeroany;
2037     for (i = 0; i < SIZE(msgtype_names); i++)
2038         if (msgtype_names[i].descr) {
2039             any.a_int = msgtype_names[i].msgtyp + 1;
2040             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2041                  msgtype_names[i].descr, MENU_UNSELECTED);
2042         }
2043 /*JP
2044     end_menu(tmpwin, "How to show the message");
2045 */
2046     end_menu(tmpwin, "\83\81\83b\83Z\81[\83W\82Ì\95\\8e¦\95û\96@");
2047     pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
2048     destroy_nhwindow(tmpwin);
2049     if (pick_cnt > 0) {
2050         i = picks->item.a_int - 1;
2051         free((genericptr_t) picks);
2052         return i;
2053     }
2054     return -1;
2055 }
2056
2057 STATIC_OVL boolean
2058 msgtype_add(typ, pattern)
2059 int typ;
2060 char *pattern;
2061 {
2062     struct plinemsg_type *tmp = (struct plinemsg_type *) alloc(sizeof *tmp);
2063
2064     tmp->msgtype = typ;
2065     tmp->regex = regex_init();
2066     if (!regex_compile(pattern, tmp->regex)) {
2067         static const char *re_error = "MSGTYPE regex error";
2068
2069         config_error_add("%s: %s", re_error, regex_error_desc(tmp->regex));
2070         regex_free(tmp->regex);
2071         free((genericptr_t) tmp);
2072         return FALSE;
2073     }
2074     tmp->pattern = dupstr(pattern);
2075     tmp->next = plinemsg_types;
2076     plinemsg_types = tmp;
2077     return TRUE;
2078 }
2079
2080 void
2081 msgtype_free()
2082 {
2083     struct plinemsg_type *tmp, *tmp2 = 0;
2084
2085     for (tmp = plinemsg_types; tmp; tmp = tmp2) {
2086         tmp2 = tmp->next;
2087         free((genericptr_t) tmp->pattern);
2088         regex_free(tmp->regex);
2089         free((genericptr_t) tmp);
2090     }
2091     plinemsg_types = (struct plinemsg_type *) 0;
2092 }
2093
2094 STATIC_OVL void
2095 free_one_msgtype(idx)
2096 int idx; /* 0 .. */
2097 {
2098     struct plinemsg_type *tmp = plinemsg_types;
2099     struct plinemsg_type *prev = NULL;
2100
2101     while (tmp) {
2102         if (idx == 0) {
2103             struct plinemsg_type *next = tmp->next;
2104
2105             regex_free(tmp->regex);
2106             free((genericptr_t) tmp->pattern);
2107             free((genericptr_t) tmp);
2108             if (prev)
2109                 prev->next = next;
2110             else
2111                 plinemsg_types = next;
2112             return;
2113         }
2114         idx--;
2115         prev = tmp;
2116         tmp = tmp->next;
2117     }
2118 }
2119
2120 int
2121 msgtype_type(msg, norepeat)
2122 const char *msg;
2123 boolean norepeat; /* called from Norep(via pline) */
2124 {
2125     struct plinemsg_type *tmp = plinemsg_types;
2126
2127     while (tmp) {
2128         /* we don't exclude entries with negative msgtype values
2129            because then the msg might end up matching a later pattern */
2130         if (regex_match(msg, tmp->regex))
2131             return tmp->msgtype;
2132         tmp = tmp->next;
2133     }
2134     return norepeat ? MSGTYP_NOREP : MSGTYP_NORMAL;
2135 }
2136
2137 /* negate one or more types of messages so that their type handling will
2138    be disabled or re-enabled; MSGTYPE_NORMAL (value 0) is not affected */
2139 void
2140 hide_unhide_msgtypes(hide, hide_mask)
2141 boolean hide;
2142 int hide_mask;
2143 {
2144     struct plinemsg_type *tmp;
2145     int mt;
2146
2147     /* negative msgtype value won't be recognized by pline, so does nothing */
2148     for (tmp = plinemsg_types; tmp; tmp = tmp->next) {
2149         mt = tmp->msgtype;
2150         if (!hide)
2151             mt = -mt; /* unhide: negate negative, yielding positive */
2152         if (mt > 0 && ((1 << mt) & hide_mask))
2153             tmp->msgtype = -tmp->msgtype;
2154     }
2155 }
2156
2157 STATIC_OVL int
2158 msgtype_count(VOID_ARGS)
2159 {
2160     int c = 0;
2161     struct plinemsg_type *tmp = plinemsg_types;
2162
2163     while (tmp) {
2164         c++;
2165         tmp = tmp->next;
2166     }
2167     return c;
2168 }
2169
2170 boolean
2171 msgtype_parse_add(str)
2172 char *str;
2173 {
2174     char pattern[256];
2175     char msgtype[11];
2176
2177     if (sscanf(str, "%10s \"%255[^\"]\"", msgtype, pattern) == 2) {
2178         int typ = -1;
2179         int i;
2180
2181         for (i = 0; i < SIZE(msgtype_names); i++)
2182             if (!strncmpi(msgtype_names[i].name, msgtype, strlen(msgtype))) {
2183                 typ = msgtype_names[i].msgtyp;
2184                 break;
2185             }
2186         if (typ != -1)
2187             return msgtype_add(typ, pattern);
2188         else
2189             config_error_add("Unknown message type '%s'", msgtype);
2190     } else {
2191         config_error_add("Malformed MSGTYPE");
2192     }
2193     return FALSE;
2194 }
2195
2196 STATIC_OVL boolean
2197 test_regex_pattern(str, errmsg)
2198 const char *str;
2199 const char *errmsg;
2200 {
2201     static const char re_error[] = "Regex error";
2202     struct nhregex *match;
2203     boolean retval = TRUE;
2204
2205     if (!str)
2206         return FALSE;
2207
2208     match = regex_init();
2209     if (!match) {
2210         config_error_add("NHregex error");
2211         return FALSE;
2212     }
2213
2214     if (!regex_compile(str, match)) {
2215         config_error_add("%s: %s", errmsg ? errmsg : re_error,
2216                          regex_error_desc(match));
2217         retval = FALSE;
2218     }
2219     regex_free(match);
2220     return retval;
2221 }
2222
2223 STATIC_OVL boolean
2224 add_menu_coloring_parsed(str, c, a)
2225 char *str;
2226 int c, a;
2227 {
2228     static const char re_error[] = "Menucolor regex error";
2229     struct menucoloring *tmp;
2230
2231     if (!str)
2232         return FALSE;
2233     tmp = (struct menucoloring *) alloc(sizeof *tmp);
2234     tmp->match = regex_init();
2235     if (!regex_compile(str, tmp->match)) {
2236         config_error_add("%s: %s", re_error, regex_error_desc(tmp->match));
2237         regex_free(tmp->match);
2238         free(tmp);
2239         return FALSE;
2240     } else {
2241         tmp->next = menu_colorings;
2242         tmp->origstr = dupstr(str);
2243         tmp->color = c;
2244         tmp->attr = a;
2245         menu_colorings = tmp;
2246         return TRUE;
2247     }
2248 }
2249
2250 /* parse '"regex_string"=color&attr' and add it to menucoloring */
2251 boolean
2252 add_menu_coloring(tmpstr)
2253 char *tmpstr; /* never Null but could be empty */
2254 {
2255     int c = NO_COLOR, a = ATR_NONE;
2256     char *tmps, *cs, *amp;
2257     char str[BUFSZ];
2258
2259     (void) strncpy(str, tmpstr, sizeof str - 1);
2260     str[sizeof str - 1] = '\0';
2261
2262     if ((cs = index(str, '=')) == 0) {
2263         config_error_add("Malformed MENUCOLOR");
2264         return FALSE;
2265     }
2266
2267     tmps = cs + 1; /* advance past '=' */
2268     mungspaces(tmps);
2269     if ((amp = index(tmps, '&')) != 0)
2270         *amp = '\0';
2271
2272     c = match_str2clr(tmps);
2273     if (c >= CLR_MAX)
2274         return FALSE;
2275
2276     if (amp) {
2277         tmps = amp + 1; /* advance past '&' */
2278         a = match_str2attr(tmps, TRUE);
2279         if (a == -1)
2280             return FALSE;
2281     }
2282
2283     /* the regexp portion here has not been condensed by mungspaces() */
2284     *cs = '\0';
2285     tmps = str;
2286     if (*tmps == '"' || *tmps == '\'') {
2287         cs--;
2288         while (isspace((uchar) *cs))
2289             cs--;
2290         if (*cs == *tmps) {
2291             *cs = '\0';
2292             tmps++;
2293         }
2294     }
2295     return add_menu_coloring_parsed(tmps, c, a);
2296 }
2297
2298 boolean
2299 get_menu_coloring(str, color, attr)
2300 const char *str;
2301 int *color, *attr;
2302 {
2303     struct menucoloring *tmpmc;
2304
2305     if (iflags.use_menu_color)
2306         for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next)
2307             if (regex_match(str, tmpmc->match)) {
2308                 *color = tmpmc->color;
2309                 *attr = tmpmc->attr;
2310                 return TRUE;
2311             }
2312     return FALSE;
2313 }
2314
2315 void
2316 free_menu_coloring()
2317 {
2318     struct menucoloring *tmp, *tmp2;
2319
2320     for (tmp = menu_colorings; tmp; tmp = tmp2) {
2321         tmp2 = tmp->next;
2322         regex_free(tmp->match);
2323         free((genericptr_t) tmp->origstr);
2324         free((genericptr_t) tmp);
2325     }
2326 }
2327
2328 STATIC_OVL void
2329 free_one_menu_coloring(idx)
2330 int idx; /* 0 .. */
2331 {
2332     struct menucoloring *tmp = menu_colorings;
2333     struct menucoloring *prev = NULL;
2334
2335     while (tmp) {
2336         if (idx == 0) {
2337             struct menucoloring *next = tmp->next;
2338
2339             regex_free(tmp->match);
2340             free((genericptr_t) tmp->origstr);
2341             free((genericptr_t) tmp);
2342             if (prev)
2343                 prev->next = next;
2344             else
2345                 menu_colorings = next;
2346             return;
2347         }
2348         idx--;
2349         prev = tmp;
2350         tmp = tmp->next;
2351     }
2352 }
2353
2354 STATIC_OVL int
2355 count_menucolors(VOID_ARGS)
2356 {
2357     struct menucoloring *tmp;
2358     int count = 0;
2359
2360     for (tmp = menu_colorings; tmp; tmp = tmp->next)
2361         count++;
2362     return count;
2363 }
2364
2365 STATIC_OVL boolean
2366 parse_role_opts(negated, fullname, opts, opp)
2367 boolean negated;
2368 const char *fullname;
2369 char *opts;
2370 char **opp;
2371 {
2372     char *op = *opp;
2373
2374     if (negated) {
2375         bad_negation(fullname, FALSE);
2376     } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2377                                         != empty_optstr) {
2378         boolean val_negated = FALSE;
2379
2380         while ((*op == '!') || !strncmpi(op, "no", 2)) {
2381             if (*op == '!')
2382                 op++;
2383             else
2384                 op += 2;
2385             val_negated = !val_negated;
2386         }
2387         if (val_negated) {
2388             if (!setrolefilter(op)) {
2389                 config_error_add("Unknown negated parameter '%s'", op);
2390                 return FALSE;
2391             }
2392         } else {
2393             if (duplicate_opt_detection(opts, 1))
2394                 complain_about_duplicate(opts, 1);
2395             *opp = op;
2396             return TRUE;
2397         }
2398     }
2399     return FALSE;
2400 }
2401
2402 /* Check if character c is illegal as a menu command key */
2403 boolean
2404 illegal_menu_cmd_key(c)
2405 char c;
2406 {
2407     if (c == 0 || c == '\r' || c == '\n' || c == '\033'
2408         || c == ' ' || digit(c) || (letter(c) && c != '@')) {
2409         config_error_add("Reserved menu command key '%s'", visctrl(c));
2410         return TRUE;
2411     } else { /* reject default object class symbols */
2412         int j;
2413         for (j = 1; j < MAXOCLASSES; j++)
2414             if (c == def_oc_syms[j].sym) {
2415                 config_error_add("Menu command key '%s' is an object class",
2416                                  visctrl(c));
2417                 return TRUE;
2418             }
2419     }
2420     return FALSE;
2421 }
2422
2423 boolean
2424 parseoptions(opts, tinitial, tfrom_file)
2425 register char *opts;
2426 boolean tinitial, tfrom_file;
2427 {
2428     char *op;
2429     unsigned num;
2430     boolean negated, duplicate;
2431     int i;
2432     const char *fullname;
2433     boolean retval = TRUE;
2434
2435     initial = tinitial;
2436     from_file = tfrom_file;
2437     if ((op = index(opts, ',')) != 0) {
2438         *op++ = 0;
2439         if (!parseoptions(op, initial, from_file))
2440             retval = FALSE;
2441     }
2442     if (strlen(opts) > BUFSZ / 2) {
2443         config_error_add("Option too long, max length is %i characters",
2444                          (BUFSZ / 2));
2445         return FALSE;
2446     }
2447
2448     /* strip leading and trailing white space */
2449     while (isspace((uchar) *opts))
2450         opts++;
2451     op = eos(opts);
2452     while (--op >= opts && isspace((uchar) *op))
2453         *op = '\0';
2454
2455     if (!*opts) {
2456         config_error_add("Empty statement");
2457         return FALSE;
2458     }
2459     negated = FALSE;
2460     while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
2461         if (*opts == '!')
2462             opts++;
2463         else
2464             opts += 2;
2465         negated = !negated;
2466     }
2467
2468     /* variant spelling */
2469
2470     if (match_optname(opts, "colour", 5, FALSE))
2471         Strcpy(opts, "color"); /* fortunately this isn't longer */
2472
2473     /* special boolean options */
2474
2475     if (match_optname(opts, "female", 3, FALSE)) {
2476         if (duplicate_opt_detection(opts, 0))
2477             complain_about_duplicate(opts, 0);
2478         if (!initial && flags.female == negated) {
2479             config_error_add("That is not anatomically possible.");
2480             return FALSE;
2481         } else
2482             flags.initgend = flags.female = !negated;
2483         return retval;
2484     }
2485
2486     if (match_optname(opts, "male", 4, FALSE)) {
2487         if (duplicate_opt_detection(opts, 0))
2488             complain_about_duplicate(opts, 0);
2489         if (!initial && flags.female != negated) {
2490             config_error_add("That is not anatomically possible.");
2491             return FALSE;
2492         } else
2493             flags.initgend = flags.female = negated;
2494         return retval;
2495     }
2496
2497 #if defined(MICRO) && !defined(AMIGA)
2498     /* included for compatibility with old NetHack.cnf files */
2499     if (match_optname(opts, "IBM_", 4, FALSE)) {
2500         iflags.BIOS = !negated;
2501         return retval;
2502     }
2503 #endif /* MICRO */
2504
2505     /* compound options */
2506
2507     /* This first batch can be duplicated if their values are negated */
2508
2509     /* align:string */
2510     fullname = "align";
2511     if (match_optname(opts, fullname, sizeof "align" - 1, TRUE)) {
2512         if (parse_role_opts(negated, fullname, opts, &op)) {
2513             if ((flags.initalign = str2align(op)) == ROLE_NONE) {
2514                 config_error_add("Unknown %s '%s'", fullname, op);
2515                 return FALSE;
2516             }
2517         } else
2518             return FALSE;
2519         return retval;
2520     }
2521
2522     /* role:string or character:string */
2523     fullname = "role";
2524     if (match_optname(opts, fullname, 4, TRUE)
2525         || match_optname(opts, (fullname = "character"), 4, TRUE)) {
2526         if (parse_role_opts(negated, fullname, opts, &op)) {
2527             if ((flags.initrole = str2role(op)) == ROLE_NONE) {
2528                 config_error_add("Unknown %s '%s'", fullname, op);
2529                 return FALSE;
2530             } else /* Backwards compatibility */
2531                 nmcpy(pl_character, op, PL_NSIZ);
2532         } else
2533             return FALSE;
2534         return retval;
2535     }
2536
2537     /* race:string */
2538     fullname = "race";
2539     if (match_optname(opts, fullname, 4, TRUE)) {
2540         if (parse_role_opts(negated, fullname, opts, &op)) {
2541             if ((flags.initrace = str2race(op)) == ROLE_NONE) {
2542                 config_error_add("Unknown %s '%s'", fullname, op);
2543                 return FALSE;
2544             } else /* Backwards compatibility */
2545                 pl_race = *op;
2546         } else
2547             return FALSE;
2548         return retval;
2549     }
2550
2551     /* gender:string */
2552     fullname = "gender";
2553     if (match_optname(opts, fullname, 4, TRUE)) {
2554         if (parse_role_opts(negated, fullname, opts, &op)) {
2555             if ((flags.initgend = str2gend(op)) == ROLE_NONE) {
2556                 config_error_add("Unknown %s '%s'", fullname, op);
2557                 return FALSE;
2558             } else
2559                 flags.female = flags.initgend;
2560         } else
2561             return FALSE;
2562         return retval;
2563     }
2564
2565     /* We always check for duplicates on the remaining compound options,
2566        although individual option processing can choose to complain or not */
2567
2568     duplicate = duplicate_opt_detection(opts, 1); /* 1: check compounds */
2569
2570     fullname = "pettype";
2571     if (match_optname(opts, fullname, 3, TRUE)) {
2572         if (duplicate)
2573             complain_about_duplicate(opts, 1);
2574         if ((op = string_for_env_opt(fullname, opts, negated))
2575                                      != empty_optstr) {
2576             if (negated) {
2577                 bad_negation(fullname, TRUE);
2578                 return FALSE;
2579             } else
2580                 switch (lowc(*op)) {
2581                 case 'd': /* dog */
2582                     preferred_pet = 'd';
2583                     break;
2584                 case 'c': /* cat */
2585                 case 'f': /* feline */
2586                     preferred_pet = 'c';
2587                     break;
2588                 case 'h': /* horse */
2589                 case 'q': /* quadruped */
2590                     /* avoids giving "unrecognized type of pet" but
2591                        pet_type(dog.c) won't actually honor this */
2592                     preferred_pet = 'h';
2593                     break;
2594                 case 'n': /* no pet */
2595                     preferred_pet = 'n';
2596                     break;
2597                 case '*': /* random */
2598                     preferred_pet = '\0';
2599                     break;
2600                 default:
2601 /*JP
2602                     config_error_add("Unrecognized pet type '%s'.", op);
2603 */
2604                     pline("'%s'\82Í\83y\83b\83g\82Ì\8eí\97Þ\82Æ\82µ\82Ä\8eó\82¯\95t\82¯\82ç\82ê\82Ü\82¹\82ñ\81D", op);
2605                     return FALSE;
2606                     break;
2607                 }
2608         } else if (negated)
2609             preferred_pet = 'n';
2610         return retval;
2611     }
2612
2613     fullname = "catname";
2614     if (match_optname(opts, fullname, 3, TRUE)) {
2615         if (duplicate)
2616             complain_about_duplicate(opts, 1);
2617         if (negated) {
2618             bad_negation(fullname, FALSE);
2619             return FALSE;
2620         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2621                                             != empty_optstr) {
2622             nmcpy(catname, op, PL_PSIZ);
2623         } else
2624             return FALSE;
2625         sanitize_name(catname);
2626         return retval;
2627     }
2628
2629     fullname = "dogname";
2630     if (match_optname(opts, fullname, 3, TRUE)) {
2631         if (duplicate)
2632             complain_about_duplicate(opts, 1);
2633         if (negated) {
2634             bad_negation(fullname, FALSE);
2635             return FALSE;
2636         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2637                                             != empty_optstr) {
2638             nmcpy(dogname, op, PL_PSIZ);
2639         } else
2640             return FALSE;
2641         sanitize_name(dogname);
2642         return retval;
2643     }
2644
2645     fullname = "horsename";
2646     if (match_optname(opts, fullname, 5, TRUE)) {
2647         if (duplicate)
2648             complain_about_duplicate(opts, 1);
2649         if (negated) {
2650             bad_negation(fullname, FALSE);
2651             return FALSE;
2652         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2653                                             != empty_optstr) {
2654             nmcpy(horsename, op, PL_PSIZ);
2655         } else
2656             return FALSE;
2657         sanitize_name(horsename);
2658         return retval;
2659     }
2660
2661     fullname = "mouse_support";
2662     if (match_optname(opts, fullname, 13, TRUE)) {
2663         boolean compat = (strlen(opts) <= 13);
2664
2665         if (duplicate)
2666             complain_about_duplicate(opts, 1);
2667         op = string_for_opt(opts, (compat || !initial));
2668         if (op == empty_optstr) {
2669             if (compat || negated || initial) {
2670                 /* for backwards compatibility, "mouse_support" without a
2671                    value is a synonym for mouse_support:1 */
2672                 iflags.wc_mouse_support = !negated;
2673             }
2674         } else if (negated) {
2675             bad_negation(fullname, TRUE);
2676             return FALSE;
2677         } else {
2678             int mode = atoi(op);
2679
2680             if (mode < 0 || mode > 2 || (mode == 0 && *op != '0')) {
2681                 config_error_add("Illegal %s parameter '%s'", fullname, op);
2682                 return FALSE;
2683             } else { /* mode >= 0 */
2684                 iflags.wc_mouse_support = mode;
2685             }
2686         }
2687         return retval;
2688     }
2689
2690     fullname = "number_pad";
2691     if (match_optname(opts, fullname, 10, TRUE)) {
2692         boolean compat = (strlen(opts) <= 10);
2693
2694         if (duplicate)
2695             complain_about_duplicate(opts, 1);
2696         op = string_for_opt(opts, (compat || !initial));
2697         if (op == empty_optstr) {
2698             if (compat || negated || initial) {
2699                 /* for backwards compatibility, "number_pad" without a
2700                    value is a synonym for number_pad:1 */
2701                 iflags.num_pad = !negated;
2702                 iflags.num_pad_mode = 0;
2703             }
2704         } else if (negated) {
2705             bad_negation(fullname, TRUE);
2706             return FALSE;
2707         } else {
2708             int mode = atoi(op);
2709
2710             if (mode < -1 || mode > 4 || (mode == 0 && *op != '0')) {
2711                 config_error_add("Illegal %s parameter '%s'", fullname, op);
2712                 return FALSE;
2713             } else if (mode <= 0) {
2714                 iflags.num_pad = FALSE;
2715                 /* German keyboard; y and z keys swapped */
2716                 iflags.num_pad_mode = (mode < 0); /* 0 or 1 */
2717             } else {                              /* mode > 0 */
2718                 iflags.num_pad = TRUE;
2719                 iflags.num_pad_mode = 0;
2720                 /* PC Hack / MSDOS compatibility */
2721                 if (mode == 2 || mode == 4)
2722                     iflags.num_pad_mode |= 1;
2723                 /* phone keypad layout */
2724                 if (mode == 3 || mode == 4)
2725                     iflags.num_pad_mode |= 2;
2726             }
2727         }
2728         reset_commands(FALSE);
2729         number_pad(iflags.num_pad ? 1 : 0);
2730         return retval;
2731     }
2732
2733     fullname = "roguesymset";
2734     if (match_optname(opts, fullname, 7, TRUE)) {
2735         if (duplicate)
2736             complain_about_duplicate(opts, 1);
2737         if (negated) {
2738             bad_negation(fullname, FALSE);
2739             return FALSE;
2740         } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2741             symset[ROGUESET].name = dupstr(op);
2742             if (!read_sym_file(ROGUESET)) {
2743                 clear_symsetentry(ROGUESET, TRUE);
2744                 config_error_add(
2745                                "Unable to load symbol set \"%s\" from \"%s\"",
2746                                  op, SYMBOLS);
2747                 return FALSE;
2748             } else {
2749                 if (!initial && Is_rogue_level(&u.uz))
2750                     assign_graphics(ROGUESET);
2751                 need_redraw = TRUE;
2752             }
2753         } else
2754             return FALSE;
2755         return retval;
2756     }
2757
2758     fullname = "symset";
2759     if (match_optname(opts, fullname, 6, TRUE)) {
2760         if (duplicate)
2761             complain_about_duplicate(opts, 1);
2762         if (negated) {
2763             bad_negation(fullname, FALSE);
2764             return FALSE;
2765         } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2766             symset[PRIMARY].name = dupstr(op);
2767             if (!read_sym_file(PRIMARY)) {
2768                 clear_symsetentry(PRIMARY, TRUE);
2769                 config_error_add(
2770                                "Unable to load symbol set \"%s\" from \"%s\"",
2771                                  op, SYMBOLS);
2772                 return FALSE;
2773             } else {
2774                 switch_symbols(symset[PRIMARY].name != (char *) 0);
2775                 need_redraw = TRUE;
2776             }
2777         } else
2778             return FALSE;
2779         return retval;
2780     }
2781
2782     fullname = "runmode";
2783     if (match_optname(opts, fullname, 4, TRUE)) {
2784         if (duplicate)
2785             complain_about_duplicate(opts, 1);
2786         if (negated) {
2787             flags.runmode = RUN_TPORT;
2788         } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2789             if (!strncmpi(op, "teleport", strlen(op)))
2790                 flags.runmode = RUN_TPORT;
2791             else if (!strncmpi(op, "run", strlen(op)))
2792                 flags.runmode = RUN_LEAP;
2793             else if (!strncmpi(op, "walk", strlen(op)))
2794                 flags.runmode = RUN_STEP;
2795             else if (!strncmpi(op, "crawl", strlen(op)))
2796                 flags.runmode = RUN_CRAWL;
2797             else {
2798                 config_error_add("Unknown %s parameter '%s'", fullname, op);
2799                 return FALSE;
2800             }
2801         } else
2802             return FALSE;
2803         return retval;
2804     }
2805
2806     /* menucolor:"regex_string"=color */
2807     fullname = "menucolor";
2808     if (match_optname(opts, fullname, 9, TRUE)) {
2809         if (negated) {
2810             bad_negation(fullname, FALSE);
2811             return FALSE;
2812         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
2813                                             != empty_optstr) {
2814             if (!add_menu_coloring(op))
2815                 return FALSE;
2816         } else
2817             return FALSE;
2818         return retval;
2819     }
2820
2821     fullname = "msghistory";
2822     if (match_optname(opts, fullname, 3, TRUE)) {
2823         if (duplicate)
2824             complain_about_duplicate(opts, 1);
2825         op = string_for_env_opt(fullname, opts, negated);
2826         if ((negated && op == empty_optstr)
2827             || (!negated && op != empty_optstr)) {
2828             iflags.msg_history = negated ? 0 : atoi(op);
2829         } else if (negated) {
2830             bad_negation(fullname, TRUE);
2831             return FALSE;
2832         }
2833         return retval;
2834     }
2835
2836     fullname = "msg_window";
2837     /* msg_window:single, combo, full or reversed */
2838     if (match_optname(opts, fullname, 4, TRUE)) {
2839 /* allow option to be silently ignored by non-tty ports */
2840 #ifdef TTY_GRAPHICS
2841         int tmp;
2842
2843         if (duplicate)
2844             complain_about_duplicate(opts, 1);
2845         if ((op = string_for_opt(opts, TRUE)) == empty_optstr) {
2846             tmp = negated ? 's' : 'f';
2847         } else {
2848             if (negated) {
2849                 bad_negation(fullname, TRUE);
2850                 return FALSE;
2851             }
2852             tmp = lowc(*op);
2853         }
2854         switch (tmp) {
2855         case 's': /* single message history cycle (default if negated) */
2856             iflags.prevmsg_window = 's';
2857             break;
2858         case 'c': /* combination: two singles, then full page */
2859             iflags.prevmsg_window = 'c';
2860             break;
2861         case 'f': /* full page (default if specified without argument) */
2862             iflags.prevmsg_window = 'f';
2863             break;
2864         case 'r': /* full page (reversed) */
2865             iflags.prevmsg_window = 'r';
2866             break;
2867         default:
2868             config_error_add("Unknown %s parameter '%s'", fullname, op);
2869             retval = FALSE;
2870         }
2871 #endif
2872         return retval;
2873     }
2874
2875     /* WINCAP
2876      * setting font options  */
2877     fullname = "font";
2878     if (!strncmpi(opts, fullname, 4)) {
2879         int opttype = -1;
2880         char *fontopts = opts + 4;
2881
2882         if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4))
2883             opttype = MAP_OPTION;
2884         else if (!strncmpi(fontopts, "message", 7)
2885                  || !strncmpi(fontopts, "_message", 8))
2886             opttype = MESSAGE_OPTION;
2887         else if (!strncmpi(fontopts, "text", 4)
2888                  || !strncmpi(fontopts, "_text", 5))
2889             opttype = TEXT_OPTION;
2890         else if (!strncmpi(fontopts, "menu", 4)
2891                  || !strncmpi(fontopts, "_menu", 5))
2892             opttype = MENU_OPTION;
2893         else if (!strncmpi(fontopts, "status", 6)
2894                  || !strncmpi(fontopts, "_status", 7))
2895             opttype = STATUS_OPTION;
2896         else if (!strncmpi(fontopts, "_size", 5)) {
2897             if (!strncmpi(fontopts, "_size_map", 8))
2898                 opttype = MAP_OPTION;
2899             else if (!strncmpi(fontopts, "_size_message", 12))
2900                 opttype = MESSAGE_OPTION;
2901             else if (!strncmpi(fontopts, "_size_text", 9))
2902                 opttype = TEXT_OPTION;
2903             else if (!strncmpi(fontopts, "_size_menu", 9))
2904                 opttype = MENU_OPTION;
2905             else if (!strncmpi(fontopts, "_size_status", 11))
2906                 opttype = STATUS_OPTION;
2907             else {
2908                 config_error_add("Unknown %s parameter '%s'", fullname, opts);
2909                 return FALSE;
2910             }
2911             if (duplicate)
2912                 complain_about_duplicate(opts, 1);
2913             if (opttype > 0 && !negated
2914                 && (op = string_for_opt(opts, FALSE)) != empty_optstr) {
2915                 switch (opttype) {
2916                 case MAP_OPTION:
2917                     iflags.wc_fontsiz_map = atoi(op);
2918                     break;
2919                 case MESSAGE_OPTION:
2920                     iflags.wc_fontsiz_message = atoi(op);
2921                     break;
2922                 case TEXT_OPTION:
2923                     iflags.wc_fontsiz_text = atoi(op);
2924                     break;
2925                 case MENU_OPTION:
2926                     iflags.wc_fontsiz_menu = atoi(op);
2927                     break;
2928                 case STATUS_OPTION:
2929                     iflags.wc_fontsiz_status = atoi(op);
2930                     break;
2931                 }
2932             }
2933             return retval;
2934         } else {
2935             config_error_add("Unknown %s parameter '%s'", fullname, opts);
2936             return FALSE;
2937         }
2938         if (opttype > 0
2939             && (op = string_for_opt(opts, FALSE)) != empty_optstr) {
2940             wc_set_font_name(opttype, op);
2941 #ifdef MAC
2942             set_font_name(opttype, op);
2943 #endif
2944             return retval;
2945         } else if (negated) {
2946             bad_negation(fullname, TRUE);
2947             return FALSE;
2948         }
2949         return retval;
2950     }
2951
2952 #ifdef CHANGE_COLOR
2953     if (match_optname(opts, "palette", 3, TRUE)
2954 #ifdef MAC
2955         || match_optname(opts, "hicolor", 3, TRUE)
2956 #endif
2957         ) {
2958         int color_number, color_incr;
2959
2960 #ifndef WIN32
2961         if (duplicate)
2962             complain_about_duplicate(opts, 1);
2963 #endif
2964 #ifdef MAC
2965         if (match_optname(opts, "hicolor", 3, TRUE)) {
2966             if (negated) {
2967                 bad_negation("hicolor", FALSE);
2968                 return FALSE;
2969             }
2970             color_number = CLR_MAX + 4; /* HARDCODED inverse number */
2971             color_incr = -1;
2972         } else
2973 #endif
2974         {
2975             if (negated) {
2976                 bad_negation("palette", FALSE);
2977                 return FALSE;
2978             }
2979             color_number = 0;
2980             color_incr = 1;
2981         }
2982 #ifdef WIN32
2983         op = string_for_opt(opts, TRUE);
2984         if (op == empty_optstr || !alternative_palette(op)) {
2985             config_error_add("Error in palette parameter '%s'", op);
2986             return FALSE;
2987         }
2988 #else
2989         if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
2990             char *pt = op;
2991             int cnt, tmp, reverse;
2992             long rgb;
2993
2994             while (*pt && color_number >= 0) {
2995                 cnt = 3;
2996                 rgb = 0L;
2997                 if (*pt == '-') {
2998                     reverse = 1;
2999                     pt++;
3000                 } else {
3001                     reverse = 0;
3002                 }
3003                 while (cnt-- > 0) {
3004                     if (*pt && *pt != '/') {
3005 #ifdef AMIGA
3006                         rgb <<= 4;
3007 #else
3008                         rgb <<= 8;
3009 #endif
3010                         tmp = *pt++;
3011                         if (isalpha((uchar) tmp)) {
3012                             tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
3013                         } else {
3014                             tmp &= 0xf; /* Digits in ASCII too... */
3015                         }
3016 #ifndef AMIGA
3017                         /* Add an extra so we fill f -> ff and 0 -> 00 */
3018                         rgb += tmp << 4;
3019 #endif
3020                         rgb += tmp;
3021                     }
3022                 }
3023                 if (*pt == '/')
3024                     pt++;
3025                 change_color(color_number, rgb, reverse);
3026                 color_number += color_incr;
3027             }
3028         }
3029 #endif /* !WIN32 */
3030         if (!initial) {
3031             need_redraw = TRUE;
3032         }
3033         return retval;
3034     }
3035 #endif /* CHANGE_COLOR */
3036
3037     if (match_optname(opts, "fruit", 2, TRUE)) {
3038         struct fruit *forig = 0;
3039
3040         if (duplicate)
3041             complain_about_duplicate(opts, 1);
3042         op = string_for_opt(opts, negated || !initial);
3043         if (negated) {
3044             if (op != empty_optstr) {
3045                 bad_negation("fruit", TRUE);
3046                 return FALSE;
3047             }
3048             op = empty_optstr;
3049             goto goodfruit;
3050         }
3051         if (op == empty_optstr)
3052             return FALSE;
3053         /* strip leading/trailing spaces, condense internal ones (3.6.2) */
3054         mungspaces(op);
3055         if (!initial) {
3056             struct fruit *f;
3057             int fnum = 0;
3058
3059             /* count number of named fruits; if 'op' is found among them,
3060                then the count doesn't matter because we won't be adding it */
3061             f = fruit_from_name(op, FALSE, &fnum);
3062             if (!f) {
3063                 if (!flags.made_fruit)
3064                     forig = fruit_from_name(pl_fruit, FALSE, (int *) 0);
3065
3066                 if (!forig && fnum >= 100) {
3067 #if 0 /*JP:T*/
3068                     config_error_add(
3069                              "Doing that so many times isn't very fruitful.");
3070 #else
3071                     config_error_add(
3072                              "\82»\82ñ\82È\82É\89½\89ñ\82à\82â\82Á\82Ä\82à\82Ù\82Æ\82ñ\82Ç\88Ó\96¡\82Í\82È\82¢\81D");
3073 #endif
3074                     return retval;
3075                 }
3076             }
3077         }
3078  goodfruit:
3079         nmcpy(pl_fruit, op, PL_FSIZ);
3080         sanitize_name(pl_fruit);
3081         /* OBJ_NAME(objects[SLIME_MOLD]) won't work for this after
3082            initialization; it gets changed to generic "fruit" */
3083         if (!*pl_fruit)
3084             nmcpy(pl_fruit, "slime mold", PL_FSIZ);
3085         if (!initial) {
3086             /* if 'forig' is nonNull, we replace it rather than add
3087                a new fruit; it can only be nonNull if no fruits have
3088                been created since the previous name was put in place */
3089             (void) fruitadd(pl_fruit, forig);
3090             pline("Fruit is now \"%s\".", pl_fruit);
3091         }
3092         /* If initial, then initoptions is allowed to do it instead
3093          * of here (initoptions always has to do it even if there's
3094          * no fruit option at all.  Also, we don't want people
3095          * setting multiple fruits in their options.)
3096          */
3097         return retval;
3098     }
3099
3100     fullname = "whatis_coord";
3101     if (match_optname(opts, fullname, 8, TRUE)) {
3102         if (duplicate)
3103             complain_about_duplicate(opts, 1);
3104         if (negated) {
3105             iflags.getpos_coords = GPCOORDS_NONE;
3106             return retval;
3107         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3108                                             != empty_optstr) {
3109             static char gpcoords[] = { GPCOORDS_NONE, GPCOORDS_COMPASS,
3110                                        GPCOORDS_COMFULL, GPCOORDS_MAP,
3111                                        GPCOORDS_SCREEN, '\0' };
3112             char c = lowc(*op);
3113
3114             if (c && index(gpcoords, c))
3115                 iflags.getpos_coords = c;
3116             else {
3117                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3118                 return FALSE;
3119             }
3120         } else
3121             return FALSE;
3122         return retval;
3123     }
3124
3125     fullname = "whatis_filter";
3126     if (match_optname(opts, fullname, 8, TRUE)) {
3127         if (duplicate)
3128             complain_about_duplicate(opts, 1);
3129         if (negated) {
3130             iflags.getloc_filter = GFILTER_NONE;
3131             return retval;
3132         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3133                                             != empty_optstr) {
3134             char c = lowc(*op);
3135
3136             switch (c) {
3137             case 'n':
3138                 iflags.getloc_filter = GFILTER_NONE;
3139                 break;
3140             case 'v':
3141                 iflags.getloc_filter = GFILTER_VIEW;
3142                 break;
3143             case 'a':
3144                 iflags.getloc_filter = GFILTER_AREA;
3145                 break;
3146             default: {
3147                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3148                 return FALSE;
3149             }
3150             }
3151         } else
3152             return FALSE;
3153         return retval;
3154     }
3155
3156     fullname = "warnings";
3157     if (match_optname(opts, fullname, 5, TRUE)) {
3158         if (duplicate)
3159             complain_about_duplicate(opts, 1);
3160         if (negated) {
3161             bad_negation(fullname, FALSE);
3162             return FALSE;
3163         }
3164         return warning_opts(opts, fullname);
3165     }
3166
3167     /* boulder:symbol */
3168     fullname = "boulder";
3169     if (match_optname(opts, fullname, 7, TRUE)) {
3170 #ifdef BACKWARD_COMPAT
3171         int clash = 0;
3172
3173         if (duplicate)
3174             complain_about_duplicate(opts, 1);
3175         if (negated) {
3176             bad_negation(fullname, FALSE);
3177             return FALSE;
3178         }
3179         /* if ((opts = string_for_env_opt(fullname, opts, FALSE))
3180                                           == empty_optstr)
3181          */
3182         if ((opts = string_for_opt(opts, FALSE)) == empty_optstr)
3183             return FALSE;
3184         escapes(opts, opts);
3185         /* note: dummy monclass #0 has symbol value '\0'; we allow that--
3186            attempting to set bouldersym to '^@'/'\0' will reset to default */
3187         if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
3188             clash = opts[0] ? 1 : 0;
3189         else if (opts[0] >= '1' && opts[0] < WARNCOUNT + '0')
3190             clash = 2;
3191         if (clash) {
3192             /* symbol chosen matches a used monster or warning
3193                symbol which is not good - reject it */
3194             config_error_add(
3195             "Badoption - boulder symbol '%s' would conflict with a %s symbol",
3196                              visctrl(opts[0]),
3197                              (clash == 1) ? "monster" : "warning");
3198         } else {
3199             /*
3200              * Override the default boulder symbol.
3201              */
3202             ov_primary_syms[SYM_BOULDER + SYM_OFF_X] = (nhsym) opts[0];
3203             ov_rogue_syms[SYM_BOULDER + SYM_OFF_X] = (nhsym) opts[0];
3204             /* for 'initial', update of BOULDER symbol is done in
3205                initoptions_finish(), after all symset options
3206                have been processed */
3207             if (!initial) {
3208                 nhsym sym = get_othersym(SYM_BOULDER,
3209                                 Is_rogue_level(&u.uz) ? ROGUESET : PRIMARY);
3210                 if (sym)
3211                     showsyms[SYM_BOULDER + SYM_OFF_X] = sym;
3212                 need_redraw = TRUE;
3213             }
3214         }
3215         return retval;
3216 #else
3217         config_error_add("'%s' no longer supported; use S_boulder:c instead",
3218                          fullname);
3219         return FALSE;
3220 #endif
3221     }
3222
3223     /* name:string */
3224     fullname = "name";
3225     if (match_optname(opts, fullname, 4, TRUE)) {
3226         if (duplicate)
3227             complain_about_duplicate(opts, 1);
3228         if (negated) {
3229             bad_negation(fullname, FALSE);
3230             return FALSE;
3231         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3232                                             != empty_optstr) {
3233             nmcpy(plname, op, PL_NSIZ);
3234         } else
3235             return FALSE;
3236         return retval;
3237     }
3238
3239     /* altkeyhandler:string */
3240     fullname = "altkeyhandler";
3241     if (match_optname(opts, fullname, 4, TRUE)) {
3242         if (duplicate)
3243             complain_about_duplicate(opts, 1);
3244         if (negated) {
3245             bad_negation(fullname, FALSE);
3246             return FALSE;
3247         } else if ((op = string_for_opt(opts, negated)) != empty_optstr) {
3248 #if defined(WIN32) && defined(TTY_GRAPHICS)
3249             set_altkeyhandling(op);
3250 #endif
3251         } else
3252             return FALSE;
3253         return retval;
3254     }
3255
3256     /* WINCAP
3257      * align_status:[left|top|right|bottom] */
3258     fullname = "align_status";
3259     if (match_optname(opts, fullname, sizeof "align_status" - 1, TRUE)) {
3260         op = string_for_opt(opts, negated);
3261         if ((op != empty_optstr) && !negated) {
3262             if (!strncmpi(op, "left", sizeof "left" - 1))
3263                 iflags.wc_align_status = ALIGN_LEFT;
3264             else if (!strncmpi(op, "top", sizeof "top" - 1))
3265                 iflags.wc_align_status = ALIGN_TOP;
3266             else if (!strncmpi(op, "right", sizeof "right" - 1))
3267                 iflags.wc_align_status = ALIGN_RIGHT;
3268             else if (!strncmpi(op, "bottom", sizeof "bottom" - 1))
3269                 iflags.wc_align_status = ALIGN_BOTTOM;
3270             else {
3271                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3272                 return FALSE;
3273             }
3274         } else if (negated) {
3275             bad_negation(fullname, TRUE);
3276             return FALSE;
3277         }
3278         return retval;
3279     }
3280
3281     /* WINCAP
3282      * align_message:[left|top|right|bottom] */
3283     fullname = "align_message";
3284     if (match_optname(opts, fullname, sizeof "align_message" - 1, TRUE)) {
3285         if (duplicate)
3286             complain_about_duplicate(opts, 1);
3287         op = string_for_opt(opts, negated);
3288         if ((op != empty_optstr) && !negated) {
3289             if (!strncmpi(op, "left", sizeof "left" - 1))
3290                 iflags.wc_align_message = ALIGN_LEFT;
3291             else if (!strncmpi(op, "top", sizeof "top" - 1))
3292                 iflags.wc_align_message = ALIGN_TOP;
3293             else if (!strncmpi(op, "right", sizeof "right" - 1))
3294                 iflags.wc_align_message = ALIGN_RIGHT;
3295             else if (!strncmpi(op, "bottom", sizeof "bottom" - 1))
3296                 iflags.wc_align_message = ALIGN_BOTTOM;
3297             else {
3298                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3299                 return FALSE;
3300             }
3301         } else if (negated) {
3302             bad_negation(fullname, TRUE);
3303             return FALSE;
3304         }
3305         return retval;
3306     }
3307
3308     /* the order to list inventory */
3309     fullname = "packorder";
3310     if (match_optname(opts, fullname, 4, TRUE)) {
3311         if (duplicate)
3312             complain_about_duplicate(opts, 1);
3313         if (negated) {
3314             bad_negation(fullname, FALSE);
3315             return FALSE;
3316         } else if ((op = string_for_opt(opts, FALSE)) == empty_optstr)
3317             return FALSE;
3318
3319         if (!change_inv_order(op))
3320             return FALSE;
3321         return retval;
3322     }
3323
3324     /* user can change required response for some prompts (quit, die, hit),
3325        or add an extra prompt (pray, Remove) that isn't ordinarily there */
3326     fullname = "paranoid_confirmation";
3327     if (match_optname(opts, fullname, 8, TRUE)) {
3328         /* at present we don't complain about duplicates for this
3329            option, but we do throw away the old settings whenever
3330            we process a new one [clearing old flags is essential
3331            for handling default paranoid_confirm:pray sanely] */
3332         flags.paranoia_bits = 0; /* clear all */
3333         if (negated) {
3334             flags.paranoia_bits = 0; /* [now redundant...] */
3335         } else if ((op = string_for_opt(opts, TRUE)) != empty_optstr) {
3336             char *pp, buf[BUFSZ];
3337
3338             strncpy(buf, op, sizeof buf - 1);
3339             buf[sizeof buf - 1] = '\0';
3340             op = mungspaces(buf);
3341             for (;;) {
3342                 /* We're looking to parse
3343                    "paranoid_confirm:whichone wheretwo whothree"
3344                    and "paranoid_confirm:" prefix has already
3345                    been stripped off by the time we get here */
3346                 pp = index(op, ' ');
3347                 if (pp)
3348                     *pp = '\0';
3349                 /* we aren't matching option names but match_optname()
3350                    does what we want once we've broken the space
3351                    delimited aggregate into separate tokens */
3352                 for (i = 0; i < SIZE(paranoia); ++i) {
3353                     if (match_optname(op, paranoia[i].argname,
3354                                       paranoia[i].argMinLen, FALSE)
3355                         || (paranoia[i].synonym
3356                             && match_optname(op, paranoia[i].synonym,
3357                                              paranoia[i].synMinLen, FALSE))) {
3358                         if (paranoia[i].flagmask)
3359                             flags.paranoia_bits |= paranoia[i].flagmask;
3360                         else /* 0 == "none", so clear all */
3361                             flags.paranoia_bits = 0;
3362                         break;
3363                     }
3364                 }
3365                 if (i == SIZE(paranoia)) {
3366                     /* didn't match anything, so arg is bad;
3367                        any flags already set will stay set */
3368                     config_error_add("Unknown %s parameter '%s'",
3369                                      fullname, op);
3370                     return FALSE;
3371                 }
3372                 /* move on to next token */
3373                 if (pp)
3374                     op = pp + 1;
3375                 else
3376                     break; /* no next token */
3377             } /* for(;;) */
3378         } else
3379             return FALSE;
3380         return retval;
3381     }
3382
3383     /* accept deprecated boolean; superseded by paranoid_confirm:pray */
3384     fullname = "prayconfirm";
3385     if (match_optname(opts, fullname, 4, FALSE)) {
3386         if (negated)
3387             flags.paranoia_bits &= ~PARANOID_PRAY;
3388         else
3389             flags.paranoia_bits |= PARANOID_PRAY;
3390         return retval;
3391     }
3392
3393     /* maximum burden picked up before prompt (Warren Cheung) */
3394     fullname = "pickup_burden";
3395     if (match_optname(opts, fullname, 8, TRUE)) {
3396         if (duplicate)
3397             complain_about_duplicate(opts, 1);
3398         if (negated) {
3399             bad_negation(fullname, FALSE);
3400             return FALSE;
3401         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
3402                                             != empty_optstr) {
3403             switch (lowc(*op)) {
3404             case 'u': /* Unencumbered */
3405                 flags.pickup_burden = UNENCUMBERED;
3406                 break;
3407             case 'b': /* Burdened (slight encumbrance) */
3408                 flags.pickup_burden = SLT_ENCUMBER;
3409                 break;
3410             case 's': /* streSsed (moderate encumbrance) */
3411                 flags.pickup_burden = MOD_ENCUMBER;
3412                 break;
3413             case 'n': /* straiNed (heavy encumbrance) */
3414                 flags.pickup_burden = HVY_ENCUMBER;
3415                 break;
3416             case 'o': /* OverTaxed (extreme encumbrance) */
3417             case 't':
3418                 flags.pickup_burden = EXT_ENCUMBER;
3419                 break;
3420             case 'l': /* overLoaded */
3421                 flags.pickup_burden = OVERLOADED;
3422                 break;
3423             default:
3424                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3425                 return FALSE;
3426             }
3427         } else
3428             return FALSE;
3429         return retval;
3430     }
3431
3432     /* types of objects to pick up automatically */
3433     fullname = "pickup_types";
3434     if (match_optname(opts, fullname, 8, TRUE)) {
3435         char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
3436              qbuf[QBUFSZ], abuf[BUFSZ];
3437         int oc_sym;
3438         boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
3439
3440         if (duplicate)
3441             complain_about_duplicate(opts, 1);
3442         oc_to_str(flags.pickup_types, tbuf);
3443         flags.pickup_types[0] = '\0'; /* all */
3444         op = string_for_opt(opts, (compat || !initial));
3445         if (op == empty_optstr) {
3446             if (compat || negated || initial) {
3447                 /* for backwards compatibility, "pickup" without a
3448                    value is a synonym for autopickup of all types
3449                    (and during initialization, we can't prompt yet) */
3450                 flags.pickup = !negated;
3451                 return retval;
3452             }
3453             oc_to_str(flags.inv_order, ocl);
3454             use_menu = TRUE;
3455             if (flags.menu_style == MENU_TRADITIONAL
3456                 || flags.menu_style == MENU_COMBINATION) {
3457                 boolean wasspace;
3458
3459                 use_menu = FALSE;
3460 #if 0 /*JP:T*/
3461                 Sprintf(qbuf, "New %s: [%s am] (%s)", fullname, ocl,
3462                         *tbuf ? tbuf : "all");
3463 #else
3464                 Sprintf(qbuf, "\90V\82µ\82¢%s: [%s am] (%s)", fullname, ocl,
3465                         *tbuf ? tbuf : "all");
3466 #endif
3467                 abuf[0] = '\0';
3468                 getlin(qbuf, abuf);
3469                 wasspace = (abuf[0] == ' '); /* before mungspaces */
3470                 op = mungspaces(abuf);
3471                 if (wasspace && !abuf[0])
3472                     ; /* one or more spaces will remove old value */
3473                 else if (!abuf[0] || abuf[0] == '\033')
3474                     op = tbuf; /* restore */
3475                 else if (abuf[0] == 'm')
3476                     use_menu = TRUE;
3477                 /* note: abuf[0]=='a' is already handled via clearing the
3478                    the old value (above) as a default action */
3479             }
3480             if (use_menu) {
3481                 if (wizard && !index(ocl, VENOM_SYM))
3482                     strkitten(ocl, VENOM_SYM);
3483 #if 0 /*JP:T*/
3484                 (void) choose_classes_menu("Autopickup what?", 1, TRUE, ocl,
3485                                            tbuf);
3486 #else
3487                 (void) choose_classes_menu("\82Ç\82ê\82ð\8e©\93®\8fE\82¢\82É\90Ý\92è\82·\82é\81H", 1, TRUE, ocl,
3488                                            tbuf);
3489 #endif
3490                 op = tbuf;
3491             }
3492         }
3493         if (negated) {
3494             bad_negation(fullname, TRUE);
3495             return FALSE;
3496         }
3497         while (*op == ' ')
3498             op++;
3499         if (*op != 'a' && *op != 'A') {
3500             num = 0;
3501             while (*op) {
3502                 oc_sym = def_char_to_objclass(*op);
3503                 /* make sure all are valid obj symbols occurring once */
3504                 if (oc_sym != MAXOCLASSES
3505                     && !index(flags.pickup_types, oc_sym)) {
3506                     flags.pickup_types[num] = (char) oc_sym;
3507                     flags.pickup_types[++num] = '\0';
3508                 } else
3509                     badopt = TRUE;
3510                 op++;
3511             }
3512             if (badopt) {
3513                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3514                 return FALSE;
3515             }
3516         }
3517         return retval;
3518     }
3519
3520     /* pile limit: when walking over objects, number which triggers
3521        "there are several/many objects here" instead of listing them */
3522     fullname = "pile_limit";
3523     if (match_optname(opts, fullname, 4, TRUE)) {
3524         if (duplicate)
3525             complain_about_duplicate(opts, 1);
3526         op = string_for_opt(opts, negated);
3527         if ((negated && op == empty_optstr)
3528             || (!negated && op != empty_optstr))
3529             flags.pile_limit = negated ? 0 : atoi(op);
3530         else if (negated) {
3531             bad_negation(fullname, TRUE);
3532             return FALSE;
3533         } else /* op == empty_optstr */
3534             flags.pile_limit = PILE_LIMIT_DFLT;
3535         /* sanity check */
3536         if (flags.pile_limit < 0)
3537             flags.pile_limit = PILE_LIMIT_DFLT;
3538         return retval;
3539     }
3540
3541     /* play mode: normal, explore/discovery, or debug/wizard */
3542     fullname = "playmode";
3543     if (match_optname(opts, fullname, 4, TRUE)) {
3544         if (duplicate)
3545             complain_about_duplicate(opts, 1);
3546         if (negated)
3547             bad_negation(fullname, FALSE);
3548         if (duplicate || negated)
3549             return FALSE;
3550         op = string_for_opt(opts, FALSE);
3551         if (op == empty_optstr)
3552             return FALSE;
3553         if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) {
3554             wizard = discover = FALSE;
3555         } else if (!strncmpi(op, "explore", 6)
3556                    || !strncmpi(op, "discovery", 6)) {
3557             wizard = FALSE, discover = TRUE;
3558         } else if (!strncmpi(op, "debug", 5) || !strncmpi(op, "wizard", 6)) {
3559             wizard = TRUE, discover = FALSE;
3560         } else {
3561             config_error_add("Invalid value for \"%s\":%s", fullname, op);
3562             return FALSE;
3563         }
3564         return retval;
3565     }
3566
3567     /* WINCAP
3568      * player_selection: dialog | prompt/prompts/prompting */
3569     fullname = "player_selection";
3570     if (match_optname(opts, fullname, sizeof "player_selection" - 1, TRUE)) {
3571         if (duplicate)
3572             complain_about_duplicate(opts, 1);
3573         op = string_for_opt(opts, negated);
3574         if (op != empty_optstr && !negated) {
3575             if (!strncmpi(op, "dialog", sizeof "dialog" - 1)) {
3576                 iflags.wc_player_selection = VIA_DIALOG;
3577             } else if (!strncmpi(op, "prompt", sizeof "prompt" - 1)) {
3578                 iflags.wc_player_selection = VIA_PROMPTS;
3579             } else {
3580                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3581                 return FALSE;
3582             }
3583         } else if (negated) {
3584             bad_negation(fullname, TRUE);
3585             return FALSE;
3586         }
3587         return retval;
3588     }
3589
3590     /* things to disclose at end of game */
3591     fullname = "disclose";
3592     if (match_optname(opts, fullname, 7, TRUE)) {
3593         /*
3594          * The order that the end_disclose options are stored:
3595          *      inventory, attribs, vanquished, genocided,
3596          *      conduct, overview.
3597          * There is an array in flags:
3598          *      end_disclose[NUM_DISCLOSURE_OPT];
3599          * with option settings for the each of the following:
3600          * iagvc [see disclosure_options in decl.c]:
3601          * Allowed setting values in that array are:
3602          *      DISCLOSE_PROMPT_DEFAULT_YES  ask with default answer yes
3603          *      DISCLOSE_PROMPT_DEFAULT_NO   ask with default answer no
3604          *      DISCLOSE_YES_WITHOUT_PROMPT  always disclose and don't ask
3605          *      DISCLOSE_NO_WITHOUT_PROMPT   never disclose and don't ask
3606          *      DISCLOSE_PROMPT_DEFAULT_SPECIAL  for 'vanquished' only...
3607          *      DISCLOSE_SPECIAL_WITHOUT_PROMPT  ...to set up sort order.
3608          *
3609          * Those setting values can be used in the option
3610          * string as a prefix to get the desired behaviour.
3611          *
3612          * For backward compatibility, no prefix is required,
3613          * and the presence of a i,a,g,v, or c without a prefix
3614          * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
3615          */
3616         int idx, prefix_val;
3617
3618         if (duplicate)
3619             complain_about_duplicate(opts, 1);
3620         op = string_for_opt(opts, TRUE);
3621         if (op != empty_optstr && negated) {
3622             bad_negation(fullname, TRUE);
3623             return FALSE;
3624         }
3625         /* "disclose" without a value means "all with prompting"
3626            and negated means "none without prompting" */
3627         if (op == empty_optstr
3628             || !strcmpi(op, "all") || !strcmpi(op, "none")) {
3629             if (op != empty_optstr && !strcmpi(op, "none"))
3630                 negated = TRUE;
3631             for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
3632                 flags.end_disclose[num] = negated
3633                                               ? DISCLOSE_NO_WITHOUT_PROMPT
3634                                               : DISCLOSE_PROMPT_DEFAULT_YES;
3635             return retval;
3636         }
3637
3638         num = 0;
3639         prefix_val = -1;
3640         while (*op && num < sizeof flags.end_disclose - 1) {
3641             static char valid_settings[] = {
3642                 DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO,
3643                 DISCLOSE_PROMPT_DEFAULT_SPECIAL,
3644                 DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT,
3645                 DISCLOSE_SPECIAL_WITHOUT_PROMPT, '\0'
3646             };
3647             register char c, *dop;
3648
3649             c = lowc(*op);
3650             if (c == 'k')
3651                 c = 'v'; /* killed -> vanquished */
3652             if (c == 'd')
3653                 c = 'o'; /* dungeon -> overview */
3654             dop = index(disclosure_options, c);
3655             if (dop) {
3656                 idx = (int) (dop - disclosure_options);
3657                 if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
3658                     impossible("bad disclosure index %d %c", idx, c);
3659                     continue;
3660                 }
3661                 if (prefix_val != -1) {
3662                     if (*dop != 'v') {
3663                         if (prefix_val == DISCLOSE_PROMPT_DEFAULT_SPECIAL)
3664                             prefix_val = DISCLOSE_PROMPT_DEFAULT_YES;
3665                         if (prefix_val == DISCLOSE_SPECIAL_WITHOUT_PROMPT)
3666                             prefix_val = DISCLOSE_YES_WITHOUT_PROMPT;
3667                     }
3668                     flags.end_disclose[idx] = prefix_val;
3669                     prefix_val = -1;
3670                 } else
3671                     flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
3672             } else if (index(valid_settings, c)) {
3673                 prefix_val = c;
3674             } else if (c == ' ') {
3675                 ; /* do nothing */
3676             } else {
3677                 config_error_add("Unknown %s parameter '%c'", fullname, *op);
3678                 return FALSE;
3679             }
3680             op++;
3681         }
3682         return retval;
3683     }
3684 #if 1 /*JP*/
3685     if (!strncmpi(opts, "kcode", 3)){
3686         if ((op = string_for_env_opt("kcode", opts, FALSE)) != 0){
3687             setkcode(*op);
3688         }
3689         return retval;
3690     }
3691 #endif
3692
3693     /* scores:5t[op] 5a[round] o[wn] */
3694     fullname = "scores";
3695     if (match_optname(opts, fullname, 4, TRUE)) {
3696         if (duplicate)
3697             complain_about_duplicate(opts, 1);
3698         if (negated) {
3699             bad_negation(fullname, FALSE);
3700             return FALSE;
3701         }
3702         if ((op = string_for_opt(opts, FALSE)) == empty_optstr)
3703             return FALSE;
3704
3705         while (*op) {
3706             int inum = 1;
3707
3708             if (digit(*op)) {
3709                 inum = atoi(op);
3710                 while (digit(*op))
3711                     op++;
3712             } else if (*op == '!') {
3713                 negated = !negated;
3714                 op++;
3715             }
3716             while (*op == ' ')
3717                 op++;
3718
3719             switch (*op) {
3720             case 't':
3721             case 'T':
3722                 flags.end_top = inum;
3723                 break;
3724             case 'a':
3725             case 'A':
3726                 flags.end_around = inum;
3727                 break;
3728             case 'o':
3729             case 'O':
3730                 flags.end_own = !negated;
3731                 break;
3732             default:
3733                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3734                 return FALSE;
3735             }
3736             /* "3a" is sufficient but accept "3around" (or "3abracadabra") */
3737             while (letter(*op))
3738                 op++;
3739             /* t, a, and o can be separated by space(s) or slash or both */
3740             while (*op == ' ')
3741                 op++;
3742             if (*op == '/')
3743                 op++;
3744         }
3745         return retval;
3746     }
3747
3748     fullname = "sortloot";
3749     if (match_optname(opts, fullname, 4, TRUE)) {
3750         op = string_for_env_opt(fullname, opts, FALSE);
3751         if (op != empty_optstr) {
3752             char c = lowc(*op);
3753
3754             switch (c) {
3755             case 'n': /* none */
3756             case 'l': /* loot (pickup) */
3757             case 'f': /* full (pickup + invent) */
3758                 flags.sortloot = c;
3759                 break;
3760             default:
3761                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3762                 return FALSE;
3763             }
3764         } else
3765             return FALSE;
3766         return retval;
3767     }
3768
3769     fullname = "suppress_alert";
3770     if (match_optname(opts, fullname, 4, TRUE)) {
3771         if (duplicate)
3772             complain_about_duplicate(opts, 1);
3773         op = string_for_opt(opts, negated);
3774         if (negated) {
3775             bad_negation(fullname, FALSE);
3776             return FALSE;
3777         } else if (op != empty_optstr)
3778             (void) feature_alert_opts(op, fullname);
3779         return retval;
3780     }
3781
3782 #ifdef VIDEOSHADES
3783     /* videocolors:string */
3784     fullname = "videocolors";
3785     if (match_optname(opts, fullname, 6, TRUE)
3786         || match_optname(opts, "videocolours", 10, TRUE)) {
3787         if (duplicate)
3788             complain_about_duplicate(opts, 1);
3789         if (negated) {
3790             bad_negation(fullname, FALSE);
3791             return FALSE;
3792         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3793                                               == empty_optstr) {
3794             return FALSE;
3795         }
3796         if (!assign_videocolors(opts)) {
3797             config_error_add("Unknown error handling '%s'", fullname);
3798             return FALSE;
3799         }
3800         return retval;
3801     }
3802     /* videoshades:string */
3803     fullname = "videoshades";
3804     if (match_optname(opts, fullname, 6, TRUE)) {
3805         if (duplicate)
3806             complain_about_duplicate(opts, 1);
3807         if (negated) {
3808             bad_negation(fullname, FALSE);
3809             return FALSE;
3810         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3811                                               == empty_optstr) {
3812             return FALSE;
3813         }
3814         if (!assign_videoshades(opts)) {
3815             config_error_add("Unknown error handling '%s'", fullname);
3816             return FALSE;
3817         }
3818         return retval;
3819     }
3820 #endif /* VIDEOSHADES */
3821
3822 #ifdef MSDOS
3823 #ifdef NO_TERMS
3824     /* video:string -- must be after longer tests */
3825     fullname = "video";
3826     if (match_optname(opts, fullname, 5, TRUE)) {
3827         if (duplicate)
3828             complain_about_duplicate(opts, 1);
3829         if (negated) {
3830             bad_negation(fullname, FALSE);
3831             return FALSE;
3832         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3833                                               == empty_optstr) {
3834             return FALSE;
3835         }
3836         if (!assign_video(opts)) {
3837             config_error_add("Unknown error handling '%s'", fullname);
3838             return FALSE;
3839         }
3840         return retval;
3841     }
3842 #endif /* NO_TERMS */
3843     /* soundcard:string -- careful not to match boolean 'sound' */
3844     fullname = "soundcard";
3845     if (match_optname(opts, fullname, 6, TRUE)) {
3846         if (duplicate)
3847             complain_about_duplicate(opts, 1);
3848         if (negated) {
3849             bad_negation(fullname, FALSE);
3850             return FALSE;
3851         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
3852                                               == empty_optstr) {
3853             return FALSE;
3854         }
3855         if (!assign_soundcard(opts)) {
3856             config_error_add("Unknown error handling '%s'", fullname);
3857             return FALSE;
3858         }
3859         return retval;
3860     }
3861 #endif /* MSDOS */
3862
3863     /* WINCAP
3864      *
3865      *  map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12
3866      *            |ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen
3867      *            |ascii_fit_to_screen|tiles_fit_to_screen]
3868      */
3869     fullname = "map_mode";
3870     if (match_optname(opts, fullname, sizeof "map_mode" - 1, TRUE)) {
3871         if (duplicate)
3872             complain_about_duplicate(opts, 1);
3873         op = string_for_opt(opts, negated);
3874         if (op != empty_optstr && !negated) {
3875             if (!strcmpi(op, "tiles"))
3876                 iflags.wc_map_mode = MAP_MODE_TILES;
3877             else if (!strncmpi(op, "ascii4x6", sizeof "ascii4x6" - 1))
3878                 iflags.wc_map_mode = MAP_MODE_ASCII4x6;
3879             else if (!strncmpi(op, "ascii6x8", sizeof "ascii6x8" - 1))
3880                 iflags.wc_map_mode = MAP_MODE_ASCII6x8;
3881             else if (!strncmpi(op, "ascii8x8", sizeof "ascii8x8" - 1))
3882                 iflags.wc_map_mode = MAP_MODE_ASCII8x8;
3883             else if (!strncmpi(op, "ascii16x8", sizeof "ascii16x8" - 1))
3884                 iflags.wc_map_mode = MAP_MODE_ASCII16x8;
3885             else if (!strncmpi(op, "ascii7x12", sizeof "ascii7x12" - 1))
3886                 iflags.wc_map_mode = MAP_MODE_ASCII7x12;
3887             else if (!strncmpi(op, "ascii8x12", sizeof "ascii8x12" - 1))
3888                 iflags.wc_map_mode = MAP_MODE_ASCII8x12;
3889             else if (!strncmpi(op, "ascii16x12", sizeof "ascii16x12" - 1))
3890                 iflags.wc_map_mode = MAP_MODE_ASCII16x12;
3891             else if (!strncmpi(op, "ascii12x16", sizeof "ascii12x16" - 1))
3892                 iflags.wc_map_mode = MAP_MODE_ASCII12x16;
3893             else if (!strncmpi(op, "ascii10x18", sizeof "ascii10x18" - 1))
3894                 iflags.wc_map_mode = MAP_MODE_ASCII10x18;
3895             else if (!strncmpi(op, "fit_to_screen",
3896                                sizeof "fit_to_screen" - 1))
3897                 iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
3898             else if (!strncmpi(op, "ascii_fit_to_screen",
3899                                sizeof "ascii_fit_to_screen" - 1))
3900                 iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
3901             else if (!strncmpi(op, "tiles_fit_to_screen",
3902                                sizeof "tiles_fit_to_screen" - 1))
3903                 iflags.wc_map_mode = MAP_MODE_TILES_FIT_TO_SCREEN;
3904             else {
3905                 config_error_add("Unknown %s parameter '%s'", fullname, op);
3906                 return FALSE;
3907             }
3908         } else if (negated) {
3909             bad_negation(fullname, TRUE);
3910             return FALSE;
3911         }
3912         return retval;
3913     }
3914
3915     /* WINCAP
3916      * scroll_amount:nn */
3917     fullname = "scroll_amount";
3918     if (match_optname(opts, fullname, sizeof "scroll_amount" - 1, TRUE)) {
3919         if (duplicate)
3920             complain_about_duplicate(opts, 1);
3921         op = string_for_opt(opts, negated);
3922         if ((negated && op == empty_optstr)
3923             || (!negated && op != empty_optstr)) {
3924             iflags.wc_scroll_amount = negated ? 1 : atoi(op);
3925         } else if (negated) {
3926             bad_negation(fullname, TRUE);
3927             return FALSE;
3928         }
3929         return retval;
3930     }
3931
3932     /* WINCAP
3933      * scroll_margin:nn */
3934     fullname = "scroll_margin";
3935     if (match_optname(opts, fullname, sizeof "scroll_margin" - 1, TRUE)) {
3936         if (duplicate)
3937             complain_about_duplicate(opts, 1);
3938         op = string_for_opt(opts, negated);
3939         if ((negated && op == empty_optstr)
3940             || (!negated && op != empty_optstr)) {
3941             iflags.wc_scroll_margin = negated ? 5 : atoi(op);
3942         } else if (negated) {
3943             bad_negation(fullname, TRUE);
3944             return FALSE;
3945         }
3946         return retval;
3947     }
3948
3949     fullname = "subkeyvalue";
3950     if (match_optname(opts, fullname, 5, TRUE)) {
3951         /* no duplicate complaint here */
3952         if (negated) {
3953             bad_negation(fullname, FALSE);
3954             return FALSE;
3955 #if defined(WIN32)
3956         } else {
3957             op = string_for_opt(opts, 0);
3958             if (op == empty_optstr)
3959                 return FALSE;
3960 #ifdef TTY_GRAPHICS
3961             map_subkeyvalue(op);
3962 #endif
3963 #endif
3964         }
3965         return retval;
3966     }
3967
3968     /* WINCAP
3969      * tile_width:nn */
3970     fullname = "tile_width";
3971     if (match_optname(opts, fullname, sizeof "tile_width" - 1, TRUE)) {
3972         if (duplicate)
3973             complain_about_duplicate(opts, 1);
3974         op = string_for_opt(opts, negated);
3975         if ((negated && op == empty_optstr)
3976             || (!negated && op != empty_optstr)) {
3977             iflags.wc_tile_width = negated ? 0 : atoi(op);
3978         } else if (negated) {
3979             bad_negation(fullname, TRUE);
3980             return FALSE;
3981         }
3982         return retval;
3983     }
3984     /* WINCAP
3985      * tile_file:name */
3986     fullname = "tile_file";
3987     if (match_optname(opts, fullname, sizeof "tile_file" - 1, TRUE)) {
3988         if (duplicate)
3989             complain_about_duplicate(opts, 1);
3990         if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
3991             if (iflags.wc_tile_file)
3992                 free(iflags.wc_tile_file);
3993             iflags.wc_tile_file = dupstr(op);
3994         } else
3995             return FALSE;
3996         return retval;
3997     }
3998     /* WINCAP
3999      * tile_height:nn */
4000     fullname = "tile_height";
4001     if (match_optname(opts, fullname, sizeof "tile_height" - 1, TRUE)) {
4002         if (duplicate)
4003             complain_about_duplicate(opts, 1);
4004         op = string_for_opt(opts, negated);
4005         if ((negated && op == empty_optstr)
4006             || (!negated && op != empty_optstr)) {
4007             iflags.wc_tile_height = negated ? 0 : atoi(op);
4008         } else if (negated) {
4009             bad_negation(fullname, TRUE);
4010             return FALSE;
4011         }
4012         return retval;
4013     }
4014
4015     /* WINCAP
4016      * vary_msgcount:nn */
4017     fullname = "vary_msgcount";
4018     if (match_optname(opts, fullname, sizeof "vary_msgcount" - 1, TRUE)) {
4019         if (duplicate)
4020             complain_about_duplicate(opts, 1);
4021         op = string_for_opt(opts, negated);
4022         if ((negated && op == empty_optstr)
4023             || (!negated && op != empty_optstr)) {
4024             iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
4025         } else if (negated) {
4026             bad_negation(fullname, TRUE);
4027             return FALSE;
4028         }
4029         return retval;
4030     }
4031
4032     /*
4033      * windowtype:  option to choose the interface for binaries built
4034      * with support for more than one interface (tty + X11, for instance).
4035      *
4036      * Ideally, 'windowtype' should be processed first, because it
4037      * causes the wc_ and wc2_ flags to be set up.
4038      * For user, making it be first in a config file is trivial, use
4039      * OPTIONS=windowtype:Foo
4040      * as the first non-comment line of the file.
4041      * Making it first in NETHACKOPTIONS requires it to be at the _end_
4042      * because comma-separated option strings are processed from right
4043      * to left.
4044      */
4045     fullname = "windowtype";
4046     if (match_optname(opts, fullname, 3, TRUE)) {
4047         if (iflags.windowtype_locked)
4048             return retval;
4049         if (duplicate)
4050             complain_about_duplicate(opts, 1);
4051         if (negated) {
4052             bad_negation(fullname, FALSE);
4053             return FALSE;
4054         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
4055                                             != empty_optstr) {
4056             if (!iflags.windowtype_deferred) {
4057                 char buf[WINTYPELEN];
4058
4059                 nmcpy(buf, op, WINTYPELEN);
4060                 choose_windows(buf);
4061             } else {
4062                 nmcpy(chosen_windowtype, op, WINTYPELEN);
4063             }
4064         } else
4065             return FALSE;
4066         return retval;
4067     }
4068
4069 #ifdef WINCHAIN
4070     fullname = "windowchain";
4071     if (match_optname(opts, fullname, 3, TRUE)) {
4072         if (negated) {
4073             bad_negation(fullname, FALSE);
4074             return FALSE;
4075         } else if ((op = string_for_env_opt(fullname, opts, FALSE))
4076                                             != empty_optstr) {
4077             char buf[WINTYPELEN];
4078
4079             nmcpy(buf, op, WINTYPELEN);
4080             addto_windowchain(buf);
4081         } else
4082             return FALSE;
4083         return retval;
4084     }
4085 #endif
4086
4087     /* WINCAP
4088      * setting window colors
4089      * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
4090      */
4091     fullname = "windowcolors";
4092     if (match_optname(opts, fullname, 7, TRUE)) {
4093         if (duplicate)
4094             complain_about_duplicate(opts, 1);
4095         if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
4096             if (!wc_set_window_colors(op)) {
4097                 config_error_add("Could not set %s '%s'", fullname, op);
4098                 return FALSE;
4099             }
4100         } else if (negated) {
4101             bad_negation(fullname, TRUE);
4102             return FALSE;
4103         }
4104         return retval;
4105     }
4106
4107 #ifdef CURSES_GRAPHICS
4108     /* WINCAP2
4109      * term_cols:amount or term_rows:amount */
4110     fullname = "term_cols";
4111     if (match_optname(opts, fullname, 8, TRUE)
4112         /* alternate spelling */
4113         || match_optname(opts, "term_columns", 9, TRUE)
4114         /* different option but identical handlng */
4115         || (fullname = "term_rows", match_optname(opts, fullname, 8, TRUE))) {
4116         long ltmp;
4117
4118         if ((op = string_for_opt(opts, negated)) != empty_optstr) {
4119             ltmp = atol(op);
4120             if (negated) {
4121                 bad_negation(fullname, FALSE);
4122                 retval = FALSE;
4123
4124             /* just checks atol() sanity, not logical window size sanity */
4125             } else if (ltmp <= 0L || ltmp >= (long) LARGEST_INT) {
4126                 config_error_add("Invalid %s: %ld", fullname, ltmp);
4127                 retval = FALSE;
4128
4129             } else {
4130                 if (!strcmp(fullname, "term_rows"))
4131                     iflags.wc2_term_rows = (int) ltmp;
4132                 else /* !strcmp(fullname, "term_cols") */
4133                     iflags.wc2_term_cols = (int) ltmp;
4134             }
4135         }
4136         return retval;
4137     }
4138
4139     /* WINCAP2
4140      * petattr:string */
4141     fullname = "petattr";
4142     if (match_optname(opts, fullname, sizeof "petattr" - 1, TRUE)) {
4143         op = string_for_opt(opts, negated);
4144         if (op != empty_optstr && negated) {
4145             bad_negation(fullname, TRUE);
4146             retval = FALSE;
4147         } else if (op != empty_optstr) {
4148 #ifdef CURSES_GRAPHICS
4149             int itmp = curses_read_attrs(op);
4150
4151             if (itmp == -1) {
4152                 config_error_add("Unknown %s parameter '%s'", fullname, opts);
4153                 retval = FALSE;
4154             } else
4155                 iflags.wc2_petattr = itmp;
4156 #else
4157             /* non-curses windowports will not use this flag anyway
4158              * but the above will not compile if we don't have curses.
4159              * Just set it to a sensible default: */
4160             iflags.wc2_petattr = ATR_INVERSE;
4161 #endif
4162         } else if (negated) {
4163             iflags.wc2_petattr = ATR_NONE;
4164         }
4165         if (retval) {
4166             iflags.hilite_pet = (iflags.wc2_petattr != ATR_NONE);
4167             if (!initial)
4168                 need_redraw = TRUE;
4169         }
4170         return retval;
4171     }
4172
4173     /* WINCAP2
4174      * windowborders:n */
4175     fullname = "windowborders";
4176     if (match_optname(opts, fullname, 10, TRUE)) {
4177         op = string_for_opt(opts, negated);
4178         if (negated && op != empty_optstr) {
4179             bad_negation(fullname, TRUE);
4180             retval = FALSE;
4181         } else {
4182             int itmp;
4183
4184             if (negated)
4185                 itmp = 0; /* Off */
4186             else if (op == empty_optstr)
4187                 itmp = 1; /* On */
4188             else    /* Value supplied; expect 0 (off), 1 (on), or 2 (auto) */
4189                 itmp = atoi(op);
4190
4191             if (itmp < 0 || itmp > 2) {
4192                 config_error_add("Invalid %s (should be 0, 1, or 2): %s",
4193                                  fullname, opts);
4194                 retval = FALSE;
4195             } else {
4196                 iflags.wc2_windowborders = itmp;
4197             }
4198         }
4199         return retval;
4200     }
4201 #endif /* CURSES_GRAPHICS */
4202
4203     /* WINCAP2
4204      * statuslines:n */
4205     fullname = "statuslines";
4206     if (match_optname(opts, fullname, 11, TRUE)) {
4207         int itmp = 0;
4208
4209         op = string_for_opt(opts, negated);
4210         if (negated) {
4211             bad_negation(fullname, TRUE);
4212             itmp = 2;
4213             retval = FALSE;
4214         } else if (op != empty_optstr) {
4215             itmp = atoi(op);
4216         }
4217         if (itmp < 2 || itmp > 3) {
4218             config_error_add("'%s' requires a value of 2 or 3", fullname);
4219             retval = FALSE;
4220         } else {
4221             iflags.wc2_statuslines = itmp;
4222             if (!initial)
4223                 need_redraw = TRUE;
4224         }
4225         return retval;
4226     }
4227
4228     /* menustyle:traditional or combination or full or partial */
4229     fullname = "menustyle";
4230     if (match_optname(opts, fullname, 4, TRUE)) {
4231         int tmp;
4232         boolean val_required = (strlen(opts) > 5 && !negated);
4233
4234         if (duplicate)
4235             complain_about_duplicate(opts, 1);
4236         if ((op = string_for_opt(opts, !val_required)) == empty_optstr) {
4237             if (val_required)
4238                 return FALSE; /* string_for_opt gave feedback */
4239             tmp = negated ? 'n' : 'f';
4240         } else {
4241             tmp = lowc(*op);
4242         }
4243         switch (tmp) {
4244         case 'n': /* none */
4245         case 't': /* traditional: prompt for class(es) by symbol,
4246                      prompt for each item within class(es) one at a time */
4247             flags.menu_style = MENU_TRADITIONAL;
4248             break;
4249         case 'c': /* combination: prompt for class(es) by symbol,
4250                      choose items within selected class(es) by menu */
4251             flags.menu_style = MENU_COMBINATION;
4252             break;
4253         case 'f': /* full: choose class(es) by first menu,
4254                      choose items within selected class(es) by second menu */
4255             flags.menu_style = MENU_FULL;
4256             break;
4257         case 'p': /* partial: skip class filtering,
4258                      choose items among all classes by menu */
4259             flags.menu_style = MENU_PARTIAL;
4260             break;
4261         default:
4262             config_error_add("Unknown %s parameter '%s'", fullname, op);
4263             return FALSE;
4264         }
4265         return retval;
4266     }
4267
4268     fullname = "menu_headings";
4269     if (match_optname(opts, fullname, 12, TRUE)) {
4270         int tmpattr;
4271
4272         if (duplicate)
4273             complain_about_duplicate(opts, 1);
4274         if (negated) {
4275             bad_negation(fullname, FALSE);
4276             return FALSE;
4277         } else if ((opts = string_for_env_opt(fullname, opts, FALSE))
4278                                               == empty_optstr) {
4279             return FALSE;
4280         }
4281         tmpattr = match_str2attr(opts, TRUE);
4282         if (tmpattr == -1)
4283             return FALSE;
4284         else
4285             iflags.menu_headings = tmpattr;
4286         return retval;
4287     }
4288
4289     /* check for menu command mapping */
4290     for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
4291         fullname = default_menu_cmd_info[i].name;
4292         if (duplicate)
4293             complain_about_duplicate(opts, 1);
4294         if (match_optname(opts, fullname, (int) strlen(fullname), TRUE)) {
4295             if (negated) {
4296                 bad_negation(fullname, FALSE);
4297                 return FALSE;
4298             } else if ((op = string_for_opt(opts, FALSE)) != empty_optstr) {
4299                 char c, op_buf[BUFSZ];
4300
4301                 escapes(op, op_buf);
4302                 c = *op_buf;
4303
4304                 if (illegal_menu_cmd_key(c))
4305                     return FALSE;
4306
4307                 add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
4308             }
4309             return retval;
4310         }
4311     }
4312
4313     /* hilite fields in status prompt */
4314     fullname = "hilite_status";
4315     if (match_optname(opts, fullname, 13, TRUE)) {
4316 #ifdef STATUS_HILITES
4317         if (duplicate)
4318             complain_about_duplicate(opts, 1);
4319         op = string_for_opt(opts, TRUE);
4320         if (op != empty_optstr && negated) {
4321             clear_status_hilites();
4322             return retval;
4323         } else if (op == empty_optstr) {
4324             config_error_add("Value is mandatory for hilite_status");
4325             return FALSE;
4326         }
4327         if (!parse_status_hl1(op, tfrom_file))
4328             return FALSE;
4329         return retval;
4330 #else
4331         config_error_add("'%s' is not supported", fullname);
4332         return FALSE;
4333 #endif
4334     }
4335
4336     /* control over whether highlights should be displayed, and for how long */
4337     fullname = "statushilites";
4338     if (match_optname(opts, fullname, 9, TRUE)) {
4339 #ifdef STATUS_HILITES
4340         if (negated) {
4341             iflags.hilite_delta = 0L;
4342         } else {
4343             op = string_for_opt(opts, TRUE);
4344             iflags.hilite_delta = (op == empty_optstr || !*op) ? 3L : atol(op);
4345             if (iflags.hilite_delta < 0L)
4346                 iflags.hilite_delta = 1L;
4347         }
4348         if (!tfrom_file)
4349             reset_status_hilites();
4350         return retval;
4351 #else
4352         config_error_add("'%s' is not supported", fullname);
4353         return FALSE;
4354 #endif
4355     }
4356
4357     fullname = "DECgraphics";
4358     if (match_optname(opts, fullname, 3, TRUE)) {
4359 #ifdef BACKWARD_COMPAT
4360         boolean badflag = FALSE;
4361
4362         if (duplicate)
4363             complain_about_duplicate(opts, 1);
4364         if (!negated) {
4365             /* There is no rogue level DECgraphics-specific set */
4366             if (symset[PRIMARY].name) {
4367                 badflag = TRUE;
4368             } else {
4369                 symset[PRIMARY].name = dupstr(fullname);
4370                 if (!read_sym_file(PRIMARY)) {
4371                     badflag = TRUE;
4372                     clear_symsetentry(PRIMARY, TRUE);
4373                 } else
4374                     switch_symbols(TRUE);
4375             }
4376             if (badflag) {
4377                 config_error_add("Failure to load symbol set %s.", fullname);
4378                 return FALSE;
4379             }
4380         }
4381         return retval;
4382 #else
4383         config_error_add("'%s' no longer supported; use 'symset:%s' instead",
4384                          fullname, fullname);
4385         return FALSE;
4386 #endif
4387     } /* "DECgraphics" */
4388
4389     fullname = "IBMgraphics";
4390     if (match_optname(opts, fullname, 3, TRUE)) {
4391 #ifdef BACKWARD_COMPAT
4392         const char *sym_name = fullname;
4393         boolean badflag = FALSE;
4394
4395         if (duplicate)
4396             complain_about_duplicate(opts, 1);
4397         if (!negated) {
4398             for (i = 0; i < NUM_GRAPHICS; ++i) {
4399                 if (symset[i].name) {
4400                     badflag = TRUE;
4401                 } else {
4402                     if (i == ROGUESET)
4403                         sym_name = "RogueIBM";
4404                     symset[i].name = dupstr(sym_name);
4405                     if (!read_sym_file(i)) {
4406                         badflag = TRUE;
4407                         clear_symsetentry(i, TRUE);
4408                         break;
4409                     }
4410                 }
4411             }
4412             if (badflag) {
4413                 config_error_add("Failure to load symbol set %s.", sym_name);
4414                 return FALSE;
4415             } else {
4416                 switch_symbols(TRUE);
4417                 if (!initial && Is_rogue_level(&u.uz))
4418                     assign_graphics(ROGUESET);
4419             }
4420         }
4421         return retval;
4422 #else
4423         config_error_add("'%s' no longer supported; use 'symset:%s' instead",
4424                          fullname, fullname);
4425         return FALSE;
4426 #endif
4427     } /* "IBMgraphics" */
4428
4429     fullname = "MACgraphics";
4430     if (match_optname(opts, fullname, 3, TRUE)) {
4431 #if defined(MAC_GRAPHICS_ENV) && defined(BACKWARD_COMPAT)
4432         boolean badflag = FALSE;
4433
4434         if (duplicate)
4435             complain_about_duplicate(opts, 1);
4436         if (!negated) {
4437             if (symset[PRIMARY].name) {
4438                 badflag = TRUE;
4439             } else {
4440                 symset[PRIMARY].name = dupstr(fullname);
4441                 if (!read_sym_file(PRIMARY)) {
4442                     badflag = TRUE;
4443                     clear_symsetentry(PRIMARY, TRUE);
4444                 }
4445             }
4446             if (badflag) {
4447                 config_error_add("Failure to load symbol set %s.", fullname);
4448                 return FALSE;
4449             } else {
4450                 switch_symbols(TRUE);
4451                 if (!initial && Is_rogue_level(&u.uz))
4452                     assign_graphics(ROGUESET);
4453             }
4454         }
4455         return retval;
4456 #else   /* !(MAC_GRAPHICS_ENV && BACKWARD_COMPAT) */
4457         config_error_add("'%s' %s; use 'symset:%s' instead",
4458                          fullname,
4459 #ifdef MAC_GRAPHICS_ENV /* implies BACKWARD_COMPAT is not defined */
4460                          "no longer supported",
4461 #else
4462                          "is not supported",
4463 #endif
4464                          fullname);
4465         return FALSE;
4466 #endif  /* ?(MAC_GRAPHICS_ENV && BACKWARD_COMPAT) */
4467     } /* "MACgraphics" */
4468
4469     /*
4470      * OK, if we still haven't recognized the option, check the boolean
4471      * options list.
4472      */
4473     for (i = 0; boolopt[i].name; i++) {
4474         if (match_optname(opts, boolopt[i].name, 3, TRUE)) {
4475             /* options that don't exist */
4476             if (!boolopt[i].addr) {
4477                 if (!initial && !negated)
4478                     pline_The("\"%s\" option is not available.",
4479                               boolopt[i].name);
4480                 return retval;
4481             }
4482             /* options that must come from config file */
4483             if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
4484                 rejectoption(boolopt[i].name);
4485                 return retval;
4486             }
4487
4488             op = string_for_opt(opts, TRUE);
4489             if (op != empty_optstr) {
4490                 if (negated) {
4491                     config_error_add(
4492                            "Negated boolean '%s' should not have a parameter",
4493                                      boolopt[i].name);
4494                     return FALSE;
4495                 }
4496                 if (!strcmp(op, "true") || !strcmp(op, "yes")) {
4497                     negated = FALSE;
4498                 } else if (!strcmp(op, "false") || !strcmp(op, "no")) {
4499                     negated = TRUE;
4500                 } else {
4501                     config_error_add("Illegal parameter for a boolean");
4502                     return FALSE;
4503                 }
4504             }
4505             if (iflags.debug_fuzzer && !initial) {
4506                 /* don't randomly toggle this/these */
4507                 if (boolopt[i].addr == &flags.silent)
4508                     return TRUE;
4509             }
4510
4511             *(boolopt[i].addr) = !negated;
4512
4513             /* 0 means boolean opts */
4514             if (duplicate_opt_detection(boolopt[i].name, 0))
4515                 complain_about_duplicate(boolopt[i].name, 0);
4516 #ifdef RLECOMP
4517             if (boolopt[i].addr == &iflags.rlecomp)
4518                 set_savepref(iflags.rlecomp ? "rlecomp" : "!rlecomp");
4519 #endif
4520 #ifdef ZEROCOMP
4521             if (boolopt[i].addr == &iflags.zerocomp)
4522                 set_savepref(iflags.zerocomp ? "zerocomp" : "externalcomp");
4523 #endif
4524             if (boolopt[i].addr == &iflags.wc_ascii_map) {
4525                 /* toggling ascii_map; set tiled_map to its opposite;
4526                    what does it mean to turn off ascii map if tiled map
4527                    isn't supported? -- right now, we do nothing */
4528                 iflags.wc_tiled_map = negated;
4529             } else if (boolopt[i].addr == &iflags.wc_tiled_map) {
4530                 /* toggling tiled_map; set ascii_map to its opposite;
4531                    as with ascii_map, what does it mean to turn off tiled
4532                    map if ascii map isn't supported? */
4533                 iflags.wc_ascii_map = negated;
4534             }
4535             /* only do processing below if setting with doset() */
4536             if (initial)
4537                 return retval;
4538
4539             if (boolopt[i].addr == &flags.time
4540 #ifdef SCORE_ON_BOTL
4541                 || boolopt[i].addr == &flags.showscore
4542 #endif
4543                 || boolopt[i].addr == &flags.showexp) {
4544                 if (VIA_WINDOWPORT())
4545                     status_initialize(REASSESS_ONLY);
4546                 context.botl = TRUE;
4547             } else if (boolopt[i].addr == &flags.invlet_constant
4548                        || boolopt[i].addr == &flags.sortpack
4549                        || boolopt[i].addr == &iflags.implicit_uncursed) {
4550                 if (!flags.invlet_constant)
4551                     reassign();
4552                 update_inventory();
4553             } else if (boolopt[i].addr == &flags.lit_corridor
4554                        || boolopt[i].addr == &flags.dark_room) {
4555                 /*
4556                  * All corridor squares seen via night vision or
4557                  * candles & lamps change.  Update them by calling
4558                  * newsym() on them.  Don't do this if we are
4559                  * initializing the options --- the vision system
4560                  * isn't set up yet.
4561                  */
4562                 vision_recalc(2);       /* shut down vision */
4563                 vision_full_recalc = 1; /* delayed recalc */
4564                 if (iflags.use_color)
4565                     need_redraw = TRUE; /* darkroom refresh */
4566             } else if (boolopt[i].addr == &flags.showrace
4567                        || boolopt[i].addr == &iflags.use_inverse
4568                        || boolopt[i].addr == &iflags.hilite_pile
4569                        || boolopt[i].addr == &iflags.perm_invent
4570 #ifdef CURSES_GRAPHICS
4571                        || boolopt[i].addr == &iflags.cursesgraphics
4572 #endif
4573                        || boolopt[i].addr == &iflags.wc_ascii_map
4574                        || boolopt[i].addr == &iflags.wc_tiled_map) {
4575                 need_redraw = TRUE;
4576             } else if (boolopt[i].addr == &iflags.hilite_pet) {
4577 #ifdef CURSES_GRAPHICS
4578                 if (WINDOWPORT("curses")) {
4579                     /* if we're enabling hilite_pet and petattr isn't set,
4580                        set it to Inverse; if we're disabling, leave petattr
4581                        alone so that re-enabling will get current value back */
4582                     if (iflags.hilite_pet && !iflags.wc2_petattr)
4583                         iflags.wc2_petattr = curses_read_attrs("I");
4584                 }
4585 #endif
4586                 need_redraw = TRUE;
4587             } else if (boolopt[i].addr == &iflags.wc2_hitpointbar) {
4588                 if (VIA_WINDOWPORT()) {
4589                     /* [is reassessment really needed here?] */
4590                     status_initialize(REASSESS_ONLY);
4591                     need_redraw = TRUE;
4592                 }
4593 #ifdef TEXTCOLOR
4594             } else if (boolopt[i].addr == &iflags.use_color) {
4595                 need_redraw = TRUE;
4596 #ifdef TOS
4597                 if (iflags.BIOS) {
4598                     if (colors_changed)
4599                         restore_colors();
4600                     else
4601                         set_colors();
4602                 }
4603 #endif
4604             } else if (boolopt[i].addr == &iflags.use_menu_color
4605                        || boolopt[i].addr == &iflags.wc2_guicolor) {
4606                 update_inventory();
4607 #endif /* TEXTCOLOR */
4608             }
4609             return retval;
4610         }
4611     }
4612
4613     /* Is it a symbol? */
4614     if (strstr(opts, "S_") == opts && parsesymbols(opts, PRIMARY)) {
4615         switch_symbols(TRUE);
4616         check_gold_symbol();
4617         return retval;
4618     }
4619
4620     /* out of valid options */
4621     config_error_add("Unknown option '%s'", opts);
4622     return FALSE;
4623 }
4624
4625 /* parse key:command */
4626 boolean
4627 parsebindings(bindings)
4628 char* bindings;
4629 {
4630     char *bind;
4631     char key;
4632     int i;
4633     boolean ret = FALSE;
4634
4635     /* break off first binding from the rest; parse the rest */
4636     if ((bind = index(bindings, ',')) != 0) {
4637         *bind++ = 0;
4638         ret |= parsebindings(bind);
4639     }
4640
4641     /* parse a single binding: first split around : */
4642     if (! (bind = index(bindings, ':')))
4643         return FALSE; /* it's not a binding */
4644     *bind++ = 0;
4645
4646     /* read the key to be bound */
4647     key = txt2key(bindings);
4648     if (!key) {
4649         config_error_add("Unknown key binding key '%s'", bindings);
4650         return FALSE;
4651     }
4652
4653     bind = trimspaces(bind);
4654
4655     /* is it a special key? */
4656     if (bind_specialkey(key, bind))
4657         return TRUE;
4658
4659     /* is it a menu command? */
4660     for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
4661         if (!strcmp(default_menu_cmd_info[i].name, bind)) {
4662             if (illegal_menu_cmd_key(key)) {
4663                 config_error_add("Bad menu key %s:%s", visctrl(key), bind);
4664                 return FALSE;
4665             } else
4666                 add_menu_cmd_alias(key, default_menu_cmd_info[i].cmd);
4667             return TRUE;
4668         }
4669     }
4670
4671     /* extended command? */
4672     if (!bind_key(key, bind)) {
4673         config_error_add("Unknown key binding command '%s'", bind);
4674         return FALSE;
4675     }
4676     return TRUE;
4677 }
4678
4679 static NEARDATA const char *menutype[] = { "traditional", "combination",
4680                                            "full", "partial" };
4681
4682 static NEARDATA const char *burdentype[] = { "unencumbered", "burdened",
4683                                              "stressed",     "strained",
4684                                              "overtaxed",    "overloaded" };
4685
4686 static NEARDATA const char *runmodes[] = { "teleport", "run", "walk",
4687                                            "crawl" };
4688
4689 static NEARDATA const char *sortltype[] = { "none", "loot", "full" };
4690
4691 /*
4692  * Convert the given string of object classes to a string of default object
4693  * symbols.
4694  */
4695 void
4696 oc_to_str(src, dest)
4697 char *src, *dest;
4698 {
4699     int i;
4700
4701     while ((i = (int) *src++) != 0) {
4702         if (i < 0 || i >= MAXOCLASSES)
4703             impossible("oc_to_str:  illegal object class %d", i);
4704         else
4705             *dest++ = def_oc_syms[i].sym;
4706     }
4707     *dest = '\0';
4708 }
4709
4710 /*
4711  * Add the given mapping to the menu command map list.  Always keep the
4712  * maps valid C strings.
4713  */
4714 void
4715 add_menu_cmd_alias(from_ch, to_ch)
4716 char from_ch, to_ch;
4717 {
4718     if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) {
4719         pline("out of menu map space.");
4720     } else {
4721         mapped_menu_cmds[n_menu_mapped] = from_ch;
4722         mapped_menu_op[n_menu_mapped] = to_ch;
4723         n_menu_mapped++;
4724         mapped_menu_cmds[n_menu_mapped] = '\0';
4725         mapped_menu_op[n_menu_mapped] = '\0';
4726     }
4727 }
4728
4729 char
4730 get_menu_cmd_key(ch)
4731 char ch;
4732 {
4733     char *found = index(mapped_menu_op, ch);
4734
4735     if (found) {
4736         int idx = (int) (found - mapped_menu_op);
4737
4738         ch = mapped_menu_cmds[idx];
4739     }
4740     return ch;
4741 }
4742
4743 /*
4744  * Map the given character to its corresponding menu command.  If it
4745  * doesn't match anything, just return the original.
4746  */
4747 char
4748 map_menu_cmd(ch)
4749 char ch;
4750 {
4751     char *found = index(mapped_menu_cmds, ch);
4752
4753     if (found) {
4754         int idx = (int) (found - mapped_menu_cmds);
4755
4756         ch = mapped_menu_op[idx];
4757     }
4758     return ch;
4759 }
4760
4761 void
4762 show_menu_controls(win, dolist)
4763 winid win;
4764 boolean dolist;
4765 {
4766     char buf[BUFSZ];
4767
4768 /*JP
4769     putstr(win, 0, "Menu control keys:");
4770 */
4771     putstr(win, 0, "\83\81\83j\83\85\81[\90§\8cä\83L\81[:");
4772     if (dolist) {
4773         int i;
4774
4775         for (i = 0; i < SIZE(default_menu_cmd_info); i++) {
4776             Sprintf(buf, "%-8s %s",
4777                     visctrl(get_menu_cmd_key(default_menu_cmd_info[i].cmd)),
4778                     default_menu_cmd_info[i].desc);
4779             putstr(win, 0, buf);
4780         }
4781     } else {
4782         const char
4783             fmt3[] = " %-12s       %-2s        %-2s  %s",
4784             fmt2[] = " %-12s       %-2s        %-2s",
4785             fmt1[] = " %10s  %-2s  %s",
4786             fmt0[] = " %14s  %s";
4787
4788         putstr(win, 0, "");
4789 /*JP
4790         putstr(win, 0, "Selection:       On page   Full menu");
4791 */
4792         putstr(win, 0, "\91I\91ð:             \83y\81[\83W  \8a®\91S\83\81\83j\83\85\81[");
4793 /*JP
4794         Sprintf(buf, fmt2, "Select all",
4795 */
4796         Sprintf(buf, fmt2, "\91S\82Ä\91I\91ð",
4797                 visctrl(get_menu_cmd_key(MENU_SELECT_PAGE)),
4798                 visctrl(get_menu_cmd_key(MENU_SELECT_ALL)));
4799         putstr(win, 0, buf);
4800 /*JP
4801         Sprintf(buf, fmt2, "Deselect all",
4802 */
4803         Sprintf(buf, fmt2, "\91S\82Ä\91I\91ð\89ð\8f\9c",
4804                 visctrl(get_menu_cmd_key(MENU_UNSELECT_PAGE)),
4805                 visctrl(get_menu_cmd_key(MENU_UNSELECT_ALL)));
4806         putstr(win, 0, buf);
4807 /*JP
4808         Sprintf(buf, fmt2, "Invert all",
4809 */
4810         Sprintf(buf, fmt2, "\91S\82Ä\94½\93]",
4811                 visctrl(get_menu_cmd_key(MENU_INVERT_PAGE)),
4812                 visctrl(get_menu_cmd_key(MENU_INVERT_ALL)));
4813         putstr(win, 0, buf);
4814 /*JP
4815         Sprintf(buf, fmt3, "Text match", "",
4816 */
4817         Sprintf(buf, fmt3, "\83e\83L\83X\83g\83}\83b\83`", "",
4818                 visctrl(get_menu_cmd_key(MENU_SEARCH)),
4819 /*JP
4820                 "Search and toggle matching entries");
4821 */
4822                 "\8c\9f\8dõ\82µ\82Ä\83}\83b\83`\82µ\82½\83G\83\93\83g\83\8a\82ð\83g\83O\83\8b");
4823         putstr(win, 0, buf);
4824         putstr(win, 0, "");
4825 /*JP
4826         putstr(win, 0, "Navigation:");
4827 */
4828         putstr(win, 0, "\91\80\8dì:");
4829 /*JP
4830         Sprintf(buf, fmt1, "Go to     ",
4831 */
4832         Sprintf(buf, fmt1, "\88Ú\93®      ",
4833                 visctrl(get_menu_cmd_key(MENU_NEXT_PAGE)),
4834 /*JP
4835                 "Next page");
4836 */
4837                 "\8e\9f\82Ì\83y\81[\83W");
4838         putstr(win, 0, buf);
4839         Sprintf(buf, fmt1, "",
4840                 visctrl(get_menu_cmd_key(MENU_PREVIOUS_PAGE)),
4841 /*JP
4842                 "Previous page");
4843 */
4844                 "\91O\82Ì\83y\81[\83W");
4845         putstr(win, 0, buf);
4846         Sprintf(buf, fmt1, "",
4847                 visctrl(get_menu_cmd_key(MENU_FIRST_PAGE)),
4848 /*JP
4849                 "First page");
4850 */
4851                 "\90æ\93ª\83y\81[\83W");
4852         putstr(win, 0, buf);
4853         Sprintf(buf, fmt1, "",
4854                 visctrl(get_menu_cmd_key(MENU_LAST_PAGE)),
4855 /*JP
4856                 "Last page");
4857 */
4858                 "\8dÅ\8fI\83y\81[\83W");
4859         putstr(win, 0, buf);
4860 /*JP
4861         Sprintf(buf, fmt0, "SPACE", "Next page, if any, otherwise RETURN");
4862 */
4863         Sprintf(buf, fmt0, "SPACE", "\82 \82ê\82Î\8e\9f\82Ì\83y\81[\83W\81A\82È\82¯\82ê\82ÎRETURN");
4864         putstr(win, 0, buf);
4865         Sprintf(buf, fmt0, "RETURN/ENTER",
4866 /*JP
4867                 "Finish menu with any selection(s) made");
4868 */
4869                 "\91I\91ð\82µ\82Ä\83\81\83j\83\85\81[\8fI\97¹");
4870         putstr(win, 0, buf);
4871         Sprintf(buf, fmt0, "ESCAPE",
4872 /*JP
4873                 "Cancel menu without selecting anything");
4874 */
4875                 "\89½\82à\91I\91ð\82¹\82¸\82É\83\81\83j\83\85\81[\82ð\83L\83\83\83\93\83Z\83\8b");
4876         putstr(win, 0, buf);
4877     }
4878 }
4879
4880 #if defined(MICRO) || defined(MAC) || defined(WIN32)
4881 #define OPTIONS_HEADING "OPTIONS"
4882 #else
4883 #define OPTIONS_HEADING "NETHACKOPTIONS"
4884 #endif
4885
4886 static char fmtstr_doset[] = "%s%-15s [%s]   ";
4887 static char fmtstr_doset_tab[] = "%s\t[%s]";
4888 /*JP
4889 static char n_currently_set[] = "(%d currently set)";
4890 */
4891 static char n_currently_set[] = "(%d\8cÂ\90Ý\92è\92\86)";
4892
4893 /* doset('O' command) menu entries for compound options */
4894 STATIC_OVL void
4895 doset_add_menu(win, option, indexoffset)
4896 winid win;          /* window to add to */
4897 const char *option; /* option name */
4898 int indexoffset;    /* value to add to index in compopt[], or zero
4899                        if option cannot be changed */
4900 {
4901     const char *value = "unknown"; /* current value */
4902     char buf[BUFSZ], buf2[BUFSZ];
4903     anything any;
4904     int i;
4905
4906     any = zeroany;
4907     if (indexoffset == 0) {
4908         any.a_int = 0;
4909         value = get_compopt_value(option, buf2);
4910     } else {
4911         for (i = 0; compopt[i].name; i++)
4912             if (strcmp(option, compopt[i].name) == 0)
4913                 break;
4914
4915         if (compopt[i].name) {
4916             any.a_int = i + 1 + indexoffset;
4917             value = get_compopt_value(option, buf2);
4918         } else {
4919             /* We are trying to add an option not found in compopt[].
4920                This is almost certainly bad, but we'll let it through anyway
4921                (with a zero value, so it can't be selected). */
4922             any.a_int = 0;
4923         }
4924     }
4925     /* "    " replaces "a - " -- assumes menus follow that style */
4926     if (!iflags.menu_tab_sep)
4927         Sprintf(buf, fmtstr_doset, any.a_int ? "" : "    ", option,
4928                 value);
4929     else
4930         Sprintf(buf, fmtstr_doset_tab, option, value);
4931     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
4932 }
4933
4934 STATIC_OVL void
4935 opts_add_others(win, name, id, bufx, nset)
4936 winid win;
4937 const char *name;
4938 int id;
4939 char *bufx;
4940 int nset;
4941 {
4942     char buf[BUFSZ], buf2[BUFSZ];
4943     anything any = zeroany;
4944
4945     any.a_int = id;
4946     if (!bufx)
4947         Sprintf(buf2, n_currently_set, nset);
4948     else
4949         Sprintf(buf2, "%s", bufx);
4950     if (!iflags.menu_tab_sep)
4951         Sprintf(buf, fmtstr_doset, any.a_int ? "" : "    ",
4952                 name, buf2);
4953     else
4954         Sprintf(buf, fmtstr_doset_tab, name, buf2);
4955     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
4956 }
4957
4958 int
4959 count_apes(VOID_ARGS)
4960 {
4961     int numapes = 0;
4962     struct autopickup_exception *ape = apelist;
4963
4964     while (ape) {
4965       numapes++;
4966       ape = ape->next;
4967     }
4968
4969     return numapes;
4970 }
4971
4972 enum opt_other_enums {
4973     OPT_OTHER_MSGTYPE = -4,
4974     OPT_OTHER_MENUCOLOR = -3,
4975     OPT_OTHER_STATHILITE = -2,
4976     OPT_OTHER_APEXC = -1
4977     /* these must be < 0 */
4978 };
4979
4980 static struct other_opts {
4981     const char *name;
4982     int optflags;
4983     enum opt_other_enums code;
4984     int NDECL((*othr_count_func));
4985 } othropt[] = {
4986     { "autopickup exceptions", SET_IN_GAME, OPT_OTHER_APEXC, count_apes },
4987     { "menu colors", SET_IN_GAME, OPT_OTHER_MENUCOLOR, count_menucolors },
4988     { "message types", SET_IN_GAME, OPT_OTHER_MSGTYPE, msgtype_count },
4989 #ifdef STATUS_HILITES
4990     { "status hilite rules", SET_IN_GAME, OPT_OTHER_STATHILITE,
4991       count_status_hilites },
4992 #endif
4993     { (char *) 0, 0, (enum opt_other_enums) 0 },
4994 };
4995
4996 /* the 'O' command */
4997 int
4998 doset() /* changing options via menu by Per Liboriussen */
4999 {
5000     static boolean made_fmtstr = FALSE;
5001     char buf[BUFSZ];
5002     const char *name;
5003     int i = 0, pass, boolcount, pick_cnt, pick_idx, opt_indx;
5004     boolean *bool_p;
5005     winid tmpwin;
5006     anything any;
5007     menu_item *pick_list;
5008     int indexoffset, startpass, endpass, optflags;
5009     boolean setinitial = FALSE, fromfile = FALSE;
5010     unsigned longest_name_len;
5011
5012     tmpwin = create_nhwindow(NHW_MENU);
5013     start_menu(tmpwin);
5014
5015 #ifdef notyet /* SYSCF */
5016     /* XXX I think this is still fragile.  Fixing initial/from_file and/or
5017        changing the SET_* etc to bitmaps will let me make this better. */
5018     if (wizard)
5019         startpass = SET_IN_SYS;
5020     else
5021 #endif
5022         startpass = DISP_IN_GAME;
5023     endpass = (wizard) ? SET_IN_WIZGAME : SET_IN_GAME;
5024
5025     if (!made_fmtstr && !iflags.menu_tab_sep) {
5026         /* spin through the options to find the longest name
5027            and adjust the format string accordingly */
5028         longest_name_len = 0;
5029         for (pass = 0; pass <= 2; pass++)
5030             for (i = 0; (name = ((pass == 0) ? boolopt[i].name
5031                                  : (pass == 1) ? compopt[i].name
5032                                    : othropt[i].name)) != 0; i++) {
5033                 if (pass == 0 && !boolopt[i].addr)
5034                     continue;
5035                 optflags = (pass == 0) ? boolopt[i].optflags
5036                            : (pass == 1) ? compopt[i].optflags
5037                              : othropt[i].optflags;
5038                 if (optflags < startpass || optflags > endpass)
5039                     continue;
5040                 if ((is_wc_option(name) && !wc_supported(name))
5041                     || (is_wc2_option(name) && !wc2_supported(name)))
5042                     continue;
5043
5044                 if (strlen(name) > longest_name_len)
5045                     longest_name_len = strlen(name);
5046             }
5047         Sprintf(fmtstr_doset, "%%s%%-%us [%%s]", longest_name_len);
5048         made_fmtstr = TRUE;
5049     }
5050
5051     any = zeroany;
5052     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5053 /*JP
5054              "Booleans (selecting will toggle value):", MENU_UNSELECTED);
5055 */
5056              "\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);
5057     any.a_int = 0;
5058     /* first list any other non-modifiable booleans, then modifiable ones */
5059     for (pass = 0; pass <= 1; pass++)
5060         for (i = 0; (name = boolopt[i].name) != 0; i++)
5061             if ((bool_p = boolopt[i].addr) != 0
5062                 && ((boolopt[i].optflags <= DISP_IN_GAME && pass == 0)
5063                     || (boolopt[i].optflags >= SET_IN_GAME && pass == 1))) {
5064                 if (bool_p == &flags.female)
5065                     continue; /* obsolete */
5066                 if (boolopt[i].optflags == SET_IN_WIZGAME && !wizard)
5067                     continue;
5068                 if ((is_wc_option(name) && !wc_supported(name))
5069                     || (is_wc2_option(name) && !wc2_supported(name)))
5070                     continue;
5071
5072                 any.a_int = (pass == 0) ? 0 : i + 1;
5073                 if (!iflags.menu_tab_sep)
5074                     Sprintf(buf, fmtstr_doset, (pass == 0) ? "    " : "",
5075                             name, *bool_p ? "true" : "false");
5076                 else
5077                     Sprintf(buf, fmtstr_doset_tab,
5078                             name, *bool_p ? "true" : "false");
5079                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
5080                          MENU_UNSELECTED);
5081             }
5082
5083     boolcount = i;
5084     indexoffset = boolcount;
5085     any = zeroany;
5086     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5087 #if 0 /*JP:T*/
5088     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5089              "Compounds (selecting will prompt for new value):",
5090              MENU_UNSELECTED);
5091 #else
5092     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5093              "\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",
5094              MENU_UNSELECTED);
5095 #endif
5096
5097     /* deliberately put playmode, name, role+race+gender+align first */
5098     doset_add_menu(tmpwin, "playmode", 0);
5099     doset_add_menu(tmpwin, "name", 0);
5100     doset_add_menu(tmpwin, "role", 0);
5101     doset_add_menu(tmpwin, "race", 0);
5102     doset_add_menu(tmpwin, "gender", 0);
5103     doset_add_menu(tmpwin, "align", 0);
5104
5105     for (pass = startpass; pass <= endpass; pass++)
5106         for (i = 0; (name = compopt[i].name) != 0; i++)
5107             if (compopt[i].optflags == pass) {
5108                 if (!strcmp(name, "playmode")  || !strcmp(name, "name")
5109                     || !strcmp(name, "role")   || !strcmp(name, "race")
5110                     || !strcmp(name, "gender") || !strcmp(name, "align"))
5111                     continue;
5112                 if ((is_wc_option(name) && !wc_supported(name))
5113                     || (is_wc2_option(name) && !wc2_supported(name)))
5114                     continue;
5115
5116                 doset_add_menu(tmpwin, name,
5117                                (pass == DISP_IN_GAME) ? 0 : indexoffset);
5118             }
5119
5120     any = zeroany;
5121     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5122     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5123              "Other settings:", MENU_UNSELECTED);
5124
5125     for (i = 0; (name = othropt[i].name) != 0; i++) {
5126         if ((is_wc_option(name) && !wc_supported(name))
5127             || (is_wc2_option(name) && !wc2_supported(name)))
5128             continue;
5129         opts_add_others(tmpwin, name, othropt[i].code,
5130                         (char *) 0, othropt[i].othr_count_func());
5131     }
5132
5133 #ifdef PREFIXES_IN_USE
5134     any = zeroany;
5135     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5136     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
5137              "Variable playground locations:", MENU_UNSELECTED);
5138     for (i = 0; i < PREFIX_COUNT; i++)
5139         doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
5140 #endif
5141 /*JP
5142     end_menu(tmpwin, "Set what options?");
5143 */
5144     end_menu(tmpwin, "\82Ç\82Ì\83I\83v\83V\83\87\83\93\82ð\90Ý\92è\82µ\82Ü\82·\82©\81H");
5145     need_redraw = FALSE;
5146     if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
5147         /*
5148          * Walk down the selection list and either invert the booleans
5149          * or prompt for new values. In most cases, call parseoptions()
5150          * to take care of options that require special attention, like
5151          * redraws.
5152          */
5153         for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
5154             opt_indx = pick_list[pick_idx].item.a_int - 1;
5155             if (opt_indx < -1)
5156                 opt_indx++; /* -1 offset for select_menu() */
5157             if (opt_indx == OPT_OTHER_APEXC) {
5158                 (void) special_handling("autopickup_exception", setinitial,
5159                                         fromfile);
5160 #ifdef STATUS_HILITES
5161             } else if (opt_indx == OPT_OTHER_STATHILITE) {
5162                 if (!status_hilite_menu()) {
5163                     pline("Bad status hilite(s) specified.");
5164                 } else {
5165                     if (wc2_supported("hilite_status"))
5166                         preference_update("hilite_status");
5167                 }
5168 #endif
5169             } else if (opt_indx == OPT_OTHER_MENUCOLOR) {
5170                     (void) special_handling("menu_colors", setinitial,
5171                                             fromfile);
5172             } else if (opt_indx == OPT_OTHER_MSGTYPE) {
5173                     (void) special_handling("msgtype", setinitial, fromfile);
5174             } else if (opt_indx < boolcount) {
5175                 /* boolean option */
5176                 Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
5177                         boolopt[opt_indx].name);
5178                 (void) parseoptions(buf, setinitial, fromfile);
5179                 if (wc_supported(boolopt[opt_indx].name)
5180                     || wc2_supported(boolopt[opt_indx].name))
5181                     preference_update(boolopt[opt_indx].name);
5182             } else {
5183                 /* compound option */
5184                 opt_indx -= boolcount;
5185
5186                 if (!special_handling(compopt[opt_indx].name, setinitial,
5187                                       fromfile)) {
5188                     char abuf[BUFSZ];
5189
5190 /*JP
5191                     Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
5192 */
5193                     Sprintf(buf, "%s\82É\89½\82ð\90Ý\92è\82·\82é\81H", compopt[opt_indx].name);
5194                     abuf[0] = '\0';
5195                     getlin(buf, abuf);
5196                     if (abuf[0] == '\033')
5197                         continue;
5198                     Sprintf(buf, "%s:", compopt[opt_indx].name);
5199                     (void) strncat(eos(buf), abuf,
5200                                    (sizeof buf - 1 - strlen(buf)));
5201                     /* pass the buck */
5202                     (void) parseoptions(buf, setinitial, fromfile);
5203                 }
5204                 if (wc_supported(compopt[opt_indx].name)
5205                     || wc2_supported(compopt[opt_indx].name))
5206                     preference_update(compopt[opt_indx].name);
5207             }
5208         }
5209         free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
5210     }
5211
5212     destroy_nhwindow(tmpwin);
5213     if (need_redraw) {
5214         check_gold_symbol();
5215         reglyph_darkroom();
5216         (void) doredraw();
5217     }
5218     return 0;
5219 }
5220
5221 /* common to msg-types, menu-colors, autopickup-exceptions */
5222 STATIC_OVL int
5223 handle_add_list_remove(optname, numtotal)
5224 const char *optname;
5225 int numtotal;
5226 {
5227     winid tmpwin;
5228     anything any;
5229     int i, pick_cnt, opt_idx;
5230     menu_item *pick_list = (menu_item *) 0;
5231     static const struct action {
5232         char letr;
5233         const char *desc;
5234     } action_titles[] = {
5235 #if 0 /*JP:T*/
5236         { 'a', "add new %s" },         /* [0] */
5237 #else
5238         { 'a', "\90V\82µ\82¢%s\82ð\92Ç\89Á" },     /* [0] */
5239 #endif
5240 #if 0 /*JP:T*/
5241         { 'l', "list %s" },            /* [1] */
5242 #else
5243         { 'l', "%s\82ð\88ê\97\97\95\\8e¦" },       /* [1] */
5244 #endif
5245 #if 0 /*JP:T*/
5246         { 'r', "remove existing %s" }, /* [2] */
5247 #else
5248         { 'r', "\8aù\82É\82 \82é%s\82ð\8dí\8f\9c" },   /* [2] */
5249 #endif
5250 #if 0 /*JP:T*/
5251         { 'x', "exit this menu" },     /* [3] */
5252 #else
5253         { 'x', "\82±\82Ì\83\81\83j\83\85\81[\82ð\95Â\82\82é" }, /* [3] */
5254 #endif
5255     };
5256
5257     opt_idx = 0;
5258     tmpwin = create_nhwindow(NHW_MENU);
5259     start_menu(tmpwin);
5260     any = zeroany;
5261     for (i = 0; i < SIZE(action_titles); i++) {
5262         char tmpbuf[BUFSZ];
5263
5264         any.a_int++;
5265         /* omit list and remove if there aren't any yet */
5266         if (!numtotal && (i == 1 || i == 2))
5267             continue;
5268         Sprintf(tmpbuf, action_titles[i].desc,
5269                 (i == 1) ? makeplural(optname) : optname);
5270         add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, 0, ATR_NONE,
5271                  tmpbuf, (i == 3) ? MENU_SELECTED : MENU_UNSELECTED);
5272     }
5273 /*JP
5274     end_menu(tmpwin, "Do what?");
5275 */
5276     end_menu(tmpwin, "\82Ç\82¤\82·\82é\81H");
5277     if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
5278         opt_idx = pick_list[0].item.a_int - 1;
5279         if (pick_cnt > 1 && opt_idx == 3)
5280             opt_idx = pick_list[1].item.a_int - 1;
5281         free((genericptr_t) pick_list);
5282     } else
5283         opt_idx = 3; /* none selected, exit menu */
5284     destroy_nhwindow(tmpwin);
5285     return opt_idx;
5286 }
5287
5288 struct symsetentry *symset_list = 0; /* files.c will populate this with
5289                                       * list of available sets */
5290
5291 STATIC_OVL boolean
5292 special_handling(optname, setinitial, setfromfile)
5293 const char *optname;
5294 boolean setinitial, setfromfile;
5295 {
5296     winid tmpwin;
5297     anything any;
5298     int i, n;
5299     char buf[BUFSZ];
5300
5301     /* Special handling of menustyle, pickup_burden, pickup_types,
5302      * disclose, runmode, msg_window, menu_headings, sortloot,
5303      * and number_pad options.
5304      * Also takes care of interactive autopickup_exception_handling changes.
5305      */
5306     if (!strcmp("menustyle", optname)) {
5307         const char *style_name;
5308         menu_item *style_pick = (menu_item *) 0;
5309
5310         tmpwin = create_nhwindow(NHW_MENU);
5311         start_menu(tmpwin);
5312         any = zeroany;
5313         for (i = 0; i < SIZE(menutype); i++) {
5314             style_name = menutype[i];
5315             /* note: separate `style_name' variable used
5316                to avoid an optimizer bug in VAX C V2.3 */
5317             any.a_int = i + 1;
5318             add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, ATR_NONE,
5319                      style_name, MENU_UNSELECTED);
5320         }
5321 /*JP
5322         end_menu(tmpwin, "Select menustyle:");
5323 */
5324         end_menu(tmpwin, "\83\81\83j\83\85\81[\83X\83^\83C\83\8b\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5325         if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
5326             flags.menu_style = style_pick->item.a_int - 1;
5327             free((genericptr_t) style_pick);
5328         }
5329         destroy_nhwindow(tmpwin);
5330     } else if (!strcmp("paranoid_confirmation", optname)) {
5331         menu_item *paranoia_picks = (menu_item *) 0;
5332
5333         tmpwin = create_nhwindow(NHW_MENU);
5334         start_menu(tmpwin);
5335         any = zeroany;
5336         for (i = 0; paranoia[i].flagmask != 0; ++i) {
5337             if (paranoia[i].flagmask == PARANOID_BONES && !wizard)
5338                 continue;
5339             any.a_int = paranoia[i].flagmask;
5340             add_menu(tmpwin, NO_GLYPH, &any, *paranoia[i].argname, 0,
5341                      ATR_NONE, paranoia[i].explain,
5342                      (flags.paranoia_bits & paranoia[i].flagmask)
5343                          ? MENU_SELECTED
5344                          : MENU_UNSELECTED);
5345         }
5346         end_menu(tmpwin, "Actions requiring extra confirmation:");
5347         i = select_menu(tmpwin, PICK_ANY, &paranoia_picks);
5348         if (i >= 0) {
5349             /* player didn't cancel; we reset all the paranoia options
5350                here even if there were no items picked, since user
5351                could have toggled off preselected ones to end up with 0 */
5352             flags.paranoia_bits = 0;
5353             if (i > 0) {
5354                 /* at least 1 item set, either preselected or newly picked */
5355                 while (--i >= 0)
5356                     flags.paranoia_bits |= paranoia_picks[i].item.a_int;
5357                 free((genericptr_t) paranoia_picks);
5358             }
5359         }
5360         destroy_nhwindow(tmpwin);
5361     } else if (!strcmp("pickup_burden", optname)) {
5362         const char *burden_name, *burden_letters = "ubsntl";
5363         menu_item *burden_pick = (menu_item *) 0;
5364
5365         tmpwin = create_nhwindow(NHW_MENU);
5366         start_menu(tmpwin);
5367         any = zeroany;
5368         for (i = 0; i < SIZE(burdentype); i++) {
5369             burden_name = burdentype[i];
5370             any.a_int = i + 1;
5371             add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, ATR_NONE,
5372                      burden_name, MENU_UNSELECTED);
5373         }
5374 /*JP
5375         end_menu(tmpwin, "Select encumbrance level:");
5376 */
5377         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");
5378         if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
5379             flags.pickup_burden = burden_pick->item.a_int - 1;
5380             free((genericptr_t) burden_pick);
5381         }
5382         destroy_nhwindow(tmpwin);
5383     } else if (!strcmp("pickup_types", optname)) {
5384         /* parseoptions will prompt for the list of types */
5385         (void) parseoptions(strcpy(buf, "pickup_types"),
5386                             setinitial, setfromfile);
5387     } else if (!strcmp("disclose", optname)) {
5388         /* order of disclose_names[] must correspond to
5389            disclosure_options in decl.c */
5390         static const char *disclosure_names[] = {
5391             "inventory", "attributes", "vanquished",
5392             "genocides", "conduct",    "overview",
5393         };
5394         int disc_cat[NUM_DISCLOSURE_OPTIONS];
5395         int pick_cnt, pick_idx, opt_idx;
5396         char c;
5397         menu_item *disclosure_pick = (menu_item *) 0;
5398
5399         tmpwin = create_nhwindow(NHW_MENU);
5400         start_menu(tmpwin);
5401         any = zeroany;
5402         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
5403             Sprintf(buf, "%-12s[%c%c]", disclosure_names[i],
5404                     flags.end_disclose[i], disclosure_options[i]);
5405             any.a_int = i + 1;
5406             add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
5407                      ATR_NONE, buf, MENU_UNSELECTED);
5408             disc_cat[i] = 0;
5409         }
5410 /*JP
5411         end_menu(tmpwin, "Change which disclosure options categories:");
5412 */
5413         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");
5414         pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_pick);
5415         if (pick_cnt > 0) {
5416             for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
5417                 opt_idx = disclosure_pick[pick_idx].item.a_int - 1;
5418                 disc_cat[opt_idx] = 1;
5419             }
5420             free((genericptr_t) disclosure_pick);
5421             disclosure_pick = (menu_item *) 0;
5422         }
5423         destroy_nhwindow(tmpwin);
5424
5425         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
5426             if (disc_cat[i]) {
5427                 c = flags.end_disclose[i];
5428 /*JP
5429                 Sprintf(buf, "Disclosure options for %s:",
5430 */
5431                 Sprintf(buf, "%s\82Ì\8fo\97Í\8c`\8e®\81F",
5432                         disclosure_names[i]);
5433                 tmpwin = create_nhwindow(NHW_MENU);
5434                 start_menu(tmpwin);
5435                 any = zeroany;
5436                 /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
5437                 any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
5438                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5439 /*JP
5440                          "Never disclose, without prompting",
5441 */
5442                          "\8am\94F\82¹\82¸\82É\8fo\97Í\82à\82µ\82È\82¢",
5443                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5444                 any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
5445                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5446 /*JP
5447                          "Always disclose, without prompting",
5448 */
5449                          "\8am\94F\82¹\82¸\82É\8fo\97Í\82·\82é",
5450                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5451                 if (*disclosure_names[i] == 'v') {
5452                     any.a_char = DISCLOSE_SPECIAL_WITHOUT_PROMPT; /* '#' */
5453                     add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5454 /*JP
5455                              "Always disclose, pick sort order from menu",
5456 */
5457                              "\83\81\83j\83\85\81[\82©\82ç\83\\81[\83g\8f\87\82ð\91I\82ñ\82Å\8fí\82É\8fo\97Í\82·\82é",
5458                              (c == any.a_char) ? MENU_SELECTED
5459                                                : MENU_UNSELECTED);
5460                 }
5461                 any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
5462                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5463 /*JP
5464                          "Prompt, with default answer of \"No\"",
5465 */
5466                          "\8am\94F\82·\82é\81C\83f\83t\83H\83\8b\83g\82Í\81u\8fo\97Í\82µ\82È\82¢\81v",
5467                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5468                 any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
5469                 add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5470 /*JP
5471                          "Prompt, with default answer of \"Yes\"",
5472 */
5473                          "\8am\94F\82·\82é\81C\83f\83t\83H\83\8b\83g\82Í\81u\8fo\97Í\82·\82é\81v",
5474                          (c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
5475                 if (*disclosure_names[i] == 'v') {
5476                     any.a_char = DISCLOSE_PROMPT_DEFAULT_SPECIAL; /* '?' */
5477                     add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
5478 /*JP
5479                 "Prompt, with default answer of \"Ask\" to request sort menu",
5480 */
5481                 "\8am\94F\82·\82é\81C\83\\81[\83g\83\81\83j\83\85\81[\82ð\97v\8b\81\82·\82é\95W\8f\80\82Ì\93\9a\82¦\82Í \"Ask\"",
5482                              (c == any.a_char) ? MENU_SELECTED
5483                                                : MENU_UNSELECTED);
5484                 }
5485                 end_menu(tmpwin, buf);
5486                 n = select_menu(tmpwin, PICK_ONE, &disclosure_pick);
5487                 if (n > 0) {
5488                     flags.end_disclose[i] = disclosure_pick[0].item.a_char;
5489                     if (n > 1 && flags.end_disclose[i] == c)
5490                         flags.end_disclose[i] = disclosure_pick[1].item.a_char;
5491                     free((genericptr_t) disclosure_pick);
5492                 }
5493                 destroy_nhwindow(tmpwin);
5494             }
5495         }
5496     } else if (!strcmp("runmode", optname)) {
5497         const char *mode_name;
5498         menu_item *mode_pick = (menu_item *) 0;
5499
5500         tmpwin = create_nhwindow(NHW_MENU);
5501         start_menu(tmpwin);
5502         any = zeroany;
5503         for (i = 0; i < SIZE(runmodes); i++) {
5504             mode_name = runmodes[i];
5505             any.a_int = i + 1;
5506             add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, ATR_NONE,
5507                      mode_name, MENU_UNSELECTED);
5508         }
5509 /*JP
5510         end_menu(tmpwin, "Select run/travel display mode:");
5511 */
5512         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");
5513         if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
5514             flags.runmode = mode_pick->item.a_int - 1;
5515             free((genericptr_t) mode_pick);
5516         }
5517         destroy_nhwindow(tmpwin);
5518     } else if (!strcmp("whatis_coord", optname)) {
5519         menu_item *window_pick = (menu_item *) 0;
5520         int pick_cnt;
5521         char gp = iflags.getpos_coords;
5522
5523         tmpwin = create_nhwindow(NHW_MENU);
5524         start_menu(tmpwin);
5525         any = zeroany;
5526         any.a_char = GPCOORDS_COMPASS;
5527         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMPASS, 0, ATR_NONE,
5528                  "compass ('east' or '3s' or '2n,4w')",
5529                  (gp == GPCOORDS_COMPASS) ? MENU_SELECTED : MENU_UNSELECTED);
5530         any.a_char = GPCOORDS_COMFULL;
5531         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMFULL, 0, ATR_NONE,
5532                  "full compass ('east' or '3south' or '2north,4west')",
5533                  (gp == GPCOORDS_COMFULL) ? MENU_SELECTED : MENU_UNSELECTED);
5534         any.a_char = GPCOORDS_MAP;
5535         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_MAP, 0, ATR_NONE,
5536                  "map <x,y>",
5537                  (gp == GPCOORDS_MAP) ? MENU_SELECTED : MENU_UNSELECTED);
5538         any.a_char = GPCOORDS_SCREEN;
5539         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_SCREEN, 0, ATR_NONE,
5540                  "screen [row,column]",
5541                  (gp == GPCOORDS_SCREEN) ? MENU_SELECTED : MENU_UNSELECTED);
5542         any.a_char = GPCOORDS_NONE;
5543         add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE, 0, ATR_NONE,
5544                  "none (no coordinates displayed)",
5545                  (gp == GPCOORDS_NONE) ? MENU_SELECTED : MENU_UNSELECTED);
5546         any.a_long = 0L;
5547         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5548         Sprintf(buf, "map: upper-left: <%d,%d>, lower-right: <%d,%d>%s",
5549                 1, 0, COLNO - 1, ROWNO - 1,
5550                 flags.verbose ? "; column 0 unused, off left edge" : "");
5551         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
5552         if (strcmp(windowprocs.name, "tty")) /* only show for non-tty */
5553             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
5554        "screen: row is offset to accommodate tty interface's use of top line",
5555                      MENU_UNSELECTED);
5556 #if COLNO == 80
5557 #define COL80ARG flags.verbose ? "; column 80 is not used" : ""
5558 #else
5559 #define COL80ARG ""
5560 #endif
5561         Sprintf(buf, "screen: upper-left: [%02d,%02d], lower-right: [%d,%d]%s",
5562                 0 + 2, 1, ROWNO - 1 + 2, COLNO - 1, COL80ARG);
5563 #undef COL80ARG
5564         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
5565         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
5566         end_menu(tmpwin,
5567             "Select coordinate display when auto-describing a map position:");
5568         if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &window_pick)) > 0) {
5569             iflags.getpos_coords = window_pick[0].item.a_char;
5570             /* PICK_ONE doesn't unselect preselected entry when
5571                selecting another one */
5572             if (pick_cnt > 1 && iflags.getpos_coords == gp)
5573                 iflags.getpos_coords = window_pick[1].item.a_char;
5574             free((genericptr_t) window_pick);
5575         }
5576         destroy_nhwindow(tmpwin);
5577     } else if (!strcmp("whatis_filter", optname)) {
5578         menu_item *window_pick = (menu_item *) 0;
5579         int pick_cnt;
5580         char gf = iflags.getloc_filter;
5581
5582         tmpwin = create_nhwindow(NHW_MENU);
5583         start_menu(tmpwin);
5584         any = zeroany;
5585         any.a_char = (GFILTER_NONE + 1);
5586         add_menu(tmpwin, NO_GLYPH, &any, 'n',
5587                  0, ATR_NONE, "no filtering",
5588                  (gf == GFILTER_NONE) ? MENU_SELECTED : MENU_UNSELECTED);
5589         any.a_char = (GFILTER_VIEW + 1);
5590         add_menu(tmpwin, NO_GLYPH, &any, 'v',
5591                  0, ATR_NONE, "in view only",
5592                  (gf == GFILTER_VIEW) ? MENU_SELECTED : MENU_UNSELECTED);
5593         any.a_char = (GFILTER_AREA + 1);
5594         add_menu(tmpwin, NO_GLYPH, &any, 'a',
5595                  0, ATR_NONE, "in same area",
5596                  (gf == GFILTER_AREA) ? MENU_SELECTED : MENU_UNSELECTED);
5597         end_menu(tmpwin,
5598       "Select location filtering when going for next/previous map position:");
5599         if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &window_pick)) > 0) {
5600             iflags.getloc_filter = (window_pick[0].item.a_char - 1);
5601             /* PICK_ONE doesn't unselect preselected entry when
5602                selecting another one */
5603             if (pick_cnt > 1 && iflags.getloc_filter == gf)
5604                 iflags.getloc_filter = (window_pick[1].item.a_char - 1);
5605             free((genericptr_t) window_pick);
5606         }
5607         destroy_nhwindow(tmpwin);
5608     } else if (!strcmp("msg_window", optname)) {
5609 #if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
5610         if (WINDOWPORT("tty") || WINDOWPORT("curses")) {
5611             /* by Christian W. Cooper */
5612             menu_item *window_pick = (menu_item *) 0;
5613
5614             tmpwin = create_nhwindow(NHW_MENU);
5615             start_menu(tmpwin);
5616             any = zeroany;
5617             if (!WINDOWPORT("curses")) {
5618                 any.a_char = 's';
5619                 add_menu(tmpwin, NO_GLYPH, &any, 's', 0, ATR_NONE,
5620                          "single", MENU_UNSELECTED);
5621                 any.a_char = 'c';
5622                 add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE,
5623                          "combination", MENU_UNSELECTED);
5624             }
5625             any.a_char = 'f';
5626             add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, ATR_NONE, "full",
5627                      MENU_UNSELECTED);
5628             any.a_char = 'r';
5629             add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "reversed",
5630                      MENU_UNSELECTED);
5631 /*JP
5632             end_menu(tmpwin, "Select message history display type:");
5633 */
5634             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");
5635             if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
5636                 iflags.prevmsg_window = window_pick->item.a_char;
5637                 free((genericptr_t) window_pick);
5638             }
5639             destroy_nhwindow(tmpwin);
5640         } else
5641 #endif /* msg_window for tty or curses */
5642             pline("'%s' option is not supported for '%s'.",
5643                   optname, windowprocs.name);
5644     } else if (!strcmp("sortloot", optname)) {
5645         const char *sortl_name;
5646         menu_item *sortl_pick = (menu_item *) 0;
5647
5648         tmpwin = create_nhwindow(NHW_MENU);
5649         start_menu(tmpwin);
5650         any = zeroany;
5651         for (i = 0; i < SIZE(sortltype); i++) {
5652             sortl_name = sortltype[i];
5653             any.a_char = *sortl_name;
5654             add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE,
5655                      sortl_name, (flags.sortloot == *sortl_name)
5656                                     ? MENU_SELECTED : MENU_UNSELECTED);
5657         }
5658         end_menu(tmpwin, "Select loot sorting type:");
5659         n = select_menu(tmpwin, PICK_ONE, &sortl_pick);
5660         if (n > 0) {
5661             char c = sortl_pick[0].item.a_char;
5662
5663             if (n > 1 && c == flags.sortloot)
5664                 c = sortl_pick[1].item.a_char;
5665             flags.sortloot = c;
5666             free((genericptr_t) sortl_pick);
5667         }
5668         destroy_nhwindow(tmpwin);
5669     } else if (!strcmp("align_message", optname)
5670                || !strcmp("align_status", optname)) {
5671         menu_item *window_pick = (menu_item *) 0;
5672         char abuf[BUFSZ];
5673         boolean msg = (*(optname + 6) == 'm');
5674
5675         tmpwin = create_nhwindow(NHW_MENU);
5676         start_menu(tmpwin);
5677         any = zeroany;
5678         any.a_int = ALIGN_TOP;
5679         add_menu(tmpwin, NO_GLYPH, &any, 't', 0, ATR_NONE, "top",
5680                  MENU_UNSELECTED);
5681         any.a_int = ALIGN_BOTTOM;
5682         add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE, "bottom",
5683                  MENU_UNSELECTED);
5684         any.a_int = ALIGN_LEFT;
5685         add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, ATR_NONE, "left",
5686                  MENU_UNSELECTED);
5687         any.a_int = ALIGN_RIGHT;
5688         add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "right",
5689                  MENU_UNSELECTED);
5690 #if 0 /*JP:T*/
5691         Sprintf(abuf, "Select %s window placement relative to the map:",
5692                 msg ? "message" : "status");
5693 #else
5694         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",
5695                 msg ? "\83\81\83b\83Z\81[\83W" : "\8fó\91Ô");
5696 #endif
5697         end_menu(tmpwin, abuf);
5698         if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
5699             if (msg)
5700                 iflags.wc_align_message = window_pick->item.a_int;
5701             else
5702                 iflags.wc_align_status = window_pick->item.a_int;
5703             free((genericptr_t) window_pick);
5704         }
5705         destroy_nhwindow(tmpwin);
5706     } else if (!strcmp("number_pad", optname)) {
5707         static const char *npchoices[] = {
5708 /*JP
5709             " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
5710 */
5711             "0 (\96³\8cø)", "1 (\97L\8cø)", "2 (\97L\8cø\81CMSDOS\8cÝ\8a·)",
5712 /*JP
5713             " 3 (on, phone-style digit layout)",
5714 */
5715             " 3 (\97L\8cø\81C\93d\98b\8e®\82Ì\90\94\8e\9a\94z\92u)",
5716 /*JP
5717             " 4 (on, phone-style layout, MSDOS compatible)",
5718 */
5719             " 4 (\97L\8cø\81C\93d\98b\8e®\82Ì\94z\92u\81CMSDOS \8cÝ\8a·)",
5720 /*JP
5721             "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
5722 */
5723             "-1 (\96³\8cø\81C'z' \82Å\8d\8fã\82É\88Ú\93®\81C'y' \82Å\8fñ\82ð\90U\82é)"
5724         };
5725         menu_item *mode_pick = (menu_item *) 0;
5726
5727         tmpwin = create_nhwindow(NHW_MENU);
5728         start_menu(tmpwin);
5729         any = zeroany;
5730         for (i = 0; i < SIZE(npchoices); i++) {
5731             any.a_int = i + 1;
5732             add_menu(tmpwin, NO_GLYPH, &any, 'a' + i, 0, ATR_NONE,
5733                      npchoices[i], MENU_UNSELECTED);
5734         }
5735 /*JP
5736         end_menu(tmpwin, "Select number_pad mode:");
5737 */
5738         end_menu(tmpwin, "number_pad\83\82\81[\83h\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F");
5739         if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
5740             switch (mode_pick->item.a_int - 1) {
5741             case 0:
5742                 iflags.num_pad = FALSE;
5743                 iflags.num_pad_mode = 0;
5744                 break;
5745             case 1:
5746                 iflags.num_pad = TRUE;
5747                 iflags.num_pad_mode = 0;
5748                 break;
5749             case 2:
5750                 iflags.num_pad = TRUE;
5751                 iflags.num_pad_mode = 1;
5752                 break;
5753             case 3:
5754                 iflags.num_pad = TRUE;
5755                 iflags.num_pad_mode = 2;
5756                 break;
5757             case 4:
5758                 iflags.num_pad = TRUE;
5759                 iflags.num_pad_mode = 3;
5760                 break;
5761             /* last menu choice: number_pad == -1 */
5762             case 5:
5763                 iflags.num_pad = FALSE;
5764                 iflags.num_pad_mode = 1;
5765                 break;
5766             }
5767             reset_commands(FALSE);
5768             number_pad(iflags.num_pad ? 1 : 0);
5769             free((genericptr_t) mode_pick);
5770         }
5771         destroy_nhwindow(tmpwin);
5772     } else if (!strcmp("menu_headings", optname)) {
5773 /*JP
5774         int mhattr = query_attr("How to highlight menu headings:");
5775 */
5776         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");
5777
5778         if (mhattr != -1)
5779             iflags.menu_headings = mhattr;
5780     } else if (!strcmp("msgtype", optname)) {
5781         int opt_idx, nmt, mttyp;
5782         char mtbuf[BUFSZ];
5783
5784  msgtypes_again:
5785         nmt = msgtype_count();
5786 /*JP
5787         opt_idx = handle_add_list_remove("message type", nmt);
5788 */
5789         opt_idx = handle_add_list_remove("\83\81\83b\83Z\81[\83W\8c^", nmt);
5790         if (opt_idx == 3) { /* done */
5791             return TRUE;
5792         } else if (opt_idx == 0) { /* add new */
5793             mtbuf[0] = '\0';
5794 /*JP
5795             getlin("What new message pattern?", mtbuf);
5796 */
5797             getlin("\90V\82µ\82¢\83\81\83b\83Z\81[\83W\83p\83^\81[\83\93\81F", mtbuf);
5798             if (*mtbuf == '\033')
5799                 return TRUE;
5800             if (*mtbuf
5801                 && test_regex_pattern(mtbuf, (const char *)0)
5802                 && (mttyp = query_msgtype()) != -1
5803                 && !msgtype_add(mttyp, mtbuf)) {
5804 /*JP
5805                 pline("Error adding the message type.");
5806 */
5807                 pline("\83\81\83b\83Z\81[\83W\8c^\92Ç\89Á\83G\83\89\81[\81D");
5808                 wait_synch();
5809             }
5810             goto msgtypes_again;
5811         } else { /* list (1) or remove (2) */
5812             int pick_idx, pick_cnt;
5813             int mt_idx;
5814             unsigned ln;
5815             const char *mtype;
5816             menu_item *pick_list = (menu_item *) 0;
5817             struct plinemsg_type *tmp = plinemsg_types;
5818
5819             tmpwin = create_nhwindow(NHW_MENU);
5820             start_menu(tmpwin);
5821             any = zeroany;
5822             mt_idx = 0;
5823             while (tmp) {
5824                 mtype = msgtype2name(tmp->msgtype);
5825                 any.a_int = ++mt_idx;
5826                 Sprintf(mtbuf, "%-5s \"", mtype);
5827                 ln = sizeof mtbuf - strlen(mtbuf) - sizeof "\"";
5828                 if (strlen(tmp->pattern) > ln)
5829                     Strcat(strncat(mtbuf, tmp->pattern, ln - 3), "...\"");
5830                 else
5831                     Strcat(strcat(mtbuf, tmp->pattern), "\"");
5832                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mtbuf,
5833                          MENU_UNSELECTED);
5834                 tmp = tmp->next;
5835             }
5836 #if 0 /*JP:T*/
5837             Sprintf(mtbuf, "%s message types",
5838                     (opt_idx == 1) ? "List of" : "Remove which");
5839 #else
5840             Strcpy(mtbuf, (opt_idx == 1) ?
5841                     "\83\81\83b\83Z\81[\83W\8c^\88ê\97\97" : "\8dí\8f\9c\82·\82é\83\81\83b\83Z\81[\83W\8c^");
5842 #endif
5843             end_menu(tmpwin, mtbuf);
5844             pick_cnt = select_menu(tmpwin,
5845                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
5846                                    &pick_list);
5847             if (pick_cnt > 0) {
5848                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
5849                     free_one_msgtype(pick_list[pick_idx].item.a_int - 1
5850                                            - pick_idx);
5851                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
5852             }
5853             destroy_nhwindow(tmpwin);
5854             if (pick_cnt >= 0)
5855                 goto msgtypes_again;
5856         }
5857     } else if (!strcmp("menu_colors", optname)) {
5858         int opt_idx, nmc, mcclr, mcattr;
5859         char mcbuf[BUFSZ];
5860
5861  menucolors_again:
5862         nmc = count_menucolors();
5863 /*JP
5864         opt_idx = handle_add_list_remove("menucolor", nmc);
5865 */
5866         opt_idx = handle_add_list_remove("\83\81\83j\83\85\81[\90F", nmc);
5867         if (opt_idx == 3) { /* done */
5868  menucolors_done:
5869             /* in case we've made a change which impacts current persistent
5870                inventory window; we don't track whether an actual changed
5871                occurred, so just assume there was one and that it matters;
5872                if we're wrong, a redundant update is cheap... */
5873             if (iflags.use_menu_color)
5874                 update_inventory();
5875
5876             /* menu colors aren't being used; if any are defined, remind
5877                player how to use them */
5878             else if (nmc > 0)
5879                 pline(
5880     "To have menu colors become active, toggle 'menucolors' option to True.");
5881             return TRUE;
5882
5883         } else if (opt_idx == 0) { /* add new */
5884             mcbuf[0] = '\0';
5885 /*JP
5886             getlin("What new menucolor pattern?", mcbuf);
5887 */
5888             getlin("\90V\82µ\82¢\83\81\83j\83\85\81[\90F\83p\83^\81[\83\93\81F", mcbuf);
5889             if (*mcbuf == '\033')
5890                 goto menucolors_done;
5891             if (*mcbuf
5892                 && test_regex_pattern(mcbuf, (const char *)0)
5893                 && (mcclr = query_color((char *) 0)) != -1
5894                 && (mcattr = query_attr((char *) 0)) != -1
5895                 && !add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) {
5896 /*JP
5897                 pline("Error adding the menu color.");
5898 */
5899                 pline("\83\81\83j\83\85\81[\90F\92Ç\89Á\83G\83\89\81[\81D");
5900                 wait_synch();
5901             }
5902             goto menucolors_again;
5903
5904         } else { /* list (1) or remove (2) */
5905             int pick_idx, pick_cnt;
5906             int mc_idx;
5907             unsigned ln;
5908             const char *sattr, *sclr;
5909             menu_item *pick_list = (menu_item *) 0;
5910             struct menucoloring *tmp = menu_colorings;
5911             char clrbuf[QBUFSZ];
5912
5913             tmpwin = create_nhwindow(NHW_MENU);
5914             start_menu(tmpwin);
5915             any = zeroany;
5916             mc_idx = 0;
5917             while (tmp) {
5918                 sattr = attr2attrname(tmp->attr);
5919                 sclr = strcpy(clrbuf, clr2colorname(tmp->color));
5920                 (void) strNsubst(clrbuf, " ", "-", 0);
5921                 any.a_int = ++mc_idx;
5922                 /* construct suffix */
5923                 Sprintf(buf, "\"\"=%s%s%s", sclr,
5924                         (tmp->attr != ATR_NONE) ? "&" : "",
5925                         (tmp->attr != ATR_NONE) ? sattr : "");
5926                 /* now main string */
5927                 ln = sizeof buf - strlen(buf) - 1; /* length available */
5928                 Strcpy(mcbuf, "\"");
5929                 if (strlen(tmp->origstr) > ln)
5930                     Strcat(strncat(mcbuf, tmp->origstr, ln - 3), "...");
5931                 else
5932                     Strcat(mcbuf, tmp->origstr);
5933                 /* combine main string and suffix */
5934                 Strcat(mcbuf, &buf[1]); /* skip buf[]'s initial quote */
5935                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mcbuf,
5936                          MENU_UNSELECTED);
5937                 tmp = tmp->next;
5938             }
5939 #if 0 /*JP:T*/
5940             Sprintf(mcbuf, "%s menu colors",
5941                     (opt_idx == 1) ? "List of" : "Remove which");
5942 #else
5943             Strcpy(mcbuf, (opt_idx == 1) ?
5944                     "\83\81\83j\83\85\81[\90F\88ê\97\97" : "\8dí\8f\9c\82·\82é\83\81\83j\83\85\81[\90F");
5945 #endif
5946             end_menu(tmpwin, mcbuf);
5947             pick_cnt = select_menu(tmpwin,
5948                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
5949                                    &pick_list);
5950             if (pick_cnt > 0) {
5951                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
5952                     free_one_menu_coloring(pick_list[pick_idx].item.a_int - 1
5953                                            - pick_idx);
5954                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
5955             }
5956             destroy_nhwindow(tmpwin);
5957             if (pick_cnt >= 0)
5958                 goto menucolors_again;
5959         }
5960     } else if (!strcmp("autopickup_exception", optname)) {
5961         int opt_idx, numapes = 0;
5962         char apebuf[2 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */
5963         struct autopickup_exception *ape;
5964
5965  ape_again:
5966         numapes = count_apes();
5967 /*JP
5968         opt_idx = handle_add_list_remove("autopickup exception", numapes);
5969 */
5970         opt_idx = handle_add_list_remove("\8e©\93®\8fE\82¢\97á\8aO", numapes);
5971         if (opt_idx == 3) { /* done */
5972             return TRUE;
5973         } else if (opt_idx == 0) { /* add new */
5974             /* EDIT_GETLIN:  assume user doesn't user want previous
5975                exception used as default input string for this one... */
5976             apebuf[0] = apebuf[1] = '\0';
5977 /*JP
5978             getlin("What new autopickup exception pattern?", &apebuf[1]);
5979 */
5980             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]);
5981             mungspaces(&apebuf[1]); /* regularize whitespace */
5982             if (apebuf[1] == '\033')
5983                 return TRUE;
5984             if (apebuf[1]) {
5985                 apebuf[0] = '\"';
5986                 /* guarantee room for \" prefix and \"\0 suffix;
5987                    -2 is good enough for apebuf[] but -3 makes
5988                    sure the whole thing fits within normal BUFSZ */
5989                 apebuf[sizeof apebuf - 2] = '\0';
5990                 Strcat(apebuf, "\"");
5991                 add_autopickup_exception(apebuf);
5992             }
5993             goto ape_again;
5994         } else { /* list (1) or remove (2) */
5995             int pick_idx, pick_cnt;
5996             menu_item *pick_list = (menu_item *) 0;
5997
5998             tmpwin = create_nhwindow(NHW_MENU);
5999             start_menu(tmpwin);
6000             if (numapes) {
6001                 ape = apelist;
6002                 any = zeroany;
6003 #if 0 /*JP:T*/
6004                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
6005                          "Always pickup '<'; never pickup '>'",
6006                          MENU_UNSELECTED);
6007 #else
6008                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
6009                          "\8fí\82É\8fE\82¤ '<'; \8fí\82É\8fE\82í\82È\82¢ '>'",
6010                          MENU_UNSELECTED);
6011 #endif
6012                 for (i = 0; i < numapes && ape; i++) {
6013                     any.a_void = (opt_idx == 1) ? 0 : ape;
6014                     /* length of pattern plus quotes (plus '<'/'>') is
6015                        less than BUFSZ */
6016                     Sprintf(apebuf, "\"%c%s\"", ape->grab ? '<' : '>',
6017                             ape->pattern);
6018                     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf,
6019                              MENU_UNSELECTED);
6020                     ape = ape->next;
6021                 }
6022             }
6023 #if 0 /*JP*/
6024             Sprintf(apebuf, "%s autopickup exceptions",
6025                     (opt_idx == 1) ? "List of" : "Remove which");
6026 #else
6027             Sprintf(apebuf, "%s\8e©\93®\8fE\82¢\97á\8aO%s",
6028                     (opt_idx == 1) ? "" : "\82Ç\82Ì",
6029                     (opt_idx == 1) ? "\82Ì\88ê\97\97" : "\82ð\8dí\8f\9c\82µ\82Ü\82·\82©\81H");
6030 #endif
6031             end_menu(tmpwin, apebuf);
6032             pick_cnt = select_menu(tmpwin,
6033                                    (opt_idx == 1) ? PICK_NONE : PICK_ANY,
6034                                    &pick_list);
6035             if (pick_cnt > 0) {
6036                 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
6037                     remove_autopickup_exception(
6038                                          (struct autopickup_exception *)
6039                                              pick_list[pick_idx].item.a_void);
6040                 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
6041             }
6042             destroy_nhwindow(tmpwin);
6043             if (pick_cnt >= 0)
6044                 goto ape_again;
6045         }
6046     } else if (!strcmp("symset", optname)
6047                || !strcmp("roguesymset", optname)) {
6048         menu_item *symset_pick = (menu_item *) 0;
6049         boolean rogueflag = (*optname == 'r'),
6050                 ready_to_switch = FALSE,
6051                 nothing_to_do = FALSE;
6052         char *symset_name, fmtstr[20];
6053         struct symsetentry *sl;
6054         int res, which_set, setcount = 0, chosen = -2, defindx = 0;
6055
6056         which_set = rogueflag ? ROGUESET : PRIMARY;
6057         symset_list = (struct symsetentry *) 0;
6058         /* clear symset[].name as a flag to read_sym_file() to build list */
6059         symset_name = symset[which_set].name;
6060         symset[which_set].name = (char *) 0;
6061
6062         res = read_sym_file(which_set);
6063         /* put symset name back */
6064         symset[which_set].name = symset_name;
6065
6066         if (res && symset_list) {
6067             int thissize,
6068                 biggest = (int) (sizeof "Default Symbols" - sizeof ""),
6069                 big_desc = 0;
6070
6071             for (sl = symset_list; sl; sl = sl->next) {
6072                 /* check restrictions */
6073                 if (rogueflag ? sl->primary : sl->rogue)
6074                     continue;
6075 #ifndef MAC_GRAPHICS_ENV
6076                 if (sl->handling == H_MAC)
6077                     continue;
6078 #endif
6079
6080                 setcount++;
6081                 /* find biggest name */
6082                 thissize = sl->name ? (int) strlen(sl->name) : 0;
6083                 if (thissize > biggest)
6084                     biggest = thissize;
6085                 thissize = sl->desc ? (int) strlen(sl->desc) : 0;
6086                 if (thissize > big_desc)
6087                     big_desc = thissize;
6088             }
6089             if (!setcount) {
6090 #if 0 /*JP:T*/
6091                 pline("There are no appropriate %s symbol sets available.",
6092                       rogueflag ? "rogue level" : "primary");
6093 #else
6094                 pline("\93K\90Ø\82È%s\83V\83\93\83{\83\8b\90Ý\92è\82ª\82 \82è\82Ü\82¹\82ñ\81D",
6095                       rogueflag ? "rogue\83\8c\83x\83\8b" : "\97D\90æ");
6096 #endif
6097                 return TRUE;
6098             }
6099
6100             Sprintf(fmtstr, "%%-%ds %%s", biggest + 2);
6101             tmpwin = create_nhwindow(NHW_MENU);
6102             start_menu(tmpwin);
6103             any = zeroany;
6104             any.a_int = 1; /* -1 + 2 [see 'if (sl->name) {' below]*/
6105             if (!symset_name)
6106                 defindx = any.a_int;
6107             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
6108                      "Default Symbols",
6109                      (any.a_int == defindx) ? MENU_SELECTED
6110                                             : MENU_UNSELECTED);
6111
6112             for (sl = symset_list; sl; sl = sl->next) {
6113                 /* check restrictions */
6114                 if (rogueflag ? sl->primary : sl->rogue)
6115                     continue;
6116 #ifndef MAC_GRAPHICS_ENV
6117                 if (sl->handling == H_MAC)
6118                     continue;
6119 #endif
6120                 if (sl->name) {
6121                     /* +2: sl->idx runs from 0 to N-1 for N symsets;
6122                        +1 because Defaults are implicitly in slot [0];
6123                        +1 again so that valid data is never 0 */
6124                     any.a_int = sl->idx + 2;
6125                     if (symset_name && !strcmpi(sl->name, symset_name))
6126                         defindx = any.a_int;
6127                     Sprintf(buf, fmtstr, sl->name, sl->desc ? sl->desc : "");
6128                     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
6129                              (any.a_int == defindx) ? MENU_SELECTED
6130                                                     : MENU_UNSELECTED);
6131                 }
6132             }
6133 #if 0 /*JP:T*/
6134             Sprintf(buf, "Select %ssymbol set:",
6135                     rogueflag ? "rogue level " : "");
6136 #else
6137             Sprintf(buf, "%s\83V\83\93\83{\83\8b\90Ý\92è\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢\81F",
6138                     rogueflag ? "rogue\83\8c\83x\83\8b" : "");
6139 #endif
6140             end_menu(tmpwin, buf);
6141             n = select_menu(tmpwin, PICK_ONE, &symset_pick);
6142             if (n > 0) {
6143                 chosen = symset_pick[0].item.a_int;
6144                 /* if picking non-preselected entry yields 2, make sure
6145                    that we're going with the non-preselected one */
6146                 if (n == 2 && chosen == defindx)
6147                     chosen = symset_pick[1].item.a_int;
6148                 chosen -= 2; /* convert menu index to symset index;
6149                               * "Default symbols" have index -1 */
6150                 free((genericptr_t) symset_pick);
6151             } else if (n == 0 && defindx > 0) {
6152                 chosen = defindx - 2;
6153             }
6154             destroy_nhwindow(tmpwin);
6155
6156             if (chosen > -1) {
6157                 /* chose an actual symset name from file */
6158                 for (sl = symset_list; sl; sl = sl->next)
6159                     if (sl->idx == chosen)
6160                         break;
6161                 if (sl) {
6162                     /* free the now stale attributes */
6163                     clear_symsetentry(which_set, TRUE);
6164
6165                     /* transfer only the name of the symbol set */
6166                     symset[which_set].name = dupstr(sl->name);
6167                     ready_to_switch = TRUE;
6168                 }
6169             } else if (chosen == -1) {
6170                 /* explicit selection of defaults */
6171                 /* free the now stale symset attributes */
6172                 clear_symsetentry(which_set, TRUE);
6173             } else
6174                 nothing_to_do = TRUE;
6175         } else if (!res) {
6176             /* The symbols file could not be accessed */
6177 /*JP
6178             pline("Unable to access \"%s\" file.", SYMBOLS);
6179 */
6180             pline("\"%s\"\83t\83@\83C\83\8b\82É\83A\83N\83Z\83X\82Å\82«\82Ü\82¹\82ñ\81D", SYMBOLS);
6181             return TRUE;
6182         } else if (!symset_list) {
6183             /* The symbols file was empty */
6184 /*JP
6185             pline("There were no symbol sets found in \"%s\".", SYMBOLS);
6186 */
6187             pline("\"%s\"\82É\83V\83\93\83{\83\8b\90Ý\92è\82ª\82 \82è\82Ü\82¹\82ñ\81D", SYMBOLS);
6188             return TRUE;
6189         }
6190
6191         /* clean up */
6192         while ((sl = symset_list) != 0) {
6193             symset_list = sl->next;
6194             if (sl->name)
6195                 free((genericptr_t) sl->name), sl->name = (char *) 0;
6196             if (sl->desc)
6197                 free((genericptr_t) sl->desc), sl->desc = (char *) 0;
6198             free((genericptr_t) sl);
6199         }
6200
6201         if (nothing_to_do)
6202             return TRUE;
6203
6204         /* Set default symbols and clear the handling value */
6205         if (rogueflag)
6206             init_rogue_symbols();
6207         else
6208             init_primary_symbols();
6209
6210         if (symset[which_set].name) {
6211             /* non-default symbols */
6212             if (read_sym_file(which_set)) {
6213                 ready_to_switch = TRUE;
6214             } else {
6215                 clear_symsetentry(which_set, TRUE);
6216                 return TRUE;
6217             }
6218         }
6219
6220         if (ready_to_switch)
6221             switch_symbols(TRUE);
6222
6223         if (Is_rogue_level(&u.uz)) {
6224             if (rogueflag)
6225                 assign_graphics(ROGUESET);
6226         } else if (!rogueflag)
6227             assign_graphics(PRIMARY);
6228         preference_update("symset");
6229         need_redraw = TRUE;
6230 #ifdef WIN32
6231     } else if (!strcmp("altkeyhandler", optname)
6232                || !strcmp("altkeyhandling", optname)) {
6233         return set_keyhandling_via_option();
6234 #endif
6235     } else {
6236         /* didn't match any of the special options */
6237         return FALSE;
6238     }
6239     return TRUE;
6240 }
6241
6242 #define rolestring(val, array, field) \
6243     ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none)
6244
6245 /* This is ugly. We have all the option names in the compopt[] array,
6246    but we need to look at each option individually to get the value. */
6247 STATIC_OVL const char *
6248 get_compopt_value(optname, buf)
6249 const char *optname;
6250 char *buf;
6251 {
6252 #if 0 /*JP:T*/
6253     static const char none[] = "(none)", randomrole[] = "random",
6254                       to_be_done[] = "(to be done)",
6255                       defopt[] = "default", defbrief[] = "def";
6256 #else
6257     static const char none[] = "(\82È\82µ)", randomrole[] = "\83\89\83\93\83_\83\80",
6258                       to_be_done[] = "(\96¢\90Ý\92è)",
6259                       defopt[] = "\83f\83t\83H\83\8b\83g", defbrief[] = "def";
6260 #endif
6261     char ocl[MAXOCLASSES + 1];
6262     int i;
6263
6264     buf[0] = '\0';
6265     if (!strcmp(optname, "align_message")
6266         || !strcmp(optname, "align_status")) {
6267         int which = !strcmp(optname, "align_status") ? iflags.wc_align_status
6268                                                      : iflags.wc_align_message;
6269 #if 0 /*JP:T*/
6270         Sprintf(buf, "%s",
6271                 (which == ALIGN_TOP) ? "top"
6272                 : (which == ALIGN_LEFT) ? "left"
6273                   : (which == ALIGN_BOTTOM) ? "bottom"
6274                     : (which == ALIGN_RIGHT) ? "right"
6275                       : defopt);
6276 #else
6277         Sprintf(buf, "%s",
6278                 (which == ALIGN_TOP) ? "\8fã\91¤"
6279                 : (which == ALIGN_LEFT) ? "\8d\91¤"
6280                   : (which == ALIGN_BOTTOM) ? "\89º\91¤"
6281                     : (which == ALIGN_RIGHT) ? "\89E\91¤"
6282                       : defopt);
6283 #endif
6284     } else if (!strcmp(optname, "align"))
6285 #if 0 /*JP*/
6286         Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
6287 #else
6288         Sprintf(buf, "%s", rolestring(flags.initalign, aligns, noun));
6289 #endif
6290 #ifdef WIN32
6291     else if (!strcmp(optname, "altkeyhandler"))
6292         Sprintf(buf, "%s",
6293                 (iflags.key_handling == ray_keyhandling)
6294                     ? "ray"
6295                     : (iflags.key_handling == nh340_keyhandling)
6296                         ? "340"
6297                         : "default");
6298 #endif
6299 #ifdef BACKWARD_COMPAT
6300     else if (!strcmp(optname, "boulder"))
6301         Sprintf(buf, "%c",
6302                 ov_primary_syms[SYM_BOULDER + SYM_OFF_X]
6303                     ? ov_primary_syms[SYM_BOULDER + SYM_OFF_X]
6304                     : showsyms[(int) objects[BOULDER].oc_class + SYM_OFF_O]);
6305 #endif
6306     else if (!strcmp(optname, "catname"))
6307         Sprintf(buf, "%s", catname[0] ? catname : none);
6308     else if (!strcmp(optname, "disclose"))
6309         for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
6310             if (i)
6311                 (void) strkitten(buf, ' ');
6312             (void) strkitten(buf, flags.end_disclose[i]);
6313             (void) strkitten(buf, disclosure_options[i]);
6314         }
6315     else if (!strcmp(optname, "dogname"))
6316         Sprintf(buf, "%s", dogname[0] ? dogname : none);
6317     else if (!strcmp(optname, "dungeon"))
6318         Sprintf(buf, "%s", to_be_done);
6319     else if (!strcmp(optname, "effects"))
6320         Sprintf(buf, "%s", to_be_done);
6321     else if (!strcmp(optname, "font_map"))
6322         Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
6323     else if (!strcmp(optname, "font_message"))
6324         Sprintf(buf, "%s",
6325                 iflags.wc_font_message ? iflags.wc_font_message : defopt);
6326     else if (!strcmp(optname, "font_status"))
6327         Sprintf(buf, "%s",
6328                 iflags.wc_font_status ? iflags.wc_font_status : defopt);
6329     else if (!strcmp(optname, "font_menu"))
6330         Sprintf(buf, "%s",
6331                 iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
6332     else if (!strcmp(optname, "font_text"))
6333         Sprintf(buf, "%s",
6334                 iflags.wc_font_text ? iflags.wc_font_text : defopt);
6335     else if (!strcmp(optname, "font_size_map")) {
6336         if (iflags.wc_fontsiz_map)
6337             Sprintf(buf, "%d", iflags.wc_fontsiz_map);
6338         else
6339             Strcpy(buf, defopt);
6340     } else if (!strcmp(optname, "font_size_message")) {
6341         if (iflags.wc_fontsiz_message)
6342             Sprintf(buf, "%d", iflags.wc_fontsiz_message);
6343         else
6344             Strcpy(buf, defopt);
6345     } else if (!strcmp(optname, "font_size_status")) {
6346         if (iflags.wc_fontsiz_status)
6347             Sprintf(buf, "%d", iflags.wc_fontsiz_status);
6348         else
6349             Strcpy(buf, defopt);
6350     } else if (!strcmp(optname, "font_size_menu")) {
6351         if (iflags.wc_fontsiz_menu)
6352             Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
6353         else
6354             Strcpy(buf, defopt);
6355     } else if (!strcmp(optname, "font_size_text")) {
6356         if (iflags.wc_fontsiz_text)
6357             Sprintf(buf, "%d", iflags.wc_fontsiz_text);
6358         else
6359             Strcpy(buf, defopt);
6360     } else if (!strcmp(optname, "fruit"))
6361         Sprintf(buf, "%s", pl_fruit);
6362     else if (!strcmp(optname, "gender"))
6363         Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
6364     else if (!strcmp(optname, "horsename"))
6365         Sprintf(buf, "%s", horsename[0] ? horsename : none);
6366     else if (!strcmp(optname, "map_mode")) {
6367         i = iflags.wc_map_mode;
6368         Sprintf(buf, "%s",
6369                 (i == MAP_MODE_TILES) ? "tiles"
6370                 : (i == MAP_MODE_ASCII4x6) ? "ascii4x6"
6371                   : (i == MAP_MODE_ASCII6x8) ? "ascii6x8"
6372                     : (i == MAP_MODE_ASCII8x8) ? "ascii8x8"
6373                       : (i == MAP_MODE_ASCII16x8) ? "ascii16x8"
6374                         : (i == MAP_MODE_ASCII7x12) ? "ascii7x12"
6375                           : (i == MAP_MODE_ASCII8x12) ? "ascii8x12"
6376                             : (i == MAP_MODE_ASCII16x12) ? "ascii16x12"
6377                               : (i == MAP_MODE_ASCII12x16) ? "ascii12x16"
6378                                 : (i == MAP_MODE_ASCII10x18) ? "ascii10x18"
6379                                   : (i == MAP_MODE_ASCII_FIT_TO_SCREEN)
6380                                     ? "fit_to_screen"
6381                                     : defopt);
6382     } else if (!strcmp(optname, "menustyle"))
6383         Sprintf(buf, "%s", menutype[(int) flags.menu_style]);
6384     else if (!strcmp(optname, "menu_deselect_all"))
6385         Sprintf(buf, "%s", to_be_done);
6386     else if (!strcmp(optname, "menu_deselect_page"))
6387         Sprintf(buf, "%s", to_be_done);
6388     else if (!strcmp(optname, "menu_first_page"))
6389         Sprintf(buf, "%s", to_be_done);
6390     else if (!strcmp(optname, "menu_invert_all"))
6391         Sprintf(buf, "%s", to_be_done);
6392     else if (!strcmp(optname, "menu_headings"))
6393         Sprintf(buf, "%s", attr2attrname(iflags.menu_headings));
6394     else if (!strcmp(optname, "menu_invert_page"))
6395         Sprintf(buf, "%s", to_be_done);
6396     else if (!strcmp(optname, "menu_last_page"))
6397         Sprintf(buf, "%s", to_be_done);
6398     else if (!strcmp(optname, "menu_next_page"))
6399         Sprintf(buf, "%s", to_be_done);
6400     else if (!strcmp(optname, "menu_previous_page"))
6401         Sprintf(buf, "%s", to_be_done);
6402     else if (!strcmp(optname, "menu_search"))
6403         Sprintf(buf, "%s", to_be_done);
6404     else if (!strcmp(optname, "menu_select_all"))
6405         Sprintf(buf, "%s", to_be_done);
6406     else if (!strcmp(optname, "menu_select_page"))
6407         Sprintf(buf, "%s", to_be_done);
6408     else if (!strcmp(optname, "monsters")) {
6409         Sprintf(buf, "%s", to_be_done);
6410     } else if (!strcmp(optname, "msghistory")) {
6411         Sprintf(buf, "%u", iflags.msg_history);
6412 #ifdef TTY_GRAPHICS
6413     } else if (!strcmp(optname, "msg_window")) {
6414         Sprintf(buf, "%s", (iflags.prevmsg_window == 's') ? "single"
6415                            : (iflags.prevmsg_window == 'c') ? "combination"
6416                              : (iflags.prevmsg_window == 'f') ? "full"
6417                                : "reversed");
6418 #endif
6419     } else if (!strcmp(optname, "name")) {
6420         Sprintf(buf, "%s", plname);
6421     } else if (!strcmp(optname, "mouse_support")) {
6422 #ifdef WIN32
6423 #define MOUSEFIX1 ", QuickEdit off"
6424 #define MOUSEFIX2 ", QuickEdit unchanged"
6425 #else
6426 #define MOUSEFIX1 ", O/S adjusted"
6427 #define MOUSEFIX2 ", O/S unchanged"
6428 #endif
6429         static const char *mousemodes[][2] = {
6430             { "0=off", "" },
6431             { "1=on",  MOUSEFIX1 },
6432             { "2=on",  MOUSEFIX2 },
6433         };
6434 #undef MOUSEFIX1
6435 #undef MOUSEFIX2
6436         int ms = iflags.wc_mouse_support;
6437
6438         if (ms >= 0 && ms <= 2)
6439             Sprintf(buf, "%s%s", mousemodes[ms][0], mousemodes[ms][1]);
6440     } else if (!strcmp(optname, "number_pad")) {
6441         static const char *numpadmodes[] = {
6442 /*JP
6443             "0=off", "1=on", "2=on, MSDOS compatible",
6444 */
6445             "0=\96³\8cø", "1=\97L\8cø", "2=\97L\8cø\81CDOS\8cÝ\8a·",
6446 /*JP
6447             "3=on, phone-style layout",
6448 */
6449             "3=\97L\8cø\81C\93d\98b\8e®\82Ì\90\94\8e\9a\94z\92u",
6450 /*JP
6451             "4=on, phone layout, MSDOS compatible",
6452 */
6453             "4=\97L\8cø\81C\93d\98b\8e®\82Ì\94z\92u\81CMSDOS \8cÝ\8a·",
6454 #if 0 /*JP:T*/
6455             "-1=off, y & z swapped", /*[5]*/
6456 #else
6457             "-1=\96³\8cø\81Cy\82Æz\82ð\93ü\82ê\91Ö\82¦", /*[5]*/
6458 #endif
6459         };
6460         int indx = Cmd.num_pad
6461                        ? (Cmd.phone_layout ? (Cmd.pcHack_compat ? 4 : 3)
6462                                            : (Cmd.pcHack_compat ? 2 : 1))
6463                        : Cmd.swap_yz ? 5 : 0;
6464
6465         Strcpy(buf, numpadmodes[indx]);
6466     } else if (!strcmp(optname, "objects")) {
6467         Sprintf(buf, "%s", to_be_done);
6468     } else if (!strcmp(optname, "packorder")) {
6469         oc_to_str(flags.inv_order, ocl);
6470         Sprintf(buf, "%s", ocl);
6471 #ifdef CHANGE_COLOR
6472     } else if (!strcmp(optname, "palette")) {
6473         Sprintf(buf, "%s", get_color_string());
6474 #endif
6475     } else if (!strcmp(optname, "paranoid_confirmation")) {
6476         char tmpbuf[QBUFSZ];
6477
6478         tmpbuf[0] = '\0';
6479         for (i = 0; paranoia[i].flagmask != 0; ++i)
6480             if (flags.paranoia_bits & paranoia[i].flagmask)
6481                 Sprintf(eos(tmpbuf), " %s", paranoia[i].argname);
6482         Strcpy(buf, tmpbuf[0] ? &tmpbuf[1] : "none");
6483     } else if (!strcmp(optname, "petattr")) {
6484 #ifdef CURSES_GRAPHICS
6485         if (WINDOWPORT("curses")) {
6486             char tmpbuf[QBUFSZ];
6487
6488             Strcpy(buf, curses_fmt_attrs(tmpbuf));
6489         } else
6490 #endif
6491         if (iflags.wc2_petattr != 0)
6492             Sprintf(buf, "0x%08x", iflags.wc2_petattr);
6493         else
6494             Strcpy(buf, defopt);
6495     } else if (!strcmp(optname, "pettype")) {
6496 #if 0 /*JP:T*/
6497         Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat"
6498                            : (preferred_pet == 'd') ? "dog"
6499                              : (preferred_pet == 'h') ? "horse"
6500                                : (preferred_pet == 'n') ? "none"
6501                                  : "random");
6502 #else
6503         Sprintf(buf, "%s", (preferred_pet == 'c') ? "\94L"
6504                            : (preferred_pet == 'd') ? "\8c¢"
6505                              : (preferred_pet == 'h') ? "\94n"
6506                                : (preferred_pet == 'n') ? "\82È\82µ"
6507                                  : "\83\89\83\93\83_\83\80");
6508 #endif
6509     } else if (!strcmp(optname, "pickup_burden")) {
6510         Sprintf(buf, "%s", burdentype[flags.pickup_burden]);
6511     } else if (!strcmp(optname, "pickup_types")) {
6512         oc_to_str(flags.pickup_types, ocl);
6513         Sprintf(buf, "%s", ocl[0] ? ocl : "all");
6514     } else if (!strcmp(optname, "pile_limit")) {
6515         Sprintf(buf, "%d", flags.pile_limit);
6516     } else if (!strcmp(optname, "playmode")) {
6517         Strcpy(buf, wizard ? "debug" : discover ? "explore" : "normal");
6518     } else if (!strcmp(optname, "race")) {
6519         Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
6520     } else if (!strcmp(optname, "roguesymset")) {
6521         Sprintf(buf, "%s",
6522                 symset[ROGUESET].name ? symset[ROGUESET].name : "default");
6523         if (currentgraphics == ROGUESET && symset[ROGUESET].name)
6524             Strcat(buf, ", active");
6525     } else if (!strcmp(optname, "role")) {
6526         Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
6527     } else if (!strcmp(optname, "runmode")) {
6528         Sprintf(buf, "%s", runmodes[flags.runmode]);
6529     } else if (!strcmp(optname, "whatis_coord")) {
6530         Sprintf(buf, "%s",
6531                 (iflags.getpos_coords == GPCOORDS_MAP) ? "map"
6532                 : (iflags.getpos_coords == GPCOORDS_COMPASS) ? "compass"
6533                 : (iflags.getpos_coords == GPCOORDS_COMFULL) ? "full compass"
6534                 : (iflags.getpos_coords == GPCOORDS_SCREEN) ? "screen"
6535                 : "none");
6536     } else if (!strcmp(optname, "whatis_filter")) {
6537         Sprintf(buf, "%s",
6538                 (iflags.getloc_filter == GFILTER_VIEW) ? "view"
6539                 : (iflags.getloc_filter == GFILTER_AREA) ? "area"
6540                 : "none");
6541     } else if (!strcmp(optname, "scores")) {
6542         Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around,
6543                 flags.end_own ? "/own" : "");
6544     } else if (!strcmp(optname, "scroll_amount")) {
6545         if (iflags.wc_scroll_amount)
6546             Sprintf(buf, "%d", iflags.wc_scroll_amount);
6547         else
6548             Strcpy(buf, defopt);
6549     } else if (!strcmp(optname, "scroll_margin")) {
6550         if (iflags.wc_scroll_margin)
6551             Sprintf(buf, "%d", iflags.wc_scroll_margin);
6552         else
6553             Strcpy(buf, defopt);
6554     } else if (!strcmp(optname, "sortloot")) {
6555         for (i = 0; i < SIZE(sortltype); i++)
6556             if (flags.sortloot == sortltype[i][0]) {
6557                 Strcpy(buf, sortltype[i]);
6558                 break;
6559             }
6560     } else if (!strcmp(optname, "player_selection")) {
6561 #if 0 /*JP:T*/
6562         Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
6563 #else
6564         Sprintf(buf, "%s\93ü\97Í", iflags.wc_player_selection ? "\83v\83\8d\83\93\83v\83g" : "\83_\83C\83A\83\8d\83O");
6565 #endif
6566 #ifdef MSDOS
6567     } else if (!strcmp(optname, "soundcard")) {
6568         Sprintf(buf, "%s", to_be_done);
6569 #endif
6570 #ifdef STATUS_HILITES
6571     } else if (!strcmp("statushilites", optname)) {
6572         if (!iflags.hilite_delta)
6573             Strcpy(buf, "0 (off: don't highlight status fields)");
6574         else
6575             Sprintf(buf, "%ld (on: highlight status for %ld turns)",
6576                     iflags.hilite_delta, iflags.hilite_delta);
6577 #endif
6578     } else if (!strcmp(optname,"statuslines")) {
6579         if (wc2_supported(optname))
6580             Strcpy(buf, (iflags.wc2_statuslines < 3) ? "2" : "3");
6581         /* else default to "unknown" */
6582     } else if (!strcmp(optname, "suppress_alert")) {
6583         if (flags.suppress_alert == 0L)
6584             Strcpy(buf, none);
6585         else
6586             Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
6587                     FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
6588     } else if (!strcmp(optname, "symset")) {
6589         Sprintf(buf, "%s",
6590                 symset[PRIMARY].name ? symset[PRIMARY].name : "default");
6591         if (currentgraphics == PRIMARY && symset[PRIMARY].name)
6592             Strcat(buf, ", active");
6593     } else if (!strcmp(optname, "term_cols")) {
6594         if (iflags.wc2_term_cols)
6595             Sprintf(buf, "%d", iflags.wc2_term_cols);
6596         else
6597             Strcpy(buf, defopt);
6598     } else if (!strcmp(optname, "term_rows")) {
6599         if (iflags.wc2_term_rows)
6600             Sprintf(buf, "%d", iflags.wc2_term_rows);
6601         else
6602             Strcpy(buf, defopt);
6603     } else if (!strcmp(optname, "tile_file")) {
6604         Sprintf(buf, "%s",
6605                 iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
6606     } else if (!strcmp(optname, "tile_height")) {
6607         if (iflags.wc_tile_height)
6608             Sprintf(buf, "%d", iflags.wc_tile_height);
6609         else
6610             Strcpy(buf, defopt);
6611     } else if (!strcmp(optname, "tile_width")) {
6612         if (iflags.wc_tile_width)
6613             Sprintf(buf, "%d", iflags.wc_tile_width);
6614         else
6615             Strcpy(buf, defopt);
6616     } else if (!strcmp(optname, "traps")) {
6617         Sprintf(buf, "%s", to_be_done);
6618     } else if (!strcmp(optname, "vary_msgcount")) {
6619         if (iflags.wc_vary_msgcount)
6620             Sprintf(buf, "%d", iflags.wc_vary_msgcount);
6621         else
6622             Strcpy(buf, defopt);
6623 #ifdef MSDOS
6624     } else if (!strcmp(optname, "video")) {
6625         Sprintf(buf, "%s", to_be_done);
6626 #endif
6627 #ifdef VIDEOSHADES
6628     } else if (!strcmp(optname, "videoshades")) {
6629         Sprintf(buf, "%s-%s-%s", shade[0], shade[1], shade[2]);
6630     } else if (!strcmp(optname, "videocolors")) {
6631         Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
6632                 ttycolors[CLR_RED], ttycolors[CLR_GREEN],
6633                 ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
6634                 ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
6635                 ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
6636                 ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
6637                 ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]);
6638 #endif /* VIDEOSHADES */
6639     } else if (!strcmp(optname,"windowborders")) {
6640         Sprintf(buf, "%s",
6641                 (iflags.wc2_windowborders == 0) ? "0=off"
6642                 : (iflags.wc2_windowborders == 1) ? "1=on"
6643                   : (iflags.wc2_windowborders == 2) ? "2=auto"
6644                     : defopt);
6645     } else if (!strcmp(optname, "windowtype")) {
6646         Sprintf(buf, "%s", windowprocs.name);
6647     } else if (!strcmp(optname, "windowcolors")) {
6648         Sprintf(
6649             buf, "%s/%s %s/%s %s/%s %s/%s",
6650             iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
6651             iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
6652             iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message
6653                                        : defbrief,
6654             iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message
6655                                        : defbrief,
6656             iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
6657             iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
6658             iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
6659             iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
6660 #ifdef PREFIXES_IN_USE
6661     } else {
6662         for (i = 0; i < PREFIX_COUNT; ++i)
6663             if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
6664                 Sprintf(buf, "%s", fqn_prefix[i]);
6665 #endif
6666     }
6667
6668     if (!buf[0])
6669 /*JP
6670         Strcpy(buf, "unknown");
6671 */
6672         Strcpy(buf, "\95s\96¾");
6673     return buf;
6674 }
6675
6676 int
6677 dotogglepickup()
6678 {
6679     char buf[BUFSZ], ocl[MAXOCLASSES + 1];
6680
6681     flags.pickup = !flags.pickup;
6682     if (flags.pickup) {
6683         oc_to_str(flags.pickup_types, ocl);
6684 #if 0 /*JP:T*/
6685         Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
6686                 (apelist)
6687                     ? ((count_apes() == 1)
6688                            ? ", with one exception"
6689                            : ", with some exceptions")
6690                     : "");
6691 #else
6692         Sprintf(buf, "%s\83A\83C\83e\83\80\82É\82Â\82¢\82Ä\83I\83\93%s", ocl[0] ? ocl : "\91S\82Ä\82Ì",
6693                 (apelist)
6694                     ? "\81C\97á\8aO\82 \82è"
6695                     : "");
6696 #endif
6697     } else {
6698 /*JP
6699         Strcpy(buf, "OFF");
6700 */
6701         Strcpy(buf, "\83I\83t");
6702     }
6703 /*JP
6704     pline("Autopickup: %s.", buf);
6705 */
6706     pline("\8e©\93®\8fE\82¢\81F%s\81D", buf);
6707     return 0;
6708 }
6709
6710 int
6711 add_autopickup_exception(mapping)
6712 const char *mapping;
6713 {
6714     static const char
6715         APE_regex_error[] = "regex error in AUTOPICKUP_EXCEPTION",
6716         APE_syntax_error[] = "syntax error in AUTOPICKUP_EXCEPTION";
6717
6718     struct autopickup_exception *ape;
6719     char text[256], end;
6720     int n;
6721     boolean grab = FALSE;
6722
6723     /* scan length limit used to be 255, but smaller size allows the
6724        quoted value to fit within BUFSZ, simplifying formatting elsewhere;
6725        this used to ignore the possibility of trailing junk but now checks
6726        for it, accepting whitespace but rejecting anything else unless it
6727        starts with '#" for a comment */
6728     end = '\0';
6729     if ((n = sscanf(mapping, "\"<%253[^\"]\" %c", text, &end)) == 1
6730         || (n == 2 && end == '#')) {
6731         grab = TRUE;
6732     } else if ((n = sscanf(mapping, "\">%253[^\"]\" %c", text, &end)) == 1
6733                || (n = sscanf(mapping, "\"%253[^\"]\" %c", text, &end)) == 1
6734                || (n == 2 && end == '#')) {
6735         grab = FALSE;
6736     } else {
6737         config_error_add("%s", APE_syntax_error);
6738         return 0;
6739     }
6740
6741     ape = (struct autopickup_exception *) alloc(sizeof *ape);
6742     ape->regex = regex_init();
6743     if (!regex_compile(text, ape->regex)) {
6744         config_error_add("%s: %s", APE_regex_error,
6745                          regex_error_desc(ape->regex));
6746         regex_free(ape->regex);
6747         free((genericptr_t) ape);
6748         return 0;
6749     }
6750
6751     ape->pattern = dupstr(text);
6752     ape->grab = grab;
6753     ape->next = apelist;
6754     apelist = ape;
6755     return 1;
6756 }
6757
6758 STATIC_OVL void
6759 remove_autopickup_exception(whichape)
6760 struct autopickup_exception *whichape;
6761 {
6762     struct autopickup_exception *ape, *freeape, *prev = 0;
6763
6764     for (ape = apelist; ape;) {
6765         if (ape == whichape) {
6766             freeape = ape;
6767             ape = ape->next;
6768             if (prev)
6769                 prev->next = ape;
6770             else
6771                 apelist = ape;
6772             regex_free(freeape->regex);
6773             free((genericptr_t) freeape->pattern);
6774             free((genericptr_t) freeape);
6775         } else {
6776             prev = ape;
6777             ape = ape->next;
6778         }
6779     }
6780 }
6781
6782 void
6783 free_autopickup_exceptions()
6784 {
6785     struct autopickup_exception *ape = apelist;
6786
6787     while ((ape = apelist) != 0) {
6788       regex_free(ape->regex);
6789       free((genericptr_t) ape->pattern);
6790       apelist = ape->next;
6791       free((genericptr_t) ape);
6792     }
6793 }
6794
6795 /* bundle some common usage into one easy-to-use routine */
6796 int
6797 load_symset(s, which_set)
6798 const char *s;
6799 int which_set;
6800 {
6801     clear_symsetentry(which_set, TRUE);
6802
6803     if (symset[which_set].name)
6804         free((genericptr_t) symset[which_set].name);
6805     symset[which_set].name = dupstr(s);
6806
6807     if (read_sym_file(which_set)) {
6808         switch_symbols(TRUE);
6809     } else {
6810         clear_symsetentry(which_set, TRUE);
6811         return 0;
6812     }
6813     return 1;
6814 }
6815
6816 void
6817 free_symsets()
6818 {
6819     clear_symsetentry(PRIMARY, TRUE);
6820     clear_symsetentry(ROGUESET, TRUE);
6821
6822     /* symset_list is cleaned up as soon as it's used, so we shouldn't
6823        have to anything about it here */
6824     /* assert( symset_list == NULL ); */
6825 }
6826
6827 /* Parse the value of a SYMBOLS line from a config file */
6828 boolean
6829 parsesymbols(opts, which_set)
6830 register char *opts;
6831 int which_set;
6832 {
6833     int val;
6834     char *op, *symname, *strval;
6835     struct symparse *symp;
6836
6837     if ((op = index(opts, ',')) != 0) {
6838         *op++ = 0;
6839         if (!parsesymbols(op, which_set))
6840             return FALSE;
6841     }
6842
6843     /* S_sample:string */
6844     symname = opts;
6845     strval = index(opts, ':');
6846     if (!strval)
6847         strval = index(opts, '=');
6848     if (!strval)
6849         return FALSE;
6850     *strval++ = '\0';
6851
6852     /* strip leading and trailing white space from symname and strval */
6853     mungspaces(symname);
6854     mungspaces(strval);
6855
6856     symp = match_sym(symname);
6857     if (!symp)
6858         return FALSE;
6859
6860     if (symp->range && symp->range != SYM_CONTROL) {
6861         val = sym_val(strval);
6862         if (which_set == ROGUESET)
6863             update_ov_rogue_symset(symp, val);
6864         else
6865             update_ov_primary_symset(symp, val);
6866     }
6867     return TRUE;
6868 }
6869
6870 struct symparse *
6871 match_sym(buf)
6872 char *buf;
6873 {
6874     size_t len = strlen(buf);
6875     const char *p = index(buf, ':'), *q = index(buf, '=');
6876     struct symparse *sp = loadsyms;
6877
6878     if (!p || (q && q < p))
6879         p = q;
6880     if (p) {
6881         /* note: there will be at most one space before the '='
6882            because caller has condensed buf[] with mungspaces() */
6883         if (p > buf && p[-1] == ' ')
6884             p--;
6885         len = (int) (p - buf);
6886     }
6887     while (sp->range) {
6888         if ((len >= strlen(sp->name)) && !strncmpi(buf, sp->name, len))
6889             return sp;
6890         sp++;
6891     }
6892     return (struct symparse *) 0;
6893 }
6894
6895 int
6896 sym_val(strval)
6897 const char *strval; /* up to 4*BUFSZ-1 long; only first few chars matter */
6898 {
6899     char buf[QBUFSZ], tmp[QBUFSZ]; /* to hold trucated copy of 'strval' */
6900
6901     buf[0] = '\0';
6902     if (!strval[0] || !strval[1]) { /* empty, or single character */
6903         /* if single char is space or tab, leave buf[0]=='\0' */
6904         if (!isspace((uchar) strval[0]))
6905             buf[0] = strval[0];
6906     } else if (strval[0] == '\'') { /* single quote */
6907         /* simple matching single quote; we know strval[1] isn't '\0' */
6908         if (strval[2] == '\'' && !strval[3]) {
6909             /* accepts '\' as backslash and ''' as single quote */
6910             buf[0] = strval[1];
6911
6912         /* if backslash, handle single or double quote or second backslash */
6913         } else if (strval[1] == '\\' && strval[2] && strval[3] == '\''
6914             && index("'\"\\", strval[2]) && !strval[4]) {
6915             buf[0] = strval[2];
6916
6917         /* not simple quote or basic backslash;
6918            strip closing quote and let escapes() deal with it */
6919         } else {
6920             char *p;
6921
6922             /* +1: skip opening single quote */
6923             (void) strncpy(tmp, strval + 1, sizeof tmp - 1);
6924             tmp[sizeof tmp - 1] = '\0';
6925             if ((p = rindex(tmp, '\'')) != 0) {
6926                 *p = '\0';
6927                 escapes(tmp, buf);
6928             } /* else buf[0] stays '\0' */
6929         }
6930     } else { /* not lone char nor single quote */
6931         (void) strncpy(tmp, strval, sizeof tmp - 1);
6932         tmp[sizeof tmp - 1] = '\0';
6933         escapes(tmp, buf);
6934     }
6935
6936     return (int) *buf;
6937 }
6938
6939 /* data for option_help() */
6940 static const char *opt_intro[] = {
6941     "",
6942 /*JP
6943     "                 NetHack Options Help:", "",
6944 */
6945     "               NetHack\83I\83v\83V\83\87\83\93\83w\83\8b\83v\81F", "",
6946 #define CONFIG_SLOT 3 /* fill in next value at run-time */
6947     (char *) 0,
6948 #if !defined(MICRO) && !defined(MAC)
6949 /*JP
6950     "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
6951 */
6952     "\82Ü\82½\82Í\8aÂ\8b«\95Ï\90\94\82É`NETHACKOPTIONS=\"<options>\"'\82Æ\92è\8b`\82Å\82«\82Ü\82·",
6953 #endif
6954 /*JP
6955     "(<options> is a list of options separated by commas)",
6956 */
6957     "(<options>\82Í\83J\83\93\83}\82Å\8bæ\90Ø\82Á\82½\83I\83v\83V\83\87\83\93\82Å\82·)",
6958 #ifdef VMS
6959 /*JP
6960     "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
6961 */
6962     "-- \97á\82¦\82Î\8e\9f\82Ì\82æ\82¤\82É\82µ\82Ü\82·\81F$ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
6963 #endif
6964 /*JP
6965     "or press \"O\" while playing and use the menu.",
6966 */
6967     "\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",
6968     "",
6969 /*JP
6970  "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
6971 */
6972  "\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·):",
6973     (char *) 0
6974 };
6975
6976 static const char *opt_epilog[] = {
6977     "",
6978 /*JP
6979     "Some of the options can be set only before the game is started; those",
6980 */
6981     "\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",
6982 /*JP
6983     "items will not be selectable in the 'O' command's menu.",
6984 */
6985     "\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",
6986     (char *) 0
6987 };
6988
6989 void
6990 option_help()
6991 {
6992     char buf[BUFSZ], buf2[BUFSZ];
6993     register int i;
6994     winid datawin;
6995
6996     datawin = create_nhwindow(NHW_TEXT);
6997 /*JP
6998     Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
6999 */
7000     Sprintf(buf, "\83I\83v\83V\83\87\83\93\82Í %s \82Ì\92\86\82ÅOPTIONS=<options>\82Æ\90Ý\92è\82µ\82Ü\82·", configfile);
7001     opt_intro[CONFIG_SLOT] = (const char *) buf;
7002     for (i = 0; opt_intro[i]; i++)
7003         putstr(datawin, 0, opt_intro[i]);
7004
7005     /* Boolean options */
7006     for (i = 0; boolopt[i].name; i++) {
7007         if (boolopt[i].addr) {
7008             if (boolopt[i].addr == &iflags.sanity_check && !wizard)
7009                 continue;
7010             if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard)
7011                 continue;
7012             next_opt(datawin, boolopt[i].name);
7013         }
7014     }
7015     next_opt(datawin, "");
7016
7017     /* Compound options */
7018 /*JP
7019     putstr(datawin, 0, "Compound options:");
7020 */
7021     putstr(datawin, 0, "\95\8e\9a\97ñ\83I\83v\83V\83\87\83\93:");
7022     for (i = 0; compopt[i].name; i++) {
7023         Sprintf(buf2, "`%s'", compopt[i].name);
7024         Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
7025                 compopt[i + 1].name ? ',' : '.');
7026         putstr(datawin, 0, buf);
7027     }
7028
7029     for (i = 0; opt_epilog[i]; i++)
7030         putstr(datawin, 0, opt_epilog[i]);
7031
7032     display_nhwindow(datawin, FALSE);
7033     destroy_nhwindow(datawin);
7034     return;
7035 }
7036
7037 /*
7038  * prints the next boolean option, on the same line if possible, on a new
7039  * line if not. End with next_opt("").
7040  */
7041 void
7042 next_opt(datawin, str)
7043 winid datawin;
7044 const char *str;
7045 {
7046     static char *buf = 0;
7047     int i;
7048     char *s;
7049
7050     if (!buf)
7051         *(buf = (char *) alloc(BUFSZ)) = '\0';
7052
7053     if (!*str) {
7054         s = eos(buf);
7055         if (s > &buf[1] && s[-2] == ',')
7056             Strcpy(s - 2, "."); /* replace last ", " */
7057         i = COLNO;              /* (greater than COLNO - 2) */
7058     } else {
7059         i = strlen(buf) + strlen(str) + 2;
7060     }
7061
7062     if (i > COLNO - 2) { /* rule of thumb */
7063         putstr(datawin, 0, buf);
7064         buf[0] = 0;
7065     }
7066     if (*str) {
7067         Strcat(buf, str);
7068         Strcat(buf, ", ");
7069     } else {
7070         putstr(datawin, 0, str);
7071         free((genericptr_t) buf), buf = 0;
7072     }
7073     return;
7074 }
7075
7076 /* Returns the fid of the fruit type; if that type already exists, it
7077  * returns the fid of that one; if it does not exist, it adds a new fruit
7078  * type to the chain and returns the new one.
7079  * If replace_fruit is sent in, replace the fruit in the chain rather than
7080  * adding a new entry--for user specified fruits only.
7081  */
7082 int
7083 fruitadd(str, replace_fruit)
7084 char *str;
7085 struct fruit *replace_fruit;
7086 {
7087     register int i;
7088     register struct fruit *f;
7089     int highest_fruit_id = 0, globpfx;
7090     char buf[PL_FSIZ], altname[PL_FSIZ];
7091     boolean user_specified = (str == pl_fruit);
7092     /* if not user-specified, then it's a fruit name for a fruit on
7093      * a bones level or from orctown raider's loot...
7094      */
7095
7096     /* Note: every fruit has an id (kept in obj->spe) of at least 1;
7097      * 0 is an error.
7098      */
7099     if (user_specified) {
7100         boolean found = FALSE, numeric = FALSE;
7101
7102         /* force fruit to be singular; this handling is not
7103            needed--or wanted--for fruits from bones because
7104            they already received it in their original game;
7105            str==pl_fruit but makesingular() creates a copy
7106            so we need to copy that back into pl_fruit */
7107         nmcpy(pl_fruit, makesingular(str), PL_FSIZ);
7108         /* (assertion doesn't matter; we use 'pl_fruit' from here on out) */
7109         /* assert( str == pl_fruit ); */
7110
7111         /* disallow naming after other foods (since it'd be impossible
7112          * to tell the difference); globs might have a size prefix which
7113          * needs to be skipped in order to match the object type name
7114          */
7115         globpfx = (!strncmp(pl_fruit, "small ", 6)
7116                    || !strncmp(pl_fruit, "large ", 6)) ? 6
7117                   : (!strncmp(pl_fruit, "very large ", 11)) ? 11
7118                     : 0;
7119         for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) {
7120             if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)
7121                 || (globpfx > 0
7122                     && !strcmp(OBJ_NAME(objects[i]), &pl_fruit[globpfx]))) {
7123                 found = TRUE;
7124                 break;
7125             }
7126         }
7127         if (!found) {
7128             char *c;
7129
7130             for (c = pl_fruit; *c >= '0' && *c <= '9'; c++)
7131                 continue;
7132             if (!*c || isspace((uchar) *c))
7133                 numeric = TRUE;
7134         }
7135         if (found || numeric
7136             /* these checks for applying food attributes to actual items
7137                are case sensitive; "glob of foo" is caught by 'found'
7138                if 'foo' is a valid glob; when not valid, allow it as-is */
7139             || !strncmp(pl_fruit, "cursed ", 7)
7140             || !strncmp(pl_fruit, "uncursed ", 9)
7141             || !strncmp(pl_fruit, "blessed ", 8)
7142             || !strncmp(pl_fruit, "partly eaten ", 13)
7143             || (!strncmp(pl_fruit, "tin of ", 7)
7144                 && (!strcmp(pl_fruit + 7, "spinach")
7145                     || name_to_mon(pl_fruit + 7) >= LOW_PM))
7146             || !strcmp(pl_fruit, "empty tin")
7147             || (!strcmp(pl_fruit, "glob")
7148                 || (globpfx > 0 && !strcmp("glob", &pl_fruit[globpfx])))
7149             || ((str_end_is(pl_fruit, " corpse")
7150                  || str_end_is(pl_fruit, " egg"))
7151                 && name_to_mon(pl_fruit) >= LOW_PM)) {
7152             Strcpy(buf, pl_fruit);
7153             Strcpy(pl_fruit, "candied ");
7154             nmcpy(pl_fruit + 8, buf, PL_FSIZ - 8);
7155         }
7156         *altname = '\0';
7157         /* This flag indicates that a fruit has been made since the
7158          * last time the user set the fruit.  If it hasn't, we can
7159          * safely overwrite the current fruit, preventing the user from
7160          * setting many fruits in a row and overflowing.
7161          * Possible expansion: check for specific fruit IDs, not for
7162          * any fruit.
7163          */
7164         flags.made_fruit = FALSE;
7165         if (replace_fruit) {
7166             /* replace_fruit is already part of the fruit chain;
7167                update it in place rather than looking it up again */
7168             f = replace_fruit;
7169             copynchars(f->fname, pl_fruit, PL_FSIZ - 1);
7170             goto nonew;
7171         }
7172     } else {
7173         /* not user_supplied, so assumed to be from bones (or orc gang) */
7174         copynchars(altname, str, PL_FSIZ - 1);
7175         sanitize_name(altname);
7176         flags.made_fruit = TRUE; /* for safety.  Any fruit name added from a
7177                                   * bones level should exist anyway. */
7178     }
7179     f = fruit_from_name(*altname ? altname : str, FALSE, &highest_fruit_id);
7180     if (f)
7181         goto nonew;
7182
7183     /* Maximum number of named fruits is 127, even if obj->spe can
7184        handle bigger values.  If adding another fruit would overflow,
7185        use a random fruit instead... we've got a lot to choose from.
7186        current_fruit remains as is. */
7187     if (highest_fruit_id >= 127)
7188         return rnd(127);
7189
7190     f = newfruit();
7191     (void) memset((genericptr_t) f, 0, sizeof (struct fruit));
7192     copynchars(f->fname, *altname ? altname : str, PL_FSIZ - 1);
7193     f->fid = ++highest_fruit_id;
7194     /* we used to go out of our way to add it at the end of the list,
7195        but the order is arbitrary so use simpler insertion at start */
7196     f->nextf = ffruit;
7197     ffruit = f;
7198  nonew:
7199     if (user_specified)
7200         context.current_fruit = f->fid;
7201     return f->fid;
7202 }
7203
7204 /*
7205  * This is a somewhat generic menu for taking a list of NetHack style
7206  * class choices and presenting them via a description
7207  * rather than the traditional NetHack characters.
7208  * (Benefits users whose first exposure to NetHack is via tiles).
7209  *
7210  * prompt
7211  *           The title at the top of the menu.
7212  *
7213  * category: 0 = monster class
7214  *           1 = object  class
7215  *
7216  * way
7217  *           FALSE = PICK_ONE, TRUE = PICK_ANY
7218  *
7219  * class_list
7220  *           a null terminated string containing the list of choices.
7221  *
7222  * class_selection
7223  *           a null terminated string containing the selected characters.
7224  *
7225  * Returns number selected.
7226  */
7227 int
7228 choose_classes_menu(prompt, category, way, class_list, class_select)
7229 const char *prompt;
7230 int category;
7231 boolean way;
7232 char *class_list;
7233 char *class_select;
7234 {
7235     menu_item *pick_list = (menu_item *) 0;
7236     winid win;
7237     anything any;
7238     char buf[BUFSZ];
7239     int i, n;
7240     int ret;
7241     int next_accelerator, accelerator;
7242
7243     if (class_list == (char *) 0 || class_select == (char *) 0)
7244         return 0;
7245     accelerator = 0;
7246     next_accelerator = 'a';
7247     any = zeroany;
7248     win = create_nhwindow(NHW_MENU);
7249     start_menu(win);
7250     while (*class_list) {
7251         const char *text;
7252         boolean selected;
7253
7254         text = (char *) 0;
7255         selected = FALSE;
7256         switch (category) {
7257         case 0:
7258             text = def_monsyms[def_char_to_monclass(*class_list)].explain;
7259             accelerator = *class_list;
7260             Sprintf(buf, "%s", text);
7261             break;
7262         case 1:
7263             text = def_oc_syms[def_char_to_objclass(*class_list)].explain;
7264             accelerator = next_accelerator;
7265             Sprintf(buf, "%c  %s", *class_list, text);
7266             break;
7267         default:
7268             impossible("choose_classes_menu: invalid category %d", category);
7269         }
7270         if (way && *class_select) { /* Selections there already */
7271             if (index(class_select, *class_list)) {
7272                 selected = TRUE;
7273             }
7274         }
7275         any.a_int = *class_list;
7276         add_menu(win, NO_GLYPH, &any, accelerator, category ? *class_list : 0,
7277                  ATR_NONE, buf, selected);
7278         ++class_list;
7279         if (category > 0) {
7280             ++next_accelerator;
7281             if (next_accelerator == ('z' + 1))
7282                 next_accelerator = 'A';
7283             if (next_accelerator == ('Z' + 1))
7284                 break;
7285         }
7286     }
7287     if (category == 1 && next_accelerator <= 'z') {
7288         /* for objects, add "A - ' '  all classes", after a separator */
7289         any = zeroany;
7290         add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
7291         any.a_int = (int) ' ';
7292         Sprintf(buf, "%c  %s", (char) any.a_int, "all classes of objects");
7293         /* we won't preselect this even if the incoming list is empty;
7294            having it selected means that it would have to be explicitly
7295            de-selected in order to select anything else */
7296         add_menu(win, NO_GLYPH, &any, 'A', 0, ATR_NONE, buf, MENU_UNSELECTED);
7297     }
7298     end_menu(win, prompt);
7299     n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
7300     destroy_nhwindow(win);
7301     if (n > 0) {
7302         if (category == 1) {
7303             /* for object classes, first check for 'all'; it means 'use
7304                a blank list' rather than 'collect every possible choice' */
7305             for (i = 0; i < n; ++i)
7306                 if (pick_list[i].item.a_int == ' ') {
7307                     pick_list[0].item.a_int = ' ';
7308                     n = 1; /* return 1; also an implicit 'break;' */
7309                 }
7310         }
7311         for (i = 0; i < n; ++i)
7312             *class_select++ = (char) pick_list[i].item.a_int;
7313         free((genericptr_t) pick_list);
7314         ret = n;
7315     } else if (n == -1) {
7316         class_select = eos(class_select);
7317         ret = -1;
7318     } else
7319         ret = 0;
7320     *class_select = '\0';
7321     return ret;
7322 }
7323
7324 static struct wc_Opt wc_options[] = {
7325     { "ascii_map", WC_ASCII_MAP },
7326     { "color", WC_COLOR },
7327     { "eight_bit_tty", WC_EIGHT_BIT_IN },
7328     { "hilite_pet", WC_HILITE_PET },
7329     { "popup_dialog", WC_POPUP_DIALOG },
7330     { "player_selection", WC_PLAYER_SELECTION },
7331     { "preload_tiles", WC_PRELOAD_TILES },
7332     { "tiled_map", WC_TILED_MAP },
7333     { "tile_file", WC_TILE_FILE },
7334     { "tile_width", WC_TILE_WIDTH },
7335     { "tile_height", WC_TILE_HEIGHT },
7336     { "use_inverse", WC_INVERSE },
7337     { "align_message", WC_ALIGN_MESSAGE },
7338     { "align_status", WC_ALIGN_STATUS },
7339     { "font_map", WC_FONT_MAP },
7340     { "font_menu", WC_FONT_MENU },
7341     { "font_message", WC_FONT_MESSAGE },
7342 #if 0
7343     {"perm_invent", WC_PERM_INVENT},
7344 #endif
7345     { "font_size_map", WC_FONTSIZ_MAP },
7346     { "font_size_menu", WC_FONTSIZ_MENU },
7347     { "font_size_message", WC_FONTSIZ_MESSAGE },
7348     { "font_size_status", WC_FONTSIZ_STATUS },
7349     { "font_size_text", WC_FONTSIZ_TEXT },
7350     { "font_status", WC_FONT_STATUS },
7351     { "font_text", WC_FONT_TEXT },
7352     { "map_mode", WC_MAP_MODE },
7353     { "scroll_amount", WC_SCROLL_AMOUNT },
7354     { "scroll_margin", WC_SCROLL_MARGIN },
7355     { "splash_screen", WC_SPLASH_SCREEN },
7356     { "vary_msgcount", WC_VARY_MSGCOUNT },
7357     { "windowcolors", WC_WINDOWCOLORS },
7358     { "mouse_support", WC_MOUSE_SUPPORT },
7359     { (char *) 0, 0L }
7360 };
7361 static struct wc_Opt wc2_options[] = {
7362     { "fullscreen", WC2_FULLSCREEN },
7363     { "softkeyboard", WC2_SOFTKEYBOARD },
7364     { "wraptext", WC2_WRAPTEXT },
7365     { "use_darkgray", WC2_DARKGRAY },
7366     { "hitpointbar", WC2_HITPOINTBAR },
7367     { "hilite_status", WC2_HILITE_STATUS },
7368     /* name shown in 'O' menu is different */
7369     { "status hilite rules", WC2_HILITE_STATUS },
7370     /* statushilites doesn't have its own bit */
7371     { "statushilites", WC2_HILITE_STATUS },
7372     { "term_cols", WC2_TERM_SIZE },
7373     { "term_rows", WC2_TERM_SIZE },
7374     { "petattr", WC2_PETATTR },
7375     { "guicolor", WC2_GUICOLOR },
7376     { "statuslines", WC2_STATUSLINES },
7377     { "windowborders", WC2_WINDOWBORDERS },
7378     { (char *) 0, 0L }
7379 };
7380
7381 /*
7382  * If a port wants to change or ensure that the SET_IN_SYS,
7383  * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
7384  * correct (for controlling its display in the option menu) call
7385  * set_option_mod_status()
7386  * with the appropriate second argument.
7387  */
7388 void
7389 set_option_mod_status(optnam, status)
7390 const char *optnam;
7391 int status;
7392 {
7393     int k;
7394
7395     if (SET__IS_VALUE_VALID(status)) {
7396         impossible("set_option_mod_status: status out of range %d.", status);
7397         return;
7398     }
7399     for (k = 0; boolopt[k].name; k++) {
7400         if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
7401             boolopt[k].optflags = status;
7402             return;
7403         }
7404     }
7405     for (k = 0; compopt[k].name; k++) {
7406         if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
7407             compopt[k].optflags = status;
7408             return;
7409         }
7410     }
7411 }
7412
7413 /*
7414  * You can set several wc_options in one call to
7415  * set_wc_option_mod_status() by setting
7416  * the appropriate bits for each option that you
7417  * are setting in the optmask argument
7418  * prior to calling.
7419  *    example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN,
7420  * SET_IN_GAME);
7421  */
7422 void
7423 set_wc_option_mod_status(optmask, status)
7424 unsigned long optmask;
7425 int status;
7426 {
7427     int k = 0;
7428
7429     if (SET__IS_VALUE_VALID(status)) {
7430         impossible("set_wc_option_mod_status: status out of range %d.",
7431                    status);
7432         return;
7433     }
7434     while (wc_options[k].wc_name) {
7435         if (optmask & wc_options[k].wc_bit) {
7436             set_option_mod_status(wc_options[k].wc_name, status);
7437         }
7438         k++;
7439     }
7440 }
7441
7442 STATIC_OVL boolean
7443 is_wc_option(optnam)
7444 const char *optnam;
7445 {
7446     int k = 0;
7447
7448     while (wc_options[k].wc_name) {
7449         if (strcmp(wc_options[k].wc_name, optnam) == 0)
7450             return TRUE;
7451         k++;
7452     }
7453     return FALSE;
7454 }
7455
7456 STATIC_OVL boolean
7457 wc_supported(optnam)
7458 const char *optnam;
7459 {
7460     int k;
7461
7462     for (k = 0; wc_options[k].wc_name; ++k) {
7463         if (!strcmp(wc_options[k].wc_name, optnam))
7464             return (windowprocs.wincap & wc_options[k].wc_bit) ? TRUE : FALSE;
7465     }
7466     return FALSE;
7467 }
7468
7469 /*
7470  * You can set several wc2_options in one call to
7471  * set_wc2_option_mod_status() by setting
7472  * the appropriate bits for each option that you
7473  * are setting in the optmask argument
7474  * prior to calling.
7475  *    example:
7476  * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
7477  * SET_IN_FILE);
7478  */
7479
7480 void
7481 set_wc2_option_mod_status(optmask, status)
7482 unsigned long optmask;
7483 int status;
7484 {
7485     int k = 0;
7486
7487     if (SET__IS_VALUE_VALID(status)) {
7488         impossible("set_wc2_option_mod_status: status out of range %d.",
7489                    status);
7490         return;
7491     }
7492     while (wc2_options[k].wc_name) {
7493         if (optmask & wc2_options[k].wc_bit) {
7494             set_option_mod_status(wc2_options[k].wc_name, status);
7495         }
7496         k++;
7497     }
7498 }
7499
7500 STATIC_OVL boolean
7501 is_wc2_option(optnam)
7502 const char *optnam;
7503 {
7504     int k = 0;
7505
7506     while (wc2_options[k].wc_name) {
7507         if (strcmp(wc2_options[k].wc_name, optnam) == 0)
7508             return TRUE;
7509         k++;
7510     }
7511     return FALSE;
7512 }
7513
7514 STATIC_OVL boolean
7515 wc2_supported(optnam)
7516 const char *optnam;
7517 {
7518     int k;
7519
7520     for (k = 0; wc2_options[k].wc_name; ++k) {
7521         if (!strcmp(wc2_options[k].wc_name, optnam))
7522             return (windowprocs.wincap2 & wc2_options[k].wc_bit) ? TRUE
7523                                                                  : FALSE;
7524     }
7525     return FALSE;
7526 }
7527
7528 STATIC_OVL void
7529 wc_set_font_name(opttype, fontname)
7530 int opttype;
7531 char *fontname;
7532 {
7533     char **fn = (char **) 0;
7534
7535     if (!fontname)
7536         return;
7537     switch (opttype) {
7538     case MAP_OPTION:
7539         fn = &iflags.wc_font_map;
7540         break;
7541     case MESSAGE_OPTION:
7542         fn = &iflags.wc_font_message;
7543         break;
7544     case TEXT_OPTION:
7545         fn = &iflags.wc_font_text;
7546         break;
7547     case MENU_OPTION:
7548         fn = &iflags.wc_font_menu;
7549         break;
7550     case STATUS_OPTION:
7551         fn = &iflags.wc_font_status;
7552         break;
7553     default:
7554         return;
7555     }
7556     if (fn) {
7557         if (*fn)
7558             free((genericptr_t) *fn);
7559         *fn = dupstr(fontname);
7560     }
7561     return;
7562 }
7563
7564 STATIC_OVL int
7565 wc_set_window_colors(op)
7566 char *op;
7567 {
7568     /* syntax:
7569      *  menu white/black message green/yellow status white/blue text
7570      * white/black
7571      */
7572     int j;
7573     char buf[BUFSZ];
7574     char *wn, *tfg, *tbg, *newop;
7575     static const char *wnames[] = { "menu", "message", "status", "text" };
7576     static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
7577     static char **fgp[] = { &iflags.wc_foregrnd_menu,
7578                             &iflags.wc_foregrnd_message,
7579                             &iflags.wc_foregrnd_status,
7580                             &iflags.wc_foregrnd_text };
7581     static char **bgp[] = { &iflags.wc_backgrnd_menu,
7582                             &iflags.wc_backgrnd_message,
7583                             &iflags.wc_backgrnd_status,
7584                             &iflags.wc_backgrnd_text };
7585
7586     Strcpy(buf, op);
7587     newop = mungspaces(buf);
7588     while (newop && *newop) {
7589         wn = tfg = tbg = (char *) 0;
7590
7591         /* until first non-space in case there's leading spaces - before
7592          * colorname*/
7593         if (*newop == ' ')
7594             newop++;
7595         if (*newop)
7596             wn = newop;
7597         else
7598             return 0;
7599
7600         /* until first space - colorname*/
7601         while (*newop && *newop != ' ')
7602             newop++;
7603         if (*newop)
7604             *newop = '\0';
7605         else
7606             return 0;
7607         newop++;
7608
7609         /* until first non-space - before foreground*/
7610         if (*newop == ' ')
7611             newop++;
7612         if (*newop)
7613             tfg = newop;
7614         else
7615             return 0;
7616
7617         /* until slash - foreground */
7618         while (*newop && *newop != '/')
7619             newop++;
7620         if (*newop)
7621             *newop = '\0';
7622         else
7623             return 0;
7624         newop++;
7625
7626         /* until first non-space (in case there's leading space after slash) -
7627          * before background */
7628         if (*newop == ' ')
7629             newop++;
7630         if (*newop)
7631             tbg = newop;
7632         else
7633             return 0;
7634
7635         /* until first space - background */
7636         while (*newop && *newop != ' ')
7637             newop++;
7638         if (*newop)
7639             *newop++ = '\0';
7640
7641         for (j = 0; j < 4; ++j) {
7642             if (!strcmpi(wn, wnames[j]) || !strcmpi(wn, shortnames[j])) {
7643                 if (tfg && !strstri(tfg, " ")) {
7644                     if (*fgp[j])
7645                         free((genericptr_t) *fgp[j]);
7646                     *fgp[j] = dupstr(tfg);
7647                 }
7648                 if (tbg && !strstri(tbg, " ")) {
7649                     if (*bgp[j])
7650                         free((genericptr_t) *bgp[j]);
7651                     *bgp[j] = dupstr(tbg);
7652                 }
7653                 break;
7654             }
7655         }
7656     }
7657     return 1;
7658 }
7659
7660 /* set up for wizard mode if player or save file has requested to it;
7661    called from port-specific startup code to handle `nethack -D' or
7662    OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
7663    restoring a game which was saved in wizard mode */
7664 void
7665 set_playmode()
7666 {
7667     if (wizard) {
7668         if (authorize_wizard_mode())
7669             Strcpy(plname, "wizard");
7670         else
7671             wizard = FALSE; /* not allowed or not available */
7672         /* force explore mode if we didn't make it into wizard mode */
7673         discover = !wizard;
7674         iflags.deferred_X = FALSE;
7675     }
7676     /* don't need to do anything special for explore mode or normal play */
7677 }
7678
7679 #endif /* OPTION_LISTS_ONLY */
7680
7681 /*options.c*/