1 /* NetHack 3.6 options.c $NHDT-Date: 1470357737 2016/08/05 00:42:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.279 $ */
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 { "autodescribe", &iflags
.autodescribe
, FALSE
, SET_IN_GAME
},
79 { "autodig", &flags
.autodig
, FALSE
, SET_IN_GAME
},
80 { "autoopen", &flags
.autoopen
, TRUE
, SET_IN_GAME
},
81 { "autopickup", &flags
.pickup
, TRUE
, SET_IN_GAME
},
82 { "autoquiver", &flags
.autoquiver
, FALSE
, SET_IN_GAME
},
83 #if defined(MICRO) && !defined(AMIGA)
84 { "BIOS", &iflags
.BIOS
, FALSE
, SET_IN_FILE
},
86 { "BIOS", (boolean
*) 0, FALSE
, SET_IN_FILE
},
88 { "blind", &u
.uroleplay
.blind
, FALSE
, DISP_IN_GAME
},
89 { "bones", &flags
.bones
, TRUE
, SET_IN_FILE
},
91 { "checkpoint", &flags
.ins_chkpt
, TRUE
, SET_IN_GAME
},
93 { "checkpoint", (boolean
*) 0, FALSE
, SET_IN_FILE
},
96 { "checkspace", &iflags
.checkspace
, TRUE
, SET_IN_GAME
},
98 { "checkspace", (boolean
*) 0, FALSE
, SET_IN_FILE
},
100 { "clicklook", &iflags
.clicklook
, FALSE
, SET_IN_GAME
},
101 { "cmdassist", &iflags
.cmdassist
, TRUE
, SET_IN_GAME
},
102 #if defined(MICRO) || defined(WIN32)
103 { "color", &iflags
.wc_color
, TRUE
, SET_IN_GAME
}, /*WC*/
104 #else /* systems that support multiple terminals, many monochrome */
105 { "color", &iflags
.wc_color
, FALSE
, SET_IN_GAME
}, /*WC*/
107 { "confirm", &flags
.confirm
, TRUE
, SET_IN_GAME
},
108 { "dark_room", &flags
.dark_room
, TRUE
, SET_IN_GAME
},
109 { "eight_bit_tty", &iflags
.wc_eight_bit_input
, FALSE
,
110 SET_IN_GAME
}, /*WC*/
112 { "extmenu", &iflags
.extmenu
, FALSE
, SET_IN_GAME
},
114 { "extmenu", (boolean
*) 0, FALSE
, SET_IN_FILE
},
117 { "fast_map", &flags
.fast_map
, TRUE
, SET_IN_GAME
},
119 { "fast_map", (boolean
*) 0, TRUE
, SET_IN_FILE
},
121 { "female", &flags
.female
, FALSE
, DISP_IN_GAME
},
122 { "fixinv", &flags
.invlet_constant
, TRUE
, SET_IN_GAME
},
123 #if defined(SYSFLAGS) && defined(AMIFLUSH)
124 { "flush", &sysflags
.amiflush
, FALSE
, SET_IN_GAME
},
126 { "flush", (boolean
*) 0, FALSE
, SET_IN_FILE
},
128 { "fullscreen", &iflags
.wc2_fullscreen
, FALSE
, SET_IN_FILE
},
129 { "help", &flags
.help
, TRUE
, SET_IN_GAME
},
130 { "hilite_pet", &iflags
.wc_hilite_pet
, FALSE
, SET_IN_GAME
}, /*WC*/
131 { "hilite_pile", &iflags
.hilite_pile
, FALSE
, SET_IN_GAME
},
133 { "ignintr", &flags
.ignintr
, FALSE
, SET_IN_GAME
},
135 { "ignintr", (boolean
*) 0, FALSE
, SET_IN_FILE
},
137 { "implicit_uncursed", &iflags
.implicit_uncursed
, TRUE
, SET_IN_GAME
},
138 { "large_font", &iflags
.obsolete
, FALSE
, SET_IN_FILE
}, /* OBSOLETE */
139 { "legacy", &flags
.legacy
, TRUE
, DISP_IN_GAME
},
140 { "lit_corridor", &flags
.lit_corridor
, FALSE
, SET_IN_GAME
},
141 { "lootabc", &flags
.lootabc
, FALSE
, SET_IN_GAME
},
143 { "mail", &flags
.biff
, TRUE
, SET_IN_GAME
},
145 { "mail", (boolean
*) 0, TRUE
, SET_IN_FILE
},
147 { "mention_walls", &iflags
.mention_walls
, FALSE
, SET_IN_GAME
},
148 { "menucolors", &iflags
.use_menu_color
, FALSE
, SET_IN_GAME
},
149 /* for menu debugging only*/
150 { "menu_tab_sep", &iflags
.menu_tab_sep
, FALSE
, SET_IN_WIZGAME
},
151 { "menu_objsyms", &iflags
.menu_head_objsym
, FALSE
, SET_IN_GAME
},
153 { "menu_overlay", &iflags
.menu_overlay
, TRUE
, SET_IN_GAME
},
155 { "menu_overlay", (boolean
*) 0, FALSE
, SET_IN_FILE
},
157 { "mouse_support", &iflags
.wc_mouse_support
, TRUE
, DISP_IN_GAME
}, /*WC*/
159 { "news", &iflags
.news
, TRUE
, DISP_IN_GAME
},
161 { "news", (boolean
*) 0, FALSE
, SET_IN_FILE
},
163 { "nudist", &u
.uroleplay
.nudist
, FALSE
, DISP_IN_GAME
},
164 { "null", &flags
.null
, TRUE
, SET_IN_GAME
},
165 #if defined(SYSFLAGS) && defined(MAC)
166 { "page_wait", &sysflags
.page_wait
, TRUE
, SET_IN_GAME
},
168 { "page_wait", (boolean
*) 0, FALSE
, SET_IN_FILE
},
170 { "perm_invent", &flags
.perm_invent
, FALSE
, SET_IN_GAME
},
171 { "pickup_thrown", &flags
.pickup_thrown
, TRUE
, SET_IN_GAME
},
172 { "popup_dialog", &iflags
.wc_popup_dialog
, FALSE
, SET_IN_GAME
}, /*WC*/
173 { "preload_tiles", &iflags
.wc_preload_tiles
, TRUE
, DISP_IN_GAME
}, /*WC*/
174 { "pushweapon", &flags
.pushweapon
, FALSE
, SET_IN_GAME
},
175 #if defined(MICRO) && !defined(AMIGA)
176 { "rawio", &iflags
.rawio
, FALSE
, DISP_IN_GAME
},
178 { "rawio", (boolean
*) 0, FALSE
, SET_IN_FILE
},
180 { "rest_on_space", &flags
.rest_on_space
, FALSE
, SET_IN_GAME
},
182 { "rlecomp", &iflags
.rlecomp
,
183 #if defined(COMPRESS) || defined(ZLIB_COMP)
190 { "safe_pet", &flags
.safe_dog
, TRUE
, SET_IN_GAME
},
191 { "sanity_check", &iflags
.sanity_check
, FALSE
, SET_IN_WIZGAME
},
192 { "selectsaved", &iflags
.wc2_selectsaved
, TRUE
, DISP_IN_GAME
}, /*WC*/
193 { "showexp", &flags
.showexp
, FALSE
, SET_IN_GAME
},
194 { "showrace", &flags
.showrace
, FALSE
, SET_IN_GAME
},
196 { "showscore", &flags
.showscore
, FALSE
, SET_IN_GAME
},
198 { "showscore", (boolean
*) 0, FALSE
, SET_IN_FILE
},
200 { "silent", &flags
.silent
, TRUE
, SET_IN_GAME
},
201 { "softkeyboard", &iflags
.wc2_softkeyboard
, FALSE
, SET_IN_FILE
},
202 { "sortpack", &flags
.sortpack
, TRUE
, SET_IN_GAME
},
203 { "sparkle", &flags
.sparkle
, TRUE
, SET_IN_GAME
},
204 { "splash_screen", &iflags
.wc_splash_screen
, TRUE
, DISP_IN_GAME
}, /*WC*/
205 { "standout", &flags
.standout
, FALSE
, SET_IN_GAME
},
206 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
207 { "statushilites", &iflags
.use_status_hilites
, TRUE
, SET_IN_GAME
},
209 { "statushilites", &iflags
.use_status_hilites
, FALSE
, DISP_IN_GAME
},
211 { "tiled_map", &iflags
.wc_tiled_map
, PREFER_TILED
, DISP_IN_GAME
}, /*WC*/
212 { "time", &flags
.time
, FALSE
, SET_IN_GAME
},
214 { "timed_delay", &flags
.nap
, TRUE
, SET_IN_GAME
},
216 { "timed_delay", (boolean
*) 0, FALSE
, SET_IN_GAME
},
218 { "tombstone", &flags
.tombstone
, TRUE
, SET_IN_GAME
},
219 { "toptenwin", &iflags
.toptenwin
, FALSE
, SET_IN_GAME
},
220 { "travel", &flags
.travelcmd
, TRUE
, SET_IN_GAME
},
221 { "use_darkgray", &iflags
.wc2_darkgray
, TRUE
, SET_IN_FILE
},
223 { "use_inverse", &iflags
.wc_inverse
, TRUE
, SET_IN_GAME
}, /*WC*/
225 { "use_inverse", &iflags
.wc_inverse
, FALSE
, SET_IN_GAME
}, /*WC*/
227 { "verbose", &flags
.verbose
, TRUE
, SET_IN_GAME
},
228 #ifdef TTY_TILES_ESCCODES
229 { "vt_tiledata", &iflags
.vt_tiledata
, FALSE
, SET_IN_FILE
},
231 { "vt_tiledata", (boolean
*) 0, FALSE
, SET_IN_FILE
},
233 { "wizweight", &iflags
.wizweight
, FALSE
, SET_IN_WIZGAME
},
234 { "wraptext", &iflags
.wc2_wraptext
, FALSE
, SET_IN_GAME
},
236 { "zerocomp", &iflags
.zerocomp
,
237 #if defined(COMPRESS) || defined(ZLIB_COMP)
244 { (char *) 0, (boolean
*) 0, FALSE
, 0 }
247 /* compound options, for option_help() and external programs like Amiga
249 static struct Comp_Opt
{
250 const char *name
, *descr
;
251 int size
; /* for frontends and such allocating space --
252 * usually allowed size of data in game, but
253 * occasionally maximum reasonable size for
254 * typing when game maintains information in
255 * a different format */
258 { "align", "your starting alignment (lawful, neutral, or chaotic)", 8,
260 { "align_message", "message window alignment", 20, DISP_IN_GAME
}, /*WC*/
261 { "align_status", "status window alignment", 20, DISP_IN_GAME
}, /*WC*/
262 { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME
},
263 #ifdef BACKWARD_COMPAT
264 { "boulder", "deprecated (use S_boulder in sym file instead)", 1,
267 { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
268 PL_PSIZ
, DISP_IN_GAME
},
269 { "disclose", "the kinds of information to disclose at end of game",
270 sizeof(flags
.end_disclose
) * 2, SET_IN_GAME
},
271 { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ
,
273 { "dungeon", "the symbols to use in drawing the dungeon map",
274 MAXDCHARS
+ 1, SET_IN_FILE
},
275 { "effects", "the symbols to use in drawing special effects",
276 MAXECHARS
+ 1, SET_IN_FILE
},
277 { "font_map", "the font to use in the map window", 40,
278 DISP_IN_GAME
}, /*WC*/
279 { "font_menu", "the font to use in menus", 40, DISP_IN_GAME
}, /*WC*/
280 { "font_message", "the font to use in the message window", 40,
281 DISP_IN_GAME
}, /*WC*/
282 { "font_size_map", "the size of the map font", 20, DISP_IN_GAME
}, /*WC*/
283 { "font_size_menu", "the size of the menu font", 20,
284 DISP_IN_GAME
}, /*WC*/
285 { "font_size_message", "the size of the message font", 20,
286 DISP_IN_GAME
}, /*WC*/
287 { "font_size_status", "the size of the status font", 20,
288 DISP_IN_GAME
}, /*WC*/
289 { "font_size_text", "the size of the text font", 20,
290 DISP_IN_GAME
}, /*WC*/
291 { "font_status", "the font to use in status window", 40,
292 DISP_IN_GAME
}, /*WC*/
293 { "font_text", "the font to use in text windows", 40,
294 DISP_IN_GAME
}, /*WC*/
295 { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ
, SET_IN_GAME
},
296 { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME
},
297 { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
298 PL_PSIZ
, DISP_IN_GAME
},
299 { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME
}, /*WC*/
300 { "menustyle", "user interface for object selection", MENUTYPELEN
,
302 { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE
},
303 { "menu_deselect_page", "deselect all items on this page of a menu", 4,
305 { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE
},
306 { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME
},
307 { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE
},
308 { "menu_invert_page", "invert all items on this page of a menu", 4,
310 { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE
},
311 { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE
},
312 { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE
},
313 { "menu_search", "search for a menu item", 4, SET_IN_FILE
},
314 { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE
},
315 { "menu_select_page", "select all items on this page of a menu", 4,
317 { "monsters", "the symbols to use for monsters", MAXMCLASSES
,
319 { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME
},
321 { "msg_window", "the type of message window required", 1, SET_IN_GAME
},
323 { "msg_window", "the type of message window required", 1, SET_IN_FILE
},
325 { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ
,
327 { "number_pad", "use the number pad for movement", 1, SET_IN_GAME
},
328 { "objects", "the symbols to use for objects", MAXOCLASSES
, SET_IN_FILE
},
329 { "packorder", "the inventory order of the items in your pack",
330 MAXOCLASSES
, SET_IN_GAME
},
334 "palette (00c/880/-fff is blue/yellow/reverse white)", 15,
337 "palette (adjust an RGB color in palette (color-R-G-B)", 15,
341 { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE
},
344 { "paranoid_confirmation", "extra prompting in certain situations", 28,
346 { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME
},
347 { "pickup_burden", "maximum burden picked up before prompt", 20,
349 { "pickup_types", "types of objects to pick up automatically",
350 MAXOCLASSES
, SET_IN_GAME
},
351 { "pile_limit", "threshold for \"there are many objects here\"", 24,
353 { "playmode", "normal play, non-scoring explore mode, or debug mode", 8,
355 { "player_selection", "choose character via dialog or prompts", 12,
357 { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ
,
359 { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ
,
361 { "runmode", "display frequency when `running' or `travelling'",
362 sizeof "teleport", SET_IN_GAME
},
363 { "scores", "the parts of the score list you wish to see", 32,
365 { "scroll_amount", "amount to scroll map when scroll_margin is reached",
366 20, DISP_IN_GAME
}, /*WC*/
367 { "scroll_margin", "scroll map when this far from the edge", 20,
368 DISP_IN_GAME
}, /*WC*/
369 { "sortloot", "sort object selection lists by description", 4,
372 { "soundcard", "type of sound card to use", 20, SET_IN_FILE
},
374 { "symset", "load a set of display symbols from the symbols file", 70,
377 "load a set of rogue display symbols from the symbols file", 70,
380 { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE
},
382 { "suppress_alert", "suppress alerts about version-specific features", 8,
384 { "tile_width", "width of tiles", 20, DISP_IN_GAME
}, /*WC*/
385 { "tile_height", "height of tiles", 20, DISP_IN_GAME
}, /*WC*/
386 { "tile_file", "name of tile file", 70, DISP_IN_GAME
}, /*WC*/
387 { "traps", "the symbols to use in drawing traps", MAXTCHARS
+ 1,
389 { "vary_msgcount", "show more old messages at a time", 20,
390 DISP_IN_GAME
}, /*WC*/
392 { "video", "method of video updating", 20, SET_IN_FILE
},
395 { "videocolors", "color mappings for internal screen routines", 40,
397 { "videoshades", "gray shades to map to black/gray/white", 32,
400 { "whatis_coord", "show coordinates when auto-describing cursor position",
402 { "windowcolors", "the foreground/background colors of windows", /*WC*/
404 { "windowtype", "windowing system to use", WINTYPELEN
, DISP_IN_GAME
},
406 { "windowchain", "window processor to use", WINTYPELEN
, SET_IN_SYS
},
408 #ifdef BACKWARD_COMPAT
409 { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE
},
410 { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE
},
411 #ifdef MAC_GRAPHICS_ENV
412 { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE
},
415 { (char *) 0, (char *) 0, 0, 0 }
418 #ifdef OPTION_LISTS_ONLY
421 #else /* use rest of file */
423 extern char configfile
[]; /* for messages */
425 extern struct symparse loadsyms
[];
426 static boolean need_redraw
; /* for doset() */
428 #if defined(TOS) && defined(TEXTCOLOR)
429 extern boolean colors_changed
; /* in tos.c */
433 extern char *shade
[3]; /* in sys/msdos/video.c */
434 extern char ttycolors
[CLR_MAX
]; /* in sys/msdos/video.c */
437 static char def_inv_order
[MAXOCLASSES
] = {
438 COIN_CLASS
, AMULET_CLASS
, WEAPON_CLASS
, ARMOR_CLASS
, FOOD_CLASS
,
439 SCROLL_CLASS
, SPBOOK_CLASS
, POTION_CLASS
, RING_CLASS
, WAND_CLASS
,
440 TOOL_CLASS
, GEM_CLASS
, ROCK_CLASS
, BALL_CLASS
, CHAIN_CLASS
, 0,
444 * Default menu manipulation command accelerators. These may _not_ be:
446 * + a number - reserved for counts
447 * + an upper or lower case US ASCII letter - used for accelerators
448 * + ESC - reserved for escaping the menu
449 * + NULL, CR or LF - reserved for commiting the selection(s). NULL
450 * is kind of odd, but the tty's xwaitforspace() will return it if
451 * someone hits a <ret>.
452 * + a default object class symbol - used for object class accelerators
454 * Standard letters (for now) are:
467 * The command name list is duplicated in the compopt array.
474 #define NUM_MENU_CMDS 11
475 static const menu_cmd_t default_menu_cmd_info
[NUM_MENU_CMDS
] = {
476 /* 0*/ { "menu_first_page", MENU_FIRST_PAGE
},
477 { "menu_last_page", MENU_LAST_PAGE
},
478 { "menu_next_page", MENU_NEXT_PAGE
},
479 { "menu_previous_page", MENU_PREVIOUS_PAGE
},
480 { "menu_select_all", MENU_SELECT_ALL
},
481 /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL
},
482 { "menu_invert_all", MENU_INVERT_ALL
},
483 { "menu_select_page", MENU_SELECT_PAGE
},
484 { "menu_deselect_page", MENU_UNSELECT_PAGE
},
485 { "menu_invert_page", MENU_INVERT_PAGE
},
486 /*10*/ { "menu_search", MENU_SEARCH
},
490 * Allow the user to map incoming characters to various menu commands.
491 * The accelerator list must be a valid C string.
493 #define MAX_MENU_MAPPED_CMDS 32 /* some number */
494 char mapped_menu_cmds
[MAX_MENU_MAPPED_CMDS
+ 1]; /* exported */
495 static char mapped_menu_op
[MAX_MENU_MAPPED_CMDS
+ 1];
496 static short n_menu_mapped
= 0;
498 static boolean initial
, from_file
;
500 STATIC_DCL
void FDECL(nmcpy
, (char *, const char *, int));
501 STATIC_DCL
void FDECL(escapes
, (const char *, char *));
502 STATIC_DCL
void FDECL(rejectoption
, (const char *));
503 STATIC_DCL
void FDECL(badoptmsg
, (const char *, const char *));
504 STATIC_DCL
void FDECL(badoption
, (const char *));
505 STATIC_DCL
char *FDECL(string_for_opt
, (char *, BOOLEAN_P
));
506 STATIC_DCL
char *FDECL(string_for_env_opt
, (const char *, char *, BOOLEAN_P
));
507 STATIC_DCL
void FDECL(bad_negation
, (const char *, BOOLEAN_P
));
508 STATIC_DCL
int FDECL(change_inv_order
, (char *));
509 STATIC_DCL
void FDECL(warning_opts
, (char *, const char *));
510 STATIC_DCL
int FDECL(feature_alert_opts
, (char *, const char *));
511 STATIC_DCL boolean
FDECL(duplicate_opt_detection
, (const char *, int));
512 STATIC_DCL
void FDECL(complain_about_duplicate
, (const char *, int));
514 STATIC_DCL
const char *FDECL(attr2attrname
, (int));
515 STATIC_DCL
int NDECL(query_color
);
516 STATIC_DCL
int FDECL(query_attr
, (const char *));
517 STATIC_DCL
const char * FDECL(msgtype2name
, (int));
518 STATIC_DCL
int NDECL(query_msgtype
);
519 STATIC_DCL boolean
FDECL(msgtype_add
, (int, char *));
520 STATIC_DCL
void FDECL(free_one_msgtype
, (int));
521 STATIC_DCL
int NDECL(msgtype_count
);
522 STATIC_DCL boolean
FDECL(add_menu_coloring_parsed
, (char *, int, int));
523 STATIC_DCL
void FDECL(free_one_menu_coloring
, (int));
524 STATIC_DCL
int NDECL(count_menucolors
);
525 STATIC_DCL boolean
FDECL(parse_role_opts
, (BOOLEAN_P
, const char *,
528 STATIC_DCL
void FDECL(oc_to_str
, (char *, char *));
529 STATIC_DCL
void FDECL(doset_add_menu
, (winid
, const char *, int));
530 STATIC_DCL
void FDECL(opts_add_others
, (winid
, const char *, int,
532 STATIC_DCL
int FDECL(handle_add_list_remove
, (const char *, int));
533 STATIC_DCL boolean
FDECL(special_handling
, (const char *,
534 BOOLEAN_P
, BOOLEAN_P
));
535 STATIC_DCL
const char *FDECL(get_compopt_value
, (const char *, char *));
536 STATIC_DCL
void FDECL(remove_autopickup_exception
,
537 (struct autopickup_exception
*));
538 STATIC_DCL
int FDECL(count_ape_maps
, (int *, int *));
540 STATIC_DCL boolean
FDECL(is_wc_option
, (const char *));
541 STATIC_DCL boolean
FDECL(wc_supported
, (const char *));
542 STATIC_DCL boolean
FDECL(is_wc2_option
, (const char *));
543 STATIC_DCL boolean
FDECL(wc2_supported
, (const char *));
544 STATIC_DCL
void FDECL(wc_set_font_name
, (int, char *));
545 STATIC_DCL
int FDECL(wc_set_window_colors
, (char *));
552 for (x
= 0; x
< COLNO
; x
++)
553 for (y
= 0; y
< ROWNO
; y
++) {
554 struct rm
*lev
= &levl
[x
][y
];
556 if (!flags
.dark_room
|| !iflags
.use_color
557 || Is_rogue_level(&u
.uz
)) {
558 if (lev
->glyph
== cmap_to_glyph(S_darkroom
))
559 lev
->glyph
= lev
->waslit
? cmap_to_glyph(S_room
)
560 : cmap_to_glyph(S_stone
);
562 if (lev
->glyph
== cmap_to_glyph(S_room
) && lev
->seenv
563 && lev
->waslit
&& !cansee(x
, y
))
564 lev
->glyph
= cmap_to_glyph(S_darkroom
);
565 else if (lev
->glyph
== cmap_to_glyph(S_stone
)
566 && lev
->typ
== ROOM
&& lev
->seenv
&& !cansee(x
, y
))
567 lev
->glyph
= cmap_to_glyph(S_darkroom
);
570 if (flags
.dark_room
&& iflags
.use_color
)
571 showsyms
[S_darkroom
] = showsyms
[S_room
];
573 showsyms
[S_darkroom
] = showsyms
[S_stone
];
576 /* check whether a user-supplied option string is a proper leading
577 substring of a particular option name; option string might have
578 a colon or equals sign and arbitrary value appended to it */
580 match_optname(user_string
, opt_name
, min_length
, val_allowed
)
581 const char *user_string
, *opt_name
;
585 int len
= (int) strlen(user_string
);
588 const char *p
= index(user_string
, ':'),
589 *q
= index(user_string
, '=');
591 if (!p
|| (q
&& q
< p
))
594 /* 'user_string' hasn't necessarily been through mungspaces()
595 so might have tabs or consecutive spaces */
596 while (p
> user_string
&& isspace((uchar
) *(p
- 1)))
598 len
= (int) (p
- user_string
);
602 return (boolean
) (len
>= min_length
603 && !strncmpi(opt_name
, user_string
, len
));
606 /* most environment variables will eventually be printed in an error
607 * message if they don't work, and most error message paths go through
608 * BUFSZ buffers, which could be overflowed by a maliciously long
609 * environment variable. If a variable can legitimately be long, or
610 * if it's put in a smaller buffer, the responsible code will have to
611 * bounds-check itself.
617 char *getev
= getenv(ev
);
619 if (getev
&& strlen(getev
) <= (BUFSZ
/ 2))
625 /* process options, possibly including SYSCF */
631 /* someday there may be other SYSCF alternatives besides text file */
633 /* If SYSCF_FILE is specified, it _must_ exist... */
635 /* ... and _must_ parse correctly. */
636 if (!read_config_file(SYSCF_FILE
, SET_IN_SYS
)) {
637 raw_printf("Error(s) found in SYSCF_FILE, quitting.");
638 terminate(EXIT_FAILURE
);
641 * TODO [maybe]: parse the sysopt entries which are space-separated
642 * lists of usernames into arrays with one name per element.
646 initoptions_finish();
652 #if defined(UNIX) || defined(VMS)
657 /* set up the command parsing */
658 reset_commands(TRUE
); /* init */
660 /* initialize the random number generator */
663 /* for detection of configfile options specified multiple times */
664 iflags
.opt_booldup
= iflags
.opt_compdup
= (int *) 0;
666 for (i
= 0; boolopt
[i
].name
; i
++) {
668 *(boolopt
[i
].addr
) = boolopt
[i
].initvalue
;
670 #if defined(COMPRESS) || defined(ZLIB_COMP)
671 set_savepref("externalcomp");
672 set_restpref("externalcomp");
674 set_savepref("!rlecomp");
675 set_restpref("!rlecomp");
679 set_savepref("zerocomp");
680 set_restpref("zerocomp");
683 set_savepref("rlecomp");
684 set_restpref("rlecomp");
688 Strcpy(sysflags
.sysflagsid
, "sysflags");
689 sysflags
.sysflagsid
[9] = (char) sizeof(struct sysflag
);
691 flags
.end_own
= FALSE
;
693 flags
.end_around
= 2;
694 flags
.paranoia_bits
= PARANOID_PRAY
; /* old prayconfirm=TRUE */
695 flags
.pile_limit
= PILE_LIMIT_DFLT
; /* 5 */
696 flags
.runmode
= RUN_LEAP
;
697 iflags
.msg_history
= 20;
699 iflags
.prevmsg_window
= 's';
701 iflags
.menu_headings
= ATR_INVERSE
;
702 iflags
.getpos_coords
= GPCOORDS_NONE
;
704 /* hero's role, race, &c haven't been chosen yet */
705 flags
.initrole
= flags
.initrace
= flags
.initgend
= flags
.initalign
=
708 /* Set the default monster and object class symbols. */
710 for (i
= 0; i
< WARNCOUNT
; i
++)
711 warnsyms
[i
] = def_warnsyms
[i
].sym
;
712 iflags
.bouldersym
= 0;
714 iflags
.travelcc
.x
= iflags
.travelcc
.y
= -1;
716 /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
717 (void) memcpy((genericptr_t
) flags
.inv_order
,
718 (genericptr_t
) def_inv_order
, sizeof flags
.inv_order
);
719 flags
.pickup_types
[0] = '\0';
720 flags
.pickup_burden
= MOD_ENCUMBER
;
721 flags
.sortloot
= 'l'; /* sort only loot by default */
723 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++)
724 flags
.end_disclose
[i
] = DISCLOSE_PROMPT_DEFAULT_NO
;
725 switch_symbols(FALSE
); /* set default characters */
726 #if defined(UNIX) && defined(TTY_GRAPHICS)
728 * Set defaults for some options depending on what we can
729 * detect about the environment's capabilities.
730 * This has to be done after the global initialization above
731 * and before reading user-specific initialization via
732 * config file/environment variable below.
734 /* this detects the IBM-compatible console on most 386 boxes */
735 if ((opts
= nh_getenv("TERM")) && !strncmp(opts
, "AT", 2)) {
736 if (!symset
[PRIMARY
].name
)
737 load_symset("IBMGraphics", PRIMARY
);
738 if (!symset
[ROGUESET
].name
)
739 load_symset("RogueIBM", ROGUESET
);
740 switch_symbols(TRUE
);
742 iflags
.use_color
= TRUE
;
745 #endif /* UNIX && TTY_GRAPHICS */
746 #if defined(UNIX) || defined(VMS)
748 /* detect whether a "vt" terminal can handle alternate charsets */
749 if ((opts
= nh_getenv("TERM"))
750 /* [could also check "xterm" which emulates vtXXX by default] */
751 && !strncmpi(opts
, "vt", 2)
752 && AS
&& AE
&& index(AS
, '\016') && index(AE
, '\017')) {
753 if (!symset
[PRIMARY
].name
)
754 load_symset("DECGraphics", PRIMARY
);
755 switch_symbols(TRUE
);
758 #endif /* UNIX || VMS */
760 #ifdef MAC_GRAPHICS_ENV
761 if (!symset
[PRIMARY
].name
)
762 load_symset("MACGraphics", PRIMARY
);
763 switch_symbols(TRUE
);
764 #endif /* MAC_GRAPHICS_ENV */
765 flags
.menu_style
= MENU_FULL
;
767 /* since this is done before init_objects(), do partial init here */
768 objects
[SLIME_MOLD
].oc_name_idx
= SLIME_MOLD
;
769 nmcpy(pl_fruit
, OBJ_NAME(objects
[SLIME_MOLD
]), PL_FSIZ
);
776 char *opts
= getenv("NETHACKOPTIONS");
779 opts
= getenv("HACKOPTIONS");
781 if (*opts
== '/' || *opts
== '\\' || *opts
== '@') {
783 opts
++; /* @filename */
784 /* looks like a filename */
785 if (strlen(opts
) < BUFSZ
/ 2)
786 read_config_file(opts
, SET_IN_FILE
);
788 read_config_file((char *) 0, SET_IN_FILE
);
789 /* let the total length of options be long;
790 * parseoptions() will check each individually
792 parseoptions(opts
, TRUE
, FALSE
);
796 read_config_file((char *) 0, SET_IN_FILE
);
798 (void) fruitadd(pl_fruit
, (struct fruit
*) 0);
800 * Remove "slime mold" from list of object names. This will
801 * prevent it from being wished unless it's actually present
802 * as a named (or default) fruit. Wishing for "fruit" will
803 * result in the player's preferred fruit [better than "\033"].
805 obj_descr
[SLIME_MOLD
].oc_name
= "fruit";
807 if (iflags
.bouldersym
)
814 nmcpy(dest
, src
, maxlen
)
821 for (count
= 1; count
< maxlen
; count
++) {
822 if (*src
== ',' || *src
== '\0')
823 break; /*exit on \0 terminator*/
830 * escapes(): escape expansion for showsyms. C-style escapes understood
831 * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
832 * The ^-prefix for control characters is also understood, and \[mM]
833 * has the effect of 'meta'-ing the value which follows (so that the
834 * alternate character set will be enabled).
840 * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
841 * prior to terminating '\0' would pull that '\0' into the output and then
842 * keep processing past it, potentially overflowing the output buffer.
843 * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
844 * output and stop there; trailing \M will fall through to \<other> and
845 * yield 'M', then stop. Any \X or \O followed by something other than
846 * an appropriate digit will also fall through to \<other> and yield 'X'
847 * or 'O', plus stop if the non-digit is end-of-string.
854 static NEARDATA
const char oct
[] = "01234567", dec
[] = "0123456789",
855 hex
[] = "00112233445566778899aAbBcCdDeEfF";
857 int cval
, meta
, dcount
;
860 /* \M has to be followed by something to do meta conversion,
861 otherwise it will just be \M which ultimately yields 'M' */
862 meta
= (*cp
== '\\' && (cp
[1] == 'm' || cp
[1] == 'M') && cp
[2]);
866 cval
= dcount
= 0; /* for decimal, octal, hexadecimal cases */
867 if ((*cp
!= '\\' && *cp
!= '^') || !cp
[1]) {
868 /* simple character, or nothing left for \ or ^ to escape */
870 } else if (*cp
== '^') { /* expand control-character syntax */
871 cval
= (*++cp
& 0x1f);
874 /* remaining cases are all for backslash; we know cp[1] is not \0 */
875 } else if (index(dec
, cp
[1])) {
876 ++cp
; /* move past backslash to first digit */
878 cval
= (cval
* 10) + (*cp
- '0');
879 } while (*++cp
&& index(dec
, *cp
) && ++dcount
< 3);
880 } else if ((cp
[1] == 'o' || cp
[1] == 'O') && cp
[2]
881 && index(oct
, cp
[2])) {
882 cp
+= 2; /* move past backslash and 'O' */
884 cval
= (cval
* 8) + (*cp
- '0');
885 } while (*++cp
&& index(oct
, *cp
) && ++dcount
< 3);
886 } else if ((cp
[1] == 'x' || cp
[1] == 'X') && cp
[2]
887 && (dp
= index(hex
, cp
[2])) != 0) {
888 cp
+= 2; /* move past backslash and 'X' */
890 cval
= (cval
* 16) + ((int) (dp
- hex
) / 2);
891 } while (*++cp
&& (dp
= index(hex
, *cp
)) != 0 && ++dcount
< 2);
892 } else { /* C-style character escapes */
923 rejectoption(optname
)
927 pline("\"%s\" settable only from %s.", optname
, configfile
);
929 pline("%s can be set only from NETHACKOPTIONS or %s.", optname
,
935 badoptmsg(opts
, reason
)
937 const char *reason
; /* "Bad syntax" or "Missing value" */
939 const char *linesplit
= "";
942 if (!strncmp(opts
, "h", 1) || !strncmp(opts
, "?", 1))
945 pline("%s: %s. Enter \"?g\" for help.", reason
, opts
);
957 raw_printf("%s in OPTIONS in %s: %s%s.\n",
958 reason
, configfile
, linesplit
, opts
);
960 raw_printf("%s in NETHACKOPTIONS: %s%s.\n",
961 reason
, linesplit
, opts
);
969 badoptmsg(opts
, "Bad syntax");
973 string_for_opt(opts
, val_optional
)
975 boolean val_optional
;
977 char *colon
, *equals
;
979 colon
= index(opts
, ':');
980 equals
= index(opts
, '=');
981 if (!colon
|| (equals
&& equals
< colon
))
984 if (!colon
|| !*++colon
) {
986 badoptmsg(opts
, "Missing value");
993 string_for_env_opt(optname
, opts
, val_optional
)
996 boolean val_optional
;
999 rejectoption(optname
);
1002 return string_for_opt(opts
, val_optional
);
1006 bad_negation(optname
, with_parameter
)
1007 const char *optname
;
1008 boolean with_parameter
;
1010 pline_The("%s option may not %sbe negated.", optname
,
1011 with_parameter
? "both have a value and " : "");
1015 * Change the inventory order, using the given string as the new order.
1016 * Missing characters in the new order are filled in at the end from
1017 * the current inv_order, except for gold, which is forced to be first
1018 * if not explicitly present.
1020 * This routine returns 1 unless there is a duplicate or bad char in
1024 change_inv_order(op
)
1028 char *sp
, buf
[QBUFSZ
];
1031 if (!index(op
, GOLD_SYM
))
1032 buf
[num
++] = COIN_CLASS
;
1034 for (sp
= op
; *sp
; sp
++) {
1035 oc_sym
= def_char_to_objclass(*sp
);
1036 /* reject bad or duplicate entries */
1037 if (oc_sym
== MAXOCLASSES
/* not an object class char */
1038 /* VENOM_CLASS, RANDOM_CLASS, and ILLOBJ_CLASS are excluded
1039 because they aren't in def_inv_order[] so don't make it
1040 into flags.inv_order, hence always fail this index() test */
1041 || !index(flags
.inv_order
, oc_sym
) || index(sp
+ 1, *sp
))
1043 /* retain good ones */
1044 buf
[num
++] = (char) oc_sym
;
1048 /* fill in any omitted classes, using previous ordering */
1049 for (sp
= flags
.inv_order
; *sp
; sp
++)
1050 if (!index(buf
, *sp
))
1051 (void) strkitten(&buf
[num
++], *sp
);
1052 buf
[MAXOCLASSES
- 1] = '\0';
1054 Strcpy(flags
.inv_order
, buf
);
1059 warning_opts(opts
, optype
)
1060 register char *opts
;
1063 uchar translate
[WARNCOUNT
];
1066 if (!(opts
= string_for_env_opt(optype
, opts
, FALSE
)))
1068 escapes(opts
, opts
);
1070 length
= (int) strlen(opts
);
1071 /* match the form obtained from PC configuration files */
1072 for (i
= 0; i
< WARNCOUNT
; i
++)
1073 translate
[i
] = (i
>= length
) ? 0
1074 : opts
[i
] ? (uchar
) opts
[i
]
1075 : def_warnsyms
[i
].sym
;
1076 assign_warnings(translate
);
1080 assign_warnings(graph_chars
)
1081 register uchar
*graph_chars
;
1085 for (i
= 0; i
< WARNCOUNT
; i
++)
1087 warnsyms
[i
] = graph_chars
[i
];
1091 feature_alert_opts(op
, optn
)
1096 boolean rejectver
= FALSE
;
1097 unsigned long fnv
= get_feature_notice_ver(op
); /* version.c */
1101 if (fnv
> get_current_feature_ver())
1104 flags
.suppress_alert
= fnv
;
1107 You_cant("disable new feature alerts for future versions.");
1110 "\n%s=%s Invalid reference to a future version ignored",
1117 Sprintf(buf
, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ
,
1118 FEATURE_NOTICE_VER_MIN
, FEATURE_NOTICE_VER_PATCH
);
1120 "Feature change alerts disabled for NetHack %s features and prior.",
1127 set_duplicate_opt_detection(on_or_off
)
1132 if (on_or_off
!= 0) {
1134 if (iflags
.opt_booldup
)
1135 impossible("iflags.opt_booldup already on (memory leak)");
1136 iflags
.opt_booldup
= (int *) alloc(SIZE(boolopt
) * sizeof(int));
1137 optptr
= iflags
.opt_booldup
;
1138 for (k
= 0; k
< SIZE(boolopt
); ++k
)
1141 if (iflags
.opt_compdup
)
1142 impossible("iflags.opt_compdup already on (memory leak)");
1143 iflags
.opt_compdup
= (int *) alloc(SIZE(compopt
) * sizeof(int));
1144 optptr
= iflags
.opt_compdup
;
1145 for (k
= 0; k
< SIZE(compopt
); ++k
)
1149 if (iflags
.opt_booldup
)
1150 free((genericptr_t
) iflags
.opt_booldup
);
1151 iflags
.opt_booldup
= (int *) 0;
1152 if (iflags
.opt_compdup
)
1153 free((genericptr_t
) iflags
.opt_compdup
);
1154 iflags
.opt_compdup
= (int *) 0;
1159 duplicate_opt_detection(opts
, iscompound
)
1161 int iscompound
; /* 0 == boolean option, 1 == compound */
1165 if (!iscompound
&& iflags
.opt_booldup
&& initial
&& from_file
) {
1166 for (i
= 0; boolopt
[i
].name
; i
++) {
1167 if (match_optname(opts
, boolopt
[i
].name
, 3, FALSE
)) {
1168 optptr
= iflags
.opt_booldup
+ i
;
1176 } else if (iscompound
&& iflags
.opt_compdup
&& initial
&& from_file
) {
1177 for (i
= 0; compopt
[i
].name
; i
++) {
1178 if (match_optname(opts
, compopt
[i
].name
, strlen(compopt
[i
].name
),
1180 optptr
= iflags
.opt_compdup
+ i
;
1193 complain_about_duplicate(opts
, iscompound
)
1195 int iscompound
; /* 0 == boolean option, 1 == compound */
1198 /* the Mac has trouble dealing with the output of messages while
1199 * processing the config file. That should get fixed one day.
1200 * For now just return.
1203 raw_printf("\nWarning - %s option specified multiple times: %s.\n",
1204 iscompound
? "compound" : "boolean", opts
);
1210 /* paranoia[] - used by parseoptions() and special_handling() */
1211 STATIC_VAR
const struct paranoia_opts
{
1212 int flagmask
; /* which paranoid option */
1213 const char *argname
; /* primary name */
1214 int argMinLen
; /* minimum number of letters to match */
1215 const char *synonym
; /* alternate name (optional) */
1217 const char *explain
; /* for interactive menu */
1219 /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
1220 takes precedence and "all" isn't present in the interactive menu,
1221 and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
1222 (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
1223 is just a synonym for "Confirm") */
1224 { PARANOID_CONFIRM
, "Confirm", 1, "Paranoia", 2,
1225 "for \"yes\" confirmations, require \"no\" to reject" },
1226 { PARANOID_QUIT
, "quit", 1, "explore", 1,
1227 "yes vs y to quit or to enter explore mode" },
1228 { PARANOID_DIE
, "die", 1, "death", 2,
1229 "yes vs y to die (explore mode or debug mode)" },
1230 { PARANOID_BONES
, "bones", 1, 0, 0,
1231 "yes vs y to save bones data when dying in debug mode" },
1232 { PARANOID_HIT
, "attack", 1, "hit", 1,
1233 "yes vs y to attack a peaceful monster" },
1234 { PARANOID_PRAY
, "pray", 1, 0, 0,
1235 "y to pray (supersedes old \"prayconfirm\" option)" },
1236 { PARANOID_REMOVE
, "Remove", 1, "Takeoff", 1,
1237 "always pick from inventory for Remove and Takeoff" },
1238 { PARANOID_BREAKWAND
, "wand", 1, "breakwand", 2,
1239 "yes vs y to break a wand" },
1240 /* for config file parsing; interactive menu skips these */
1241 { 0, "none", 4, 0, 0, 0 }, /* require full word match */
1242 { ~0, "all", 3, 0, 0, 0 }, /* ditto */
1245 extern struct menucoloring
*menu_colorings
;
1247 static const struct {
1251 { "black", CLR_BLACK
},
1253 { "green", CLR_GREEN
},
1254 { "brown", CLR_BROWN
},
1255 { "blue", CLR_BLUE
},
1256 { "magenta", CLR_MAGENTA
},
1257 { "cyan", CLR_CYAN
},
1258 { "gray", CLR_GRAY
},
1259 { "orange", CLR_ORANGE
},
1260 { "light green", CLR_BRIGHT_GREEN
},
1261 { "yellow", CLR_YELLOW
},
1262 { "light blue", CLR_BRIGHT_BLUE
},
1263 { "light magenta", CLR_BRIGHT_MAGENTA
},
1264 { "light cyan", CLR_BRIGHT_CYAN
},
1265 { "white", CLR_WHITE
},
1266 { NULL
, CLR_BLACK
}, /* everything after this is an alias */
1267 { "transparent", NO_COLOR
},
1268 { "nocolor", NO_COLOR
},
1269 { "purple", CLR_MAGENTA
},
1270 { "light purple", CLR_BRIGHT_MAGENTA
},
1271 { "bright purple", CLR_BRIGHT_MAGENTA
},
1272 { "grey", CLR_GRAY
},
1273 { "bright red", CLR_ORANGE
},
1274 { "bright green", CLR_BRIGHT_GREEN
},
1275 { "bright blue", CLR_BRIGHT_BLUE
},
1276 { "bright magenta", CLR_BRIGHT_MAGENTA
},
1277 { "bright cyan", CLR_BRIGHT_CYAN
}
1280 static const struct {
1284 { "none", ATR_NONE
},
1285 { "bold", ATR_BOLD
},
1287 { "underline", ATR_ULINE
},
1288 { "blink", ATR_BLINK
},
1289 { "inverse", ATR_INVERSE
}
1298 for (i
= 0; i
< SIZE(colornames
); i
++)
1299 if (colornames
[i
].name
&& colornames
[i
].color
== clr
)
1300 return colornames
[i
].name
;
1308 int i
, c
= NO_COLOR
;
1310 /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
1311 (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
1312 also copes with trailing space; mungspaces removed any leading space */
1313 for (i
= 0; i
< SIZE(colornames
); i
++)
1314 if (colornames
[i
].name
1315 && fuzzymatch(str
, colornames
[i
].name
, " -_", TRUE
)) {
1316 c
= colornames
[i
].color
;
1319 if (i
== SIZE(colornames
) && (*str
>= '0' && *str
<= '9'))
1324 STATIC_OVL
const char *
1330 for (i
= 0; i
< SIZE(attrnames
); i
++)
1331 if (attrnames
[i
].attr
== attr
)
1332 return attrnames
[i
].name
;
1342 menu_item
*picks
= (menu_item
*) 0;
1344 tmpwin
= create_nhwindow(NHW_MENU
);
1347 for (i
= 0; i
< SIZE(colornames
); i
++) {
1348 if (!colornames
[i
].name
)
1351 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, colornames
[i
].name
,
1354 end_menu(tmpwin
, "Pick a color");
1355 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1356 destroy_nhwindow(tmpwin
);
1358 i
= colornames
[picks
->item
.a_int
- 1].color
;
1359 free((genericptr_t
) picks
);
1372 menu_item
*picks
= (menu_item
*) 0;
1374 tmpwin
= create_nhwindow(NHW_MENU
);
1377 for (i
= 0; i
< SIZE(attrnames
); i
++) {
1379 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, attrnames
[i
].attr
,
1380 attrnames
[i
].name
, MENU_UNSELECTED
);
1382 end_menu(tmpwin
, prompt
? prompt
: "Pick an attribute");
1383 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1384 destroy_nhwindow(tmpwin
);
1386 i
= attrnames
[picks
->item
.a_int
- 1].attr
;
1387 free((genericptr_t
) picks
);
1393 static const struct {
1397 } msgtype_names
[] = {
1398 { "show", MSGTYP_NORMAL
, "Show message normally" },
1399 { "hide", MSGTYP_NOSHOW
, "Hide message" },
1400 { "noshow", MSGTYP_NOSHOW
, NULL
},
1401 { "stop", MSGTYP_STOP
, "Prompt for more after the message" },
1402 { "more", MSGTYP_STOP
, NULL
},
1403 { "norep", MSGTYP_NOREP
, "Do not repeat the message" }
1406 STATIC_OVL
const char *
1412 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1413 if (msgtype_names
[i
].descr
&& msgtype_names
[i
].msgtyp
== typ
)
1414 return msgtype_names
[i
].name
;
1424 menu_item
*picks
= (menu_item
*) 0;
1426 tmpwin
= create_nhwindow(NHW_MENU
);
1429 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1430 if (msgtype_names
[i
].descr
) {
1431 any
.a_int
= msgtype_names
[i
].msgtyp
+ 1;
1432 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1433 msgtype_names
[i
].descr
, MENU_UNSELECTED
);
1435 end_menu(tmpwin
, "How to show the message");
1436 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1437 destroy_nhwindow(tmpwin
);
1439 i
= picks
->item
.a_int
- 1;
1440 free((genericptr_t
) picks
);
1447 msgtype_add(typ
, pattern
)
1451 struct plinemsg_type
*tmp
1452 = (struct plinemsg_type
*) alloc(sizeof (struct plinemsg_type
));
1457 tmp
->regex
= regex_init();
1458 if (!regex_compile(pattern
, tmp
->regex
)) {
1459 static const char *re_error
= "MSGTYPE regex error";
1461 if (!iflags
.window_inited
)
1462 raw_printf("\n%s: %s\n", re_error
, regex_error_desc(tmp
->regex
));
1464 pline("%s: %s", re_error
, regex_error_desc(tmp
->regex
));
1466 regex_free(tmp
->regex
);
1467 free((genericptr_t
) tmp
);
1470 tmp
->pattern
= dupstr(pattern
);
1471 tmp
->next
= plinemsg_types
;
1472 plinemsg_types
= tmp
;
1479 struct plinemsg_type
*tmp
, *tmp2
= 0;
1481 for (tmp
= plinemsg_types
; tmp
; tmp
= tmp2
) {
1483 free((genericptr_t
) tmp
->pattern
);
1484 regex_free(tmp
->regex
);
1485 free((genericptr_t
) tmp
);
1487 plinemsg_types
= (struct plinemsg_type
*) 0;
1491 free_one_msgtype(idx
)
1494 struct plinemsg_type
*tmp
= plinemsg_types
;
1495 struct plinemsg_type
*prev
= NULL
;
1499 struct plinemsg_type
*next
= tmp
->next
;
1501 regex_free(tmp
->regex
);
1502 free((genericptr_t
) tmp
->pattern
);
1503 free((genericptr_t
) tmp
);
1507 plinemsg_types
= next
;
1517 msgtype_type(msg
, norepeat
)
1519 boolean norepeat
; /* called from Norep(via pline) */
1521 struct plinemsg_type
*tmp
= plinemsg_types
;
1524 /* we don't exclude entries with negative msgtype values
1525 because then the msg might end up matching a later pattern */
1526 if (regex_match(msg
, tmp
->regex
))
1527 return tmp
->msgtype
;
1530 return norepeat
? MSGTYP_NOREP
: MSGTYP_NORMAL
;
1533 /* negate one or more types of messages so that their type handling will
1534 be disabled or re-enabled; MSGTYPE_NORMAL (value 0) is not affected */
1536 hide_unhide_msgtypes(hide
, hide_mask
)
1540 struct plinemsg_type
*tmp
;
1543 /* negative msgtype value won't be recognized by pline, so does nothing */
1544 for (tmp
= plinemsg_types
; tmp
; tmp
= tmp
->next
) {
1547 mt
= -mt
; /* unhide: negate negative, yielding positive */
1548 if (mt
> 0 && ((1 << mt
) & hide_mask
))
1549 tmp
->msgtype
= -tmp
->msgtype
;
1557 struct plinemsg_type
*tmp
= plinemsg_types
;
1567 msgtype_parse_add(str
)
1573 if (sscanf(str
, "%10s \"%255[^\"]\"", msgtype
, pattern
) == 2) {
1577 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1578 if (!strncmpi(msgtype_names
[i
].name
, msgtype
, strlen(msgtype
))) {
1579 typ
= msgtype_names
[i
].msgtyp
;
1583 return msgtype_add(typ
, pattern
);
1589 add_menu_coloring_parsed(str
, c
, a
)
1593 static const char re_error
[] = "Menucolor regex error";
1594 struct menucoloring
*tmp
;
1598 tmp
= (struct menucoloring
*) alloc(sizeof (struct menucoloring
));
1599 tmp
->match
= regex_init();
1600 if (!regex_compile(str
, tmp
->match
)) {
1601 if (!iflags
.window_inited
)
1602 raw_printf("\n%s: %s\n", re_error
, regex_error_desc(tmp
->match
));
1604 pline("%s: %s", re_error
, regex_error_desc(tmp
->match
));
1606 regex_free(tmp
->match
);
1610 tmp
->next
= menu_colorings
;
1611 tmp
->origstr
= dupstr(str
);
1614 menu_colorings
= tmp
;
1619 /* parse '"regex_string"=color&attr' and add it to menucoloring */
1621 add_menu_coloring(str
)
1624 int i
, c
= NO_COLOR
, a
= ATR_NONE
;
1625 char *tmps
, *cs
, *amp
;
1627 if (!str
|| (cs
= index(str
, '=')) == 0)
1630 tmps
= cs
+ 1; /* advance past '=' */
1632 if ((amp
= index(tmps
, '&')) != 0)
1635 c
= match_str2clr(tmps
);
1640 tmps
= amp
+ 1; /* advance past '&' */
1641 /* unlike colors, none of he attribute names has any embedded spaces,
1642 but use of fuzzymatch() allows us ignore the presence of leading
1643 and/or trailing (and also embedded) spaces in the user's string;
1644 dash and underscore skipping could be omitted but does no harm */
1645 for (i
= 0; i
< SIZE(attrnames
); i
++)
1646 if (fuzzymatch(tmps
, attrnames
[i
].name
, " -_", TRUE
)) {
1647 a
= attrnames
[i
].attr
;
1650 if (i
== SIZE(attrnames
) && (*tmps
>= '0' && *tmps
<= '9'))
1654 /* the regexp portion here has not been condensed by mungspaces() */
1657 if (*tmps
== '"' || *tmps
== '\'') {
1659 while (isspace((uchar
) *cs
))
1667 return add_menu_coloring_parsed(tmps
, c
, a
);
1671 get_menu_coloring(str
, color
, attr
)
1675 struct menucoloring
*tmpmc
;
1677 if (iflags
.use_menu_color
)
1678 for (tmpmc
= menu_colorings
; tmpmc
; tmpmc
= tmpmc
->next
)
1679 if (regex_match(str
, tmpmc
->match
)) {
1680 *color
= tmpmc
->color
;
1681 *attr
= tmpmc
->attr
;
1688 free_menu_coloring()
1690 struct menucoloring
*tmp
= menu_colorings
;
1693 struct menucoloring
*tmp2
= tmp
->next
;
1695 regex_free(tmp
->match
);
1696 free((genericptr_t
) tmp
->origstr
);
1697 free((genericptr_t
) tmp
);
1703 free_one_menu_coloring(idx
)
1706 struct menucoloring
*tmp
= menu_colorings
;
1707 struct menucoloring
*prev
= NULL
;
1711 struct menucoloring
*next
= tmp
->next
;
1713 regex_free(tmp
->match
);
1714 free((genericptr_t
) tmp
->origstr
);
1715 free((genericptr_t
) tmp
);
1719 menu_colorings
= next
;
1732 struct menucoloring
*tmp
= menu_colorings
;
1742 parse_role_opts(negated
, fullname
, opts
, opp
)
1744 const char *fullname
;
1751 bad_negation(fullname
, FALSE
);
1752 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
1753 boolean val_negated
= FALSE
;
1755 while ((*op
== '!') || !strncmpi(op
, "no", 2)) {
1760 val_negated
= !val_negated
;
1763 if (!setrolefilter(op
))
1766 if (duplicate_opt_detection(opts
, 1))
1767 complain_about_duplicate(opts
, 1);
1775 /* Check if character c is illegal as a menu command key */
1777 illegal_menu_cmd_key(c
)
1780 if (c
== 0 || c
== '\r' || c
== '\n' || c
== '\033'
1781 || c
== ' ' || digit(c
) || (letter(c
) && c
!= '@'))
1783 else { /* reject default object class symbols */
1785 for (j
= 1; j
< MAXOCLASSES
; j
++)
1786 if (c
== def_oc_syms
[j
].sym
)
1793 parseoptions(opts
, tinitial
, tfrom_file
)
1794 register char *opts
;
1795 boolean tinitial
, tfrom_file
;
1799 boolean negated
, duplicate
;
1801 const char *fullname
;
1804 from_file
= tfrom_file
;
1805 if ((op
= index(opts
, ',')) != 0) {
1807 parseoptions(op
, initial
, from_file
);
1809 if (strlen(opts
) > BUFSZ
/ 2) {
1810 badoption("option too long");
1814 /* strip leading and trailing white space */
1815 while (isspace((uchar
) *opts
))
1818 while (--op
>= opts
&& isspace((uchar
) *op
))
1824 while ((*opts
== '!') || !strncmpi(opts
, "no", 2)) {
1832 /* variant spelling */
1834 if (match_optname(opts
, "colour", 5, FALSE
))
1835 Strcpy(opts
, "color"); /* fortunately this isn't longer */
1837 /* special boolean options */
1839 if (match_optname(opts
, "female", 3, FALSE
)) {
1840 if (duplicate_opt_detection(opts
, 0))
1841 complain_about_duplicate(opts
, 0);
1842 if (!initial
&& flags
.female
== negated
)
1843 pline("That is not anatomically possible.");
1845 flags
.initgend
= flags
.female
= !negated
;
1849 if (match_optname(opts
, "male", 4, FALSE
)) {
1850 if (duplicate_opt_detection(opts
, 0))
1851 complain_about_duplicate(opts
, 0);
1852 if (!initial
&& flags
.female
!= negated
)
1853 pline("That is not anatomically possible.");
1855 flags
.initgend
= flags
.female
= negated
;
1859 #if defined(MICRO) && !defined(AMIGA)
1860 /* included for compatibility with old NetHack.cnf files */
1861 if (match_optname(opts
, "IBM_", 4, FALSE
)) {
1862 iflags
.BIOS
= !negated
;
1867 /* compound options */
1869 /* This first batch can be duplicated if their values are negated */
1873 if (match_optname(opts
, fullname
, sizeof("align") - 1, TRUE
)) {
1874 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1875 if ((flags
.initalign
= str2align(op
)) == ROLE_NONE
)
1881 /* role:string or character:string */
1883 if (match_optname(opts
, fullname
, 4, TRUE
)
1884 || match_optname(opts
, (fullname
= "character"), 4, TRUE
)) {
1885 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1886 if ((flags
.initrole
= str2role(op
)) == ROLE_NONE
)
1888 else /* Backwards compatibility */
1889 nmcpy(pl_character
, op
, PL_NSIZ
);
1896 if (match_optname(opts
, fullname
, 4, TRUE
)) {
1897 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1898 if ((flags
.initrace
= str2race(op
)) == ROLE_NONE
)
1900 else /* Backwards compatibility */
1907 fullname
= "gender";
1908 if (match_optname(opts
, fullname
, 4, TRUE
)) {
1909 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1910 if ((flags
.initgend
= str2gend(op
)) == ROLE_NONE
)
1913 flags
.female
= flags
.initgend
;
1918 /* We always check for duplicates on the remaining compound options,
1919 although individual option processing can choose to complain or not */
1922 duplicate_opt_detection(opts
, 1); /* 1 means check compounds */
1924 fullname
= "pettype";
1925 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1927 complain_about_duplicate(opts
, 1);
1928 if ((op
= string_for_env_opt(fullname
, opts
, negated
)) != 0) {
1930 bad_negation(fullname
, TRUE
);
1932 switch (lowc(*op
)) {
1934 preferred_pet
= 'd';
1937 case 'f': /* feline */
1938 preferred_pet
= 'c';
1940 case 'h': /* horse */
1941 case 'q': /* quadruped */
1942 /* avoids giving "unrecognized type of pet" but
1943 pet_type(dog.c) won't actually honor this */
1944 preferred_pet
= 'h';
1946 case 'n': /* no pet */
1947 preferred_pet
= 'n';
1949 case '*': /* random */
1950 preferred_pet
= '\0';
1953 pline("Unrecognized pet type '%s'.", op
);
1957 preferred_pet
= 'n';
1961 fullname
= "catname";
1962 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1964 complain_about_duplicate(opts
, 1);
1966 bad_negation(fullname
, FALSE
);
1967 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1968 nmcpy(catname
, op
, PL_PSIZ
);
1969 sanitize_name(catname
);
1973 fullname
= "dogname";
1974 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1976 complain_about_duplicate(opts
, 1);
1978 bad_negation(fullname
, FALSE
);
1979 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1980 nmcpy(dogname
, op
, PL_PSIZ
);
1981 sanitize_name(dogname
);
1985 fullname
= "horsename";
1986 if (match_optname(opts
, fullname
, 5, TRUE
)) {
1988 complain_about_duplicate(opts
, 1);
1990 bad_negation(fullname
, FALSE
);
1991 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1992 nmcpy(horsename
, op
, PL_PSIZ
);
1993 sanitize_name(horsename
);
1997 fullname
= "number_pad";
1998 if (match_optname(opts
, fullname
, 10, TRUE
)) {
1999 boolean compat
= (strlen(opts
) <= 10);
2002 complain_about_duplicate(opts
, 1);
2003 op
= string_for_opt(opts
, (compat
|| !initial
));
2005 if (compat
|| negated
|| initial
) {
2006 /* for backwards compatibility, "number_pad" without a
2007 value is a synonym for number_pad:1 */
2008 iflags
.num_pad
= !negated
;
2009 iflags
.num_pad_mode
= 0;
2011 } else if (negated
) {
2012 bad_negation("number_pad", TRUE
);
2015 int mode
= atoi(op
);
2017 if (mode
< -1 || mode
> 4 || (mode
== 0 && *op
!= '0')) {
2020 } else if (mode
<= 0) {
2021 iflags
.num_pad
= FALSE
;
2022 /* German keyboard; y and z keys swapped */
2023 iflags
.num_pad_mode
= (mode
< 0); /* 0 or 1 */
2024 } else { /* mode > 0 */
2025 iflags
.num_pad
= TRUE
;
2026 iflags
.num_pad_mode
= 0;
2027 /* PC Hack / MSDOS compatibility */
2028 if (mode
== 2 || mode
== 4)
2029 iflags
.num_pad_mode
|= 1;
2030 /* phone keypad layout */
2031 if (mode
== 3 || mode
== 4)
2032 iflags
.num_pad_mode
|= 2;
2035 reset_commands(FALSE
);
2036 number_pad(iflags
.num_pad
? 1 : 0);
2040 fullname
= "roguesymset";
2041 if (match_optname(opts
, fullname
, 7, TRUE
)) {
2043 complain_about_duplicate(opts
, 1);
2045 bad_negation(fullname
, FALSE
);
2046 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2047 symset
[ROGUESET
].name
= dupstr(op
);
2048 if (!read_sym_file(ROGUESET
)) {
2049 clear_symsetentry(ROGUESET
, TRUE
);
2050 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2054 if (!initial
&& Is_rogue_level(&u
.uz
))
2055 assign_graphics(ROGUESET
);
2062 fullname
= "symset";
2063 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2065 complain_about_duplicate(opts
, 1);
2067 bad_negation(fullname
, FALSE
);
2068 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2069 symset
[PRIMARY
].name
= dupstr(op
);
2070 if (!read_sym_file(PRIMARY
)) {
2071 clear_symsetentry(PRIMARY
, TRUE
);
2072 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2076 switch_symbols(symset
[PRIMARY
].name
!= (char *) 0);
2083 fullname
= "runmode";
2084 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2086 complain_about_duplicate(opts
, 1);
2088 flags
.runmode
= RUN_TPORT
;
2089 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2090 if (!strncmpi(op
, "teleport", strlen(op
)))
2091 flags
.runmode
= RUN_TPORT
;
2092 else if (!strncmpi(op
, "run", strlen(op
)))
2093 flags
.runmode
= RUN_LEAP
;
2094 else if (!strncmpi(op
, "walk", strlen(op
)))
2095 flags
.runmode
= RUN_STEP
;
2096 else if (!strncmpi(op
, "crawl", strlen(op
)))
2097 flags
.runmode
= RUN_CRAWL
;
2104 /* menucolor:"regex_string"=color */
2105 fullname
= "menucolor";
2106 if (match_optname(opts
, fullname
, 9, TRUE
)) {
2108 bad_negation(fullname
, FALSE
);
2109 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
2110 if (!add_menu_coloring(op
))
2115 fullname
= "msghistory";
2116 if (match_optname(opts
, fullname
, 3, TRUE
)) {
2118 complain_about_duplicate(opts
, 1);
2119 op
= string_for_env_opt(fullname
, opts
, negated
);
2120 if ((negated
&& !op
) || (!negated
&& op
)) {
2121 iflags
.msg_history
= negated
? 0 : atoi(op
);
2123 bad_negation(fullname
, TRUE
);
2127 fullname
= "msg_window";
2128 /* msg_window:single, combo, full or reversed */
2129 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2130 /* allow option to be silently ignored by non-tty ports */
2135 complain_about_duplicate(opts
, 1);
2136 if (!(op
= string_for_opt(opts
, TRUE
))) {
2137 tmp
= negated
? 's' : 'f';
2140 bad_negation(fullname
, TRUE
);
2146 case 's': /* single message history cycle (default if negated) */
2147 iflags
.prevmsg_window
= 's';
2149 case 'c': /* combination: two singles, then full page reversed */
2150 iflags
.prevmsg_window
= 'c';
2152 case 'f': /* full page (default if no opts) */
2153 iflags
.prevmsg_window
= 'f';
2155 case 'r': /* full page (reversed) */
2156 iflags
.prevmsg_window
= 'r';
2166 * setting font options */
2168 if (!strncmpi(opts
, fullname
, 4)) {
2170 char *fontopts
= opts
+ 4;
2172 if (!strncmpi(fontopts
, "map", 3) || !strncmpi(fontopts
, "_map", 4))
2173 opttype
= MAP_OPTION
;
2174 else if (!strncmpi(fontopts
, "message", 7)
2175 || !strncmpi(fontopts
, "_message", 8))
2176 opttype
= MESSAGE_OPTION
;
2177 else if (!strncmpi(fontopts
, "text", 4)
2178 || !strncmpi(fontopts
, "_text", 5))
2179 opttype
= TEXT_OPTION
;
2180 else if (!strncmpi(fontopts
, "menu", 4)
2181 || !strncmpi(fontopts
, "_menu", 5))
2182 opttype
= MENU_OPTION
;
2183 else if (!strncmpi(fontopts
, "status", 6)
2184 || !strncmpi(fontopts
, "_status", 7))
2185 opttype
= STATUS_OPTION
;
2186 else if (!strncmpi(fontopts
, "_size", 5)) {
2187 if (!strncmpi(fontopts
, "_size_map", 8))
2188 opttype
= MAP_OPTION
;
2189 else if (!strncmpi(fontopts
, "_size_message", 12))
2190 opttype
= MESSAGE_OPTION
;
2191 else if (!strncmpi(fontopts
, "_size_text", 9))
2192 opttype
= TEXT_OPTION
;
2193 else if (!strncmpi(fontopts
, "_size_menu", 9))
2194 opttype
= MENU_OPTION
;
2195 else if (!strncmpi(fontopts
, "_size_status", 11))
2196 opttype
= STATUS_OPTION
;
2202 complain_about_duplicate(opts
, 1);
2203 if (opttype
> 0 && !negated
2204 && (op
= string_for_opt(opts
, FALSE
)) != 0) {
2207 iflags
.wc_fontsiz_map
= atoi(op
);
2209 case MESSAGE_OPTION
:
2210 iflags
.wc_fontsiz_message
= atoi(op
);
2213 iflags
.wc_fontsiz_text
= atoi(op
);
2216 iflags
.wc_fontsiz_menu
= atoi(op
);
2219 iflags
.wc_fontsiz_status
= atoi(op
);
2227 if (opttype
> 0 && (op
= string_for_opt(opts
, FALSE
)) != 0) {
2228 wc_set_font_name(opttype
, op
);
2230 set_font_name(opttype
, op
);
2234 bad_negation(fullname
, TRUE
);
2239 if (match_optname(opts
, "palette", 3, TRUE
)
2241 || match_optname(opts
, "hicolor", 3, TRUE
)
2244 int color_number
, color_incr
;
2248 complain_about_duplicate(opts
, 1);
2251 if (match_optname(opts
, "hicolor", 3, TRUE
)) {
2253 bad_negation("hicolor", FALSE
);
2256 color_number
= CLR_MAX
+ 4; /* HARDCODED inverse number */
2262 bad_negation("palette", FALSE
);
2269 op
= string_for_opt(opts
, TRUE
);
2270 if (!alternative_palette(op
))
2273 if ((op
= string_for_opt(opts
, FALSE
)) != (char *) 0) {
2275 int cnt
, tmp
, reverse
;
2278 while (*pt
&& color_number
>= 0) {
2288 if (*pt
&& *pt
!= '/') {
2295 if (isalpha((uchar
) tmp
)) {
2296 tmp
= (tmp
+ 9) & 0xf; /* Assumes ASCII... */
2298 tmp
&= 0xf; /* Digits in ASCII too... */
2301 /* Add an extra so we fill f -> ff and 0 -> 00 */
2309 change_color(color_number
, rgb
, reverse
);
2310 color_number
+= color_incr
;
2319 #endif /* CHANGE_COLOR */
2321 if (match_optname(opts
, "fruit", 2, TRUE
)) {
2322 struct fruit
*forig
= 0;
2323 char empty_str
= '\0';
2326 complain_about_duplicate(opts
, 1);
2327 op
= string_for_opt(opts
, negated
);
2330 bad_negation("fruit", TRUE
);
2342 for (f
= ffruit
; f
; f
= f
->nextf
) {
2343 if (!strcmp(op
, f
->fname
))
2347 if (!flags
.made_fruit
) {
2348 for (forig
= ffruit
; forig
; forig
= forig
->nextf
) {
2349 if (!strcmp(pl_fruit
, forig
->fname
)) {
2354 if (!forig
&& num
>= 100) {
2355 pline("Doing that so many times isn't very fruitful.");
2360 nmcpy(pl_fruit
, op
, PL_FSIZ
);
2361 sanitize_name(pl_fruit
);
2362 /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
2364 nmcpy(pl_fruit
, "slime mold", PL_FSIZ
);
2366 (void) fruitadd(pl_fruit
, forig
);
2367 pline("Fruit is now \"%s\".", pl_fruit
);
2369 /* If initial, then initoptions is allowed to do it instead
2370 * of here (initoptions always has to do it even if there's
2371 * no fruit option at all. Also, we don't want people
2372 * setting multiple fruits in their options.)
2377 fullname
= "whatis_coord";
2378 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2380 complain_about_duplicate(opts
, 1);
2382 iflags
.getpos_coords
= GPCOORDS_NONE
;
2384 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
2385 static char gpcoords
[] = { GPCOORDS_NONE
, GPCOORDS_COMPASS
,
2386 GPCOORDS_COMFULL
, GPCOORDS_MAP
,
2387 GPCOORDS_SCREEN
, '\0' };
2390 if (c
&& index(gpcoords
, c
))
2391 iflags
.getpos_coords
= c
;
2398 fullname
= "warnings";
2399 if (match_optname(opts
, fullname
, 5, TRUE
)) {
2401 complain_about_duplicate(opts
, 1);
2403 bad_negation(fullname
, FALSE
);
2405 warning_opts(opts
, fullname
);
2409 #ifdef BACKWARD_COMPAT
2410 /* boulder:symbol */
2411 fullname
= "boulder";
2412 if (match_optname(opts
, fullname
, 7, TRUE
)) {
2415 complain_about_duplicate(opts
, 1);
2417 bad_negation(fullname
, FALSE
);
2420 /* if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
2422 if (!(opts
= string_for_opt(opts
, FALSE
)))
2424 escapes(opts
, opts
);
2425 if (def_char_to_monclass(opts
[0]) != MAXMCLASSES
)
2427 else if (opts
[0] >= '1' && opts
[0] <= '5')
2430 /* symbol chosen matches a used monster or warning
2431 symbol which is not good - reject it*/
2433 "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
2434 opts
[0], (clash
== 1) ? "monster" : "warning");
2437 * Override the default boulder symbol.
2439 iflags
.bouldersym
= (uchar
) opts
[0];
2449 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2451 complain_about_duplicate(opts
, 1);
2453 bad_negation(fullname
, FALSE
);
2454 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
2455 nmcpy(plname
, op
, PL_NSIZ
);
2459 /* altkeyhandler:string */
2460 fullname
= "altkeyhandler";
2461 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2463 complain_about_duplicate(opts
, 1);
2465 bad_negation(fullname
, FALSE
);
2466 } else if ((op
= string_for_opt(opts
, negated
)) != 0) {
2468 (void) strncpy(iflags
.altkeyhandler
, op
, MAX_ALTKEYHANDLER
- 5);
2469 load_keyboard_handler();
2476 * align_status:[left|top|right|bottom] */
2477 fullname
= "align_status";
2478 if (match_optname(opts
, fullname
, sizeof("align_status") - 1, TRUE
)) {
2479 op
= string_for_opt(opts
, negated
);
2480 if (op
&& !negated
) {
2481 if (!strncmpi(op
, "left", sizeof("left") - 1))
2482 iflags
.wc_align_status
= ALIGN_LEFT
;
2483 else if (!strncmpi(op
, "top", sizeof("top") - 1))
2484 iflags
.wc_align_status
= ALIGN_TOP
;
2485 else if (!strncmpi(op
, "right", sizeof("right") - 1))
2486 iflags
.wc_align_status
= ALIGN_RIGHT
;
2487 else if (!strncmpi(op
, "bottom", sizeof("bottom") - 1))
2488 iflags
.wc_align_status
= ALIGN_BOTTOM
;
2492 bad_negation(fullname
, TRUE
);
2496 * align_message:[left|top|right|bottom] */
2497 fullname
= "align_message";
2498 if (match_optname(opts
, fullname
, sizeof("align_message") - 1, TRUE
)) {
2500 complain_about_duplicate(opts
, 1);
2501 op
= string_for_opt(opts
, negated
);
2502 if (op
&& !negated
) {
2503 if (!strncmpi(op
, "left", sizeof("left") - 1))
2504 iflags
.wc_align_message
= ALIGN_LEFT
;
2505 else if (!strncmpi(op
, "top", sizeof("top") - 1))
2506 iflags
.wc_align_message
= ALIGN_TOP
;
2507 else if (!strncmpi(op
, "right", sizeof("right") - 1))
2508 iflags
.wc_align_message
= ALIGN_RIGHT
;
2509 else if (!strncmpi(op
, "bottom", sizeof("bottom") - 1))
2510 iflags
.wc_align_message
= ALIGN_BOTTOM
;
2514 bad_negation(fullname
, TRUE
);
2517 /* the order to list the pack */
2518 fullname
= "packorder";
2519 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2521 complain_about_duplicate(opts
, 1);
2523 bad_negation(fullname
, FALSE
);
2525 } else if (!(op
= string_for_opt(opts
, FALSE
)))
2528 if (!change_inv_order(op
))
2533 /* user can change required response for some prompts (quit, die, hit),
2534 or add an extra prompt (pray, Remove) that isn't ordinarily there */
2535 fullname
= "paranoid_confirmation";
2536 if (match_optname(opts
, fullname
, 8, TRUE
)) {
2537 /* at present we don't complain about duplicates for this
2538 option, but we do throw away the old settings whenever
2539 we process a new one [clearing old flags is essential
2540 for handling default paranoid_confirm:pray sanely] */
2541 flags
.paranoia_bits
= 0; /* clear all */
2543 flags
.paranoia_bits
= 0; /* [now redundant...] */
2544 } else if ((op
= string_for_opt(opts
, TRUE
)) != 0) {
2545 char *pp
, buf
[BUFSZ
];
2547 strncpy(buf
, op
, sizeof buf
- 1);
2548 buf
[sizeof buf
- 1] = '\0';
2549 op
= mungspaces(buf
);
2551 /* We're looking to parse
2552 "paranoid_confirm:whichone wheretwo whothree"
2553 and "paranoid_confirm:" prefix has already
2554 been stripped off by the time we get here */
2555 pp
= index(op
, ' ');
2558 /* we aren't matching option names but match_optname
2559 does what we want once we've broken the space
2560 delimited aggregate into separate tokens */
2561 for (i
= 0; i
< SIZE(paranoia
); ++i
) {
2562 if (match_optname(op
, paranoia
[i
].argname
,
2563 paranoia
[i
].argMinLen
, FALSE
)
2564 || (paranoia
[i
].synonym
2565 && match_optname(op
, paranoia
[i
].synonym
,
2566 paranoia
[i
].synMinLen
, FALSE
))) {
2567 if (paranoia
[i
].flagmask
)
2568 flags
.paranoia_bits
|= paranoia
[i
].flagmask
;
2569 else /* 0 == "none", so clear all */
2570 flags
.paranoia_bits
= 0;
2574 if (i
== SIZE(paranoia
)) {
2575 /* didn't match anything, so arg is bad;
2576 any flags already set will stay set */
2580 /* move on to next token */
2584 break; /* no next token */
2590 /* accept deprecated boolean; superseded by paranoid_confirm:pray */
2591 fullname
= "prayconfirm";
2592 if (match_optname(opts
, fullname
, 4, FALSE
)) {
2594 flags
.paranoia_bits
&= ~PARANOID_PRAY
;
2596 flags
.paranoia_bits
|= PARANOID_PRAY
;
2600 /* maximum burden picked up before prompt (Warren Cheung) */
2601 fullname
= "pickup_burden";
2602 if (match_optname(opts
, fullname
, 8, TRUE
)) {
2604 complain_about_duplicate(opts
, 1);
2606 bad_negation(fullname
, FALSE
);
2608 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
2609 switch (lowc(*op
)) {
2610 case 'u': /* Unencumbered */
2611 flags
.pickup_burden
= UNENCUMBERED
;
2613 case 'b': /* Burdened (slight encumbrance) */
2614 flags
.pickup_burden
= SLT_ENCUMBER
;
2616 case 's': /* streSsed (moderate encumbrance) */
2617 flags
.pickup_burden
= MOD_ENCUMBER
;
2619 case 'n': /* straiNed (heavy encumbrance) */
2620 flags
.pickup_burden
= HVY_ENCUMBER
;
2622 case 'o': /* OverTaxed (extreme encumbrance) */
2624 flags
.pickup_burden
= EXT_ENCUMBER
;
2626 case 'l': /* overLoaded */
2627 flags
.pickup_burden
= OVERLOADED
;
2636 /* types of objects to pick up automatically */
2637 if (match_optname(opts
, "pickup_types", 8, TRUE
)) {
2638 char ocl
[MAXOCLASSES
+ 1], tbuf
[MAXOCLASSES
+ 1], qbuf
[QBUFSZ
],
2641 boolean badopt
= FALSE
, compat
= (strlen(opts
) <= 6), use_menu
;
2644 complain_about_duplicate(opts
, 1);
2645 oc_to_str(flags
.pickup_types
, tbuf
);
2646 flags
.pickup_types
[0] = '\0'; /* all */
2647 op
= string_for_opt(opts
, (compat
|| !initial
));
2649 if (compat
|| negated
|| initial
) {
2650 /* for backwards compatibility, "pickup" without a
2651 value is a synonym for autopickup of all types
2652 (and during initialization, we can't prompt yet) */
2653 flags
.pickup
= !negated
;
2656 oc_to_str(flags
.inv_order
, ocl
);
2658 if (flags
.menu_style
== MENU_TRADITIONAL
2659 || flags
.menu_style
== MENU_COMBINATION
) {
2661 Sprintf(qbuf
, "New pickup_types: [%s am] (%s)", ocl
,
2662 *tbuf
? tbuf
: "all");
2664 op
= mungspaces(abuf
);
2665 if (abuf
[0] == '\0' || abuf
[0] == '\033')
2666 op
= tbuf
; /* restore */
2667 else if (abuf
[0] == 'm')
2671 (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE
, ocl
,
2677 bad_negation("pickup_types", TRUE
);
2682 if (*op
!= 'a' && *op
!= 'A') {
2685 oc_sym
= def_char_to_objclass(*op
);
2686 /* make sure all are valid obj symbols occurring once */
2687 if (oc_sym
!= MAXOCLASSES
2688 && !index(flags
.pickup_types
, oc_sym
)) {
2689 flags
.pickup_types
[num
] = (char) oc_sym
;
2690 flags
.pickup_types
[++num
] = '\0';
2701 /* pile limit: when walking over objects, number which triggers
2702 "there are several/many objects here" instead of listing them */
2703 fullname
= "pile_limit";
2704 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2706 complain_about_duplicate(opts
, 1);
2707 op
= string_for_opt(opts
, negated
);
2708 if ((negated
&& !op
) || (!negated
&& op
))
2709 flags
.pile_limit
= negated
? 0 : atoi(op
);
2711 bad_negation(fullname
, TRUE
);
2713 flags
.pile_limit
= PILE_LIMIT_DFLT
;
2715 if (flags
.pile_limit
< 0)
2716 flags
.pile_limit
= PILE_LIMIT_DFLT
;
2720 /* play mode: normal, explore/discovery, or debug/wizard */
2721 fullname
= "playmode";
2722 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2724 complain_about_duplicate(opts
, 1);
2726 bad_negation(fullname
, FALSE
);
2727 if (duplicate
|| negated
)
2729 op
= string_for_opt(opts
, FALSE
);
2732 if (!strncmpi(op
, "normal", 6) || !strcmpi(op
, "play")) {
2733 wizard
= discover
= FALSE
;
2734 } else if (!strncmpi(op
, "explore", 6)
2735 || !strncmpi(op
, "discovery", 6)) {
2736 wizard
= FALSE
, discover
= TRUE
;
2737 } else if (!strncmpi(op
, "debug", 5) || !strncmpi(op
, "wizard", 6)) {
2738 wizard
= TRUE
, discover
= FALSE
;
2740 raw_printf("Invalid value for \"%s\":%s.", fullname
, op
);
2746 * player_selection: dialog | prompts */
2747 fullname
= "player_selection";
2748 if (match_optname(opts
, fullname
, sizeof("player_selection") - 1, TRUE
)) {
2750 complain_about_duplicate(opts
, 1);
2751 op
= string_for_opt(opts
, negated
);
2752 if (op
&& !negated
) {
2753 if (!strncmpi(op
, "dialog", sizeof("dialog") - 1))
2754 iflags
.wc_player_selection
= VIA_DIALOG
;
2755 else if (!strncmpi(op
, "prompt", sizeof("prompt") - 1))
2756 iflags
.wc_player_selection
= VIA_PROMPTS
;
2760 bad_negation(fullname
, TRUE
);
2764 /* things to disclose at end of game */
2765 if (match_optname(opts
, "disclose", 7, TRUE
)) {
2767 * The order that the end_disclose options are stored:
2768 * inventory, attribs, vanquished, genocided,
2769 * conduct, overview.
2770 * There is an array in flags:
2771 * end_disclose[NUM_DISCLOSURE_OPT];
2772 * with option settings for the each of the following:
2773 * iagvc [see disclosure_options in decl.c]:
2774 * Legal setting values in that array are:
2775 * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
2776 * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
2777 * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
2778 * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
2780 * Those setting values can be used in the option
2781 * string as a prefix to get the desired behaviour.
2783 * For backward compatibility, no prefix is required,
2784 * and the presence of a i,a,g,v, or c without a prefix
2785 * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
2787 boolean badopt
= FALSE
;
2788 int idx
, prefix_val
;
2791 complain_about_duplicate(opts
, 1);
2792 op
= string_for_opt(opts
, TRUE
);
2793 if (op
&& negated
) {
2794 bad_negation("disclose", TRUE
);
2797 /* "disclose" without a value means "all with prompting"
2798 and negated means "none without prompting" */
2799 if (!op
|| !strcmpi(op
, "all") || !strcmpi(op
, "none")) {
2800 if (op
&& !strcmpi(op
, "none"))
2802 for (num
= 0; num
< NUM_DISCLOSURE_OPTIONS
; num
++)
2803 flags
.end_disclose
[num
] = negated
2804 ? DISCLOSE_NO_WITHOUT_PROMPT
2805 : DISCLOSE_PROMPT_DEFAULT_YES
;
2811 while (*op
&& num
< sizeof flags
.end_disclose
- 1) {
2812 static char valid_settings
[] = {
2813 DISCLOSE_PROMPT_DEFAULT_YES
, DISCLOSE_PROMPT_DEFAULT_NO
,
2814 DISCLOSE_PROMPT_DEFAULT_SPECIAL
,
2815 DISCLOSE_YES_WITHOUT_PROMPT
, DISCLOSE_NO_WITHOUT_PROMPT
,
2816 DISCLOSE_SPECIAL_WITHOUT_PROMPT
, '\0'
2818 register char c
, *dop
;
2822 c
= 'v'; /* killed -> vanquished */
2824 c
= 'o'; /* dungeon -> overview */
2825 dop
= index(disclosure_options
, c
);
2827 idx
= (int) (dop
- disclosure_options
);
2828 if (idx
< 0 || idx
> NUM_DISCLOSURE_OPTIONS
- 1) {
2829 impossible("bad disclosure index %d %c", idx
, c
);
2832 if (prefix_val
!= -1) {
2834 if (prefix_val
== DISCLOSE_PROMPT_DEFAULT_SPECIAL
)
2835 prefix_val
= DISCLOSE_PROMPT_DEFAULT_YES
;
2836 if (prefix_val
== DISCLOSE_SPECIAL_WITHOUT_PROMPT
)
2837 prefix_val
= DISCLOSE_YES_WITHOUT_PROMPT
;
2839 flags
.end_disclose
[idx
] = prefix_val
;
2842 flags
.end_disclose
[idx
] = DISCLOSE_YES_WITHOUT_PROMPT
;
2843 } else if (index(valid_settings
, c
)) {
2845 } else if (c
== ' ') {
2856 /* scores:5t[op] 5a[round] o[wn] */
2857 if (match_optname(opts
, "scores", 4, TRUE
)) {
2859 complain_about_duplicate(opts
, 1);
2861 bad_negation("scores", FALSE
);
2864 if (!(op
= string_for_opt(opts
, FALSE
)))
2874 } else if (*op
== '!') {
2884 flags
.end_top
= inum
;
2888 flags
.end_around
= inum
;
2892 flags
.end_own
= !negated
;
2898 while (letter(*++op
) || *op
== ' ')
2906 fullname
= "sortloot";
2907 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2908 op
= string_for_env_opt(fullname
, opts
, FALSE
);
2913 case 'n': /* none */
2914 case 'l': /* loot (pickup) */
2915 case 'f': /* full (pickup + invent) */
2926 fullname
= "suppress_alert";
2927 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2929 complain_about_duplicate(opts
, 1);
2930 op
= string_for_opt(opts
, negated
);
2932 bad_negation(fullname
, FALSE
);
2934 (void) feature_alert_opts(op
, fullname
);
2939 /* videocolors:string */
2940 fullname
= "videocolors";
2941 if (match_optname(opts
, fullname
, 6, TRUE
)
2942 || match_optname(opts
, "videocolours", 10, TRUE
)) {
2944 complain_about_duplicate(opts
, 1);
2946 bad_negation(fullname
, FALSE
);
2948 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2951 if (!assign_videocolors(opts
))
2955 /* videoshades:string */
2956 fullname
= "videoshades";
2957 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2959 complain_about_duplicate(opts
, 1);
2961 bad_negation(fullname
, FALSE
);
2963 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2966 if (!assign_videoshades(opts
))
2970 #endif /* VIDEOSHADES */
2973 /* video:string -- must be after longer tests */
2975 if (match_optname(opts
, fullname
, 5, TRUE
)) {
2977 complain_about_duplicate(opts
, 1);
2979 bad_negation(fullname
, FALSE
);
2981 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2984 if (!assign_video(opts
))
2988 #endif /* NO_TERMS */
2989 /* soundcard:string -- careful not to match boolean 'sound' */
2990 fullname
= "soundcard";
2991 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2993 complain_about_duplicate(opts
, 1);
2995 bad_negation(fullname
, FALSE
);
2997 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
3000 if (!assign_soundcard(opts
))
3008 * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|
3009 * ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen]
3011 fullname
= "map_mode";
3012 if (match_optname(opts
, fullname
, sizeof("map_mode") - 1, TRUE
)) {
3014 complain_about_duplicate(opts
, 1);
3015 op
= string_for_opt(opts
, negated
);
3016 if (op
&& !negated
) {
3017 if (!strncmpi(op
, "tiles", sizeof("tiles") - 1))
3018 iflags
.wc_map_mode
= MAP_MODE_TILES
;
3019 else if (!strncmpi(op
, "ascii4x6", sizeof("ascii4x6") - 1))
3020 iflags
.wc_map_mode
= MAP_MODE_ASCII4x6
;
3021 else if (!strncmpi(op
, "ascii6x8", sizeof("ascii6x8") - 1))
3022 iflags
.wc_map_mode
= MAP_MODE_ASCII6x8
;
3023 else if (!strncmpi(op
, "ascii8x8", sizeof("ascii8x8") - 1))
3024 iflags
.wc_map_mode
= MAP_MODE_ASCII8x8
;
3025 else if (!strncmpi(op
, "ascii16x8", sizeof("ascii16x8") - 1))
3026 iflags
.wc_map_mode
= MAP_MODE_ASCII16x8
;
3027 else if (!strncmpi(op
, "ascii7x12", sizeof("ascii7x12") - 1))
3028 iflags
.wc_map_mode
= MAP_MODE_ASCII7x12
;
3029 else if (!strncmpi(op
, "ascii8x12", sizeof("ascii8x12") - 1))
3030 iflags
.wc_map_mode
= MAP_MODE_ASCII8x12
;
3031 else if (!strncmpi(op
, "ascii16x12", sizeof("ascii16x12") - 1))
3032 iflags
.wc_map_mode
= MAP_MODE_ASCII16x12
;
3033 else if (!strncmpi(op
, "ascii12x16", sizeof("ascii12x16") - 1))
3034 iflags
.wc_map_mode
= MAP_MODE_ASCII12x16
;
3035 else if (!strncmpi(op
, "ascii10x18", sizeof("ascii10x18") - 1))
3036 iflags
.wc_map_mode
= MAP_MODE_ASCII10x18
;
3037 else if (!strncmpi(op
, "fit_to_screen",
3038 sizeof("fit_to_screen") - 1))
3039 iflags
.wc_map_mode
= MAP_MODE_ASCII_FIT_TO_SCREEN
;
3043 bad_negation(fullname
, TRUE
);
3047 * scroll_amount:nn */
3048 fullname
= "scroll_amount";
3049 if (match_optname(opts
, fullname
, sizeof("scroll_amount") - 1, TRUE
)) {
3051 complain_about_duplicate(opts
, 1);
3052 op
= string_for_opt(opts
, negated
);
3053 if ((negated
&& !op
) || (!negated
&& op
)) {
3054 iflags
.wc_scroll_amount
= negated
? 1 : atoi(op
);
3056 bad_negation(fullname
, TRUE
);
3060 * scroll_margin:nn */
3061 fullname
= "scroll_margin";
3062 if (match_optname(opts
, fullname
, sizeof("scroll_margin") - 1, TRUE
)) {
3064 complain_about_duplicate(opts
, 1);
3065 op
= string_for_opt(opts
, negated
);
3066 if ((negated
&& !op
) || (!negated
&& op
)) {
3067 iflags
.wc_scroll_margin
= negated
? 5 : atoi(op
);
3069 bad_negation(fullname
, TRUE
);
3072 fullname
= "subkeyvalue";
3073 if (match_optname(opts
, fullname
, 5, TRUE
)) {
3074 /* no duplicate complaint here */
3076 bad_negation(fullname
, FALSE
);
3079 op
= string_for_opt(opts
, 0);
3080 map_subkeyvalue(op
);
3087 fullname
= "tile_width";
3088 if (match_optname(opts
, fullname
, sizeof("tile_width") - 1, TRUE
)) {
3090 complain_about_duplicate(opts
, 1);
3091 op
= string_for_opt(opts
, negated
);
3092 if ((negated
&& !op
) || (!negated
&& op
)) {
3093 iflags
.wc_tile_width
= negated
? 0 : atoi(op
);
3095 bad_negation(fullname
, TRUE
);
3100 fullname
= "tile_file";
3101 if (match_optname(opts
, fullname
, sizeof("tile_file") - 1, TRUE
)) {
3103 complain_about_duplicate(opts
, 1);
3104 if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3105 if (iflags
.wc_tile_file
)
3106 free(iflags
.wc_tile_file
);
3107 iflags
.wc_tile_file
= dupstr(op
);
3113 fullname
= "tile_height";
3114 if (match_optname(opts
, fullname
, sizeof("tile_height") - 1, TRUE
)) {
3116 complain_about_duplicate(opts
, 1);
3117 op
= string_for_opt(opts
, negated
);
3118 if ((negated
&& !op
) || (!negated
&& op
)) {
3119 iflags
.wc_tile_height
= negated
? 0 : atoi(op
);
3121 bad_negation(fullname
, TRUE
);
3125 * vary_msgcount:nn */
3126 fullname
= "vary_msgcount";
3127 if (match_optname(opts
, fullname
, sizeof("vary_msgcount") - 1, TRUE
)) {
3129 complain_about_duplicate(opts
, 1);
3130 op
= string_for_opt(opts
, negated
);
3131 if ((negated
&& !op
) || (!negated
&& op
)) {
3132 iflags
.wc_vary_msgcount
= negated
? 0 : atoi(op
);
3134 bad_negation(fullname
, TRUE
);
3137 fullname
= "windowtype";
3138 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3140 complain_about_duplicate(opts
, 1);
3142 bad_negation(fullname
, FALSE
);
3144 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
3145 char buf
[WINTYPELEN
];
3146 nmcpy(buf
, op
, WINTYPELEN
);
3147 choose_windows(buf
);
3152 fullname
= "windowchain";
3153 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3155 bad_negation(fullname
, FALSE
);
3157 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
3158 char buf
[WINTYPELEN
];
3159 nmcpy(buf
, op
, WINTYPELEN
);
3160 addto_windowchain(buf
);
3167 * setting window colors
3168 * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
3170 fullname
= "windowcolors";
3171 if (match_optname(opts
, fullname
, 7, TRUE
)) {
3173 complain_about_duplicate(opts
, 1);
3174 if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3175 if (!wc_set_window_colors(op
))
3178 bad_negation(fullname
, TRUE
);
3182 /* menustyle:traditional or combination or full or partial */
3183 if (match_optname(opts
, "menustyle", 4, TRUE
)) {
3185 boolean val_required
= (strlen(opts
) > 5 && !negated
);
3188 complain_about_duplicate(opts
, 1);
3189 if (!(op
= string_for_opt(opts
, !val_required
))) {
3191 return; /* string_for_opt gave feedback */
3192 tmp
= negated
? 'n' : 'f';
3197 case 'n': /* none */
3198 case 't': /* traditional: prompt for class(es) by symbol,
3199 prompt for each item within class(es) one at a time */
3200 flags
.menu_style
= MENU_TRADITIONAL
;
3202 case 'c': /* combination: prompt for class(es) by symbol,
3203 choose items within selected class(es) by menu */
3204 flags
.menu_style
= MENU_COMBINATION
;
3206 case 'f': /* full: choose class(es) by first menu,
3207 choose items within selected class(es) by second menu */
3208 flags
.menu_style
= MENU_FULL
;
3210 case 'p': /* partial: skip class filtering,
3211 choose items among all classes by menu */
3212 flags
.menu_style
= MENU_PARTIAL
;
3220 fullname
= "menu_headings";
3221 if (match_optname(opts
, fullname
, 12, TRUE
)) {
3223 complain_about_duplicate(opts
, 1);
3225 bad_negation(fullname
, FALSE
);
3227 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
3230 for (i
= 0; i
< SIZE(attrnames
); i
++)
3231 if (!strcmpi(opts
, attrnames
[i
].name
)) {
3232 iflags
.menu_headings
= attrnames
[i
].attr
;
3239 /* check for menu command mapping */
3240 for (i
= 0; i
< NUM_MENU_CMDS
; i
++) {
3241 fullname
= default_menu_cmd_info
[i
].name
;
3243 complain_about_duplicate(opts
, 1);
3244 if (match_optname(opts
, fullname
, (int) strlen(fullname
), TRUE
)) {
3246 bad_negation(fullname
, FALSE
);
3247 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3248 char c
, op_buf
[BUFSZ
];
3250 escapes(op
, op_buf
);
3253 if (illegal_menu_cmd_key(c
))
3256 add_menu_cmd_alias(c
, default_menu_cmd_info
[i
].cmd
);
3261 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
3262 /* hilite fields in status prompt */
3263 if (match_optname(opts
, "hilite_status", 13, TRUE
)) {
3265 complain_about_duplicate(opts
, 1);
3266 op
= string_for_opt(opts
, TRUE
);
3267 if (op
&& negated
) {
3268 clear_status_hilites(tfrom_file
);
3271 /* a value is mandatory */
3275 if (!set_status_hilites(op
, tfrom_file
))
3281 #if defined(BACKWARD_COMPAT)
3282 fullname
= "DECgraphics";
3283 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3284 boolean badflag
= FALSE
;
3287 complain_about_duplicate(opts
, 1);
3289 /* There is no rogue level DECgraphics-specific set */
3290 if (symset
[PRIMARY
].name
) {
3293 symset
[PRIMARY
].name
= dupstr(fullname
);
3294 if (!read_sym_file(PRIMARY
)) {
3296 clear_symsetentry(PRIMARY
, TRUE
);
3298 switch_symbols(TRUE
);
3301 pline("Failure to load symbol set %s.", fullname
);
3307 fullname
= "IBMgraphics";
3308 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3309 const char *sym_name
= fullname
;
3310 boolean badflag
= FALSE
;
3313 complain_about_duplicate(opts
, 1);
3315 for (i
= 0; i
< NUM_GRAPHICS
; ++i
) {
3316 if (symset
[i
].name
) {
3320 sym_name
= "RogueIBM";
3321 symset
[i
].name
= dupstr(sym_name
);
3322 if (!read_sym_file(i
)) {
3324 clear_symsetentry(i
, TRUE
);
3330 pline("Failure to load symbol set %s.", sym_name
);
3333 switch_symbols(TRUE
);
3334 if (!initial
&& Is_rogue_level(&u
.uz
))
3335 assign_graphics(ROGUESET
);
3341 #ifdef MAC_GRAPHICS_ENV
3342 fullname
= "MACgraphics";
3343 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3344 boolean badflag
= FALSE
;
3347 complain_about_duplicate(opts
, 1);
3349 if (symset
[PRIMARY
].name
) {
3352 symset
[PRIMARY
].name
= dupstr(fullname
);
3353 if (!read_sym_file(PRIMARY
)) {
3355 clear_symsetentry(PRIMARY
, TRUE
);
3359 pline("Failure to load symbol set %s.", fullname
);
3362 switch_symbols(TRUE
);
3363 if (!initial
&& Is_rogue_level(&u
.uz
))
3364 assign_graphics(ROGUESET
);
3371 /* OK, if we still haven't recognized the option, check the boolean
3374 for (i
= 0; boolopt
[i
].name
; i
++) {
3375 if (match_optname(opts
, boolopt
[i
].name
, 3, TRUE
)) {
3376 /* options that don't exist */
3377 if (!boolopt
[i
].addr
) {
3378 if (!initial
&& !negated
)
3379 pline_The("\"%s\" option is not available.",
3383 /* options that must come from config file */
3384 if (!initial
&& (boolopt
[i
].optflags
== SET_IN_FILE
)) {
3385 rejectoption(boolopt
[i
].name
);
3389 op
= string_for_opt(opts
, TRUE
);
3396 if (!strcmp(op
, "true") || !strcmp(op
, "yes")) {
3398 } else if (!strcmp(op
, "false") || !strcmp(op
, "no")) {
3406 *(boolopt
[i
].addr
) = !negated
;
3408 /* 0 means boolean opts */
3409 if (duplicate_opt_detection(boolopt
[i
].name
, 0))
3410 complain_about_duplicate(boolopt
[i
].name
, 0);
3412 if (boolopt
[i
].addr
== &iflags
.rlecomp
)
3413 set_savepref(iflags
.rlecomp
? "rlecomp" : "!rlecomp");
3416 if (boolopt
[i
].addr
== &iflags
.zerocomp
)
3417 set_savepref(iflags
.zerocomp
? "zerocomp" : "externalcomp");
3419 /* only do processing below if setting with doset() */
3423 if (boolopt
[i
].addr
== &flags
.time
3424 #ifdef SCORE_ON_BOTL
3425 || boolopt
[i
].addr
== &flags
.showscore
3427 || boolopt
[i
].addr
== &flags
.showexp
) {
3428 #ifdef STATUS_VIA_WINDOWPORT
3429 status_initialize(REASSESS_ONLY
);
3431 context
.botl
= TRUE
;
3432 } else if (boolopt
[i
].addr
== &flags
.invlet_constant
) {
3433 if (flags
.invlet_constant
)
3435 } else if (boolopt
[i
].addr
== &flags
.lit_corridor
3436 || boolopt
[i
].addr
== &flags
.dark_room
) {
3438 * All corridor squares seen via night vision or
3439 * candles & lamps change. Update them by calling
3440 * newsym() on them. Don't do this if we are
3441 * initializing the options --- the vision system
3444 vision_recalc(2); /* shut down vision */
3445 vision_full_recalc
= 1; /* delayed recalc */
3446 if (iflags
.use_color
)
3447 need_redraw
= TRUE
; /* darkroom refresh */
3448 } else if (boolopt
[i
].addr
== &iflags
.wc_tiled_map
3449 || boolopt
[i
].addr
== &flags
.showrace
3450 || boolopt
[i
].addr
== &iflags
.use_inverse
3451 || boolopt
[i
].addr
== &iflags
.hilite_pile
3452 || boolopt
[i
].addr
== &iflags
.hilite_pet
) {
3455 } else if (boolopt
[i
].addr
== &iflags
.use_color
) {
3465 #endif /* TEXTCOLOR */
3471 /* Is it a symbol? */
3472 if (strstr(opts
, "S_") == opts
&& parsesymbols(opts
)) {
3473 switch_symbols(TRUE
);
3477 /* out of valid options */
3481 /* parse key:command */
3483 parsebindings(bindings
)
3490 /* break off first binding from the rest; parse the rest */
3491 if ((bind
= index(bindings
, ',')) != 0) {
3493 parsebindings(bind
);
3496 /* parse a single binding: first split around : */
3497 if (! (bind
= index(bindings
, ':'))) return; /* it's not a binding */
3500 /* read the key to be bound */
3501 key
= txt2key(bindings
);
3503 raw_printf("Bad binding %s.", bindings
);
3508 bind
= trimspaces(bind
);
3510 /* is it a special key? */
3511 if (bind_specialkey(key
, bind
))
3514 /* is it a menu command? */
3515 for (i
= 0; i
< NUM_MENU_CMDS
; i
++) {
3516 if (!strcmp(default_menu_cmd_info
[i
].name
, bind
)) {
3517 if (illegal_menu_cmd_key(key
)) {
3519 Sprintf(tmp
, "Bad menu key %s:%s", visctrl(key
), bind
);
3522 add_menu_cmd_alias(key
, default_menu_cmd_info
[i
].cmd
);
3527 /* extended command? */
3528 bind_key(key
, bind
);
3531 static NEARDATA
const char *menutype
[] = { "traditional", "combination",
3532 "full", "partial" };
3534 static NEARDATA
const char *burdentype
[] = { "unencumbered", "burdened",
3535 "stressed", "strained",
3536 "overtaxed", "overloaded" };
3538 static NEARDATA
const char *runmodes
[] = { "teleport", "run", "walk",
3541 static NEARDATA
const char *sortltype
[] = { "none", "loot", "full" };
3544 * Convert the given string of object classes to a string of default object
3548 oc_to_str(src
, dest
)
3553 while ((i
= (int) *src
++) != 0) {
3554 if (i
< 0 || i
>= MAXOCLASSES
)
3555 impossible("oc_to_str: illegal object class %d", i
);
3557 *dest
++ = def_oc_syms
[i
].sym
;
3563 * Add the given mapping to the menu command map list. Always keep the
3564 * maps valid C strings.
3567 add_menu_cmd_alias(from_ch
, to_ch
)
3568 char from_ch
, to_ch
;
3570 if (n_menu_mapped
>= MAX_MENU_MAPPED_CMDS
) {
3571 pline("out of menu map space.");
3573 mapped_menu_cmds
[n_menu_mapped
] = from_ch
;
3574 mapped_menu_op
[n_menu_mapped
] = to_ch
;
3576 mapped_menu_cmds
[n_menu_mapped
] = 0;
3577 mapped_menu_op
[n_menu_mapped
] = 0;
3582 * Map the given character to its corresponding menu command. If it
3583 * doesn't match anything, just return the original.
3589 char *found
= index(mapped_menu_cmds
, ch
);
3591 int idx
= (int) (found
- mapped_menu_cmds
);
3592 ch
= mapped_menu_op
[idx
];
3597 #if defined(MICRO) || defined(MAC) || defined(WIN32)
3598 #define OPTIONS_HEADING "OPTIONS"
3600 #define OPTIONS_HEADING "NETHACKOPTIONS"
3603 static char fmtstr_doset
[] = "%s%-15s [%s] ";
3604 static char fmtstr_doset_tab
[] = "%s\t[%s]";
3605 static char n_currently_set
[] = "(%d currently set)";
3607 /* doset('O' command) menu entries for compound options */
3609 doset_add_menu(win
, option
, indexoffset
)
3610 winid win
; /* window to add to */
3611 const char *option
; /* option name */
3612 int indexoffset
; /* value to add to index in compopt[], or zero
3613 if option cannot be changed */
3615 const char *value
= "unknown"; /* current value */
3616 char buf
[BUFSZ
], buf2
[BUFSZ
];
3621 if (indexoffset
== 0) {
3623 value
= get_compopt_value(option
, buf2
);
3625 for (i
= 0; compopt
[i
].name
; i
++)
3626 if (strcmp(option
, compopt
[i
].name
) == 0)
3629 if (compopt
[i
].name
) {
3630 any
.a_int
= i
+ 1 + indexoffset
;
3631 value
= get_compopt_value(option
, buf2
);
3633 /* We are trying to add an option not found in compopt[].
3634 This is almost certainly bad, but we'll let it through anyway
3635 (with a zero value, so it can't be selected). */
3639 /* " " replaces "a - " -- assumes menus follow that style */
3640 if (!iflags
.menu_tab_sep
)
3641 Sprintf(buf
, fmtstr_doset
, any
.a_int
? "" : " ", option
,
3644 Sprintf(buf
, fmtstr_doset_tab
, option
, value
);
3645 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
3649 opts_add_others(win
, name
, id
, bufx
, nset
)
3656 char buf
[BUFSZ
], buf2
[BUFSZ
];
3657 anything any
= zeroany
;
3661 Sprintf(buf2
, n_currently_set
, nset
);
3663 Sprintf(buf2
, "%s", bufx
);
3664 if (!iflags
.menu_tab_sep
)
3665 Sprintf(buf
, fmtstr_doset
, any
.a_int
? "" : " ",
3668 Sprintf(buf
, fmtstr_doset_tab
, name
, buf2
);
3669 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
3672 enum opt_other_enums
{
3673 OPT_OTHER_MSGTYPE
= -4,
3674 OPT_OTHER_MENUCOLOR
= -3,
3675 OPT_OTHER_STATHILITE
= -2,
3676 OPT_OTHER_APEXC
= -1
3677 /* these must be < 0 */
3680 /* presently only used when determining longest option name */
3681 static struct other_opts
{
3684 enum opt_other_enums code
;
3686 { "autopickup exceptions", SET_IN_GAME
, OPT_OTHER_APEXC
},
3687 { "menucolors", SET_IN_GAME
, OPT_OTHER_MENUCOLOR
},
3688 { "message types", SET_IN_GAME
, OPT_OTHER_MSGTYPE
},
3689 #ifdef STATUS_VIA_WINDOWPORT
3690 #ifdef STATUS_HILITES
3691 { "status_hilites", SET_IN_GAME
, OPT_OTHER_STATHILITE
},
3694 { (char *) 0, 0, (enum opt_other_enums
) 0 },
3697 /* the 'O' command */
3699 doset() /* changing options via menu by Per Liboriussen */
3701 static boolean made_fmtstr
= FALSE
;
3702 char buf
[BUFSZ
], buf2
[BUFSZ
];
3704 int i
= 0, pass
, boolcount
, pick_cnt
, pick_idx
, opt_indx
;
3708 menu_item
*pick_list
;
3709 int indexoffset
, startpass
, endpass
, optflags
;
3710 boolean setinitial
= FALSE
, fromfile
= FALSE
;
3711 unsigned longest_name_len
;
3713 tmpwin
= create_nhwindow(NHW_MENU
);
3716 #ifdef notyet /* SYSCF */
3717 /* XXX I think this is still fragile. Fixing initial/from_file and/or
3718 changing the SET_* etc to bitmaps will let me make this better. */
3720 startpass
= SET_IN_SYS
;
3723 startpass
= DISP_IN_GAME
;
3724 endpass
= (wizard
) ? SET_IN_WIZGAME
: SET_IN_GAME
;
3726 if (!made_fmtstr
&& !iflags
.menu_tab_sep
) {
3727 /* spin through the options to find the longest name
3728 and adjust the format string accordingly */
3729 longest_name_len
= 0;
3730 for (pass
= 0; pass
<= 2; pass
++)
3731 for (i
= 0; (name
= ((pass
== 0)
3735 : othropt
[i
].name
)) != 0; i
++) {
3736 if (pass
== 0 && !boolopt
[i
].addr
)
3738 optflags
= (pass
== 0) ? boolopt
[i
].optflags
3740 ? compopt
[i
].optflags
3741 : othropt
[i
].optflags
;
3742 if (optflags
< startpass
|| optflags
> endpass
)
3744 if ((is_wc_option(name
) && !wc_supported(name
))
3745 || (is_wc2_option(name
) && !wc2_supported(name
)))
3748 if (strlen(name
) > longest_name_len
)
3749 longest_name_len
= strlen(name
);
3751 Sprintf(fmtstr_doset
, "%%s%%-%us [%%s]", longest_name_len
);
3756 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3757 "Booleans (selecting will toggle value):", MENU_UNSELECTED
);
3759 /* first list any other non-modifiable booleans, then modifiable ones */
3760 for (pass
= 0; pass
<= 1; pass
++)
3761 for (i
= 0; (name
= boolopt
[i
].name
) != 0; i
++)
3762 if ((bool_p
= boolopt
[i
].addr
) != 0
3763 && ((boolopt
[i
].optflags
<= DISP_IN_GAME
&& pass
== 0)
3764 || (boolopt
[i
].optflags
>= SET_IN_GAME
&& pass
== 1))) {
3765 if (bool_p
== &flags
.female
)
3766 continue; /* obsolete */
3767 if (boolopt
[i
].optflags
== SET_IN_WIZGAME
&& !wizard
)
3769 if ((is_wc_option(name
) && !wc_supported(name
))
3770 || (is_wc2_option(name
) && !wc2_supported(name
)))
3773 any
.a_int
= (pass
== 0) ? 0 : i
+ 1;
3774 if (!iflags
.menu_tab_sep
)
3775 Sprintf(buf
, fmtstr_doset
, (pass
== 0) ? " " : "",
3776 name
, *bool_p
? "true" : "false");
3778 Sprintf(buf
, fmtstr_doset_tab
,
3779 name
, *bool_p
? "true" : "false");
3780 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
,
3785 indexoffset
= boolcount
;
3787 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3788 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3789 "Compounds (selecting will prompt for new value):",
3792 /* deliberately put playmode, name, role+race+gender+align first */
3793 doset_add_menu(tmpwin
, "playmode", 0);
3794 doset_add_menu(tmpwin
, "name", 0);
3795 doset_add_menu(tmpwin
, "role", 0);
3796 doset_add_menu(tmpwin
, "race", 0);
3797 doset_add_menu(tmpwin
, "gender", 0);
3798 doset_add_menu(tmpwin
, "align", 0);
3800 for (pass
= startpass
; pass
<= endpass
; pass
++)
3801 for (i
= 0; (name
= compopt
[i
].name
) != 0; i
++)
3802 if (compopt
[i
].optflags
== pass
) {
3803 if (!strcmp(name
, "playmode") || !strcmp(name
, "name")
3804 || !strcmp(name
, "role") || !strcmp(name
, "race")
3805 || !strcmp(name
, "gender") || !strcmp(name
, "align"))
3807 if ((is_wc_option(name
) && !wc_supported(name
))
3808 || (is_wc2_option(name
) && !wc2_supported(name
)))
3811 doset_add_menu(tmpwin
, name
,
3812 (pass
== DISP_IN_GAME
) ? 0 : indexoffset
);
3816 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3817 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3821 opts_add_others(tmpwin
, "autopickup exceptions", OPT_OTHER_APEXC
,
3822 NULL
, count_ape_maps((int *) 0, (int *) 0));
3823 opts_add_others(tmpwin
, "menucolors", OPT_OTHER_MENUCOLOR
,
3824 NULL
, count_menucolors());
3825 opts_add_others(tmpwin
, "message types", OPT_OTHER_MSGTYPE
,
3826 NULL
, msgtype_count());
3827 #ifdef STATUS_VIA_WINDOWPORT
3828 #ifdef STATUS_HILITES
3829 get_status_hilites(buf2
, 60);
3831 Sprintf(buf2
, "%s", "(none)");
3832 opts_add_others(tmpwin
, "status_hilites", OPT_OTHER_STATHILITE
, buf2
, 0);
3835 #ifdef PREFIXES_IN_USE
3837 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3838 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3839 "Variable playground locations:", MENU_UNSELECTED
);
3840 for (i
= 0; i
< PREFIX_COUNT
; i
++)
3841 doset_add_menu(tmpwin
, fqn_prefix_names
[i
], 0);
3843 end_menu(tmpwin
, "Set what options?");
3844 need_redraw
= FALSE
;
3845 if ((pick_cnt
= select_menu(tmpwin
, PICK_ANY
, &pick_list
)) > 0) {
3847 * Walk down the selection list and either invert the booleans
3848 * or prompt for new values. In most cases, call parseoptions()
3849 * to take care of options that require special attention, like
3852 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
) {
3853 opt_indx
= pick_list
[pick_idx
].item
.a_int
- 1;
3854 if (opt_indx
< -1) opt_indx
++; /* -1 offset for select_menu() */
3855 if (opt_indx
== OPT_OTHER_APEXC
) {
3856 (void) special_handling("autopickup_exception", setinitial
,
3858 #ifdef STATUS_VIA_WINDOWPORT
3859 #ifdef STATUS_HILITES
3860 } else if (opt_indx
== OPT_OTHER_STATHILITE
) {
3861 if (!status_hilite_menu()) {
3862 pline("Bad status hilite(s) specified.");
3864 if (wc2_supported("status_hilites"))
3865 preference_update("status_hilites");
3869 } else if (opt_indx
== OPT_OTHER_MENUCOLOR
) {
3870 (void) special_handling("menucolors", setinitial
,
3872 } else if (opt_indx
== OPT_OTHER_MSGTYPE
) {
3873 (void) special_handling("msgtype", setinitial
, fromfile
);
3874 } else if (opt_indx
< boolcount
) {
3875 /* boolean option */
3876 Sprintf(buf
, "%s%s", *boolopt
[opt_indx
].addr
? "!" : "",
3877 boolopt
[opt_indx
].name
);
3878 parseoptions(buf
, setinitial
, fromfile
);
3879 if (wc_supported(boolopt
[opt_indx
].name
)
3880 || wc2_supported(boolopt
[opt_indx
].name
))
3881 preference_update(boolopt
[opt_indx
].name
);
3883 /* compound option */
3884 opt_indx
-= boolcount
;
3886 if (!special_handling(compopt
[opt_indx
].name
, setinitial
,
3888 Sprintf(buf
, "Set %s to what?", compopt
[opt_indx
].name
);
3890 if (buf2
[0] == '\033')
3892 Sprintf(buf
, "%s:%s", compopt
[opt_indx
].name
, buf2
);
3894 parseoptions(buf
, setinitial
, fromfile
);
3896 if (wc_supported(compopt
[opt_indx
].name
)
3897 || wc2_supported(compopt
[opt_indx
].name
))
3898 preference_update(compopt
[opt_indx
].name
);
3901 free((genericptr_t
) pick_list
);
3902 pick_list
= (menu_item
*) 0;
3905 destroy_nhwindow(tmpwin
);
3914 handle_add_list_remove(optname
, numtotal
)
3915 const char *optname
;
3920 int i
, pick_cnt
, opt_idx
;
3921 menu_item
*pick_list
= (menu_item
*) 0;
3922 static const struct action
{
3925 } action_titles
[] = {
3926 { 'a', "add new %s" }, /* [0] */
3927 { 'l', "list %s" }, /* [1] */
3928 { 'r', "remove existing %s" }, /* [2] */
3929 { 'x', "exit this menu" }, /* [3] */
3933 tmpwin
= create_nhwindow(NHW_MENU
);
3936 for (i
= 0; i
< SIZE(action_titles
); i
++) {
3940 /* omit list and remove if there aren't any yet */
3941 if (!numtotal
&& (i
== 1 || i
== 2))
3943 Sprintf(tmpbuf
, action_titles
[i
].desc
,
3944 (i
== 1) ? makeplural(optname
) : optname
);
3945 add_menu(tmpwin
, NO_GLYPH
, &any
, action_titles
[i
].letr
, 0, ATR_NONE
,
3946 tmpbuf
, (i
== 3) ? MENU_SELECTED
: MENU_UNSELECTED
);
3948 end_menu(tmpwin
, "Do what?");
3949 if ((pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &pick_list
)) > 0) {
3950 opt_idx
= pick_list
[0].item
.a_int
- 1;
3951 if (pick_cnt
> 1 && opt_idx
== 3)
3952 opt_idx
= pick_list
[1].item
.a_int
- 1;
3953 free((genericptr_t
) pick_list
);
3955 opt_idx
= 3; /* none selected, exit menu */
3956 destroy_nhwindow(tmpwin
);
3960 struct symsetentry
*symset_list
= 0; /* files.c will populate this with
3961 list of available sets */
3964 special_handling(optname
, setinitial
, setfromfile
)
3965 const char *optname
;
3966 boolean setinitial
, setfromfile
;
3973 /* Special handling of menustyle, pickup_burden, pickup_types,
3974 * disclose, runmode, msg_window, menu_headings, sortloot,
3975 * and number_pad options.
3976 * Also takes care of interactive autopickup_exception_handling changes.
3978 if (!strcmp("menustyle", optname
)) {
3979 const char *style_name
;
3980 menu_item
*style_pick
= (menu_item
*) 0;
3981 tmpwin
= create_nhwindow(NHW_MENU
);
3984 for (i
= 0; i
< SIZE(menutype
); i
++) {
3985 style_name
= menutype
[i
];
3986 /* note: separate `style_name' variable used
3987 to avoid an optimizer bug in VAX C V2.3 */
3989 add_menu(tmpwin
, NO_GLYPH
, &any
, *style_name
, 0, ATR_NONE
,
3990 style_name
, MENU_UNSELECTED
);
3992 end_menu(tmpwin
, "Select menustyle:");
3993 if (select_menu(tmpwin
, PICK_ONE
, &style_pick
) > 0) {
3994 flags
.menu_style
= style_pick
->item
.a_int
- 1;
3995 free((genericptr_t
) style_pick
);
3997 destroy_nhwindow(tmpwin
);
3998 } else if (!strcmp("paranoid_confirmation", optname
)) {
3999 menu_item
*paranoia_picks
= (menu_item
*) 0;
4001 tmpwin
= create_nhwindow(NHW_MENU
);
4004 for (i
= 0; paranoia
[i
].flagmask
!= 0; ++i
) {
4005 if (paranoia
[i
].flagmask
== PARANOID_BONES
&& !wizard
)
4007 any
.a_int
= paranoia
[i
].flagmask
;
4008 add_menu(tmpwin
, NO_GLYPH
, &any
, *paranoia
[i
].argname
, 0,
4009 ATR_NONE
, paranoia
[i
].explain
,
4010 (flags
.paranoia_bits
& paranoia
[i
].flagmask
)
4014 end_menu(tmpwin
, "Actions requiring extra confirmation:");
4015 i
= select_menu(tmpwin
, PICK_ANY
, ¶noia_picks
);
4017 /* player didn't cancel; we reset all the paranoia options
4018 here even if there were no items picked, since user
4019 could have toggled off preselected ones to end up with 0 */
4020 flags
.paranoia_bits
= 0;
4022 /* at least 1 item set, either preselected or newly picked */
4024 flags
.paranoia_bits
|= paranoia_picks
[i
].item
.a_int
;
4025 free((genericptr_t
) paranoia_picks
);
4028 destroy_nhwindow(tmpwin
);
4029 } else if (!strcmp("pickup_burden", optname
)) {
4030 const char *burden_name
, *burden_letters
= "ubsntl";
4031 menu_item
*burden_pick
= (menu_item
*) 0;
4033 tmpwin
= create_nhwindow(NHW_MENU
);
4036 for (i
= 0; i
< SIZE(burdentype
); i
++) {
4037 burden_name
= burdentype
[i
];
4039 add_menu(tmpwin
, NO_GLYPH
, &any
, burden_letters
[i
], 0, ATR_NONE
,
4040 burden_name
, MENU_UNSELECTED
);
4042 end_menu(tmpwin
, "Select encumbrance level:");
4043 if (select_menu(tmpwin
, PICK_ONE
, &burden_pick
) > 0) {
4044 flags
.pickup_burden
= burden_pick
->item
.a_int
- 1;
4045 free((genericptr_t
) burden_pick
);
4047 destroy_nhwindow(tmpwin
);
4048 } else if (!strcmp("pickup_types", optname
)) {
4049 /* parseoptions will prompt for the list of types */
4050 parseoptions(strcpy(buf
, "pickup_types"), setinitial
, setfromfile
);
4051 } else if (!strcmp("disclose", optname
)) {
4052 /* order of disclose_names[] must correspond to
4053 disclosure_options in decl.c */
4054 static const char *disclosure_names
[] = {
4055 "inventory", "attributes", "vanquished",
4056 "genocides", "conduct", "overview",
4058 int disc_cat
[NUM_DISCLOSURE_OPTIONS
];
4059 int pick_cnt
, pick_idx
, opt_idx
;
4061 menu_item
*disclosure_pick
= (menu_item
*) 0;
4063 tmpwin
= create_nhwindow(NHW_MENU
);
4066 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4067 Sprintf(buf
, "%-12s[%c%c]", disclosure_names
[i
],
4068 flags
.end_disclose
[i
], disclosure_options
[i
]);
4070 add_menu(tmpwin
, NO_GLYPH
, &any
, disclosure_options
[i
], 0,
4071 ATR_NONE
, buf
, MENU_UNSELECTED
);
4074 end_menu(tmpwin
, "Change which disclosure options categories:");
4075 pick_cnt
= select_menu(tmpwin
, PICK_ANY
, &disclosure_pick
);
4077 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
) {
4078 opt_idx
= disclosure_pick
[pick_idx
].item
.a_int
- 1;
4079 disc_cat
[opt_idx
] = 1;
4081 free((genericptr_t
) disclosure_pick
);
4082 disclosure_pick
= (menu_item
*) 0;
4084 destroy_nhwindow(tmpwin
);
4086 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4088 c
= flags
.end_disclose
[i
];
4089 Sprintf(buf
, "Disclosure options for %s:",
4090 disclosure_names
[i
]);
4091 tmpwin
= create_nhwindow(NHW_MENU
);
4094 /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
4095 any
.a_char
= DISCLOSE_NO_WITHOUT_PROMPT
;
4096 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4097 "Never disclose, without prompting",
4098 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4099 any
.a_char
= DISCLOSE_YES_WITHOUT_PROMPT
;
4100 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4101 "Always disclose, without prompting",
4102 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4103 if (*disclosure_names
[i
] == 'v') {
4104 any
.a_char
= DISCLOSE_SPECIAL_WITHOUT_PROMPT
; /* '#' */
4105 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4106 "Always disclose, pick sort order from menu",
4107 (c
== any
.a_char
) ? MENU_SELECTED
4110 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_NO
;
4111 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4112 "Prompt, with default answer of \"No\"",
4113 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4114 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_YES
;
4115 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4116 "Prompt, with default answer of \"Yes\"",
4117 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4118 if (*disclosure_names
[i
] == 'v') {
4119 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_SPECIAL
; /* '?' */
4120 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4121 "Prompt, with default answer of \"Ask\" to request sort menu",
4122 (c
== any
.a_char
) ? MENU_SELECTED
4125 end_menu(tmpwin
, buf
);
4126 n
= select_menu(tmpwin
, PICK_ONE
, &disclosure_pick
);
4128 flags
.end_disclose
[i
] = disclosure_pick
[0].item
.a_char
;
4129 if (n
> 1 && flags
.end_disclose
[i
] == c
)
4130 flags
.end_disclose
[i
] = disclosure_pick
[1].item
.a_char
;
4131 free((genericptr_t
) disclosure_pick
);
4133 destroy_nhwindow(tmpwin
);
4136 } else if (!strcmp("runmode", optname
)) {
4137 const char *mode_name
;
4138 menu_item
*mode_pick
= (menu_item
*) 0;
4140 tmpwin
= create_nhwindow(NHW_MENU
);
4143 for (i
= 0; i
< SIZE(runmodes
); i
++) {
4144 mode_name
= runmodes
[i
];
4146 add_menu(tmpwin
, NO_GLYPH
, &any
, *mode_name
, 0, ATR_NONE
,
4147 mode_name
, MENU_UNSELECTED
);
4149 end_menu(tmpwin
, "Select run/travel display mode:");
4150 if (select_menu(tmpwin
, PICK_ONE
, &mode_pick
) > 0) {
4151 flags
.runmode
= mode_pick
->item
.a_int
- 1;
4152 free((genericptr_t
) mode_pick
);
4154 destroy_nhwindow(tmpwin
);
4155 } else if (!strcmp("whatis_coord", optname
)) {
4156 menu_item
*window_pick
= (menu_item
*) 0;
4158 char gp
= iflags
.getpos_coords
;
4160 tmpwin
= create_nhwindow(NHW_MENU
);
4163 any
.a_char
= GPCOORDS_COMPASS
;
4164 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_COMPASS
,
4165 0, ATR_NONE
, "compass ('east' or '3s' or '2n,4w')",
4166 (gp
== GPCOORDS_COMPASS
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4167 any
.a_char
= GPCOORDS_COMFULL
;
4168 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_COMFULL
,
4169 0, ATR_NONE
, "full compass ('east' or '3south' or '2north,4west')",
4170 (gp
== GPCOORDS_COMFULL
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4171 any
.a_char
= GPCOORDS_MAP
;
4172 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_MAP
,
4173 0, ATR_NONE
, "map <x,y>",
4174 (gp
== GPCOORDS_MAP
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4175 any
.a_char
= GPCOORDS_SCREEN
;
4176 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_SCREEN
,
4177 0, ATR_NONE
, "screen [row,column]",
4178 (gp
== GPCOORDS_SCREEN
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4179 any
.a_char
= GPCOORDS_NONE
;
4180 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_NONE
,
4181 0, ATR_NONE
, "none (no coordinates displayed)",
4182 (gp
== GPCOORDS_NONE
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4184 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
4185 Sprintf(buf
, "map: upper-left: <%d,%d>, lower-right: <%d,%d>%s",
4186 1, 0, COLNO
- 1, ROWNO
- 1,
4187 flags
.verbose
? "; column 0 unused, off left edge" : "");
4188 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
4189 if (strcmp(windowprocs
.name
, "tty"))
4190 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
4191 "screen: row is offset to accommodate tty interface's use of top line",
4194 #define COL80ARG flags.verbose ? "; column 80 is not used" : ""
4198 Sprintf(buf
, "screen: upper-left: [%02d,%02d], lower-right: [%d,%d]%s",
4199 0 + 2, 1, ROWNO
- 1 + 2, COLNO
- 1, COL80ARG
);
4201 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
4202 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
4204 "Select coordinate display when auto-describing a map position:");
4205 if ((pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &window_pick
)) > 0) {
4206 iflags
.getpos_coords
= window_pick
[0].item
.a_char
;
4207 /* PICK_ONE doesn't unselect preselected entry when
4208 selecting another one */
4209 if (pick_cnt
> 1 && iflags
.getpos_coords
== gp
)
4210 iflags
.getpos_coords
= window_pick
[1].item
.a_char
;
4211 free((genericptr_t
) window_pick
);
4213 destroy_nhwindow(tmpwin
);
4214 } else if (!strcmp("msg_window", optname
)) {
4216 /* by Christian W. Cooper */
4217 menu_item
*window_pick
= (menu_item
*) 0;
4219 tmpwin
= create_nhwindow(NHW_MENU
);
4223 add_menu(tmpwin
, NO_GLYPH
, &any
, 's', 0, ATR_NONE
, "single",
4226 add_menu(tmpwin
, NO_GLYPH
, &any
, 'c', 0, ATR_NONE
, "combination",
4229 add_menu(tmpwin
, NO_GLYPH
, &any
, 'f', 0, ATR_NONE
, "full",
4232 add_menu(tmpwin
, NO_GLYPH
, &any
, 'r', 0, ATR_NONE
, "reversed",
4234 end_menu(tmpwin
, "Select message history display type:");
4235 if (select_menu(tmpwin
, PICK_ONE
, &window_pick
) > 0) {
4236 iflags
.prevmsg_window
= window_pick
->item
.a_char
;
4237 free((genericptr_t
) window_pick
);
4239 destroy_nhwindow(tmpwin
);
4241 } else if (!strcmp("sortloot", optname
)) {
4242 const char *sortl_name
;
4243 menu_item
*sortl_pick
= (menu_item
*) 0;
4245 tmpwin
= create_nhwindow(NHW_MENU
);
4248 for (i
= 0; i
< SIZE(sortltype
); i
++) {
4249 sortl_name
= sortltype
[i
];
4250 any
.a_char
= *sortl_name
;
4251 add_menu(tmpwin
, NO_GLYPH
, &any
, *sortl_name
, 0, ATR_NONE
,
4252 sortl_name
, (flags
.sortloot
== *sortl_name
)
4253 ? MENU_SELECTED
: MENU_UNSELECTED
);
4255 end_menu(tmpwin
, "Select loot sorting type:");
4256 n
= select_menu(tmpwin
, PICK_ONE
, &sortl_pick
);
4258 char c
= sortl_pick
[0].item
.a_char
;
4260 if (n
> 1 && c
== flags
.sortloot
)
4261 c
= sortl_pick
[1].item
.a_char
;
4263 free((genericptr_t
) sortl_pick
);
4265 destroy_nhwindow(tmpwin
);
4266 } else if (!strcmp("align_message", optname
)
4267 || !strcmp("align_status", optname
)) {
4268 menu_item
*window_pick
= (menu_item
*) 0;
4270 boolean msg
= (*(optname
+ 6) == 'm');
4272 tmpwin
= create_nhwindow(NHW_MENU
);
4275 any
.a_int
= ALIGN_TOP
;
4276 add_menu(tmpwin
, NO_GLYPH
, &any
, 't', 0, ATR_NONE
, "top",
4278 any
.a_int
= ALIGN_BOTTOM
;
4279 add_menu(tmpwin
, NO_GLYPH
, &any
, 'b', 0, ATR_NONE
, "bottom",
4281 any
.a_int
= ALIGN_LEFT
;
4282 add_menu(tmpwin
, NO_GLYPH
, &any
, 'l', 0, ATR_NONE
, "left",
4284 any
.a_int
= ALIGN_RIGHT
;
4285 add_menu(tmpwin
, NO_GLYPH
, &any
, 'r', 0, ATR_NONE
, "right",
4287 Sprintf(abuf
, "Select %s window placement relative to the map:",
4288 msg
? "message" : "status");
4289 end_menu(tmpwin
, abuf
);
4290 if (select_menu(tmpwin
, PICK_ONE
, &window_pick
) > 0) {
4292 iflags
.wc_align_message
= window_pick
->item
.a_int
;
4294 iflags
.wc_align_status
= window_pick
->item
.a_int
;
4295 free((genericptr_t
) window_pick
);
4297 destroy_nhwindow(tmpwin
);
4298 } else if (!strcmp("number_pad", optname
)) {
4299 static const char *npchoices
[] = {
4300 " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
4301 " 3 (on, phone-style digit layout)",
4302 " 4 (on, phone-style layout, MSDOS compatible)",
4303 "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
4305 menu_item
*mode_pick
= (menu_item
*) 0;
4307 tmpwin
= create_nhwindow(NHW_MENU
);
4310 for (i
= 0; i
< SIZE(npchoices
); i
++) {
4312 add_menu(tmpwin
, NO_GLYPH
, &any
, 'a' + i
, 0, ATR_NONE
,
4313 npchoices
[i
], MENU_UNSELECTED
);
4315 end_menu(tmpwin
, "Select number_pad mode:");
4316 if (select_menu(tmpwin
, PICK_ONE
, &mode_pick
) > 0) {
4317 switch (mode_pick
->item
.a_int
- 1) {
4319 iflags
.num_pad
= FALSE
;
4320 iflags
.num_pad_mode
= 0;
4323 iflags
.num_pad
= TRUE
;
4324 iflags
.num_pad_mode
= 0;
4327 iflags
.num_pad
= TRUE
;
4328 iflags
.num_pad_mode
= 1;
4331 iflags
.num_pad
= TRUE
;
4332 iflags
.num_pad_mode
= 2;
4335 iflags
.num_pad
= TRUE
;
4336 iflags
.num_pad_mode
= 3;
4338 /* last menu choice: number_pad == -1 */
4340 iflags
.num_pad
= FALSE
;
4341 iflags
.num_pad_mode
= 1;
4344 reset_commands(FALSE
);
4345 number_pad(iflags
.num_pad
? 1 : 0);
4346 free((genericptr_t
) mode_pick
);
4348 destroy_nhwindow(tmpwin
);
4349 } else if (!strcmp("menu_headings", optname
)) {
4350 int mhattr
= query_attr("How to highlight menu headings:");
4353 iflags
.menu_headings
= mhattr
;
4354 } else if (!strcmp("msgtype", optname
)) {
4355 int opt_idx
, nmt
, mttyp
;
4359 nmt
= msgtype_count();
4360 opt_idx
= handle_add_list_remove("message type", nmt
);
4361 if (opt_idx
== 3) { /* done */
4363 } else if (opt_idx
== 0) { /* add new */
4364 getlin("What new message pattern?", mtbuf
);
4365 if (*mtbuf
== '\033')
4368 && (mttyp
= query_msgtype()) != -1
4369 && !msgtype_add(mttyp
, mtbuf
)) {
4370 pline("Error adding the message type.");
4373 goto msgtypes_again
;
4374 } else { /* list (1) or remove (2) */
4375 int pick_idx
, pick_cnt
;
4379 menu_item
*pick_list
= (menu_item
*) 0;
4380 struct plinemsg_type
*tmp
= plinemsg_types
;
4382 tmpwin
= create_nhwindow(NHW_MENU
);
4387 mtype
= msgtype2name(tmp
->msgtype
);
4388 any
.a_int
= ++mt_idx
;
4389 Sprintf(mtbuf
, "%-5s \"", mtype
);
4390 ln
= sizeof mtbuf
- strlen(mtbuf
) - sizeof "\"";
4391 if (strlen(tmp
->pattern
) > ln
)
4392 Strcat(strncat(mtbuf
, tmp
->pattern
, ln
- 3), "...\"");
4394 Strcat(mtbuf
, "\"");
4395 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, mtbuf
,
4399 Sprintf(mtbuf
, "%s message types",
4400 (opt_idx
== 1) ? "List of" : "Remove which");
4401 end_menu(tmpwin
, mtbuf
);
4402 pick_cnt
= select_menu(tmpwin
,
4403 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4406 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4407 free_one_msgtype(pick_list
[pick_idx
].item
.a_int
- 1
4409 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4411 destroy_nhwindow(tmpwin
);
4413 goto msgtypes_again
;
4415 } else if (!strcmp("menucolors", optname
)) {
4416 int opt_idx
, nmc
, mcclr
, mcattr
;
4420 nmc
= count_menucolors();
4421 opt_idx
= handle_add_list_remove("menucolor", nmc
);
4422 if (opt_idx
== 3) { /* done */
4424 } else if (opt_idx
== 0) { /* add new */
4425 getlin("What new menucolor pattern?", mcbuf
);
4426 if (*mcbuf
== '\033')
4429 && (mcclr
= query_color()) != -1
4430 && (mcattr
= query_attr((char *) 0)) != -1
4431 && !add_menu_coloring_parsed(mcbuf
, mcclr
, mcattr
)) {
4432 pline("Error adding the menu color.");
4435 goto menucolors_again
;
4436 } else { /* list (1) or remove (2) */
4437 int pick_idx
, pick_cnt
;
4440 const char *sattr
, *sclr
;
4441 menu_item
*pick_list
= (menu_item
*) 0;
4442 struct menucoloring
*tmp
= menu_colorings
;
4444 tmpwin
= create_nhwindow(NHW_MENU
);
4449 sattr
= attr2attrname(tmp
->attr
);
4450 sclr
= clr2colorname(tmp
->color
);
4451 any
.a_int
= ++mc_idx
;
4452 /* construct suffix */
4453 Sprintf(buf
, "\"\"=%s%s%s", sclr
,
4454 (tmp
->attr
!= ATR_NONE
) ? " & " : "",
4455 (tmp
->attr
!= ATR_NONE
) ? sattr
: "");
4456 /* now main string */
4457 ln
= sizeof buf
- strlen(buf
) - 1; /* length available */
4458 Strcpy(mcbuf
, "\"");
4459 if (strlen(tmp
->origstr
) > ln
)
4460 Strcat(strncat(mcbuf
, tmp
->origstr
, ln
- 3), "...");
4462 Strcat(mcbuf
, tmp
->origstr
);
4463 /* combine main string and suffix */
4464 Strcat(mcbuf
, &buf
[1]); /* skip buf[]'s initial quote */
4465 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, mcbuf
,
4469 Sprintf(mcbuf
, "%s menu colors",
4470 (opt_idx
== 1) ? "List of" : "Remove which");
4471 end_menu(tmpwin
, mcbuf
);
4472 pick_cnt
= select_menu(tmpwin
,
4473 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4476 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4477 free_one_menu_coloring(pick_list
[pick_idx
].item
.a_int
- 1
4479 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4481 destroy_nhwindow(tmpwin
);
4483 goto menucolors_again
;
4485 } else if (!strcmp("autopickup_exception", optname
)) {
4486 int opt_idx
, pass
, totalapes
= 0, numapes
[2] = { 0, 0 };
4487 char apebuf
[1 + BUFSZ
]; /* so &apebuf[1] is BUFSZ long for getlin() */
4488 struct autopickup_exception
*ape
;
4491 totalapes
= count_ape_maps(&numapes
[AP_LEAVE
], &numapes
[AP_GRAB
]);
4492 opt_idx
= handle_add_list_remove("autopickup exception", totalapes
);
4493 if (opt_idx
== 3) { /* done */
4495 } else if (opt_idx
== 0) { /* add new */
4496 getlin("What new autopickup exception pattern?", &apebuf
[1]);
4497 mungspaces(&apebuf
[1]); /* regularize whitespace */
4498 if (apebuf
[1] == '\033')
4502 /* guarantee room for \" prefix and \"\0 suffix;
4503 -2 is good enough for apebuf[] but -3 makes
4504 sure the whole thing fits within normal BUFSZ */
4505 apebuf
[sizeof apebuf
- 3] = '\0';
4506 Strcat(apebuf
, "\"");
4507 add_autopickup_exception(apebuf
);
4510 } else { /* list (1) or remove (2) */
4511 int pick_idx
, pick_cnt
;
4512 menu_item
*pick_list
= (menu_item
*) 0;
4514 tmpwin
= create_nhwindow(NHW_MENU
);
4516 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
4517 if (numapes
[pass
] == 0)
4519 ape
= iflags
.autopickup_exceptions
[pass
];
4521 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
4522 (pass
== 0) ? "Never pickup" : "Always pickup",
4524 for (i
= 0; i
< numapes
[pass
] && ape
; i
++) {
4525 any
.a_void
= (opt_idx
== 1) ? 0 : ape
;
4526 /* length of pattern plus quotes is less than BUFSZ */
4527 Sprintf(apebuf
, "\"%s\"", ape
->pattern
);
4528 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, apebuf
,
4533 Sprintf(apebuf
, "%s autopickup exceptions",
4534 (opt_idx
== 1) ? "List of" : "Remove which");
4535 end_menu(tmpwin
, apebuf
);
4536 pick_cnt
= select_menu(tmpwin
,
4537 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4540 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4541 remove_autopickup_exception(
4542 (struct autopickup_exception
*)
4543 pick_list
[pick_idx
].item
.a_void
);
4544 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4546 destroy_nhwindow(tmpwin
);
4550 } else if (!strcmp("symset", optname
)
4551 || !strcmp("roguesymset", optname
)) {
4552 menu_item
*symset_pick
= (menu_item
*) 0;
4553 boolean primaryflag
= (*optname
== 's'),
4554 rogueflag
= (*optname
== 'r'),
4555 ready_to_switch
= FALSE
,
4556 nothing_to_do
= FALSE
;
4557 char *symset_name
, fmtstr
[20];
4558 struct symsetentry
*sl
;
4559 int res
, which_set
, setcount
= 0, chosen
= -2;
4562 which_set
= ROGUESET
;
4564 which_set
= PRIMARY
;
4566 /* clear symset[].name as a flag to read_sym_file() to build list */
4567 symset_name
= symset
[which_set
].name
;
4568 symset
[which_set
].name
= (char *) 0;
4569 symset_list
= (struct symsetentry
*) 0;
4571 res
= read_sym_file(which_set
);
4572 if (res
&& symset_list
) {
4573 char symsetchoice
[BUFSZ
];
4574 int let
= 'a', biggest
= 0, thissize
= 0;
4578 /* check restrictions */
4579 if ((!rogueflag
&& sl
->rogue
)
4580 || (!primaryflag
&& sl
->primary
)) {
4585 /* find biggest name */
4587 thissize
= strlen(sl
->name
);
4588 if (thissize
> biggest
)
4593 pline("There are no appropriate %ssymbol sets available.",
4594 (rogueflag
) ? "rogue level "
4595 : (primaryflag
) ? "primary " : "");
4599 Sprintf(fmtstr
, "%%-%ds %%s", biggest
+ 5);
4600 tmpwin
= create_nhwindow(NHW_MENU
);
4604 add_menu(tmpwin
, NO_GLYPH
, &any
, let
++, 0, ATR_NONE
,
4605 "Default Symbols", MENU_UNSELECTED
);
4609 /* check restrictions */
4610 if ((!rogueflag
&& sl
->rogue
)
4611 || (!primaryflag
&& sl
->primary
)) {
4616 any
.a_int
= sl
->idx
+ 2;
4617 Sprintf(symsetchoice
, fmtstr
, sl
->name
,
4618 sl
->desc
? sl
->desc
: "");
4619 add_menu(tmpwin
, NO_GLYPH
, &any
, let
, 0, ATR_NONE
,
4620 symsetchoice
, MENU_UNSELECTED
);
4628 Sprintf(buf
, "Select %ssymbol set:", rogueflag
? "rogue level " : "");
4629 end_menu(tmpwin
, buf
);
4630 if (select_menu(tmpwin
, PICK_ONE
, &symset_pick
) > 0) {
4631 chosen
= symset_pick
->item
.a_int
- 2;
4632 free((genericptr_t
) symset_pick
);
4634 destroy_nhwindow(tmpwin
);
4637 /* chose an actual symset name from file */
4640 if (sl
->idx
== chosen
) {
4642 free((genericptr_t
) symset_name
);
4643 symset_name
= (char *) 0;
4645 /* free the now stale attributes */
4646 clear_symsetentry(which_set
, TRUE
);
4648 /* transfer only the name of the symbol set */
4649 symset
[which_set
].name
= dupstr(sl
->name
);
4650 ready_to_switch
= TRUE
;
4655 } else if (chosen
== -1) {
4656 /* explicit selection of defaults */
4657 /* free the now stale symset attributes */
4659 free((genericptr_t
) symset_name
);
4660 symset_name
= (char *) 0;
4662 clear_symsetentry(which_set
, TRUE
);
4664 nothing_to_do
= TRUE
;
4666 /* The symbols file could not be accessed */
4667 pline("Unable to access \"%s\" file.", SYMBOLS
);
4669 } else if (!symset_list
) {
4670 /* The symbols file was empty */
4671 pline("There were no symbol sets found in \"%s\".", SYMBOLS
);
4676 while (symset_list
) {
4679 free((genericptr_t
) sl
->name
);
4680 sl
->name
= (char *) 0;
4683 free((genericptr_t
) sl
->desc
);
4684 sl
->desc
= (char *) 0;
4686 symset_list
= sl
->next
;
4687 free((genericptr_t
) sl
);
4693 if (!symset
[which_set
].name
&& symset_name
)
4694 symset
[which_set
].name
= symset_name
; /* not dupstr() here */
4696 /* Set default symbols and clear the handling value */
4702 if (symset
[which_set
].name
) {
4703 if (read_sym_file(which_set
)) {
4704 ready_to_switch
= TRUE
;
4706 clear_symsetentry(which_set
, TRUE
);
4711 if (ready_to_switch
)
4712 switch_symbols(TRUE
);
4714 if (Is_rogue_level(&u
.uz
)) {
4716 assign_graphics(ROGUESET
);
4717 } else if (!rogueflag
)
4718 assign_graphics(PRIMARY
);
4723 /* didn't match any of the special options */
4729 #define rolestring(val, array, field) \
4730 ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none)
4732 /* This is ugly. We have all the option names in the compopt[] array,
4733 but we need to look at each option individually to get the value. */
4734 STATIC_OVL
const char *
4735 get_compopt_value(optname
, buf
)
4736 const char *optname
;
4739 char ocl
[MAXOCLASSES
+ 1];
4740 static const char none
[] = "(none)", randomrole
[] = "random",
4741 to_be_done
[] = "(to be done)", defopt
[] = "default",
4746 if (!strcmp(optname
, "align_message"))
4748 iflags
.wc_align_message
== ALIGN_TOP
4750 : iflags
.wc_align_message
== ALIGN_LEFT
4752 : iflags
.wc_align_message
== ALIGN_BOTTOM
4754 : iflags
.wc_align_message
== ALIGN_RIGHT
4757 else if (!strcmp(optname
, "align_status"))
4759 iflags
.wc_align_status
== ALIGN_TOP
4761 : iflags
.wc_align_status
== ALIGN_LEFT
4763 : iflags
.wc_align_status
== ALIGN_BOTTOM
4765 : iflags
.wc_align_status
== ALIGN_RIGHT
4768 else if (!strcmp(optname
, "align"))
4769 Sprintf(buf
, "%s", rolestring(flags
.initalign
, aligns
, adj
));
4771 else if (!strcmp(optname
, "altkeyhandler"))
4773 iflags
.altkeyhandler
[0] ? iflags
.altkeyhandler
: "default");
4775 #ifdef BACKWARD_COMPAT
4776 else if (!strcmp(optname
, "boulder"))
4780 : showsyms
[(int) objects
[BOULDER
].oc_class
+ SYM_OFF_O
]);
4782 else if (!strcmp(optname
, "catname"))
4783 Sprintf(buf
, "%s", catname
[0] ? catname
: none
);
4784 else if (!strcmp(optname
, "disclose"))
4785 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4787 (void) strkitten(buf
, ' ');
4788 (void) strkitten(buf
, flags
.end_disclose
[i
]);
4789 (void) strkitten(buf
, disclosure_options
[i
]);
4791 else if (!strcmp(optname
, "dogname"))
4792 Sprintf(buf
, "%s", dogname
[0] ? dogname
: none
);
4793 else if (!strcmp(optname
, "dungeon"))
4794 Sprintf(buf
, "%s", to_be_done
);
4795 else if (!strcmp(optname
, "effects"))
4796 Sprintf(buf
, "%s", to_be_done
);
4797 else if (!strcmp(optname
, "font_map"))
4798 Sprintf(buf
, "%s", iflags
.wc_font_map
? iflags
.wc_font_map
: defopt
);
4799 else if (!strcmp(optname
, "font_message"))
4801 iflags
.wc_font_message
? iflags
.wc_font_message
: defopt
);
4802 else if (!strcmp(optname
, "font_status"))
4804 iflags
.wc_font_status
? iflags
.wc_font_status
: defopt
);
4805 else if (!strcmp(optname
, "font_menu"))
4807 iflags
.wc_font_menu
? iflags
.wc_font_menu
: defopt
);
4808 else if (!strcmp(optname
, "font_text"))
4810 iflags
.wc_font_text
? iflags
.wc_font_text
: defopt
);
4811 else if (!strcmp(optname
, "font_size_map")) {
4812 if (iflags
.wc_fontsiz_map
)
4813 Sprintf(buf
, "%d", iflags
.wc_fontsiz_map
);
4815 Strcpy(buf
, defopt
);
4816 } else if (!strcmp(optname
, "font_size_message")) {
4817 if (iflags
.wc_fontsiz_message
)
4818 Sprintf(buf
, "%d", iflags
.wc_fontsiz_message
);
4820 Strcpy(buf
, defopt
);
4821 } else if (!strcmp(optname
, "font_size_status")) {
4822 if (iflags
.wc_fontsiz_status
)
4823 Sprintf(buf
, "%d", iflags
.wc_fontsiz_status
);
4825 Strcpy(buf
, defopt
);
4826 } else if (!strcmp(optname
, "font_size_menu")) {
4827 if (iflags
.wc_fontsiz_menu
)
4828 Sprintf(buf
, "%d", iflags
.wc_fontsiz_menu
);
4830 Strcpy(buf
, defopt
);
4831 } else if (!strcmp(optname
, "font_size_text")) {
4832 if (iflags
.wc_fontsiz_text
)
4833 Sprintf(buf
, "%d", iflags
.wc_fontsiz_text
);
4835 Strcpy(buf
, defopt
);
4836 } else if (!strcmp(optname
, "fruit"))
4837 Sprintf(buf
, "%s", pl_fruit
);
4838 else if (!strcmp(optname
, "gender"))
4839 Sprintf(buf
, "%s", rolestring(flags
.initgend
, genders
, adj
));
4840 else if (!strcmp(optname
, "horsename"))
4841 Sprintf(buf
, "%s", horsename
[0] ? horsename
: none
);
4842 else if (!strcmp(optname
, "map_mode"))
4844 iflags
.wc_map_mode
== MAP_MODE_TILES
4846 : iflags
.wc_map_mode
== MAP_MODE_ASCII4x6
4848 : iflags
.wc_map_mode
== MAP_MODE_ASCII6x8
4850 : iflags
.wc_map_mode
== MAP_MODE_ASCII8x8
4852 : iflags
.wc_map_mode
== MAP_MODE_ASCII16x8
4854 : iflags
.wc_map_mode
== MAP_MODE_ASCII7x12
4856 : iflags
.wc_map_mode
== MAP_MODE_ASCII8x12
4858 : iflags
.wc_map_mode
4859 == MAP_MODE_ASCII16x12
4861 : iflags
.wc_map_mode
4862 == MAP_MODE_ASCII12x16
4864 : iflags
.wc_map_mode
4865 == MAP_MODE_ASCII10x18
4867 : iflags
.wc_map_mode
4868 == MAP_MODE_ASCII_FIT_TO_SCREEN
4871 else if (!strcmp(optname
, "menustyle"))
4872 Sprintf(buf
, "%s", menutype
[(int) flags
.menu_style
]);
4873 else if (!strcmp(optname
, "menu_deselect_all"))
4874 Sprintf(buf
, "%s", to_be_done
);
4875 else if (!strcmp(optname
, "menu_deselect_page"))
4876 Sprintf(buf
, "%s", to_be_done
);
4877 else if (!strcmp(optname
, "menu_first_page"))
4878 Sprintf(buf
, "%s", to_be_done
);
4879 else if (!strcmp(optname
, "menu_invert_all"))
4880 Sprintf(buf
, "%s", to_be_done
);
4881 else if (!strcmp(optname
, "menu_headings"))
4882 Sprintf(buf
, "%s", attr2attrname(iflags
.menu_headings
));
4883 else if (!strcmp(optname
, "menu_invert_page"))
4884 Sprintf(buf
, "%s", to_be_done
);
4885 else if (!strcmp(optname
, "menu_last_page"))
4886 Sprintf(buf
, "%s", to_be_done
);
4887 else if (!strcmp(optname
, "menu_next_page"))
4888 Sprintf(buf
, "%s", to_be_done
);
4889 else if (!strcmp(optname
, "menu_previous_page"))
4890 Sprintf(buf
, "%s", to_be_done
);
4891 else if (!strcmp(optname
, "menu_search"))
4892 Sprintf(buf
, "%s", to_be_done
);
4893 else if (!strcmp(optname
, "menu_select_all"))
4894 Sprintf(buf
, "%s", to_be_done
);
4895 else if (!strcmp(optname
, "menu_select_page"))
4896 Sprintf(buf
, "%s", to_be_done
);
4897 else if (!strcmp(optname
, "monsters")) {
4898 Sprintf(buf
, "%s", to_be_done
);
4899 } else if (!strcmp(optname
, "msghistory")) {
4900 Sprintf(buf
, "%u", iflags
.msg_history
);
4902 } else if (!strcmp(optname
, "msg_window")) {
4903 Sprintf(buf
, "%s", (iflags
.prevmsg_window
== 's')
4905 : (iflags
.prevmsg_window
== 'c')
4907 : (iflags
.prevmsg_window
== 'f')
4911 } else if (!strcmp(optname
, "name")) {
4912 Sprintf(buf
, "%s", plname
);
4913 } else if (!strcmp(optname
, "number_pad")) {
4914 static const char *numpadmodes
[] = {
4915 "0=off", "1=on", "2=on, MSDOS compatible",
4916 "3=on, phone-style layout",
4917 "4=on, phone layout, MSDOS compatible",
4918 "-1=off, y & z swapped", /*[5]*/
4920 int indx
= Cmd
.num_pad
4921 ? (Cmd
.phone_layout
? (Cmd
.pcHack_compat
? 4 : 3)
4922 : (Cmd
.pcHack_compat
? 2 : 1))
4923 : Cmd
.swap_yz
? 5 : 0;
4925 Strcpy(buf
, numpadmodes
[indx
]);
4926 } else if (!strcmp(optname
, "objects")) {
4927 Sprintf(buf
, "%s", to_be_done
);
4928 } else if (!strcmp(optname
, "packorder")) {
4929 oc_to_str(flags
.inv_order
, ocl
);
4930 Sprintf(buf
, "%s", ocl
);
4932 } else if (!strcmp(optname
, "palette")) {
4933 Sprintf(buf
, "%s", get_color_string());
4935 } else if (!strcmp(optname
, "paranoid_confirmation")) {
4936 char tmpbuf
[QBUFSZ
];
4939 if (ParanoidConfirm
)
4940 Strcat(tmpbuf
, " Confirm");
4942 Strcat(tmpbuf
, " quit");
4944 Strcat(tmpbuf
, " die");
4946 Strcat(tmpbuf
, " bones");
4948 Strcat(tmpbuf
, " attack");
4950 Strcat(tmpbuf
, " pray");
4952 Strcat(tmpbuf
, " Remove");
4953 Strcpy(buf
, tmpbuf
[0] ? &tmpbuf
[1] : "none");
4954 } else if (!strcmp(optname
, "pettype")) {
4955 Sprintf(buf
, "%s", (preferred_pet
== 'c') ? "cat"
4956 : (preferred_pet
== 'd') ? "dog"
4957 : (preferred_pet
== 'h') ? "horse"
4958 : (preferred_pet
== 'n') ? "none"
4960 } else if (!strcmp(optname
, "pickup_burden")) {
4961 Sprintf(buf
, "%s", burdentype
[flags
.pickup_burden
]);
4962 } else if (!strcmp(optname
, "pickup_types")) {
4963 oc_to_str(flags
.pickup_types
, ocl
);
4964 Sprintf(buf
, "%s", ocl
[0] ? ocl
: "all");
4965 } else if (!strcmp(optname
, "pile_limit")) {
4966 Sprintf(buf
, "%d", flags
.pile_limit
);
4967 } else if (!strcmp(optname
, "playmode")) {
4968 Strcpy(buf
, wizard
? "debug" : discover
? "explore" : "normal");
4969 } else if (!strcmp(optname
, "race")) {
4970 Sprintf(buf
, "%s", rolestring(flags
.initrace
, races
, noun
));
4971 } else if (!strcmp(optname
, "roguesymset")) {
4973 symset
[ROGUESET
].name
? symset
[ROGUESET
].name
: "default");
4974 if (currentgraphics
== ROGUESET
&& symset
[ROGUESET
].name
)
4975 Strcat(buf
, ", active");
4976 } else if (!strcmp(optname
, "role")) {
4977 Sprintf(buf
, "%s", rolestring(flags
.initrole
, roles
, name
.m
));
4978 } else if (!strcmp(optname
, "runmode")) {
4979 Sprintf(buf
, "%s", runmodes
[flags
.runmode
]);
4980 } else if (!strcmp(optname
, "whatis_coord")) {
4982 (iflags
.getpos_coords
== GPCOORDS_MAP
) ? "map"
4983 : (iflags
.getpos_coords
== GPCOORDS_COMPASS
) ? "compass"
4984 : (iflags
.getpos_coords
== GPCOORDS_COMFULL
) ? "full compass"
4985 : (iflags
.getpos_coords
== GPCOORDS_SCREEN
) ? "screen"
4987 } else if (!strcmp(optname
, "scores")) {
4988 Sprintf(buf
, "%d top/%d around%s", flags
.end_top
, flags
.end_around
,
4989 flags
.end_own
? "/own" : "");
4990 } else if (!strcmp(optname
, "scroll_amount")) {
4991 if (iflags
.wc_scroll_amount
)
4992 Sprintf(buf
, "%d", iflags
.wc_scroll_amount
);
4994 Strcpy(buf
, defopt
);
4995 } else if (!strcmp(optname
, "scroll_margin")) {
4996 if (iflags
.wc_scroll_margin
)
4997 Sprintf(buf
, "%d", iflags
.wc_scroll_margin
);
4999 Strcpy(buf
, defopt
);
5000 } else if (!strcmp(optname
, "sortloot")) {
5001 for (i
= 0; i
< SIZE(sortltype
); i
++)
5002 if (flags
.sortloot
== sortltype
[i
][0]) {
5003 Strcpy(buf
, sortltype
[i
]);
5006 } else if (!strcmp(optname
, "player_selection")) {
5007 Sprintf(buf
, "%s", iflags
.wc_player_selection
? "prompts" : "dialog");
5009 } else if (!strcmp(optname
, "soundcard")) {
5010 Sprintf(buf
, "%s", to_be_done
);
5012 } else if (!strcmp(optname
, "suppress_alert")) {
5013 if (flags
.suppress_alert
== 0L)
5016 Sprintf(buf
, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ
,
5017 FEATURE_NOTICE_VER_MIN
, FEATURE_NOTICE_VER_PATCH
);
5018 } else if (!strcmp(optname
, "symset")) {
5020 symset
[PRIMARY
].name
? symset
[PRIMARY
].name
: "default");
5021 if (currentgraphics
== PRIMARY
&& symset
[PRIMARY
].name
)
5022 Strcat(buf
, ", active");
5023 } else if (!strcmp(optname
, "tile_file")) {
5025 iflags
.wc_tile_file
? iflags
.wc_tile_file
: defopt
);
5026 } else if (!strcmp(optname
, "tile_height")) {
5027 if (iflags
.wc_tile_height
)
5028 Sprintf(buf
, "%d", iflags
.wc_tile_height
);
5030 Strcpy(buf
, defopt
);
5031 } else if (!strcmp(optname
, "tile_width")) {
5032 if (iflags
.wc_tile_width
)
5033 Sprintf(buf
, "%d", iflags
.wc_tile_width
);
5035 Strcpy(buf
, defopt
);
5036 } else if (!strcmp(optname
, "traps")) {
5037 Sprintf(buf
, "%s", to_be_done
);
5038 } else if (!strcmp(optname
, "vary_msgcount")) {
5039 if (iflags
.wc_vary_msgcount
)
5040 Sprintf(buf
, "%d", iflags
.wc_vary_msgcount
);
5042 Strcpy(buf
, defopt
);
5044 } else if (!strcmp(optname
, "video")) {
5045 Sprintf(buf
, "%s", to_be_done
);
5048 } else if (!strcmp(optname
, "videoshades")) {
5049 Sprintf(buf
, "%s-%s-%s", shade
[0], shade
[1], shade
[2]);
5050 } else if (!strcmp(optname
, "videocolors")) {
5051 Sprintf(buf
, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
5052 ttycolors
[CLR_RED
], ttycolors
[CLR_GREEN
],
5053 ttycolors
[CLR_BROWN
], ttycolors
[CLR_BLUE
],
5054 ttycolors
[CLR_MAGENTA
], ttycolors
[CLR_CYAN
],
5055 ttycolors
[CLR_ORANGE
], ttycolors
[CLR_BRIGHT_GREEN
],
5056 ttycolors
[CLR_YELLOW
], ttycolors
[CLR_BRIGHT_BLUE
],
5057 ttycolors
[CLR_BRIGHT_MAGENTA
], ttycolors
[CLR_BRIGHT_CYAN
]);
5058 #endif /* VIDEOSHADES */
5059 } else if (!strcmp(optname
, "windowtype")) {
5060 Sprintf(buf
, "%s", windowprocs
.name
);
5061 } else if (!strcmp(optname
, "windowcolors")) {
5063 buf
, "%s/%s %s/%s %s/%s %s/%s",
5064 iflags
.wc_foregrnd_menu
? iflags
.wc_foregrnd_menu
: defbrief
,
5065 iflags
.wc_backgrnd_menu
? iflags
.wc_backgrnd_menu
: defbrief
,
5066 iflags
.wc_foregrnd_message
? iflags
.wc_foregrnd_message
5068 iflags
.wc_backgrnd_message
? iflags
.wc_backgrnd_message
5070 iflags
.wc_foregrnd_status
? iflags
.wc_foregrnd_status
: defbrief
,
5071 iflags
.wc_backgrnd_status
? iflags
.wc_backgrnd_status
: defbrief
,
5072 iflags
.wc_foregrnd_text
? iflags
.wc_foregrnd_text
: defbrief
,
5073 iflags
.wc_backgrnd_text
? iflags
.wc_backgrnd_text
: defbrief
);
5074 #ifdef PREFIXES_IN_USE
5076 for (i
= 0; i
< PREFIX_COUNT
; ++i
)
5077 if (!strcmp(optname
, fqn_prefix_names
[i
]) && fqn_prefix
[i
])
5078 Sprintf(buf
, "%s", fqn_prefix
[i
]);
5091 char buf
[BUFSZ
], ocl
[MAXOCLASSES
+ 1];
5093 flags
.pickup
= !flags
.pickup
;
5095 oc_to_str(flags
.pickup_types
, ocl
);
5096 Sprintf(buf
, "ON, for %s objects%s", ocl
[0] ? ocl
: "all",
5097 (iflags
.autopickup_exceptions
[AP_LEAVE
]
5098 || iflags
.autopickup_exceptions
[AP_GRAB
])
5099 ? ((count_ape_maps((int *) 0, (int *) 0) == 1)
5100 ? ", with one exception"
5101 : ", with some exceptions")
5106 pline("Autopickup: %s.", buf
);
5111 add_autopickup_exception(mapping
)
5112 const char *mapping
;
5115 APE_regex_error
[] = "regex error in AUTOPICKUP_EXCEPTION",
5116 APE_syntax_error
[] = "syntax error in AUTOPICKUP_EXCEPTION";
5118 struct autopickup_exception
*ape
, **apehead
;
5119 char text
[256], end
;
5121 boolean grab
= FALSE
;
5123 /* scan length limit used to be 255, but smaller size allows the
5124 quoted value to fit within BUFSZ, simplifying formatting elsewhere;
5125 this used to ignore the possibility of trailing junk but now checks
5126 for it, accepting whitespace but rejecting anything else unless it
5127 starts with '#" for a comment */
5129 if ((n
= sscanf(mapping
, "\"<%253[^\"]\" %c", text
, &end
)) == 1
5130 || (n
== 2 && end
== '#')) {
5132 } else if ((n
= sscanf(mapping
, "\">%253[^\"]\" %c", text
, &end
)) == 1
5133 || (n
= sscanf(mapping
, "\"%253[^\"]\" %c", text
, &end
)) == 1
5134 || (n
== 2 && end
== '#')) {
5137 if (!iflags
.window_inited
)
5138 raw_print(APE_syntax_error
); /* from options file */
5140 pline("%s", APE_syntax_error
); /* via 'O' command */
5144 ape
= (struct autopickup_exception
*) alloc(sizeof *ape
);
5145 ape
->regex
= regex_init();
5146 if (!regex_compile(text
, ape
->regex
)) {
5147 if (!iflags
.window_inited
)
5148 raw_print(APE_regex_error
);
5150 pline("%s", APE_regex_error
);
5151 regex_free(ape
->regex
);
5152 free((genericptr_t
) ape
);
5155 apehead
= (grab
) ? &iflags
.autopickup_exceptions
[AP_GRAB
]
5156 : &iflags
.autopickup_exceptions
[AP_LEAVE
];
5158 ape
->pattern
= dupstr(text
);
5160 ape
->next
= *apehead
;
5166 remove_autopickup_exception(whichape
)
5167 struct autopickup_exception
*whichape
;
5169 struct autopickup_exception
*ape
, *prev
= 0;
5170 int chain
= whichape
->grab
? AP_GRAB
: AP_LEAVE
;
5172 for (ape
= iflags
.autopickup_exceptions
[chain
]; ape
;) {
5173 if (ape
== whichape
) {
5174 struct autopickup_exception
*freeape
= ape
;
5180 iflags
.autopickup_exceptions
[chain
] = ape
;
5181 regex_free(freeape
->regex
);
5182 free((genericptr_t
) freeape
->pattern
);
5183 free((genericptr_t
) freeape
);
5192 count_ape_maps(leave
, grab
)
5195 struct autopickup_exception
*ape
;
5196 int pass
, totalapes
, numapes
[2] = { 0, 0 };
5198 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
5199 ape
= iflags
.autopickup_exceptions
[pass
];
5205 totalapes
= numapes
[AP_LEAVE
] + numapes
[AP_GRAB
];
5207 *leave
= numapes
[AP_LEAVE
];
5209 *grab
= numapes
[AP_GRAB
];
5214 free_autopickup_exceptions()
5216 struct autopickup_exception
*ape
;
5219 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
5220 while ((ape
= iflags
.autopickup_exceptions
[pass
]) != 0) {
5221 regex_free(ape
->regex
);
5222 free((genericptr_t
) ape
->pattern
);
5223 iflags
.autopickup_exceptions
[pass
] = ape
->next
;
5224 free((genericptr_t
) ape
);
5229 /* bundle some common usage into one easy-to-use routine */
5231 load_symset(s
, which_set
)
5235 clear_symsetentry(which_set
, TRUE
);
5237 if (symset
[which_set
].name
)
5238 free((genericptr_t
) symset
[which_set
].name
);
5239 symset
[which_set
].name
= dupstr(s
);
5241 if (read_sym_file(which_set
)) {
5242 switch_symbols(TRUE
);
5244 clear_symsetentry(which_set
, TRUE
);
5253 clear_symsetentry(PRIMARY
, TRUE
);
5254 clear_symsetentry(ROGUESET
, TRUE
);
5256 /* symset_list is cleaned up as soon as it's used, so we shouldn't
5257 have to anything about it here */
5258 /* assert( symset_list == NULL ); */
5261 /* Parse the value of a SYMBOLS line from a config file */
5264 register char *opts
;
5267 char *op
, *symname
, *strval
;
5268 struct symparse
*symp
;
5270 if ((op
= index(opts
, ',')) != 0) {
5272 if (!parsesymbols(op
)) return FALSE
;
5275 /* S_sample:string */
5277 strval
= index(opts
, ':');
5279 strval
= index(opts
, '=');
5284 /* strip leading and trailing white space from symname and strval */
5285 mungspaces(symname
);
5288 symp
= match_sym(symname
);
5292 if (symp
->range
&& symp
->range
!= SYM_CONTROL
) {
5293 val
= sym_val(strval
);
5294 update_l_symset(symp
, val
);
5303 size_t len
= strlen(buf
);
5304 const char *p
= index(buf
, ':'), *q
= index(buf
, '=');
5305 struct symparse
*sp
= loadsyms
;
5307 if (!p
|| (q
&& q
< p
))
5310 /* note: there will be at most one space before the '='
5311 because caller has condensed buf[] with mungspaces() */
5312 if (p
> buf
&& p
[-1] == ' ')
5314 len
= (int) (p
- buf
);
5317 if ((len
>= strlen(sp
->name
)) && !strncmpi(buf
, sp
->name
, len
))
5321 return (struct symparse
*) 0;
5331 if (!strval
[0] || !strval
[1]) { /* empty, or single character */
5332 /* if single char is space or tab, leave buf[0]=='\0' */
5333 if (!isspace((uchar
) strval
[0]))
5335 } else if (strval
[0] == '\'') { /* single quote */
5336 /* simple matching single quote; we know strval[1] isn't '\0' */
5337 if (strval
[2] == '\'' && !strval
[3]) {
5338 /* accepts '\' as backslash and ''' as single quote */
5341 /* if backslash, handle single or double quote or second backslash */
5342 } else if (strval
[1] == '\\' && strval
[2] && strval
[3] == '\''
5343 && index("'\"\\", strval
[2]) && !strval
[4]) {
5346 /* not simple quote or basic backslash;
5347 strip closing quote and let escapes() deal with it */
5349 char *p
, tmp
[QBUFSZ
];
5351 (void) strncpy(tmp
, strval
+ 1, sizeof tmp
- 1);
5352 tmp
[sizeof tmp
- 1] = '\0';
5353 if ((p
= rindex(tmp
, '\'')) != 0) {
5356 } /* else buf[0] stays '\0' */
5358 } else /* not lone char nor single quote */
5359 escapes(strval
, buf
);
5364 /* data for option_help() */
5365 static const char *opt_intro
[] = {
5366 "", " NetHack Options Help:", "",
5367 #define CONFIG_SLOT 3 /* fill in next value at run-time */
5369 #if !defined(MICRO) && !defined(MAC)
5370 "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
5372 "(<options> is a list of options separated by commas)",
5374 "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
5376 "or press \"O\" while playing and use the menu.", "",
5377 "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
5381 static const char *opt_epilog
[] = {
5383 "Some of the options can be set only before the game is started; those",
5384 "items will not be selectable in the 'O' command's menu.", (char *) 0
5390 char buf
[BUFSZ
], buf2
[BUFSZ
];
5394 datawin
= create_nhwindow(NHW_TEXT
);
5395 Sprintf(buf
, "Set options as OPTIONS=<options> in %s", configfile
);
5396 opt_intro
[CONFIG_SLOT
] = (const char *) buf
;
5397 for (i
= 0; opt_intro
[i
]; i
++)
5398 putstr(datawin
, 0, opt_intro
[i
]);
5400 /* Boolean options */
5401 for (i
= 0; boolopt
[i
].name
; i
++) {
5402 if (boolopt
[i
].addr
) {
5403 if (boolopt
[i
].addr
== &iflags
.sanity_check
&& !wizard
)
5405 if (boolopt
[i
].addr
== &iflags
.menu_tab_sep
&& !wizard
)
5407 next_opt(datawin
, boolopt
[i
].name
);
5410 next_opt(datawin
, "");
5412 /* Compound options */
5413 putstr(datawin
, 0, "Compound options:");
5414 for (i
= 0; compopt
[i
].name
; i
++) {
5415 Sprintf(buf2
, "`%s'", compopt
[i
].name
);
5416 Sprintf(buf
, "%-20s - %s%c", buf2
, compopt
[i
].descr
,
5417 compopt
[i
+ 1].name
? ',' : '.');
5418 putstr(datawin
, 0, buf
);
5421 for (i
= 0; opt_epilog
[i
]; i
++)
5422 putstr(datawin
, 0, opt_epilog
[i
]);
5424 display_nhwindow(datawin
, FALSE
);
5425 destroy_nhwindow(datawin
);
5430 * prints the next boolean option, on the same line if possible, on a new
5431 * line if not. End with next_opt("").
5434 next_opt(datawin
, str
)
5438 static char *buf
= 0;
5443 *(buf
= (char *) alloc(BUFSZ
)) = '\0';
5447 if (s
> &buf
[1] && s
[-2] == ',')
5448 Strcpy(s
- 2, "."); /* replace last ", " */
5449 i
= COLNO
; /* (greater than COLNO - 2) */
5451 i
= strlen(buf
) + strlen(str
) + 2;
5454 if (i
> COLNO
- 2) { /* rule of thumb */
5455 putstr(datawin
, 0, buf
);
5462 putstr(datawin
, 0, str
);
5463 free((genericptr_t
) buf
), buf
= 0;
5468 /* Returns the fid of the fruit type; if that type already exists, it
5469 * returns the fid of that one; if it does not exist, it adds a new fruit
5470 * type to the chain and returns the new one.
5471 * If replace_fruit is sent in, replace the fruit in the chain rather than
5472 * adding a new entry--for user specified fruits only.
5475 fruitadd(str
, replace_fruit
)
5477 struct fruit
*replace_fruit
;
5480 register struct fruit
*f
;
5481 int highest_fruit_id
= 0;
5482 char buf
[PL_FSIZ
], altname
[PL_FSIZ
];
5483 boolean user_specified
= (str
== pl_fruit
);
5484 /* if not user-specified, then it's a fruit name for a fruit on
5488 /* Note: every fruit has an id (kept in obj->spe) of at least 1;
5491 if (user_specified
) {
5492 boolean found
= FALSE
, numeric
= FALSE
;
5494 /* force fruit to be singular; this handling is not
5495 needed--or wanted--for fruits from bones because
5496 they already received it in their original game */
5497 nmcpy(pl_fruit
, makesingular(str
), PL_FSIZ
);
5498 /* assert( str == pl_fruit ); */
5500 /* disallow naming after other foods (since it'd be impossible
5501 * to tell the difference)
5504 for (i
= bases
[FOOD_CLASS
]; objects
[i
].oc_class
== FOOD_CLASS
; i
++) {
5505 if (!strcmp(OBJ_NAME(objects
[i
]), pl_fruit
)) {
5515 for (c
= pl_fruit
; *c
>= '0' && *c
<= '9'; c
++)
5517 if (isspace((uchar
) *c
) || *c
== 0)
5520 if (found
|| numeric
|| !strncmp(str
, "cursed ", 7)
5521 || !strncmp(str
, "uncursed ", 9) || !strncmp(str
, "blessed ", 8)
5522 || !strncmp(str
, "partly eaten ", 13)
5523 || (!strncmp(str
, "tin of ", 7)
5524 && (!strcmp(str
+ 7, "spinach")
5525 || name_to_mon(str
+ 7) >= LOW_PM
))
5526 || !strcmp(str
, "empty tin")
5527 || ((str_end_is(str
, " corpse")
5528 || str_end_is(str
, " egg"))
5529 && name_to_mon(str
) >= LOW_PM
)) {
5530 Strcpy(buf
, pl_fruit
);
5531 Strcpy(pl_fruit
, "candied ");
5532 nmcpy(pl_fruit
+ 8, buf
, PL_FSIZ
- 8);
5535 /* This flag indicates that a fruit has been made since the
5536 * last time the user set the fruit. If it hasn't, we can
5537 * safely overwrite the current fruit, preventing the user from
5538 * setting many fruits in a row and overflowing.
5539 * Possible expansion: check for specific fruit IDs, not for
5542 flags
.made_fruit
= FALSE
;
5543 if (replace_fruit
) {
5544 for (f
= ffruit
; f
; f
= f
->nextf
) {
5545 if (f
== replace_fruit
) {
5546 copynchars(f
->fname
, str
, PL_FSIZ
- 1);
5552 /* not user_supplied, so assumed to be from bones */
5553 copynchars(altname
, str
, PL_FSIZ
- 1);
5554 sanitize_name(altname
);
5555 flags
.made_fruit
= TRUE
; /* for safety. Any fruit name added from a
5556 bones level should exist anyway. */
5558 for (f
= ffruit
; f
; f
= f
->nextf
) {
5559 if (f
->fid
> highest_fruit_id
)
5560 highest_fruit_id
= f
->fid
;
5561 if (!strncmp(str
, f
->fname
, PL_FSIZ
- 1)
5562 || (*altname
&& !strcmp(altname
, f
->fname
)))
5565 /* if adding another fruit would overflow spe, use a random
5566 fruit instead... we've got a lot to choose from.
5567 current_fruit remains as is. */
5568 if (highest_fruit_id
>= 127)
5572 (void) memset((genericptr_t
)f
, 0, sizeof(struct fruit
));
5573 copynchars(f
->fname
, *altname
? altname
: str
, PL_FSIZ
- 1);
5574 f
->fid
= ++highest_fruit_id
;
5575 /* we used to go out of our way to add it at the end of the list,
5576 but the order is arbitrary so use simpler insertion at start */
5581 context
.current_fruit
= f
->fid
;
5586 * This is a somewhat generic menu for taking a list of NetHack style
5587 * class choices and presenting them via a description
5588 * rather than the traditional NetHack characters.
5589 * (Benefits users whose first exposure to NetHack is via tiles).
5592 * The title at the top of the menu.
5594 * category: 0 = monster class
5598 * FALSE = PICK_ONE, TRUE = PICK_ANY
5601 * a null terminated string containing the list of choices.
5604 * a null terminated string containing the selected characters.
5606 * Returns number selected.
5609 choose_classes_menu(prompt
, category
, way
, class_list
, class_select
)
5616 menu_item
*pick_list
= (menu_item
*) 0;
5622 int next_accelerator
, accelerator
;
5624 if (class_list
== (char *) 0 || class_select
== (char *) 0)
5627 next_accelerator
= 'a';
5629 win
= create_nhwindow(NHW_MENU
);
5631 while (*class_list
) {
5639 text
= def_monsyms
[def_char_to_monclass(*class_list
)].explain
;
5640 accelerator
= *class_list
;
5641 Sprintf(buf
, "%s", text
);
5644 text
= def_oc_syms
[def_char_to_objclass(*class_list
)].explain
;
5645 accelerator
= next_accelerator
;
5646 Sprintf(buf
, "%c %s", *class_list
, text
);
5649 impossible("choose_classes_menu: invalid category %d", category
);
5651 if (way
&& *class_select
) { /* Selections there already */
5652 if (index(class_select
, *class_list
)) {
5656 any
.a_int
= *class_list
;
5657 add_menu(win
, NO_GLYPH
, &any
, accelerator
, category
? *class_list
: 0,
5658 ATR_NONE
, buf
, selected
);
5662 if (next_accelerator
== ('z' + 1))
5663 next_accelerator
= 'A';
5664 if (next_accelerator
== ('Z' + 1))
5668 end_menu(win
, prompt
);
5669 n
= select_menu(win
, way
? PICK_ANY
: PICK_ONE
, &pick_list
);
5670 destroy_nhwindow(win
);
5672 for (i
= 0; i
< n
; ++i
)
5673 *class_select
++ = (char) pick_list
[i
].item
.a_int
;
5674 free((genericptr_t
) pick_list
);
5676 } else if (n
== -1) {
5677 class_select
= eos(class_select
);
5681 *class_select
= '\0';
5685 struct wc_Opt wc_options
[] = { { "ascii_map", WC_ASCII_MAP
},
5686 { "color", WC_COLOR
},
5687 { "eight_bit_tty", WC_EIGHT_BIT_IN
},
5688 { "hilite_pet", WC_HILITE_PET
},
5689 { "popup_dialog", WC_POPUP_DIALOG
},
5690 { "player_selection", WC_PLAYER_SELECTION
},
5691 { "preload_tiles", WC_PRELOAD_TILES
},
5692 { "tiled_map", WC_TILED_MAP
},
5693 { "tile_file", WC_TILE_FILE
},
5694 { "tile_width", WC_TILE_WIDTH
},
5695 { "tile_height", WC_TILE_HEIGHT
},
5696 { "use_inverse", WC_INVERSE
},
5697 { "align_message", WC_ALIGN_MESSAGE
},
5698 { "align_status", WC_ALIGN_STATUS
},
5699 { "font_map", WC_FONT_MAP
},
5700 { "font_menu", WC_FONT_MENU
},
5701 { "font_message", WC_FONT_MESSAGE
},
5703 {"perm_invent", WC_PERM_INVENT
},
5705 { "font_size_map", WC_FONTSIZ_MAP
},
5706 { "font_size_menu", WC_FONTSIZ_MENU
},
5707 { "font_size_message", WC_FONTSIZ_MESSAGE
},
5708 { "font_size_status", WC_FONTSIZ_STATUS
},
5709 { "font_size_text", WC_FONTSIZ_TEXT
},
5710 { "font_status", WC_FONT_STATUS
},
5711 { "font_text", WC_FONT_TEXT
},
5712 { "map_mode", WC_MAP_MODE
},
5713 { "scroll_amount", WC_SCROLL_AMOUNT
},
5714 { "scroll_margin", WC_SCROLL_MARGIN
},
5715 { "splash_screen", WC_SPLASH_SCREEN
},
5716 { "vary_msgcount", WC_VARY_MSGCOUNT
},
5717 { "windowcolors", WC_WINDOWCOLORS
},
5718 { "mouse_support", WC_MOUSE_SUPPORT
},
5719 { (char *) 0, 0L } };
5721 struct wc_Opt wc2_options
[] = { { "fullscreen", WC2_FULLSCREEN
},
5722 { "softkeyboard", WC2_SOFTKEYBOARD
},
5723 { "wraptext", WC2_WRAPTEXT
},
5724 { "use_darkgray", WC2_DARKGRAY
},
5725 #ifdef STATUS_VIA_WINDOWPORT
5726 { "hilite_status", WC2_HILITE_STATUS
},
5728 { (char *) 0, 0L } };
5731 * If a port wants to change or ensure that the SET_IN_SYS,
5732 * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
5733 * correct (for controlling its display in the option menu) call
5734 * set_option_mod_status()
5735 * with the appropriate second argument.
5738 set_option_mod_status(optnam
, status
)
5744 if (SET__IS_VALUE_VALID(status
)) {
5745 impossible("set_option_mod_status: status out of range %d.", status
);
5748 for (k
= 0; boolopt
[k
].name
; k
++) {
5749 if (!strncmpi(boolopt
[k
].name
, optnam
, strlen(optnam
))) {
5750 boolopt
[k
].optflags
= status
;
5754 for (k
= 0; compopt
[k
].name
; k
++) {
5755 if (!strncmpi(compopt
[k
].name
, optnam
, strlen(optnam
))) {
5756 compopt
[k
].optflags
= status
;
5763 * You can set several wc_options in one call to
5764 * set_wc_option_mod_status() by setting
5765 * the appropriate bits for each option that you
5766 * are setting in the optmask argument
5768 * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN,
5772 set_wc_option_mod_status(optmask
, status
)
5773 unsigned long optmask
;
5778 if (SET__IS_VALUE_VALID(status
)) {
5779 impossible("set_wc_option_mod_status: status out of range %d.",
5783 while (wc_options
[k
].wc_name
) {
5784 if (optmask
& wc_options
[k
].wc_bit
) {
5785 set_option_mod_status(wc_options
[k
].wc_name
, status
);
5792 is_wc_option(optnam
)
5797 while (wc_options
[k
].wc_name
) {
5798 if (strcmp(wc_options
[k
].wc_name
, optnam
) == 0)
5806 wc_supported(optnam
)
5811 while (wc_options
[k
].wc_name
) {
5812 if (!strcmp(wc_options
[k
].wc_name
, optnam
)
5813 && (windowprocs
.wincap
& wc_options
[k
].wc_bit
))
5821 * You can set several wc2_options in one call to
5822 * set_wc2_option_mod_status() by setting
5823 * the appropriate bits for each option that you
5824 * are setting in the optmask argument
5827 * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
5832 set_wc2_option_mod_status(optmask
, status
)
5833 unsigned long optmask
;
5838 if (SET__IS_VALUE_VALID(status
)) {
5839 impossible("set_wc2_option_mod_status: status out of range %d.",
5843 while (wc2_options
[k
].wc_name
) {
5844 if (optmask
& wc2_options
[k
].wc_bit
) {
5845 set_option_mod_status(wc2_options
[k
].wc_name
, status
);
5852 is_wc2_option(optnam
)
5857 while (wc2_options
[k
].wc_name
) {
5858 if (strcmp(wc2_options
[k
].wc_name
, optnam
) == 0)
5866 wc2_supported(optnam
)
5871 while (wc2_options
[k
].wc_name
) {
5872 if (!strcmp(wc2_options
[k
].wc_name
, optnam
)
5873 && (windowprocs
.wincap2
& wc2_options
[k
].wc_bit
))
5881 wc_set_font_name(opttype
, fontname
)
5885 char **fn
= (char **) 0;
5891 fn
= &iflags
.wc_font_map
;
5893 case MESSAGE_OPTION
:
5894 fn
= &iflags
.wc_font_message
;
5897 fn
= &iflags
.wc_font_text
;
5900 fn
= &iflags
.wc_font_menu
;
5903 fn
= &iflags
.wc_font_status
;
5910 free((genericptr_t
) *fn
);
5911 *fn
= dupstr(fontname
);
5917 wc_set_window_colors(op
)
5921 * menu white/black message green/yellow status white/blue text
5926 char *wn
, *tfg
, *tbg
, *newop
;
5927 static const char *wnames
[] = { "menu", "message", "status", "text" };
5928 static const char *shortnames
[] = { "mnu", "msg", "sts", "txt" };
5929 static char **fgp
[] = { &iflags
.wc_foregrnd_menu
,
5930 &iflags
.wc_foregrnd_message
,
5931 &iflags
.wc_foregrnd_status
,
5932 &iflags
.wc_foregrnd_text
};
5933 static char **bgp
[] = { &iflags
.wc_backgrnd_menu
,
5934 &iflags
.wc_backgrnd_message
,
5935 &iflags
.wc_backgrnd_status
,
5936 &iflags
.wc_backgrnd_text
};
5939 newop
= mungspaces(buf
);
5940 while (newop
&& *newop
) {
5941 wn
= tfg
= tbg
= (char *) 0;
5943 /* until first non-space in case there's leading spaces - before
5952 /* until first space - colorname*/
5953 while (*newop
&& *newop
!= ' ')
5961 /* until first non-space - before foreground*/
5969 /* until slash - foreground */
5970 while (*newop
&& *newop
!= '/')
5978 /* until first non-space (in case there's leading space after slash) -
5979 * before background */
5987 /* until first space - background */
5988 while (*newop
&& *newop
!= ' ')
5993 for (j
= 0; j
< 4; ++j
) {
5994 if (!strcmpi(wn
, wnames
[j
]) || !strcmpi(wn
, shortnames
[j
])) {
5995 if (tfg
&& !strstri(tfg
, " ")) {
5997 free((genericptr_t
) *fgp
[j
]);
5998 *fgp
[j
] = dupstr(tfg
);
6000 if (tbg
&& !strstri(tbg
, " ")) {
6002 free((genericptr_t
) *bgp
[j
]);
6003 *bgp
[j
] = dupstr(tbg
);
6012 /* set up for wizard mode if player or save file has requested to it;
6013 called from port-specific startup code to handle `nethack -D' or
6014 OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
6015 restoring a game which was saved in wizard mode */
6020 if (authorize_wizard_mode())
6021 Strcpy(plname
, "wizard");
6023 wizard
= FALSE
; /* not allowed or not available */
6024 /* force explore mode if we didn't make it into wizard mode */
6026 iflags
.deferred_X
= FALSE
;
6028 /* don't need to do anything special for explore mode or normal play */
6031 #endif /* OPTION_LISTS_ONLY */