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).
836 * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
837 * prior to terminating '\0' would pull that '\0' into the output and then
838 * keep processing past it, potentially overflowing the output buffer.
839 * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
840 * output and stop there; trailing \M will fall through to \<other> and
841 * yield 'M', then stop. Any \X or \O followed by something other than
842 * an appropriate digit will also fall through to \<other> and yield 'X'
843 * or 'O', plus stop if the non-digit is end-of-string.
850 static NEARDATA
const char oct
[] = "01234567", dec
[] = "0123456789",
851 hex
[] = "00112233445566778899aAbBcCdDeEfF";
853 int cval
, meta
, dcount
;
856 /* \M has to be followed by something to do meta conversion,
857 otherwise it will just be \M which ultimately yields 'M' */
858 meta
= (*cp
== '\\' && (cp
[1] == 'm' || cp
[1] == 'M') && cp
[2]);
862 cval
= dcount
= 0; /* for decimal, octal, hexadecimal cases */
863 if ((*cp
!= '\\' && *cp
!= '^') || !cp
[1]) {
864 /* simple character, or nothing left for \ or ^ to escape */
866 } else if (*cp
== '^') { /* expand control-character syntax */
867 cval
= (*++cp
& 0x1f);
870 /* remaining cases are all for backslash; we know cp[1] is not \0 */
871 } else if (index(dec
, cp
[1])) {
872 ++cp
; /* move past backslash to first digit */
874 cval
= (cval
* 10) + (*cp
- '0');
875 } while (*++cp
&& index(dec
, *cp
) && ++dcount
< 3);
876 } else if ((cp
[1] == 'o' || cp
[1] == 'O') && cp
[2]
877 && index(oct
, cp
[2])) {
878 cp
+= 2; /* move past backslash and 'O' */
880 cval
= (cval
* 8) + (*cp
- '0');
881 } while (*++cp
&& index(oct
, *cp
) && ++dcount
< 3);
882 } else if ((cp
[1] == 'x' || cp
[1] == 'X') && cp
[2]
883 && (dp
= index(hex
, cp
[2])) != 0) {
884 cp
+= 2; /* move past backslash and 'X' */
886 cval
= (cval
* 16) + ((int) (dp
- hex
) / 2);
887 } while (*++cp
&& (dp
= index(hex
, *cp
)) != 0 && ++dcount
< 2);
888 } else { /* C-style character escapes */
919 rejectoption(optname
)
923 pline("\"%s\" settable only from %s.", optname
, configfile
);
925 pline("%s can be set only from NETHACKOPTIONS or %s.", optname
,
931 badoptmsg(opts
, reason
)
933 const char *reason
; /* "Bad syntax" or "Missing value" */
935 const char *linesplit
= "";
938 if (!strncmp(opts
, "h", 1) || !strncmp(opts
, "?", 1))
941 pline("%s: %s. Enter \"?g\" for help.", reason
, opts
);
953 raw_printf("%s in OPTIONS in %s: %s%s.\n",
954 reason
, configfile
, linesplit
, opts
);
956 raw_printf("%s in NETHACKOPTIONS: %s%s.\n",
957 reason
, linesplit
, opts
);
965 badoptmsg(opts
, "Bad syntax");
969 string_for_opt(opts
, val_optional
)
971 boolean val_optional
;
973 char *colon
, *equals
;
975 colon
= index(opts
, ':');
976 equals
= index(opts
, '=');
977 if (!colon
|| (equals
&& equals
< colon
))
980 if (!colon
|| !*++colon
) {
982 badoptmsg(opts
, "Missing value");
989 string_for_env_opt(optname
, opts
, val_optional
)
992 boolean val_optional
;
995 rejectoption(optname
);
998 return string_for_opt(opts
, val_optional
);
1002 bad_negation(optname
, with_parameter
)
1003 const char *optname
;
1004 boolean with_parameter
;
1006 pline_The("%s option may not %sbe negated.", optname
,
1007 with_parameter
? "both have a value and " : "");
1011 * Change the inventory order, using the given string as the new order.
1012 * Missing characters in the new order are filled in at the end from
1013 * the current inv_order, except for gold, which is forced to be first
1014 * if not explicitly present.
1016 * This routine returns 1 unless there is a duplicate or bad char in
1020 change_inv_order(op
)
1024 char *sp
, buf
[QBUFSZ
];
1027 if (!index(op
, GOLD_SYM
))
1028 buf
[num
++] = COIN_CLASS
;
1030 for (sp
= op
; *sp
; sp
++) {
1031 oc_sym
= def_char_to_objclass(*sp
);
1032 /* reject bad or duplicate entries */
1033 if (oc_sym
== MAXOCLASSES
/* not an object class char */
1034 /* VENOM_CLASS, RANDOM_CLASS, and ILLOBJ_CLASS are excluded
1035 because they aren't in def_inv_order[] so don't make it
1036 into flags.inv_order, hence always fail this index() test */
1037 || !index(flags
.inv_order
, oc_sym
) || index(sp
+ 1, *sp
))
1039 /* retain good ones */
1040 buf
[num
++] = (char) oc_sym
;
1044 /* fill in any omitted classes, using previous ordering */
1045 for (sp
= flags
.inv_order
; *sp
; sp
++)
1046 if (!index(buf
, *sp
))
1047 (void) strkitten(&buf
[num
++], *sp
);
1048 buf
[MAXOCLASSES
- 1] = '\0';
1050 Strcpy(flags
.inv_order
, buf
);
1055 warning_opts(opts
, optype
)
1056 register char *opts
;
1059 uchar translate
[WARNCOUNT
];
1062 if (!(opts
= string_for_env_opt(optype
, opts
, FALSE
)))
1064 escapes(opts
, opts
);
1066 length
= (int) strlen(opts
);
1067 /* match the form obtained from PC configuration files */
1068 for (i
= 0; i
< WARNCOUNT
; i
++)
1069 translate
[i
] = (i
>= length
) ? 0
1070 : opts
[i
] ? (uchar
) opts
[i
]
1071 : def_warnsyms
[i
].sym
;
1072 assign_warnings(translate
);
1076 assign_warnings(graph_chars
)
1077 register uchar
*graph_chars
;
1081 for (i
= 0; i
< WARNCOUNT
; i
++)
1083 warnsyms
[i
] = graph_chars
[i
];
1087 feature_alert_opts(op
, optn
)
1092 boolean rejectver
= FALSE
;
1093 unsigned long fnv
= get_feature_notice_ver(op
); /* version.c */
1097 if (fnv
> get_current_feature_ver())
1100 flags
.suppress_alert
= fnv
;
1103 You_cant("disable new feature alerts for future versions.");
1106 "\n%s=%s Invalid reference to a future version ignored",
1113 Sprintf(buf
, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ
,
1114 FEATURE_NOTICE_VER_MIN
, FEATURE_NOTICE_VER_PATCH
);
1116 "Feature change alerts disabled for NetHack %s features and prior.",
1123 set_duplicate_opt_detection(on_or_off
)
1128 if (on_or_off
!= 0) {
1130 if (iflags
.opt_booldup
)
1131 impossible("iflags.opt_booldup already on (memory leak)");
1132 iflags
.opt_booldup
= (int *) alloc(SIZE(boolopt
) * sizeof(int));
1133 optptr
= iflags
.opt_booldup
;
1134 for (k
= 0; k
< SIZE(boolopt
); ++k
)
1137 if (iflags
.opt_compdup
)
1138 impossible("iflags.opt_compdup already on (memory leak)");
1139 iflags
.opt_compdup
= (int *) alloc(SIZE(compopt
) * sizeof(int));
1140 optptr
= iflags
.opt_compdup
;
1141 for (k
= 0; k
< SIZE(compopt
); ++k
)
1145 if (iflags
.opt_booldup
)
1146 free((genericptr_t
) iflags
.opt_booldup
);
1147 iflags
.opt_booldup
= (int *) 0;
1148 if (iflags
.opt_compdup
)
1149 free((genericptr_t
) iflags
.opt_compdup
);
1150 iflags
.opt_compdup
= (int *) 0;
1155 duplicate_opt_detection(opts
, iscompound
)
1157 int iscompound
; /* 0 == boolean option, 1 == compound */
1161 if (!iscompound
&& iflags
.opt_booldup
&& initial
&& from_file
) {
1162 for (i
= 0; boolopt
[i
].name
; i
++) {
1163 if (match_optname(opts
, boolopt
[i
].name
, 3, FALSE
)) {
1164 optptr
= iflags
.opt_booldup
+ i
;
1172 } else if (iscompound
&& iflags
.opt_compdup
&& initial
&& from_file
) {
1173 for (i
= 0; compopt
[i
].name
; i
++) {
1174 if (match_optname(opts
, compopt
[i
].name
, strlen(compopt
[i
].name
),
1176 optptr
= iflags
.opt_compdup
+ i
;
1189 complain_about_duplicate(opts
, iscompound
)
1191 int iscompound
; /* 0 == boolean option, 1 == compound */
1194 /* the Mac has trouble dealing with the output of messages while
1195 * processing the config file. That should get fixed one day.
1196 * For now just return.
1199 raw_printf("\nWarning - %s option specified multiple times: %s.\n",
1200 iscompound
? "compound" : "boolean", opts
);
1206 /* paranoia[] - used by parseoptions() and special_handling() */
1207 STATIC_VAR
const struct paranoia_opts
{
1208 int flagmask
; /* which paranoid option */
1209 const char *argname
; /* primary name */
1210 int argMinLen
; /* minimum number of letters to match */
1211 const char *synonym
; /* alternate name (optional) */
1213 const char *explain
; /* for interactive menu */
1215 /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
1216 takes precedence and "all" isn't present in the interactive menu,
1217 and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
1218 (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
1219 is just a synonym for "Confirm") */
1220 { PARANOID_CONFIRM
, "Confirm", 1, "Paranoia", 2,
1221 "for \"yes\" confirmations, require \"no\" to reject" },
1222 { PARANOID_QUIT
, "quit", 1, "explore", 1,
1223 "yes vs y to quit or to enter explore mode" },
1224 { PARANOID_DIE
, "die", 1, "death", 2,
1225 "yes vs y to die (explore mode or debug mode)" },
1226 { PARANOID_BONES
, "bones", 1, 0, 0,
1227 "yes vs y to save bones data when dying in debug mode" },
1228 { PARANOID_HIT
, "attack", 1, "hit", 1,
1229 "yes vs y to attack a peaceful monster" },
1230 { PARANOID_PRAY
, "pray", 1, 0, 0,
1231 "y to pray (supersedes old \"prayconfirm\" option)" },
1232 { PARANOID_REMOVE
, "Remove", 1, "Takeoff", 1,
1233 "always pick from inventory for Remove and Takeoff" },
1234 { PARANOID_BREAKWAND
, "wand", 1, "breakwand", 2,
1235 "yes vs y to break a wand" },
1236 /* for config file parsing; interactive menu skips these */
1237 { 0, "none", 4, 0, 0, 0 }, /* require full word match */
1238 { ~0, "all", 3, 0, 0, 0 }, /* ditto */
1241 extern struct menucoloring
*menu_colorings
;
1243 static const struct {
1247 { "black", CLR_BLACK
},
1249 { "green", CLR_GREEN
},
1250 { "brown", CLR_BROWN
},
1251 { "blue", CLR_BLUE
},
1252 { "magenta", CLR_MAGENTA
},
1253 { "cyan", CLR_CYAN
},
1254 { "gray", CLR_GRAY
},
1255 { "orange", CLR_ORANGE
},
1256 { "light green", CLR_BRIGHT_GREEN
},
1257 { "yellow", CLR_YELLOW
},
1258 { "light blue", CLR_BRIGHT_BLUE
},
1259 { "light magenta", CLR_BRIGHT_MAGENTA
},
1260 { "light cyan", CLR_BRIGHT_CYAN
},
1261 { "white", CLR_WHITE
},
1262 { NULL
, CLR_BLACK
}, /* everything after this is an alias */
1263 { "transparent", NO_COLOR
},
1264 { "nocolor", NO_COLOR
},
1265 { "purple", CLR_MAGENTA
},
1266 { "light purple", CLR_BRIGHT_MAGENTA
},
1267 { "bright purple", CLR_BRIGHT_MAGENTA
},
1268 { "grey", CLR_GRAY
},
1269 { "bright red", CLR_ORANGE
},
1270 { "bright green", CLR_BRIGHT_GREEN
},
1271 { "bright blue", CLR_BRIGHT_BLUE
},
1272 { "bright magenta", CLR_BRIGHT_MAGENTA
},
1273 { "bright cyan", CLR_BRIGHT_CYAN
}
1276 static const struct {
1280 { "none", ATR_NONE
},
1281 { "bold", ATR_BOLD
},
1283 { "underline", ATR_ULINE
},
1284 { "blink", ATR_BLINK
},
1285 { "inverse", ATR_INVERSE
}
1294 for (i
= 0; i
< SIZE(colornames
); i
++)
1295 if (colornames
[i
].name
&& colornames
[i
].color
== clr
)
1296 return colornames
[i
].name
;
1304 int i
, c
= NO_COLOR
;
1306 /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
1307 (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
1308 also copes with trailing space; mungspaces removed any leading space */
1309 for (i
= 0; i
< SIZE(colornames
); i
++)
1310 if (colornames
[i
].name
1311 && fuzzymatch(str
, colornames
[i
].name
, " -_", TRUE
)) {
1312 c
= colornames
[i
].color
;
1315 if (i
== SIZE(colornames
) && (*str
>= '0' && *str
<= '9'))
1320 STATIC_OVL
const char *
1326 for (i
= 0; i
< SIZE(attrnames
); i
++)
1327 if (attrnames
[i
].attr
== attr
)
1328 return attrnames
[i
].name
;
1338 menu_item
*picks
= (menu_item
*) 0;
1340 tmpwin
= create_nhwindow(NHW_MENU
);
1343 for (i
= 0; i
< SIZE(colornames
); i
++) {
1344 if (!colornames
[i
].name
)
1347 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, colornames
[i
].name
,
1350 end_menu(tmpwin
, "Pick a color");
1351 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1352 destroy_nhwindow(tmpwin
);
1354 i
= colornames
[picks
->item
.a_int
- 1].color
;
1355 free((genericptr_t
) picks
);
1368 menu_item
*picks
= (menu_item
*) 0;
1370 tmpwin
= create_nhwindow(NHW_MENU
);
1373 for (i
= 0; i
< SIZE(attrnames
); i
++) {
1375 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, attrnames
[i
].attr
,
1376 attrnames
[i
].name
, MENU_UNSELECTED
);
1378 end_menu(tmpwin
, prompt
? prompt
: "Pick an attribute");
1379 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1380 destroy_nhwindow(tmpwin
);
1382 i
= attrnames
[picks
->item
.a_int
- 1].attr
;
1383 free((genericptr_t
) picks
);
1389 static const struct {
1393 } msgtype_names
[] = {
1394 { "show", MSGTYP_NORMAL
, "Show message normally" },
1395 { "hide", MSGTYP_NOSHOW
, "Hide message" },
1396 { "noshow", MSGTYP_NOSHOW
, NULL
},
1397 { "stop", MSGTYP_STOP
, "Prompt for more after the message" },
1398 { "more", MSGTYP_STOP
, NULL
},
1399 { "norep", MSGTYP_NOREP
, "Do not repeat the message" }
1402 STATIC_OVL
const char *
1408 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1409 if (msgtype_names
[i
].descr
&& msgtype_names
[i
].msgtyp
== typ
)
1410 return msgtype_names
[i
].name
;
1420 menu_item
*picks
= (menu_item
*) 0;
1422 tmpwin
= create_nhwindow(NHW_MENU
);
1425 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1426 if (msgtype_names
[i
].descr
) {
1427 any
.a_int
= msgtype_names
[i
].msgtyp
+ 1;
1428 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1429 msgtype_names
[i
].descr
, MENU_UNSELECTED
);
1431 end_menu(tmpwin
, "How to show the message");
1432 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1433 destroy_nhwindow(tmpwin
);
1435 i
= picks
->item
.a_int
- 1;
1436 free((genericptr_t
) picks
);
1443 msgtype_add(typ
, pattern
)
1447 struct plinemsg_type
*tmp
1448 = (struct plinemsg_type
*) alloc(sizeof (struct plinemsg_type
));
1453 tmp
->regex
= regex_init();
1454 if (!regex_compile(pattern
, tmp
->regex
)) {
1455 static const char *re_error
= "MSGTYPE regex error";
1457 if (!iflags
.window_inited
)
1458 raw_printf("\n%s: %s\n", re_error
, regex_error_desc(tmp
->regex
));
1460 pline("%s: %s", re_error
, regex_error_desc(tmp
->regex
));
1462 regex_free(tmp
->regex
);
1463 free((genericptr_t
) tmp
);
1466 tmp
->pattern
= dupstr(pattern
);
1467 tmp
->next
= plinemsg_types
;
1468 plinemsg_types
= tmp
;
1475 struct plinemsg_type
*tmp
, *tmp2
= 0;
1477 for (tmp
= plinemsg_types
; tmp
; tmp
= tmp2
) {
1479 free((genericptr_t
) tmp
->pattern
);
1480 regex_free(tmp
->regex
);
1481 free((genericptr_t
) tmp
);
1483 plinemsg_types
= (struct plinemsg_type
*) 0;
1487 free_one_msgtype(idx
)
1490 struct plinemsg_type
*tmp
= plinemsg_types
;
1491 struct plinemsg_type
*prev
= NULL
;
1495 struct plinemsg_type
*next
= tmp
->next
;
1497 regex_free(tmp
->regex
);
1498 free((genericptr_t
) tmp
->pattern
);
1499 free((genericptr_t
) tmp
);
1503 plinemsg_types
= next
;
1513 msgtype_type(msg
, norepeat
)
1515 boolean norepeat
; /* called from Norep(via pline) */
1517 struct plinemsg_type
*tmp
= plinemsg_types
;
1520 /* we don't exclude entries with negative msgtype values
1521 because then the msg might end up matching a later pattern */
1522 if (regex_match(msg
, tmp
->regex
))
1523 return tmp
->msgtype
;
1526 return norepeat
? MSGTYP_NOREP
: MSGTYP_NORMAL
;
1529 /* negate one or more types of messages so that their type handling will
1530 be disabled or re-enabled; MSGTYPE_NORMAL (value 0) is not affected */
1532 hide_unhide_msgtypes(hide
, hide_mask
)
1536 struct plinemsg_type
*tmp
;
1539 /* negative msgtype value won't be recognized by pline, so does nothing */
1540 for (tmp
= plinemsg_types
; tmp
; tmp
= tmp
->next
) {
1543 mt
= -mt
; /* unhide: negate negative, yielding positive */
1544 if (mt
> 0 && ((1 << mt
) & hide_mask
))
1545 tmp
->msgtype
= -tmp
->msgtype
;
1553 struct plinemsg_type
*tmp
= plinemsg_types
;
1563 msgtype_parse_add(str
)
1569 if (sscanf(str
, "%10s \"%255[^\"]\"", msgtype
, pattern
) == 2) {
1573 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1574 if (!strncmpi(msgtype_names
[i
].name
, msgtype
, strlen(msgtype
))) {
1575 typ
= msgtype_names
[i
].msgtyp
;
1579 return msgtype_add(typ
, pattern
);
1585 add_menu_coloring_parsed(str
, c
, a
)
1589 static const char re_error
[] = "Menucolor regex error";
1590 struct menucoloring
*tmp
;
1594 tmp
= (struct menucoloring
*) alloc(sizeof (struct menucoloring
));
1595 tmp
->match
= regex_init();
1596 if (!regex_compile(str
, tmp
->match
)) {
1597 if (!iflags
.window_inited
)
1598 raw_printf("\n%s: %s\n", re_error
, regex_error_desc(tmp
->match
));
1600 pline("%s: %s", re_error
, regex_error_desc(tmp
->match
));
1602 regex_free(tmp
->match
);
1606 tmp
->next
= menu_colorings
;
1607 tmp
->origstr
= dupstr(str
);
1610 menu_colorings
= tmp
;
1615 /* parse '"regex_string"=color&attr' and add it to menucoloring */
1617 add_menu_coloring(str
)
1620 int i
, c
= NO_COLOR
, a
= ATR_NONE
;
1621 char *tmps
, *cs
, *amp
;
1623 if (!str
|| (cs
= index(str
, '=')) == 0)
1626 tmps
= cs
+ 1; /* advance past '=' */
1628 if ((amp
= index(tmps
, '&')) != 0)
1631 c
= match_str2clr(tmps
);
1636 tmps
= amp
+ 1; /* advance past '&' */
1637 /* unlike colors, none of he attribute names has any embedded spaces,
1638 but use of fuzzymatch() allows us ignore the presence of leading
1639 and/or trailing (and also embedded) spaces in the user's string;
1640 dash and underscore skipping could be omitted but does no harm */
1641 for (i
= 0; i
< SIZE(attrnames
); i
++)
1642 if (fuzzymatch(tmps
, attrnames
[i
].name
, " -_", TRUE
)) {
1643 a
= attrnames
[i
].attr
;
1646 if (i
== SIZE(attrnames
) && (*tmps
>= '0' && *tmps
<= '9'))
1650 /* the regexp portion here has not been condensed by mungspaces() */
1653 if (*tmps
== '"' || *tmps
== '\'') {
1655 while (isspace((uchar
) *cs
))
1663 return add_menu_coloring_parsed(tmps
, c
, a
);
1667 get_menu_coloring(str
, color
, attr
)
1671 struct menucoloring
*tmpmc
;
1673 if (iflags
.use_menu_color
)
1674 for (tmpmc
= menu_colorings
; tmpmc
; tmpmc
= tmpmc
->next
)
1675 if (regex_match(str
, tmpmc
->match
)) {
1676 *color
= tmpmc
->color
;
1677 *attr
= tmpmc
->attr
;
1684 free_menu_coloring()
1686 struct menucoloring
*tmp
= menu_colorings
;
1689 struct menucoloring
*tmp2
= tmp
->next
;
1691 regex_free(tmp
->match
);
1692 free((genericptr_t
) tmp
->origstr
);
1693 free((genericptr_t
) tmp
);
1699 free_one_menu_coloring(idx
)
1702 struct menucoloring
*tmp
= menu_colorings
;
1703 struct menucoloring
*prev
= NULL
;
1707 struct menucoloring
*next
= tmp
->next
;
1709 regex_free(tmp
->match
);
1710 free((genericptr_t
) tmp
->origstr
);
1711 free((genericptr_t
) tmp
);
1715 menu_colorings
= next
;
1728 struct menucoloring
*tmp
= menu_colorings
;
1738 parse_role_opts(negated
, fullname
, opts
, opp
)
1740 const char *fullname
;
1747 bad_negation(fullname
, FALSE
);
1748 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
1749 boolean val_negated
= FALSE
;
1751 while ((*op
== '!') || !strncmpi(op
, "no", 2)) {
1756 val_negated
= !val_negated
;
1759 if (!setrolefilter(op
))
1762 if (duplicate_opt_detection(opts
, 1))
1763 complain_about_duplicate(opts
, 1);
1772 parseoptions(opts
, tinitial
, tfrom_file
)
1773 register char *opts
;
1774 boolean tinitial
, tfrom_file
;
1778 boolean negated
, duplicate
;
1780 const char *fullname
;
1783 from_file
= tfrom_file
;
1784 if ((op
= index(opts
, ',')) != 0) {
1786 parseoptions(op
, initial
, from_file
);
1788 if (strlen(opts
) > BUFSZ
/ 2) {
1789 badoption("option too long");
1793 /* strip leading and trailing white space */
1794 while (isspace((uchar
) *opts
))
1797 while (--op
>= opts
&& isspace((uchar
) *op
))
1803 while ((*opts
== '!') || !strncmpi(opts
, "no", 2)) {
1811 /* variant spelling */
1813 if (match_optname(opts
, "colour", 5, FALSE
))
1814 Strcpy(opts
, "color"); /* fortunately this isn't longer */
1816 /* special boolean options */
1818 if (match_optname(opts
, "female", 3, FALSE
)) {
1819 if (duplicate_opt_detection(opts
, 0))
1820 complain_about_duplicate(opts
, 0);
1821 if (!initial
&& flags
.female
== negated
)
1822 pline("That is not anatomically possible.");
1824 flags
.initgend
= flags
.female
= !negated
;
1828 if (match_optname(opts
, "male", 4, FALSE
)) {
1829 if (duplicate_opt_detection(opts
, 0))
1830 complain_about_duplicate(opts
, 0);
1831 if (!initial
&& flags
.female
!= negated
)
1832 pline("That is not anatomically possible.");
1834 flags
.initgend
= flags
.female
= negated
;
1838 #if defined(MICRO) && !defined(AMIGA)
1839 /* included for compatibility with old NetHack.cnf files */
1840 if (match_optname(opts
, "IBM_", 4, FALSE
)) {
1841 iflags
.BIOS
= !negated
;
1846 /* compound options */
1848 /* This first batch can be duplicated if their values are negated */
1852 if (match_optname(opts
, fullname
, sizeof("align") - 1, TRUE
)) {
1853 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1854 if ((flags
.initalign
= str2align(op
)) == ROLE_NONE
)
1860 /* role:string or character:string */
1862 if (match_optname(opts
, fullname
, 4, TRUE
)
1863 || match_optname(opts
, (fullname
= "character"), 4, TRUE
)) {
1864 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1865 if ((flags
.initrole
= str2role(op
)) == ROLE_NONE
)
1867 else /* Backwards compatibility */
1868 nmcpy(pl_character
, op
, PL_NSIZ
);
1875 if (match_optname(opts
, fullname
, 4, TRUE
)) {
1876 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1877 if ((flags
.initrace
= str2race(op
)) == ROLE_NONE
)
1879 else /* Backwards compatibility */
1886 fullname
= "gender";
1887 if (match_optname(opts
, fullname
, 4, TRUE
)) {
1888 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1889 if ((flags
.initgend
= str2gend(op
)) == ROLE_NONE
)
1892 flags
.female
= flags
.initgend
;
1897 /* We always check for duplicates on the remaining compound options,
1898 although individual option processing can choose to complain or not */
1901 duplicate_opt_detection(opts
, 1); /* 1 means check compounds */
1903 fullname
= "pettype";
1904 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1906 complain_about_duplicate(opts
, 1);
1907 if ((op
= string_for_env_opt(fullname
, opts
, negated
)) != 0) {
1909 bad_negation(fullname
, TRUE
);
1911 switch (lowc(*op
)) {
1913 preferred_pet
= 'd';
1916 case 'f': /* feline */
1917 preferred_pet
= 'c';
1919 case 'h': /* horse */
1920 case 'q': /* quadruped */
1921 /* avoids giving "unrecognized type of pet" but
1922 pet_type(dog.c) won't actually honor this */
1923 preferred_pet
= 'h';
1925 case 'n': /* no pet */
1926 preferred_pet
= 'n';
1928 case '*': /* random */
1929 preferred_pet
= '\0';
1932 pline("Unrecognized pet type '%s'.", op
);
1936 preferred_pet
= 'n';
1940 fullname
= "catname";
1941 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1943 complain_about_duplicate(opts
, 1);
1945 bad_negation(fullname
, FALSE
);
1946 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1947 nmcpy(catname
, op
, PL_PSIZ
);
1948 sanitize_name(catname
);
1952 fullname
= "dogname";
1953 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1955 complain_about_duplicate(opts
, 1);
1957 bad_negation(fullname
, FALSE
);
1958 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1959 nmcpy(dogname
, op
, PL_PSIZ
);
1960 sanitize_name(dogname
);
1964 fullname
= "horsename";
1965 if (match_optname(opts
, fullname
, 5, TRUE
)) {
1967 complain_about_duplicate(opts
, 1);
1969 bad_negation(fullname
, FALSE
);
1970 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1971 nmcpy(horsename
, op
, PL_PSIZ
);
1972 sanitize_name(horsename
);
1976 fullname
= "number_pad";
1977 if (match_optname(opts
, fullname
, 10, TRUE
)) {
1978 boolean compat
= (strlen(opts
) <= 10);
1981 complain_about_duplicate(opts
, 1);
1982 op
= string_for_opt(opts
, (compat
|| !initial
));
1984 if (compat
|| negated
|| initial
) {
1985 /* for backwards compatibility, "number_pad" without a
1986 value is a synonym for number_pad:1 */
1987 iflags
.num_pad
= !negated
;
1988 iflags
.num_pad_mode
= 0;
1990 } else if (negated
) {
1991 bad_negation("number_pad", TRUE
);
1994 int mode
= atoi(op
);
1996 if (mode
< -1 || mode
> 4 || (mode
== 0 && *op
!= '0')) {
1999 } else if (mode
<= 0) {
2000 iflags
.num_pad
= FALSE
;
2001 /* German keyboard; y and z keys swapped */
2002 iflags
.num_pad_mode
= (mode
< 0); /* 0 or 1 */
2003 } else { /* mode > 0 */
2004 iflags
.num_pad
= TRUE
;
2005 iflags
.num_pad_mode
= 0;
2006 /* PC Hack / MSDOS compatibility */
2007 if (mode
== 2 || mode
== 4)
2008 iflags
.num_pad_mode
|= 1;
2009 /* phone keypad layout */
2010 if (mode
== 3 || mode
== 4)
2011 iflags
.num_pad_mode
|= 2;
2014 reset_commands(FALSE
);
2015 number_pad(iflags
.num_pad
? 1 : 0);
2019 fullname
= "roguesymset";
2020 if (match_optname(opts
, fullname
, 7, TRUE
)) {
2022 complain_about_duplicate(opts
, 1);
2024 bad_negation(fullname
, FALSE
);
2025 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2026 symset
[ROGUESET
].name
= dupstr(op
);
2027 if (!read_sym_file(ROGUESET
)) {
2028 clear_symsetentry(ROGUESET
, TRUE
);
2029 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2033 if (!initial
&& Is_rogue_level(&u
.uz
))
2034 assign_graphics(ROGUESET
);
2041 fullname
= "symset";
2042 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2044 complain_about_duplicate(opts
, 1);
2046 bad_negation(fullname
, FALSE
);
2047 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2048 symset
[PRIMARY
].name
= dupstr(op
);
2049 if (!read_sym_file(PRIMARY
)) {
2050 clear_symsetentry(PRIMARY
, TRUE
);
2051 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2055 switch_symbols(symset
[PRIMARY
].name
!= (char *) 0);
2062 fullname
= "runmode";
2063 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2065 complain_about_duplicate(opts
, 1);
2067 flags
.runmode
= RUN_TPORT
;
2068 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2069 if (!strncmpi(op
, "teleport", strlen(op
)))
2070 flags
.runmode
= RUN_TPORT
;
2071 else if (!strncmpi(op
, "run", strlen(op
)))
2072 flags
.runmode
= RUN_LEAP
;
2073 else if (!strncmpi(op
, "walk", strlen(op
)))
2074 flags
.runmode
= RUN_STEP
;
2075 else if (!strncmpi(op
, "crawl", strlen(op
)))
2076 flags
.runmode
= RUN_CRAWL
;
2083 /* menucolor:"regex_string"=color */
2084 fullname
= "menucolor";
2085 if (match_optname(opts
, fullname
, 9, TRUE
)) {
2087 bad_negation(fullname
, FALSE
);
2088 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
2089 if (!add_menu_coloring(op
))
2094 fullname
= "msghistory";
2095 if (match_optname(opts
, fullname
, 3, TRUE
)) {
2097 complain_about_duplicate(opts
, 1);
2098 op
= string_for_env_opt(fullname
, opts
, negated
);
2099 if ((negated
&& !op
) || (!negated
&& op
)) {
2100 iflags
.msg_history
= negated
? 0 : atoi(op
);
2102 bad_negation(fullname
, TRUE
);
2106 fullname
= "msg_window";
2107 /* msg_window:single, combo, full or reversed */
2108 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2109 /* allow option to be silently ignored by non-tty ports */
2114 complain_about_duplicate(opts
, 1);
2115 if (!(op
= string_for_opt(opts
, TRUE
))) {
2116 tmp
= negated
? 's' : 'f';
2119 bad_negation(fullname
, TRUE
);
2125 case 's': /* single message history cycle (default if negated) */
2126 iflags
.prevmsg_window
= 's';
2128 case 'c': /* combination: two singles, then full page reversed */
2129 iflags
.prevmsg_window
= 'c';
2131 case 'f': /* full page (default if no opts) */
2132 iflags
.prevmsg_window
= 'f';
2134 case 'r': /* full page (reversed) */
2135 iflags
.prevmsg_window
= 'r';
2145 * setting font options */
2147 if (!strncmpi(opts
, fullname
, 4)) {
2149 char *fontopts
= opts
+ 4;
2151 if (!strncmpi(fontopts
, "map", 3) || !strncmpi(fontopts
, "_map", 4))
2152 opttype
= MAP_OPTION
;
2153 else if (!strncmpi(fontopts
, "message", 7)
2154 || !strncmpi(fontopts
, "_message", 8))
2155 opttype
= MESSAGE_OPTION
;
2156 else if (!strncmpi(fontopts
, "text", 4)
2157 || !strncmpi(fontopts
, "_text", 5))
2158 opttype
= TEXT_OPTION
;
2159 else if (!strncmpi(fontopts
, "menu", 4)
2160 || !strncmpi(fontopts
, "_menu", 5))
2161 opttype
= MENU_OPTION
;
2162 else if (!strncmpi(fontopts
, "status", 6)
2163 || !strncmpi(fontopts
, "_status", 7))
2164 opttype
= STATUS_OPTION
;
2165 else if (!strncmpi(fontopts
, "_size", 5)) {
2166 if (!strncmpi(fontopts
, "_size_map", 8))
2167 opttype
= MAP_OPTION
;
2168 else if (!strncmpi(fontopts
, "_size_message", 12))
2169 opttype
= MESSAGE_OPTION
;
2170 else if (!strncmpi(fontopts
, "_size_text", 9))
2171 opttype
= TEXT_OPTION
;
2172 else if (!strncmpi(fontopts
, "_size_menu", 9))
2173 opttype
= MENU_OPTION
;
2174 else if (!strncmpi(fontopts
, "_size_status", 11))
2175 opttype
= STATUS_OPTION
;
2181 complain_about_duplicate(opts
, 1);
2182 if (opttype
> 0 && !negated
2183 && (op
= string_for_opt(opts
, FALSE
)) != 0) {
2186 iflags
.wc_fontsiz_map
= atoi(op
);
2188 case MESSAGE_OPTION
:
2189 iflags
.wc_fontsiz_message
= atoi(op
);
2192 iflags
.wc_fontsiz_text
= atoi(op
);
2195 iflags
.wc_fontsiz_menu
= atoi(op
);
2198 iflags
.wc_fontsiz_status
= atoi(op
);
2206 if (opttype
> 0 && (op
= string_for_opt(opts
, FALSE
)) != 0) {
2207 wc_set_font_name(opttype
, op
);
2209 set_font_name(opttype
, op
);
2213 bad_negation(fullname
, TRUE
);
2218 if (match_optname(opts
, "palette", 3, TRUE
)
2220 || match_optname(opts
, "hicolor", 3, TRUE
)
2223 int color_number
, color_incr
;
2227 complain_about_duplicate(opts
, 1);
2230 if (match_optname(opts
, "hicolor", 3, TRUE
)) {
2232 bad_negation("hicolor", FALSE
);
2235 color_number
= CLR_MAX
+ 4; /* HARDCODED inverse number */
2241 bad_negation("palette", FALSE
);
2248 op
= string_for_opt(opts
, TRUE
);
2249 if (!alternative_palette(op
))
2252 if ((op
= string_for_opt(opts
, FALSE
)) != (char *) 0) {
2254 int cnt
, tmp
, reverse
;
2257 while (*pt
&& color_number
>= 0) {
2267 if (*pt
&& *pt
!= '/') {
2274 if (isalpha((uchar
) tmp
)) {
2275 tmp
= (tmp
+ 9) & 0xf; /* Assumes ASCII... */
2277 tmp
&= 0xf; /* Digits in ASCII too... */
2280 /* Add an extra so we fill f -> ff and 0 -> 00 */
2288 change_color(color_number
, rgb
, reverse
);
2289 color_number
+= color_incr
;
2298 #endif /* CHANGE_COLOR */
2300 if (match_optname(opts
, "fruit", 2, TRUE
)) {
2301 struct fruit
*forig
= 0;
2302 char empty_str
= '\0';
2305 complain_about_duplicate(opts
, 1);
2306 op
= string_for_opt(opts
, negated
);
2309 bad_negation("fruit", TRUE
);
2321 for (f
= ffruit
; f
; f
= f
->nextf
) {
2322 if (!strcmp(op
, f
->fname
))
2326 if (!flags
.made_fruit
) {
2327 for (forig
= ffruit
; forig
; forig
= forig
->nextf
) {
2328 if (!strcmp(pl_fruit
, forig
->fname
)) {
2333 if (!forig
&& num
>= 100) {
2334 pline("Doing that so many times isn't very fruitful.");
2339 nmcpy(pl_fruit
, op
, PL_FSIZ
);
2340 sanitize_name(pl_fruit
);
2341 /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
2343 nmcpy(pl_fruit
, "slime mold", PL_FSIZ
);
2345 (void) fruitadd(pl_fruit
, forig
);
2346 pline("Fruit is now \"%s\".", pl_fruit
);
2348 /* If initial, then initoptions is allowed to do it instead
2349 * of here (initoptions always has to do it even if there's
2350 * no fruit option at all. Also, we don't want people
2351 * setting multiple fruits in their options.)
2356 fullname
= "whatis_coord";
2357 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2359 complain_about_duplicate(opts
, 1);
2361 iflags
.getpos_coords
= GPCOORDS_NONE
;
2363 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
2364 static char gpcoords
[] = { GPCOORDS_NONE
, GPCOORDS_COMPASS
,
2365 GPCOORDS_COMFULL
, GPCOORDS_MAP
,
2366 GPCOORDS_SCREEN
, '\0' };
2369 if (c
&& index(gpcoords
, c
))
2370 iflags
.getpos_coords
= c
;
2377 fullname
= "warnings";
2378 if (match_optname(opts
, fullname
, 5, TRUE
)) {
2380 complain_about_duplicate(opts
, 1);
2382 bad_negation(fullname
, FALSE
);
2384 warning_opts(opts
, fullname
);
2388 #ifdef BACKWARD_COMPAT
2389 /* boulder:symbol */
2390 fullname
= "boulder";
2391 if (match_optname(opts
, fullname
, 7, TRUE
)) {
2394 complain_about_duplicate(opts
, 1);
2396 bad_negation(fullname
, FALSE
);
2399 /* if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
2401 if (!(opts
= string_for_opt(opts
, FALSE
)))
2403 escapes(opts
, opts
);
2404 if (def_char_to_monclass(opts
[0]) != MAXMCLASSES
)
2406 else if (opts
[0] >= '1' && opts
[0] <= '5')
2409 /* symbol chosen matches a used monster or warning
2410 symbol which is not good - reject it*/
2412 "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
2413 opts
[0], (clash
== 1) ? "monster" : "warning");
2416 * Override the default boulder symbol.
2418 iflags
.bouldersym
= (uchar
) opts
[0];
2428 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2430 complain_about_duplicate(opts
, 1);
2432 bad_negation(fullname
, FALSE
);
2433 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
2434 nmcpy(plname
, op
, PL_NSIZ
);
2438 /* altkeyhandler:string */
2439 fullname
= "altkeyhandler";
2440 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2442 complain_about_duplicate(opts
, 1);
2444 bad_negation(fullname
, FALSE
);
2445 } else if ((op
= string_for_opt(opts
, negated
)) != 0) {
2447 (void) strncpy(iflags
.altkeyhandler
, op
, MAX_ALTKEYHANDLER
- 5);
2448 load_keyboard_handler();
2455 * align_status:[left|top|right|bottom] */
2456 fullname
= "align_status";
2457 if (match_optname(opts
, fullname
, sizeof("align_status") - 1, TRUE
)) {
2458 op
= string_for_opt(opts
, negated
);
2459 if (op
&& !negated
) {
2460 if (!strncmpi(op
, "left", sizeof("left") - 1))
2461 iflags
.wc_align_status
= ALIGN_LEFT
;
2462 else if (!strncmpi(op
, "top", sizeof("top") - 1))
2463 iflags
.wc_align_status
= ALIGN_TOP
;
2464 else if (!strncmpi(op
, "right", sizeof("right") - 1))
2465 iflags
.wc_align_status
= ALIGN_RIGHT
;
2466 else if (!strncmpi(op
, "bottom", sizeof("bottom") - 1))
2467 iflags
.wc_align_status
= ALIGN_BOTTOM
;
2471 bad_negation(fullname
, TRUE
);
2475 * align_message:[left|top|right|bottom] */
2476 fullname
= "align_message";
2477 if (match_optname(opts
, fullname
, sizeof("align_message") - 1, TRUE
)) {
2479 complain_about_duplicate(opts
, 1);
2480 op
= string_for_opt(opts
, negated
);
2481 if (op
&& !negated
) {
2482 if (!strncmpi(op
, "left", sizeof("left") - 1))
2483 iflags
.wc_align_message
= ALIGN_LEFT
;
2484 else if (!strncmpi(op
, "top", sizeof("top") - 1))
2485 iflags
.wc_align_message
= ALIGN_TOP
;
2486 else if (!strncmpi(op
, "right", sizeof("right") - 1))
2487 iflags
.wc_align_message
= ALIGN_RIGHT
;
2488 else if (!strncmpi(op
, "bottom", sizeof("bottom") - 1))
2489 iflags
.wc_align_message
= ALIGN_BOTTOM
;
2493 bad_negation(fullname
, TRUE
);
2496 /* the order to list the pack */
2497 fullname
= "packorder";
2498 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2500 complain_about_duplicate(opts
, 1);
2502 bad_negation(fullname
, FALSE
);
2504 } else if (!(op
= string_for_opt(opts
, FALSE
)))
2507 if (!change_inv_order(op
))
2512 /* user can change required response for some prompts (quit, die, hit),
2513 or add an extra prompt (pray, Remove) that isn't ordinarily there */
2514 fullname
= "paranoid_confirmation";
2515 if (match_optname(opts
, fullname
, 8, TRUE
)) {
2516 /* at present we don't complain about duplicates for this
2517 option, but we do throw away the old settings whenever
2518 we process a new one [clearing old flags is essential
2519 for handling default paranoid_confirm:pray sanely] */
2520 flags
.paranoia_bits
= 0; /* clear all */
2522 flags
.paranoia_bits
= 0; /* [now redundant...] */
2523 } else if ((op
= string_for_opt(opts
, TRUE
)) != 0) {
2524 char *pp
, buf
[BUFSZ
];
2526 strncpy(buf
, op
, sizeof buf
- 1);
2527 buf
[sizeof buf
- 1] = '\0';
2528 op
= mungspaces(buf
);
2530 /* We're looking to parse
2531 "paranoid_confirm:whichone wheretwo whothree"
2532 and "paranoid_confirm:" prefix has already
2533 been stripped off by the time we get here */
2534 pp
= index(op
, ' ');
2537 /* we aren't matching option names but match_optname
2538 does what we want once we've broken the space
2539 delimited aggregate into separate tokens */
2540 for (i
= 0; i
< SIZE(paranoia
); ++i
) {
2541 if (match_optname(op
, paranoia
[i
].argname
,
2542 paranoia
[i
].argMinLen
, FALSE
)
2543 || (paranoia
[i
].synonym
2544 && match_optname(op
, paranoia
[i
].synonym
,
2545 paranoia
[i
].synMinLen
, FALSE
))) {
2546 if (paranoia
[i
].flagmask
)
2547 flags
.paranoia_bits
|= paranoia
[i
].flagmask
;
2548 else /* 0 == "none", so clear all */
2549 flags
.paranoia_bits
= 0;
2553 if (i
== SIZE(paranoia
)) {
2554 /* didn't match anything, so arg is bad;
2555 any flags already set will stay set */
2559 /* move on to next token */
2563 break; /* no next token */
2569 /* accept deprecated boolean; superseded by paranoid_confirm:pray */
2570 fullname
= "prayconfirm";
2571 if (match_optname(opts
, fullname
, 4, FALSE
)) {
2573 flags
.paranoia_bits
&= ~PARANOID_PRAY
;
2575 flags
.paranoia_bits
|= PARANOID_PRAY
;
2579 /* maximum burden picked up before prompt (Warren Cheung) */
2580 fullname
= "pickup_burden";
2581 if (match_optname(opts
, fullname
, 8, TRUE
)) {
2583 complain_about_duplicate(opts
, 1);
2585 bad_negation(fullname
, FALSE
);
2587 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
2588 switch (lowc(*op
)) {
2589 case 'u': /* Unencumbered */
2590 flags
.pickup_burden
= UNENCUMBERED
;
2592 case 'b': /* Burdened (slight encumbrance) */
2593 flags
.pickup_burden
= SLT_ENCUMBER
;
2595 case 's': /* streSsed (moderate encumbrance) */
2596 flags
.pickup_burden
= MOD_ENCUMBER
;
2598 case 'n': /* straiNed (heavy encumbrance) */
2599 flags
.pickup_burden
= HVY_ENCUMBER
;
2601 case 'o': /* OverTaxed (extreme encumbrance) */
2603 flags
.pickup_burden
= EXT_ENCUMBER
;
2605 case 'l': /* overLoaded */
2606 flags
.pickup_burden
= OVERLOADED
;
2615 /* types of objects to pick up automatically */
2616 if (match_optname(opts
, "pickup_types", 8, TRUE
)) {
2617 char ocl
[MAXOCLASSES
+ 1], tbuf
[MAXOCLASSES
+ 1], qbuf
[QBUFSZ
],
2620 boolean badopt
= FALSE
, compat
= (strlen(opts
) <= 6), use_menu
;
2623 complain_about_duplicate(opts
, 1);
2624 oc_to_str(flags
.pickup_types
, tbuf
);
2625 flags
.pickup_types
[0] = '\0'; /* all */
2626 op
= string_for_opt(opts
, (compat
|| !initial
));
2628 if (compat
|| negated
|| initial
) {
2629 /* for backwards compatibility, "pickup" without a
2630 value is a synonym for autopickup of all types
2631 (and during initialization, we can't prompt yet) */
2632 flags
.pickup
= !negated
;
2635 oc_to_str(flags
.inv_order
, ocl
);
2637 if (flags
.menu_style
== MENU_TRADITIONAL
2638 || flags
.menu_style
== MENU_COMBINATION
) {
2640 Sprintf(qbuf
, "New pickup_types: [%s am] (%s)", ocl
,
2641 *tbuf
? tbuf
: "all");
2643 op
= mungspaces(abuf
);
2644 if (abuf
[0] == '\0' || abuf
[0] == '\033')
2645 op
= tbuf
; /* restore */
2646 else if (abuf
[0] == 'm')
2650 (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE
, ocl
,
2656 bad_negation("pickup_types", TRUE
);
2661 if (*op
!= 'a' && *op
!= 'A') {
2664 oc_sym
= def_char_to_objclass(*op
);
2665 /* make sure all are valid obj symbols occurring once */
2666 if (oc_sym
!= MAXOCLASSES
2667 && !index(flags
.pickup_types
, oc_sym
)) {
2668 flags
.pickup_types
[num
] = (char) oc_sym
;
2669 flags
.pickup_types
[++num
] = '\0';
2680 /* pile limit: when walking over objects, number which triggers
2681 "there are several/many objects here" instead of listing them */
2682 fullname
= "pile_limit";
2683 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2685 complain_about_duplicate(opts
, 1);
2686 op
= string_for_opt(opts
, negated
);
2687 if ((negated
&& !op
) || (!negated
&& op
))
2688 flags
.pile_limit
= negated
? 0 : atoi(op
);
2690 bad_negation(fullname
, TRUE
);
2692 flags
.pile_limit
= PILE_LIMIT_DFLT
;
2694 if (flags
.pile_limit
< 0)
2695 flags
.pile_limit
= PILE_LIMIT_DFLT
;
2699 /* play mode: normal, explore/discovery, or debug/wizard */
2700 fullname
= "playmode";
2701 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2703 complain_about_duplicate(opts
, 1);
2705 bad_negation(fullname
, FALSE
);
2706 if (duplicate
|| negated
)
2708 op
= string_for_opt(opts
, FALSE
);
2711 if (!strncmpi(op
, "normal", 6) || !strcmpi(op
, "play")) {
2712 wizard
= discover
= FALSE
;
2713 } else if (!strncmpi(op
, "explore", 6)
2714 || !strncmpi(op
, "discovery", 6)) {
2715 wizard
= FALSE
, discover
= TRUE
;
2716 } else if (!strncmpi(op
, "debug", 5) || !strncmpi(op
, "wizard", 6)) {
2717 wizard
= TRUE
, discover
= FALSE
;
2719 raw_printf("Invalid value for \"%s\":%s.", fullname
, op
);
2725 * player_selection: dialog | prompts */
2726 fullname
= "player_selection";
2727 if (match_optname(opts
, fullname
, sizeof("player_selection") - 1, TRUE
)) {
2729 complain_about_duplicate(opts
, 1);
2730 op
= string_for_opt(opts
, negated
);
2731 if (op
&& !negated
) {
2732 if (!strncmpi(op
, "dialog", sizeof("dialog") - 1))
2733 iflags
.wc_player_selection
= VIA_DIALOG
;
2734 else if (!strncmpi(op
, "prompt", sizeof("prompt") - 1))
2735 iflags
.wc_player_selection
= VIA_PROMPTS
;
2739 bad_negation(fullname
, TRUE
);
2743 /* things to disclose at end of game */
2744 if (match_optname(opts
, "disclose", 7, TRUE
)) {
2746 * The order that the end_disclose options are stored:
2747 * inventory, attribs, vanquished, genocided,
2748 * conduct, overview.
2749 * There is an array in flags:
2750 * end_disclose[NUM_DISCLOSURE_OPT];
2751 * with option settings for the each of the following:
2752 * iagvc [see disclosure_options in decl.c]:
2753 * Legal setting values in that array are:
2754 * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
2755 * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
2756 * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
2757 * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
2759 * Those setting values can be used in the option
2760 * string as a prefix to get the desired behaviour.
2762 * For backward compatibility, no prefix is required,
2763 * and the presence of a i,a,g,v, or c without a prefix
2764 * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
2766 boolean badopt
= FALSE
;
2767 int idx
, prefix_val
;
2770 complain_about_duplicate(opts
, 1);
2771 op
= string_for_opt(opts
, TRUE
);
2772 if (op
&& negated
) {
2773 bad_negation("disclose", TRUE
);
2776 /* "disclose" without a value means "all with prompting"
2777 and negated means "none without prompting" */
2778 if (!op
|| !strcmpi(op
, "all") || !strcmpi(op
, "none")) {
2779 if (op
&& !strcmpi(op
, "none"))
2781 for (num
= 0; num
< NUM_DISCLOSURE_OPTIONS
; num
++)
2782 flags
.end_disclose
[num
] = negated
2783 ? DISCLOSE_NO_WITHOUT_PROMPT
2784 : DISCLOSE_PROMPT_DEFAULT_YES
;
2790 while (*op
&& num
< sizeof flags
.end_disclose
- 1) {
2791 static char valid_settings
[] = {
2792 DISCLOSE_PROMPT_DEFAULT_YES
, DISCLOSE_PROMPT_DEFAULT_NO
,
2793 DISCLOSE_PROMPT_DEFAULT_SPECIAL
,
2794 DISCLOSE_YES_WITHOUT_PROMPT
, DISCLOSE_NO_WITHOUT_PROMPT
,
2795 DISCLOSE_SPECIAL_WITHOUT_PROMPT
, '\0'
2797 register char c
, *dop
;
2801 c
= 'v'; /* killed -> vanquished */
2803 c
= 'o'; /* dungeon -> overview */
2804 dop
= index(disclosure_options
, c
);
2806 idx
= (int) (dop
- disclosure_options
);
2807 if (idx
< 0 || idx
> NUM_DISCLOSURE_OPTIONS
- 1) {
2808 impossible("bad disclosure index %d %c", idx
, c
);
2811 if (prefix_val
!= -1) {
2813 if (prefix_val
== DISCLOSE_PROMPT_DEFAULT_SPECIAL
)
2814 prefix_val
= DISCLOSE_PROMPT_DEFAULT_YES
;
2815 if (prefix_val
== DISCLOSE_SPECIAL_WITHOUT_PROMPT
)
2816 prefix_val
= DISCLOSE_YES_WITHOUT_PROMPT
;
2818 flags
.end_disclose
[idx
] = prefix_val
;
2821 flags
.end_disclose
[idx
] = DISCLOSE_YES_WITHOUT_PROMPT
;
2822 } else if (index(valid_settings
, c
)) {
2824 } else if (c
== ' ') {
2835 /* scores:5t[op] 5a[round] o[wn] */
2836 if (match_optname(opts
, "scores", 4, TRUE
)) {
2838 complain_about_duplicate(opts
, 1);
2840 bad_negation("scores", FALSE
);
2843 if (!(op
= string_for_opt(opts
, FALSE
)))
2853 } else if (*op
== '!') {
2863 flags
.end_top
= inum
;
2867 flags
.end_around
= inum
;
2871 flags
.end_own
= !negated
;
2877 while (letter(*++op
) || *op
== ' ')
2885 fullname
= "sortloot";
2886 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2887 op
= string_for_env_opt(fullname
, opts
, FALSE
);
2892 case 'n': /* none */
2893 case 'l': /* loot (pickup) */
2894 case 'f': /* full (pickup + invent) */
2905 fullname
= "suppress_alert";
2906 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2908 complain_about_duplicate(opts
, 1);
2909 op
= string_for_opt(opts
, negated
);
2911 bad_negation(fullname
, FALSE
);
2913 (void) feature_alert_opts(op
, fullname
);
2918 /* videocolors:string */
2919 fullname
= "videocolors";
2920 if (match_optname(opts
, fullname
, 6, TRUE
)
2921 || match_optname(opts
, "videocolours", 10, TRUE
)) {
2923 complain_about_duplicate(opts
, 1);
2925 bad_negation(fullname
, FALSE
);
2927 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2930 if (!assign_videocolors(opts
))
2934 /* videoshades:string */
2935 fullname
= "videoshades";
2936 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2938 complain_about_duplicate(opts
, 1);
2940 bad_negation(fullname
, FALSE
);
2942 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2945 if (!assign_videoshades(opts
))
2949 #endif /* VIDEOSHADES */
2952 /* video:string -- must be after longer tests */
2954 if (match_optname(opts
, fullname
, 5, TRUE
)) {
2956 complain_about_duplicate(opts
, 1);
2958 bad_negation(fullname
, FALSE
);
2960 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2963 if (!assign_video(opts
))
2967 #endif /* NO_TERMS */
2968 /* soundcard:string -- careful not to match boolean 'sound' */
2969 fullname
= "soundcard";
2970 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2972 complain_about_duplicate(opts
, 1);
2974 bad_negation(fullname
, FALSE
);
2976 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2979 if (!assign_soundcard(opts
))
2987 * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|
2988 * ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen]
2990 fullname
= "map_mode";
2991 if (match_optname(opts
, fullname
, sizeof("map_mode") - 1, TRUE
)) {
2993 complain_about_duplicate(opts
, 1);
2994 op
= string_for_opt(opts
, negated
);
2995 if (op
&& !negated
) {
2996 if (!strncmpi(op
, "tiles", sizeof("tiles") - 1))
2997 iflags
.wc_map_mode
= MAP_MODE_TILES
;
2998 else if (!strncmpi(op
, "ascii4x6", sizeof("ascii4x6") - 1))
2999 iflags
.wc_map_mode
= MAP_MODE_ASCII4x6
;
3000 else if (!strncmpi(op
, "ascii6x8", sizeof("ascii6x8") - 1))
3001 iflags
.wc_map_mode
= MAP_MODE_ASCII6x8
;
3002 else if (!strncmpi(op
, "ascii8x8", sizeof("ascii8x8") - 1))
3003 iflags
.wc_map_mode
= MAP_MODE_ASCII8x8
;
3004 else if (!strncmpi(op
, "ascii16x8", sizeof("ascii16x8") - 1))
3005 iflags
.wc_map_mode
= MAP_MODE_ASCII16x8
;
3006 else if (!strncmpi(op
, "ascii7x12", sizeof("ascii7x12") - 1))
3007 iflags
.wc_map_mode
= MAP_MODE_ASCII7x12
;
3008 else if (!strncmpi(op
, "ascii8x12", sizeof("ascii8x12") - 1))
3009 iflags
.wc_map_mode
= MAP_MODE_ASCII8x12
;
3010 else if (!strncmpi(op
, "ascii16x12", sizeof("ascii16x12") - 1))
3011 iflags
.wc_map_mode
= MAP_MODE_ASCII16x12
;
3012 else if (!strncmpi(op
, "ascii12x16", sizeof("ascii12x16") - 1))
3013 iflags
.wc_map_mode
= MAP_MODE_ASCII12x16
;
3014 else if (!strncmpi(op
, "ascii10x18", sizeof("ascii10x18") - 1))
3015 iflags
.wc_map_mode
= MAP_MODE_ASCII10x18
;
3016 else if (!strncmpi(op
, "fit_to_screen",
3017 sizeof("fit_to_screen") - 1))
3018 iflags
.wc_map_mode
= MAP_MODE_ASCII_FIT_TO_SCREEN
;
3022 bad_negation(fullname
, TRUE
);
3026 * scroll_amount:nn */
3027 fullname
= "scroll_amount";
3028 if (match_optname(opts
, fullname
, sizeof("scroll_amount") - 1, TRUE
)) {
3030 complain_about_duplicate(opts
, 1);
3031 op
= string_for_opt(opts
, negated
);
3032 if ((negated
&& !op
) || (!negated
&& op
)) {
3033 iflags
.wc_scroll_amount
= negated
? 1 : atoi(op
);
3035 bad_negation(fullname
, TRUE
);
3039 * scroll_margin:nn */
3040 fullname
= "scroll_margin";
3041 if (match_optname(opts
, fullname
, sizeof("scroll_margin") - 1, TRUE
)) {
3043 complain_about_duplicate(opts
, 1);
3044 op
= string_for_opt(opts
, negated
);
3045 if ((negated
&& !op
) || (!negated
&& op
)) {
3046 iflags
.wc_scroll_margin
= negated
? 5 : atoi(op
);
3048 bad_negation(fullname
, TRUE
);
3051 fullname
= "subkeyvalue";
3052 if (match_optname(opts
, fullname
, 5, TRUE
)) {
3053 /* no duplicate complaint here */
3055 bad_negation(fullname
, FALSE
);
3058 op
= string_for_opt(opts
, 0);
3059 map_subkeyvalue(op
);
3066 fullname
= "tile_width";
3067 if (match_optname(opts
, fullname
, sizeof("tile_width") - 1, TRUE
)) {
3069 complain_about_duplicate(opts
, 1);
3070 op
= string_for_opt(opts
, negated
);
3071 if ((negated
&& !op
) || (!negated
&& op
)) {
3072 iflags
.wc_tile_width
= negated
? 0 : atoi(op
);
3074 bad_negation(fullname
, TRUE
);
3079 fullname
= "tile_file";
3080 if (match_optname(opts
, fullname
, sizeof("tile_file") - 1, TRUE
)) {
3082 complain_about_duplicate(opts
, 1);
3083 if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3084 if (iflags
.wc_tile_file
)
3085 free(iflags
.wc_tile_file
);
3086 iflags
.wc_tile_file
= dupstr(op
);
3092 fullname
= "tile_height";
3093 if (match_optname(opts
, fullname
, sizeof("tile_height") - 1, TRUE
)) {
3095 complain_about_duplicate(opts
, 1);
3096 op
= string_for_opt(opts
, negated
);
3097 if ((negated
&& !op
) || (!negated
&& op
)) {
3098 iflags
.wc_tile_height
= negated
? 0 : atoi(op
);
3100 bad_negation(fullname
, TRUE
);
3104 * vary_msgcount:nn */
3105 fullname
= "vary_msgcount";
3106 if (match_optname(opts
, fullname
, sizeof("vary_msgcount") - 1, TRUE
)) {
3108 complain_about_duplicate(opts
, 1);
3109 op
= string_for_opt(opts
, negated
);
3110 if ((negated
&& !op
) || (!negated
&& op
)) {
3111 iflags
.wc_vary_msgcount
= negated
? 0 : atoi(op
);
3113 bad_negation(fullname
, TRUE
);
3116 fullname
= "windowtype";
3117 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3119 complain_about_duplicate(opts
, 1);
3121 bad_negation(fullname
, FALSE
);
3123 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
3124 char buf
[WINTYPELEN
];
3125 nmcpy(buf
, op
, WINTYPELEN
);
3126 choose_windows(buf
);
3131 fullname
= "windowchain";
3132 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3134 bad_negation(fullname
, FALSE
);
3136 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
3137 char buf
[WINTYPELEN
];
3138 nmcpy(buf
, op
, WINTYPELEN
);
3139 addto_windowchain(buf
);
3146 * setting window colors
3147 * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
3149 fullname
= "windowcolors";
3150 if (match_optname(opts
, fullname
, 7, TRUE
)) {
3152 complain_about_duplicate(opts
, 1);
3153 if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3154 if (!wc_set_window_colors(op
))
3157 bad_negation(fullname
, TRUE
);
3161 /* menustyle:traditional or combination or full or partial */
3162 if (match_optname(opts
, "menustyle", 4, TRUE
)) {
3164 boolean val_required
= (strlen(opts
) > 5 && !negated
);
3167 complain_about_duplicate(opts
, 1);
3168 if (!(op
= string_for_opt(opts
, !val_required
))) {
3170 return; /* string_for_opt gave feedback */
3171 tmp
= negated
? 'n' : 'f';
3176 case 'n': /* none */
3177 case 't': /* traditional: prompt for class(es) by symbol,
3178 prompt for each item within class(es) one at a time */
3179 flags
.menu_style
= MENU_TRADITIONAL
;
3181 case 'c': /* combination: prompt for class(es) by symbol,
3182 choose items within selected class(es) by menu */
3183 flags
.menu_style
= MENU_COMBINATION
;
3185 case 'f': /* full: choose class(es) by first menu,
3186 choose items within selected class(es) by second menu */
3187 flags
.menu_style
= MENU_FULL
;
3189 case 'p': /* partial: skip class filtering,
3190 choose items among all classes by menu */
3191 flags
.menu_style
= MENU_PARTIAL
;
3199 fullname
= "menu_headings";
3200 if (match_optname(opts
, fullname
, 12, TRUE
)) {
3202 complain_about_duplicate(opts
, 1);
3204 bad_negation(fullname
, FALSE
);
3206 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
3209 for (i
= 0; i
< SIZE(attrnames
); i
++)
3210 if (!strcmpi(opts
, attrnames
[i
].name
)) {
3211 iflags
.menu_headings
= attrnames
[i
].attr
;
3218 /* check for menu command mapping */
3219 for (i
= 0; i
< NUM_MENU_CMDS
; i
++) {
3220 fullname
= default_menu_cmd_info
[i
].name
;
3222 complain_about_duplicate(opts
, 1);
3223 if (match_optname(opts
, fullname
, (int) strlen(fullname
), TRUE
)) {
3225 bad_negation(fullname
, FALSE
);
3226 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3228 char c
, op_buf
[BUFSZ
];
3229 boolean isbad
= FALSE
;
3231 escapes(op
, op_buf
);
3234 if (c
== 0 || c
== '\r' || c
== '\n' || c
== '\033'
3235 || c
== ' ' || digit(c
) || (letter(c
) && c
!= '@'))
3237 else /* reject default object class symbols */
3238 for (j
= 1; j
< MAXOCLASSES
; j
++)
3239 if (c
== def_oc_syms
[i
].sym
) {
3247 add_menu_cmd_alias(c
, default_menu_cmd_info
[i
].cmd
);
3252 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
3253 /* hilite fields in status prompt */
3254 if (match_optname(opts
, "hilite_status", 13, TRUE
)) {
3256 complain_about_duplicate(opts
, 1);
3257 op
= string_for_opt(opts
, TRUE
);
3258 if (op
&& negated
) {
3259 clear_status_hilites(tfrom_file
);
3262 /* a value is mandatory */
3266 if (!set_status_hilites(op
, tfrom_file
))
3272 #if defined(BACKWARD_COMPAT)
3273 fullname
= "DECgraphics";
3274 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3275 boolean badflag
= FALSE
;
3278 complain_about_duplicate(opts
, 1);
3280 /* There is no rogue level DECgraphics-specific set */
3281 if (symset
[PRIMARY
].name
) {
3284 symset
[PRIMARY
].name
= dupstr(fullname
);
3285 if (!read_sym_file(PRIMARY
)) {
3287 clear_symsetentry(PRIMARY
, TRUE
);
3289 switch_symbols(TRUE
);
3292 pline("Failure to load symbol set %s.", fullname
);
3298 fullname
= "IBMgraphics";
3299 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3300 const char *sym_name
= fullname
;
3301 boolean badflag
= FALSE
;
3304 complain_about_duplicate(opts
, 1);
3306 for (i
= 0; i
< NUM_GRAPHICS
; ++i
) {
3307 if (symset
[i
].name
) {
3311 sym_name
= "RogueIBM";
3312 symset
[i
].name
= dupstr(sym_name
);
3313 if (!read_sym_file(i
)) {
3315 clear_symsetentry(i
, TRUE
);
3321 pline("Failure to load symbol set %s.", sym_name
);
3324 switch_symbols(TRUE
);
3325 if (!initial
&& Is_rogue_level(&u
.uz
))
3326 assign_graphics(ROGUESET
);
3332 #ifdef MAC_GRAPHICS_ENV
3333 fullname
= "MACgraphics";
3334 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3335 boolean badflag
= FALSE
;
3338 complain_about_duplicate(opts
, 1);
3340 if (symset
[PRIMARY
].name
) {
3343 symset
[PRIMARY
].name
= dupstr(fullname
);
3344 if (!read_sym_file(PRIMARY
)) {
3346 clear_symsetentry(PRIMARY
, TRUE
);
3350 pline("Failure to load symbol set %s.", fullname
);
3353 switch_symbols(TRUE
);
3354 if (!initial
&& Is_rogue_level(&u
.uz
))
3355 assign_graphics(ROGUESET
);
3362 /* OK, if we still haven't recognized the option, check the boolean
3365 for (i
= 0; boolopt
[i
].name
; i
++) {
3366 if (match_optname(opts
, boolopt
[i
].name
, 3, TRUE
)) {
3367 /* options that don't exist */
3368 if (!boolopt
[i
].addr
) {
3369 if (!initial
&& !negated
)
3370 pline_The("\"%s\" option is not available.",
3374 /* options that must come from config file */
3375 if (!initial
&& (boolopt
[i
].optflags
== SET_IN_FILE
)) {
3376 rejectoption(boolopt
[i
].name
);
3380 op
= string_for_opt(opts
, TRUE
);
3387 if (!strcmp(op
, "true") || !strcmp(op
, "yes")) {
3389 } else if (!strcmp(op
, "false") || !strcmp(op
, "no")) {
3397 *(boolopt
[i
].addr
) = !negated
;
3399 /* 0 means boolean opts */
3400 if (duplicate_opt_detection(boolopt
[i
].name
, 0))
3401 complain_about_duplicate(boolopt
[i
].name
, 0);
3403 if (boolopt
[i
].addr
== &iflags
.rlecomp
)
3404 set_savepref(iflags
.rlecomp
? "rlecomp" : "!rlecomp");
3407 if (boolopt
[i
].addr
== &iflags
.zerocomp
)
3408 set_savepref(iflags
.zerocomp
? "zerocomp" : "externalcomp");
3410 /* only do processing below if setting with doset() */
3414 if (boolopt
[i
].addr
== &flags
.time
3415 #ifdef SCORE_ON_BOTL
3416 || boolopt
[i
].addr
== &flags
.showscore
3418 || boolopt
[i
].addr
== &flags
.showexp
) {
3419 #ifdef STATUS_VIA_WINDOWPORT
3420 status_initialize(REASSESS_ONLY
);
3422 context
.botl
= TRUE
;
3423 } else if (boolopt
[i
].addr
== &flags
.invlet_constant
) {
3424 if (flags
.invlet_constant
)
3426 } else if (boolopt
[i
].addr
== &flags
.lit_corridor
3427 || boolopt
[i
].addr
== &flags
.dark_room
) {
3429 * All corridor squares seen via night vision or
3430 * candles & lamps change. Update them by calling
3431 * newsym() on them. Don't do this if we are
3432 * initializing the options --- the vision system
3435 vision_recalc(2); /* shut down vision */
3436 vision_full_recalc
= 1; /* delayed recalc */
3437 if (iflags
.use_color
)
3438 need_redraw
= TRUE
; /* darkroom refresh */
3439 } else if (boolopt
[i
].addr
== &iflags
.wc_tiled_map
3440 || boolopt
[i
].addr
== &flags
.showrace
3441 || boolopt
[i
].addr
== &iflags
.use_inverse
3442 || boolopt
[i
].addr
== &iflags
.hilite_pile
3443 || boolopt
[i
].addr
== &iflags
.hilite_pet
) {
3446 } else if (boolopt
[i
].addr
== &iflags
.use_color
) {
3456 #endif /* TEXTCOLOR */
3462 /* Is it a symbol? */
3463 if (strstr(opts
, "S_") == opts
&& parsesymbols(opts
)) {
3464 switch_symbols(TRUE
);
3468 /* out of valid options */
3472 static NEARDATA
const char *menutype
[] = { "traditional", "combination",
3473 "full", "partial" };
3475 static NEARDATA
const char *burdentype
[] = { "unencumbered", "burdened",
3476 "stressed", "strained",
3477 "overtaxed", "overloaded" };
3479 static NEARDATA
const char *runmodes
[] = { "teleport", "run", "walk",
3482 static NEARDATA
const char *sortltype
[] = { "none", "loot", "full" };
3485 * Convert the given string of object classes to a string of default object
3489 oc_to_str(src
, dest
)
3494 while ((i
= (int) *src
++) != 0) {
3495 if (i
< 0 || i
>= MAXOCLASSES
)
3496 impossible("oc_to_str: illegal object class %d", i
);
3498 *dest
++ = def_oc_syms
[i
].sym
;
3504 * Add the given mapping to the menu command map list. Always keep the
3505 * maps valid C strings.
3508 add_menu_cmd_alias(from_ch
, to_ch
)
3509 char from_ch
, to_ch
;
3511 if (n_menu_mapped
>= MAX_MENU_MAPPED_CMDS
) {
3512 pline("out of menu map space.");
3514 mapped_menu_cmds
[n_menu_mapped
] = from_ch
;
3515 mapped_menu_op
[n_menu_mapped
] = to_ch
;
3517 mapped_menu_cmds
[n_menu_mapped
] = 0;
3518 mapped_menu_op
[n_menu_mapped
] = 0;
3523 * Map the given character to its corresponding menu command. If it
3524 * doesn't match anything, just return the original.
3530 char *found
= index(mapped_menu_cmds
, ch
);
3532 int idx
= (int) (found
- mapped_menu_cmds
);
3533 ch
= mapped_menu_op
[idx
];
3538 #if defined(MICRO) || defined(MAC) || defined(WIN32)
3539 #define OPTIONS_HEADING "OPTIONS"
3541 #define OPTIONS_HEADING "NETHACKOPTIONS"
3544 static char fmtstr_doset
[] = "%s%-15s [%s] ";
3545 static char fmtstr_doset_tab
[] = "%s\t[%s]";
3546 static char n_currently_set
[] = "(%d currently set)";
3548 /* doset('O' command) menu entries for compound options */
3550 doset_add_menu(win
, option
, indexoffset
)
3551 winid win
; /* window to add to */
3552 const char *option
; /* option name */
3553 int indexoffset
; /* value to add to index in compopt[], or zero
3554 if option cannot be changed */
3556 const char *value
= "unknown"; /* current value */
3557 char buf
[BUFSZ
], buf2
[BUFSZ
];
3562 if (indexoffset
== 0) {
3564 value
= get_compopt_value(option
, buf2
);
3566 for (i
= 0; compopt
[i
].name
; i
++)
3567 if (strcmp(option
, compopt
[i
].name
) == 0)
3570 if (compopt
[i
].name
) {
3571 any
.a_int
= i
+ 1 + indexoffset
;
3572 value
= get_compopt_value(option
, buf2
);
3574 /* We are trying to add an option not found in compopt[].
3575 This is almost certainly bad, but we'll let it through anyway
3576 (with a zero value, so it can't be selected). */
3580 /* " " replaces "a - " -- assumes menus follow that style */
3581 if (!iflags
.menu_tab_sep
)
3582 Sprintf(buf
, fmtstr_doset
, any
.a_int
? "" : " ", option
,
3585 Sprintf(buf
, fmtstr_doset_tab
, option
, value
);
3586 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
3590 opts_add_others(win
, name
, id
, bufx
, nset
)
3597 char buf
[BUFSZ
], buf2
[BUFSZ
];
3598 anything any
= zeroany
;
3602 Sprintf(buf2
, n_currently_set
, nset
);
3604 Sprintf(buf2
, "%s", bufx
);
3605 if (!iflags
.menu_tab_sep
)
3606 Sprintf(buf
, fmtstr_doset
, any
.a_int
? "" : " ",
3609 Sprintf(buf
, fmtstr_doset_tab
, name
, buf2
);
3610 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
3613 enum opt_other_enums
{
3614 OPT_OTHER_MSGTYPE
= -4,
3615 OPT_OTHER_MENUCOLOR
= -3,
3616 OPT_OTHER_STATHILITE
= -2,
3617 OPT_OTHER_APEXC
= -1
3618 /* these must be < 0 */
3621 /* presently only used when determining longest option name */
3622 static struct other_opts
{
3625 enum opt_other_enums code
;
3627 { "autopickup exceptions", SET_IN_GAME
, OPT_OTHER_APEXC
},
3628 { "menucolors", SET_IN_GAME
, OPT_OTHER_MENUCOLOR
},
3629 { "message types", SET_IN_GAME
, OPT_OTHER_MSGTYPE
},
3630 #ifdef STATUS_VIA_WINDOWPORT
3631 #ifdef STATUS_HILITES
3632 { "status_hilites", SET_IN_GAME
, OPT_OTHER_STATHILITE
},
3635 { (char *) 0, 0, (enum opt_other_enums
) 0 },
3638 /* the 'O' command */
3640 doset() /* changing options via menu by Per Liboriussen */
3642 static boolean made_fmtstr
= FALSE
;
3643 char buf
[BUFSZ
], buf2
[BUFSZ
];
3645 int i
= 0, pass
, boolcount
, pick_cnt
, pick_idx
, opt_indx
;
3649 menu_item
*pick_list
;
3650 int indexoffset
, startpass
, endpass
, optflags
;
3651 boolean setinitial
= FALSE
, fromfile
= FALSE
;
3652 unsigned longest_name_len
;
3654 tmpwin
= create_nhwindow(NHW_MENU
);
3657 #ifdef notyet /* SYSCF */
3658 /* XXX I think this is still fragile. Fixing initial/from_file and/or
3659 changing the SET_* etc to bitmaps will let me make this better. */
3661 startpass
= SET_IN_SYS
;
3664 startpass
= DISP_IN_GAME
;
3665 endpass
= (wizard
) ? SET_IN_WIZGAME
: SET_IN_GAME
;
3667 if (!made_fmtstr
&& !iflags
.menu_tab_sep
) {
3668 /* spin through the options to find the longest name
3669 and adjust the format string accordingly */
3670 longest_name_len
= 0;
3671 for (pass
= 0; pass
<= 2; pass
++)
3672 for (i
= 0; (name
= ((pass
== 0)
3676 : othropt
[i
].name
)) != 0; i
++) {
3677 if (pass
== 0 && !boolopt
[i
].addr
)
3679 optflags
= (pass
== 0) ? boolopt
[i
].optflags
3681 ? compopt
[i
].optflags
3682 : othropt
[i
].optflags
;
3683 if (optflags
< startpass
|| optflags
> endpass
)
3685 if ((is_wc_option(name
) && !wc_supported(name
))
3686 || (is_wc2_option(name
) && !wc2_supported(name
)))
3689 if (strlen(name
) > longest_name_len
)
3690 longest_name_len
= strlen(name
);
3692 Sprintf(fmtstr_doset
, "%%s%%-%us [%%s]", longest_name_len
);
3697 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3698 "Booleans (selecting will toggle value):", MENU_UNSELECTED
);
3700 /* first list any other non-modifiable booleans, then modifiable ones */
3701 for (pass
= 0; pass
<= 1; pass
++)
3702 for (i
= 0; (name
= boolopt
[i
].name
) != 0; i
++)
3703 if ((bool_p
= boolopt
[i
].addr
) != 0
3704 && ((boolopt
[i
].optflags
<= DISP_IN_GAME
&& pass
== 0)
3705 || (boolopt
[i
].optflags
>= SET_IN_GAME
&& pass
== 1))) {
3706 if (bool_p
== &flags
.female
)
3707 continue; /* obsolete */
3708 if (boolopt
[i
].optflags
== SET_IN_WIZGAME
&& !wizard
)
3710 if ((is_wc_option(name
) && !wc_supported(name
))
3711 || (is_wc2_option(name
) && !wc2_supported(name
)))
3714 any
.a_int
= (pass
== 0) ? 0 : i
+ 1;
3715 if (!iflags
.menu_tab_sep
)
3716 Sprintf(buf
, fmtstr_doset
, (pass
== 0) ? " " : "",
3717 name
, *bool_p
? "true" : "false");
3719 Sprintf(buf
, fmtstr_doset_tab
,
3720 name
, *bool_p
? "true" : "false");
3721 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
,
3726 indexoffset
= boolcount
;
3728 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3729 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3730 "Compounds (selecting will prompt for new value):",
3733 /* deliberately put playmode, name, role+race+gender+align first */
3734 doset_add_menu(tmpwin
, "playmode", 0);
3735 doset_add_menu(tmpwin
, "name", 0);
3736 doset_add_menu(tmpwin
, "role", 0);
3737 doset_add_menu(tmpwin
, "race", 0);
3738 doset_add_menu(tmpwin
, "gender", 0);
3739 doset_add_menu(tmpwin
, "align", 0);
3741 for (pass
= startpass
; pass
<= endpass
; pass
++)
3742 for (i
= 0; (name
= compopt
[i
].name
) != 0; i
++)
3743 if (compopt
[i
].optflags
== pass
) {
3744 if (!strcmp(name
, "playmode") || !strcmp(name
, "name")
3745 || !strcmp(name
, "role") || !strcmp(name
, "race")
3746 || !strcmp(name
, "gender") || !strcmp(name
, "align"))
3748 if ((is_wc_option(name
) && !wc_supported(name
))
3749 || (is_wc2_option(name
) && !wc2_supported(name
)))
3752 doset_add_menu(tmpwin
, name
,
3753 (pass
== DISP_IN_GAME
) ? 0 : indexoffset
);
3757 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3758 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3762 opts_add_others(tmpwin
, "autopickup exceptions", OPT_OTHER_APEXC
,
3763 NULL
, count_ape_maps((int *) 0, (int *) 0));
3764 opts_add_others(tmpwin
, "menucolors", OPT_OTHER_MENUCOLOR
,
3765 NULL
, count_menucolors());
3766 opts_add_others(tmpwin
, "message types", OPT_OTHER_MSGTYPE
,
3767 NULL
, msgtype_count());
3768 #ifdef STATUS_VIA_WINDOWPORT
3769 #ifdef STATUS_HILITES
3770 get_status_hilites(buf2
, 60);
3772 Sprintf(buf2
, "%s", "(none)");
3773 opts_add_others(tmpwin
, "status_hilites", OPT_OTHER_STATHILITE
, buf2
, 0);
3776 #ifdef PREFIXES_IN_USE
3778 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3779 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3780 "Variable playground locations:", MENU_UNSELECTED
);
3781 for (i
= 0; i
< PREFIX_COUNT
; i
++)
3782 doset_add_menu(tmpwin
, fqn_prefix_names
[i
], 0);
3784 end_menu(tmpwin
, "Set what options?");
3785 need_redraw
= FALSE
;
3786 if ((pick_cnt
= select_menu(tmpwin
, PICK_ANY
, &pick_list
)) > 0) {
3788 * Walk down the selection list and either invert the booleans
3789 * or prompt for new values. In most cases, call parseoptions()
3790 * to take care of options that require special attention, like
3793 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
) {
3794 opt_indx
= pick_list
[pick_idx
].item
.a_int
- 1;
3795 if (opt_indx
< -1) opt_indx
++; /* -1 offset for select_menu() */
3796 if (opt_indx
== OPT_OTHER_APEXC
) {
3797 (void) special_handling("autopickup_exception", setinitial
,
3799 #ifdef STATUS_VIA_WINDOWPORT
3800 #ifdef STATUS_HILITES
3801 } else if (opt_indx
== OPT_OTHER_STATHILITE
) {
3802 if (!status_hilite_menu()) {
3803 pline("Bad status hilite(s) specified.");
3805 if (wc2_supported("status_hilites"))
3806 preference_update("status_hilites");
3810 } else if (opt_indx
== OPT_OTHER_MENUCOLOR
) {
3811 (void) special_handling("menucolors", setinitial
,
3813 } else if (opt_indx
== OPT_OTHER_MSGTYPE
) {
3814 (void) special_handling("msgtype", setinitial
, fromfile
);
3815 } else if (opt_indx
< boolcount
) {
3816 /* boolean option */
3817 Sprintf(buf
, "%s%s", *boolopt
[opt_indx
].addr
? "!" : "",
3818 boolopt
[opt_indx
].name
);
3819 parseoptions(buf
, setinitial
, fromfile
);
3820 if (wc_supported(boolopt
[opt_indx
].name
)
3821 || wc2_supported(boolopt
[opt_indx
].name
))
3822 preference_update(boolopt
[opt_indx
].name
);
3824 /* compound option */
3825 opt_indx
-= boolcount
;
3827 if (!special_handling(compopt
[opt_indx
].name
, setinitial
,
3829 Sprintf(buf
, "Set %s to what?", compopt
[opt_indx
].name
);
3831 if (buf2
[0] == '\033')
3833 Sprintf(buf
, "%s:%s", compopt
[opt_indx
].name
, buf2
);
3835 parseoptions(buf
, setinitial
, fromfile
);
3837 if (wc_supported(compopt
[opt_indx
].name
)
3838 || wc2_supported(compopt
[opt_indx
].name
))
3839 preference_update(compopt
[opt_indx
].name
);
3842 free((genericptr_t
) pick_list
);
3843 pick_list
= (menu_item
*) 0;
3846 destroy_nhwindow(tmpwin
);
3855 handle_add_list_remove(optname
, numtotal
)
3856 const char *optname
;
3861 int i
, pick_cnt
, opt_idx
;
3862 menu_item
*pick_list
= (menu_item
*) 0;
3863 static const struct action
{
3866 } action_titles
[] = {
3867 { 'a', "add new %s" }, /* [0] */
3868 { 'l', "list %s" }, /* [1] */
3869 { 'r', "remove existing %s" }, /* [2] */
3870 { 'x', "exit this menu" }, /* [3] */
3874 tmpwin
= create_nhwindow(NHW_MENU
);
3877 for (i
= 0; i
< SIZE(action_titles
); i
++) {
3881 /* omit list and remove if there aren't any yet */
3882 if (!numtotal
&& (i
== 1 || i
== 2))
3884 Sprintf(tmpbuf
, action_titles
[i
].desc
,
3885 (i
== 1) ? makeplural(optname
) : optname
);
3886 add_menu(tmpwin
, NO_GLYPH
, &any
, action_titles
[i
].letr
, 0, ATR_NONE
,
3887 tmpbuf
, (i
== 3) ? MENU_SELECTED
: MENU_UNSELECTED
);
3889 end_menu(tmpwin
, "Do what?");
3890 if ((pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &pick_list
)) > 0) {
3891 opt_idx
= pick_list
[0].item
.a_int
- 1;
3892 if (pick_cnt
> 1 && opt_idx
== 3)
3893 opt_idx
= pick_list
[1].item
.a_int
- 1;
3894 free((genericptr_t
) pick_list
);
3896 opt_idx
= 3; /* none selected, exit menu */
3897 destroy_nhwindow(tmpwin
);
3901 struct symsetentry
*symset_list
= 0; /* files.c will populate this with
3902 list of available sets */
3905 special_handling(optname
, setinitial
, setfromfile
)
3906 const char *optname
;
3907 boolean setinitial
, setfromfile
;
3914 /* Special handling of menustyle, pickup_burden, pickup_types,
3915 * disclose, runmode, msg_window, menu_headings, sortloot,
3916 * and number_pad options.
3917 * Also takes care of interactive autopickup_exception_handling changes.
3919 if (!strcmp("menustyle", optname
)) {
3920 const char *style_name
;
3921 menu_item
*style_pick
= (menu_item
*) 0;
3922 tmpwin
= create_nhwindow(NHW_MENU
);
3925 for (i
= 0; i
< SIZE(menutype
); i
++) {
3926 style_name
= menutype
[i
];
3927 /* note: separate `style_name' variable used
3928 to avoid an optimizer bug in VAX C V2.3 */
3930 add_menu(tmpwin
, NO_GLYPH
, &any
, *style_name
, 0, ATR_NONE
,
3931 style_name
, MENU_UNSELECTED
);
3933 end_menu(tmpwin
, "Select menustyle:");
3934 if (select_menu(tmpwin
, PICK_ONE
, &style_pick
) > 0) {
3935 flags
.menu_style
= style_pick
->item
.a_int
- 1;
3936 free((genericptr_t
) style_pick
);
3938 destroy_nhwindow(tmpwin
);
3939 } else if (!strcmp("paranoid_confirmation", optname
)) {
3940 menu_item
*paranoia_picks
= (menu_item
*) 0;
3942 tmpwin
= create_nhwindow(NHW_MENU
);
3945 for (i
= 0; paranoia
[i
].flagmask
!= 0; ++i
) {
3946 if (paranoia
[i
].flagmask
== PARANOID_BONES
&& !wizard
)
3948 any
.a_int
= paranoia
[i
].flagmask
;
3949 add_menu(tmpwin
, NO_GLYPH
, &any
, *paranoia
[i
].argname
, 0,
3950 ATR_NONE
, paranoia
[i
].explain
,
3951 (flags
.paranoia_bits
& paranoia
[i
].flagmask
)
3955 end_menu(tmpwin
, "Actions requiring extra confirmation:");
3956 i
= select_menu(tmpwin
, PICK_ANY
, ¶noia_picks
);
3958 /* player didn't cancel; we reset all the paranoia options
3959 here even if there were no items picked, since user
3960 could have toggled off preselected ones to end up with 0 */
3961 flags
.paranoia_bits
= 0;
3963 /* at least 1 item set, either preselected or newly picked */
3965 flags
.paranoia_bits
|= paranoia_picks
[i
].item
.a_int
;
3966 free((genericptr_t
) paranoia_picks
);
3969 destroy_nhwindow(tmpwin
);
3970 } else if (!strcmp("pickup_burden", optname
)) {
3971 const char *burden_name
, *burden_letters
= "ubsntl";
3972 menu_item
*burden_pick
= (menu_item
*) 0;
3974 tmpwin
= create_nhwindow(NHW_MENU
);
3977 for (i
= 0; i
< SIZE(burdentype
); i
++) {
3978 burden_name
= burdentype
[i
];
3980 add_menu(tmpwin
, NO_GLYPH
, &any
, burden_letters
[i
], 0, ATR_NONE
,
3981 burden_name
, MENU_UNSELECTED
);
3983 end_menu(tmpwin
, "Select encumbrance level:");
3984 if (select_menu(tmpwin
, PICK_ONE
, &burden_pick
) > 0) {
3985 flags
.pickup_burden
= burden_pick
->item
.a_int
- 1;
3986 free((genericptr_t
) burden_pick
);
3988 destroy_nhwindow(tmpwin
);
3989 } else if (!strcmp("pickup_types", optname
)) {
3990 /* parseoptions will prompt for the list of types */
3991 parseoptions(strcpy(buf
, "pickup_types"), setinitial
, setfromfile
);
3992 } else if (!strcmp("disclose", optname
)) {
3993 /* order of disclose_names[] must correspond to
3994 disclosure_options in decl.c */
3995 static const char *disclosure_names
[] = {
3996 "inventory", "attributes", "vanquished",
3997 "genocides", "conduct", "overview",
3999 int disc_cat
[NUM_DISCLOSURE_OPTIONS
];
4000 int pick_cnt
, pick_idx
, opt_idx
;
4002 menu_item
*disclosure_pick
= (menu_item
*) 0;
4004 tmpwin
= create_nhwindow(NHW_MENU
);
4007 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4008 Sprintf(buf
, "%-12s[%c%c]", disclosure_names
[i
],
4009 flags
.end_disclose
[i
], disclosure_options
[i
]);
4011 add_menu(tmpwin
, NO_GLYPH
, &any
, disclosure_options
[i
], 0,
4012 ATR_NONE
, buf
, MENU_UNSELECTED
);
4015 end_menu(tmpwin
, "Change which disclosure options categories:");
4016 pick_cnt
= select_menu(tmpwin
, PICK_ANY
, &disclosure_pick
);
4018 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
) {
4019 opt_idx
= disclosure_pick
[pick_idx
].item
.a_int
- 1;
4020 disc_cat
[opt_idx
] = 1;
4022 free((genericptr_t
) disclosure_pick
);
4023 disclosure_pick
= (menu_item
*) 0;
4025 destroy_nhwindow(tmpwin
);
4027 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4029 c
= flags
.end_disclose
[i
];
4030 Sprintf(buf
, "Disclosure options for %s:",
4031 disclosure_names
[i
]);
4032 tmpwin
= create_nhwindow(NHW_MENU
);
4035 /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
4036 any
.a_char
= DISCLOSE_NO_WITHOUT_PROMPT
;
4037 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4038 "Never disclose, without prompting",
4039 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4040 any
.a_char
= DISCLOSE_YES_WITHOUT_PROMPT
;
4041 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4042 "Always disclose, without prompting",
4043 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4044 if (*disclosure_names
[i
] == 'v') {
4045 any
.a_char
= DISCLOSE_SPECIAL_WITHOUT_PROMPT
; /* '#' */
4046 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4047 "Always disclose, pick sort order from menu",
4048 (c
== any
.a_char
) ? MENU_SELECTED
4051 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_NO
;
4052 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4053 "Prompt, with default answer of \"No\"",
4054 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4055 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_YES
;
4056 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4057 "Prompt, with default answer of \"Yes\"",
4058 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4059 if (*disclosure_names
[i
] == 'v') {
4060 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_SPECIAL
; /* '?' */
4061 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4062 "Prompt, with default answer of \"Ask\" to request sort menu",
4063 (c
== any
.a_char
) ? MENU_SELECTED
4066 end_menu(tmpwin
, buf
);
4067 n
= select_menu(tmpwin
, PICK_ONE
, &disclosure_pick
);
4069 flags
.end_disclose
[i
] = disclosure_pick
[0].item
.a_char
;
4070 if (n
> 1 && flags
.end_disclose
[i
] == c
)
4071 flags
.end_disclose
[i
] = disclosure_pick
[1].item
.a_char
;
4072 free((genericptr_t
) disclosure_pick
);
4074 destroy_nhwindow(tmpwin
);
4077 } else if (!strcmp("runmode", optname
)) {
4078 const char *mode_name
;
4079 menu_item
*mode_pick
= (menu_item
*) 0;
4081 tmpwin
= create_nhwindow(NHW_MENU
);
4084 for (i
= 0; i
< SIZE(runmodes
); i
++) {
4085 mode_name
= runmodes
[i
];
4087 add_menu(tmpwin
, NO_GLYPH
, &any
, *mode_name
, 0, ATR_NONE
,
4088 mode_name
, MENU_UNSELECTED
);
4090 end_menu(tmpwin
, "Select run/travel display mode:");
4091 if (select_menu(tmpwin
, PICK_ONE
, &mode_pick
) > 0) {
4092 flags
.runmode
= mode_pick
->item
.a_int
- 1;
4093 free((genericptr_t
) mode_pick
);
4095 destroy_nhwindow(tmpwin
);
4096 } else if (!strcmp("whatis_coord", optname
)) {
4097 menu_item
*window_pick
= (menu_item
*) 0;
4099 char gp
= iflags
.getpos_coords
;
4101 tmpwin
= create_nhwindow(NHW_MENU
);
4104 any
.a_char
= GPCOORDS_COMPASS
;
4105 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_COMPASS
,
4106 0, ATR_NONE
, "compass ('east' or '3s' or '2n,4w')",
4107 (gp
== GPCOORDS_COMPASS
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4108 any
.a_char
= GPCOORDS_COMFULL
;
4109 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_COMFULL
,
4110 0, ATR_NONE
, "full compass ('east' or '3south' or '2north,4west')",
4111 (gp
== GPCOORDS_COMFULL
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4112 any
.a_char
= GPCOORDS_MAP
;
4113 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_MAP
,
4114 0, ATR_NONE
, "map <x,y>",
4115 (gp
== GPCOORDS_MAP
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4116 any
.a_char
= GPCOORDS_SCREEN
;
4117 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_SCREEN
,
4118 0, ATR_NONE
, "screen [row,column]",
4119 (gp
== GPCOORDS_SCREEN
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4120 any
.a_char
= GPCOORDS_NONE
;
4121 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_NONE
,
4122 0, ATR_NONE
, "none (no coordinates displayed)",
4123 (gp
== GPCOORDS_NONE
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4125 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
4126 Sprintf(buf
, "map: upper-left: <%d,%d>, lower-right: <%d,%d>%s",
4127 1, 0, COLNO
- 1, ROWNO
- 1,
4128 flags
.verbose
? "; column 0 unused, off left edge" : "");
4129 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
4130 if (strcmp(windowprocs
.name
, "tty"))
4131 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
4132 "screen: row is offset to accommodate tty interface's use of top line",
4135 #define COL80ARG flags.verbose ? "; column 80 is not used" : ""
4139 Sprintf(buf
, "screen: upper-left: [%02d,%02d], lower-right: [%d,%d]%s",
4140 0 + 2, 1, ROWNO
- 1 + 2, COLNO
- 1, COL80ARG
);
4142 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
4143 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
4145 "Select coordinate display when auto-describing a map position:");
4146 if ((pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &window_pick
)) > 0) {
4147 iflags
.getpos_coords
= window_pick
[0].item
.a_char
;
4148 /* PICK_ONE doesn't unselect preselected entry when
4149 selecting another one */
4150 if (pick_cnt
> 1 && iflags
.getpos_coords
== gp
)
4151 iflags
.getpos_coords
= window_pick
[1].item
.a_char
;
4152 free((genericptr_t
) window_pick
);
4154 destroy_nhwindow(tmpwin
);
4155 } else if (!strcmp("msg_window", optname
)) {
4157 /* by Christian W. Cooper */
4158 menu_item
*window_pick
= (menu_item
*) 0;
4160 tmpwin
= create_nhwindow(NHW_MENU
);
4164 add_menu(tmpwin
, NO_GLYPH
, &any
, 's', 0, ATR_NONE
, "single",
4167 add_menu(tmpwin
, NO_GLYPH
, &any
, 'c', 0, ATR_NONE
, "combination",
4170 add_menu(tmpwin
, NO_GLYPH
, &any
, 'f', 0, ATR_NONE
, "full",
4173 add_menu(tmpwin
, NO_GLYPH
, &any
, 'r', 0, ATR_NONE
, "reversed",
4175 end_menu(tmpwin
, "Select message history display type:");
4176 if (select_menu(tmpwin
, PICK_ONE
, &window_pick
) > 0) {
4177 iflags
.prevmsg_window
= window_pick
->item
.a_char
;
4178 free((genericptr_t
) window_pick
);
4180 destroy_nhwindow(tmpwin
);
4182 } else if (!strcmp("sortloot", optname
)) {
4183 const char *sortl_name
;
4184 menu_item
*sortl_pick
= (menu_item
*) 0;
4186 tmpwin
= create_nhwindow(NHW_MENU
);
4189 for (i
= 0; i
< SIZE(sortltype
); i
++) {
4190 sortl_name
= sortltype
[i
];
4191 any
.a_char
= *sortl_name
;
4192 add_menu(tmpwin
, NO_GLYPH
, &any
, *sortl_name
, 0, ATR_NONE
,
4193 sortl_name
, (flags
.sortloot
== *sortl_name
)
4194 ? MENU_SELECTED
: MENU_UNSELECTED
);
4196 end_menu(tmpwin
, "Select loot sorting type:");
4197 n
= select_menu(tmpwin
, PICK_ONE
, &sortl_pick
);
4199 char c
= sortl_pick
[0].item
.a_char
;
4201 if (n
> 1 && c
== flags
.sortloot
)
4202 c
= sortl_pick
[1].item
.a_char
;
4204 free((genericptr_t
) sortl_pick
);
4206 destroy_nhwindow(tmpwin
);
4207 } else if (!strcmp("align_message", optname
)
4208 || !strcmp("align_status", optname
)) {
4209 menu_item
*window_pick
= (menu_item
*) 0;
4211 boolean msg
= (*(optname
+ 6) == 'm');
4213 tmpwin
= create_nhwindow(NHW_MENU
);
4216 any
.a_int
= ALIGN_TOP
;
4217 add_menu(tmpwin
, NO_GLYPH
, &any
, 't', 0, ATR_NONE
, "top",
4219 any
.a_int
= ALIGN_BOTTOM
;
4220 add_menu(tmpwin
, NO_GLYPH
, &any
, 'b', 0, ATR_NONE
, "bottom",
4222 any
.a_int
= ALIGN_LEFT
;
4223 add_menu(tmpwin
, NO_GLYPH
, &any
, 'l', 0, ATR_NONE
, "left",
4225 any
.a_int
= ALIGN_RIGHT
;
4226 add_menu(tmpwin
, NO_GLYPH
, &any
, 'r', 0, ATR_NONE
, "right",
4228 Sprintf(abuf
, "Select %s window placement relative to the map:",
4229 msg
? "message" : "status");
4230 end_menu(tmpwin
, abuf
);
4231 if (select_menu(tmpwin
, PICK_ONE
, &window_pick
) > 0) {
4233 iflags
.wc_align_message
= window_pick
->item
.a_int
;
4235 iflags
.wc_align_status
= window_pick
->item
.a_int
;
4236 free((genericptr_t
) window_pick
);
4238 destroy_nhwindow(tmpwin
);
4239 } else if (!strcmp("number_pad", optname
)) {
4240 static const char *npchoices
[] = {
4241 " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
4242 " 3 (on, phone-style digit layout)",
4243 " 4 (on, phone-style layout, MSDOS compatible)",
4244 "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
4246 menu_item
*mode_pick
= (menu_item
*) 0;
4248 tmpwin
= create_nhwindow(NHW_MENU
);
4251 for (i
= 0; i
< SIZE(npchoices
); i
++) {
4253 add_menu(tmpwin
, NO_GLYPH
, &any
, 'a' + i
, 0, ATR_NONE
,
4254 npchoices
[i
], MENU_UNSELECTED
);
4256 end_menu(tmpwin
, "Select number_pad mode:");
4257 if (select_menu(tmpwin
, PICK_ONE
, &mode_pick
) > 0) {
4258 switch (mode_pick
->item
.a_int
- 1) {
4260 iflags
.num_pad
= FALSE
;
4261 iflags
.num_pad_mode
= 0;
4264 iflags
.num_pad
= TRUE
;
4265 iflags
.num_pad_mode
= 0;
4268 iflags
.num_pad
= TRUE
;
4269 iflags
.num_pad_mode
= 1;
4272 iflags
.num_pad
= TRUE
;
4273 iflags
.num_pad_mode
= 2;
4276 iflags
.num_pad
= TRUE
;
4277 iflags
.num_pad_mode
= 3;
4279 /* last menu choice: number_pad == -1 */
4281 iflags
.num_pad
= FALSE
;
4282 iflags
.num_pad_mode
= 1;
4285 reset_commands(FALSE
);
4286 number_pad(iflags
.num_pad
? 1 : 0);
4287 free((genericptr_t
) mode_pick
);
4289 destroy_nhwindow(tmpwin
);
4290 } else if (!strcmp("menu_headings", optname
)) {
4291 int mhattr
= query_attr("How to highlight menu headings:");
4294 iflags
.menu_headings
= mhattr
;
4295 } else if (!strcmp("msgtype", optname
)) {
4296 int opt_idx
, nmt
, mttyp
;
4300 nmt
= msgtype_count();
4301 opt_idx
= handle_add_list_remove("message type", nmt
);
4302 if (opt_idx
== 3) { /* done */
4304 } else if (opt_idx
== 0) { /* add new */
4305 getlin("What new message pattern?", mtbuf
);
4306 if (*mtbuf
== '\033')
4309 && (mttyp
= query_msgtype()) != -1
4310 && !msgtype_add(mttyp
, mtbuf
)) {
4311 pline("Error adding the message type.");
4314 goto msgtypes_again
;
4315 } else { /* list (1) or remove (2) */
4316 int pick_idx
, pick_cnt
;
4320 menu_item
*pick_list
= (menu_item
*) 0;
4321 struct plinemsg_type
*tmp
= plinemsg_types
;
4323 tmpwin
= create_nhwindow(NHW_MENU
);
4328 mtype
= msgtype2name(tmp
->msgtype
);
4329 any
.a_int
= ++mt_idx
;
4330 Sprintf(mtbuf
, "%-5s \"", mtype
);
4331 ln
= sizeof mtbuf
- strlen(mtbuf
) - sizeof "\"";
4332 if (strlen(tmp
->pattern
) > ln
)
4333 Strcat(strncat(mtbuf
, tmp
->pattern
, ln
- 3), "...\"");
4335 Strcat(mtbuf
, "\"");
4336 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, mtbuf
,
4340 Sprintf(mtbuf
, "%s message types",
4341 (opt_idx
== 1) ? "List of" : "Remove which");
4342 end_menu(tmpwin
, mtbuf
);
4343 pick_cnt
= select_menu(tmpwin
,
4344 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4347 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4348 free_one_msgtype(pick_list
[pick_idx
].item
.a_int
- 1
4350 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4352 destroy_nhwindow(tmpwin
);
4354 goto msgtypes_again
;
4356 } else if (!strcmp("menucolors", optname
)) {
4357 int opt_idx
, nmc
, mcclr
, mcattr
;
4361 nmc
= count_menucolors();
4362 opt_idx
= handle_add_list_remove("menucolor", nmc
);
4363 if (opt_idx
== 3) { /* done */
4365 } else if (opt_idx
== 0) { /* add new */
4366 getlin("What new menucolor pattern?", mcbuf
);
4367 if (*mcbuf
== '\033')
4370 && (mcclr
= query_color()) != -1
4371 && (mcattr
= query_attr((char *) 0)) != -1
4372 && !add_menu_coloring_parsed(mcbuf
, mcclr
, mcattr
)) {
4373 pline("Error adding the menu color.");
4376 goto menucolors_again
;
4377 } else { /* list (1) or remove (2) */
4378 int pick_idx
, pick_cnt
;
4381 const char *sattr
, *sclr
;
4382 menu_item
*pick_list
= (menu_item
*) 0;
4383 struct menucoloring
*tmp
= menu_colorings
;
4385 tmpwin
= create_nhwindow(NHW_MENU
);
4390 sattr
= attr2attrname(tmp
->attr
);
4391 sclr
= clr2colorname(tmp
->color
);
4392 any
.a_int
= ++mc_idx
;
4393 /* construct suffix */
4394 Sprintf(buf
, "\"\"=%s%s%s", sclr
,
4395 (tmp
->attr
!= ATR_NONE
) ? " & " : "",
4396 (tmp
->attr
!= ATR_NONE
) ? sattr
: "");
4397 /* now main string */
4398 ln
= sizeof buf
- strlen(buf
) - 1; /* length available */
4399 Strcpy(mcbuf
, "\"");
4400 if (strlen(tmp
->origstr
) > ln
)
4401 Strcat(strncat(mcbuf
, tmp
->origstr
, ln
- 3), "...");
4403 Strcat(mcbuf
, tmp
->origstr
);
4404 /* combine main string and suffix */
4405 Strcat(mcbuf
, &buf
[1]); /* skip buf[]'s initial quote */
4406 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, mcbuf
,
4410 Sprintf(mcbuf
, "%s menu colors",
4411 (opt_idx
== 1) ? "List of" : "Remove which");
4412 end_menu(tmpwin
, mcbuf
);
4413 pick_cnt
= select_menu(tmpwin
,
4414 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4417 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4418 free_one_menu_coloring(pick_list
[pick_idx
].item
.a_int
- 1
4420 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4422 destroy_nhwindow(tmpwin
);
4424 goto menucolors_again
;
4426 } else if (!strcmp("autopickup_exception", optname
)) {
4427 int opt_idx
, pass
, totalapes
= 0, numapes
[2] = { 0, 0 };
4428 char apebuf
[1 + BUFSZ
]; /* so &apebuf[1] is BUFSZ long for getlin() */
4429 struct autopickup_exception
*ape
;
4432 totalapes
= count_ape_maps(&numapes
[AP_LEAVE
], &numapes
[AP_GRAB
]);
4433 opt_idx
= handle_add_list_remove("autopickup exception", totalapes
);
4434 if (opt_idx
== 3) { /* done */
4436 } else if (opt_idx
== 0) { /* add new */
4437 getlin("What new autopickup exception pattern?", &apebuf
[1]);
4438 mungspaces(&apebuf
[1]); /* regularize whitespace */
4439 if (apebuf
[1] == '\033')
4443 /* guarantee room for \" prefix and \"\0 suffix;
4444 -2 is good enough for apebuf[] but -3 makes
4445 sure the whole thing fits within normal BUFSZ */
4446 apebuf
[sizeof apebuf
- 3] = '\0';
4447 Strcat(apebuf
, "\"");
4448 add_autopickup_exception(apebuf
);
4451 } else { /* list (1) or remove (2) */
4452 int pick_idx
, pick_cnt
;
4453 menu_item
*pick_list
= (menu_item
*) 0;
4455 tmpwin
= create_nhwindow(NHW_MENU
);
4457 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
4458 if (numapes
[pass
] == 0)
4460 ape
= iflags
.autopickup_exceptions
[pass
];
4462 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
4463 (pass
== 0) ? "Never pickup" : "Always pickup",
4465 for (i
= 0; i
< numapes
[pass
] && ape
; i
++) {
4466 any
.a_void
= (opt_idx
== 1) ? 0 : ape
;
4467 /* length of pattern plus quotes is less than BUFSZ */
4468 Sprintf(apebuf
, "\"%s\"", ape
->pattern
);
4469 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, apebuf
,
4474 Sprintf(apebuf
, "%s autopickup exceptions",
4475 (opt_idx
== 1) ? "List of" : "Remove which");
4476 end_menu(tmpwin
, apebuf
);
4477 pick_cnt
= select_menu(tmpwin
,
4478 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4481 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4482 remove_autopickup_exception(
4483 (struct autopickup_exception
*)
4484 pick_list
[pick_idx
].item
.a_void
);
4485 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4487 destroy_nhwindow(tmpwin
);
4491 } else if (!strcmp("symset", optname
)
4492 || !strcmp("roguesymset", optname
)) {
4493 menu_item
*symset_pick
= (menu_item
*) 0;
4494 boolean primaryflag
= (*optname
== 's'),
4495 rogueflag
= (*optname
== 'r'),
4496 ready_to_switch
= FALSE
,
4497 nothing_to_do
= FALSE
;
4498 char *symset_name
, fmtstr
[20];
4499 struct symsetentry
*sl
;
4500 int res
, which_set
, setcount
= 0, chosen
= -2;
4503 which_set
= ROGUESET
;
4505 which_set
= PRIMARY
;
4507 /* clear symset[].name as a flag to read_sym_file() to build list */
4508 symset_name
= symset
[which_set
].name
;
4509 symset
[which_set
].name
= (char *) 0;
4510 symset_list
= (struct symsetentry
*) 0;
4512 res
= read_sym_file(which_set
);
4513 if (res
&& symset_list
) {
4514 char symsetchoice
[BUFSZ
];
4515 int let
= 'a', biggest
= 0, thissize
= 0;
4519 /* check restrictions */
4520 if ((!rogueflag
&& sl
->rogue
)
4521 || (!primaryflag
&& sl
->primary
)) {
4526 /* find biggest name */
4528 thissize
= strlen(sl
->name
);
4529 if (thissize
> biggest
)
4534 pline("There are no appropriate %ssymbol sets available.",
4535 (rogueflag
) ? "rogue level "
4536 : (primaryflag
) ? "primary " : "");
4540 Sprintf(fmtstr
, "%%-%ds %%s", biggest
+ 5);
4541 tmpwin
= create_nhwindow(NHW_MENU
);
4545 add_menu(tmpwin
, NO_GLYPH
, &any
, let
++, 0, ATR_NONE
,
4546 "Default Symbols", MENU_UNSELECTED
);
4550 /* check restrictions */
4551 if ((!rogueflag
&& sl
->rogue
)
4552 || (!primaryflag
&& sl
->primary
)) {
4557 any
.a_int
= sl
->idx
+ 2;
4558 Sprintf(symsetchoice
, fmtstr
, sl
->name
,
4559 sl
->desc
? sl
->desc
: "");
4560 add_menu(tmpwin
, NO_GLYPH
, &any
, let
, 0, ATR_NONE
,
4561 symsetchoice
, MENU_UNSELECTED
);
4569 Sprintf(buf
, "Select %ssymbol set:", rogueflag
? "rogue level " : "");
4570 end_menu(tmpwin
, buf
);
4571 if (select_menu(tmpwin
, PICK_ONE
, &symset_pick
) > 0) {
4572 chosen
= symset_pick
->item
.a_int
- 2;
4573 free((genericptr_t
) symset_pick
);
4575 destroy_nhwindow(tmpwin
);
4578 /* chose an actual symset name from file */
4581 if (sl
->idx
== chosen
) {
4583 free((genericptr_t
) symset_name
);
4584 symset_name
= (char *) 0;
4586 /* free the now stale attributes */
4587 clear_symsetentry(which_set
, TRUE
);
4589 /* transfer only the name of the symbol set */
4590 symset
[which_set
].name
= dupstr(sl
->name
);
4591 ready_to_switch
= TRUE
;
4596 } else if (chosen
== -1) {
4597 /* explicit selection of defaults */
4598 /* free the now stale symset attributes */
4600 free((genericptr_t
) symset_name
);
4601 symset_name
= (char *) 0;
4603 clear_symsetentry(which_set
, TRUE
);
4605 nothing_to_do
= TRUE
;
4607 /* The symbols file could not be accessed */
4608 pline("Unable to access \"%s\" file.", SYMBOLS
);
4610 } else if (!symset_list
) {
4611 /* The symbols file was empty */
4612 pline("There were no symbol sets found in \"%s\".", SYMBOLS
);
4617 while (symset_list
) {
4620 free((genericptr_t
) sl
->name
);
4621 sl
->name
= (char *) 0;
4624 free((genericptr_t
) sl
->desc
);
4625 sl
->desc
= (char *) 0;
4627 symset_list
= sl
->next
;
4628 free((genericptr_t
) sl
);
4634 if (!symset
[which_set
].name
&& symset_name
)
4635 symset
[which_set
].name
= symset_name
; /* not dupstr() here */
4637 /* Set default symbols and clear the handling value */
4643 if (symset
[which_set
].name
) {
4644 if (read_sym_file(which_set
)) {
4645 ready_to_switch
= TRUE
;
4647 clear_symsetentry(which_set
, TRUE
);
4652 if (ready_to_switch
)
4653 switch_symbols(TRUE
);
4655 if (Is_rogue_level(&u
.uz
)) {
4657 assign_graphics(ROGUESET
);
4658 } else if (!rogueflag
)
4659 assign_graphics(PRIMARY
);
4664 /* didn't match any of the special options */
4670 #define rolestring(val, array, field) \
4671 ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none)
4673 /* This is ugly. We have all the option names in the compopt[] array,
4674 but we need to look at each option individually to get the value. */
4675 STATIC_OVL
const char *
4676 get_compopt_value(optname
, buf
)
4677 const char *optname
;
4680 char ocl
[MAXOCLASSES
+ 1];
4681 static const char none
[] = "(none)", randomrole
[] = "random",
4682 to_be_done
[] = "(to be done)", defopt
[] = "default",
4687 if (!strcmp(optname
, "align_message"))
4689 iflags
.wc_align_message
== ALIGN_TOP
4691 : iflags
.wc_align_message
== ALIGN_LEFT
4693 : iflags
.wc_align_message
== ALIGN_BOTTOM
4695 : iflags
.wc_align_message
== ALIGN_RIGHT
4698 else if (!strcmp(optname
, "align_status"))
4700 iflags
.wc_align_status
== ALIGN_TOP
4702 : iflags
.wc_align_status
== ALIGN_LEFT
4704 : iflags
.wc_align_status
== ALIGN_BOTTOM
4706 : iflags
.wc_align_status
== ALIGN_RIGHT
4709 else if (!strcmp(optname
, "align"))
4710 Sprintf(buf
, "%s", rolestring(flags
.initalign
, aligns
, adj
));
4712 else if (!strcmp(optname
, "altkeyhandler"))
4714 iflags
.altkeyhandler
[0] ? iflags
.altkeyhandler
: "default");
4716 #ifdef BACKWARD_COMPAT
4717 else if (!strcmp(optname
, "boulder"))
4721 : showsyms
[(int) objects
[BOULDER
].oc_class
+ SYM_OFF_O
]);
4723 else if (!strcmp(optname
, "catname"))
4724 Sprintf(buf
, "%s", catname
[0] ? catname
: none
);
4725 else if (!strcmp(optname
, "disclose"))
4726 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4728 (void) strkitten(buf
, ' ');
4729 (void) strkitten(buf
, flags
.end_disclose
[i
]);
4730 (void) strkitten(buf
, disclosure_options
[i
]);
4732 else if (!strcmp(optname
, "dogname"))
4733 Sprintf(buf
, "%s", dogname
[0] ? dogname
: none
);
4734 else if (!strcmp(optname
, "dungeon"))
4735 Sprintf(buf
, "%s", to_be_done
);
4736 else if (!strcmp(optname
, "effects"))
4737 Sprintf(buf
, "%s", to_be_done
);
4738 else if (!strcmp(optname
, "font_map"))
4739 Sprintf(buf
, "%s", iflags
.wc_font_map
? iflags
.wc_font_map
: defopt
);
4740 else if (!strcmp(optname
, "font_message"))
4742 iflags
.wc_font_message
? iflags
.wc_font_message
: defopt
);
4743 else if (!strcmp(optname
, "font_status"))
4745 iflags
.wc_font_status
? iflags
.wc_font_status
: defopt
);
4746 else if (!strcmp(optname
, "font_menu"))
4748 iflags
.wc_font_menu
? iflags
.wc_font_menu
: defopt
);
4749 else if (!strcmp(optname
, "font_text"))
4751 iflags
.wc_font_text
? iflags
.wc_font_text
: defopt
);
4752 else if (!strcmp(optname
, "font_size_map")) {
4753 if (iflags
.wc_fontsiz_map
)
4754 Sprintf(buf
, "%d", iflags
.wc_fontsiz_map
);
4756 Strcpy(buf
, defopt
);
4757 } else if (!strcmp(optname
, "font_size_message")) {
4758 if (iflags
.wc_fontsiz_message
)
4759 Sprintf(buf
, "%d", iflags
.wc_fontsiz_message
);
4761 Strcpy(buf
, defopt
);
4762 } else if (!strcmp(optname
, "font_size_status")) {
4763 if (iflags
.wc_fontsiz_status
)
4764 Sprintf(buf
, "%d", iflags
.wc_fontsiz_status
);
4766 Strcpy(buf
, defopt
);
4767 } else if (!strcmp(optname
, "font_size_menu")) {
4768 if (iflags
.wc_fontsiz_menu
)
4769 Sprintf(buf
, "%d", iflags
.wc_fontsiz_menu
);
4771 Strcpy(buf
, defopt
);
4772 } else if (!strcmp(optname
, "font_size_text")) {
4773 if (iflags
.wc_fontsiz_text
)
4774 Sprintf(buf
, "%d", iflags
.wc_fontsiz_text
);
4776 Strcpy(buf
, defopt
);
4777 } else if (!strcmp(optname
, "fruit"))
4778 Sprintf(buf
, "%s", pl_fruit
);
4779 else if (!strcmp(optname
, "gender"))
4780 Sprintf(buf
, "%s", rolestring(flags
.initgend
, genders
, adj
));
4781 else if (!strcmp(optname
, "horsename"))
4782 Sprintf(buf
, "%s", horsename
[0] ? horsename
: none
);
4783 else if (!strcmp(optname
, "map_mode"))
4785 iflags
.wc_map_mode
== MAP_MODE_TILES
4787 : iflags
.wc_map_mode
== MAP_MODE_ASCII4x6
4789 : iflags
.wc_map_mode
== MAP_MODE_ASCII6x8
4791 : iflags
.wc_map_mode
== MAP_MODE_ASCII8x8
4793 : iflags
.wc_map_mode
== MAP_MODE_ASCII16x8
4795 : iflags
.wc_map_mode
== MAP_MODE_ASCII7x12
4797 : iflags
.wc_map_mode
== MAP_MODE_ASCII8x12
4799 : iflags
.wc_map_mode
4800 == MAP_MODE_ASCII16x12
4802 : iflags
.wc_map_mode
4803 == MAP_MODE_ASCII12x16
4805 : iflags
.wc_map_mode
4806 == MAP_MODE_ASCII10x18
4808 : iflags
.wc_map_mode
4809 == MAP_MODE_ASCII_FIT_TO_SCREEN
4812 else if (!strcmp(optname
, "menustyle"))
4813 Sprintf(buf
, "%s", menutype
[(int) flags
.menu_style
]);
4814 else if (!strcmp(optname
, "menu_deselect_all"))
4815 Sprintf(buf
, "%s", to_be_done
);
4816 else if (!strcmp(optname
, "menu_deselect_page"))
4817 Sprintf(buf
, "%s", to_be_done
);
4818 else if (!strcmp(optname
, "menu_first_page"))
4819 Sprintf(buf
, "%s", to_be_done
);
4820 else if (!strcmp(optname
, "menu_invert_all"))
4821 Sprintf(buf
, "%s", to_be_done
);
4822 else if (!strcmp(optname
, "menu_headings"))
4823 Sprintf(buf
, "%s", attr2attrname(iflags
.menu_headings
));
4824 else if (!strcmp(optname
, "menu_invert_page"))
4825 Sprintf(buf
, "%s", to_be_done
);
4826 else if (!strcmp(optname
, "menu_last_page"))
4827 Sprintf(buf
, "%s", to_be_done
);
4828 else if (!strcmp(optname
, "menu_next_page"))
4829 Sprintf(buf
, "%s", to_be_done
);
4830 else if (!strcmp(optname
, "menu_previous_page"))
4831 Sprintf(buf
, "%s", to_be_done
);
4832 else if (!strcmp(optname
, "menu_search"))
4833 Sprintf(buf
, "%s", to_be_done
);
4834 else if (!strcmp(optname
, "menu_select_all"))
4835 Sprintf(buf
, "%s", to_be_done
);
4836 else if (!strcmp(optname
, "menu_select_page"))
4837 Sprintf(buf
, "%s", to_be_done
);
4838 else if (!strcmp(optname
, "monsters")) {
4839 Sprintf(buf
, "%s", to_be_done
);
4840 } else if (!strcmp(optname
, "msghistory")) {
4841 Sprintf(buf
, "%u", iflags
.msg_history
);
4843 } else if (!strcmp(optname
, "msg_window")) {
4844 Sprintf(buf
, "%s", (iflags
.prevmsg_window
== 's')
4846 : (iflags
.prevmsg_window
== 'c')
4848 : (iflags
.prevmsg_window
== 'f')
4852 } else if (!strcmp(optname
, "name")) {
4853 Sprintf(buf
, "%s", plname
);
4854 } else if (!strcmp(optname
, "number_pad")) {
4855 static const char *numpadmodes
[] = {
4856 "0=off", "1=on", "2=on, MSDOS compatible",
4857 "3=on, phone-style layout",
4858 "4=on, phone layout, MSDOS compatible",
4859 "-1=off, y & z swapped", /*[5]*/
4861 int indx
= Cmd
.num_pad
4862 ? (Cmd
.phone_layout
? (Cmd
.pcHack_compat
? 4 : 3)
4863 : (Cmd
.pcHack_compat
? 2 : 1))
4864 : Cmd
.swap_yz
? 5 : 0;
4866 Strcpy(buf
, numpadmodes
[indx
]);
4867 } else if (!strcmp(optname
, "objects")) {
4868 Sprintf(buf
, "%s", to_be_done
);
4869 } else if (!strcmp(optname
, "packorder")) {
4870 oc_to_str(flags
.inv_order
, ocl
);
4871 Sprintf(buf
, "%s", ocl
);
4873 } else if (!strcmp(optname
, "palette")) {
4874 Sprintf(buf
, "%s", get_color_string());
4876 } else if (!strcmp(optname
, "paranoid_confirmation")) {
4877 char tmpbuf
[QBUFSZ
];
4880 if (ParanoidConfirm
)
4881 Strcat(tmpbuf
, " Confirm");
4883 Strcat(tmpbuf
, " quit");
4885 Strcat(tmpbuf
, " die");
4887 Strcat(tmpbuf
, " bones");
4889 Strcat(tmpbuf
, " attack");
4891 Strcat(tmpbuf
, " pray");
4893 Strcat(tmpbuf
, " Remove");
4894 Strcpy(buf
, tmpbuf
[0] ? &tmpbuf
[1] : "none");
4895 } else if (!strcmp(optname
, "pettype")) {
4896 Sprintf(buf
, "%s", (preferred_pet
== 'c') ? "cat"
4897 : (preferred_pet
== 'd') ? "dog"
4898 : (preferred_pet
== 'h') ? "horse"
4899 : (preferred_pet
== 'n') ? "none"
4901 } else if (!strcmp(optname
, "pickup_burden")) {
4902 Sprintf(buf
, "%s", burdentype
[flags
.pickup_burden
]);
4903 } else if (!strcmp(optname
, "pickup_types")) {
4904 oc_to_str(flags
.pickup_types
, ocl
);
4905 Sprintf(buf
, "%s", ocl
[0] ? ocl
: "all");
4906 } else if (!strcmp(optname
, "pile_limit")) {
4907 Sprintf(buf
, "%d", flags
.pile_limit
);
4908 } else if (!strcmp(optname
, "playmode")) {
4909 Strcpy(buf
, wizard
? "debug" : discover
? "explore" : "normal");
4910 } else if (!strcmp(optname
, "race")) {
4911 Sprintf(buf
, "%s", rolestring(flags
.initrace
, races
, noun
));
4912 } else if (!strcmp(optname
, "roguesymset")) {
4914 symset
[ROGUESET
].name
? symset
[ROGUESET
].name
: "default");
4915 if (currentgraphics
== ROGUESET
&& symset
[ROGUESET
].name
)
4916 Strcat(buf
, ", active");
4917 } else if (!strcmp(optname
, "role")) {
4918 Sprintf(buf
, "%s", rolestring(flags
.initrole
, roles
, name
.m
));
4919 } else if (!strcmp(optname
, "runmode")) {
4920 Sprintf(buf
, "%s", runmodes
[flags
.runmode
]);
4921 } else if (!strcmp(optname
, "whatis_coord")) {
4923 (iflags
.getpos_coords
== GPCOORDS_MAP
) ? "map"
4924 : (iflags
.getpos_coords
== GPCOORDS_COMPASS
) ? "compass"
4925 : (iflags
.getpos_coords
== GPCOORDS_COMFULL
) ? "full compass"
4926 : (iflags
.getpos_coords
== GPCOORDS_SCREEN
) ? "screen"
4928 } else if (!strcmp(optname
, "scores")) {
4929 Sprintf(buf
, "%d top/%d around%s", flags
.end_top
, flags
.end_around
,
4930 flags
.end_own
? "/own" : "");
4931 } else if (!strcmp(optname
, "scroll_amount")) {
4932 if (iflags
.wc_scroll_amount
)
4933 Sprintf(buf
, "%d", iflags
.wc_scroll_amount
);
4935 Strcpy(buf
, defopt
);
4936 } else if (!strcmp(optname
, "scroll_margin")) {
4937 if (iflags
.wc_scroll_margin
)
4938 Sprintf(buf
, "%d", iflags
.wc_scroll_margin
);
4940 Strcpy(buf
, defopt
);
4941 } else if (!strcmp(optname
, "sortloot")) {
4942 for (i
= 0; i
< SIZE(sortltype
); i
++)
4943 if (flags
.sortloot
== sortltype
[i
][0]) {
4944 Strcpy(buf
, sortltype
[i
]);
4947 } else if (!strcmp(optname
, "player_selection")) {
4948 Sprintf(buf
, "%s", iflags
.wc_player_selection
? "prompts" : "dialog");
4950 } else if (!strcmp(optname
, "soundcard")) {
4951 Sprintf(buf
, "%s", to_be_done
);
4953 } else if (!strcmp(optname
, "suppress_alert")) {
4954 if (flags
.suppress_alert
== 0L)
4957 Sprintf(buf
, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ
,
4958 FEATURE_NOTICE_VER_MIN
, FEATURE_NOTICE_VER_PATCH
);
4959 } else if (!strcmp(optname
, "symset")) {
4961 symset
[PRIMARY
].name
? symset
[PRIMARY
].name
: "default");
4962 if (currentgraphics
== PRIMARY
&& symset
[PRIMARY
].name
)
4963 Strcat(buf
, ", active");
4964 } else if (!strcmp(optname
, "tile_file")) {
4966 iflags
.wc_tile_file
? iflags
.wc_tile_file
: defopt
);
4967 } else if (!strcmp(optname
, "tile_height")) {
4968 if (iflags
.wc_tile_height
)
4969 Sprintf(buf
, "%d", iflags
.wc_tile_height
);
4971 Strcpy(buf
, defopt
);
4972 } else if (!strcmp(optname
, "tile_width")) {
4973 if (iflags
.wc_tile_width
)
4974 Sprintf(buf
, "%d", iflags
.wc_tile_width
);
4976 Strcpy(buf
, defopt
);
4977 } else if (!strcmp(optname
, "traps")) {
4978 Sprintf(buf
, "%s", to_be_done
);
4979 } else if (!strcmp(optname
, "vary_msgcount")) {
4980 if (iflags
.wc_vary_msgcount
)
4981 Sprintf(buf
, "%d", iflags
.wc_vary_msgcount
);
4983 Strcpy(buf
, defopt
);
4985 } else if (!strcmp(optname
, "video")) {
4986 Sprintf(buf
, "%s", to_be_done
);
4989 } else if (!strcmp(optname
, "videoshades")) {
4990 Sprintf(buf
, "%s-%s-%s", shade
[0], shade
[1], shade
[2]);
4991 } else if (!strcmp(optname
, "videocolors")) {
4992 Sprintf(buf
, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
4993 ttycolors
[CLR_RED
], ttycolors
[CLR_GREEN
],
4994 ttycolors
[CLR_BROWN
], ttycolors
[CLR_BLUE
],
4995 ttycolors
[CLR_MAGENTA
], ttycolors
[CLR_CYAN
],
4996 ttycolors
[CLR_ORANGE
], ttycolors
[CLR_BRIGHT_GREEN
],
4997 ttycolors
[CLR_YELLOW
], ttycolors
[CLR_BRIGHT_BLUE
],
4998 ttycolors
[CLR_BRIGHT_MAGENTA
], ttycolors
[CLR_BRIGHT_CYAN
]);
4999 #endif /* VIDEOSHADES */
5000 } else if (!strcmp(optname
, "windowtype")) {
5001 Sprintf(buf
, "%s", windowprocs
.name
);
5002 } else if (!strcmp(optname
, "windowcolors")) {
5004 buf
, "%s/%s %s/%s %s/%s %s/%s",
5005 iflags
.wc_foregrnd_menu
? iflags
.wc_foregrnd_menu
: defbrief
,
5006 iflags
.wc_backgrnd_menu
? iflags
.wc_backgrnd_menu
: defbrief
,
5007 iflags
.wc_foregrnd_message
? iflags
.wc_foregrnd_message
5009 iflags
.wc_backgrnd_message
? iflags
.wc_backgrnd_message
5011 iflags
.wc_foregrnd_status
? iflags
.wc_foregrnd_status
: defbrief
,
5012 iflags
.wc_backgrnd_status
? iflags
.wc_backgrnd_status
: defbrief
,
5013 iflags
.wc_foregrnd_text
? iflags
.wc_foregrnd_text
: defbrief
,
5014 iflags
.wc_backgrnd_text
? iflags
.wc_backgrnd_text
: defbrief
);
5015 #ifdef PREFIXES_IN_USE
5017 for (i
= 0; i
< PREFIX_COUNT
; ++i
)
5018 if (!strcmp(optname
, fqn_prefix_names
[i
]) && fqn_prefix
[i
])
5019 Sprintf(buf
, "%s", fqn_prefix
[i
]);
5032 char buf
[BUFSZ
], ocl
[MAXOCLASSES
+ 1];
5034 flags
.pickup
= !flags
.pickup
;
5036 oc_to_str(flags
.pickup_types
, ocl
);
5037 Sprintf(buf
, "ON, for %s objects%s", ocl
[0] ? ocl
: "all",
5038 (iflags
.autopickup_exceptions
[AP_LEAVE
]
5039 || iflags
.autopickup_exceptions
[AP_GRAB
])
5040 ? ((count_ape_maps((int *) 0, (int *) 0) == 1)
5041 ? ", with one exception"
5042 : ", with some exceptions")
5047 pline("Autopickup: %s.", buf
);
5052 add_autopickup_exception(mapping
)
5053 const char *mapping
;
5056 APE_regex_error
[] = "regex error in AUTOPICKUP_EXCEPTION",
5057 APE_syntax_error
[] = "syntax error in AUTOPICKUP_EXCEPTION";
5059 struct autopickup_exception
*ape
, **apehead
;
5060 char text
[256], end
;
5062 boolean grab
= FALSE
;
5064 /* scan length limit used to be 255, but smaller size allows the
5065 quoted value to fit within BUFSZ, simplifying formatting elsewhere;
5066 this used to ignore the possibility of trailing junk but now checks
5067 for it, accepting whitespace but rejecting anything else unless it
5068 starts with '#" for a comment */
5070 if ((n
= sscanf(mapping
, "\"<%253[^\"]\" %c", text
, &end
)) == 1
5071 || (n
== 2 && end
== '#')) {
5073 } else if ((n
= sscanf(mapping
, "\">%253[^\"]\" %c", text
, &end
)) == 1
5074 || (n
= sscanf(mapping
, "\"%253[^\"]\" %c", text
, &end
)) == 1
5075 || (n
== 2 && end
== '#')) {
5078 if (!iflags
.window_inited
)
5079 raw_print(APE_syntax_error
); /* from options file */
5081 pline("%s", APE_syntax_error
); /* via 'O' command */
5085 ape
= (struct autopickup_exception
*) alloc(sizeof *ape
);
5086 ape
->regex
= regex_init();
5087 if (!regex_compile(text
, ape
->regex
)) {
5088 if (!iflags
.window_inited
)
5089 raw_print(APE_regex_error
);
5091 pline("%s", APE_regex_error
);
5092 regex_free(ape
->regex
);
5093 free((genericptr_t
) ape
);
5096 apehead
= (grab
) ? &iflags
.autopickup_exceptions
[AP_GRAB
]
5097 : &iflags
.autopickup_exceptions
[AP_LEAVE
];
5099 ape
->pattern
= dupstr(text
);
5101 ape
->next
= *apehead
;
5107 remove_autopickup_exception(whichape
)
5108 struct autopickup_exception
*whichape
;
5110 struct autopickup_exception
*ape
, *prev
= 0;
5111 int chain
= whichape
->grab
? AP_GRAB
: AP_LEAVE
;
5113 for (ape
= iflags
.autopickup_exceptions
[chain
]; ape
;) {
5114 if (ape
== whichape
) {
5115 struct autopickup_exception
*freeape
= ape
;
5121 iflags
.autopickup_exceptions
[chain
] = ape
;
5122 regex_free(freeape
->regex
);
5123 free((genericptr_t
) freeape
->pattern
);
5124 free((genericptr_t
) freeape
);
5133 count_ape_maps(leave
, grab
)
5136 struct autopickup_exception
*ape
;
5137 int pass
, totalapes
, numapes
[2] = { 0, 0 };
5139 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
5140 ape
= iflags
.autopickup_exceptions
[pass
];
5146 totalapes
= numapes
[AP_LEAVE
] + numapes
[AP_GRAB
];
5148 *leave
= numapes
[AP_LEAVE
];
5150 *grab
= numapes
[AP_GRAB
];
5155 free_autopickup_exceptions()
5157 struct autopickup_exception
*ape
;
5160 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
5161 while ((ape
= iflags
.autopickup_exceptions
[pass
]) != 0) {
5162 regex_free(ape
->regex
);
5163 free((genericptr_t
) ape
->pattern
);
5164 iflags
.autopickup_exceptions
[pass
] = ape
->next
;
5165 free((genericptr_t
) ape
);
5170 /* bundle some common usage into one easy-to-use routine */
5172 load_symset(s
, which_set
)
5176 clear_symsetentry(which_set
, TRUE
);
5178 if (symset
[which_set
].name
)
5179 free((genericptr_t
) symset
[which_set
].name
);
5180 symset
[which_set
].name
= dupstr(s
);
5182 if (read_sym_file(which_set
)) {
5183 switch_symbols(TRUE
);
5185 clear_symsetentry(which_set
, TRUE
);
5194 clear_symsetentry(PRIMARY
, TRUE
);
5195 clear_symsetentry(ROGUESET
, TRUE
);
5197 /* symset_list is cleaned up as soon as it's used, so we shouldn't
5198 have to anything about it here */
5199 /* assert( symset_list == NULL ); */
5202 /* Parse the value of a SYMBOLS line from a config file */
5205 register char *opts
;
5208 char *op
, *symname
, *strval
;
5209 struct symparse
*symp
;
5211 if ((op
= index(opts
, ',')) != 0) {
5213 if (!parsesymbols(op
)) return FALSE
;
5216 /* S_sample:string */
5218 strval
= index(opts
, ':');
5220 strval
= index(opts
, '=');
5225 /* strip leading and trailing white space from symname and strval */
5226 mungspaces(symname
);
5229 symp
= match_sym(symname
);
5233 if (symp
->range
&& symp
->range
!= SYM_CONTROL
) {
5234 val
= sym_val(strval
);
5235 update_l_symset(symp
, val
);
5244 size_t len
= strlen(buf
);
5245 const char *p
= index(buf
, ':'), *q
= index(buf
, '=');
5246 struct symparse
*sp
= loadsyms
;
5248 if (!p
|| (q
&& q
< p
))
5251 /* note: there will be at most one space before the '='
5252 because caller has condensed buf[] with mungspaces() */
5253 if (p
> buf
&& p
[-1] == ' ')
5255 len
= (int) (p
- buf
);
5258 if ((len
>= strlen(sp
->name
)) && !strncmpi(buf
, sp
->name
, len
))
5262 return (struct symparse
*) 0;
5272 if (!strval
[0] || !strval
[1]) { /* empty, or single character */
5273 /* if single char is space or tab, leave buf[0]=='\0' */
5274 if (!isspace((uchar
) strval
[0]))
5276 } else if (strval
[0] == '\'') { /* single quote */
5277 /* simple matching single quote; we know strval[1] isn't '\0' */
5278 if (strval
[2] == '\'' && !strval
[3]) {
5279 /* accepts '\' as backslash and ''' as single quote */
5282 /* if backslash, handle single or double quote or second backslash */
5283 } else if (strval
[1] == '\\' && strval
[2] && strval
[3] == '\''
5284 && index("'\"\\", strval
[2]) && !strval
[4]) {
5287 /* not simple quote or basic backslash;
5288 strip closing quote and let escapes() deal with it */
5290 char *p
, tmp
[QBUFSZ
];
5292 (void) strncpy(tmp
, strval
+ 1, sizeof tmp
- 1);
5293 tmp
[sizeof tmp
- 1] = '\0';
5294 if ((p
= rindex(tmp
, '\'')) != 0) {
5297 } /* else buf[0] stays '\0' */
5299 } else /* not lone char nor single quote */
5300 escapes(strval
, buf
);
5305 /* data for option_help() */
5306 static const char *opt_intro
[] = {
5307 "", " NetHack Options Help:", "",
5308 #define CONFIG_SLOT 3 /* fill in next value at run-time */
5310 #if !defined(MICRO) && !defined(MAC)
5311 "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
5313 "(<options> is a list of options separated by commas)",
5315 "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
5317 "or press \"O\" while playing and use the menu.", "",
5318 "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
5322 static const char *opt_epilog
[] = {
5324 "Some of the options can be set only before the game is started; those",
5325 "items will not be selectable in the 'O' command's menu.", (char *) 0
5331 char buf
[BUFSZ
], buf2
[BUFSZ
];
5335 datawin
= create_nhwindow(NHW_TEXT
);
5336 Sprintf(buf
, "Set options as OPTIONS=<options> in %s", configfile
);
5337 opt_intro
[CONFIG_SLOT
] = (const char *) buf
;
5338 for (i
= 0; opt_intro
[i
]; i
++)
5339 putstr(datawin
, 0, opt_intro
[i
]);
5341 /* Boolean options */
5342 for (i
= 0; boolopt
[i
].name
; i
++) {
5343 if (boolopt
[i
].addr
) {
5344 if (boolopt
[i
].addr
== &iflags
.sanity_check
&& !wizard
)
5346 if (boolopt
[i
].addr
== &iflags
.menu_tab_sep
&& !wizard
)
5348 next_opt(datawin
, boolopt
[i
].name
);
5351 next_opt(datawin
, "");
5353 /* Compound options */
5354 putstr(datawin
, 0, "Compound options:");
5355 for (i
= 0; compopt
[i
].name
; i
++) {
5356 Sprintf(buf2
, "`%s'", compopt
[i
].name
);
5357 Sprintf(buf
, "%-20s - %s%c", buf2
, compopt
[i
].descr
,
5358 compopt
[i
+ 1].name
? ',' : '.');
5359 putstr(datawin
, 0, buf
);
5362 for (i
= 0; opt_epilog
[i
]; i
++)
5363 putstr(datawin
, 0, opt_epilog
[i
]);
5365 display_nhwindow(datawin
, FALSE
);
5366 destroy_nhwindow(datawin
);
5371 * prints the next boolean option, on the same line if possible, on a new
5372 * line if not. End with next_opt("").
5375 next_opt(datawin
, str
)
5379 static char *buf
= 0;
5384 *(buf
= (char *) alloc(BUFSZ
)) = '\0';
5388 if (s
> &buf
[1] && s
[-2] == ',')
5389 Strcpy(s
- 2, "."); /* replace last ", " */
5390 i
= COLNO
; /* (greater than COLNO - 2) */
5392 i
= strlen(buf
) + strlen(str
) + 2;
5395 if (i
> COLNO
- 2) { /* rule of thumb */
5396 putstr(datawin
, 0, buf
);
5403 putstr(datawin
, 0, str
);
5404 free((genericptr_t
) buf
), buf
= 0;
5409 /* Returns the fid of the fruit type; if that type already exists, it
5410 * returns the fid of that one; if it does not exist, it adds a new fruit
5411 * type to the chain and returns the new one.
5412 * If replace_fruit is sent in, replace the fruit in the chain rather than
5413 * adding a new entry--for user specified fruits only.
5416 fruitadd(str
, replace_fruit
)
5418 struct fruit
*replace_fruit
;
5421 register struct fruit
*f
;
5422 int highest_fruit_id
= 0;
5423 char buf
[PL_FSIZ
], altname
[PL_FSIZ
];
5424 boolean user_specified
= (str
== pl_fruit
);
5425 /* if not user-specified, then it's a fruit name for a fruit on
5429 /* Note: every fruit has an id (kept in obj->spe) of at least 1;
5432 if (user_specified
) {
5433 boolean found
= FALSE
, numeric
= FALSE
;
5435 /* force fruit to be singular; this handling is not
5436 needed--or wanted--for fruits from bones because
5437 they already received it in their original game */
5438 nmcpy(pl_fruit
, makesingular(str
), PL_FSIZ
);
5439 /* assert( str == pl_fruit ); */
5441 /* disallow naming after other foods (since it'd be impossible
5442 * to tell the difference)
5445 for (i
= bases
[FOOD_CLASS
]; objects
[i
].oc_class
== FOOD_CLASS
; i
++) {
5446 if (!strcmp(OBJ_NAME(objects
[i
]), pl_fruit
)) {
5456 for (c
= pl_fruit
; *c
>= '0' && *c
<= '9'; c
++)
5458 if (isspace((uchar
) *c
) || *c
== 0)
5461 if (found
|| numeric
|| !strncmp(str
, "cursed ", 7)
5462 || !strncmp(str
, "uncursed ", 9) || !strncmp(str
, "blessed ", 8)
5463 || !strncmp(str
, "partly eaten ", 13)
5464 || (!strncmp(str
, "tin of ", 7)
5465 && (!strcmp(str
+ 7, "spinach")
5466 || name_to_mon(str
+ 7) >= LOW_PM
))
5467 || !strcmp(str
, "empty tin")
5468 || ((str_end_is(str
, " corpse")
5469 || str_end_is(str
, " egg"))
5470 && name_to_mon(str
) >= LOW_PM
)) {
5471 Strcpy(buf
, pl_fruit
);
5472 Strcpy(pl_fruit
, "candied ");
5473 nmcpy(pl_fruit
+ 8, buf
, PL_FSIZ
- 8);
5476 /* This flag indicates that a fruit has been made since the
5477 * last time the user set the fruit. If it hasn't, we can
5478 * safely overwrite the current fruit, preventing the user from
5479 * setting many fruits in a row and overflowing.
5480 * Possible expansion: check for specific fruit IDs, not for
5483 flags
.made_fruit
= FALSE
;
5484 if (replace_fruit
) {
5485 for (f
= ffruit
; f
; f
= f
->nextf
) {
5486 if (f
== replace_fruit
) {
5487 copynchars(f
->fname
, str
, PL_FSIZ
- 1);
5493 /* not user_supplied, so assumed to be from bones */
5494 copynchars(altname
, str
, PL_FSIZ
- 1);
5495 sanitize_name(altname
);
5496 flags
.made_fruit
= TRUE
; /* for safety. Any fruit name added from a
5497 bones level should exist anyway. */
5499 for (f
= ffruit
; f
; f
= f
->nextf
) {
5500 if (f
->fid
> highest_fruit_id
)
5501 highest_fruit_id
= f
->fid
;
5502 if (!strncmp(str
, f
->fname
, PL_FSIZ
- 1)
5503 || (*altname
&& !strcmp(altname
, f
->fname
)))
5506 /* if adding another fruit would overflow spe, use a random
5507 fruit instead... we've got a lot to choose from.
5508 current_fruit remains as is. */
5509 if (highest_fruit_id
>= 127)
5513 (void) memset((genericptr_t
)f
, 0, sizeof(struct fruit
));
5514 copynchars(f
->fname
, *altname
? altname
: str
, PL_FSIZ
- 1);
5515 f
->fid
= ++highest_fruit_id
;
5516 /* we used to go out of our way to add it at the end of the list,
5517 but the order is arbitrary so use simpler insertion at start */
5522 context
.current_fruit
= f
->fid
;
5527 * This is a somewhat generic menu for taking a list of NetHack style
5528 * class choices and presenting them via a description
5529 * rather than the traditional NetHack characters.
5530 * (Benefits users whose first exposure to NetHack is via tiles).
5533 * The title at the top of the menu.
5535 * category: 0 = monster class
5539 * FALSE = PICK_ONE, TRUE = PICK_ANY
5542 * a null terminated string containing the list of choices.
5545 * a null terminated string containing the selected characters.
5547 * Returns number selected.
5550 choose_classes_menu(prompt
, category
, way
, class_list
, class_select
)
5557 menu_item
*pick_list
= (menu_item
*) 0;
5563 int next_accelerator
, accelerator
;
5565 if (class_list
== (char *) 0 || class_select
== (char *) 0)
5568 next_accelerator
= 'a';
5570 win
= create_nhwindow(NHW_MENU
);
5572 while (*class_list
) {
5580 text
= def_monsyms
[def_char_to_monclass(*class_list
)].explain
;
5581 accelerator
= *class_list
;
5582 Sprintf(buf
, "%s", text
);
5585 text
= def_oc_syms
[def_char_to_objclass(*class_list
)].explain
;
5586 accelerator
= next_accelerator
;
5587 Sprintf(buf
, "%c %s", *class_list
, text
);
5590 impossible("choose_classes_menu: invalid category %d", category
);
5592 if (way
&& *class_select
) { /* Selections there already */
5593 if (index(class_select
, *class_list
)) {
5597 any
.a_int
= *class_list
;
5598 add_menu(win
, NO_GLYPH
, &any
, accelerator
, category
? *class_list
: 0,
5599 ATR_NONE
, buf
, selected
);
5603 if (next_accelerator
== ('z' + 1))
5604 next_accelerator
= 'A';
5605 if (next_accelerator
== ('Z' + 1))
5609 end_menu(win
, prompt
);
5610 n
= select_menu(win
, way
? PICK_ANY
: PICK_ONE
, &pick_list
);
5611 destroy_nhwindow(win
);
5613 for (i
= 0; i
< n
; ++i
)
5614 *class_select
++ = (char) pick_list
[i
].item
.a_int
;
5615 free((genericptr_t
) pick_list
);
5617 } else if (n
== -1) {
5618 class_select
= eos(class_select
);
5622 *class_select
= '\0';
5626 struct wc_Opt wc_options
[] = { { "ascii_map", WC_ASCII_MAP
},
5627 { "color", WC_COLOR
},
5628 { "eight_bit_tty", WC_EIGHT_BIT_IN
},
5629 { "hilite_pet", WC_HILITE_PET
},
5630 { "popup_dialog", WC_POPUP_DIALOG
},
5631 { "player_selection", WC_PLAYER_SELECTION
},
5632 { "preload_tiles", WC_PRELOAD_TILES
},
5633 { "tiled_map", WC_TILED_MAP
},
5634 { "tile_file", WC_TILE_FILE
},
5635 { "tile_width", WC_TILE_WIDTH
},
5636 { "tile_height", WC_TILE_HEIGHT
},
5637 { "use_inverse", WC_INVERSE
},
5638 { "align_message", WC_ALIGN_MESSAGE
},
5639 { "align_status", WC_ALIGN_STATUS
},
5640 { "font_map", WC_FONT_MAP
},
5641 { "font_menu", WC_FONT_MENU
},
5642 { "font_message", WC_FONT_MESSAGE
},
5644 {"perm_invent", WC_PERM_INVENT
},
5646 { "font_size_map", WC_FONTSIZ_MAP
},
5647 { "font_size_menu", WC_FONTSIZ_MENU
},
5648 { "font_size_message", WC_FONTSIZ_MESSAGE
},
5649 { "font_size_status", WC_FONTSIZ_STATUS
},
5650 { "font_size_text", WC_FONTSIZ_TEXT
},
5651 { "font_status", WC_FONT_STATUS
},
5652 { "font_text", WC_FONT_TEXT
},
5653 { "map_mode", WC_MAP_MODE
},
5654 { "scroll_amount", WC_SCROLL_AMOUNT
},
5655 { "scroll_margin", WC_SCROLL_MARGIN
},
5656 { "splash_screen", WC_SPLASH_SCREEN
},
5657 { "vary_msgcount", WC_VARY_MSGCOUNT
},
5658 { "windowcolors", WC_WINDOWCOLORS
},
5659 { "mouse_support", WC_MOUSE_SUPPORT
},
5660 { (char *) 0, 0L } };
5662 struct wc_Opt wc2_options
[] = { { "fullscreen", WC2_FULLSCREEN
},
5663 { "softkeyboard", WC2_SOFTKEYBOARD
},
5664 { "wraptext", WC2_WRAPTEXT
},
5665 { "use_darkgray", WC2_DARKGRAY
},
5666 #ifdef STATUS_VIA_WINDOWPORT
5667 { "hilite_status", WC2_HILITE_STATUS
},
5669 { (char *) 0, 0L } };
5672 * If a port wants to change or ensure that the SET_IN_SYS,
5673 * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
5674 * correct (for controlling its display in the option menu) call
5675 * set_option_mod_status()
5676 * with the appropriate second argument.
5679 set_option_mod_status(optnam
, status
)
5685 if (SET__IS_VALUE_VALID(status
)) {
5686 impossible("set_option_mod_status: status out of range %d.", status
);
5689 for (k
= 0; boolopt
[k
].name
; k
++) {
5690 if (!strncmpi(boolopt
[k
].name
, optnam
, strlen(optnam
))) {
5691 boolopt
[k
].optflags
= status
;
5695 for (k
= 0; compopt
[k
].name
; k
++) {
5696 if (!strncmpi(compopt
[k
].name
, optnam
, strlen(optnam
))) {
5697 compopt
[k
].optflags
= status
;
5704 * You can set several wc_options in one call to
5705 * set_wc_option_mod_status() by setting
5706 * the appropriate bits for each option that you
5707 * are setting in the optmask argument
5709 * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN,
5713 set_wc_option_mod_status(optmask
, status
)
5714 unsigned long optmask
;
5719 if (SET__IS_VALUE_VALID(status
)) {
5720 impossible("set_wc_option_mod_status: status out of range %d.",
5724 while (wc_options
[k
].wc_name
) {
5725 if (optmask
& wc_options
[k
].wc_bit
) {
5726 set_option_mod_status(wc_options
[k
].wc_name
, status
);
5733 is_wc_option(optnam
)
5738 while (wc_options
[k
].wc_name
) {
5739 if (strcmp(wc_options
[k
].wc_name
, optnam
) == 0)
5747 wc_supported(optnam
)
5752 while (wc_options
[k
].wc_name
) {
5753 if (!strcmp(wc_options
[k
].wc_name
, optnam
)
5754 && (windowprocs
.wincap
& wc_options
[k
].wc_bit
))
5762 * You can set several wc2_options in one call to
5763 * set_wc2_option_mod_status() by setting
5764 * the appropriate bits for each option that you
5765 * are setting in the optmask argument
5768 * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
5773 set_wc2_option_mod_status(optmask
, status
)
5774 unsigned long optmask
;
5779 if (SET__IS_VALUE_VALID(status
)) {
5780 impossible("set_wc2_option_mod_status: status out of range %d.",
5784 while (wc2_options
[k
].wc_name
) {
5785 if (optmask
& wc2_options
[k
].wc_bit
) {
5786 set_option_mod_status(wc2_options
[k
].wc_name
, status
);
5793 is_wc2_option(optnam
)
5798 while (wc2_options
[k
].wc_name
) {
5799 if (strcmp(wc2_options
[k
].wc_name
, optnam
) == 0)
5807 wc2_supported(optnam
)
5812 while (wc2_options
[k
].wc_name
) {
5813 if (!strcmp(wc2_options
[k
].wc_name
, optnam
)
5814 && (windowprocs
.wincap2
& wc2_options
[k
].wc_bit
))
5822 wc_set_font_name(opttype
, fontname
)
5826 char **fn
= (char **) 0;
5832 fn
= &iflags
.wc_font_map
;
5834 case MESSAGE_OPTION
:
5835 fn
= &iflags
.wc_font_message
;
5838 fn
= &iflags
.wc_font_text
;
5841 fn
= &iflags
.wc_font_menu
;
5844 fn
= &iflags
.wc_font_status
;
5851 free((genericptr_t
) *fn
);
5852 *fn
= dupstr(fontname
);
5858 wc_set_window_colors(op
)
5862 * menu white/black message green/yellow status white/blue text
5867 char *wn
, *tfg
, *tbg
, *newop
;
5868 static const char *wnames
[] = { "menu", "message", "status", "text" };
5869 static const char *shortnames
[] = { "mnu", "msg", "sts", "txt" };
5870 static char **fgp
[] = { &iflags
.wc_foregrnd_menu
,
5871 &iflags
.wc_foregrnd_message
,
5872 &iflags
.wc_foregrnd_status
,
5873 &iflags
.wc_foregrnd_text
};
5874 static char **bgp
[] = { &iflags
.wc_backgrnd_menu
,
5875 &iflags
.wc_backgrnd_message
,
5876 &iflags
.wc_backgrnd_status
,
5877 &iflags
.wc_backgrnd_text
};
5880 newop
= mungspaces(buf
);
5881 while (newop
&& *newop
) {
5882 wn
= tfg
= tbg
= (char *) 0;
5884 /* until first non-space in case there's leading spaces - before
5893 /* until first space - colorname*/
5894 while (*newop
&& *newop
!= ' ')
5902 /* until first non-space - before foreground*/
5910 /* until slash - foreground */
5911 while (*newop
&& *newop
!= '/')
5919 /* until first non-space (in case there's leading space after slash) -
5920 * before background */
5928 /* until first space - background */
5929 while (*newop
&& *newop
!= ' ')
5934 for (j
= 0; j
< 4; ++j
) {
5935 if (!strcmpi(wn
, wnames
[j
]) || !strcmpi(wn
, shortnames
[j
])) {
5936 if (tfg
&& !strstri(tfg
, " ")) {
5938 free((genericptr_t
) *fgp
[j
]);
5939 *fgp
[j
] = dupstr(tfg
);
5941 if (tbg
&& !strstri(tbg
, " ")) {
5943 free((genericptr_t
) *bgp
[j
]);
5944 *bgp
[j
] = dupstr(tbg
);
5953 /* set up for wizard mode if player or save file has requested to it;
5954 called from port-specific startup code to handle `nethack -D' or
5955 OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
5956 restoring a game which was saved in wizard mode */
5961 if (authorize_wizard_mode())
5962 Strcpy(plname
, "wizard");
5964 wizard
= FALSE
; /* not allowed or not available */
5965 /* force explore mode if we didn't make it into wizard mode */
5967 iflags
.deferred_X
= FALSE
;
5969 /* don't need to do anything special for explore mode or normal play */
5972 #endif /* OPTION_LISTS_ONLY */