1 /* NetHack 3.6 options.c $NHDT-Date: 1448241657 2015/11/23 01:20:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.243 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */
9 NEARDATA struct flag flags; /* provide linkage */
11 NEARDATA struct sysflag sysflags; /* provide linkage */
13 NEARDATA struct instance_flags iflags; /* provide linkage */
21 #define BACKWARD_COMPAT
24 #ifdef DEFAULT_WC_TILED_MAP
25 #define PREFER_TILED TRUE
27 #define PREFER_TILED FALSE
30 #define MESSAGE_OPTION 1
31 #define STATUS_OPTION 2
36 #define PILE_LIMIT_DFLT 5
39 * NOTE: If you add (or delete) an option, please update the short
40 * options help (option_help()), the long options help (dat/opthelp),
41 * and the current options setting display function (doset()),
42 * and also the Guidebooks.
44 * The order matters. If an option is a an initial substring of another
45 * option (e.g. time and timed_delay) the shorter one must come first.
48 static struct Bool_Opt {
50 boolean *addr, initvalue;
53 { "acoustics", &flags.acoustics, TRUE, SET_IN_GAME },
54 #if defined(SYSFLAGS) && defined(AMIGA)
55 /* Amiga altmeta causes Alt+key to be converted into Meta+key by
56 low level nethack code; on by default, can be toggled off if
57 Alt+key is needed for some ASCII chars on non-ASCII keyboard */
58 { "altmeta", &sysflags.altmeta, TRUE, DISP_IN_GAME },
61 /* non-Amiga altmeta causes nethack's top level command loop to treat
62 two character sequence "ESC c" as M-c, for terminals or emulators
63 which send "ESC c" when Alt+c is pressed; off by default, enabling
64 this can potentially make trouble if user types ESC when nethack
65 is honoring this conversion request (primarily after starting a
66 count prefix prior to a command and then deciding to cancel it) */
67 { "altmeta", &iflags.altmeta, FALSE, SET_IN_GAME },
69 { "altmeta", (boolean *) 0, TRUE, DISP_IN_GAME },
72 { "ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME }, /*WC*/
73 #if defined(SYSFLAGS) && defined(MFLOPPY)
74 { "asksavedisk", &sysflags.asksavedisk, FALSE, SET_IN_GAME },
76 { "asksavedisk", (boolean *) 0, FALSE, SET_IN_FILE },
78 { "autodig", &flags.autodig, FALSE, SET_IN_GAME },
79 { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME },
80 { "autopickup", &flags.pickup, TRUE, SET_IN_GAME },
81 { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME },
82 #if defined(MICRO) && !defined(AMIGA)
83 { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE },
85 { "BIOS", (boolean *) 0, FALSE, SET_IN_FILE },
87 { "blind", &u.uroleplay.blind, FALSE, DISP_IN_GAME },
88 { "bones", &flags.bones, TRUE, SET_IN_FILE },
90 { "checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME },
92 { "checkpoint", (boolean *) 0, FALSE, SET_IN_FILE },
95 { "checkspace", &iflags.checkspace, TRUE, SET_IN_GAME },
97 { "checkspace", (boolean *) 0, FALSE, SET_IN_FILE },
99 { "clicklook", &iflags.clicklook, FALSE, SET_IN_GAME },
100 { "cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME },
101 #if defined(MICRO) || defined(WIN32)
102 { "color", &iflags.wc_color, TRUE, SET_IN_GAME }, /*WC*/
103 #else /* systems that support multiple terminals, many monochrome */
104 { "color", &iflags.wc_color, FALSE, SET_IN_GAME }, /*WC*/
106 { "confirm", &flags.confirm, TRUE, SET_IN_GAME },
107 { "dark_room", &flags.dark_room, TRUE, SET_IN_GAME },
108 { "eight_bit_tty", &iflags.wc_eight_bit_input, FALSE,
109 SET_IN_GAME }, /*WC*/
111 { "extmenu", &iflags.extmenu, FALSE, SET_IN_GAME },
113 { "extmenu", (boolean *) 0, FALSE, SET_IN_FILE },
116 { "fast_map", &flags.fast_map, TRUE, SET_IN_GAME },
118 { "fast_map", (boolean *) 0, TRUE, SET_IN_FILE },
120 { "female", &flags.female, FALSE, DISP_IN_GAME },
121 { "fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME },
122 #if defined(SYSFLAGS) && defined(AMIFLUSH)
123 { "flush", &sysflags.amiflush, FALSE, SET_IN_GAME },
125 { "flush", (boolean *) 0, FALSE, SET_IN_FILE },
127 { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE },
128 { "help", &flags.help, TRUE, SET_IN_GAME },
129 { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/
130 { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME },
132 { "ignintr", &flags.ignintr, FALSE, SET_IN_GAME },
134 { "ignintr", (boolean *) 0, FALSE, SET_IN_FILE },
136 { "implicit_uncursed", &iflags.implicit_uncursed, TRUE, SET_IN_GAME },
137 { "large_font", &iflags.obsolete, FALSE, SET_IN_FILE }, /* OBSOLETE */
138 { "legacy", &flags.legacy, TRUE, DISP_IN_GAME },
139 { "lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME },
140 { "lootabc", &flags.lootabc, FALSE, SET_IN_GAME },
142 { "mail", &flags.biff, TRUE, SET_IN_GAME },
144 { "mail", (boolean *) 0, TRUE, SET_IN_FILE },
146 { "mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME },
147 { "menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME },
148 /* for menu debugging only*/
149 { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME },
150 { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME },
151 { "mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME }, /*WC*/
153 { "news", &iflags.news, TRUE, DISP_IN_GAME },
155 { "news", (boolean *) 0, FALSE, SET_IN_FILE },
157 { "nudist", &u.uroleplay.nudist, FALSE, DISP_IN_GAME },
158 { "null", &flags.null, TRUE, SET_IN_GAME },
159 #if defined(SYSFLAGS) && defined(MAC)
160 { "page_wait", &sysflags.page_wait, TRUE, SET_IN_GAME },
162 { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE },
164 { "perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME },
165 { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME },
166 { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME }, /*WC*/
167 { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/
168 { "pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME },
169 #if defined(MICRO) && !defined(AMIGA)
170 { "rawio", &iflags.rawio, FALSE, DISP_IN_GAME },
172 { "rawio", (boolean *) 0, FALSE, SET_IN_FILE },
174 { "rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME },
176 { "rlecomp", &iflags.rlecomp,
177 #if defined(COMPRESS) || defined(ZLIB_COMP)
184 { "safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME },
185 { "sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME },
186 { "selectsaved", &iflags.wc2_selectsaved, TRUE, DISP_IN_GAME }, /*WC*/
187 { "showexp", &flags.showexp, FALSE, SET_IN_GAME },
188 { "showrace", &flags.showrace, FALSE, SET_IN_GAME },
190 { "showscore", &flags.showscore, FALSE, SET_IN_GAME },
192 { "showscore", (boolean *) 0, FALSE, SET_IN_FILE },
194 { "silent", &flags.silent, TRUE, SET_IN_GAME },
195 { "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE },
196 { "sortpack", &flags.sortpack, TRUE, SET_IN_GAME },
197 { "sparkle", &flags.sparkle, TRUE, SET_IN_GAME },
198 { "splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME }, /*WC*/
199 { "standout", &flags.standout, FALSE, SET_IN_GAME },
200 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
201 { "statushilites", &iflags.use_status_hilites, TRUE, SET_IN_GAME },
203 { "statushilites", &iflags.use_status_hilites, FALSE, DISP_IN_GAME },
205 { "tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME }, /*WC*/
206 { "time", &flags.time, FALSE, SET_IN_GAME },
208 { "timed_delay", &flags.nap, TRUE, SET_IN_GAME },
210 { "timed_delay", (boolean *) 0, FALSE, SET_IN_GAME },
212 { "tombstone", &flags.tombstone, TRUE, SET_IN_GAME },
213 { "toptenwin", &iflags.toptenwin, FALSE, SET_IN_GAME },
214 { "travel", &flags.travelcmd, TRUE, SET_IN_GAME },
215 { "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE },
217 { "use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME }, /*WC*/
219 { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/
221 { "verbose", &flags.verbose, TRUE, SET_IN_GAME },
222 { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME },
224 { "zerocomp", &iflags.zerocomp,
225 #if defined(COMPRESS) || defined(ZLIB_COMP)
232 { (char *) 0, (boolean *) 0, FALSE, 0 }
235 /* compound options, for option_help() and external programs like Amiga
237 static struct Comp_Opt {
238 const char *name, *descr;
239 int size; /* for frontends and such allocating space --
240 * usually allowed size of data in game, but
241 * occasionally maximum reasonable size for
242 * typing when game maintains information in
243 * a different format */
246 { "align", "your starting alignment (lawful, neutral, or chaotic)", 8,
248 { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
249 { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/
250 { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
251 #ifdef BACKWARD_COMPAT
252 { "boulder", "deprecated (use S_boulder in sym file instead)", 1,
255 { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
256 PL_PSIZ, DISP_IN_GAME },
257 { "disclose", "the kinds of information to disclose at end of game",
258 sizeof(flags.end_disclose) * 2, SET_IN_GAME },
259 { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ,
261 { "dungeon", "the symbols to use in drawing the dungeon map",
262 MAXDCHARS + 1, SET_IN_FILE },
263 { "effects", "the symbols to use in drawing special effects",
264 MAXECHARS + 1, SET_IN_FILE },
265 { "font_map", "the font to use in the map window", 40,
266 DISP_IN_GAME }, /*WC*/
267 { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
268 { "font_message", "the font to use in the message window", 40,
269 DISP_IN_GAME }, /*WC*/
270 { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
271 { "font_size_menu", "the size of the menu font", 20,
272 DISP_IN_GAME }, /*WC*/
273 { "font_size_message", "the size of the message font", 20,
274 DISP_IN_GAME }, /*WC*/
275 { "font_size_status", "the size of the status font", 20,
276 DISP_IN_GAME }, /*WC*/
277 { "font_size_text", "the size of the text font", 20,
278 DISP_IN_GAME }, /*WC*/
279 { "font_status", "the font to use in status window", 40,
280 DISP_IN_GAME }, /*WC*/
281 { "font_text", "the font to use in text windows", 40,
282 DISP_IN_GAME }, /*WC*/
283 { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME },
284 { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME },
285 { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
286 PL_PSIZ, DISP_IN_GAME },
287 { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
288 { "menustyle", "user interface for object selection", MENUTYPELEN,
290 { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
291 { "menu_deselect_page", "deselect all items on this page of a menu", 4,
293 { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE },
294 { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME },
295 { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
296 { "menu_invert_page", "invert all items on this page of a menu", 4,
298 { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
299 { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
300 { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
301 { "menu_search", "search for a menu item", 4, SET_IN_FILE },
302 { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
303 { "menu_select_page", "select all items on this page of a menu", 4,
305 { "monsters", "the symbols to use for monsters", MAXMCLASSES,
307 { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME },
309 { "msg_window", "the type of message window required", 1, SET_IN_GAME },
311 { "msg_window", "the type of message window required", 1, SET_IN_FILE },
313 { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ,
315 { "number_pad", "use the number pad for movement", 1, SET_IN_GAME },
316 { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE },
317 { "packorder", "the inventory order of the items in your pack",
318 MAXOCLASSES, SET_IN_GAME },
322 "palette (00c/880/-fff is blue/yellow/reverse white)", 15,
325 "palette (adjust an RGB color in palette (color-R-G-B)", 15,
329 { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE },
332 { "paranoid_confirmation", "extra prompting in certain situations", 28,
334 { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
335 { "pickup_burden", "maximum burden picked up before prompt", 20,
337 { "pickup_types", "types of objects to pick up automatically",
338 MAXOCLASSES, SET_IN_GAME },
339 { "pile_limit", "threshold for \"there are many objects here\"", 24,
341 { "playmode", "normal play, non-scoring explore mode, or debug mode", 8,
343 { "player_selection", "choose character via dialog or prompts", 12,
345 { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ,
347 { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ,
349 { "runmode", "display frequency when `running' or `travelling'",
350 sizeof "teleport", SET_IN_GAME },
351 { "scores", "the parts of the score list you wish to see", 32,
353 { "scroll_amount", "amount to scroll map when scroll_margin is reached",
354 20, DISP_IN_GAME }, /*WC*/
355 { "scroll_margin", "scroll map when this far from the edge", 20,
356 DISP_IN_GAME }, /*WC*/
357 { "sortloot", "sort object selection lists by description", 4,
360 { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
362 { "symset", "load a set of display symbols from the symbols file", 70,
365 "load a set of rogue display symbols from the symbols file", 70,
367 { "suppress_alert", "suppress alerts about version-specific features", 8,
369 { "tile_width", "width of tiles", 20, DISP_IN_GAME }, /*WC*/
370 { "tile_height", "height of tiles", 20, DISP_IN_GAME }, /*WC*/
371 { "tile_file", "name of tile file", 70, DISP_IN_GAME }, /*WC*/
372 { "traps", "the symbols to use in drawing traps", MAXTCHARS + 1,
374 { "vary_msgcount", "show more old messages at a time", 20,
375 DISP_IN_GAME }, /*WC*/
377 { "video", "method of video updating", 20, SET_IN_FILE },
380 { "videocolors", "color mappings for internal screen routines", 40,
382 { "videoshades", "gray shades to map to black/gray/white", 32,
386 { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE },
388 { "windowcolors", "the foreground/background colors of windows", /*WC*/
390 { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
392 { "windowchain", "window processor to use", WINTYPELEN, SET_IN_SYS },
394 #ifdef BACKWARD_COMPAT
395 { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE },
396 { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE },
397 #ifdef MAC_GRAPHICS_ENV
398 { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE },
401 { (char *) 0, (char *) 0, 0, 0 }
404 #ifdef OPTION_LISTS_ONLY
407 #else /* use rest of file */
409 extern struct symparse loadsyms[];
410 static boolean need_redraw; /* for doset() */
412 #if defined(TOS) && defined(TEXTCOLOR)
413 extern boolean colors_changed; /* in tos.c */
417 extern char *shade[3]; /* in sys/msdos/video.c */
418 extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
421 static char def_inv_order[MAXOCLASSES] = {
422 COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
423 SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
424 TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
428 * Default menu manipulation command accelerators. These may _not_ be:
430 * + a number - reserved for counts
431 * + an upper or lower case US ASCII letter - used for accelerators
432 * + ESC - reserved for escaping the menu
433 * + NULL, CR or LF - reserved for commiting the selection(s). NULL
434 * is kind of odd, but the tty's xwaitforspace() will return it if
435 * someone hits a <ret>.
436 * + a default object class symbol - used for object class accelerators
438 * Standard letters (for now) are:
451 * The command name list is duplicated in the compopt array.
458 #define NUM_MENU_CMDS 11
459 static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
460 /* 0*/ { "menu_first_page", MENU_FIRST_PAGE },
461 { "menu_last_page", MENU_LAST_PAGE },
462 { "menu_next_page", MENU_NEXT_PAGE },
463 { "menu_previous_page", MENU_PREVIOUS_PAGE },
464 { "menu_select_all", MENU_SELECT_ALL },
465 /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL },
466 { "menu_invert_all", MENU_INVERT_ALL },
467 { "menu_select_page", MENU_SELECT_PAGE },
468 { "menu_deselect_page", MENU_UNSELECT_PAGE },
469 { "menu_invert_page", MENU_INVERT_PAGE },
470 /*10*/ { "menu_search", MENU_SEARCH },
474 * Allow the user to map incoming characters to various menu commands.
475 * The accelerator list must be a valid C string.
477 #define MAX_MENU_MAPPED_CMDS 32 /* some number */
478 char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */
479 static char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1];
480 static short n_menu_mapped = 0;
482 static boolean initial, from_file;
484 STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int));
485 STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
486 STATIC_DCL void FDECL(escapes, (const char *, char *));
487 STATIC_DCL void FDECL(rejectoption, (const char *));
488 STATIC_DCL void FDECL(badoption, (const char *));
489 STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P));
490 STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
491 STATIC_DCL void FDECL(bad_negation, (const char *, BOOLEAN_P));
492 STATIC_DCL int FDECL(change_inv_order, (char *));
493 STATIC_DCL void FDECL(oc_to_str, (char *, char *));
494 STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
495 STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
496 STATIC_DCL boolean FDECL(special_handling, (const char *,
497 BOOLEAN_P, BOOLEAN_P));
498 STATIC_DCL void FDECL(warning_opts, (char *, const char *));
499 STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int));
500 STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int));
502 STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
503 STATIC_OVL int FDECL(wc_set_window_colors, (char *));
504 STATIC_OVL boolean FDECL(is_wc_option, (const char *));
505 STATIC_OVL boolean FDECL(wc_supported, (const char *));
506 STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
507 STATIC_OVL boolean FDECL(wc2_supported, (const char *));
508 STATIC_DCL void FDECL(remove_autopickup_exception,
509 (struct autopickup_exception *));
510 STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
511 STATIC_DCL const char *FDECL(attr2attrname, (int));
512 STATIC_DCL int NDECL(query_color);
513 STATIC_DCL int NDECL(query_msgtype);
514 STATIC_DCL int FDECL(query_attr, (const char *));
515 STATIC_DCL const char * FDECL(msgtype2name, (int));
516 STATIC_DCL boolean FDECL(msgtype_add, (int, char *));
517 STATIC_DCL void FDECL(free_one_msgtype, (int));
518 STATIC_DCL int NDECL(msgtype_count);
519 STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
520 STATIC_DCL void FDECL(free_one_menu_coloring, (int));
521 STATIC_DCL int NDECL(count_menucolors);
522 STATIC_DCL int FDECL(handle_add_list_remove, (const char *, int));
529 for (x = 0; x < COLNO; x++)
530 for (y = 0; y < ROWNO; y++) {
531 struct rm *lev = &levl[x][y];
533 if (!flags.dark_room || !iflags.use_color
534 || Is_rogue_level(&u.uz)) {
535 if (lev->glyph == cmap_to_glyph(S_darkroom))
536 lev->glyph = lev->waslit ? cmap_to_glyph(S_room)
537 : cmap_to_glyph(S_stone);
539 if (lev->glyph == cmap_to_glyph(S_room) && lev->seenv
540 && lev->waslit && !cansee(x, y))
541 lev->glyph = cmap_to_glyph(S_darkroom);
542 else if (lev->glyph == cmap_to_glyph(S_stone)
543 && lev->typ == ROOM && lev->seenv && !cansee(x, y))
544 lev->glyph = cmap_to_glyph(S_darkroom);
547 if (flags.dark_room && iflags.use_color)
548 showsyms[S_darkroom] = showsyms[S_room];
550 showsyms[S_darkroom] = showsyms[S_stone];
553 /* check whether a user-supplied option string is a proper leading
554 substring of a particular option name; option string might have
555 a colon or equals sign and arbitrary value appended to it */
557 match_optname(user_string, opt_name, min_length, val_allowed)
558 const char *user_string, *opt_name;
562 int len = (int) strlen(user_string);
565 const char *p = index(user_string, ':'),
566 *q = index(user_string, '=');
568 if (!p || (q && q < p))
570 while (p && p > user_string && isspace((uchar) * (p - 1)))
573 len = (int) (p - user_string);
576 return (boolean) (len >= min_length
577 && !strncmpi(opt_name, user_string, len));
580 /* most environment variables will eventually be printed in an error
581 * message if they don't work, and most error message paths go through
582 * BUFSZ buffers, which could be overflowed by a maliciously long
583 * environment variable. If a variable can legitimately be long, or
584 * if it's put in a smaller buffer, the responsible code will have to
585 * bounds-check itself.
591 char *getev = getenv(ev);
593 if (getev && strlen(getev) <= (BUFSZ / 2))
599 /* process options, possibly including SYSCF */
605 /* someday there may be other SYSCF alternatives besides text file */
607 /* If SYSCF_FILE is specified, it _must_ exist... */
609 /* ... and _must_ parse correctly. */
610 if (!read_config_file(SYSCF_FILE, SET_IN_SYS)) {
611 raw_printf("Error(s) found in SYSCF_FILE, quitting.");
612 terminate(EXIT_FAILURE);
615 * TODO [maybe]: parse the sysopt entries which are space-separated
616 * lists of usernames into arrays with one name per element.
620 initoptions_finish();
626 #if defined(UNIX) || defined(VMS)
631 /* set up the command parsing */
632 reset_commands(TRUE); /* init */
634 /* initialize the random number generator */
637 /* for detection of configfile options specified multiple times */
638 iflags.opt_booldup = iflags.opt_compdup = (int *) 0;
640 for (i = 0; boolopt[i].name; i++) {
642 *(boolopt[i].addr) = boolopt[i].initvalue;
644 #if defined(COMPRESS) || defined(ZLIB_COMP)
645 set_savepref("externalcomp");
646 set_restpref("externalcomp");
648 set_savepref("!rlecomp");
649 set_restpref("!rlecomp");
653 set_savepref("zerocomp");
654 set_restpref("zerocomp");
657 set_savepref("rlecomp");
658 set_restpref("rlecomp");
662 Strcpy(sysflags.sysflagsid, "sysflags");
663 sysflags.sysflagsid[9] = (char) sizeof(struct sysflag);
665 flags.end_own = FALSE;
667 flags.end_around = 2;
668 flags.paranoia_bits = PARANOID_PRAY; /* old prayconfirm=TRUE */
669 flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */
670 flags.runmode = RUN_LEAP;
671 iflags.msg_history = 20;
673 iflags.prevmsg_window = 's';
675 iflags.menu_headings = ATR_INVERSE;
677 /* hero's role, race, &c haven't been chosen yet */
678 flags.initrole = flags.initrace = flags.initgend = flags.initalign =
681 /* Set the default monster and object class symbols. */
683 for (i = 0; i < WARNCOUNT; i++)
684 warnsyms[i] = def_warnsyms[i].sym;
685 iflags.bouldersym = 0;
687 iflags.travelcc.x = iflags.travelcc.y = -1;
689 /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
690 (void) memcpy((genericptr_t) flags.inv_order,
691 (genericptr_t) def_inv_order, sizeof flags.inv_order);
692 flags.pickup_types[0] = '\0';
693 flags.pickup_burden = MOD_ENCUMBER;
694 flags.sortloot = 'l'; /* sort only loot by default */
696 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
697 flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
698 switch_symbols(FALSE); /* set default characters */
699 #if defined(UNIX) && defined(TTY_GRAPHICS)
701 * Set defaults for some options depending on what we can
702 * detect about the environment's capabilities.
703 * This has to be done after the global initialization above
704 * and before reading user-specific initialization via
705 * config file/environment variable below.
707 /* this detects the IBM-compatible console on most 386 boxes */
708 if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
709 if (!symset[PRIMARY].name)
710 load_symset("IBMGraphics", PRIMARY);
711 if (!symset[ROGUESET].name)
712 load_symset("RogueIBM", ROGUESET);
713 switch_symbols(TRUE);
715 iflags.use_color = TRUE;
718 #endif /* UNIX && TTY_GRAPHICS */
719 #if defined(UNIX) || defined(VMS)
721 /* detect whether a "vt" terminal can handle alternate charsets */
722 if ((opts = nh_getenv("TERM"))
723 /* [could also check "xterm" which emulates vtXXX by default] */
724 && !strncmpi(opts, "vt", 2)
725 && AS && AE && index(AS, '\016') && index(AE, '\017')) {
726 if (!symset[PRIMARY].name)
727 load_symset("DECGraphics", PRIMARY);
728 switch_symbols(TRUE);
731 #endif /* UNIX || VMS */
733 #ifdef MAC_GRAPHICS_ENV
734 if (!symset[PRIMARY].name)
735 load_symset("MACGraphics", PRIMARY);
736 switch_symbols(TRUE);
737 #endif /* MAC_GRAPHICS_ENV */
738 flags.menu_style = MENU_FULL;
740 /* since this is done before init_objects(), do partial init here */
741 objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
742 nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
749 char *opts = getenv("NETHACKOPTIONS");
752 opts = getenv("HACKOPTIONS");
754 if (*opts == '/' || *opts == '\\' || *opts == '@') {
756 opts++; /* @filename */
757 /* looks like a filename */
758 if (strlen(opts) < BUFSZ / 2)
759 read_config_file(opts, SET_IN_FILE);
761 read_config_file((char *) 0, SET_IN_FILE);
762 /* let the total length of options be long;
763 * parseoptions() will check each individually
765 parseoptions(opts, TRUE, FALSE);
769 read_config_file((char *) 0, SET_IN_FILE);
771 (void) fruitadd(pl_fruit, (struct fruit *) 0);
773 * Remove "slime mold" from list of object names. This will
774 * prevent it from being wished unless it's actually present
775 * as a named (or default) fruit. Wishing for "fruit" will
776 * result in the player's preferred fruit [better than "\033"].
778 obj_descr[SLIME_MOLD].oc_name = "fruit";
780 if (iflags.bouldersym)
787 nmcpy(dest, src, maxlen)
794 for (count = 1; count < maxlen; count++) {
795 if (*src == ',' || *src == '\0')
796 break; /*exit on \0 terminator*/
803 * escapes(): escape expansion for showsyms. C-style escapes understood
804 * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
805 * The ^-prefix for control characters is also understood, and \[mM]
806 * has the effect of 'meta'-ing the value which follows (so that the
807 * alternate character set will be enabled).
809 * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
810 * prior to terminating '\0' would pull that '\0' into the output and then
811 * keep processing past it, potentially overflowing the output buffer.
812 * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
813 * output and stop there; trailing \M will fall through to \<other> and
814 * yield 'M', then stop. Any \X or \O followed by something other than
815 * an appropriate digit will also fall through to \<other> and yield 'X'
816 * or 'O', plus stop if the non-digit is end-of-string.
823 static NEARDATA const char oct[] = "01234567", dec[] = "0123456789",
824 hex[] = "00112233445566778899aAbBcCdDeEfF";
826 int cval, meta, dcount;
829 /* \M has to be followed by something to do meta conversion,
830 otherwise it will just be \M which ultimately yields 'M' */
831 meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]);
835 cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
836 if ((*cp != '\\' && *cp != '^') || !cp[1]) {
837 /* simple character, or nothing left for \ or ^ to escape */
839 } else if (*cp == '^') { /* expand control-character syntax */
840 cval = (*++cp & 0x1f);
842 /* remaining cases are all for backslash and we know cp[1] is not
844 } else if (index(dec, cp[1])) {
845 ++cp; /* move past backslash to first digit */
847 cval = (cval * 10) + (*cp - '0');
848 } while (*++cp && index(dec, *cp) && ++dcount < 3);
849 } else if ((cp[1] == 'o' || cp[1] == 'O') && cp[2]
850 && index(oct, cp[2])) {
851 cp += 2; /* move past backslash and 'O' */
853 cval = (cval * 8) + (*cp - '0');
854 } while (*++cp && index(oct, *cp) && ++dcount < 3);
855 } else if ((cp[1] == 'x' || cp[1] == 'X') && cp[2]
856 && (dp = index(hex, cp[2])) != 0) {
857 cp += 2; /* move past backslash and 'X' */
859 cval = (cval * 16) + ((int) (dp - hex) / 2);
860 } while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2);
861 } else { /* C-style character escapes */
892 rejectoption(optname)
896 pline("\"%s\" settable only from %s.", optname, lastconfigfile);
898 pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
908 if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
911 pline("Bad syntax: %s. Enter \"?g\" for help.", opts);
920 raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", lastconfigfile,
928 raw_printf("Bad syntax in NETHACKOPTIONS: %s%s.\n",
939 string_for_opt(opts, val_optional)
941 boolean val_optional;
943 char *colon, *equals;
945 colon = index(opts, ':');
946 equals = index(opts, '=');
947 if (!colon || (equals && equals < colon))
950 if (!colon || !*++colon) {
959 string_for_env_opt(optname, opts, val_optional)
962 boolean val_optional;
965 rejectoption(optname);
968 return string_for_opt(opts, val_optional);
972 bad_negation(optname, with_parameter)
974 boolean with_parameter;
976 pline_The("%s option may not %sbe negated.", optname,
977 with_parameter ? "both have a value and " : "");
981 * Change the inventory order, using the given string as the new order.
982 * Missing characters in the new order are filled in at the end from
983 * the current inv_order, except for gold, which is forced to be first
984 * if not explicitly present.
986 * This routine returns 1 unless there is a duplicate or bad char in
994 char *sp, buf[BUFSZ];
997 /* !!!! probably unnecessary with gold as normal inventory */
999 for (sp = op; *sp; sp++) {
1000 oc_sym = def_char_to_objclass(*sp);
1001 /* reject bad or duplicate entries */
1002 if (oc_sym == MAXOCLASSES || oc_sym == RANDOM_CLASS
1003 || oc_sym == ILLOBJ_CLASS || !index(flags.inv_order, oc_sym)
1004 || index(sp + 1, *sp))
1006 /* retain good ones */
1007 buf[num++] = (char) oc_sym;
1011 /* fill in any omitted classes, using previous ordering */
1012 for (sp = flags.inv_order; *sp; sp++)
1013 if (!index(buf, *sp)) {
1015 buf[num] = '\0'; /* explicitly terminate for next index() */
1018 Strcpy(flags.inv_order, buf);
1023 warning_opts(opts, optype)
1024 register char *opts;
1027 uchar translate[WARNCOUNT];
1030 if (!(opts = string_for_env_opt(optype, opts, FALSE)))
1032 escapes(opts, opts);
1034 length = (int) strlen(opts);
1035 /* match the form obtained from PC configuration files */
1036 for (i = 0; i < WARNCOUNT; i++)
1037 translate[i] = (i >= length) ? 0
1038 : opts[i] ? (uchar) opts[i]
1039 : def_warnsyms[i].sym;
1040 assign_warnings(translate);
1044 assign_warnings(graph_chars)
1045 register uchar *graph_chars;
1049 for (i = 0; i < WARNCOUNT; i++)
1051 warnsyms[i] = graph_chars[i];
1055 feature_alert_opts(op, optn)
1060 boolean rejectver = FALSE;
1061 unsigned long fnv = get_feature_notice_ver(op); /* version.c */
1065 if (fnv > get_current_feature_ver())
1068 flags.suppress_alert = fnv;
1071 You_cant("disable new feature alerts for future versions.");
1074 "\n%s=%s Invalid reference to a future version ignored",
1081 Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
1082 FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
1084 "Feature change alerts disabled for NetHack %s features and prior.",
1091 set_duplicate_opt_detection(on_or_off)
1096 if (on_or_off != 0) {
1098 if (iflags.opt_booldup)
1099 impossible("iflags.opt_booldup already on (memory leak)");
1100 iflags.opt_booldup = (int *) alloc(SIZE(boolopt) * sizeof(int));
1101 optptr = iflags.opt_booldup;
1102 for (k = 0; k < SIZE(boolopt); ++k)
1105 if (iflags.opt_compdup)
1106 impossible("iflags.opt_compdup already on (memory leak)");
1107 iflags.opt_compdup = (int *) alloc(SIZE(compopt) * sizeof(int));
1108 optptr = iflags.opt_compdup;
1109 for (k = 0; k < SIZE(compopt); ++k)
1113 if (iflags.opt_booldup)
1114 free((genericptr_t) iflags.opt_booldup);
1115 iflags.opt_booldup = (int *) 0;
1116 if (iflags.opt_compdup)
1117 free((genericptr_t) iflags.opt_compdup);
1118 iflags.opt_compdup = (int *) 0;
1123 duplicate_opt_detection(opts, iscompound)
1125 int iscompound; /* 0 == boolean option, 1 == compound */
1129 if (!iscompound && iflags.opt_booldup && initial && from_file) {
1130 for (i = 0; boolopt[i].name; i++) {
1131 if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
1132 optptr = iflags.opt_booldup + i;
1140 } else if (iscompound && iflags.opt_compdup && initial && from_file) {
1141 for (i = 0; compopt[i].name; i++) {
1142 if (match_optname(opts, compopt[i].name, strlen(compopt[i].name),
1144 optptr = iflags.opt_compdup + i;
1157 complain_about_duplicate(opts, iscompound)
1159 int iscompound; /* 0 == boolean option, 1 == compound */
1162 /* the Mac has trouble dealing with the output of messages while
1163 * processing the config file. That should get fixed one day.
1164 * For now just return.
1167 raw_printf("\nWarning - %s option specified multiple times: %s.\n",
1168 iscompound ? "compound" : "boolean", opts);
1174 /* paranoia[] - used by parseoptions() and special_handling() */
1175 STATIC_VAR const struct paranoia_opts {
1176 int flagmask; /* which paranoid option */
1177 const char *argname; /* primary name */
1178 int argMinLen; /* minimum number of letters to match */
1179 const char *synonym; /* alternate name (optional) */
1181 const char *explain; /* for interactive menu */
1183 /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
1184 takes precedence and "all" isn't present in the interactive menu,
1185 and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
1186 (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
1187 is just a synonym for "Confirm") */
1188 { PARANOID_CONFIRM, "Confirm", 1, "Paranoia", 2,
1189 "for \"yes\" confirmations, require \"no\" to reject" },
1190 { PARANOID_QUIT, "quit", 1, "explore", 1,
1191 "yes vs y to quit or to enter explore mode" },
1192 { PARANOID_DIE, "die", 1, "death", 2,
1193 "yes vs y to die (explore mode or debug mode)" },
1194 { PARANOID_BONES, "bones", 1, 0, 0,
1195 "yes vs y to save bones data when dying in debug mode" },
1196 { PARANOID_HIT, "attack", 1, "hit", 1,
1197 "yes vs y to attack a peaceful monster" },
1198 { PARANOID_PRAY, "pray", 1, 0, 0,
1199 "y to pray (supersedes old \"prayconfirm\" option)" },
1200 { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1,
1201 "always pick from inventory for Remove and Takeoff" },
1202 { PARANOID_BREAKWAND, "wand", 1, "breakwand", 2,
1203 "yes vs y to break a wand" },
1204 /* for config file parsing; interactive menu skips these */
1205 { 0, "none", 4, 0, 0, 0 }, /* require full word match */
1206 { ~0, "all", 3, 0, 0, 0 }, /* ditto */
1209 extern struct menucoloring *menu_colorings;
1211 static const struct {
1215 { "black", CLR_BLACK },
1217 { "green", CLR_GREEN },
1218 { "brown", CLR_BROWN },
1219 { "blue", CLR_BLUE },
1220 { "magenta", CLR_MAGENTA },
1221 { "cyan", CLR_CYAN },
1222 { "gray", CLR_GRAY },
1223 { "grey", CLR_GRAY },
1224 { "orange", CLR_ORANGE },
1225 { "light green", CLR_BRIGHT_GREEN },
1226 { "yellow", CLR_YELLOW },
1227 { "light blue", CLR_BRIGHT_BLUE },
1228 { "light magenta", CLR_BRIGHT_MAGENTA },
1229 { "light cyan", CLR_BRIGHT_CYAN },
1230 { "white", CLR_WHITE }
1233 static const struct {
1237 { "none", ATR_NONE },
1238 { "bold", ATR_BOLD },
1240 { "underline", ATR_ULINE },
1241 { "blink", ATR_BLINK },
1242 { "inverse", ATR_INVERSE }
1251 for (i = 0; i < SIZE(colornames); i++)
1252 if (colornames[i].color == clr)
1253 return colornames[i].name;
1263 for (i = 0; i < SIZE(attrnames); i++)
1264 if (attrnames[i].attr == attr)
1265 return attrnames[i].name;
1275 menu_item *picks = (menu_item *) 0;
1277 tmpwin = create_nhwindow(NHW_MENU);
1280 for (i = 0; i < SIZE(colornames); i++) {
1281 if (!strcmp(colornames[i].name, "grey"))
1284 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name,
1287 end_menu(tmpwin, "Pick a color");
1288 pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1289 destroy_nhwindow(tmpwin);
1291 i = colornames[picks->item.a_int - 1].color;
1292 free((genericptr_t) picks);
1305 menu_item *picks = (menu_item *) 0;
1307 tmpwin = create_nhwindow(NHW_MENU);
1310 for (i = 0; i < SIZE(attrnames); i++) {
1312 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr,
1313 attrnames[i].name, MENU_UNSELECTED);
1315 end_menu(tmpwin, prompt ? prompt : "Pick an attribute");
1316 pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1317 destroy_nhwindow(tmpwin);
1319 i = attrnames[picks->item.a_int - 1].attr;
1320 free((genericptr_t) picks);
1326 static const struct {
1330 } msgtype_names[] = {
1331 { "show", MSGTYP_NORMAL, "Show message normally" },
1332 { "hide", MSGTYP_NOSHOW, "Hide message" },
1333 { "noshow", MSGTYP_NOSHOW, NULL },
1334 { "stop", MSGTYP_STOP, "Prompt for more after the message" },
1335 { "more", MSGTYP_STOP, NULL },
1336 { "norep", MSGTYP_NOREP, "Do not repeat the message" }
1345 for (i = 0; i < SIZE(msgtype_names); i++)
1346 if (msgtype_names[i].descr && msgtype_names[i].msgtyp == typ)
1347 return msgtype_names[i].name;
1357 menu_item *picks = (menu_item *) 0;
1359 tmpwin = create_nhwindow(NHW_MENU);
1362 for (i = 0; i < SIZE(msgtype_names); i++)
1363 if (msgtype_names[i].descr) {
1364 any.a_int = msgtype_names[i].msgtyp + 1;
1365 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1366 msgtype_names[i].descr, MENU_UNSELECTED);
1368 end_menu(tmpwin, "How to show the message");
1369 pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
1370 destroy_nhwindow(tmpwin);
1372 i = picks->item.a_int - 1;
1373 free((genericptr_t) picks);
1380 msgtype_add(typ, pattern)
1384 struct plinemsg_type *tmp
1385 = (struct plinemsg_type *) alloc(sizeof (struct plinemsg_type));
1390 tmp->regex = regex_init();
1391 if (!regex_compile(pattern, tmp->regex)) {
1392 static const char *re_error = "MSGTYPE regex error";
1394 if (!iflags.window_inited)
1395 raw_printf("\n%s: %s\n", re_error, regex_error_desc(tmp->regex));
1397 pline("%s: %s", re_error, regex_error_desc(tmp->regex));
1399 regex_free(tmp->regex);
1400 free((genericptr_t) tmp);
1403 tmp->pattern = dupstr(pattern);
1404 tmp->next = plinemsg_types;
1405 plinemsg_types = tmp;
1412 struct plinemsg_type *tmp, *tmp2 = 0;
1414 for (tmp = plinemsg_types; tmp; tmp = tmp2) {
1416 free((genericptr_t) tmp->pattern);
1417 regex_free(tmp->regex);
1418 free((genericptr_t) tmp);
1420 plinemsg_types = (struct plinemsg_type *) 0;
1424 free_one_msgtype(idx)
1427 struct plinemsg_type *tmp = plinemsg_types;
1428 struct plinemsg_type *prev = NULL;
1432 struct plinemsg_type *next = tmp->next;
1434 regex_free(tmp->regex);
1435 free((genericptr_t) tmp->pattern);
1436 free((genericptr_t) tmp);
1440 plinemsg_types = next;
1453 struct plinemsg_type *tmp = plinemsg_types;
1456 if (regex_match(msg, tmp->regex))
1457 return tmp->msgtype;
1460 return MSGTYP_NORMAL;
1467 struct plinemsg_type *tmp = plinemsg_types;
1477 msgtype_parse_add(str)
1483 if (sscanf(str, "%10s \"%255[^\"]\"", msgtype, pattern) == 2) {
1487 for (i = 0; i < SIZE(msgtype_names); i++)
1488 if (!strncmpi(msgtype_names[i].name, msgtype, strlen(msgtype))) {
1489 typ = msgtype_names[i].msgtyp;
1493 return msgtype_add(typ, pattern);
1499 add_menu_coloring_parsed(str, c, a)
1503 static const char re_error[] = "Menucolor regex error";
1504 struct menucoloring *tmp;
1508 tmp = (struct menucoloring *) alloc(sizeof (struct menucoloring));
1509 tmp->match = regex_init();
1510 if (!regex_compile(str, tmp->match)) {
1511 if (!iflags.window_inited)
1512 raw_printf("\n%s: %s\n", re_error, regex_error_desc(tmp->match));
1514 pline("%s: %s", re_error, regex_error_desc(tmp->match));
1516 regex_free(tmp->match);
1520 tmp->next = menu_colorings;
1521 tmp->origstr = dupstr(str);
1524 menu_colorings = tmp;
1529 /* parse '"regex_string"=color&attr' and add it to menucoloring */
1531 add_menu_coloring(str)
1534 int i, c = NO_COLOR, a = ATR_NONE;
1535 char *tmps, *cs, *amp;
1537 if (!str || (cs = index(str, '=')) == 0)
1540 tmps = cs + 1; /* advance past '=' */
1542 if ((amp = index(tmps, '&')) != 0)
1545 /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
1546 (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
1547 also copes with trailing space; mungspaces removed any leading space */
1548 for (i = 0; i < SIZE(colornames); i++)
1549 if (fuzzymatch(tmps, colornames[i].name, " -_", TRUE)) {
1550 c = colornames[i].color;
1553 if (i == SIZE(colornames) && (*tmps >= '0' && *tmps <= '9'))
1560 tmps = amp + 1; /* advance past '&' */
1561 /* unlike colors, none of he attribute names has any embedded spaces,
1562 but use of fuzzymatch() allows us ignore the presence of leading
1563 and/or trailing (and also embedded) spaces in the user's string;
1564 dash and underscore skipping could be omitted but does no harm */
1565 for (i = 0; i < SIZE(attrnames); i++)
1566 if (fuzzymatch(tmps, attrnames[i].name, " -_", TRUE)) {
1567 a = attrnames[i].attr;
1570 if (i == SIZE(attrnames) && (*tmps >= '0' && *tmps <= '9'))
1574 /* the regexp portion here has not been condensed by mungspaces() */
1577 if (*tmps == '"' || *tmps == '\'') {
1579 while (isspace((uchar) *cs))
1587 return add_menu_coloring_parsed(tmps, c, a);
1591 get_menu_coloring(str, color, attr)
1595 struct menucoloring *tmpmc;
1597 if (iflags.use_menu_color)
1598 for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next)
1599 if (regex_match(str, tmpmc->match)) {
1600 *color = tmpmc->color;
1601 *attr = tmpmc->attr;
1608 free_menu_coloring()
1610 struct menucoloring *tmp = menu_colorings;
1613 struct menucoloring *tmp2 = tmp->next;
1615 regex_free(tmp->match);
1616 free((genericptr_t) tmp->origstr);
1617 free((genericptr_t) tmp);
1623 free_one_menu_coloring(idx)
1626 struct menucoloring *tmp = menu_colorings;
1627 struct menucoloring *prev = NULL;
1631 struct menucoloring *next = tmp->next;
1633 regex_free(tmp->match);
1634 free((genericptr_t) tmp->origstr);
1635 free((genericptr_t) tmp);
1639 menu_colorings = next;
1652 struct menucoloring *tmp = menu_colorings;
1662 parseoptions(opts, tinitial, tfrom_file)
1663 register char *opts;
1664 boolean tinitial, tfrom_file;
1668 boolean negated, val_negated, duplicate;
1670 const char *fullname;
1673 from_file = tfrom_file;
1674 if ((op = index(opts, ',')) != 0) {
1676 parseoptions(op, initial, from_file);
1678 if (strlen(opts) > BUFSZ / 2) {
1679 badoption("option too long");
1683 /* strip leading and trailing white space */
1684 while (isspace((uchar) *opts))
1687 while (--op >= opts && isspace((uchar) *op))
1693 while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
1701 /* variant spelling */
1703 if (match_optname(opts, "colour", 5, FALSE))
1704 Strcpy(opts, "color"); /* fortunately this isn't longer */
1706 /* special boolean options */
1708 if (match_optname(opts, "female", 3, FALSE)) {
1709 if (duplicate_opt_detection(opts, 0))
1710 complain_about_duplicate(opts, 0);
1711 if (!initial && flags.female == negated)
1712 pline("That is not anatomically possible.");
1714 flags.initgend = flags.female = !negated;
1718 if (match_optname(opts, "male", 4, FALSE)) {
1719 if (duplicate_opt_detection(opts, 0))
1720 complain_about_duplicate(opts, 0);
1721 if (!initial && flags.female != negated)
1722 pline("That is not anatomically possible.");
1724 flags.initgend = flags.female = negated;
1728 #if defined(MICRO) && !defined(AMIGA)
1729 /* included for compatibility with old NetHack.cnf files */
1730 if (match_optname(opts, "IBM_", 4, FALSE)) {
1731 iflags.BIOS = !negated;
1736 /* compound options */
1738 /* This first batch can be duplicated if their values are negated */
1742 if (match_optname(opts, fullname, sizeof("align") - 1, TRUE)) {
1744 bad_negation(fullname, FALSE);
1745 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1746 val_negated = FALSE;
1747 while ((*op == '!') || !strncmpi(op, "no", 2)) {
1752 val_negated = !val_negated;
1755 if (!setrolefilter(op))
1758 if (duplicate_opt_detection(opts, 1))
1759 complain_about_duplicate(opts, 1);
1760 if ((flags.initalign = str2align(op)) == ROLE_NONE)
1767 /* role:string or character:string */
1769 if (match_optname(opts, fullname, 4, TRUE)
1770 || match_optname(opts, (fullname = "character"), 4, TRUE)) {
1772 bad_negation(fullname, FALSE);
1773 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1774 val_negated = FALSE;
1775 while ((*op == '!') || !strncmpi(op, "no", 2)) {
1780 val_negated = !val_negated;
1783 if (!setrolefilter(op))
1786 if (duplicate_opt_detection(opts, 1))
1787 complain_about_duplicate(opts, 1);
1788 if ((flags.initrole = str2role(op)) == ROLE_NONE)
1790 else /* Backwards compatibility */
1791 nmcpy(pl_character, op, PL_NSIZ);
1799 if (match_optname(opts, fullname, 4, TRUE)) {
1801 bad_negation(fullname, FALSE);
1802 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1803 val_negated = FALSE;
1804 while ((*op == '!') || !strncmpi(op, "no", 2)) {
1809 val_negated = !val_negated;
1812 if (!setrolefilter(op))
1815 if (duplicate_opt_detection(opts, 1))
1816 complain_about_duplicate(opts, 1);
1817 if ((flags.initrace = str2race(op)) == ROLE_NONE)
1819 else /* Backwards compatibility */
1827 fullname = "gender";
1828 if (match_optname(opts, fullname, 4, TRUE)) {
1830 bad_negation(fullname, FALSE);
1831 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1832 val_negated = FALSE;
1833 while ((*op == '!') || !strncmpi(op, "no", 2)) {
1838 val_negated = !val_negated;
1841 if (!setrolefilter(op))
1844 if (duplicate_opt_detection(opts, 1))
1845 complain_about_duplicate(opts, 1);
1846 if ((flags.initgend = str2gend(op)) == ROLE_NONE)
1849 flags.female = flags.initgend;
1855 /* We always check for duplicates on the remaining compound options,
1856 although individual option processing can choose to complain or not */
1859 duplicate_opt_detection(opts, 1); /* 1 means check compounds */
1861 fullname = "pettype";
1862 if (match_optname(opts, fullname, 3, TRUE)) {
1864 complain_about_duplicate(opts, 1);
1865 if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
1867 bad_negation(fullname, TRUE);
1869 switch (lowc(*op)) {
1871 preferred_pet = 'd';
1874 case 'f': /* feline */
1875 preferred_pet = 'c';
1877 case 'h': /* horse */
1878 case 'q': /* quadruped */
1879 /* avoids giving "unrecognized type of pet" but
1880 pet_type(dog.c) won't actually honor this */
1881 preferred_pet = 'h';
1883 case 'n': /* no pet */
1884 preferred_pet = 'n';
1886 case '*': /* random */
1887 preferred_pet = '\0';
1890 pline("Unrecognized pet type '%s'.", op);
1894 preferred_pet = 'n';
1898 fullname = "catname";
1899 if (match_optname(opts, fullname, 3, TRUE)) {
1901 complain_about_duplicate(opts, 1);
1903 bad_negation(fullname, FALSE);
1904 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1905 nmcpy(catname, op, PL_PSIZ);
1906 sanitize_name(catname);
1910 fullname = "dogname";
1911 if (match_optname(opts, fullname, 3, TRUE)) {
1913 complain_about_duplicate(opts, 1);
1915 bad_negation(fullname, FALSE);
1916 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1917 nmcpy(dogname, op, PL_PSIZ);
1918 sanitize_name(dogname);
1922 fullname = "horsename";
1923 if (match_optname(opts, fullname, 5, TRUE)) {
1925 complain_about_duplicate(opts, 1);
1927 bad_negation(fullname, FALSE);
1928 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1929 nmcpy(horsename, op, PL_PSIZ);
1930 sanitize_name(horsename);
1934 fullname = "number_pad";
1935 if (match_optname(opts, fullname, 10, TRUE)) {
1936 boolean compat = (strlen(opts) <= 10);
1939 complain_about_duplicate(opts, 1);
1940 op = string_for_opt(opts, (compat || !initial));
1942 if (compat || negated || initial) {
1943 /* for backwards compatibility, "number_pad" without a
1944 value is a synonym for number_pad:1 */
1945 iflags.num_pad = !negated;
1946 iflags.num_pad_mode = 0;
1948 } else if (negated) {
1949 bad_negation("number_pad", TRUE);
1952 int mode = atoi(op);
1954 if (mode < -1 || mode > 4 || (mode == 0 && *op != '0')) {
1957 } else if (mode <= 0) {
1958 iflags.num_pad = FALSE;
1959 /* German keyboard; y and z keys swapped */
1960 iflags.num_pad_mode = (mode < 0); /* 0 or 1 */
1961 } else { /* mode > 0 */
1962 iflags.num_pad = TRUE;
1963 iflags.num_pad_mode = 0;
1964 /* PC Hack / MSDOS compatibility */
1965 if (mode == 2 || mode == 4)
1966 iflags.num_pad_mode |= 1;
1967 /* phone keypad layout */
1968 if (mode == 3 || mode == 4)
1969 iflags.num_pad_mode |= 2;
1972 reset_commands(FALSE);
1973 number_pad(iflags.num_pad ? 1 : 0);
1977 fullname = "roguesymset";
1978 if (match_optname(opts, fullname, 7, TRUE)) {
1980 complain_about_duplicate(opts, 1);
1982 bad_negation(fullname, FALSE);
1983 } else if ((op = string_for_opt(opts, FALSE)) != 0) {
1984 symset[ROGUESET].name = dupstr(op);
1985 if (!read_sym_file(ROGUESET)) {
1986 clear_symsetentry(ROGUESET, TRUE);
1987 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
1991 if (!initial && Is_rogue_level(&u.uz))
1992 assign_graphics(ROGUESET);
1999 fullname = "symset";
2000 if (match_optname(opts, fullname, 6, TRUE)) {
2002 complain_about_duplicate(opts, 1);
2004 bad_negation(fullname, FALSE);
2005 } else if ((op = string_for_opt(opts, FALSE)) != 0) {
2006 symset[PRIMARY].name = dupstr(op);
2007 if (!read_sym_file(PRIMARY)) {
2008 clear_symsetentry(PRIMARY, TRUE);
2009 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2013 switch_symbols(TRUE);
2020 fullname = "runmode";
2021 if (match_optname(opts, fullname, 4, TRUE)) {
2023 complain_about_duplicate(opts, 1);
2025 flags.runmode = RUN_TPORT;
2026 } else if ((op = string_for_opt(opts, FALSE)) != 0) {
2027 if (!strncmpi(op, "teleport", strlen(op)))
2028 flags.runmode = RUN_TPORT;
2029 else if (!strncmpi(op, "run", strlen(op)))
2030 flags.runmode = RUN_LEAP;
2031 else if (!strncmpi(op, "walk", strlen(op)))
2032 flags.runmode = RUN_STEP;
2033 else if (!strncmpi(op, "crawl", strlen(op)))
2034 flags.runmode = RUN_CRAWL;
2041 /* menucolor:"regex_string"=color */
2042 fullname = "menucolor";
2043 if (match_optname(opts, fullname, 9, TRUE)) {
2045 bad_negation(fullname, FALSE);
2046 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
2047 if (!add_menu_coloring(op))
2052 fullname = "msghistory";
2053 if (match_optname(opts, fullname, 3, TRUE)) {
2055 complain_about_duplicate(opts, 1);
2056 op = string_for_env_opt(fullname, opts, negated);
2057 if ((negated && !op) || (!negated && op)) {
2058 iflags.msg_history = negated ? 0 : atoi(op);
2060 bad_negation(fullname, TRUE);
2064 fullname = "msg_window";
2065 /* msg_window:single, combo, full or reversed */
2066 if (match_optname(opts, fullname, 4, TRUE)) {
2067 /* allow option to be silently ignored by non-tty ports */
2072 complain_about_duplicate(opts, 1);
2073 if (!(op = string_for_opt(opts, TRUE))) {
2074 tmp = negated ? 's' : 'f';
2077 bad_negation(fullname, TRUE);
2083 case 's': /* single message history cycle (default if negated) */
2084 iflags.prevmsg_window = 's';
2086 case 'c': /* combination: two singles, then full page reversed */
2087 iflags.prevmsg_window = 'c';
2089 case 'f': /* full page (default if no opts) */
2090 iflags.prevmsg_window = 'f';
2092 case 'r': /* full page (reversed) */
2093 iflags.prevmsg_window = 'r';
2103 * setting font options */
2105 if (!strncmpi(opts, fullname, 4)) {
2107 char *fontopts = opts + 4;
2109 if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4))
2110 opttype = MAP_OPTION;
2111 else if (!strncmpi(fontopts, "message", 7)
2112 || !strncmpi(fontopts, "_message", 8))
2113 opttype = MESSAGE_OPTION;
2114 else if (!strncmpi(fontopts, "text", 4)
2115 || !strncmpi(fontopts, "_text", 5))
2116 opttype = TEXT_OPTION;
2117 else if (!strncmpi(fontopts, "menu", 4)
2118 || !strncmpi(fontopts, "_menu", 5))
2119 opttype = MENU_OPTION;
2120 else if (!strncmpi(fontopts, "status", 6)
2121 || !strncmpi(fontopts, "_status", 7))
2122 opttype = STATUS_OPTION;
2123 else if (!strncmpi(fontopts, "_size", 5)) {
2124 if (!strncmpi(fontopts, "_size_map", 8))
2125 opttype = MAP_OPTION;
2126 else if (!strncmpi(fontopts, "_size_message", 12))
2127 opttype = MESSAGE_OPTION;
2128 else if (!strncmpi(fontopts, "_size_text", 9))
2129 opttype = TEXT_OPTION;
2130 else if (!strncmpi(fontopts, "_size_menu", 9))
2131 opttype = MENU_OPTION;
2132 else if (!strncmpi(fontopts, "_size_status", 11))
2133 opttype = STATUS_OPTION;
2139 complain_about_duplicate(opts, 1);
2140 if (opttype > 0 && !negated
2141 && (op = string_for_opt(opts, FALSE)) != 0) {
2144 iflags.wc_fontsiz_map = atoi(op);
2146 case MESSAGE_OPTION:
2147 iflags.wc_fontsiz_message = atoi(op);
2150 iflags.wc_fontsiz_text = atoi(op);
2153 iflags.wc_fontsiz_menu = atoi(op);
2156 iflags.wc_fontsiz_status = atoi(op);
2164 if (opttype > 0 && (op = string_for_opt(opts, FALSE)) != 0) {
2165 wc_set_font_name(opttype, op);
2167 set_font_name(opttype, op);
2171 bad_negation(fullname, TRUE);
2175 if (match_optname(opts, "palette", 3, TRUE)
2177 || match_optname(opts, "hicolor", 3, TRUE)
2180 int color_number, color_incr;
2184 complain_about_duplicate(opts, 1);
2187 if (match_optname(opts, "hicolor", 3, TRUE)) {
2189 bad_negation("hicolor", FALSE);
2192 color_number = CLR_MAX + 4; /* HARDCODED inverse number */
2197 bad_negation("palette", FALSE);
2206 op = string_for_opt(opts, TRUE);
2207 if (!alternative_palette(op))
2210 if ((op = string_for_opt(opts, FALSE)) != (char *) 0) {
2212 int cnt, tmp, reverse;
2215 while (*pt && color_number >= 0) {
2225 if (*pt && *pt != '/') {
2233 tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
2235 tmp &= 0xf; /* Digits in ASCII too... */
2238 /* Add an extra so we fill f -> ff and 0 -> 00 */
2247 change_color(color_number, rgb, reverse);
2248 color_number += color_incr;
2257 #endif /* CHANGE_COLOR */
2259 if (match_optname(opts, "fruit", 2, TRUE)) {
2260 struct fruit *forig = 0;
2261 char empty_str = '\0';
2264 complain_about_duplicate(opts, 1);
2265 op = string_for_opt(opts, negated);
2268 bad_negation("fruit", TRUE);
2280 for (f = ffruit; f; f = f->nextf) {
2281 if (!strcmp(op, f->fname))
2285 if (!flags.made_fruit) {
2286 for (forig = ffruit; forig; forig = forig->nextf) {
2287 if (!strcmp(pl_fruit, forig->fname)) {
2292 if (!forig && num >= 100) {
2293 pline("Doing that so many times isn't very fruitful.");
2298 nmcpy(pl_fruit, op, PL_FSIZ);
2299 sanitize_name(pl_fruit);
2300 /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
2302 nmcpy(pl_fruit, "slime mold", PL_FSIZ);
2304 (void) fruitadd(pl_fruit, forig);
2305 pline("Fruit is now \"%s\".", pl_fruit);
2307 /* If initial, then initoptions is allowed to do it instead
2308 * of here (initoptions always has to do it even if there's
2309 * no fruit option at all. Also, we don't want people
2310 * setting multiple fruits in their options.)
2315 fullname = "warnings";
2316 if (match_optname(opts, fullname, 5, TRUE)) {
2318 complain_about_duplicate(opts, 1);
2320 bad_negation(fullname, FALSE);
2322 warning_opts(opts, fullname);
2326 #ifdef BACKWARD_COMPAT
2327 /* boulder:symbol */
2328 fullname = "boulder";
2329 if (match_optname(opts, fullname, 7, TRUE)) {
2332 complain_about_duplicate(opts, 1);
2334 bad_negation(fullname, FALSE);
2337 /* if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
2339 if (!(opts = string_for_opt(opts, FALSE)))
2341 escapes(opts, opts);
2342 if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
2344 else if (opts[0] >= '1' && opts[0] <= '5')
2347 /* symbol chosen matches a used monster or warning
2348 symbol which is not good - reject it*/
2350 "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
2351 opts[0], (clash == 1) ? "monster" : "warning");
2354 * Override the default boulder symbol.
2356 iflags.bouldersym = (uchar) opts[0];
2366 if (match_optname(opts, fullname, 4, TRUE)) {
2368 complain_about_duplicate(opts, 1);
2370 bad_negation(fullname, FALSE);
2371 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
2372 nmcpy(plname, op, PL_NSIZ);
2376 /* altkeyhandler:string */
2377 fullname = "altkeyhandler";
2378 if (match_optname(opts, fullname, 4, TRUE)) {
2380 complain_about_duplicate(opts, 1);
2382 bad_negation(fullname, FALSE);
2383 } else if ((op = string_for_opt(opts, negated)) != 0) {
2385 (void) strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
2386 load_keyboard_handler();
2393 * align_status:[left|top|right|bottom] */
2394 fullname = "align_status";
2395 if (match_optname(opts, fullname, sizeof("align_status") - 1, TRUE)) {
2396 op = string_for_opt(opts, negated);
2397 if (op && !negated) {
2398 if (!strncmpi(op, "left", sizeof("left") - 1))
2399 iflags.wc_align_status = ALIGN_LEFT;
2400 else if (!strncmpi(op, "top", sizeof("top") - 1))
2401 iflags.wc_align_status = ALIGN_TOP;
2402 else if (!strncmpi(op, "right", sizeof("right") - 1))
2403 iflags.wc_align_status = ALIGN_RIGHT;
2404 else if (!strncmpi(op, "bottom", sizeof("bottom") - 1))
2405 iflags.wc_align_status = ALIGN_BOTTOM;
2409 bad_negation(fullname, TRUE);
2413 * align_message:[left|top|right|bottom] */
2414 fullname = "align_message";
2415 if (match_optname(opts, fullname, sizeof("align_message") - 1, TRUE)) {
2417 complain_about_duplicate(opts, 1);
2418 op = string_for_opt(opts, negated);
2419 if (op && !negated) {
2420 if (!strncmpi(op, "left", sizeof("left") - 1))
2421 iflags.wc_align_message = ALIGN_LEFT;
2422 else if (!strncmpi(op, "top", sizeof("top") - 1))
2423 iflags.wc_align_message = ALIGN_TOP;
2424 else if (!strncmpi(op, "right", sizeof("right") - 1))
2425 iflags.wc_align_message = ALIGN_RIGHT;
2426 else if (!strncmpi(op, "bottom", sizeof("bottom") - 1))
2427 iflags.wc_align_message = ALIGN_BOTTOM;
2431 bad_negation(fullname, TRUE);
2434 /* the order to list the pack */
2435 fullname = "packorder";
2436 if (match_optname(opts, fullname, 4, TRUE)) {
2438 complain_about_duplicate(opts, 1);
2440 bad_negation(fullname, FALSE);
2442 } else if (!(op = string_for_opt(opts, FALSE)))
2445 if (!change_inv_order(op))
2450 /* user can change required response for some prompts (quit, die, hit),
2451 or add an extra prompt (pray, Remove) that isn't ordinarily there */
2452 fullname = "paranoid_confirmation";
2453 if (match_optname(opts, fullname, 8, TRUE)) {
2454 /* at present we don't complain about duplicates for this
2455 option, but we do throw away the old settings whenever
2456 we process a new one [clearing old flags is essential
2457 for handling default paranoid_confirm:pray sanely] */
2458 flags.paranoia_bits = 0; /* clear all */
2460 flags.paranoia_bits = 0; /* [now redundant...] */
2461 } else if ((op = string_for_opt(opts, TRUE)) != 0) {
2462 char *pp, buf[BUFSZ];
2464 op = mungspaces(strcpy(buf, op));
2466 /* We're looking to parse
2467 "paranoid_confirm:whichone wheretwo whothree"
2468 and "paranoid_confirm:" prefix has already
2469 been stripped off by the time we get here */
2470 pp = index(op, ' ');
2473 /* we aren't matching option names but match_optname
2474 does what we want once we've broken the space
2475 delimited aggregate into separate tokens */
2476 for (i = 0; i < SIZE(paranoia); ++i) {
2477 if (match_optname(op, paranoia[i].argname,
2478 paranoia[i].argMinLen, FALSE)
2479 || (paranoia[i].synonym
2480 && match_optname(op, paranoia[i].synonym,
2481 paranoia[i].synMinLen, FALSE))) {
2482 if (paranoia[i].flagmask)
2483 flags.paranoia_bits |= paranoia[i].flagmask;
2484 else /* 0 == "none", so clear all */
2485 flags.paranoia_bits = 0;
2489 if (i == SIZE(paranoia)) {
2490 /* didn't match anything, so arg is bad;
2491 any flags already set will stay set */
2495 /* move on to next token */
2499 break; /* no next token */
2505 /* accept deprecated boolean; superseded by paranoid_confirm:pray */
2506 fullname = "prayconfirm";
2507 if (match_optname(opts, fullname, 4, FALSE)) {
2509 flags.paranoia_bits &= ~PARANOID_PRAY;
2511 flags.paranoia_bits |= PARANOID_PRAY;
2515 /* maximum burden picked up before prompt (Warren Cheung) */
2516 fullname = "pickup_burden";
2517 if (match_optname(opts, fullname, 8, TRUE)) {
2519 complain_about_duplicate(opts, 1);
2521 bad_negation(fullname, FALSE);
2523 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
2524 switch (tolower(*op)) {
2527 flags.pickup_burden = UNENCUMBERED;
2529 /* Burdened (slight encumbrance) */
2531 flags.pickup_burden = SLT_ENCUMBER;
2533 /* streSsed (moderate encumbrance) */
2535 flags.pickup_burden = MOD_ENCUMBER;
2537 /* straiNed (heavy encumbrance) */
2539 flags.pickup_burden = HVY_ENCUMBER;
2541 /* OverTaxed (extreme encumbrance) */
2544 flags.pickup_burden = EXT_ENCUMBER;
2548 flags.pickup_burden = OVERLOADED;
2557 /* types of objects to pick up automatically */
2558 if (match_optname(opts, "pickup_types", 8, TRUE)) {
2559 char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], qbuf[QBUFSZ],
2562 boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
2565 complain_about_duplicate(opts, 1);
2566 oc_to_str(flags.pickup_types, tbuf);
2567 flags.pickup_types[0] = '\0'; /* all */
2568 op = string_for_opt(opts, (compat || !initial));
2570 if (compat || negated || initial) {
2571 /* for backwards compatibility, "pickup" without a
2572 value is a synonym for autopickup of all types
2573 (and during initialization, we can't prompt yet) */
2574 flags.pickup = !negated;
2577 oc_to_str(flags.inv_order, ocl);
2579 if (flags.menu_style == MENU_TRADITIONAL
2580 || flags.menu_style == MENU_COMBINATION) {
2582 Sprintf(qbuf, "New pickup_types: [%s am] (%s)", ocl,
2583 *tbuf ? tbuf : "all");
2585 op = mungspaces(abuf);
2586 if (abuf[0] == '\0' || abuf[0] == '\033')
2587 op = tbuf; /* restore */
2588 else if (abuf[0] == 'm')
2592 (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE, ocl,
2598 bad_negation("pickup_types", TRUE);
2603 if (*op != 'a' && *op != 'A') {
2606 oc_sym = def_char_to_objclass(*op);
2607 /* make sure all are valid obj symbols occurring once */
2608 if (oc_sym != MAXOCLASSES
2609 && !index(flags.pickup_types, oc_sym)) {
2610 flags.pickup_types[num] = (char) oc_sym;
2611 flags.pickup_types[++num] = '\0';
2622 /* pile limit: when walking over objects, number which triggers
2623 "there are several/many objects here" instead of listing them */
2624 fullname = "pile_limit";
2625 if (match_optname(opts, fullname, 4, TRUE)) {
2627 complain_about_duplicate(opts, 1);
2628 op = string_for_opt(opts, negated);
2629 if ((negated && !op) || (!negated && op))
2630 flags.pile_limit = negated ? 0 : atoi(op);
2632 bad_negation(fullname, TRUE);
2634 flags.pile_limit = PILE_LIMIT_DFLT;
2636 if (flags.pile_limit < 0)
2637 flags.pile_limit = PILE_LIMIT_DFLT;
2641 /* play mode: normal, explore/discovery, or debug/wizard */
2642 fullname = "playmode";
2643 if (match_optname(opts, fullname, 4, TRUE)) {
2645 complain_about_duplicate(opts, 1);
2647 bad_negation(fullname, FALSE);
2648 if (duplicate || negated)
2650 op = string_for_opt(opts, TRUE);
2651 if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) {
2652 wizard = discover = FALSE;
2653 } else if (!strncmpi(op, "explore", 6)
2654 || !strncmpi(op, "discovery", 6)) {
2655 wizard = FALSE, discover = TRUE;
2656 } else if (!strncmpi(op, "debug", 5) || !strncmpi(op, "wizard", 6)) {
2657 wizard = TRUE, discover = FALSE;
2659 raw_printf("Invalid value for \"%s\":%s.", fullname, op);
2665 * player_selection: dialog | prompts */
2666 fullname = "player_selection";
2667 if (match_optname(opts, fullname, sizeof("player_selection") - 1, TRUE)) {
2669 complain_about_duplicate(opts, 1);
2670 op = string_for_opt(opts, negated);
2671 if (op && !negated) {
2672 if (!strncmpi(op, "dialog", sizeof("dialog") - 1))
2673 iflags.wc_player_selection = VIA_DIALOG;
2674 else if (!strncmpi(op, "prompt", sizeof("prompt") - 1))
2675 iflags.wc_player_selection = VIA_PROMPTS;
2679 bad_negation(fullname, TRUE);
2683 /* things to disclose at end of game */
2684 if (match_optname(opts, "disclose", 7, TRUE)) {
2686 * The order that the end_disclose options are stored:
2687 * inventory, attribs, vanquished, genocided,
2688 * conduct, overview.
2689 * There is an array in flags:
2690 * end_disclose[NUM_DISCLOSURE_OPT];
2691 * with option settings for the each of the following:
2692 * iagvc [see disclosure_options in decl.c]:
2693 * Legal setting values in that array are:
2694 * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
2695 * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
2696 * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
2697 * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
2699 * Those setting values can be used in the option
2700 * string as a prefix to get the desired behaviour.
2702 * For backward compatibility, no prefix is required,
2703 * and the presence of a i,a,g,v, or c without a prefix
2704 * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
2706 boolean badopt = FALSE;
2707 int idx, prefix_val;
2710 complain_about_duplicate(opts, 1);
2711 op = string_for_opt(opts, TRUE);
2712 if (op && negated) {
2713 bad_negation("disclose", TRUE);
2716 /* "disclose" without a value means "all with prompting"
2717 and negated means "none without prompting" */
2718 if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
2719 if (op && !strcmpi(op, "none"))
2721 for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
2722 flags.end_disclose[num] = negated
2723 ? DISCLOSE_NO_WITHOUT_PROMPT
2724 : DISCLOSE_PROMPT_DEFAULT_YES;
2730 while (*op && num < sizeof flags.end_disclose - 1) {
2731 static char valid_settings[] = {
2732 DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO,
2733 DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT, '\0'
2735 register char c, *dop;
2739 c = 'v'; /* killed -> vanquished */
2741 c = 'o'; /* dungeon -> overview */
2742 dop = index(disclosure_options, c);
2744 idx = (int) (dop - disclosure_options);
2745 if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
2746 impossible("bad disclosure index %d %c", idx, c);
2749 if (prefix_val != -1) {
2750 flags.end_disclose[idx] = prefix_val;
2753 flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
2754 } else if (index(valid_settings, c)) {
2756 } else if (c == ' ') {
2767 /* scores:5t[op] 5a[round] o[wn] */
2768 if (match_optname(opts, "scores", 4, TRUE)) {
2770 complain_about_duplicate(opts, 1);
2772 bad_negation("scores", FALSE);
2775 if (!(op = string_for_opt(opts, FALSE)))
2785 } else if (*op == '!') {
2795 flags.end_top = inum;
2799 flags.end_around = inum;
2803 flags.end_own = !negated;
2809 while (letter(*++op) || *op == ' ')
2817 fullname = "sortloot";
2818 if (match_optname(opts, fullname, 4, TRUE)) {
2819 op = string_for_env_opt(fullname, opts, FALSE);
2821 switch (tolower(*op)) {
2825 flags.sortloot = tolower(*op);
2835 fullname = "suppress_alert";
2836 if (match_optname(opts, fullname, 4, TRUE)) {
2838 complain_about_duplicate(opts, 1);
2839 op = string_for_opt(opts, negated);
2841 bad_negation(fullname, FALSE);
2843 (void) feature_alert_opts(op, fullname);
2848 /* videocolors:string */
2849 fullname = "videocolors";
2850 if (match_optname(opts, fullname, 6, TRUE)
2851 || match_optname(opts, "videocolours", 10, TRUE)) {
2853 complain_about_duplicate(opts, 1);
2855 bad_negation(fullname, FALSE);
2857 } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2860 if (!assign_videocolors(opts))
2864 /* videoshades:string */
2865 fullname = "videoshades";
2866 if (match_optname(opts, fullname, 6, TRUE)) {
2868 complain_about_duplicate(opts, 1);
2870 bad_negation(fullname, FALSE);
2872 } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2875 if (!assign_videoshades(opts))
2879 #endif /* VIDEOSHADES */
2882 /* video:string -- must be after longer tests */
2884 if (match_optname(opts, fullname, 5, TRUE)) {
2886 complain_about_duplicate(opts, 1);
2888 bad_negation(fullname, FALSE);
2890 } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2893 if (!assign_video(opts))
2897 #endif /* NO_TERMS */
2898 /* soundcard:string -- careful not to match boolean 'sound' */
2899 fullname = "soundcard";
2900 if (match_optname(opts, fullname, 6, TRUE)) {
2902 complain_about_duplicate(opts, 1);
2904 bad_negation(fullname, FALSE);
2906 } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2909 if (!assign_soundcard(opts))
2917 * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|
2918 * ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen]
2920 fullname = "map_mode";
2921 if (match_optname(opts, fullname, sizeof("map_mode") - 1, TRUE)) {
2923 complain_about_duplicate(opts, 1);
2924 op = string_for_opt(opts, negated);
2925 if (op && !negated) {
2926 if (!strncmpi(op, "tiles", sizeof("tiles") - 1))
2927 iflags.wc_map_mode = MAP_MODE_TILES;
2928 else if (!strncmpi(op, "ascii4x6", sizeof("ascii4x6") - 1))
2929 iflags.wc_map_mode = MAP_MODE_ASCII4x6;
2930 else if (!strncmpi(op, "ascii6x8", sizeof("ascii6x8") - 1))
2931 iflags.wc_map_mode = MAP_MODE_ASCII6x8;
2932 else if (!strncmpi(op, "ascii8x8", sizeof("ascii8x8") - 1))
2933 iflags.wc_map_mode = MAP_MODE_ASCII8x8;
2934 else if (!strncmpi(op, "ascii16x8", sizeof("ascii16x8") - 1))
2935 iflags.wc_map_mode = MAP_MODE_ASCII16x8;
2936 else if (!strncmpi(op, "ascii7x12", sizeof("ascii7x12") - 1))
2937 iflags.wc_map_mode = MAP_MODE_ASCII7x12;
2938 else if (!strncmpi(op, "ascii8x12", sizeof("ascii8x12") - 1))
2939 iflags.wc_map_mode = MAP_MODE_ASCII8x12;
2940 else if (!strncmpi(op, "ascii16x12", sizeof("ascii16x12") - 1))
2941 iflags.wc_map_mode = MAP_MODE_ASCII16x12;
2942 else if (!strncmpi(op, "ascii12x16", sizeof("ascii12x16") - 1))
2943 iflags.wc_map_mode = MAP_MODE_ASCII12x16;
2944 else if (!strncmpi(op, "ascii10x18", sizeof("ascii10x18") - 1))
2945 iflags.wc_map_mode = MAP_MODE_ASCII10x18;
2946 else if (!strncmpi(op, "fit_to_screen",
2947 sizeof("fit_to_screen") - 1))
2948 iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
2952 bad_negation(fullname, TRUE);
2956 * scroll_amount:nn */
2957 fullname = "scroll_amount";
2958 if (match_optname(opts, fullname, sizeof("scroll_amount") - 1, TRUE)) {
2960 complain_about_duplicate(opts, 1);
2961 op = string_for_opt(opts, negated);
2962 if ((negated && !op) || (!negated && op)) {
2963 iflags.wc_scroll_amount = negated ? 1 : atoi(op);
2965 bad_negation(fullname, TRUE);
2969 * scroll_margin:nn */
2970 fullname = "scroll_margin";
2971 if (match_optname(opts, fullname, sizeof("scroll_margin") - 1, TRUE)) {
2973 complain_about_duplicate(opts, 1);
2974 op = string_for_opt(opts, negated);
2975 if ((negated && !op) || (!negated && op)) {
2976 iflags.wc_scroll_margin = negated ? 5 : atoi(op);
2978 bad_negation(fullname, TRUE);
2981 fullname = "subkeyvalue";
2982 if (match_optname(opts, fullname, 5, TRUE)) {
2983 /* no duplicate complaint here */
2985 bad_negation(fullname, FALSE);
2988 op = string_for_opt(opts, 0);
2989 map_subkeyvalue(op);
2996 fullname = "tile_width";
2997 if (match_optname(opts, fullname, sizeof("tile_width") - 1, TRUE)) {
2999 complain_about_duplicate(opts, 1);
3000 op = string_for_opt(opts, negated);
3001 if ((negated && !op) || (!negated && op)) {
3002 iflags.wc_tile_width = negated ? 0 : atoi(op);
3004 bad_negation(fullname, TRUE);
3009 fullname = "tile_file";
3010 if (match_optname(opts, fullname, sizeof("tile_file") - 1, TRUE)) {
3012 complain_about_duplicate(opts, 1);
3013 if ((op = string_for_opt(opts, FALSE)) != 0) {
3014 if (iflags.wc_tile_file)
3015 free(iflags.wc_tile_file);
3016 iflags.wc_tile_file = (char *) alloc(strlen(op) + 1);
3017 Strcpy(iflags.wc_tile_file, op);
3023 fullname = "tile_height";
3024 if (match_optname(opts, fullname, sizeof("tile_height") - 1, TRUE)) {
3026 complain_about_duplicate(opts, 1);
3027 op = string_for_opt(opts, negated);
3028 if ((negated && !op) || (!negated && op)) {
3029 iflags.wc_tile_height = negated ? 0 : atoi(op);
3031 bad_negation(fullname, TRUE);
3035 * vary_msgcount:nn */
3036 fullname = "vary_msgcount";
3037 if (match_optname(opts, fullname, sizeof("vary_msgcount") - 1, TRUE)) {
3039 complain_about_duplicate(opts, 1);
3040 op = string_for_opt(opts, negated);
3041 if ((negated && !op) || (!negated && op)) {
3042 iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
3044 bad_negation(fullname, TRUE);
3047 fullname = "windowtype";
3048 if (match_optname(opts, fullname, 3, TRUE)) {
3050 complain_about_duplicate(opts, 1);
3052 bad_negation(fullname, FALSE);
3054 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
3055 char buf[WINTYPELEN];
3056 nmcpy(buf, op, WINTYPELEN);
3057 choose_windows(buf);
3062 fullname = "windowchain";
3063 if (match_optname(opts, fullname, 3, TRUE)) {
3065 bad_negation(fullname, FALSE);
3067 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
3068 char buf[WINTYPELEN];
3069 nmcpy(buf, op, WINTYPELEN);
3070 addto_windowchain(buf);
3077 * setting window colors
3078 * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
3080 fullname = "windowcolors";
3081 if (match_optname(opts, fullname, 7, TRUE)) {
3083 complain_about_duplicate(opts, 1);
3084 if ((op = string_for_opt(opts, FALSE)) != 0) {
3085 if (!wc_set_window_colors(op))
3088 bad_negation(fullname, TRUE);
3092 /* menustyle:traditional or combination or full or partial */
3093 if (match_optname(opts, "menustyle", 4, TRUE)) {
3095 boolean val_required = (strlen(opts) > 5 && !negated);
3098 complain_about_duplicate(opts, 1);
3099 if (!(op = string_for_opt(opts, !val_required))) {
3101 return; /* string_for_opt gave feedback */
3102 tmp = negated ? 'n' : 'f';
3107 case 'n': /* none */
3108 case 't': /* traditional */
3109 flags.menu_style = MENU_TRADITIONAL;
3111 case 'c': /* combo: trad.class sel+menu */
3112 flags.menu_style = MENU_COMBINATION;
3114 case 'p': /* partial: no class menu */
3115 flags.menu_style = MENU_PARTIAL;
3117 case 'f': /* full: class menu + menu */
3118 flags.menu_style = MENU_FULL;
3126 fullname = "menu_headings";
3127 if (match_optname(opts, fullname, 12, TRUE)) {
3129 complain_about_duplicate(opts, 1);
3131 bad_negation(fullname, FALSE);
3133 } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
3136 for (i = 0; i < SIZE(attrnames); i++)
3137 if (!strcmpi(opts, attrnames[i].name)) {
3138 iflags.menu_headings = attrnames[i].attr;
3145 /* check for menu command mapping */
3146 for (i = 0; i < NUM_MENU_CMDS; i++) {
3147 fullname = default_menu_cmd_info[i].name;
3149 complain_about_duplicate(opts, 1);
3150 if (match_optname(opts, fullname, (int) strlen(fullname), TRUE)) {
3152 bad_negation(fullname, FALSE);
3153 } else if ((op = string_for_opt(opts, FALSE)) != 0) {
3155 char c, op_buf[BUFSZ];
3156 boolean isbad = FALSE;
3158 escapes(op, op_buf);
3161 if (c == 0 || c == '\r' || c == '\n' || c == '\033'
3162 || c == ' ' || digit(c) || (letter(c) && c != '@'))
3164 else /* reject default object class symbols */
3165 for (j = 1; j < MAXOCLASSES; j++)
3166 if (c == def_oc_syms[i].sym) {
3174 add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
3179 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
3180 /* hilite fields in status prompt */
3181 if (match_optname(opts, "hilite_status", 13, TRUE)) {
3183 complain_about_duplicate(opts, 1);
3184 op = string_for_opt(opts, TRUE);
3185 if (op && negated) {
3186 clear_status_hilites(tfrom_file);
3189 /* a value is mandatory */
3193 if (!set_status_hilites(op, tfrom_file))
3199 #if defined(BACKWARD_COMPAT)
3200 fullname = "DECgraphics";
3201 if (match_optname(opts, fullname, 3, TRUE)) {
3202 boolean badflag = FALSE;
3205 complain_about_duplicate(opts, 1);
3207 /* There is no rogue level DECgraphics-specific set */
3208 if (symset[PRIMARY].name) {
3211 symset[PRIMARY].name = dupstr(fullname);
3212 if (!read_sym_file(PRIMARY)) {
3214 clear_symsetentry(PRIMARY, TRUE);
3216 switch_symbols(TRUE);
3219 pline("Failure to load symbol set %s.", fullname);
3225 fullname = "IBMgraphics";
3226 if (match_optname(opts, fullname, 3, TRUE)) {
3227 const char *sym_name = fullname;
3228 boolean badflag = FALSE;
3231 complain_about_duplicate(opts, 1);
3233 for (i = 0; i < NUM_GRAPHICS; ++i) {
3234 if (symset[i].name) {
3238 sym_name = "RogueIBM";
3239 symset[i].name = dupstr(sym_name);
3240 if (!read_sym_file(i)) {
3242 clear_symsetentry(i, TRUE);
3248 pline("Failure to load symbol set %s.", sym_name);
3251 switch_symbols(TRUE);
3252 if (!initial && Is_rogue_level(&u.uz))
3253 assign_graphics(ROGUESET);
3259 #ifdef MAC_GRAPHICS_ENV
3260 fullname = "MACgraphics";
3261 if (match_optname(opts, fullname, 3, TRUE)) {
3262 boolean badflag = FALSE;
3265 complain_about_duplicate(opts, 1);
3267 if (symset[PRIMARY].name) {
3270 symset[PRIMARY].name = dupstr(fullname);
3271 if (!read_sym_file(PRIMARY)) {
3273 clear_symsetentry(PRIMARY, TRUE);
3277 pline("Failure to load symbol set %s.", fullname);
3280 switch_symbols(TRUE);
3281 if (!initial && Is_rogue_level(&u.uz))
3282 assign_graphics(ROGUESET);
3289 /* OK, if we still haven't recognized the option, check the boolean
3292 for (i = 0; boolopt[i].name; i++) {
3293 if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
3294 /* options that don't exist */
3295 if (!boolopt[i].addr) {
3296 if (!initial && !negated)
3297 pline_The("\"%s\" option is not available.",
3301 /* options that must come from config file */
3302 if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
3303 rejectoption(boolopt[i].name);
3307 *(boolopt[i].addr) = !negated;
3309 /* 0 means boolean opts */
3310 if (duplicate_opt_detection(boolopt[i].name, 0))
3311 complain_about_duplicate(boolopt[i].name, 0);
3314 if ((boolopt[i].addr) == &iflags.rlecomp) {
3315 if (*boolopt[i].addr)
3316 set_savepref("rlecomp");
3318 set_savepref("!rlecomp");
3322 if ((boolopt[i].addr) == &iflags.zerocomp) {
3323 if (*boolopt[i].addr)
3324 set_savepref("zerocomp");
3326 set_savepref("externalcomp");
3329 /* only do processing below if setting with doset() */
3333 if ((boolopt[i].addr) == &flags.time
3334 || (boolopt[i].addr) == &flags.showexp
3335 #ifdef SCORE_ON_BOTL
3336 || (boolopt[i].addr) == &flags.showscore
3339 #ifdef STATUS_VIA_WINDOWPORT
3340 status_initialize(REASSESS_ONLY);
3342 context.botl = TRUE;
3343 } else if ((boolopt[i].addr) == &flags.invlet_constant) {
3344 if (flags.invlet_constant)
3346 } else if (((boolopt[i].addr) == &flags.lit_corridor)
3347 || ((boolopt[i].addr) == &flags.dark_room)) {
3349 * All corridor squares seen via night vision or
3350 * candles & lamps change. Update them by calling
3351 * newsym() on them. Don't do this if we are
3352 * initializing the options --- the vision system
3355 vision_recalc(2); /* shut down vision */
3356 vision_full_recalc = 1; /* delayed recalc */
3357 if (iflags.use_color)
3358 need_redraw = TRUE; /* darkroom refresh */
3359 } else if ((boolopt[i].addr) == &iflags.use_inverse
3360 || (boolopt[i].addr) == &flags.showrace
3361 || (boolopt[i].addr) == &iflags.hilite_pet) {
3364 } else if ((boolopt[i].addr) == &iflags.use_color) {
3367 if ((boolopt[i].addr) == &iflags.use_color && iflags.BIOS) {
3374 #endif /* TEXTCOLOR */
3380 /* out of valid options */
3384 static NEARDATA const char *menutype[] = { "traditional", "combination",
3385 "full", "partial" };
3387 static NEARDATA const char *burdentype[] = { "unencumbered", "burdened",
3388 "stressed", "strained",
3389 "overtaxed", "overloaded" };
3391 static NEARDATA const char *runmodes[] = { "teleport", "run", "walk",
3394 static NEARDATA const char *sortltype[] = { "none", "loot", "full" };
3397 * Convert the given string of object classes to a string of default object
3401 oc_to_str(src, dest)
3406 while ((i = (int) *src++) != 0) {
3407 if (i < 0 || i >= MAXOCLASSES)
3408 impossible("oc_to_str: illegal object class %d", i);
3410 *dest++ = def_oc_syms[i].sym;
3416 * Add the given mapping to the menu command map list. Always keep the
3417 * maps valid C strings.
3420 add_menu_cmd_alias(from_ch, to_ch)
3421 char from_ch, to_ch;
3423 if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) {
3424 pline("out of menu map space.");
3426 mapped_menu_cmds[n_menu_mapped] = from_ch;
3427 mapped_menu_op[n_menu_mapped] = to_ch;
3429 mapped_menu_cmds[n_menu_mapped] = 0;
3430 mapped_menu_op[n_menu_mapped] = 0;
3435 * Map the given character to its corresponding menu command. If it
3436 * doesn't match anything, just return the original.
3442 char *found = index(mapped_menu_cmds, ch);
3444 int idx = (int) (found - mapped_menu_cmds);
3445 ch = mapped_menu_op[idx];
3450 #if defined(MICRO) || defined(MAC) || defined(WIN32)
3451 #define OPTIONS_HEADING "OPTIONS"
3453 #define OPTIONS_HEADING "NETHACKOPTIONS"
3456 static char fmtstr_doset_add_menu[] = "%s%-15s [%s] ";
3457 static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
3460 doset_add_menu(win, option, indexoffset)
3461 winid win; /* window to add to */
3462 const char *option; /* option name */
3463 int indexoffset; /* value to add to index in compopt[], or zero
3464 if option cannot be changed */
3466 const char *value = "unknown"; /* current value */
3467 char buf[BUFSZ], buf2[BUFSZ];
3472 if (indexoffset == 0) {
3474 value = get_compopt_value(option, buf2);
3476 for (i = 0; compopt[i].name; i++)
3477 if (strcmp(option, compopt[i].name) == 0)
3480 if (compopt[i].name) {
3481 any.a_int = i + 1 + indexoffset;
3482 value = get_compopt_value(option, buf2);
3484 /* We are trying to add an option not found in compopt[].
3485 This is almost certainly bad, but we'll let it through anyway
3486 (with a zero value, so it can't be selected). */
3490 /* " " replaces "a - " -- assumes menus follow that style */
3491 if (!iflags.menu_tab_sep)
3492 Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", option,
3495 Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
3496 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3499 /* Changing options via menu by Per Liboriussen */
3503 char buf[BUFSZ], buf2[BUFSZ];
3504 int i = 0, pass, boolcount, pick_cnt, pick_idx, opt_indx;
3508 menu_item *pick_list;
3509 int indexoffset, startpass, endpass;
3510 boolean setinitial = FALSE, fromfile = FALSE;
3511 int biggest_name = 0;
3512 const char *n_currently_set = "(%d currently set)";
3514 tmpwin = create_nhwindow(NHW_MENU);
3518 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3519 "Booleans (selecting will toggle value):", MENU_UNSELECTED);
3521 /* first list any other non-modifiable booleans, then modifiable ones */
3522 for (pass = 0; pass <= 1; pass++)
3523 for (i = 0; boolopt[i].name; i++)
3524 if ((bool_p = boolopt[i].addr) != 0
3525 && ((boolopt[i].optflags == DISP_IN_GAME && pass == 0)
3526 || (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
3527 if (bool_p == &flags.female)
3528 continue; /* obsolete */
3529 if (bool_p == &iflags.sanity_check && !wizard)
3531 if (bool_p == &iflags.menu_tab_sep && !wizard)
3533 if (is_wc_option(boolopt[i].name)
3534 && !wc_supported(boolopt[i].name))
3536 if (is_wc2_option(boolopt[i].name)
3537 && !wc2_supported(boolopt[i].name))
3539 any.a_int = (pass == 0) ? 0 : i + 1;
3540 if (!iflags.menu_tab_sep)
3541 Sprintf(buf, "%s%-17s [%s]", pass == 0 ? " " : "",
3542 boolopt[i].name, *bool_p ? "true" : "false");
3544 Sprintf(buf, "%s\t[%s]", boolopt[i].name,
3545 *bool_p ? "true" : "false");
3546 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
3551 indexoffset = boolcount;
3553 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3554 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3555 "Compounds (selecting will prompt for new value):",
3558 #ifdef notyet /* SYSCF */
3559 /* XXX I think this is still fragile. Fixing initial/from_file and/or
3561 the SET_* etc to bitmaps will let me make this better. */
3563 startpass = SET_IN_SYS;
3566 startpass = DISP_IN_GAME;
3567 endpass = SET_IN_GAME;
3569 /* spin through the options to find the biggest name
3570 and adjust the format string accordingly if needed */
3572 for (i = 0; compopt[i].name; i++)
3573 if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass
3574 && strlen(compopt[i].name) > (unsigned) biggest_name)
3575 biggest_name = (int) strlen(compopt[i].name);
3576 if (biggest_name > 30)
3578 if (!iflags.menu_tab_sep)
3579 Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
3581 /* deliberately put `playmode', `name', `role', `race', `gender' first
3582 (also alignment if anything ever comes before it in compopt[]) */
3583 doset_add_menu(tmpwin, "playmode", 0);
3584 doset_add_menu(tmpwin, "name", 0);
3585 doset_add_menu(tmpwin, "role", 0);
3586 doset_add_menu(tmpwin, "race", 0);
3587 doset_add_menu(tmpwin, "gender", 0);
3589 for (pass = startpass; pass <= endpass; pass++)
3590 for (i = 0; compopt[i].name; i++)
3591 if (compopt[i].optflags == pass) {
3592 if (!strcmp(compopt[i].name, "playmode")
3593 || !strcmp(compopt[i].name, "name")
3594 || !strcmp(compopt[i].name, "role")
3595 || !strcmp(compopt[i].name, "race")
3596 || !strcmp(compopt[i].name, "gender"))
3598 else if (is_wc_option(compopt[i].name)
3599 && !wc_supported(compopt[i].name))
3601 else if (is_wc2_option(compopt[i].name)
3602 && !wc2_supported(compopt[i].name))
3605 doset_add_menu(tmpwin, compopt[i].name,
3606 (pass == DISP_IN_GAME) ? 0 : indexoffset);
3609 Sprintf(buf2, n_currently_set, msgtype_count());
3610 Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ",
3611 "message types", buf2);
3612 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3614 Sprintf(buf2, n_currently_set, count_menucolors());
3615 Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ",
3616 "menucolors", buf2);
3617 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3618 #ifdef STATUS_VIA_WINDOWPORT
3619 #ifdef STATUS_HILITES
3621 get_status_hilites(buf2, 60);
3623 Sprintf(buf2, "%s", "(none)");
3624 if (!iflags.menu_tab_sep)
3625 Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ",
3626 "status_hilites", buf2);
3628 Sprintf(buf, fmtstr_doset_add_menu_tab, "status_hilites", buf2);
3629 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3633 Sprintf(buf2, n_currently_set, count_ape_maps((int *) 0, (int *) 0));
3634 Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ",
3635 "autopickup exceptions", buf2);
3636 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
3637 #ifdef PREFIXES_IN_USE
3639 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3640 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
3641 "Variable playground locations:", MENU_UNSELECTED);
3642 for (i = 0; i < PREFIX_COUNT; i++)
3643 doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
3645 end_menu(tmpwin, "Set what options?");
3646 need_redraw = FALSE;
3647 if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
3649 * Walk down the selection list and either invert the booleans
3650 * or prompt for new values. In most cases, call parseoptions()
3651 * to take care of options that require special attention, like
3654 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
3655 opt_indx = pick_list[pick_idx].item.a_int - 1;
3656 if (opt_indx == -2) {
3657 /* -2 due to -1 offset for select_menu() */
3658 (void) special_handling("autopickup_exception", setinitial,
3660 #ifdef STATUS_VIA_WINDOWPORT
3661 #ifdef STATUS_HILITES
3662 } else if (opt_indx == -3) {
3663 /* -3 due to -1 offset for select_menu() */
3664 if (!status_hilite_menu()) {
3665 pline("Bad status hilite(s) specified.");
3667 if (wc2_supported("status_hilites"))
3668 preference_update("status_hilites");
3672 } else if (opt_indx == -4) {
3673 (void) special_handling("menucolors", setinitial,
3675 } else if (opt_indx == -5) {
3676 (void) special_handling("msgtype", setinitial, fromfile);
3677 } else if (opt_indx < boolcount) {
3678 /* boolean option */
3679 Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
3680 boolopt[opt_indx].name);
3681 parseoptions(buf, setinitial, fromfile);
3682 if (wc_supported(boolopt[opt_indx].name)
3683 || wc2_supported(boolopt[opt_indx].name))
3684 preference_update(boolopt[opt_indx].name);
3686 /* compound option */
3687 opt_indx -= boolcount;
3689 if (!special_handling(compopt[opt_indx].name, setinitial,
3691 Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
3693 if (buf2[0] == '\033')
3695 Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
3697 parseoptions(buf, setinitial, fromfile);
3699 if (wc_supported(compopt[opt_indx].name)
3700 || wc2_supported(compopt[opt_indx].name))
3701 preference_update(compopt[opt_indx].name);
3704 free((genericptr_t) pick_list);
3705 pick_list = (menu_item *) 0;
3708 destroy_nhwindow(tmpwin);
3717 handle_add_list_remove(optname, numtotal)
3718 const char *optname;
3723 int i, pick_cnt, pick_idx, opt_idx;
3724 menu_item *pick_list = (menu_item *) 0;
3725 static const struct action {
3728 } action_titles[] = {
3729 { 'a', "add new %s" }, /* [0] */
3730 { 'l', "list %s" }, /* [1] */
3731 { 'r', "remove existing %s" }, /* [2] */
3732 { 'x', "exit this menu" }, /* [3] */
3736 tmpwin = create_nhwindow(NHW_MENU);
3739 for (i = 0; i < SIZE(action_titles); i++) {
3742 /* omit list and remove if there aren't any yet */
3743 if (!numtotal && (i == 1 || i == 2))
3745 Sprintf(tmpbuf, action_titles[i].desc,
3746 (i == 1) ? makeplural(optname) : optname);
3747 add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, 0, ATR_NONE,
3749 #if 0 /* this ought to work but doesn't... */
3750 (action_titles[i].letr == 'x') ? MENU_SELECTED :
3754 end_menu(tmpwin, "Do what?");
3755 if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
3756 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
3757 opt_idx = pick_list[pick_idx].item.a_int - 1;
3759 free((genericptr_t) pick_list);
3760 pick_list = (menu_item *) 0;
3762 destroy_nhwindow(tmpwin);
3765 opt_idx = 3; /* none selected, exit menu */
3769 struct symsetentry *symset_list = 0; /* files.c will populate this with
3770 list of available sets */
3773 special_handling(optname, setinitial, setfromfile)
3774 const char *optname;
3775 boolean setinitial, setfromfile;
3782 /* Special handling of menustyle, pickup_burden, pickup_types,
3783 * disclose, runmode, msg_window, menu_headings, sortloot,
3784 * and number_pad options.
3785 * Also takes care of interactive autopickup_exception_handling changes.
3787 if (!strcmp("menustyle", optname)) {
3788 const char *style_name;
3789 menu_item *style_pick = (menu_item *) 0;
3790 tmpwin = create_nhwindow(NHW_MENU);
3793 for (i = 0; i < SIZE(menutype); i++) {
3794 style_name = menutype[i];
3795 /* note: separate `style_name' variable used
3796 to avoid an optimizer bug in VAX C V2.3 */
3798 add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, ATR_NONE,
3799 style_name, MENU_UNSELECTED);
3801 end_menu(tmpwin, "Select menustyle:");
3802 if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
3803 flags.menu_style = style_pick->item.a_int - 1;
3804 free((genericptr_t) style_pick);
3806 destroy_nhwindow(tmpwin);
3807 } else if (!strcmp("paranoid_confirmation", optname)) {
3808 menu_item *paranoia_picks = (menu_item *) 0;
3810 tmpwin = create_nhwindow(NHW_MENU);
3813 for (i = 0; paranoia[i].flagmask != 0; ++i) {
3814 if (paranoia[i].flagmask == PARANOID_BONES && !wizard)
3816 any.a_int = paranoia[i].flagmask;
3817 add_menu(tmpwin, NO_GLYPH, &any, *paranoia[i].argname, 0,
3818 ATR_NONE, paranoia[i].explain,
3819 (flags.paranoia_bits & paranoia[i].flagmask)
3823 end_menu(tmpwin, "Actions requiring extra confirmation:");
3824 i = select_menu(tmpwin, PICK_ANY, ¶noia_picks);
3826 /* player didn't cancel; we reset all the paranoia options
3827 here even if there were no items picked, since user
3828 could have toggled off preselected ones to end up with 0 */
3829 flags.paranoia_bits = 0;
3831 /* at least 1 item set, either preselected or newly picked */
3833 flags.paranoia_bits |= paranoia_picks[i].item.a_int;
3834 free((genericptr_t) paranoia_picks);
3837 destroy_nhwindow(tmpwin);
3838 } else if (!strcmp("pickup_burden", optname)) {
3839 const char *burden_name, *burden_letters = "ubsntl";
3840 menu_item *burden_pick = (menu_item *) 0;
3842 tmpwin = create_nhwindow(NHW_MENU);
3845 for (i = 0; i < SIZE(burdentype); i++) {
3846 burden_name = burdentype[i];
3848 add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, ATR_NONE,
3849 burden_name, MENU_UNSELECTED);
3851 end_menu(tmpwin, "Select encumbrance level:");
3852 if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
3853 flags.pickup_burden = burden_pick->item.a_int - 1;
3854 free((genericptr_t) burden_pick);
3856 destroy_nhwindow(tmpwin);
3857 } else if (!strcmp("pickup_types", optname)) {
3858 /* parseoptions will prompt for the list of types */
3859 parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
3860 } else if (!strcmp("disclose", optname)) {
3861 /* order of disclose_names[] must correspond to
3862 disclosure_options in decl.c */
3863 static const char *disclosure_names[] = {
3864 "inventory", "attributes", "vanquished",
3865 "genocides", "conduct", "overview",
3867 int disc_cat[NUM_DISCLOSURE_OPTIONS];
3868 int pick_cnt, pick_idx, opt_idx;
3869 menu_item *disclosure_pick = (menu_item *) 0;
3871 tmpwin = create_nhwindow(NHW_MENU);
3874 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
3875 Sprintf(buf, "%-12s[%c%c]", disclosure_names[i],
3876 flags.end_disclose[i], disclosure_options[i]);
3878 add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
3879 ATR_NONE, buf, MENU_UNSELECTED);
3882 end_menu(tmpwin, "Change which disclosure options categories:");
3883 pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_pick);
3885 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
3886 opt_idx = disclosure_pick[pick_idx].item.a_int - 1;
3887 disc_cat[opt_idx] = 1;
3889 free((genericptr_t) disclosure_pick);
3890 disclosure_pick = (menu_item *) 0;
3892 destroy_nhwindow(tmpwin);
3894 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
3896 Sprintf(buf, "Disclosure options for %s:",
3897 disclosure_names[i]);
3898 tmpwin = create_nhwindow(NHW_MENU);
3901 /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
3902 any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
3903 add_menu(tmpwin, NO_GLYPH, &any, 'a', any.a_char, ATR_NONE,
3904 "Never disclose, without prompting",
3906 any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
3907 add_menu(tmpwin, NO_GLYPH, &any, 'b', any.a_char, ATR_NONE,
3908 "Always disclose, without prompting",
3910 any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
3911 add_menu(tmpwin, NO_GLYPH, &any, 'c', any.a_char, ATR_NONE,
3912 "Prompt, with default answer of \"No\"",
3914 any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
3915 add_menu(tmpwin, NO_GLYPH, &any, 'd', any.a_char, ATR_NONE,
3916 "Prompt, with default answer of \"Yes\"",
3918 end_menu(tmpwin, buf);
3919 if (select_menu(tmpwin, PICK_ONE, &disclosure_pick) > 0) {
3920 flags.end_disclose[i] = disclosure_pick->item.a_char;
3921 free((genericptr_t) disclosure_pick);
3923 destroy_nhwindow(tmpwin);
3926 } else if (!strcmp("runmode", optname)) {
3927 const char *mode_name;
3928 menu_item *mode_pick = (menu_item *) 0;
3930 tmpwin = create_nhwindow(NHW_MENU);
3933 for (i = 0; i < SIZE(runmodes); i++) {
3934 mode_name = runmodes[i];
3936 add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, ATR_NONE,
3937 mode_name, MENU_UNSELECTED);
3939 end_menu(tmpwin, "Select run/travel display mode:");
3940 if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
3941 flags.runmode = mode_pick->item.a_int - 1;
3942 free((genericptr_t) mode_pick);
3944 destroy_nhwindow(tmpwin);
3945 } else if (!strcmp("msg_window", optname)) {
3947 /* by Christian W. Cooper */
3948 menu_item *window_pick = (menu_item *) 0;
3950 tmpwin = create_nhwindow(NHW_MENU);
3954 add_menu(tmpwin, NO_GLYPH, &any, 's', 0, ATR_NONE, "single",
3957 add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE, "combination",
3960 add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, ATR_NONE, "full",
3963 add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "reversed",
3965 end_menu(tmpwin, "Select message history display type:");
3966 if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
3967 iflags.prevmsg_window = window_pick->item.a_char;
3968 free((genericptr_t) window_pick);
3970 destroy_nhwindow(tmpwin);
3972 } else if (!strcmp("sortloot", optname)) {
3973 const char *sortl_name;
3974 menu_item *sortl_pick = (menu_item *) 0;
3976 tmpwin = create_nhwindow(NHW_MENU);
3979 for (i = 0; i < SIZE(sortltype); i++) {
3980 sortl_name = sortltype[i];
3981 any.a_char = *sortl_name;
3982 add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE,
3983 sortl_name, MENU_UNSELECTED);
3985 end_menu(tmpwin, "Select loot sorting type:");
3986 if (select_menu(tmpwin, PICK_ONE, &sortl_pick) > 0) {
3987 flags.sortloot = sortl_pick->item.a_char;
3988 free((genericptr_t) sortl_pick);
3990 destroy_nhwindow(tmpwin);
3991 } else if (!strcmp("align_message", optname)
3992 || !strcmp("align_status", optname)) {
3993 menu_item *window_pick = (menu_item *) 0;
3995 boolean msg = (*(optname + 6) == 'm');
3997 tmpwin = create_nhwindow(NHW_MENU);
4000 any.a_int = ALIGN_TOP;
4001 add_menu(tmpwin, NO_GLYPH, &any, 't', 0, ATR_NONE, "top",
4003 any.a_int = ALIGN_BOTTOM;
4004 add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE, "bottom",
4006 any.a_int = ALIGN_LEFT;
4007 add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, ATR_NONE, "left",
4009 any.a_int = ALIGN_RIGHT;
4010 add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "right",
4012 Sprintf(abuf, "Select %s window placement relative to the map:",
4013 msg ? "message" : "status");
4014 end_menu(tmpwin, abuf);
4015 if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
4017 iflags.wc_align_message = window_pick->item.a_int;
4019 iflags.wc_align_status = window_pick->item.a_int;
4020 free((genericptr_t) window_pick);
4022 destroy_nhwindow(tmpwin);
4023 } else if (!strcmp("number_pad", optname)) {
4024 static const char *npchoices[] = {
4025 " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
4026 " 3 (on, phone-style digit layout)",
4027 " 4 (on, phone-style layout, MSDOS compatible)",
4028 "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
4030 menu_item *mode_pick = (menu_item *) 0;
4032 tmpwin = create_nhwindow(NHW_MENU);
4035 for (i = 0; i < SIZE(npchoices); i++) {
4037 add_menu(tmpwin, NO_GLYPH, &any, 'a' + i, 0, ATR_NONE,
4038 npchoices[i], MENU_UNSELECTED);
4040 end_menu(tmpwin, "Select number_pad mode:");
4041 if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
4042 switch (mode_pick->item.a_int - 1) {
4044 iflags.num_pad = FALSE;
4045 iflags.num_pad_mode = 0;
4048 iflags.num_pad = TRUE;
4049 iflags.num_pad_mode = 0;
4052 iflags.num_pad = TRUE;
4053 iflags.num_pad_mode = 1;
4056 iflags.num_pad = TRUE;
4057 iflags.num_pad_mode = 2;
4060 iflags.num_pad = TRUE;
4061 iflags.num_pad_mode = 3;
4063 /* last menu choice: number_pad == -1 */
4065 iflags.num_pad = FALSE;
4066 iflags.num_pad_mode = 1;
4069 reset_commands(FALSE);
4070 number_pad(iflags.num_pad ? 1 : 0);
4071 free((genericptr_t) mode_pick);
4073 destroy_nhwindow(tmpwin);
4074 } else if (!strcmp("menu_headings", optname)) {
4075 int mhattr = query_attr("How to highlight menu headings:");
4078 iflags.menu_headings = mhattr;
4079 } else if (!strcmp("msgtype", optname)) {
4080 int opt_idx, nmt, mttyp;
4084 nmt = msgtype_count();
4085 opt_idx = handle_add_list_remove("message type", nmt);
4087 ; /* done--fall through to function exit */
4088 } else if (opt_idx == 0) { /* add new */
4089 getlin("What new message pattern?", mtbuf);
4090 if (*mtbuf == '\033' || !*mtbuf)
4091 goto msgtypes_again;
4092 mttyp = query_msgtype();
4094 goto msgtypes_again;
4095 if (!msgtype_add(mttyp, mtbuf)) {
4096 pline("Error adding the message type.");
4098 goto msgtypes_again;
4100 } else { /* list or remove */
4101 int pick_idx, pick_cnt;
4103 menu_item *pick_list = (menu_item *) 0;
4104 struct plinemsg_type *tmp = plinemsg_types;
4106 tmpwin = create_nhwindow(NHW_MENU);
4111 const char *mtype = msgtype2name(tmp->msgtype);
4113 any.a_int = ++mt_idx;
4114 Sprintf(mtbuf, "%-5s \"%s\"", mtype, tmp->pattern);
4115 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mtbuf,
4119 Sprintf(mtbuf, "%s message types",
4120 (opt_idx == 1) ? "List of" : "Remove which");
4121 end_menu(tmpwin, mtbuf);
4122 pick_cnt = select_menu(tmpwin,
4123 (opt_idx == 1) ? PICK_NONE : PICK_ANY,
4126 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
4127 free_one_msgtype(pick_list[pick_idx].item.a_int - 1
4129 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
4131 destroy_nhwindow(tmpwin);
4133 goto msgtypes_again;
4135 } else if (!strcmp("menucolors", optname)) {
4136 int opt_idx, nmc, mcclr, mcattr;
4140 nmc = count_menucolors();
4141 opt_idx = handle_add_list_remove("menucolor", nmc);
4143 ; /* done--fall through to function exit */
4144 } else if (opt_idx == 0) { /* add new */
4145 getlin("What new menucolor pattern?", mcbuf);
4146 if (*mcbuf == '\033' || !*mcbuf)
4147 goto menucolors_again;
4148 mcclr = query_color();
4150 goto menucolors_again;
4151 mcattr = query_attr(NULL);
4153 goto menucolors_again;
4154 if (!add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) {
4155 pline("Error adding the menu color.");
4157 goto menucolors_again;
4159 } else { /* list or remove */
4160 int pick_idx, pick_cnt;
4162 menu_item *pick_list = (menu_item *) 0;
4163 struct menucoloring *tmp = menu_colorings;
4165 tmpwin = create_nhwindow(NHW_MENU);
4170 const char *sattr = attr2attrname(tmp->attr);
4171 const char *sclr = clr2colorname(tmp->color);
4173 any.a_int = (++mc_idx);
4174 Sprintf(mcbuf, "\"%s\"=%s%s%s", tmp->origstr, sclr,
4175 (tmp->attr != ATR_NONE) ? " & " : "",
4176 (tmp->attr != ATR_NONE) ? sattr : "");
4177 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mcbuf,
4181 Sprintf(mcbuf, "%s menu colors",
4182 (opt_idx == 1) ? "List of" : "Remove which");
4183 end_menu(tmpwin, mcbuf);
4184 pick_cnt = select_menu(tmpwin,
4185 (opt_idx == 1) ? PICK_NONE : PICK_ANY,
4188 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
4189 free_one_menu_coloring(pick_list[pick_idx].item.a_int - 1
4191 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
4193 destroy_nhwindow(tmpwin);
4195 goto menucolors_again;
4197 } else if (!strcmp("autopickup_exception", optname)) {
4198 int opt_idx, pass, totalapes = 0, numapes[2] = { 0, 0 };
4199 char apebuf[1 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */
4200 struct autopickup_exception *ape;
4203 totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
4204 opt_idx = handle_add_list_remove("autopickup exception", totalapes);
4206 ; /* done--fall through to function exit */
4207 } else if (opt_idx == 0) { /* add new */
4208 getlin("What new autopickup exception pattern?", &apebuf[1]);
4209 mungspaces(&apebuf[1]); /* regularize whitespace */
4210 if (apebuf[1] == '\033') {
4211 ; /* fall through to function exit */
4215 /* guarantee room for \" prefix and \"\0 suffix;
4216 -2 is good enough for apebuf[] but -3 makes
4217 sure the whole thing fits within normal BUFSZ */
4218 apebuf[sizeof apebuf - 3] = '\0';
4219 Strcat(apebuf, "\"");
4220 add_autopickup_exception(apebuf);
4224 } else { /* list or remove */
4225 int pick_idx, pick_cnt;
4226 menu_item *pick_list = (menu_item *) 0;
4228 tmpwin = create_nhwindow(NHW_MENU);
4230 for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
4231 if (numapes[pass] == 0)
4233 ape = iflags.autopickup_exceptions[pass];
4235 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
4236 (pass == 0) ? "Never pickup" : "Always pickup",
4238 for (i = 0; i < numapes[pass] && ape; i++) {
4239 any.a_void = (opt_idx == 1) ? 0 : ape;
4240 Sprintf(apebuf, "\"%s\"", ape->pattern);
4241 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf,
4246 Sprintf(apebuf, "%s autopickup exceptions",
4247 (opt_idx == 1) ? "List of" : "Remove which");
4248 end_menu(tmpwin, apebuf);
4249 pick_cnt = select_menu(tmpwin,
4250 (opt_idx == 1) ? PICK_NONE : PICK_ANY,
4253 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
4254 remove_autopickup_exception(
4255 (struct autopickup_exception *)
4256 pick_list[pick_idx].item.a_void);
4257 free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
4259 destroy_nhwindow(tmpwin);
4263 } else if (!strcmp("symset", optname)
4264 || !strcmp("roguesymset", optname)) {
4265 menu_item *symset_pick = (menu_item *) 0;
4266 boolean primaryflag = (*optname == 's'),
4267 rogueflag = (*optname == 'r'),
4268 ready_to_switch = FALSE,
4269 nothing_to_do = FALSE;
4270 char *symset_name, fmtstr[20];
4271 struct symsetentry *sl;
4272 int res, which_set, setcount = 0, chosen = -2;
4275 which_set = ROGUESET;
4277 which_set = PRIMARY;
4279 /* clear symset[].name as a flag to read_sym_file() to build list */
4280 symset_name = symset[which_set].name;
4281 symset[which_set].name = (char *) 0;
4282 symset_list = (struct symsetentry *) 0;
4284 res = read_sym_file(which_set);
4285 if (res && symset_list) {
4286 char symsetchoice[BUFSZ];
4287 int let = 'a', biggest = 0, thissize = 0;
4291 /* check restrictions */
4292 if ((!rogueflag && sl->rogue)
4293 || (!primaryflag && sl->primary)) {
4298 /* find biggest name */
4300 thissize = strlen(sl->name);
4301 if (thissize > biggest)
4306 pline("There are no appropriate %ssymbol sets available.",
4307 (rogueflag) ? "rogue level "
4308 : (primaryflag) ? "primary " : "");
4312 Sprintf(fmtstr, "%%-%ds %%s", biggest + 5);
4313 tmpwin = create_nhwindow(NHW_MENU);
4317 add_menu(tmpwin, NO_GLYPH, &any, let++, 0, ATR_NONE,
4318 "Default Symbols", MENU_UNSELECTED);
4322 /* check restrictions */
4323 if ((!rogueflag && sl->rogue)
4324 || (!primaryflag && sl->primary)) {
4329 any.a_int = sl->idx + 2;
4330 Sprintf(symsetchoice, fmtstr, sl->name,
4331 sl->desc ? sl->desc : "");
4332 add_menu(tmpwin, NO_GLYPH, &any, let, 0, ATR_NONE,
4333 symsetchoice, MENU_UNSELECTED);
4341 end_menu(tmpwin, "Select symbol set:");
4342 if (select_menu(tmpwin, PICK_ONE, &symset_pick) > 0) {
4343 chosen = symset_pick->item.a_int - 2;
4344 free((genericptr_t) symset_pick);
4346 destroy_nhwindow(tmpwin);
4349 /* chose an actual symset name from file */
4352 if (sl->idx == chosen) {
4354 free((genericptr_t) symset_name);
4355 symset_name = (char *) 0;
4357 /* free the now stale attributes */
4358 clear_symsetentry(which_set, TRUE);
4360 /* transfer only the name of the symbol set */
4361 symset[which_set].name = dupstr(sl->name);
4362 ready_to_switch = TRUE;
4367 } else if (chosen == -1) {
4368 /* explicit selection of defaults */
4369 /* free the now stale symset attributes */
4371 free((genericptr_t) symset_name);
4372 symset_name = (char *) 0;
4374 clear_symsetentry(which_set, TRUE);
4376 nothing_to_do = TRUE;
4378 /* The symbols file could not be accessed */
4379 pline("Unable to access \"%s\" file.", SYMBOLS);
4381 } else if (!symset_list) {
4382 /* The symbols file was empty */
4383 pline("There were no symbol sets found in \"%s\".", SYMBOLS);
4388 while (symset_list) {
4391 free((genericptr_t) sl->name);
4392 sl->name = (char *) 0;
4395 free((genericptr_t) sl->desc);
4396 sl->desc = (char *) 0;
4398 symset_list = sl->next;
4399 free((genericptr_t) sl);
4405 if (!symset[which_set].name && symset_name)
4406 symset[which_set].name = symset_name; /* not dupstr() here */
4408 /* Set default symbols and clear the handling value */
4414 if (symset[which_set].name) {
4415 if (read_sym_file(which_set)) {
4416 ready_to_switch = TRUE;
4418 clear_symsetentry(which_set, TRUE);
4423 if (ready_to_switch)
4424 switch_symbols(TRUE);
4426 if (Is_rogue_level(&u.uz)) {
4428 assign_graphics(ROGUESET);
4429 } else if (!rogueflag)
4430 assign_graphics(PRIMARY);
4435 /* didn't match any of the special options */
4441 #define rolestring(val, array, field) \
4442 ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none)
4444 /* This is ugly. We have all the option names in the compopt[] array,
4445 but we need to look at each option individually to get the value. */
4446 STATIC_OVL const char *
4447 get_compopt_value(optname, buf)
4448 const char *optname;
4451 char ocl[MAXOCLASSES + 1];
4452 static const char none[] = "(none)", randomrole[] = "random",
4453 to_be_done[] = "(to be done)", defopt[] = "default",
4458 if (!strcmp(optname, "align_message"))
4460 iflags.wc_align_message == ALIGN_TOP
4462 : iflags.wc_align_message == ALIGN_LEFT
4464 : iflags.wc_align_message == ALIGN_BOTTOM
4466 : iflags.wc_align_message == ALIGN_RIGHT
4469 else if (!strcmp(optname, "align_status"))
4471 iflags.wc_align_status == ALIGN_TOP
4473 : iflags.wc_align_status == ALIGN_LEFT
4475 : iflags.wc_align_status == ALIGN_BOTTOM
4477 : iflags.wc_align_status == ALIGN_RIGHT
4480 else if (!strcmp(optname, "align"))
4481 Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
4483 else if (!strcmp(optname, "altkeyhandler"))
4485 iflags.altkeyhandler[0] ? iflags.altkeyhandler : "default");
4487 #ifdef BACKWARD_COMPAT
4488 else if (!strcmp(optname, "boulder"))
4492 : showsyms[(int) objects[BOULDER].oc_class + SYM_OFF_O]);
4494 else if (!strcmp(optname, "catname"))
4495 Sprintf(buf, "%s", catname[0] ? catname : none);
4496 else if (!strcmp(optname, "disclose"))
4497 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
4499 (void) strkitten(buf, ' ');
4500 (void) strkitten(buf, flags.end_disclose[i]);
4501 (void) strkitten(buf, disclosure_options[i]);
4503 else if (!strcmp(optname, "dogname"))
4504 Sprintf(buf, "%s", dogname[0] ? dogname : none);
4505 else if (!strcmp(optname, "dungeon"))
4506 Sprintf(buf, "%s", to_be_done);
4507 else if (!strcmp(optname, "effects"))
4508 Sprintf(buf, "%s", to_be_done);
4509 else if (!strcmp(optname, "font_map"))
4510 Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
4511 else if (!strcmp(optname, "font_message"))
4513 iflags.wc_font_message ? iflags.wc_font_message : defopt);
4514 else if (!strcmp(optname, "font_status"))
4516 iflags.wc_font_status ? iflags.wc_font_status : defopt);
4517 else if (!strcmp(optname, "font_menu"))
4519 iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
4520 else if (!strcmp(optname, "font_text"))
4522 iflags.wc_font_text ? iflags.wc_font_text : defopt);
4523 else if (!strcmp(optname, "font_size_map")) {
4524 if (iflags.wc_fontsiz_map)
4525 Sprintf(buf, "%d", iflags.wc_fontsiz_map);
4527 Strcpy(buf, defopt);
4528 } else if (!strcmp(optname, "font_size_message")) {
4529 if (iflags.wc_fontsiz_message)
4530 Sprintf(buf, "%d", iflags.wc_fontsiz_message);
4532 Strcpy(buf, defopt);
4533 } else if (!strcmp(optname, "font_size_status")) {
4534 if (iflags.wc_fontsiz_status)
4535 Sprintf(buf, "%d", iflags.wc_fontsiz_status);
4537 Strcpy(buf, defopt);
4538 } else if (!strcmp(optname, "font_size_menu")) {
4539 if (iflags.wc_fontsiz_menu)
4540 Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
4542 Strcpy(buf, defopt);
4543 } else if (!strcmp(optname, "font_size_text")) {
4544 if (iflags.wc_fontsiz_text)
4545 Sprintf(buf, "%d", iflags.wc_fontsiz_text);
4547 Strcpy(buf, defopt);
4548 } else if (!strcmp(optname, "fruit"))
4549 Sprintf(buf, "%s", pl_fruit);
4550 else if (!strcmp(optname, "gender"))
4551 Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
4552 else if (!strcmp(optname, "horsename"))
4553 Sprintf(buf, "%s", horsename[0] ? horsename : none);
4554 else if (!strcmp(optname, "map_mode"))
4556 iflags.wc_map_mode == MAP_MODE_TILES
4558 : iflags.wc_map_mode == MAP_MODE_ASCII4x6
4560 : iflags.wc_map_mode == MAP_MODE_ASCII6x8
4562 : iflags.wc_map_mode == MAP_MODE_ASCII8x8
4564 : iflags.wc_map_mode == MAP_MODE_ASCII16x8
4566 : iflags.wc_map_mode == MAP_MODE_ASCII7x12
4568 : iflags.wc_map_mode == MAP_MODE_ASCII8x12
4570 : iflags.wc_map_mode
4571 == MAP_MODE_ASCII16x12
4573 : iflags.wc_map_mode
4574 == MAP_MODE_ASCII12x16
4576 : iflags.wc_map_mode
4577 == MAP_MODE_ASCII10x18
4579 : iflags.wc_map_mode
4580 == MAP_MODE_ASCII_FIT_TO_SCREEN
4583 else if (!strcmp(optname, "menustyle"))
4584 Sprintf(buf, "%s", menutype[(int) flags.menu_style]);
4585 else if (!strcmp(optname, "menu_deselect_all"))
4586 Sprintf(buf, "%s", to_be_done);
4587 else if (!strcmp(optname, "menu_deselect_page"))
4588 Sprintf(buf, "%s", to_be_done);
4589 else if (!strcmp(optname, "menu_first_page"))
4590 Sprintf(buf, "%s", to_be_done);
4591 else if (!strcmp(optname, "menu_invert_all"))
4592 Sprintf(buf, "%s", to_be_done);
4593 else if (!strcmp(optname, "menu_headings"))
4594 Sprintf(buf, "%s", attr2attrname(iflags.menu_headings));
4595 else if (!strcmp(optname, "menu_invert_page"))
4596 Sprintf(buf, "%s", to_be_done);
4597 else if (!strcmp(optname, "menu_last_page"))
4598 Sprintf(buf, "%s", to_be_done);
4599 else if (!strcmp(optname, "menu_next_page"))
4600 Sprintf(buf, "%s", to_be_done);
4601 else if (!strcmp(optname, "menu_previous_page"))
4602 Sprintf(buf, "%s", to_be_done);
4603 else if (!strcmp(optname, "menu_search"))
4604 Sprintf(buf, "%s", to_be_done);
4605 else if (!strcmp(optname, "menu_select_all"))
4606 Sprintf(buf, "%s", to_be_done);
4607 else if (!strcmp(optname, "menu_select_page"))
4608 Sprintf(buf, "%s", to_be_done);
4609 else if (!strcmp(optname, "monsters")) {
4610 Sprintf(buf, "%s", to_be_done);
4611 } else if (!strcmp(optname, "msghistory")) {
4612 Sprintf(buf, "%u", iflags.msg_history);
4614 } else if (!strcmp(optname, "msg_window")) {
4615 Sprintf(buf, "%s", (iflags.prevmsg_window == 's')
4617 : (iflags.prevmsg_window == 'c')
4619 : (iflags.prevmsg_window == 'f')
4623 } else if (!strcmp(optname, "name")) {
4624 Sprintf(buf, "%s", plname);
4625 } else if (!strcmp(optname, "number_pad")) {
4626 static const char *numpadmodes[] = {
4627 "0=off", "1=on", "2=on, MSDOS compatible",
4628 "3=on, phone-style layout",
4629 "4=on, phone layout, MSDOS compatible",
4630 "-1=off, y & z swapped", /*[5]*/
4632 int indx = Cmd.num_pad
4633 ? (Cmd.phone_layout ? (Cmd.pcHack_compat ? 4 : 3)
4634 : (Cmd.pcHack_compat ? 2 : 1))
4635 : Cmd.swap_yz ? 5 : 0;
4637 Strcpy(buf, numpadmodes[indx]);
4638 } else if (!strcmp(optname, "objects")) {
4639 Sprintf(buf, "%s", to_be_done);
4640 } else if (!strcmp(optname, "packorder")) {
4641 oc_to_str(flags.inv_order, ocl);
4642 Sprintf(buf, "%s", ocl);
4644 } else if (!strcmp(optname, "palette")) {
4645 Sprintf(buf, "%s", get_color_string());
4647 } else if (!strcmp(optname, "paranoid_confirmation")) {
4648 char tmpbuf[QBUFSZ];
4651 if (ParanoidConfirm)
4652 Strcat(tmpbuf, " Confirm");
4654 Strcat(tmpbuf, " quit");
4656 Strcat(tmpbuf, " die");
4658 Strcat(tmpbuf, " bones");
4660 Strcat(tmpbuf, " attack");
4662 Strcat(tmpbuf, " pray");
4664 Strcat(tmpbuf, " Remove");
4665 Strcpy(buf, tmpbuf[0] ? &tmpbuf[1] : "none");
4666 } else if (!strcmp(optname, "pettype")) {
4667 Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat"
4668 : (preferred_pet == 'd') ? "dog"
4669 : (preferred_pet == 'h') ? "horse"
4670 : (preferred_pet == 'n') ? "none"
4672 } else if (!strcmp(optname, "pickup_burden")) {
4673 Sprintf(buf, "%s", burdentype[flags.pickup_burden]);
4674 } else if (!strcmp(optname, "pickup_types")) {
4675 oc_to_str(flags.pickup_types, ocl);
4676 Sprintf(buf, "%s", ocl[0] ? ocl : "all");
4677 } else if (!strcmp(optname, "pile_limit")) {
4678 Sprintf(buf, "%d", flags.pile_limit);
4679 } else if (!strcmp(optname, "playmode")) {
4680 Strcpy(buf, wizard ? "debug" : discover ? "explore" : "normal");
4681 } else if (!strcmp(optname, "race")) {
4682 Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
4683 } else if (!strcmp(optname, "roguesymset")) {
4685 symset[ROGUESET].name ? symset[ROGUESET].name : "default");
4686 if (currentgraphics == ROGUESET && symset[ROGUESET].name)
4687 Strcat(buf, ", active");
4688 } else if (!strcmp(optname, "role")) {
4689 Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
4690 } else if (!strcmp(optname, "runmode")) {
4691 Sprintf(buf, "%s", runmodes[flags.runmode]);
4692 } else if (!strcmp(optname, "scores")) {
4693 Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around,
4694 flags.end_own ? "/own" : "");
4695 } else if (!strcmp(optname, "scroll_amount")) {
4696 if (iflags.wc_scroll_amount)
4697 Sprintf(buf, "%d", iflags.wc_scroll_amount);
4699 Strcpy(buf, defopt);
4700 } else if (!strcmp(optname, "scroll_margin")) {
4701 if (iflags.wc_scroll_margin)
4702 Sprintf(buf, "%d", iflags.wc_scroll_margin);
4704 Strcpy(buf, defopt);
4705 } else if (!strcmp(optname, "sortloot")) {
4706 for (i = 0; i < SIZE(sortltype); i++)
4707 if (flags.sortloot == sortltype[i][0]) {
4708 Strcpy(buf, sortltype[i]);
4711 } else if (!strcmp(optname, "player_selection")) {
4712 Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
4714 } else if (!strcmp(optname, "soundcard")) {
4715 Sprintf(buf, "%s", to_be_done);
4717 } else if (!strcmp(optname, "suppress_alert")) {
4718 if (flags.suppress_alert == 0L)
4721 Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
4722 FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
4723 } else if (!strcmp(optname, "symset")) {
4725 symset[PRIMARY].name ? symset[PRIMARY].name : "default");
4726 if (currentgraphics == PRIMARY && symset[PRIMARY].name)
4727 Strcat(buf, ", active");
4728 } else if (!strcmp(optname, "tile_file")) {
4730 iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
4731 } else if (!strcmp(optname, "tile_height")) {
4732 if (iflags.wc_tile_height)
4733 Sprintf(buf, "%d", iflags.wc_tile_height);
4735 Strcpy(buf, defopt);
4736 } else if (!strcmp(optname, "tile_width")) {
4737 if (iflags.wc_tile_width)
4738 Sprintf(buf, "%d", iflags.wc_tile_width);
4740 Strcpy(buf, defopt);
4741 } else if (!strcmp(optname, "traps")) {
4742 Sprintf(buf, "%s", to_be_done);
4743 } else if (!strcmp(optname, "vary_msgcount")) {
4744 if (iflags.wc_vary_msgcount)
4745 Sprintf(buf, "%d", iflags.wc_vary_msgcount);
4747 Strcpy(buf, defopt);
4749 } else if (!strcmp(optname, "video")) {
4750 Sprintf(buf, "%s", to_be_done);
4753 } else if (!strcmp(optname, "videoshades")) {
4754 Sprintf(buf, "%s-%s-%s", shade[0], shade[1], shade[2]);
4755 } else if (!strcmp(optname, "videocolors")) {
4756 Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
4757 ttycolors[CLR_RED], ttycolors[CLR_GREEN],
4758 ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
4759 ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
4760 ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
4761 ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
4762 ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]);
4763 #endif /* VIDEOSHADES */
4764 } else if (!strcmp(optname, "windowtype")) {
4765 Sprintf(buf, "%s", windowprocs.name);
4766 } else if (!strcmp(optname, "windowcolors")) {
4768 buf, "%s/%s %s/%s %s/%s %s/%s",
4769 iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
4770 iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
4771 iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message
4773 iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message
4775 iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
4776 iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
4777 iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
4778 iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
4779 #ifdef PREFIXES_IN_USE
4781 for (i = 0; i < PREFIX_COUNT; ++i)
4782 if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
4783 Sprintf(buf, "%s", fqn_prefix[i]);
4796 char buf[BUFSZ], ocl[MAXOCLASSES + 1];
4798 flags.pickup = !flags.pickup;
4800 oc_to_str(flags.pickup_types, ocl);
4801 Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
4802 (iflags.autopickup_exceptions[AP_LEAVE]
4803 || iflags.autopickup_exceptions[AP_GRAB])
4804 ? ((count_ape_maps((int *) 0, (int *) 0) == 1)
4805 ? ", with one exception"
4806 : ", with some exceptions")
4811 pline("Autopickup: %s.", buf);
4816 add_autopickup_exception(mapping)
4817 const char *mapping;
4819 struct autopickup_exception *ape, **apehead;
4820 char text[256], *text2;
4821 boolean grab = FALSE;
4823 if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
4825 if (*text2 == '<') { /* force autopickup */
4828 } else if (*text2 == '>') { /* default - Do not pickup */
4832 apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB]
4833 : &iflags.autopickup_exceptions[AP_LEAVE];
4834 ape = (struct autopickup_exception *) alloc(
4835 sizeof (struct autopickup_exception));
4836 ape->regex = regex_init();
4837 if (!regex_compile(text2, ape->regex)) {
4838 raw_print("regex error in AUTOPICKUP_EXCEPTION");
4839 regex_free(ape->regex);
4840 free((genericptr_t) ape);
4843 ape->pattern = (char *) alloc(strlen(text2) + 1);
4844 strcpy(ape->pattern, text2);
4846 ape->next = *apehead;
4849 raw_print("syntax error in AUTOPICKUP_EXCEPTION");
4856 remove_autopickup_exception(whichape)
4857 struct autopickup_exception *whichape;
4859 struct autopickup_exception *ape, *prev = 0;
4860 int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
4862 for (ape = iflags.autopickup_exceptions[chain]; ape;) {
4863 if (ape == whichape) {
4864 struct autopickup_exception *freeape = ape;
4870 iflags.autopickup_exceptions[chain] = ape;
4871 regex_free(freeape->regex);
4872 free((genericptr_t) freeape->pattern);
4873 free((genericptr_t) freeape);
4882 count_ape_maps(leave, grab)
4885 struct autopickup_exception *ape;
4886 int pass, totalapes, numapes[2] = { 0, 0 };
4888 for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
4889 ape = iflags.autopickup_exceptions[pass];
4895 totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
4897 *leave = numapes[AP_LEAVE];
4899 *grab = numapes[AP_GRAB];
4904 free_autopickup_exceptions()
4906 struct autopickup_exception *ape;
4909 for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
4910 while ((ape = iflags.autopickup_exceptions[pass]) != 0) {
4911 regex_free(ape->regex);
4912 free((genericptr_t) ape->pattern);
4913 iflags.autopickup_exceptions[pass] = ape->next;
4914 free((genericptr_t) ape);
4919 /* bundle some common usage into one easy-to-use routine */
4921 load_symset(s, which_set)
4925 clear_symsetentry(which_set, TRUE);
4927 if (symset[which_set].name)
4928 free((genericptr_t) symset[which_set].name);
4929 symset[which_set].name = dupstr(s);
4931 if (read_sym_file(which_set)) {
4932 switch_symbols(TRUE);
4934 clear_symsetentry(which_set, TRUE);
4943 clear_symsetentry(PRIMARY, TRUE);
4944 clear_symsetentry(ROGUESET, TRUE);
4946 /* symset_list is cleaned up as soon as it's used, so we shouldn't
4947 have to anything about it here */
4948 /* assert( symset_list == NULL ); */
4951 /* Parse the value of a SYMBOLS line from a config file */
4954 register char *opts;
4957 char *op, *symname, *strval;
4958 struct symparse *symp;
4960 if ((op = index(opts, ',')) != 0) {
4965 /* S_sample:string */
4967 strval = index(opts, ':');
4969 strval = index(opts, '=');
4974 /* strip leading and trailing white space from symname and strval */
4975 mungspaces(symname);
4978 symp = match_sym(symname);
4982 if (symp->range && symp->range != SYM_CONTROL) {
4983 val = sym_val(strval);
4984 update_l_symset(symp, val);
4992 size_t len = strlen(buf);
4993 const char *p = index(buf, ':'), *q = index(buf, '=');
4994 struct symparse *sp = loadsyms;
4996 if (!p || (q && q < p))
4999 /* note: there will be at most one space before the '='
5000 because caller has condensed buf[] with mungspaces() */
5001 if (p > buf && p[-1] == ' ')
5003 len = (int) (p - buf);
5006 if ((len >= strlen(sp->name)) && !strncmpi(buf, sp->name, len))
5010 return (struct symparse *) 0;
5019 escapes(strval, buf);
5023 /* data for option_help() */
5024 static const char *opt_intro[] = {
5025 "", " NetHack Options Help:", "",
5026 #define CONFIG_SLOT 3 /* fill in next value at run-time */
5028 #if !defined(MICRO) && !defined(MAC)
5029 "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
5031 "(<options> is a list of options separated by commas)",
5033 "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
5035 "or press \"O\" while playing and use the menu.", "",
5036 "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
5040 static const char *opt_epilog[] = {
5042 "Some of the options can be set only before the game is started; those",
5043 "items will not be selectable in the 'O' command's menu.", (char *) 0
5049 char buf[BUFSZ], buf2[BUFSZ];
5053 datawin = create_nhwindow(NHW_TEXT);
5054 Sprintf(buf, "Set options as OPTIONS=<options> in %s", lastconfigfile);
5055 opt_intro[CONFIG_SLOT] = (const char *) buf;
5056 for (i = 0; opt_intro[i]; i++)
5057 putstr(datawin, 0, opt_intro[i]);
5059 /* Boolean options */
5060 for (i = 0; boolopt[i].name; i++) {
5061 if (boolopt[i].addr) {
5062 if (boolopt[i].addr == &iflags.sanity_check && !wizard)
5064 if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard)
5066 next_opt(datawin, boolopt[i].name);
5069 next_opt(datawin, "");
5071 /* Compound options */
5072 putstr(datawin, 0, "Compound options:");
5073 for (i = 0; compopt[i].name; i++) {
5074 Sprintf(buf2, "`%s'", compopt[i].name);
5075 Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
5076 compopt[i + 1].name ? ',' : '.');
5077 putstr(datawin, 0, buf);
5080 for (i = 0; opt_epilog[i]; i++)
5081 putstr(datawin, 0, opt_epilog[i]);
5083 display_nhwindow(datawin, FALSE);
5084 destroy_nhwindow(datawin);
5089 * prints the next boolean option, on the same line if possible, on a new
5090 * line if not. End with next_opt("").
5093 next_opt(datawin, str)
5097 static char *buf = 0;
5102 *(buf = (char *) alloc(BUFSZ)) = '\0';
5106 if (s > &buf[1] && s[-2] == ',')
5107 Strcpy(s - 2, "."); /* replace last ", " */
5108 i = COLNO; /* (greater than COLNO - 2) */
5110 i = strlen(buf) + strlen(str) + 2;
5113 if (i > COLNO - 2) { /* rule of thumb */
5114 putstr(datawin, 0, buf);
5121 putstr(datawin, 0, str);
5122 free((genericptr_t) buf), buf = 0;
5127 /* Returns the fid of the fruit type; if that type already exists, it
5128 * returns the fid of that one; if it does not exist, it adds a new fruit
5129 * type to the chain and returns the new one.
5130 * If replace_fruit is sent in, replace the fruit in the chain rather than
5131 * adding a new entry--for user specified fruits only.
5134 fruitadd(str, replace_fruit)
5136 struct fruit *replace_fruit;
5139 register struct fruit *f;
5140 int highest_fruit_id = 0;
5141 char buf[PL_FSIZ], altname[PL_FSIZ];
5142 boolean user_specified = (str == pl_fruit);
5143 /* if not user-specified, then it's a fruit name for a fruit on
5147 /* Note: every fruit has an id (kept in obj->spe) of at least 1;
5150 if (user_specified) {
5151 boolean found = FALSE, numeric = FALSE;
5153 /* force fruit to be singular; this handling is not
5154 needed--or wanted--for fruits from bones because
5155 they already received it in their original game */
5156 nmcpy(pl_fruit, makesingular(str), PL_FSIZ);
5157 /* assert( str == pl_fruit ); */
5159 /* disallow naming after other foods (since it'd be impossible
5160 * to tell the difference)
5163 for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) {
5164 if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
5174 for (c = pl_fruit; *c >= '0' && *c <= '9'; c++)
5176 if (isspace((uchar) *c) || *c == 0)
5179 if (found || numeric || !strncmp(str, "cursed ", 7)
5180 || !strncmp(str, "uncursed ", 9) || !strncmp(str, "blessed ", 8)
5181 || !strncmp(str, "partly eaten ", 13)
5182 || (!strncmp(str, "tin of ", 7)
5183 && (!strcmp(str + 7, "spinach")
5184 || name_to_mon(str + 7) >= LOW_PM))
5185 || !strcmp(str, "empty tin")
5186 || ((str_end_is(str, " corpse")
5187 || str_end_is(str, " egg"))
5188 && name_to_mon(str) >= LOW_PM)) {
5189 Strcpy(buf, pl_fruit);
5190 Strcpy(pl_fruit, "candied ");
5191 nmcpy(pl_fruit + 8, buf, PL_FSIZ - 8);
5194 /* This flag indicates that a fruit has been made since the
5195 * last time the user set the fruit. If it hasn't, we can
5196 * safely overwrite the current fruit, preventing the user from
5197 * setting many fruits in a row and overflowing.
5198 * Possible expansion: check for specific fruit IDs, not for
5201 flags.made_fruit = FALSE;
5202 if (replace_fruit) {
5203 for (f = ffruit; f; f = f->nextf) {
5204 if (f == replace_fruit) {
5205 copynchars(f->fname, str, PL_FSIZ - 1);
5211 /* not user_supplied, so assumed to be from bones */
5212 copynchars(altname, str, PL_FSIZ - 1);
5213 sanitize_name(altname);
5214 flags.made_fruit = TRUE; /* for safety. Any fruit name added from a
5215 bones level should exist anyway. */
5217 for (f = ffruit; f; f = f->nextf) {
5218 if (f->fid > highest_fruit_id)
5219 highest_fruit_id = f->fid;
5220 if (!strncmp(str, f->fname, PL_FSIZ - 1)
5221 || (*altname && !strcmp(altname, f->fname)))
5224 /* if adding another fruit would overflow spe, use a random
5225 fruit instead... we've got a lot to choose from.
5226 current_fruit remains as is. */
5227 if (highest_fruit_id >= 127)
5231 copynchars(f->fname, *altname ? altname : str, PL_FSIZ - 1);
5232 f->fid = ++highest_fruit_id;
5233 /* we used to go out of our way to add it at the end of the list,
5234 but the order is arbitrary so use simpler insertion at start */
5239 context.current_fruit = f->fid;
5244 * This is a somewhat generic menu for taking a list of NetHack style
5245 * class choices and presenting them via a description
5246 * rather than the traditional NetHack characters.
5247 * (Benefits users whose first exposure to NetHack is via tiles).
5250 * The title at the top of the menu.
5252 * category: 0 = monster class
5256 * FALSE = PICK_ONE, TRUE = PICK_ANY
5259 * a null terminated string containing the list of choices.
5262 * a null terminated string containing the selected characters.
5264 * Returns number selected.
5267 choose_classes_menu(prompt, category, way, class_list, class_select)
5274 menu_item *pick_list = (menu_item *) 0;
5280 int next_accelerator, accelerator;
5282 if (class_list == (char *) 0 || class_select == (char *) 0)
5285 next_accelerator = 'a';
5287 win = create_nhwindow(NHW_MENU);
5289 while (*class_list) {
5297 text = def_monsyms[def_char_to_monclass(*class_list)].explain;
5298 accelerator = *class_list;
5299 Sprintf(buf, "%s", text);
5302 text = def_oc_syms[def_char_to_objclass(*class_list)].explain;
5303 accelerator = next_accelerator;
5304 Sprintf(buf, "%c %s", *class_list, text);
5307 impossible("choose_classes_menu: invalid category %d", category);
5309 if (way && *class_select) { /* Selections there already */
5310 if (index(class_select, *class_list)) {
5314 any.a_int = *class_list;
5315 add_menu(win, NO_GLYPH, &any, accelerator, category ? *class_list : 0,
5316 ATR_NONE, buf, selected);
5320 if (next_accelerator == ('z' + 1))
5321 next_accelerator = 'A';
5322 if (next_accelerator == ('Z' + 1))
5326 end_menu(win, prompt);
5327 n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
5328 destroy_nhwindow(win);
5330 for (i = 0; i < n; ++i)
5331 *class_select++ = (char) pick_list[i].item.a_int;
5332 free((genericptr_t) pick_list);
5334 } else if (n == -1) {
5335 class_select = eos(class_select);
5339 *class_select = '\0';
5343 struct wc_Opt wc_options[] = { { "ascii_map", WC_ASCII_MAP },
5344 { "color", WC_COLOR },
5345 { "eight_bit_tty", WC_EIGHT_BIT_IN },
5346 { "hilite_pet", WC_HILITE_PET },
5347 { "popup_dialog", WC_POPUP_DIALOG },
5348 { "player_selection", WC_PLAYER_SELECTION },
5349 { "preload_tiles", WC_PRELOAD_TILES },
5350 { "tiled_map", WC_TILED_MAP },
5351 { "tile_file", WC_TILE_FILE },
5352 { "tile_width", WC_TILE_WIDTH },
5353 { "tile_height", WC_TILE_HEIGHT },
5354 { "use_inverse", WC_INVERSE },
5355 { "align_message", WC_ALIGN_MESSAGE },
5356 { "align_status", WC_ALIGN_STATUS },
5357 { "font_map", WC_FONT_MAP },
5358 { "font_menu", WC_FONT_MENU },
5359 { "font_message", WC_FONT_MESSAGE },
5361 {"perm_invent", WC_PERM_INVENT},
5363 { "font_size_map", WC_FONTSIZ_MAP },
5364 { "font_size_menu", WC_FONTSIZ_MENU },
5365 { "font_size_message", WC_FONTSIZ_MESSAGE },
5366 { "font_size_status", WC_FONTSIZ_STATUS },
5367 { "font_size_text", WC_FONTSIZ_TEXT },
5368 { "font_status", WC_FONT_STATUS },
5369 { "font_text", WC_FONT_TEXT },
5370 { "map_mode", WC_MAP_MODE },
5371 { "scroll_amount", WC_SCROLL_AMOUNT },
5372 { "scroll_margin", WC_SCROLL_MARGIN },
5373 { "splash_screen", WC_SPLASH_SCREEN },
5374 { "vary_msgcount", WC_VARY_MSGCOUNT },
5375 { "windowcolors", WC_WINDOWCOLORS },
5376 { "mouse_support", WC_MOUSE_SUPPORT },
5377 { (char *) 0, 0L } };
5379 struct wc_Opt wc2_options[] = { { "fullscreen", WC2_FULLSCREEN },
5380 { "softkeyboard", WC2_SOFTKEYBOARD },
5381 { "wraptext", WC2_WRAPTEXT },
5382 { "use_darkgray", WC2_DARKGRAY },
5383 #ifdef STATUS_VIA_WINDOWPORT
5384 { "hilite_status", WC2_HILITE_STATUS },
5386 { (char *) 0, 0L } };
5389 * If a port wants to change or ensure that the SET_IN_SYS,
5390 * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
5391 * correct (for controlling its display in the option menu) call
5392 * set_option_mod_status()
5393 * with the appropriate second argument.
5396 set_option_mod_status(optnam, status)
5402 if (SET__IS_VALUE_VALID(status)) {
5403 impossible("set_option_mod_status: status out of range %d.", status);
5406 for (k = 0; boolopt[k].name; k++) {
5407 if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
5408 boolopt[k].optflags = status;
5412 for (k = 0; compopt[k].name; k++) {
5413 if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
5414 compopt[k].optflags = status;
5421 * You can set several wc_options in one call to
5422 * set_wc_option_mod_status() by setting
5423 * the appropriate bits for each option that you
5424 * are setting in the optmask argument
5426 * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN,
5430 set_wc_option_mod_status(optmask, status)
5431 unsigned long optmask;
5436 if (SET__IS_VALUE_VALID(status)) {
5437 impossible("set_wc_option_mod_status: status out of range %d.",
5441 while (wc_options[k].wc_name) {
5442 if (optmask & wc_options[k].wc_bit) {
5443 set_option_mod_status(wc_options[k].wc_name, status);
5450 is_wc_option(optnam)
5455 while (wc_options[k].wc_name) {
5456 if (strcmp(wc_options[k].wc_name, optnam) == 0)
5464 wc_supported(optnam)
5469 while (wc_options[k].wc_name) {
5470 if (!strcmp(wc_options[k].wc_name, optnam)
5471 && (windowprocs.wincap & wc_options[k].wc_bit))
5479 * You can set several wc2_options in one call to
5480 * set_wc2_option_mod_status() by setting
5481 * the appropriate bits for each option that you
5482 * are setting in the optmask argument
5485 * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
5490 set_wc2_option_mod_status(optmask, status)
5491 unsigned long optmask;
5496 if (SET__IS_VALUE_VALID(status)) {
5497 impossible("set_wc2_option_mod_status: status out of range %d.",
5501 while (wc2_options[k].wc_name) {
5502 if (optmask & wc2_options[k].wc_bit) {
5503 set_option_mod_status(wc2_options[k].wc_name, status);
5510 is_wc2_option(optnam)
5515 while (wc2_options[k].wc_name) {
5516 if (strcmp(wc2_options[k].wc_name, optnam) == 0)
5524 wc2_supported(optnam)
5529 while (wc2_options[k].wc_name) {
5530 if (!strcmp(wc2_options[k].wc_name, optnam)
5531 && (windowprocs.wincap2 & wc2_options[k].wc_bit))
5539 wc_set_font_name(opttype, fontname)
5543 char **fn = (char **) 0;
5549 fn = &iflags.wc_font_map;
5551 case MESSAGE_OPTION:
5552 fn = &iflags.wc_font_message;
5555 fn = &iflags.wc_font_text;
5558 fn = &iflags.wc_font_menu;
5561 fn = &iflags.wc_font_status;
5568 free((genericptr_t) *fn);
5569 *fn = dupstr(fontname);
5575 wc_set_window_colors(op)
5579 * menu white/black message green/yellow status white/blue text
5584 char *wn, *tfg, *tbg, *newop;
5585 static const char *wnames[] = { "menu", "message", "status", "text" };
5586 static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
5587 static char **fgp[] = { &iflags.wc_foregrnd_menu,
5588 &iflags.wc_foregrnd_message,
5589 &iflags.wc_foregrnd_status,
5590 &iflags.wc_foregrnd_text };
5591 static char **bgp[] = { &iflags.wc_backgrnd_menu,
5592 &iflags.wc_backgrnd_message,
5593 &iflags.wc_backgrnd_status,
5594 &iflags.wc_backgrnd_text };
5597 newop = mungspaces(buf);
5598 while (newop && *newop) {
5599 wn = tfg = tbg = (char *) 0;
5601 /* until first non-space in case there's leading spaces - before
5610 /* until first space - colorname*/
5611 while (*newop && *newop != ' ')
5619 /* until first non-space - before foreground*/
5627 /* until slash - foreground */
5628 while (*newop && *newop != '/')
5636 /* until first non-space (in case there's leading space after slash) -
5637 * before background */
5645 /* until first space - background */
5646 while (*newop && *newop != ' ')
5651 for (j = 0; j < 4; ++j) {
5652 if (!strcmpi(wn, wnames[j]) || !strcmpi(wn, shortnames[j])) {
5653 if (tfg && !strstri(tfg, " ")) {
5655 free((genericptr_t) *fgp[j]);
5656 *fgp[j] = dupstr(tfg);
5658 if (tbg && !strstri(tbg, " ")) {
5660 free((genericptr_t) *bgp[j]);
5661 *bgp[j] = dupstr(tbg);
5670 /* set up for wizard mode if player or save file has requested to it;
5671 called from port-specific startup code to handle `nethack -D' or
5672 OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
5673 restoring a game which was saved in wizard mode */
5678 if (authorize_wizard_mode())
5679 Strcpy(plname, "wizard");
5681 wizard = FALSE; /* not allowed or not available */
5682 /* force explore mode if we didn't make it into wizard mode */
5684 iflags.deferred_X = FALSE;
5686 /* don't need to do anything special for explore mode or normal play */
5689 #endif /* OPTION_LISTS_ONLY */