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 { "status_updates", &iflags
.status_updates
, TRUE
, DISP_IN_GAME
},
212 { "tiled_map", &iflags
.wc_tiled_map
, PREFER_TILED
, DISP_IN_GAME
}, /*WC*/
213 { "time", &flags
.time
, FALSE
, SET_IN_GAME
},
215 { "timed_delay", &flags
.nap
, TRUE
, SET_IN_GAME
},
217 { "timed_delay", (boolean
*) 0, FALSE
, SET_IN_GAME
},
219 { "tombstone", &flags
.tombstone
, TRUE
, SET_IN_GAME
},
220 { "toptenwin", &iflags
.toptenwin
, FALSE
, SET_IN_GAME
},
221 { "travel", &flags
.travelcmd
, TRUE
, SET_IN_GAME
},
222 { "use_darkgray", &iflags
.wc2_darkgray
, TRUE
, SET_IN_FILE
},
224 { "use_inverse", &iflags
.wc_inverse
, TRUE
, SET_IN_GAME
}, /*WC*/
226 { "use_inverse", &iflags
.wc_inverse
, FALSE
, SET_IN_GAME
}, /*WC*/
228 { "verbose", &flags
.verbose
, TRUE
, SET_IN_GAME
},
229 #ifdef TTY_TILES_ESCCODES
230 { "vt_tiledata", &iflags
.vt_tiledata
, FALSE
, SET_IN_FILE
},
232 { "vt_tiledata", (boolean
*) 0, FALSE
, SET_IN_FILE
},
234 { "whatis_menu", &iflags
.getloc_usemenu
, FALSE
, SET_IN_GAME
},
235 { "whatis_inview", &iflags
.getloc_limitview
, FALSE
, SET_IN_GAME
},
236 { "wizweight", &iflags
.wizweight
, FALSE
, SET_IN_WIZGAME
},
237 { "wraptext", &iflags
.wc2_wraptext
, FALSE
, SET_IN_GAME
},
239 { "zerocomp", &iflags
.zerocomp
,
240 #if defined(COMPRESS) || defined(ZLIB_COMP)
247 { (char *) 0, (boolean
*) 0, FALSE
, 0 }
250 /* compound options, for option_help() and external programs like Amiga
252 static struct Comp_Opt
{
253 const char *name
, *descr
;
254 int size
; /* for frontends and such allocating space --
255 * usually allowed size of data in game, but
256 * occasionally maximum reasonable size for
257 * typing when game maintains information in
258 * a different format */
261 { "align", "your starting alignment (lawful, neutral, or chaotic)", 8,
263 { "align_message", "message window alignment", 20, DISP_IN_GAME
}, /*WC*/
264 { "align_status", "status window alignment", 20, DISP_IN_GAME
}, /*WC*/
265 { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME
},
266 #ifdef BACKWARD_COMPAT
267 { "boulder", "deprecated (use S_boulder in sym file instead)", 1,
270 { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
271 PL_PSIZ
, DISP_IN_GAME
},
272 { "disclose", "the kinds of information to disclose at end of game",
273 sizeof(flags
.end_disclose
) * 2, SET_IN_GAME
},
274 { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ
,
276 { "dungeon", "the symbols to use in drawing the dungeon map",
277 MAXDCHARS
+ 1, SET_IN_FILE
},
278 { "effects", "the symbols to use in drawing special effects",
279 MAXECHARS
+ 1, SET_IN_FILE
},
280 { "font_map", "the font to use in the map window", 40,
281 DISP_IN_GAME
}, /*WC*/
282 { "font_menu", "the font to use in menus", 40, DISP_IN_GAME
}, /*WC*/
283 { "font_message", "the font to use in the message window", 40,
284 DISP_IN_GAME
}, /*WC*/
285 { "font_size_map", "the size of the map font", 20, DISP_IN_GAME
}, /*WC*/
286 { "font_size_menu", "the size of the menu font", 20,
287 DISP_IN_GAME
}, /*WC*/
288 { "font_size_message", "the size of the message font", 20,
289 DISP_IN_GAME
}, /*WC*/
290 { "font_size_status", "the size of the status font", 20,
291 DISP_IN_GAME
}, /*WC*/
292 { "font_size_text", "the size of the text font", 20,
293 DISP_IN_GAME
}, /*WC*/
294 { "font_status", "the font to use in status window", 40,
295 DISP_IN_GAME
}, /*WC*/
296 { "font_text", "the font to use in text windows", 40,
297 DISP_IN_GAME
}, /*WC*/
298 { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ
, SET_IN_GAME
},
299 { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME
},
300 { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
301 PL_PSIZ
, DISP_IN_GAME
},
302 { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME
}, /*WC*/
303 { "menustyle", "user interface for object selection", MENUTYPELEN
,
305 { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE
},
306 { "menu_deselect_page", "deselect all items on this page of a menu", 4,
308 { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE
},
309 { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME
},
310 { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE
},
311 { "menu_invert_page", "invert all items on this page of a menu", 4,
313 { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE
},
314 { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE
},
315 { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE
},
316 { "menu_search", "search for a menu item", 4, SET_IN_FILE
},
317 { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE
},
318 { "menu_select_page", "select all items on this page of a menu", 4,
320 { "monsters", "the symbols to use for monsters", MAXMCLASSES
,
322 { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME
},
324 { "msg_window", "the type of message window required", 1, SET_IN_GAME
},
326 { "msg_window", "the type of message window required", 1, SET_IN_FILE
},
328 { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ
,
330 { "number_pad", "use the number pad for movement", 1, SET_IN_GAME
},
331 { "objects", "the symbols to use for objects", MAXOCLASSES
, SET_IN_FILE
},
332 { "packorder", "the inventory order of the items in your pack",
333 MAXOCLASSES
, SET_IN_GAME
},
337 "palette (00c/880/-fff is blue/yellow/reverse white)", 15,
340 "palette (adjust an RGB color in palette (color-R-G-B)", 15,
344 { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE
},
347 { "paranoid_confirmation", "extra prompting in certain situations", 28,
349 { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME
},
350 { "pickup_burden", "maximum burden picked up before prompt", 20,
352 { "pickup_types", "types of objects to pick up automatically",
353 MAXOCLASSES
, SET_IN_GAME
},
354 { "pile_limit", "threshold for \"there are many objects here\"", 24,
356 { "playmode", "normal play, non-scoring explore mode, or debug mode", 8,
358 { "player_selection", "choose character via dialog or prompts", 12,
360 { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ
,
362 { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ
,
364 { "runmode", "display frequency when `running' or `travelling'",
365 sizeof "teleport", SET_IN_GAME
},
366 { "scores", "the parts of the score list you wish to see", 32,
368 { "scroll_amount", "amount to scroll map when scroll_margin is reached",
369 20, DISP_IN_GAME
}, /*WC*/
370 { "scroll_margin", "scroll map when this far from the edge", 20,
371 DISP_IN_GAME
}, /*WC*/
372 { "sortloot", "sort object selection lists by description", 4,
375 { "soundcard", "type of sound card to use", 20, SET_IN_FILE
},
377 { "symset", "load a set of display symbols from the symbols file", 70,
380 "load a set of rogue display symbols from the symbols file", 70,
383 { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE
},
385 { "suppress_alert", "suppress alerts about version-specific features", 8,
387 { "tile_width", "width of tiles", 20, DISP_IN_GAME
}, /*WC*/
388 { "tile_height", "height of tiles", 20, DISP_IN_GAME
}, /*WC*/
389 { "tile_file", "name of tile file", 70, DISP_IN_GAME
}, /*WC*/
390 { "traps", "the symbols to use in drawing traps", MAXTCHARS
+ 1,
392 { "vary_msgcount", "show more old messages at a time", 20,
393 DISP_IN_GAME
}, /*WC*/
395 { "video", "method of video updating", 20, SET_IN_FILE
},
398 { "videocolors", "color mappings for internal screen routines", 40,
400 { "videoshades", "gray shades to map to black/gray/white", 32,
403 { "whatis_coord", "show coordinates when auto-describing cursor position",
405 { "windowcolors", "the foreground/background colors of windows", /*WC*/
407 { "windowtype", "windowing system to use", WINTYPELEN
, DISP_IN_GAME
},
409 { "windowchain", "window processor to use", WINTYPELEN
, SET_IN_SYS
},
411 #ifdef BACKWARD_COMPAT
412 { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE
},
413 { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE
},
414 #ifdef MAC_GRAPHICS_ENV
415 { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE
},
418 { (char *) 0, (char *) 0, 0, 0 }
421 #ifdef OPTION_LISTS_ONLY
424 #else /* use rest of file */
426 extern char configfile
[]; /* for messages */
428 extern struct symparse loadsyms
[];
429 static boolean need_redraw
; /* for doset() */
431 #if defined(TOS) && defined(TEXTCOLOR)
432 extern boolean colors_changed
; /* in tos.c */
436 extern char *shade
[3]; /* in sys/msdos/video.c */
437 extern char ttycolors
[CLR_MAX
]; /* in sys/msdos/video.c */
440 static char def_inv_order
[MAXOCLASSES
] = {
441 COIN_CLASS
, AMULET_CLASS
, WEAPON_CLASS
, ARMOR_CLASS
, FOOD_CLASS
,
442 SCROLL_CLASS
, SPBOOK_CLASS
, POTION_CLASS
, RING_CLASS
, WAND_CLASS
,
443 TOOL_CLASS
, GEM_CLASS
, ROCK_CLASS
, BALL_CLASS
, CHAIN_CLASS
, 0,
447 * Default menu manipulation command accelerators. These may _not_ be:
449 * + a number - reserved for counts
450 * + an upper or lower case US ASCII letter - used for accelerators
451 * + ESC - reserved for escaping the menu
452 * + NULL, CR or LF - reserved for commiting the selection(s). NULL
453 * is kind of odd, but the tty's xwaitforspace() will return it if
454 * someone hits a <ret>.
455 * + a default object class symbol - used for object class accelerators
457 * Standard letters (for now) are:
470 * The command name list is duplicated in the compopt array.
478 static const menu_cmd_t default_menu_cmd_info
[] = {
479 { "menu_first_page", MENU_FIRST_PAGE
, "Go to first page" },
480 { "menu_last_page", MENU_LAST_PAGE
, "Go to last page" },
481 { "menu_next_page", MENU_NEXT_PAGE
, "Go to next page" },
482 { "menu_previous_page", MENU_PREVIOUS_PAGE
, "Go to previous page" },
483 { "menu_select_all", MENU_SELECT_ALL
, "Select all items" },
484 { "menu_deselect_all", MENU_UNSELECT_ALL
, "Unselect all items" },
485 { "menu_invert_all", MENU_INVERT_ALL
, "Insert selection" },
486 { "menu_select_page", MENU_SELECT_PAGE
, "Select items in current page" },
487 { "menu_deselect_page", MENU_UNSELECT_PAGE
, "Unselect items in current page" },
488 { "menu_invert_page", MENU_INVERT_PAGE
, "Invert current page selection" },
489 { "menu_search", MENU_SEARCH
, "Search and toggle matching items" },
493 * Allow the user to map incoming characters to various menu commands.
494 * The accelerator list must be a valid C string.
496 #define MAX_MENU_MAPPED_CMDS 32 /* some number */
497 char mapped_menu_cmds
[MAX_MENU_MAPPED_CMDS
+ 1]; /* exported */
498 static char mapped_menu_op
[MAX_MENU_MAPPED_CMDS
+ 1];
499 static short n_menu_mapped
= 0;
501 static boolean initial
, from_file
;
503 STATIC_DCL
void FDECL(nmcpy
, (char *, const char *, int));
504 STATIC_DCL
void FDECL(escapes
, (const char *, char *));
505 STATIC_DCL
void FDECL(rejectoption
, (const char *));
506 STATIC_DCL
void FDECL(badoptmsg
, (const char *, const char *));
507 STATIC_DCL
void FDECL(badoption
, (const char *));
508 STATIC_DCL
char *FDECL(string_for_opt
, (char *, BOOLEAN_P
));
509 STATIC_DCL
char *FDECL(string_for_env_opt
, (const char *, char *, BOOLEAN_P
));
510 STATIC_DCL
void FDECL(bad_negation
, (const char *, BOOLEAN_P
));
511 STATIC_DCL
int FDECL(change_inv_order
, (char *));
512 STATIC_DCL
void FDECL(warning_opts
, (char *, const char *));
513 STATIC_DCL
int FDECL(feature_alert_opts
, (char *, const char *));
514 STATIC_DCL boolean
FDECL(duplicate_opt_detection
, (const char *, int));
515 STATIC_DCL
void FDECL(complain_about_duplicate
, (const char *, int));
517 STATIC_DCL
const char *FDECL(attr2attrname
, (int));
518 STATIC_DCL
int NDECL(query_color
);
519 STATIC_DCL
int FDECL(query_attr
, (const char *));
520 STATIC_DCL
const char * FDECL(msgtype2name
, (int));
521 STATIC_DCL
int NDECL(query_msgtype
);
522 STATIC_DCL boolean
FDECL(msgtype_add
, (int, char *));
523 STATIC_DCL
void FDECL(free_one_msgtype
, (int));
524 STATIC_DCL
int NDECL(msgtype_count
);
525 STATIC_DCL boolean
FDECL(add_menu_coloring_parsed
, (char *, int, int));
526 STATIC_DCL
void FDECL(free_one_menu_coloring
, (int));
527 STATIC_DCL
int NDECL(count_menucolors
);
528 STATIC_DCL boolean
FDECL(parse_role_opts
, (BOOLEAN_P
, const char *,
531 STATIC_DCL
void FDECL(oc_to_str
, (char *, char *));
532 STATIC_DCL
void FDECL(doset_add_menu
, (winid
, const char *, int));
533 STATIC_DCL
void FDECL(opts_add_others
, (winid
, const char *, int,
535 STATIC_DCL
int FDECL(handle_add_list_remove
, (const char *, int));
536 STATIC_DCL boolean
FDECL(special_handling
, (const char *,
537 BOOLEAN_P
, BOOLEAN_P
));
538 STATIC_DCL
const char *FDECL(get_compopt_value
, (const char *, char *));
539 STATIC_DCL
void FDECL(remove_autopickup_exception
,
540 (struct autopickup_exception
*));
541 STATIC_DCL
int FDECL(count_ape_maps
, (int *, int *));
543 STATIC_DCL boolean
FDECL(is_wc_option
, (const char *));
544 STATIC_DCL boolean
FDECL(wc_supported
, (const char *));
545 STATIC_DCL boolean
FDECL(is_wc2_option
, (const char *));
546 STATIC_DCL boolean
FDECL(wc2_supported
, (const char *));
547 STATIC_DCL
void FDECL(wc_set_font_name
, (int, char *));
548 STATIC_DCL
int FDECL(wc_set_window_colors
, (char *));
555 for (x
= 0; x
< COLNO
; x
++)
556 for (y
= 0; y
< ROWNO
; y
++) {
557 struct rm
*lev
= &levl
[x
][y
];
559 if (!flags
.dark_room
|| !iflags
.use_color
560 || Is_rogue_level(&u
.uz
)) {
561 if (lev
->glyph
== cmap_to_glyph(S_darkroom
))
562 lev
->glyph
= lev
->waslit
? cmap_to_glyph(S_room
)
563 : cmap_to_glyph(S_stone
);
565 if (lev
->glyph
== cmap_to_glyph(S_room
) && lev
->seenv
566 && lev
->waslit
&& !cansee(x
, y
))
567 lev
->glyph
= cmap_to_glyph(S_darkroom
);
568 else if (lev
->glyph
== cmap_to_glyph(S_stone
)
569 && lev
->typ
== ROOM
&& lev
->seenv
&& !cansee(x
, y
))
570 lev
->glyph
= cmap_to_glyph(S_darkroom
);
573 if (flags
.dark_room
&& iflags
.use_color
)
574 showsyms
[S_darkroom
] = showsyms
[S_room
];
576 showsyms
[S_darkroom
] = showsyms
[S_stone
];
579 /* check whether a user-supplied option string is a proper leading
580 substring of a particular option name; option string might have
581 a colon or equals sign and arbitrary value appended to it */
583 match_optname(user_string
, opt_name
, min_length
, val_allowed
)
584 const char *user_string
, *opt_name
;
588 int len
= (int) strlen(user_string
);
591 const char *p
= index(user_string
, ':'),
592 *q
= index(user_string
, '=');
594 if (!p
|| (q
&& q
< p
))
597 /* 'user_string' hasn't necessarily been through mungspaces()
598 so might have tabs or consecutive spaces */
599 while (p
> user_string
&& isspace((uchar
) *(p
- 1)))
601 len
= (int) (p
- user_string
);
605 return (boolean
) (len
>= min_length
606 && !strncmpi(opt_name
, user_string
, len
));
609 /* most environment variables will eventually be printed in an error
610 * message if they don't work, and most error message paths go through
611 * BUFSZ buffers, which could be overflowed by a maliciously long
612 * environment variable. If a variable can legitimately be long, or
613 * if it's put in a smaller buffer, the responsible code will have to
614 * bounds-check itself.
620 char *getev
= getenv(ev
);
622 if (getev
&& strlen(getev
) <= (BUFSZ
/ 2))
628 /* process options, possibly including SYSCF */
634 /* someday there may be other SYSCF alternatives besides text file */
636 /* If SYSCF_FILE is specified, it _must_ exist... */
638 /* ... and _must_ parse correctly. */
639 if (!read_config_file(SYSCF_FILE
, SET_IN_SYS
)) {
640 raw_printf("Error(s) found in SYSCF_FILE, quitting.");
641 terminate(EXIT_FAILURE
);
644 * TODO [maybe]: parse the sysopt entries which are space-separated
645 * lists of usernames into arrays with one name per element.
649 initoptions_finish();
655 #if defined(UNIX) || defined(VMS)
660 /* set up the command parsing */
661 reset_commands(TRUE
); /* init */
663 /* initialize the random number generator */
666 /* for detection of configfile options specified multiple times */
667 iflags
.opt_booldup
= iflags
.opt_compdup
= (int *) 0;
669 for (i
= 0; boolopt
[i
].name
; i
++) {
671 *(boolopt
[i
].addr
) = boolopt
[i
].initvalue
;
673 #if defined(COMPRESS) || defined(ZLIB_COMP)
674 set_savepref("externalcomp");
675 set_restpref("externalcomp");
677 set_savepref("!rlecomp");
678 set_restpref("!rlecomp");
682 set_savepref("zerocomp");
683 set_restpref("zerocomp");
686 set_savepref("rlecomp");
687 set_restpref("rlecomp");
691 Strcpy(sysflags
.sysflagsid
, "sysflags");
692 sysflags
.sysflagsid
[9] = (char) sizeof(struct sysflag
);
694 flags
.end_own
= FALSE
;
696 flags
.end_around
= 2;
697 flags
.paranoia_bits
= PARANOID_PRAY
; /* old prayconfirm=TRUE */
698 flags
.pile_limit
= PILE_LIMIT_DFLT
; /* 5 */
699 flags
.runmode
= RUN_LEAP
;
700 iflags
.msg_history
= 20;
702 iflags
.prevmsg_window
= 's';
704 iflags
.menu_headings
= ATR_INVERSE
;
705 iflags
.getpos_coords
= GPCOORDS_NONE
;
707 /* hero's role, race, &c haven't been chosen yet */
708 flags
.initrole
= flags
.initrace
= flags
.initgend
= flags
.initalign
=
711 /* Set the default monster and object class symbols. */
713 for (i
= 0; i
< WARNCOUNT
; i
++)
714 warnsyms
[i
] = def_warnsyms
[i
].sym
;
715 iflags
.bouldersym
= 0;
717 iflags
.travelcc
.x
= iflags
.travelcc
.y
= -1;
719 /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
720 (void) memcpy((genericptr_t
) flags
.inv_order
,
721 (genericptr_t
) def_inv_order
, sizeof flags
.inv_order
);
722 flags
.pickup_types
[0] = '\0';
723 flags
.pickup_burden
= MOD_ENCUMBER
;
724 flags
.sortloot
= 'l'; /* sort only loot by default */
726 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++)
727 flags
.end_disclose
[i
] = DISCLOSE_PROMPT_DEFAULT_NO
;
728 switch_symbols(FALSE
); /* set default characters */
729 #if defined(UNIX) && defined(TTY_GRAPHICS)
731 * Set defaults for some options depending on what we can
732 * detect about the environment's capabilities.
733 * This has to be done after the global initialization above
734 * and before reading user-specific initialization via
735 * config file/environment variable below.
737 /* this detects the IBM-compatible console on most 386 boxes */
738 if ((opts
= nh_getenv("TERM")) && !strncmp(opts
, "AT", 2)) {
739 if (!symset
[PRIMARY
].name
)
740 load_symset("IBMGraphics", PRIMARY
);
741 if (!symset
[ROGUESET
].name
)
742 load_symset("RogueIBM", ROGUESET
);
743 switch_symbols(TRUE
);
745 iflags
.use_color
= TRUE
;
748 #endif /* UNIX && TTY_GRAPHICS */
749 #if defined(UNIX) || defined(VMS)
751 /* detect whether a "vt" terminal can handle alternate charsets */
752 if ((opts
= nh_getenv("TERM"))
753 /* [could also check "xterm" which emulates vtXXX by default] */
754 && !strncmpi(opts
, "vt", 2)
755 && AS
&& AE
&& index(AS
, '\016') && index(AE
, '\017')) {
756 if (!symset
[PRIMARY
].name
)
757 load_symset("DECGraphics", PRIMARY
);
758 switch_symbols(TRUE
);
761 #endif /* UNIX || VMS */
763 #ifdef MAC_GRAPHICS_ENV
764 if (!symset
[PRIMARY
].name
)
765 load_symset("MACGraphics", PRIMARY
);
766 switch_symbols(TRUE
);
767 #endif /* MAC_GRAPHICS_ENV */
768 flags
.menu_style
= MENU_FULL
;
770 /* since this is done before init_objects(), do partial init here */
771 objects
[SLIME_MOLD
].oc_name_idx
= SLIME_MOLD
;
772 nmcpy(pl_fruit
, OBJ_NAME(objects
[SLIME_MOLD
]), PL_FSIZ
);
779 char *opts
= getenv("NETHACKOPTIONS");
782 opts
= getenv("HACKOPTIONS");
784 if (*opts
== '/' || *opts
== '\\' || *opts
== '@') {
786 opts
++; /* @filename */
787 /* looks like a filename */
788 if (strlen(opts
) < BUFSZ
/ 2)
789 read_config_file(opts
, SET_IN_FILE
);
791 read_config_file((char *) 0, SET_IN_FILE
);
792 /* let the total length of options be long;
793 * parseoptions() will check each individually
795 parseoptions(opts
, TRUE
, FALSE
);
799 read_config_file((char *) 0, SET_IN_FILE
);
801 (void) fruitadd(pl_fruit
, (struct fruit
*) 0);
803 * Remove "slime mold" from list of object names. This will
804 * prevent it from being wished unless it's actually present
805 * as a named (or default) fruit. Wishing for "fruit" will
806 * result in the player's preferred fruit [better than "\033"].
808 obj_descr
[SLIME_MOLD
].oc_name
= "fruit";
810 if (iflags
.bouldersym
)
817 nmcpy(dest
, src
, maxlen
)
824 for (count
= 1; count
< maxlen
; count
++) {
825 if (*src
== ',' || *src
== '\0')
826 break; /*exit on \0 terminator*/
833 * escapes(): escape expansion for showsyms. C-style escapes understood
834 * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal).
835 * The ^-prefix for control characters is also understood, and \[mM]
836 * has the effect of 'meta'-ing the value which follows (so that the
837 * alternate character set will be enabled).
843 * For 3.4.3 and earlier, input ending with "\M", backslash, or caret
844 * prior to terminating '\0' would pull that '\0' into the output and then
845 * keep processing past it, potentially overflowing the output buffer.
846 * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
847 * output and stop there; trailing \M will fall through to \<other> and
848 * yield 'M', then stop. Any \X or \O followed by something other than
849 * an appropriate digit will also fall through to \<other> and yield 'X'
850 * or 'O', plus stop if the non-digit is end-of-string.
857 static NEARDATA
const char oct
[] = "01234567", dec
[] = "0123456789",
858 hex
[] = "00112233445566778899aAbBcCdDeEfF";
860 int cval
, meta
, dcount
;
863 /* \M has to be followed by something to do meta conversion,
864 otherwise it will just be \M which ultimately yields 'M' */
865 meta
= (*cp
== '\\' && (cp
[1] == 'm' || cp
[1] == 'M') && cp
[2]);
869 cval
= dcount
= 0; /* for decimal, octal, hexadecimal cases */
870 if ((*cp
!= '\\' && *cp
!= '^') || !cp
[1]) {
871 /* simple character, or nothing left for \ or ^ to escape */
873 } else if (*cp
== '^') { /* expand control-character syntax */
874 cval
= (*++cp
& 0x1f);
877 /* remaining cases are all for backslash; we know cp[1] is not \0 */
878 } else if (index(dec
, cp
[1])) {
879 ++cp
; /* move past backslash to first digit */
881 cval
= (cval
* 10) + (*cp
- '0');
882 } while (*++cp
&& index(dec
, *cp
) && ++dcount
< 3);
883 } else if ((cp
[1] == 'o' || cp
[1] == 'O') && cp
[2]
884 && index(oct
, cp
[2])) {
885 cp
+= 2; /* move past backslash and 'O' */
887 cval
= (cval
* 8) + (*cp
- '0');
888 } while (*++cp
&& index(oct
, *cp
) && ++dcount
< 3);
889 } else if ((cp
[1] == 'x' || cp
[1] == 'X') && cp
[2]
890 && (dp
= index(hex
, cp
[2])) != 0) {
891 cp
+= 2; /* move past backslash and 'X' */
893 cval
= (cval
* 16) + ((int) (dp
- hex
) / 2);
894 } while (*++cp
&& (dp
= index(hex
, *cp
)) != 0 && ++dcount
< 2);
895 } else { /* C-style character escapes */
926 rejectoption(optname
)
930 pline("\"%s\" settable only from %s.", optname
, configfile
);
932 pline("%s can be set only from NETHACKOPTIONS or %s.", optname
,
938 badoptmsg(opts
, reason
)
940 const char *reason
; /* "Bad syntax" or "Missing value" */
942 const char *linesplit
= "";
945 if (!strncmp(opts
, "h", 1) || !strncmp(opts
, "?", 1))
948 pline("%s: %s. Enter \"?g\" for help.", reason
, opts
);
960 raw_printf("%s in OPTIONS in %s: %s%s.\n",
961 reason
, configfile
, linesplit
, opts
);
963 raw_printf("%s in NETHACKOPTIONS: %s%s.\n",
964 reason
, linesplit
, opts
);
972 badoptmsg(opts
, "Bad syntax");
976 string_for_opt(opts
, val_optional
)
978 boolean val_optional
;
980 char *colon
, *equals
;
982 colon
= index(opts
, ':');
983 equals
= index(opts
, '=');
984 if (!colon
|| (equals
&& equals
< colon
))
987 if (!colon
|| !*++colon
) {
989 badoptmsg(opts
, "Missing value");
996 string_for_env_opt(optname
, opts
, val_optional
)
999 boolean val_optional
;
1002 rejectoption(optname
);
1005 return string_for_opt(opts
, val_optional
);
1009 bad_negation(optname
, with_parameter
)
1010 const char *optname
;
1011 boolean with_parameter
;
1013 pline_The("%s option may not %sbe negated.", optname
,
1014 with_parameter
? "both have a value and " : "");
1018 * Change the inventory order, using the given string as the new order.
1019 * Missing characters in the new order are filled in at the end from
1020 * the current inv_order, except for gold, which is forced to be first
1021 * if not explicitly present.
1023 * This routine returns 1 unless there is a duplicate or bad char in
1027 change_inv_order(op
)
1031 char *sp
, buf
[QBUFSZ
];
1034 if (!index(op
, GOLD_SYM
))
1035 buf
[num
++] = COIN_CLASS
;
1037 for (sp
= op
; *sp
; sp
++) {
1038 oc_sym
= def_char_to_objclass(*sp
);
1039 /* reject bad or duplicate entries */
1040 if (oc_sym
== MAXOCLASSES
/* not an object class char */
1041 /* VENOM_CLASS, RANDOM_CLASS, and ILLOBJ_CLASS are excluded
1042 because they aren't in def_inv_order[] so don't make it
1043 into flags.inv_order, hence always fail this index() test */
1044 || !index(flags
.inv_order
, oc_sym
) || index(sp
+ 1, *sp
))
1046 /* retain good ones */
1047 buf
[num
++] = (char) oc_sym
;
1051 /* fill in any omitted classes, using previous ordering */
1052 for (sp
= flags
.inv_order
; *sp
; sp
++)
1053 if (!index(buf
, *sp
))
1054 (void) strkitten(&buf
[num
++], *sp
);
1055 buf
[MAXOCLASSES
- 1] = '\0';
1057 Strcpy(flags
.inv_order
, buf
);
1062 warning_opts(opts
, optype
)
1063 register char *opts
;
1066 uchar translate
[WARNCOUNT
];
1069 if (!(opts
= string_for_env_opt(optype
, opts
, FALSE
)))
1071 escapes(opts
, opts
);
1073 length
= (int) strlen(opts
);
1074 /* match the form obtained from PC configuration files */
1075 for (i
= 0; i
< WARNCOUNT
; i
++)
1076 translate
[i
] = (i
>= length
) ? 0
1077 : opts
[i
] ? (uchar
) opts
[i
]
1078 : def_warnsyms
[i
].sym
;
1079 assign_warnings(translate
);
1083 assign_warnings(graph_chars
)
1084 register uchar
*graph_chars
;
1088 for (i
= 0; i
< WARNCOUNT
; i
++)
1090 warnsyms
[i
] = graph_chars
[i
];
1094 feature_alert_opts(op
, optn
)
1099 boolean rejectver
= FALSE
;
1100 unsigned long fnv
= get_feature_notice_ver(op
); /* version.c */
1104 if (fnv
> get_current_feature_ver())
1107 flags
.suppress_alert
= fnv
;
1110 You_cant("disable new feature alerts for future versions.");
1113 "\n%s=%s Invalid reference to a future version ignored",
1120 Sprintf(buf
, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ
,
1121 FEATURE_NOTICE_VER_MIN
, FEATURE_NOTICE_VER_PATCH
);
1123 "Feature change alerts disabled for NetHack %s features and prior.",
1130 set_duplicate_opt_detection(on_or_off
)
1135 if (on_or_off
!= 0) {
1137 if (iflags
.opt_booldup
)
1138 impossible("iflags.opt_booldup already on (memory leak)");
1139 iflags
.opt_booldup
= (int *) alloc(SIZE(boolopt
) * sizeof(int));
1140 optptr
= iflags
.opt_booldup
;
1141 for (k
= 0; k
< SIZE(boolopt
); ++k
)
1144 if (iflags
.opt_compdup
)
1145 impossible("iflags.opt_compdup already on (memory leak)");
1146 iflags
.opt_compdup
= (int *) alloc(SIZE(compopt
) * sizeof(int));
1147 optptr
= iflags
.opt_compdup
;
1148 for (k
= 0; k
< SIZE(compopt
); ++k
)
1152 if (iflags
.opt_booldup
)
1153 free((genericptr_t
) iflags
.opt_booldup
);
1154 iflags
.opt_booldup
= (int *) 0;
1155 if (iflags
.opt_compdup
)
1156 free((genericptr_t
) iflags
.opt_compdup
);
1157 iflags
.opt_compdup
= (int *) 0;
1162 duplicate_opt_detection(opts
, iscompound
)
1164 int iscompound
; /* 0 == boolean option, 1 == compound */
1168 if (!iscompound
&& iflags
.opt_booldup
&& initial
&& from_file
) {
1169 for (i
= 0; boolopt
[i
].name
; i
++) {
1170 if (match_optname(opts
, boolopt
[i
].name
, 3, FALSE
)) {
1171 optptr
= iflags
.opt_booldup
+ i
;
1179 } else if (iscompound
&& iflags
.opt_compdup
&& initial
&& from_file
) {
1180 for (i
= 0; compopt
[i
].name
; i
++) {
1181 if (match_optname(opts
, compopt
[i
].name
, strlen(compopt
[i
].name
),
1183 optptr
= iflags
.opt_compdup
+ i
;
1196 complain_about_duplicate(opts
, iscompound
)
1198 int iscompound
; /* 0 == boolean option, 1 == compound */
1201 /* the Mac has trouble dealing with the output of messages while
1202 * processing the config file. That should get fixed one day.
1203 * For now just return.
1206 raw_printf("\nWarning - %s option specified multiple times: %s.\n",
1207 iscompound
? "compound" : "boolean", opts
);
1213 /* paranoia[] - used by parseoptions() and special_handling() */
1214 STATIC_VAR
const struct paranoia_opts
{
1215 int flagmask
; /* which paranoid option */
1216 const char *argname
; /* primary name */
1217 int argMinLen
; /* minimum number of letters to match */
1218 const char *synonym
; /* alternate name (optional) */
1220 const char *explain
; /* for interactive menu */
1222 /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack"
1223 takes precedence and "all" isn't present in the interactive menu,
1224 and "d"ie vs "d"eath, synonyms for each other so doesn't matter;
1225 (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia"
1226 is just a synonym for "Confirm") */
1227 { PARANOID_CONFIRM
, "Confirm", 1, "Paranoia", 2,
1228 "for \"yes\" confirmations, require \"no\" to reject" },
1229 { PARANOID_QUIT
, "quit", 1, "explore", 1,
1230 "yes vs y to quit or to enter explore mode" },
1231 { PARANOID_DIE
, "die", 1, "death", 2,
1232 "yes vs y to die (explore mode or debug mode)" },
1233 { PARANOID_BONES
, "bones", 1, 0, 0,
1234 "yes vs y to save bones data when dying in debug mode" },
1235 { PARANOID_HIT
, "attack", 1, "hit", 1,
1236 "yes vs y to attack a peaceful monster" },
1237 { PARANOID_PRAY
, "pray", 1, 0, 0,
1238 "y to pray (supersedes old \"prayconfirm\" option)" },
1239 { PARANOID_REMOVE
, "Remove", 1, "Takeoff", 1,
1240 "always pick from inventory for Remove and Takeoff" },
1241 { PARANOID_BREAKWAND
, "wand", 1, "breakwand", 2,
1242 "yes vs y to break a wand" },
1243 /* for config file parsing; interactive menu skips these */
1244 { 0, "none", 4, 0, 0, 0 }, /* require full word match */
1245 { ~0, "all", 3, 0, 0, 0 }, /* ditto */
1248 extern struct menucoloring
*menu_colorings
;
1250 static const struct {
1254 { "black", CLR_BLACK
},
1256 { "green", CLR_GREEN
},
1257 { "brown", CLR_BROWN
},
1258 { "blue", CLR_BLUE
},
1259 { "magenta", CLR_MAGENTA
},
1260 { "cyan", CLR_CYAN
},
1261 { "gray", CLR_GRAY
},
1262 { "orange", CLR_ORANGE
},
1263 { "light green", CLR_BRIGHT_GREEN
},
1264 { "yellow", CLR_YELLOW
},
1265 { "light blue", CLR_BRIGHT_BLUE
},
1266 { "light magenta", CLR_BRIGHT_MAGENTA
},
1267 { "light cyan", CLR_BRIGHT_CYAN
},
1268 { "white", CLR_WHITE
},
1269 { NULL
, CLR_BLACK
}, /* everything after this is an alias */
1270 { "transparent", NO_COLOR
},
1271 { "nocolor", NO_COLOR
},
1272 { "purple", CLR_MAGENTA
},
1273 { "light purple", CLR_BRIGHT_MAGENTA
},
1274 { "bright purple", CLR_BRIGHT_MAGENTA
},
1275 { "grey", CLR_GRAY
},
1276 { "bright red", CLR_ORANGE
},
1277 { "bright green", CLR_BRIGHT_GREEN
},
1278 { "bright blue", CLR_BRIGHT_BLUE
},
1279 { "bright magenta", CLR_BRIGHT_MAGENTA
},
1280 { "bright cyan", CLR_BRIGHT_CYAN
}
1283 static const struct {
1287 { "none", ATR_NONE
},
1288 { "bold", ATR_BOLD
},
1290 { "underline", ATR_ULINE
},
1291 { "blink", ATR_BLINK
},
1292 { "inverse", ATR_INVERSE
}
1301 for (i
= 0; i
< SIZE(colornames
); i
++)
1302 if (colornames
[i
].name
&& colornames
[i
].color
== clr
)
1303 return colornames
[i
].name
;
1311 int i
, c
= NO_COLOR
;
1313 /* allow "lightblue", "light blue", and "light-blue" to match "light blue"
1314 (also junk like "_l i-gh_t---b l u e" but we won't worry about that);
1315 also copes with trailing space; mungspaces removed any leading space */
1316 for (i
= 0; i
< SIZE(colornames
); i
++)
1317 if (colornames
[i
].name
1318 && fuzzymatch(str
, colornames
[i
].name
, " -_", TRUE
)) {
1319 c
= colornames
[i
].color
;
1322 if (i
== SIZE(colornames
) && (*str
>= '0' && *str
<= '9'))
1327 STATIC_OVL
const char *
1333 for (i
= 0; i
< SIZE(attrnames
); i
++)
1334 if (attrnames
[i
].attr
== attr
)
1335 return attrnames
[i
].name
;
1345 menu_item
*picks
= (menu_item
*) 0;
1347 tmpwin
= create_nhwindow(NHW_MENU
);
1350 for (i
= 0; i
< SIZE(colornames
); i
++) {
1351 if (!colornames
[i
].name
)
1354 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, colornames
[i
].name
,
1357 end_menu(tmpwin
, "Pick a color");
1358 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1359 destroy_nhwindow(tmpwin
);
1361 i
= colornames
[picks
->item
.a_int
- 1].color
;
1362 free((genericptr_t
) picks
);
1375 menu_item
*picks
= (menu_item
*) 0;
1377 tmpwin
= create_nhwindow(NHW_MENU
);
1380 for (i
= 0; i
< SIZE(attrnames
); i
++) {
1382 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, attrnames
[i
].attr
,
1383 attrnames
[i
].name
, MENU_UNSELECTED
);
1385 end_menu(tmpwin
, prompt
? prompt
: "Pick an attribute");
1386 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1387 destroy_nhwindow(tmpwin
);
1389 i
= attrnames
[picks
->item
.a_int
- 1].attr
;
1390 free((genericptr_t
) picks
);
1396 static const struct {
1400 } msgtype_names
[] = {
1401 { "show", MSGTYP_NORMAL
, "Show message normally" },
1402 { "hide", MSGTYP_NOSHOW
, "Hide message" },
1403 { "noshow", MSGTYP_NOSHOW
, NULL
},
1404 { "stop", MSGTYP_STOP
, "Prompt for more after the message" },
1405 { "more", MSGTYP_STOP
, NULL
},
1406 { "norep", MSGTYP_NOREP
, "Do not repeat the message" }
1409 STATIC_OVL
const char *
1415 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1416 if (msgtype_names
[i
].descr
&& msgtype_names
[i
].msgtyp
== typ
)
1417 return msgtype_names
[i
].name
;
1427 menu_item
*picks
= (menu_item
*) 0;
1429 tmpwin
= create_nhwindow(NHW_MENU
);
1432 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1433 if (msgtype_names
[i
].descr
) {
1434 any
.a_int
= msgtype_names
[i
].msgtyp
+ 1;
1435 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1436 msgtype_names
[i
].descr
, MENU_UNSELECTED
);
1438 end_menu(tmpwin
, "How to show the message");
1439 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
1440 destroy_nhwindow(tmpwin
);
1442 i
= picks
->item
.a_int
- 1;
1443 free((genericptr_t
) picks
);
1450 msgtype_add(typ
, pattern
)
1454 struct plinemsg_type
*tmp
1455 = (struct plinemsg_type
*) alloc(sizeof (struct plinemsg_type
));
1460 tmp
->regex
= regex_init();
1461 if (!regex_compile(pattern
, tmp
->regex
)) {
1462 static const char *re_error
= "MSGTYPE regex error";
1464 if (!iflags
.window_inited
)
1465 raw_printf("\n%s: %s\n", re_error
, regex_error_desc(tmp
->regex
));
1467 pline("%s: %s", re_error
, regex_error_desc(tmp
->regex
));
1469 regex_free(tmp
->regex
);
1470 free((genericptr_t
) tmp
);
1473 tmp
->pattern
= dupstr(pattern
);
1474 tmp
->next
= plinemsg_types
;
1475 plinemsg_types
= tmp
;
1482 struct plinemsg_type
*tmp
, *tmp2
= 0;
1484 for (tmp
= plinemsg_types
; tmp
; tmp
= tmp2
) {
1486 free((genericptr_t
) tmp
->pattern
);
1487 regex_free(tmp
->regex
);
1488 free((genericptr_t
) tmp
);
1490 plinemsg_types
= (struct plinemsg_type
*) 0;
1494 free_one_msgtype(idx
)
1497 struct plinemsg_type
*tmp
= plinemsg_types
;
1498 struct plinemsg_type
*prev
= NULL
;
1502 struct plinemsg_type
*next
= tmp
->next
;
1504 regex_free(tmp
->regex
);
1505 free((genericptr_t
) tmp
->pattern
);
1506 free((genericptr_t
) tmp
);
1510 plinemsg_types
= next
;
1520 msgtype_type(msg
, norepeat
)
1522 boolean norepeat
; /* called from Norep(via pline) */
1524 struct plinemsg_type
*tmp
= plinemsg_types
;
1527 /* we don't exclude entries with negative msgtype values
1528 because then the msg might end up matching a later pattern */
1529 if (regex_match(msg
, tmp
->regex
))
1530 return tmp
->msgtype
;
1533 return norepeat
? MSGTYP_NOREP
: MSGTYP_NORMAL
;
1536 /* negate one or more types of messages so that their type handling will
1537 be disabled or re-enabled; MSGTYPE_NORMAL (value 0) is not affected */
1539 hide_unhide_msgtypes(hide
, hide_mask
)
1543 struct plinemsg_type
*tmp
;
1546 /* negative msgtype value won't be recognized by pline, so does nothing */
1547 for (tmp
= plinemsg_types
; tmp
; tmp
= tmp
->next
) {
1550 mt
= -mt
; /* unhide: negate negative, yielding positive */
1551 if (mt
> 0 && ((1 << mt
) & hide_mask
))
1552 tmp
->msgtype
= -tmp
->msgtype
;
1560 struct plinemsg_type
*tmp
= plinemsg_types
;
1570 msgtype_parse_add(str
)
1576 if (sscanf(str
, "%10s \"%255[^\"]\"", msgtype
, pattern
) == 2) {
1580 for (i
= 0; i
< SIZE(msgtype_names
); i
++)
1581 if (!strncmpi(msgtype_names
[i
].name
, msgtype
, strlen(msgtype
))) {
1582 typ
= msgtype_names
[i
].msgtyp
;
1586 return msgtype_add(typ
, pattern
);
1592 add_menu_coloring_parsed(str
, c
, a
)
1596 static const char re_error
[] = "Menucolor regex error";
1597 struct menucoloring
*tmp
;
1601 tmp
= (struct menucoloring
*) alloc(sizeof (struct menucoloring
));
1602 tmp
->match
= regex_init();
1603 if (!regex_compile(str
, tmp
->match
)) {
1604 if (!iflags
.window_inited
)
1605 raw_printf("\n%s: %s\n", re_error
, regex_error_desc(tmp
->match
));
1607 pline("%s: %s", re_error
, regex_error_desc(tmp
->match
));
1609 regex_free(tmp
->match
);
1613 tmp
->next
= menu_colorings
;
1614 tmp
->origstr
= dupstr(str
);
1617 menu_colorings
= tmp
;
1622 /* parse '"regex_string"=color&attr' and add it to menucoloring */
1624 add_menu_coloring(str
)
1627 int i
, c
= NO_COLOR
, a
= ATR_NONE
;
1628 char *tmps
, *cs
, *amp
;
1630 if (!str
|| (cs
= index(str
, '=')) == 0)
1633 tmps
= cs
+ 1; /* advance past '=' */
1635 if ((amp
= index(tmps
, '&')) != 0)
1638 c
= match_str2clr(tmps
);
1643 tmps
= amp
+ 1; /* advance past '&' */
1644 /* unlike colors, none of he attribute names has any embedded spaces,
1645 but use of fuzzymatch() allows us ignore the presence of leading
1646 and/or trailing (and also embedded) spaces in the user's string;
1647 dash and underscore skipping could be omitted but does no harm */
1648 for (i
= 0; i
< SIZE(attrnames
); i
++)
1649 if (fuzzymatch(tmps
, attrnames
[i
].name
, " -_", TRUE
)) {
1650 a
= attrnames
[i
].attr
;
1653 if (i
== SIZE(attrnames
) && (*tmps
>= '0' && *tmps
<= '9'))
1657 /* the regexp portion here has not been condensed by mungspaces() */
1660 if (*tmps
== '"' || *tmps
== '\'') {
1662 while (isspace((uchar
) *cs
))
1670 return add_menu_coloring_parsed(tmps
, c
, a
);
1674 get_menu_coloring(str
, color
, attr
)
1678 struct menucoloring
*tmpmc
;
1680 if (iflags
.use_menu_color
)
1681 for (tmpmc
= menu_colorings
; tmpmc
; tmpmc
= tmpmc
->next
)
1682 if (regex_match(str
, tmpmc
->match
)) {
1683 *color
= tmpmc
->color
;
1684 *attr
= tmpmc
->attr
;
1691 free_menu_coloring()
1693 struct menucoloring
*tmp
= menu_colorings
;
1696 struct menucoloring
*tmp2
= tmp
->next
;
1698 regex_free(tmp
->match
);
1699 free((genericptr_t
) tmp
->origstr
);
1700 free((genericptr_t
) tmp
);
1706 free_one_menu_coloring(idx
)
1709 struct menucoloring
*tmp
= menu_colorings
;
1710 struct menucoloring
*prev
= NULL
;
1714 struct menucoloring
*next
= tmp
->next
;
1716 regex_free(tmp
->match
);
1717 free((genericptr_t
) tmp
->origstr
);
1718 free((genericptr_t
) tmp
);
1722 menu_colorings
= next
;
1735 struct menucoloring
*tmp
= menu_colorings
;
1745 parse_role_opts(negated
, fullname
, opts
, opp
)
1747 const char *fullname
;
1754 bad_negation(fullname
, FALSE
);
1755 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
1756 boolean val_negated
= FALSE
;
1758 while ((*op
== '!') || !strncmpi(op
, "no", 2)) {
1763 val_negated
= !val_negated
;
1766 if (!setrolefilter(op
))
1769 if (duplicate_opt_detection(opts
, 1))
1770 complain_about_duplicate(opts
, 1);
1778 /* Check if character c is illegal as a menu command key */
1780 illegal_menu_cmd_key(c
)
1783 if (c
== 0 || c
== '\r' || c
== '\n' || c
== '\033'
1784 || c
== ' ' || digit(c
) || (letter(c
) && c
!= '@'))
1786 else { /* reject default object class symbols */
1788 for (j
= 1; j
< MAXOCLASSES
; j
++)
1789 if (c
== def_oc_syms
[j
].sym
)
1796 parseoptions(opts
, tinitial
, tfrom_file
)
1797 register char *opts
;
1798 boolean tinitial
, tfrom_file
;
1802 boolean negated
, duplicate
;
1804 const char *fullname
;
1807 from_file
= tfrom_file
;
1808 if ((op
= index(opts
, ',')) != 0) {
1810 parseoptions(op
, initial
, from_file
);
1812 if (strlen(opts
) > BUFSZ
/ 2) {
1813 badoption("option too long");
1817 /* strip leading and trailing white space */
1818 while (isspace((uchar
) *opts
))
1821 while (--op
>= opts
&& isspace((uchar
) *op
))
1827 while ((*opts
== '!') || !strncmpi(opts
, "no", 2)) {
1835 /* variant spelling */
1837 if (match_optname(opts
, "colour", 5, FALSE
))
1838 Strcpy(opts
, "color"); /* fortunately this isn't longer */
1840 /* special boolean options */
1842 if (match_optname(opts
, "female", 3, FALSE
)) {
1843 if (duplicate_opt_detection(opts
, 0))
1844 complain_about_duplicate(opts
, 0);
1845 if (!initial
&& flags
.female
== negated
)
1846 pline("That is not anatomically possible.");
1848 flags
.initgend
= flags
.female
= !negated
;
1852 if (match_optname(opts
, "male", 4, FALSE
)) {
1853 if (duplicate_opt_detection(opts
, 0))
1854 complain_about_duplicate(opts
, 0);
1855 if (!initial
&& flags
.female
!= negated
)
1856 pline("That is not anatomically possible.");
1858 flags
.initgend
= flags
.female
= negated
;
1862 #if defined(MICRO) && !defined(AMIGA)
1863 /* included for compatibility with old NetHack.cnf files */
1864 if (match_optname(opts
, "IBM_", 4, FALSE
)) {
1865 iflags
.BIOS
= !negated
;
1870 /* compound options */
1872 /* This first batch can be duplicated if their values are negated */
1876 if (match_optname(opts
, fullname
, sizeof("align") - 1, TRUE
)) {
1877 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1878 if ((flags
.initalign
= str2align(op
)) == ROLE_NONE
)
1884 /* role:string or character:string */
1886 if (match_optname(opts
, fullname
, 4, TRUE
)
1887 || match_optname(opts
, (fullname
= "character"), 4, TRUE
)) {
1888 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1889 if ((flags
.initrole
= str2role(op
)) == ROLE_NONE
)
1891 else /* Backwards compatibility */
1892 nmcpy(pl_character
, op
, PL_NSIZ
);
1899 if (match_optname(opts
, fullname
, 4, TRUE
)) {
1900 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1901 if ((flags
.initrace
= str2race(op
)) == ROLE_NONE
)
1903 else /* Backwards compatibility */
1910 fullname
= "gender";
1911 if (match_optname(opts
, fullname
, 4, TRUE
)) {
1912 if (parse_role_opts(negated
, fullname
, opts
, &op
)) {
1913 if ((flags
.initgend
= str2gend(op
)) == ROLE_NONE
)
1916 flags
.female
= flags
.initgend
;
1921 /* We always check for duplicates on the remaining compound options,
1922 although individual option processing can choose to complain or not */
1925 duplicate_opt_detection(opts
, 1); /* 1 means check compounds */
1927 fullname
= "pettype";
1928 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1930 complain_about_duplicate(opts
, 1);
1931 if ((op
= string_for_env_opt(fullname
, opts
, negated
)) != 0) {
1933 bad_negation(fullname
, TRUE
);
1935 switch (lowc(*op
)) {
1937 preferred_pet
= 'd';
1940 case 'f': /* feline */
1941 preferred_pet
= 'c';
1943 case 'h': /* horse */
1944 case 'q': /* quadruped */
1945 /* avoids giving "unrecognized type of pet" but
1946 pet_type(dog.c) won't actually honor this */
1947 preferred_pet
= 'h';
1949 case 'n': /* no pet */
1950 preferred_pet
= 'n';
1952 case '*': /* random */
1953 preferred_pet
= '\0';
1956 pline("Unrecognized pet type '%s'.", op
);
1960 preferred_pet
= 'n';
1964 fullname
= "catname";
1965 if (match_optname(opts
, fullname
, 3, 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(catname
, op
, PL_PSIZ
);
1972 sanitize_name(catname
);
1976 fullname
= "dogname";
1977 if (match_optname(opts
, fullname
, 3, TRUE
)) {
1979 complain_about_duplicate(opts
, 1);
1981 bad_negation(fullname
, FALSE
);
1982 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1983 nmcpy(dogname
, op
, PL_PSIZ
);
1984 sanitize_name(dogname
);
1988 fullname
= "horsename";
1989 if (match_optname(opts
, fullname
, 5, TRUE
)) {
1991 complain_about_duplicate(opts
, 1);
1993 bad_negation(fullname
, FALSE
);
1994 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
1995 nmcpy(horsename
, op
, PL_PSIZ
);
1996 sanitize_name(horsename
);
2000 fullname
= "number_pad";
2001 if (match_optname(opts
, fullname
, 10, TRUE
)) {
2002 boolean compat
= (strlen(opts
) <= 10);
2005 complain_about_duplicate(opts
, 1);
2006 op
= string_for_opt(opts
, (compat
|| !initial
));
2008 if (compat
|| negated
|| initial
) {
2009 /* for backwards compatibility, "number_pad" without a
2010 value is a synonym for number_pad:1 */
2011 iflags
.num_pad
= !negated
;
2012 iflags
.num_pad_mode
= 0;
2014 } else if (negated
) {
2015 bad_negation("number_pad", TRUE
);
2018 int mode
= atoi(op
);
2020 if (mode
< -1 || mode
> 4 || (mode
== 0 && *op
!= '0')) {
2023 } else if (mode
<= 0) {
2024 iflags
.num_pad
= FALSE
;
2025 /* German keyboard; y and z keys swapped */
2026 iflags
.num_pad_mode
= (mode
< 0); /* 0 or 1 */
2027 } else { /* mode > 0 */
2028 iflags
.num_pad
= TRUE
;
2029 iflags
.num_pad_mode
= 0;
2030 /* PC Hack / MSDOS compatibility */
2031 if (mode
== 2 || mode
== 4)
2032 iflags
.num_pad_mode
|= 1;
2033 /* phone keypad layout */
2034 if (mode
== 3 || mode
== 4)
2035 iflags
.num_pad_mode
|= 2;
2038 reset_commands(FALSE
);
2039 number_pad(iflags
.num_pad
? 1 : 0);
2043 fullname
= "roguesymset";
2044 if (match_optname(opts
, fullname
, 7, TRUE
)) {
2046 complain_about_duplicate(opts
, 1);
2048 bad_negation(fullname
, FALSE
);
2049 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2050 symset
[ROGUESET
].name
= dupstr(op
);
2051 if (!read_sym_file(ROGUESET
)) {
2052 clear_symsetentry(ROGUESET
, TRUE
);
2053 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2057 if (!initial
&& Is_rogue_level(&u
.uz
))
2058 assign_graphics(ROGUESET
);
2065 fullname
= "symset";
2066 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2068 complain_about_duplicate(opts
, 1);
2070 bad_negation(fullname
, FALSE
);
2071 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2072 symset
[PRIMARY
].name
= dupstr(op
);
2073 if (!read_sym_file(PRIMARY
)) {
2074 clear_symsetentry(PRIMARY
, TRUE
);
2075 raw_printf("Unable to load symbol set \"%s\" from \"%s\".",
2079 switch_symbols(symset
[PRIMARY
].name
!= (char *) 0);
2086 fullname
= "runmode";
2087 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2089 complain_about_duplicate(opts
, 1);
2091 flags
.runmode
= RUN_TPORT
;
2092 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
2093 if (!strncmpi(op
, "teleport", strlen(op
)))
2094 flags
.runmode
= RUN_TPORT
;
2095 else if (!strncmpi(op
, "run", strlen(op
)))
2096 flags
.runmode
= RUN_LEAP
;
2097 else if (!strncmpi(op
, "walk", strlen(op
)))
2098 flags
.runmode
= RUN_STEP
;
2099 else if (!strncmpi(op
, "crawl", strlen(op
)))
2100 flags
.runmode
= RUN_CRAWL
;
2107 /* menucolor:"regex_string"=color */
2108 fullname
= "menucolor";
2109 if (match_optname(opts
, fullname
, 9, TRUE
)) {
2111 bad_negation(fullname
, FALSE
);
2112 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
2113 if (!add_menu_coloring(op
))
2118 fullname
= "msghistory";
2119 if (match_optname(opts
, fullname
, 3, TRUE
)) {
2121 complain_about_duplicate(opts
, 1);
2122 op
= string_for_env_opt(fullname
, opts
, negated
);
2123 if ((negated
&& !op
) || (!negated
&& op
)) {
2124 iflags
.msg_history
= negated
? 0 : atoi(op
);
2126 bad_negation(fullname
, TRUE
);
2130 fullname
= "msg_window";
2131 /* msg_window:single, combo, full or reversed */
2132 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2133 /* allow option to be silently ignored by non-tty ports */
2138 complain_about_duplicate(opts
, 1);
2139 if (!(op
= string_for_opt(opts
, TRUE
))) {
2140 tmp
= negated
? 's' : 'f';
2143 bad_negation(fullname
, TRUE
);
2149 case 's': /* single message history cycle (default if negated) */
2150 iflags
.prevmsg_window
= 's';
2152 case 'c': /* combination: two singles, then full page reversed */
2153 iflags
.prevmsg_window
= 'c';
2155 case 'f': /* full page (default if no opts) */
2156 iflags
.prevmsg_window
= 'f';
2158 case 'r': /* full page (reversed) */
2159 iflags
.prevmsg_window
= 'r';
2169 * setting font options */
2171 if (!strncmpi(opts
, fullname
, 4)) {
2173 char *fontopts
= opts
+ 4;
2175 if (!strncmpi(fontopts
, "map", 3) || !strncmpi(fontopts
, "_map", 4))
2176 opttype
= MAP_OPTION
;
2177 else if (!strncmpi(fontopts
, "message", 7)
2178 || !strncmpi(fontopts
, "_message", 8))
2179 opttype
= MESSAGE_OPTION
;
2180 else if (!strncmpi(fontopts
, "text", 4)
2181 || !strncmpi(fontopts
, "_text", 5))
2182 opttype
= TEXT_OPTION
;
2183 else if (!strncmpi(fontopts
, "menu", 4)
2184 || !strncmpi(fontopts
, "_menu", 5))
2185 opttype
= MENU_OPTION
;
2186 else if (!strncmpi(fontopts
, "status", 6)
2187 || !strncmpi(fontopts
, "_status", 7))
2188 opttype
= STATUS_OPTION
;
2189 else if (!strncmpi(fontopts
, "_size", 5)) {
2190 if (!strncmpi(fontopts
, "_size_map", 8))
2191 opttype
= MAP_OPTION
;
2192 else if (!strncmpi(fontopts
, "_size_message", 12))
2193 opttype
= MESSAGE_OPTION
;
2194 else if (!strncmpi(fontopts
, "_size_text", 9))
2195 opttype
= TEXT_OPTION
;
2196 else if (!strncmpi(fontopts
, "_size_menu", 9))
2197 opttype
= MENU_OPTION
;
2198 else if (!strncmpi(fontopts
, "_size_status", 11))
2199 opttype
= STATUS_OPTION
;
2205 complain_about_duplicate(opts
, 1);
2206 if (opttype
> 0 && !negated
2207 && (op
= string_for_opt(opts
, FALSE
)) != 0) {
2210 iflags
.wc_fontsiz_map
= atoi(op
);
2212 case MESSAGE_OPTION
:
2213 iflags
.wc_fontsiz_message
= atoi(op
);
2216 iflags
.wc_fontsiz_text
= atoi(op
);
2219 iflags
.wc_fontsiz_menu
= atoi(op
);
2222 iflags
.wc_fontsiz_status
= atoi(op
);
2230 if (opttype
> 0 && (op
= string_for_opt(opts
, FALSE
)) != 0) {
2231 wc_set_font_name(opttype
, op
);
2233 set_font_name(opttype
, op
);
2237 bad_negation(fullname
, TRUE
);
2242 if (match_optname(opts
, "palette", 3, TRUE
)
2244 || match_optname(opts
, "hicolor", 3, TRUE
)
2247 int color_number
, color_incr
;
2251 complain_about_duplicate(opts
, 1);
2254 if (match_optname(opts
, "hicolor", 3, TRUE
)) {
2256 bad_negation("hicolor", FALSE
);
2259 color_number
= CLR_MAX
+ 4; /* HARDCODED inverse number */
2265 bad_negation("palette", FALSE
);
2272 op
= string_for_opt(opts
, TRUE
);
2273 if (!alternative_palette(op
))
2276 if ((op
= string_for_opt(opts
, FALSE
)) != (char *) 0) {
2278 int cnt
, tmp
, reverse
;
2281 while (*pt
&& color_number
>= 0) {
2291 if (*pt
&& *pt
!= '/') {
2298 if (isalpha((uchar
) tmp
)) {
2299 tmp
= (tmp
+ 9) & 0xf; /* Assumes ASCII... */
2301 tmp
&= 0xf; /* Digits in ASCII too... */
2304 /* Add an extra so we fill f -> ff and 0 -> 00 */
2312 change_color(color_number
, rgb
, reverse
);
2313 color_number
+= color_incr
;
2322 #endif /* CHANGE_COLOR */
2324 if (match_optname(opts
, "fruit", 2, TRUE
)) {
2325 struct fruit
*forig
= 0;
2326 char empty_str
= '\0';
2329 complain_about_duplicate(opts
, 1);
2330 op
= string_for_opt(opts
, negated
);
2333 bad_negation("fruit", TRUE
);
2345 for (f
= ffruit
; f
; f
= f
->nextf
) {
2346 if (!strcmp(op
, f
->fname
))
2350 if (!flags
.made_fruit
) {
2351 for (forig
= ffruit
; forig
; forig
= forig
->nextf
) {
2352 if (!strcmp(pl_fruit
, forig
->fname
)) {
2357 if (!forig
&& num
>= 100) {
2358 pline("Doing that so many times isn't very fruitful.");
2363 nmcpy(pl_fruit
, op
, PL_FSIZ
);
2364 sanitize_name(pl_fruit
);
2365 /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
2367 nmcpy(pl_fruit
, "slime mold", PL_FSIZ
);
2369 (void) fruitadd(pl_fruit
, forig
);
2370 pline("Fruit is now \"%s\".", pl_fruit
);
2372 /* If initial, then initoptions is allowed to do it instead
2373 * of here (initoptions always has to do it even if there's
2374 * no fruit option at all. Also, we don't want people
2375 * setting multiple fruits in their options.)
2380 fullname
= "whatis_coord";
2381 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2383 complain_about_duplicate(opts
, 1);
2385 iflags
.getpos_coords
= GPCOORDS_NONE
;
2387 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
2388 static char gpcoords
[] = { GPCOORDS_NONE
, GPCOORDS_COMPASS
,
2389 GPCOORDS_COMFULL
, GPCOORDS_MAP
,
2390 GPCOORDS_SCREEN
, '\0' };
2393 if (c
&& index(gpcoords
, c
))
2394 iflags
.getpos_coords
= c
;
2401 fullname
= "warnings";
2402 if (match_optname(opts
, fullname
, 5, TRUE
)) {
2404 complain_about_duplicate(opts
, 1);
2406 bad_negation(fullname
, FALSE
);
2408 warning_opts(opts
, fullname
);
2412 #ifdef BACKWARD_COMPAT
2413 /* boulder:symbol */
2414 fullname
= "boulder";
2415 if (match_optname(opts
, fullname
, 7, TRUE
)) {
2418 complain_about_duplicate(opts
, 1);
2420 bad_negation(fullname
, FALSE
);
2423 /* if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
2425 if (!(opts
= string_for_opt(opts
, FALSE
)))
2427 escapes(opts
, opts
);
2428 if (def_char_to_monclass(opts
[0]) != MAXMCLASSES
)
2430 else if (opts
[0] >= '1' && opts
[0] <= '5')
2433 /* symbol chosen matches a used monster or warning
2434 symbol which is not good - reject it*/
2436 "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
2437 opts
[0], (clash
== 1) ? "monster" : "warning");
2440 * Override the default boulder symbol.
2442 iflags
.bouldersym
= (uchar
) opts
[0];
2452 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2454 complain_about_duplicate(opts
, 1);
2456 bad_negation(fullname
, FALSE
);
2457 else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0)
2458 nmcpy(plname
, op
, PL_NSIZ
);
2462 /* altkeyhandler:string */
2463 fullname
= "altkeyhandler";
2464 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2466 complain_about_duplicate(opts
, 1);
2468 bad_negation(fullname
, FALSE
);
2469 } else if ((op
= string_for_opt(opts
, negated
)) != 0) {
2471 (void) strncpy(iflags
.altkeyhandler
, op
, MAX_ALTKEYHANDLER
- 5);
2472 load_keyboard_handler();
2479 * align_status:[left|top|right|bottom] */
2480 fullname
= "align_status";
2481 if (match_optname(opts
, fullname
, sizeof("align_status") - 1, TRUE
)) {
2482 op
= string_for_opt(opts
, negated
);
2483 if (op
&& !negated
) {
2484 if (!strncmpi(op
, "left", sizeof("left") - 1))
2485 iflags
.wc_align_status
= ALIGN_LEFT
;
2486 else if (!strncmpi(op
, "top", sizeof("top") - 1))
2487 iflags
.wc_align_status
= ALIGN_TOP
;
2488 else if (!strncmpi(op
, "right", sizeof("right") - 1))
2489 iflags
.wc_align_status
= ALIGN_RIGHT
;
2490 else if (!strncmpi(op
, "bottom", sizeof("bottom") - 1))
2491 iflags
.wc_align_status
= ALIGN_BOTTOM
;
2495 bad_negation(fullname
, TRUE
);
2499 * align_message:[left|top|right|bottom] */
2500 fullname
= "align_message";
2501 if (match_optname(opts
, fullname
, sizeof("align_message") - 1, TRUE
)) {
2503 complain_about_duplicate(opts
, 1);
2504 op
= string_for_opt(opts
, negated
);
2505 if (op
&& !negated
) {
2506 if (!strncmpi(op
, "left", sizeof("left") - 1))
2507 iflags
.wc_align_message
= ALIGN_LEFT
;
2508 else if (!strncmpi(op
, "top", sizeof("top") - 1))
2509 iflags
.wc_align_message
= ALIGN_TOP
;
2510 else if (!strncmpi(op
, "right", sizeof("right") - 1))
2511 iflags
.wc_align_message
= ALIGN_RIGHT
;
2512 else if (!strncmpi(op
, "bottom", sizeof("bottom") - 1))
2513 iflags
.wc_align_message
= ALIGN_BOTTOM
;
2517 bad_negation(fullname
, TRUE
);
2520 /* the order to list the pack */
2521 fullname
= "packorder";
2522 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2524 complain_about_duplicate(opts
, 1);
2526 bad_negation(fullname
, FALSE
);
2528 } else if (!(op
= string_for_opt(opts
, FALSE
)))
2531 if (!change_inv_order(op
))
2536 /* user can change required response for some prompts (quit, die, hit),
2537 or add an extra prompt (pray, Remove) that isn't ordinarily there */
2538 fullname
= "paranoid_confirmation";
2539 if (match_optname(opts
, fullname
, 8, TRUE
)) {
2540 /* at present we don't complain about duplicates for this
2541 option, but we do throw away the old settings whenever
2542 we process a new one [clearing old flags is essential
2543 for handling default paranoid_confirm:pray sanely] */
2544 flags
.paranoia_bits
= 0; /* clear all */
2546 flags
.paranoia_bits
= 0; /* [now redundant...] */
2547 } else if ((op
= string_for_opt(opts
, TRUE
)) != 0) {
2548 char *pp
, buf
[BUFSZ
];
2550 strncpy(buf
, op
, sizeof buf
- 1);
2551 buf
[sizeof buf
- 1] = '\0';
2552 op
= mungspaces(buf
);
2554 /* We're looking to parse
2555 "paranoid_confirm:whichone wheretwo whothree"
2556 and "paranoid_confirm:" prefix has already
2557 been stripped off by the time we get here */
2558 pp
= index(op
, ' ');
2561 /* we aren't matching option names but match_optname
2562 does what we want once we've broken the space
2563 delimited aggregate into separate tokens */
2564 for (i
= 0; i
< SIZE(paranoia
); ++i
) {
2565 if (match_optname(op
, paranoia
[i
].argname
,
2566 paranoia
[i
].argMinLen
, FALSE
)
2567 || (paranoia
[i
].synonym
2568 && match_optname(op
, paranoia
[i
].synonym
,
2569 paranoia
[i
].synMinLen
, FALSE
))) {
2570 if (paranoia
[i
].flagmask
)
2571 flags
.paranoia_bits
|= paranoia
[i
].flagmask
;
2572 else /* 0 == "none", so clear all */
2573 flags
.paranoia_bits
= 0;
2577 if (i
== SIZE(paranoia
)) {
2578 /* didn't match anything, so arg is bad;
2579 any flags already set will stay set */
2583 /* move on to next token */
2587 break; /* no next token */
2593 /* accept deprecated boolean; superseded by paranoid_confirm:pray */
2594 fullname
= "prayconfirm";
2595 if (match_optname(opts
, fullname
, 4, FALSE
)) {
2597 flags
.paranoia_bits
&= ~PARANOID_PRAY
;
2599 flags
.paranoia_bits
|= PARANOID_PRAY
;
2603 /* maximum burden picked up before prompt (Warren Cheung) */
2604 fullname
= "pickup_burden";
2605 if (match_optname(opts
, fullname
, 8, TRUE
)) {
2607 complain_about_duplicate(opts
, 1);
2609 bad_negation(fullname
, FALSE
);
2611 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
2612 switch (lowc(*op
)) {
2613 case 'u': /* Unencumbered */
2614 flags
.pickup_burden
= UNENCUMBERED
;
2616 case 'b': /* Burdened (slight encumbrance) */
2617 flags
.pickup_burden
= SLT_ENCUMBER
;
2619 case 's': /* streSsed (moderate encumbrance) */
2620 flags
.pickup_burden
= MOD_ENCUMBER
;
2622 case 'n': /* straiNed (heavy encumbrance) */
2623 flags
.pickup_burden
= HVY_ENCUMBER
;
2625 case 'o': /* OverTaxed (extreme encumbrance) */
2627 flags
.pickup_burden
= EXT_ENCUMBER
;
2629 case 'l': /* overLoaded */
2630 flags
.pickup_burden
= OVERLOADED
;
2639 /* types of objects to pick up automatically */
2640 if (match_optname(opts
, "pickup_types", 8, TRUE
)) {
2641 char ocl
[MAXOCLASSES
+ 1], tbuf
[MAXOCLASSES
+ 1], qbuf
[QBUFSZ
],
2644 boolean badopt
= FALSE
, compat
= (strlen(opts
) <= 6), use_menu
;
2647 complain_about_duplicate(opts
, 1);
2648 oc_to_str(flags
.pickup_types
, tbuf
);
2649 flags
.pickup_types
[0] = '\0'; /* all */
2650 op
= string_for_opt(opts
, (compat
|| !initial
));
2652 if (compat
|| negated
|| initial
) {
2653 /* for backwards compatibility, "pickup" without a
2654 value is a synonym for autopickup of all types
2655 (and during initialization, we can't prompt yet) */
2656 flags
.pickup
= !negated
;
2659 oc_to_str(flags
.inv_order
, ocl
);
2661 if (flags
.menu_style
== MENU_TRADITIONAL
2662 || flags
.menu_style
== MENU_COMBINATION
) {
2664 Sprintf(qbuf
, "New pickup_types: [%s am] (%s)", ocl
,
2665 *tbuf
? tbuf
: "all");
2667 op
= mungspaces(abuf
);
2668 if (abuf
[0] == '\0' || abuf
[0] == '\033')
2669 op
= tbuf
; /* restore */
2670 else if (abuf
[0] == 'm')
2674 (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE
, ocl
,
2680 bad_negation("pickup_types", TRUE
);
2685 if (*op
!= 'a' && *op
!= 'A') {
2688 oc_sym
= def_char_to_objclass(*op
);
2689 /* make sure all are valid obj symbols occurring once */
2690 if (oc_sym
!= MAXOCLASSES
2691 && !index(flags
.pickup_types
, oc_sym
)) {
2692 flags
.pickup_types
[num
] = (char) oc_sym
;
2693 flags
.pickup_types
[++num
] = '\0';
2704 /* pile limit: when walking over objects, number which triggers
2705 "there are several/many objects here" instead of listing them */
2706 fullname
= "pile_limit";
2707 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2709 complain_about_duplicate(opts
, 1);
2710 op
= string_for_opt(opts
, negated
);
2711 if ((negated
&& !op
) || (!negated
&& op
))
2712 flags
.pile_limit
= negated
? 0 : atoi(op
);
2714 bad_negation(fullname
, TRUE
);
2716 flags
.pile_limit
= PILE_LIMIT_DFLT
;
2718 if (flags
.pile_limit
< 0)
2719 flags
.pile_limit
= PILE_LIMIT_DFLT
;
2723 /* play mode: normal, explore/discovery, or debug/wizard */
2724 fullname
= "playmode";
2725 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2727 complain_about_duplicate(opts
, 1);
2729 bad_negation(fullname
, FALSE
);
2730 if (duplicate
|| negated
)
2732 op
= string_for_opt(opts
, FALSE
);
2735 if (!strncmpi(op
, "normal", 6) || !strcmpi(op
, "play")) {
2736 wizard
= discover
= FALSE
;
2737 } else if (!strncmpi(op
, "explore", 6)
2738 || !strncmpi(op
, "discovery", 6)) {
2739 wizard
= FALSE
, discover
= TRUE
;
2740 } else if (!strncmpi(op
, "debug", 5) || !strncmpi(op
, "wizard", 6)) {
2741 wizard
= TRUE
, discover
= FALSE
;
2743 raw_printf("Invalid value for \"%s\":%s.", fullname
, op
);
2749 * player_selection: dialog | prompts */
2750 fullname
= "player_selection";
2751 if (match_optname(opts
, fullname
, sizeof("player_selection") - 1, TRUE
)) {
2753 complain_about_duplicate(opts
, 1);
2754 op
= string_for_opt(opts
, negated
);
2755 if (op
&& !negated
) {
2756 if (!strncmpi(op
, "dialog", sizeof("dialog") - 1))
2757 iflags
.wc_player_selection
= VIA_DIALOG
;
2758 else if (!strncmpi(op
, "prompt", sizeof("prompt") - 1))
2759 iflags
.wc_player_selection
= VIA_PROMPTS
;
2763 bad_negation(fullname
, TRUE
);
2767 /* things to disclose at end of game */
2768 if (match_optname(opts
, "disclose", 7, TRUE
)) {
2770 * The order that the end_disclose options are stored:
2771 * inventory, attribs, vanquished, genocided,
2772 * conduct, overview.
2773 * There is an array in flags:
2774 * end_disclose[NUM_DISCLOSURE_OPT];
2775 * with option settings for the each of the following:
2776 * iagvc [see disclosure_options in decl.c]:
2777 * Legal setting values in that array are:
2778 * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
2779 * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
2780 * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
2781 * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
2783 * Those setting values can be used in the option
2784 * string as a prefix to get the desired behaviour.
2786 * For backward compatibility, no prefix is required,
2787 * and the presence of a i,a,g,v, or c without a prefix
2788 * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
2790 boolean badopt
= FALSE
;
2791 int idx
, prefix_val
;
2794 complain_about_duplicate(opts
, 1);
2795 op
= string_for_opt(opts
, TRUE
);
2796 if (op
&& negated
) {
2797 bad_negation("disclose", TRUE
);
2800 /* "disclose" without a value means "all with prompting"
2801 and negated means "none without prompting" */
2802 if (!op
|| !strcmpi(op
, "all") || !strcmpi(op
, "none")) {
2803 if (op
&& !strcmpi(op
, "none"))
2805 for (num
= 0; num
< NUM_DISCLOSURE_OPTIONS
; num
++)
2806 flags
.end_disclose
[num
] = negated
2807 ? DISCLOSE_NO_WITHOUT_PROMPT
2808 : DISCLOSE_PROMPT_DEFAULT_YES
;
2814 while (*op
&& num
< sizeof flags
.end_disclose
- 1) {
2815 static char valid_settings
[] = {
2816 DISCLOSE_PROMPT_DEFAULT_YES
, DISCLOSE_PROMPT_DEFAULT_NO
,
2817 DISCLOSE_PROMPT_DEFAULT_SPECIAL
,
2818 DISCLOSE_YES_WITHOUT_PROMPT
, DISCLOSE_NO_WITHOUT_PROMPT
,
2819 DISCLOSE_SPECIAL_WITHOUT_PROMPT
, '\0'
2821 register char c
, *dop
;
2825 c
= 'v'; /* killed -> vanquished */
2827 c
= 'o'; /* dungeon -> overview */
2828 dop
= index(disclosure_options
, c
);
2830 idx
= (int) (dop
- disclosure_options
);
2831 if (idx
< 0 || idx
> NUM_DISCLOSURE_OPTIONS
- 1) {
2832 impossible("bad disclosure index %d %c", idx
, c
);
2835 if (prefix_val
!= -1) {
2837 if (prefix_val
== DISCLOSE_PROMPT_DEFAULT_SPECIAL
)
2838 prefix_val
= DISCLOSE_PROMPT_DEFAULT_YES
;
2839 if (prefix_val
== DISCLOSE_SPECIAL_WITHOUT_PROMPT
)
2840 prefix_val
= DISCLOSE_YES_WITHOUT_PROMPT
;
2842 flags
.end_disclose
[idx
] = prefix_val
;
2845 flags
.end_disclose
[idx
] = DISCLOSE_YES_WITHOUT_PROMPT
;
2846 } else if (index(valid_settings
, c
)) {
2848 } else if (c
== ' ') {
2859 /* scores:5t[op] 5a[round] o[wn] */
2860 if (match_optname(opts
, "scores", 4, TRUE
)) {
2862 complain_about_duplicate(opts
, 1);
2864 bad_negation("scores", FALSE
);
2867 if (!(op
= string_for_opt(opts
, FALSE
)))
2877 } else if (*op
== '!') {
2887 flags
.end_top
= inum
;
2891 flags
.end_around
= inum
;
2895 flags
.end_own
= !negated
;
2901 while (letter(*++op
) || *op
== ' ')
2909 fullname
= "sortloot";
2910 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2911 op
= string_for_env_opt(fullname
, opts
, FALSE
);
2916 case 'n': /* none */
2917 case 'l': /* loot (pickup) */
2918 case 'f': /* full (pickup + invent) */
2929 fullname
= "suppress_alert";
2930 if (match_optname(opts
, fullname
, 4, TRUE
)) {
2932 complain_about_duplicate(opts
, 1);
2933 op
= string_for_opt(opts
, negated
);
2935 bad_negation(fullname
, FALSE
);
2937 (void) feature_alert_opts(op
, fullname
);
2942 /* videocolors:string */
2943 fullname
= "videocolors";
2944 if (match_optname(opts
, fullname
, 6, TRUE
)
2945 || match_optname(opts
, "videocolours", 10, TRUE
)) {
2947 complain_about_duplicate(opts
, 1);
2949 bad_negation(fullname
, FALSE
);
2951 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2954 if (!assign_videocolors(opts
))
2958 /* videoshades:string */
2959 fullname
= "videoshades";
2960 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2962 complain_about_duplicate(opts
, 1);
2964 bad_negation(fullname
, FALSE
);
2966 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2969 if (!assign_videoshades(opts
))
2973 #endif /* VIDEOSHADES */
2976 /* video:string -- must be after longer tests */
2978 if (match_optname(opts
, fullname
, 5, TRUE
)) {
2980 complain_about_duplicate(opts
, 1);
2982 bad_negation(fullname
, FALSE
);
2984 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
2987 if (!assign_video(opts
))
2991 #endif /* NO_TERMS */
2992 /* soundcard:string -- careful not to match boolean 'sound' */
2993 fullname
= "soundcard";
2994 if (match_optname(opts
, fullname
, 6, TRUE
)) {
2996 complain_about_duplicate(opts
, 1);
2998 bad_negation(fullname
, FALSE
);
3000 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
3003 if (!assign_soundcard(opts
))
3011 * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|
3012 * ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen]
3014 fullname
= "map_mode";
3015 if (match_optname(opts
, fullname
, sizeof("map_mode") - 1, TRUE
)) {
3017 complain_about_duplicate(opts
, 1);
3018 op
= string_for_opt(opts
, negated
);
3019 if (op
&& !negated
) {
3020 if (!strncmpi(op
, "tiles", sizeof("tiles") - 1))
3021 iflags
.wc_map_mode
= MAP_MODE_TILES
;
3022 else if (!strncmpi(op
, "ascii4x6", sizeof("ascii4x6") - 1))
3023 iflags
.wc_map_mode
= MAP_MODE_ASCII4x6
;
3024 else if (!strncmpi(op
, "ascii6x8", sizeof("ascii6x8") - 1))
3025 iflags
.wc_map_mode
= MAP_MODE_ASCII6x8
;
3026 else if (!strncmpi(op
, "ascii8x8", sizeof("ascii8x8") - 1))
3027 iflags
.wc_map_mode
= MAP_MODE_ASCII8x8
;
3028 else if (!strncmpi(op
, "ascii16x8", sizeof("ascii16x8") - 1))
3029 iflags
.wc_map_mode
= MAP_MODE_ASCII16x8
;
3030 else if (!strncmpi(op
, "ascii7x12", sizeof("ascii7x12") - 1))
3031 iflags
.wc_map_mode
= MAP_MODE_ASCII7x12
;
3032 else if (!strncmpi(op
, "ascii8x12", sizeof("ascii8x12") - 1))
3033 iflags
.wc_map_mode
= MAP_MODE_ASCII8x12
;
3034 else if (!strncmpi(op
, "ascii16x12", sizeof("ascii16x12") - 1))
3035 iflags
.wc_map_mode
= MAP_MODE_ASCII16x12
;
3036 else if (!strncmpi(op
, "ascii12x16", sizeof("ascii12x16") - 1))
3037 iflags
.wc_map_mode
= MAP_MODE_ASCII12x16
;
3038 else if (!strncmpi(op
, "ascii10x18", sizeof("ascii10x18") - 1))
3039 iflags
.wc_map_mode
= MAP_MODE_ASCII10x18
;
3040 else if (!strncmpi(op
, "fit_to_screen",
3041 sizeof("fit_to_screen") - 1))
3042 iflags
.wc_map_mode
= MAP_MODE_ASCII_FIT_TO_SCREEN
;
3046 bad_negation(fullname
, TRUE
);
3050 * scroll_amount:nn */
3051 fullname
= "scroll_amount";
3052 if (match_optname(opts
, fullname
, sizeof("scroll_amount") - 1, TRUE
)) {
3054 complain_about_duplicate(opts
, 1);
3055 op
= string_for_opt(opts
, negated
);
3056 if ((negated
&& !op
) || (!negated
&& op
)) {
3057 iflags
.wc_scroll_amount
= negated
? 1 : atoi(op
);
3059 bad_negation(fullname
, TRUE
);
3063 * scroll_margin:nn */
3064 fullname
= "scroll_margin";
3065 if (match_optname(opts
, fullname
, sizeof("scroll_margin") - 1, TRUE
)) {
3067 complain_about_duplicate(opts
, 1);
3068 op
= string_for_opt(opts
, negated
);
3069 if ((negated
&& !op
) || (!negated
&& op
)) {
3070 iflags
.wc_scroll_margin
= negated
? 5 : atoi(op
);
3072 bad_negation(fullname
, TRUE
);
3075 fullname
= "subkeyvalue";
3076 if (match_optname(opts
, fullname
, 5, TRUE
)) {
3077 /* no duplicate complaint here */
3079 bad_negation(fullname
, FALSE
);
3082 op
= string_for_opt(opts
, 0);
3083 map_subkeyvalue(op
);
3090 fullname
= "tile_width";
3091 if (match_optname(opts
, fullname
, sizeof("tile_width") - 1, TRUE
)) {
3093 complain_about_duplicate(opts
, 1);
3094 op
= string_for_opt(opts
, negated
);
3095 if ((negated
&& !op
) || (!negated
&& op
)) {
3096 iflags
.wc_tile_width
= negated
? 0 : atoi(op
);
3098 bad_negation(fullname
, TRUE
);
3103 fullname
= "tile_file";
3104 if (match_optname(opts
, fullname
, sizeof("tile_file") - 1, TRUE
)) {
3106 complain_about_duplicate(opts
, 1);
3107 if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3108 if (iflags
.wc_tile_file
)
3109 free(iflags
.wc_tile_file
);
3110 iflags
.wc_tile_file
= dupstr(op
);
3116 fullname
= "tile_height";
3117 if (match_optname(opts
, fullname
, sizeof("tile_height") - 1, TRUE
)) {
3119 complain_about_duplicate(opts
, 1);
3120 op
= string_for_opt(opts
, negated
);
3121 if ((negated
&& !op
) || (!negated
&& op
)) {
3122 iflags
.wc_tile_height
= negated
? 0 : atoi(op
);
3124 bad_negation(fullname
, TRUE
);
3128 * vary_msgcount:nn */
3129 fullname
= "vary_msgcount";
3130 if (match_optname(opts
, fullname
, sizeof("vary_msgcount") - 1, TRUE
)) {
3132 complain_about_duplicate(opts
, 1);
3133 op
= string_for_opt(opts
, negated
);
3134 if ((negated
&& !op
) || (!negated
&& op
)) {
3135 iflags
.wc_vary_msgcount
= negated
? 0 : atoi(op
);
3137 bad_negation(fullname
, TRUE
);
3140 fullname
= "windowtype";
3141 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3143 complain_about_duplicate(opts
, 1);
3145 bad_negation(fullname
, FALSE
);
3147 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
3148 char buf
[WINTYPELEN
];
3149 nmcpy(buf
, op
, WINTYPELEN
);
3150 choose_windows(buf
);
3155 fullname
= "windowchain";
3156 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3158 bad_negation(fullname
, FALSE
);
3160 } else if ((op
= string_for_env_opt(fullname
, opts
, FALSE
)) != 0) {
3161 char buf
[WINTYPELEN
];
3162 nmcpy(buf
, op
, WINTYPELEN
);
3163 addto_windowchain(buf
);
3170 * setting window colors
3171 * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
3173 fullname
= "windowcolors";
3174 if (match_optname(opts
, fullname
, 7, TRUE
)) {
3176 complain_about_duplicate(opts
, 1);
3177 if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3178 if (!wc_set_window_colors(op
))
3181 bad_negation(fullname
, TRUE
);
3185 /* menustyle:traditional or combination or full or partial */
3186 if (match_optname(opts
, "menustyle", 4, TRUE
)) {
3188 boolean val_required
= (strlen(opts
) > 5 && !negated
);
3191 complain_about_duplicate(opts
, 1);
3192 if (!(op
= string_for_opt(opts
, !val_required
))) {
3194 return; /* string_for_opt gave feedback */
3195 tmp
= negated
? 'n' : 'f';
3200 case 'n': /* none */
3201 case 't': /* traditional: prompt for class(es) by symbol,
3202 prompt for each item within class(es) one at a time */
3203 flags
.menu_style
= MENU_TRADITIONAL
;
3205 case 'c': /* combination: prompt for class(es) by symbol,
3206 choose items within selected class(es) by menu */
3207 flags
.menu_style
= MENU_COMBINATION
;
3209 case 'f': /* full: choose class(es) by first menu,
3210 choose items within selected class(es) by second menu */
3211 flags
.menu_style
= MENU_FULL
;
3213 case 'p': /* partial: skip class filtering,
3214 choose items among all classes by menu */
3215 flags
.menu_style
= MENU_PARTIAL
;
3223 fullname
= "menu_headings";
3224 if (match_optname(opts
, fullname
, 12, TRUE
)) {
3226 complain_about_duplicate(opts
, 1);
3228 bad_negation(fullname
, FALSE
);
3230 } else if (!(opts
= string_for_env_opt(fullname
, opts
, FALSE
))) {
3233 for (i
= 0; i
< SIZE(attrnames
); i
++)
3234 if (!strcmpi(opts
, attrnames
[i
].name
)) {
3235 iflags
.menu_headings
= attrnames
[i
].attr
;
3242 /* check for menu command mapping */
3243 for (i
= 0; i
< SIZE(default_menu_cmd_info
); i
++) {
3244 fullname
= default_menu_cmd_info
[i
].name
;
3246 complain_about_duplicate(opts
, 1);
3247 if (match_optname(opts
, fullname
, (int) strlen(fullname
), TRUE
)) {
3249 bad_negation(fullname
, FALSE
);
3250 } else if ((op
= string_for_opt(opts
, FALSE
)) != 0) {
3251 char c
, op_buf
[BUFSZ
];
3253 escapes(op
, op_buf
);
3256 if (illegal_menu_cmd_key(c
))
3259 add_menu_cmd_alias(c
, default_menu_cmd_info
[i
].cmd
);
3264 #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES)
3265 /* hilite fields in status prompt */
3266 if (match_optname(opts
, "hilite_status", 13, TRUE
)) {
3268 complain_about_duplicate(opts
, 1);
3269 op
= string_for_opt(opts
, TRUE
);
3270 if (op
&& negated
) {
3271 clear_status_hilites(tfrom_file
);
3274 /* a value is mandatory */
3278 if (!set_status_hilites(op
, tfrom_file
))
3284 #if defined(BACKWARD_COMPAT)
3285 fullname
= "DECgraphics";
3286 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3287 boolean badflag
= FALSE
;
3290 complain_about_duplicate(opts
, 1);
3292 /* There is no rogue level DECgraphics-specific set */
3293 if (symset
[PRIMARY
].name
) {
3296 symset
[PRIMARY
].name
= dupstr(fullname
);
3297 if (!read_sym_file(PRIMARY
)) {
3299 clear_symsetentry(PRIMARY
, TRUE
);
3301 switch_symbols(TRUE
);
3304 pline("Failure to load symbol set %s.", fullname
);
3310 fullname
= "IBMgraphics";
3311 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3312 const char *sym_name
= fullname
;
3313 boolean badflag
= FALSE
;
3316 complain_about_duplicate(opts
, 1);
3318 for (i
= 0; i
< NUM_GRAPHICS
; ++i
) {
3319 if (symset
[i
].name
) {
3323 sym_name
= "RogueIBM";
3324 symset
[i
].name
= dupstr(sym_name
);
3325 if (!read_sym_file(i
)) {
3327 clear_symsetentry(i
, TRUE
);
3333 pline("Failure to load symbol set %s.", sym_name
);
3336 switch_symbols(TRUE
);
3337 if (!initial
&& Is_rogue_level(&u
.uz
))
3338 assign_graphics(ROGUESET
);
3344 #ifdef MAC_GRAPHICS_ENV
3345 fullname
= "MACgraphics";
3346 if (match_optname(opts
, fullname
, 3, TRUE
)) {
3347 boolean badflag
= FALSE
;
3350 complain_about_duplicate(opts
, 1);
3352 if (symset
[PRIMARY
].name
) {
3355 symset
[PRIMARY
].name
= dupstr(fullname
);
3356 if (!read_sym_file(PRIMARY
)) {
3358 clear_symsetentry(PRIMARY
, TRUE
);
3362 pline("Failure to load symbol set %s.", fullname
);
3365 switch_symbols(TRUE
);
3366 if (!initial
&& Is_rogue_level(&u
.uz
))
3367 assign_graphics(ROGUESET
);
3374 /* OK, if we still haven't recognized the option, check the boolean
3377 for (i
= 0; boolopt
[i
].name
; i
++) {
3378 if (match_optname(opts
, boolopt
[i
].name
, 3, TRUE
)) {
3379 /* options that don't exist */
3380 if (!boolopt
[i
].addr
) {
3381 if (!initial
&& !negated
)
3382 pline_The("\"%s\" option is not available.",
3386 /* options that must come from config file */
3387 if (!initial
&& (boolopt
[i
].optflags
== SET_IN_FILE
)) {
3388 rejectoption(boolopt
[i
].name
);
3392 op
= string_for_opt(opts
, TRUE
);
3399 if (!strcmp(op
, "true") || !strcmp(op
, "yes")) {
3401 } else if (!strcmp(op
, "false") || !strcmp(op
, "no")) {
3409 *(boolopt
[i
].addr
) = !negated
;
3411 /* 0 means boolean opts */
3412 if (duplicate_opt_detection(boolopt
[i
].name
, 0))
3413 complain_about_duplicate(boolopt
[i
].name
, 0);
3415 if (boolopt
[i
].addr
== &iflags
.rlecomp
)
3416 set_savepref(iflags
.rlecomp
? "rlecomp" : "!rlecomp");
3419 if (boolopt
[i
].addr
== &iflags
.zerocomp
)
3420 set_savepref(iflags
.zerocomp
? "zerocomp" : "externalcomp");
3422 /* only do processing below if setting with doset() */
3426 if (boolopt
[i
].addr
== &flags
.time
3427 #ifdef SCORE_ON_BOTL
3428 || boolopt
[i
].addr
== &flags
.showscore
3430 || boolopt
[i
].addr
== &flags
.showexp
) {
3431 #ifdef STATUS_VIA_WINDOWPORT
3432 status_initialize(REASSESS_ONLY
);
3434 context
.botl
= TRUE
;
3435 } else if (boolopt
[i
].addr
== &flags
.invlet_constant
) {
3436 if (flags
.invlet_constant
)
3438 } else if (boolopt
[i
].addr
== &flags
.lit_corridor
3439 || boolopt
[i
].addr
== &flags
.dark_room
) {
3441 * All corridor squares seen via night vision or
3442 * candles & lamps change. Update them by calling
3443 * newsym() on them. Don't do this if we are
3444 * initializing the options --- the vision system
3447 vision_recalc(2); /* shut down vision */
3448 vision_full_recalc
= 1; /* delayed recalc */
3449 if (iflags
.use_color
)
3450 need_redraw
= TRUE
; /* darkroom refresh */
3451 } else if (boolopt
[i
].addr
== &iflags
.wc_tiled_map
3452 || boolopt
[i
].addr
== &flags
.showrace
3453 || boolopt
[i
].addr
== &iflags
.use_inverse
3454 || boolopt
[i
].addr
== &iflags
.hilite_pile
3455 || boolopt
[i
].addr
== &iflags
.hilite_pet
) {
3458 } else if (boolopt
[i
].addr
== &iflags
.use_color
) {
3468 #endif /* TEXTCOLOR */
3474 /* Is it a symbol? */
3475 if (strstr(opts
, "S_") == opts
&& parsesymbols(opts
)) {
3476 switch_symbols(TRUE
);
3480 /* out of valid options */
3484 /* parse key:command */
3486 parsebindings(bindings
)
3493 /* break off first binding from the rest; parse the rest */
3494 if ((bind
= index(bindings
, ',')) != 0) {
3496 parsebindings(bind
);
3499 /* parse a single binding: first split around : */
3500 if (! (bind
= index(bindings
, ':'))) return; /* it's not a binding */
3503 /* read the key to be bound */
3504 key
= txt2key(bindings
);
3506 raw_printf("Bad binding %s.", bindings
);
3511 bind
= trimspaces(bind
);
3513 /* is it a special key? */
3514 if (bind_specialkey(key
, bind
))
3517 /* is it a menu command? */
3518 for (i
= 0; i
< SIZE(default_menu_cmd_info
); i
++) {
3519 if (!strcmp(default_menu_cmd_info
[i
].name
, bind
)) {
3520 if (illegal_menu_cmd_key(key
)) {
3522 Sprintf(tmp
, "Bad menu key %s:%s", visctrl(key
), bind
);
3525 add_menu_cmd_alias(key
, default_menu_cmd_info
[i
].cmd
);
3530 /* extended command? */
3531 bind_key(key
, bind
);
3534 static NEARDATA
const char *menutype
[] = { "traditional", "combination",
3535 "full", "partial" };
3537 static NEARDATA
const char *burdentype
[] = { "unencumbered", "burdened",
3538 "stressed", "strained",
3539 "overtaxed", "overloaded" };
3541 static NEARDATA
const char *runmodes
[] = { "teleport", "run", "walk",
3544 static NEARDATA
const char *sortltype
[] = { "none", "loot", "full" };
3547 * Convert the given string of object classes to a string of default object
3551 oc_to_str(src
, dest
)
3556 while ((i
= (int) *src
++) != 0) {
3557 if (i
< 0 || i
>= MAXOCLASSES
)
3558 impossible("oc_to_str: illegal object class %d", i
);
3560 *dest
++ = def_oc_syms
[i
].sym
;
3566 * Add the given mapping to the menu command map list. Always keep the
3567 * maps valid C strings.
3570 add_menu_cmd_alias(from_ch
, to_ch
)
3571 char from_ch
, to_ch
;
3573 if (n_menu_mapped
>= MAX_MENU_MAPPED_CMDS
) {
3574 pline("out of menu map space.");
3576 mapped_menu_cmds
[n_menu_mapped
] = from_ch
;
3577 mapped_menu_op
[n_menu_mapped
] = to_ch
;
3579 mapped_menu_cmds
[n_menu_mapped
] = 0;
3580 mapped_menu_op
[n_menu_mapped
] = 0;
3585 get_menu_cmd_key(ch
)
3588 char *found
= index(mapped_menu_op
, ch
);
3590 int idx
= (int) (found
- mapped_menu_op
);
3591 ch
= mapped_menu_cmds
[idx
];
3597 * Map the given character to its corresponding menu command. If it
3598 * doesn't match anything, just return the original.
3604 char *found
= index(mapped_menu_cmds
, ch
);
3606 int idx
= (int) (found
- mapped_menu_cmds
);
3607 ch
= mapped_menu_op
[idx
];
3613 show_menu_controls(win
, dolist
)
3619 putstr(win
, 0, "Menu control keys:");
3622 for (i
= 0; i
< SIZE(default_menu_cmd_info
); i
++) {
3623 Sprintf(buf
, "%-8s %s",
3624 visctrl(get_menu_cmd_key(default_menu_cmd_info
[i
].cmd
)),
3625 default_menu_cmd_info
[i
].desc
);
3626 putstr(win
, 0, buf
);
3630 putstr(win
, 0, " Page All items");
3631 Sprintf(buf
, " Select %s %s",
3632 visctrl(get_menu_cmd_key(MENU_SELECT_PAGE
)),
3633 visctrl(get_menu_cmd_key(MENU_SELECT_ALL
)));
3634 putstr(win
, 0, buf
);
3635 Sprintf(buf
, "Deselect %s %s",
3636 visctrl(get_menu_cmd_key(MENU_UNSELECT_PAGE
)),
3637 visctrl(get_menu_cmd_key(MENU_UNSELECT_ALL
)));
3638 putstr(win
, 0, buf
);
3639 Sprintf(buf
, " Invert %s %s",
3640 visctrl(get_menu_cmd_key(MENU_INVERT_PAGE
)),
3641 visctrl(get_menu_cmd_key(MENU_INVERT_ALL
)));
3642 putstr(win
, 0, buf
);
3644 Sprintf(buf
, " Go to %s Next page",
3645 visctrl(get_menu_cmd_key(MENU_NEXT_PAGE
)));
3646 putstr(win
, 0, buf
);
3647 Sprintf(buf
, " %s Previous page",
3648 visctrl(get_menu_cmd_key(MENU_PREVIOUS_PAGE
)));
3649 putstr(win
, 0, buf
);
3650 Sprintf(buf
, " %s First page",
3651 visctrl(get_menu_cmd_key(MENU_FIRST_PAGE
)));
3652 putstr(win
, 0, buf
);
3653 Sprintf(buf
, " %s Last page",
3654 visctrl(get_menu_cmd_key(MENU_LAST_PAGE
)));
3655 putstr(win
, 0, buf
);
3657 Sprintf(buf
, " %s Search and toggle matching entries",
3658 visctrl(get_menu_cmd_key(MENU_SEARCH
)));
3659 putstr(win
, 0, buf
);
3663 #if defined(MICRO) || defined(MAC) || defined(WIN32)
3664 #define OPTIONS_HEADING "OPTIONS"
3666 #define OPTIONS_HEADING "NETHACKOPTIONS"
3669 static char fmtstr_doset
[] = "%s%-15s [%s] ";
3670 static char fmtstr_doset_tab
[] = "%s\t[%s]";
3671 static char n_currently_set
[] = "(%d currently set)";
3673 /* doset('O' command) menu entries for compound options */
3675 doset_add_menu(win
, option
, indexoffset
)
3676 winid win
; /* window to add to */
3677 const char *option
; /* option name */
3678 int indexoffset
; /* value to add to index in compopt[], or zero
3679 if option cannot be changed */
3681 const char *value
= "unknown"; /* current value */
3682 char buf
[BUFSZ
], buf2
[BUFSZ
];
3687 if (indexoffset
== 0) {
3689 value
= get_compopt_value(option
, buf2
);
3691 for (i
= 0; compopt
[i
].name
; i
++)
3692 if (strcmp(option
, compopt
[i
].name
) == 0)
3695 if (compopt
[i
].name
) {
3696 any
.a_int
= i
+ 1 + indexoffset
;
3697 value
= get_compopt_value(option
, buf2
);
3699 /* We are trying to add an option not found in compopt[].
3700 This is almost certainly bad, but we'll let it through anyway
3701 (with a zero value, so it can't be selected). */
3705 /* " " replaces "a - " -- assumes menus follow that style */
3706 if (!iflags
.menu_tab_sep
)
3707 Sprintf(buf
, fmtstr_doset
, any
.a_int
? "" : " ", option
,
3710 Sprintf(buf
, fmtstr_doset_tab
, option
, value
);
3711 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
3715 opts_add_others(win
, name
, id
, bufx
, nset
)
3722 char buf
[BUFSZ
], buf2
[BUFSZ
];
3723 anything any
= zeroany
;
3727 Sprintf(buf2
, n_currently_set
, nset
);
3729 Sprintf(buf2
, "%s", bufx
);
3730 if (!iflags
.menu_tab_sep
)
3731 Sprintf(buf
, fmtstr_doset
, any
.a_int
? "" : " ",
3734 Sprintf(buf
, fmtstr_doset_tab
, name
, buf2
);
3735 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
3738 enum opt_other_enums
{
3739 OPT_OTHER_MSGTYPE
= -4,
3740 OPT_OTHER_MENUCOLOR
= -3,
3741 OPT_OTHER_STATHILITE
= -2,
3742 OPT_OTHER_APEXC
= -1
3743 /* these must be < 0 */
3746 /* presently only used when determining longest option name */
3747 static struct other_opts
{
3750 enum opt_other_enums code
;
3752 { "autopickup exceptions", SET_IN_GAME
, OPT_OTHER_APEXC
},
3753 { "menucolors", SET_IN_GAME
, OPT_OTHER_MENUCOLOR
},
3754 { "message types", SET_IN_GAME
, OPT_OTHER_MSGTYPE
},
3755 #ifdef STATUS_VIA_WINDOWPORT
3756 #ifdef STATUS_HILITES
3757 { "status_hilites", SET_IN_GAME
, OPT_OTHER_STATHILITE
},
3760 { (char *) 0, 0, (enum opt_other_enums
) 0 },
3763 /* the 'O' command */
3765 doset() /* changing options via menu by Per Liboriussen */
3767 static boolean made_fmtstr
= FALSE
;
3768 char buf
[BUFSZ
], buf2
[BUFSZ
];
3770 int i
= 0, pass
, boolcount
, pick_cnt
, pick_idx
, opt_indx
;
3774 menu_item
*pick_list
;
3775 int indexoffset
, startpass
, endpass
, optflags
;
3776 boolean setinitial
= FALSE
, fromfile
= FALSE
;
3777 unsigned longest_name_len
;
3779 tmpwin
= create_nhwindow(NHW_MENU
);
3782 #ifdef notyet /* SYSCF */
3783 /* XXX I think this is still fragile. Fixing initial/from_file and/or
3784 changing the SET_* etc to bitmaps will let me make this better. */
3786 startpass
= SET_IN_SYS
;
3789 startpass
= DISP_IN_GAME
;
3790 endpass
= (wizard
) ? SET_IN_WIZGAME
: SET_IN_GAME
;
3792 if (!made_fmtstr
&& !iflags
.menu_tab_sep
) {
3793 /* spin through the options to find the longest name
3794 and adjust the format string accordingly */
3795 longest_name_len
= 0;
3796 for (pass
= 0; pass
<= 2; pass
++)
3797 for (i
= 0; (name
= ((pass
== 0)
3801 : othropt
[i
].name
)) != 0; i
++) {
3802 if (pass
== 0 && !boolopt
[i
].addr
)
3804 optflags
= (pass
== 0) ? boolopt
[i
].optflags
3806 ? compopt
[i
].optflags
3807 : othropt
[i
].optflags
;
3808 if (optflags
< startpass
|| optflags
> endpass
)
3810 if ((is_wc_option(name
) && !wc_supported(name
))
3811 || (is_wc2_option(name
) && !wc2_supported(name
)))
3814 if (strlen(name
) > longest_name_len
)
3815 longest_name_len
= strlen(name
);
3817 Sprintf(fmtstr_doset
, "%%s%%-%us [%%s]", longest_name_len
);
3822 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3823 "Booleans (selecting will toggle value):", MENU_UNSELECTED
);
3825 /* first list any other non-modifiable booleans, then modifiable ones */
3826 for (pass
= 0; pass
<= 1; pass
++)
3827 for (i
= 0; (name
= boolopt
[i
].name
) != 0; i
++)
3828 if ((bool_p
= boolopt
[i
].addr
) != 0
3829 && ((boolopt
[i
].optflags
<= DISP_IN_GAME
&& pass
== 0)
3830 || (boolopt
[i
].optflags
>= SET_IN_GAME
&& pass
== 1))) {
3831 if (bool_p
== &flags
.female
)
3832 continue; /* obsolete */
3833 if (boolopt
[i
].optflags
== SET_IN_WIZGAME
&& !wizard
)
3835 if ((is_wc_option(name
) && !wc_supported(name
))
3836 || (is_wc2_option(name
) && !wc2_supported(name
)))
3839 any
.a_int
= (pass
== 0) ? 0 : i
+ 1;
3840 if (!iflags
.menu_tab_sep
)
3841 Sprintf(buf
, fmtstr_doset
, (pass
== 0) ? " " : "",
3842 name
, *bool_p
? "true" : "false");
3844 Sprintf(buf
, fmtstr_doset_tab
,
3845 name
, *bool_p
? "true" : "false");
3846 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
,
3851 indexoffset
= boolcount
;
3853 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3854 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3855 "Compounds (selecting will prompt for new value):",
3858 /* deliberately put playmode, name, role+race+gender+align first */
3859 doset_add_menu(tmpwin
, "playmode", 0);
3860 doset_add_menu(tmpwin
, "name", 0);
3861 doset_add_menu(tmpwin
, "role", 0);
3862 doset_add_menu(tmpwin
, "race", 0);
3863 doset_add_menu(tmpwin
, "gender", 0);
3864 doset_add_menu(tmpwin
, "align", 0);
3866 for (pass
= startpass
; pass
<= endpass
; pass
++)
3867 for (i
= 0; (name
= compopt
[i
].name
) != 0; i
++)
3868 if (compopt
[i
].optflags
== pass
) {
3869 if (!strcmp(name
, "playmode") || !strcmp(name
, "name")
3870 || !strcmp(name
, "role") || !strcmp(name
, "race")
3871 || !strcmp(name
, "gender") || !strcmp(name
, "align"))
3873 if ((is_wc_option(name
) && !wc_supported(name
))
3874 || (is_wc2_option(name
) && !wc2_supported(name
)))
3877 doset_add_menu(tmpwin
, name
,
3878 (pass
== DISP_IN_GAME
) ? 0 : indexoffset
);
3882 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3883 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3887 opts_add_others(tmpwin
, "autopickup exceptions", OPT_OTHER_APEXC
,
3888 NULL
, count_ape_maps((int *) 0, (int *) 0));
3889 opts_add_others(tmpwin
, "menucolors", OPT_OTHER_MENUCOLOR
,
3890 NULL
, count_menucolors());
3891 opts_add_others(tmpwin
, "message types", OPT_OTHER_MSGTYPE
,
3892 NULL
, msgtype_count());
3893 #ifdef STATUS_VIA_WINDOWPORT
3894 #ifdef STATUS_HILITES
3895 get_status_hilites(buf2
, 60);
3897 Sprintf(buf2
, "%s", "(none)");
3898 opts_add_others(tmpwin
, "status_hilites", OPT_OTHER_STATHILITE
, buf2
, 0);
3901 #ifdef PREFIXES_IN_USE
3903 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3904 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
3905 "Variable playground locations:", MENU_UNSELECTED
);
3906 for (i
= 0; i
< PREFIX_COUNT
; i
++)
3907 doset_add_menu(tmpwin
, fqn_prefix_names
[i
], 0);
3909 end_menu(tmpwin
, "Set what options?");
3910 need_redraw
= FALSE
;
3911 if ((pick_cnt
= select_menu(tmpwin
, PICK_ANY
, &pick_list
)) > 0) {
3913 * Walk down the selection list and either invert the booleans
3914 * or prompt for new values. In most cases, call parseoptions()
3915 * to take care of options that require special attention, like
3918 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
) {
3919 opt_indx
= pick_list
[pick_idx
].item
.a_int
- 1;
3920 if (opt_indx
< -1) opt_indx
++; /* -1 offset for select_menu() */
3921 if (opt_indx
== OPT_OTHER_APEXC
) {
3922 (void) special_handling("autopickup_exception", setinitial
,
3924 #ifdef STATUS_VIA_WINDOWPORT
3925 #ifdef STATUS_HILITES
3926 } else if (opt_indx
== OPT_OTHER_STATHILITE
) {
3927 if (!status_hilite_menu()) {
3928 pline("Bad status hilite(s) specified.");
3930 if (wc2_supported("status_hilites"))
3931 preference_update("status_hilites");
3935 } else if (opt_indx
== OPT_OTHER_MENUCOLOR
) {
3936 (void) special_handling("menucolors", setinitial
,
3938 } else if (opt_indx
== OPT_OTHER_MSGTYPE
) {
3939 (void) special_handling("msgtype", setinitial
, fromfile
);
3940 } else if (opt_indx
< boolcount
) {
3941 /* boolean option */
3942 Sprintf(buf
, "%s%s", *boolopt
[opt_indx
].addr
? "!" : "",
3943 boolopt
[opt_indx
].name
);
3944 parseoptions(buf
, setinitial
, fromfile
);
3945 if (wc_supported(boolopt
[opt_indx
].name
)
3946 || wc2_supported(boolopt
[opt_indx
].name
))
3947 preference_update(boolopt
[opt_indx
].name
);
3949 /* compound option */
3950 opt_indx
-= boolcount
;
3952 if (!special_handling(compopt
[opt_indx
].name
, setinitial
,
3954 Sprintf(buf
, "Set %s to what?", compopt
[opt_indx
].name
);
3956 if (buf2
[0] == '\033')
3958 Sprintf(buf
, "%s:%s", compopt
[opt_indx
].name
, buf2
);
3960 parseoptions(buf
, setinitial
, fromfile
);
3962 if (wc_supported(compopt
[opt_indx
].name
)
3963 || wc2_supported(compopt
[opt_indx
].name
))
3964 preference_update(compopt
[opt_indx
].name
);
3967 free((genericptr_t
) pick_list
);
3968 pick_list
= (menu_item
*) 0;
3971 destroy_nhwindow(tmpwin
);
3980 handle_add_list_remove(optname
, numtotal
)
3981 const char *optname
;
3986 int i
, pick_cnt
, opt_idx
;
3987 menu_item
*pick_list
= (menu_item
*) 0;
3988 static const struct action
{
3991 } action_titles
[] = {
3992 { 'a', "add new %s" }, /* [0] */
3993 { 'l', "list %s" }, /* [1] */
3994 { 'r', "remove existing %s" }, /* [2] */
3995 { 'x', "exit this menu" }, /* [3] */
3999 tmpwin
= create_nhwindow(NHW_MENU
);
4002 for (i
= 0; i
< SIZE(action_titles
); i
++) {
4006 /* omit list and remove if there aren't any yet */
4007 if (!numtotal
&& (i
== 1 || i
== 2))
4009 Sprintf(tmpbuf
, action_titles
[i
].desc
,
4010 (i
== 1) ? makeplural(optname
) : optname
);
4011 add_menu(tmpwin
, NO_GLYPH
, &any
, action_titles
[i
].letr
, 0, ATR_NONE
,
4012 tmpbuf
, (i
== 3) ? MENU_SELECTED
: MENU_UNSELECTED
);
4014 end_menu(tmpwin
, "Do what?");
4015 if ((pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &pick_list
)) > 0) {
4016 opt_idx
= pick_list
[0].item
.a_int
- 1;
4017 if (pick_cnt
> 1 && opt_idx
== 3)
4018 opt_idx
= pick_list
[1].item
.a_int
- 1;
4019 free((genericptr_t
) pick_list
);
4021 opt_idx
= 3; /* none selected, exit menu */
4022 destroy_nhwindow(tmpwin
);
4026 struct symsetentry
*symset_list
= 0; /* files.c will populate this with
4027 list of available sets */
4030 special_handling(optname
, setinitial
, setfromfile
)
4031 const char *optname
;
4032 boolean setinitial
, setfromfile
;
4039 /* Special handling of menustyle, pickup_burden, pickup_types,
4040 * disclose, runmode, msg_window, menu_headings, sortloot,
4041 * and number_pad options.
4042 * Also takes care of interactive autopickup_exception_handling changes.
4044 if (!strcmp("menustyle", optname
)) {
4045 const char *style_name
;
4046 menu_item
*style_pick
= (menu_item
*) 0;
4047 tmpwin
= create_nhwindow(NHW_MENU
);
4050 for (i
= 0; i
< SIZE(menutype
); i
++) {
4051 style_name
= menutype
[i
];
4052 /* note: separate `style_name' variable used
4053 to avoid an optimizer bug in VAX C V2.3 */
4055 add_menu(tmpwin
, NO_GLYPH
, &any
, *style_name
, 0, ATR_NONE
,
4056 style_name
, MENU_UNSELECTED
);
4058 end_menu(tmpwin
, "Select menustyle:");
4059 if (select_menu(tmpwin
, PICK_ONE
, &style_pick
) > 0) {
4060 flags
.menu_style
= style_pick
->item
.a_int
- 1;
4061 free((genericptr_t
) style_pick
);
4063 destroy_nhwindow(tmpwin
);
4064 } else if (!strcmp("paranoid_confirmation", optname
)) {
4065 menu_item
*paranoia_picks
= (menu_item
*) 0;
4067 tmpwin
= create_nhwindow(NHW_MENU
);
4070 for (i
= 0; paranoia
[i
].flagmask
!= 0; ++i
) {
4071 if (paranoia
[i
].flagmask
== PARANOID_BONES
&& !wizard
)
4073 any
.a_int
= paranoia
[i
].flagmask
;
4074 add_menu(tmpwin
, NO_GLYPH
, &any
, *paranoia
[i
].argname
, 0,
4075 ATR_NONE
, paranoia
[i
].explain
,
4076 (flags
.paranoia_bits
& paranoia
[i
].flagmask
)
4080 end_menu(tmpwin
, "Actions requiring extra confirmation:");
4081 i
= select_menu(tmpwin
, PICK_ANY
, ¶noia_picks
);
4083 /* player didn't cancel; we reset all the paranoia options
4084 here even if there were no items picked, since user
4085 could have toggled off preselected ones to end up with 0 */
4086 flags
.paranoia_bits
= 0;
4088 /* at least 1 item set, either preselected or newly picked */
4090 flags
.paranoia_bits
|= paranoia_picks
[i
].item
.a_int
;
4091 free((genericptr_t
) paranoia_picks
);
4094 destroy_nhwindow(tmpwin
);
4095 } else if (!strcmp("pickup_burden", optname
)) {
4096 const char *burden_name
, *burden_letters
= "ubsntl";
4097 menu_item
*burden_pick
= (menu_item
*) 0;
4099 tmpwin
= create_nhwindow(NHW_MENU
);
4102 for (i
= 0; i
< SIZE(burdentype
); i
++) {
4103 burden_name
= burdentype
[i
];
4105 add_menu(tmpwin
, NO_GLYPH
, &any
, burden_letters
[i
], 0, ATR_NONE
,
4106 burden_name
, MENU_UNSELECTED
);
4108 end_menu(tmpwin
, "Select encumbrance level:");
4109 if (select_menu(tmpwin
, PICK_ONE
, &burden_pick
) > 0) {
4110 flags
.pickup_burden
= burden_pick
->item
.a_int
- 1;
4111 free((genericptr_t
) burden_pick
);
4113 destroy_nhwindow(tmpwin
);
4114 } else if (!strcmp("pickup_types", optname
)) {
4115 /* parseoptions will prompt for the list of types */
4116 parseoptions(strcpy(buf
, "pickup_types"), setinitial
, setfromfile
);
4117 } else if (!strcmp("disclose", optname
)) {
4118 /* order of disclose_names[] must correspond to
4119 disclosure_options in decl.c */
4120 static const char *disclosure_names
[] = {
4121 "inventory", "attributes", "vanquished",
4122 "genocides", "conduct", "overview",
4124 int disc_cat
[NUM_DISCLOSURE_OPTIONS
];
4125 int pick_cnt
, pick_idx
, opt_idx
;
4127 menu_item
*disclosure_pick
= (menu_item
*) 0;
4129 tmpwin
= create_nhwindow(NHW_MENU
);
4132 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4133 Sprintf(buf
, "%-12s[%c%c]", disclosure_names
[i
],
4134 flags
.end_disclose
[i
], disclosure_options
[i
]);
4136 add_menu(tmpwin
, NO_GLYPH
, &any
, disclosure_options
[i
], 0,
4137 ATR_NONE
, buf
, MENU_UNSELECTED
);
4140 end_menu(tmpwin
, "Change which disclosure options categories:");
4141 pick_cnt
= select_menu(tmpwin
, PICK_ANY
, &disclosure_pick
);
4143 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
) {
4144 opt_idx
= disclosure_pick
[pick_idx
].item
.a_int
- 1;
4145 disc_cat
[opt_idx
] = 1;
4147 free((genericptr_t
) disclosure_pick
);
4148 disclosure_pick
= (menu_item
*) 0;
4150 destroy_nhwindow(tmpwin
);
4152 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4154 c
= flags
.end_disclose
[i
];
4155 Sprintf(buf
, "Disclosure options for %s:",
4156 disclosure_names
[i
]);
4157 tmpwin
= create_nhwindow(NHW_MENU
);
4160 /* 'y','n',and '+' work as alternate selectors; '-' doesn't */
4161 any
.a_char
= DISCLOSE_NO_WITHOUT_PROMPT
;
4162 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4163 "Never disclose, without prompting",
4164 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4165 any
.a_char
= DISCLOSE_YES_WITHOUT_PROMPT
;
4166 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4167 "Always disclose, without prompting",
4168 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4169 if (*disclosure_names
[i
] == 'v') {
4170 any
.a_char
= DISCLOSE_SPECIAL_WITHOUT_PROMPT
; /* '#' */
4171 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4172 "Always disclose, pick sort order from menu",
4173 (c
== any
.a_char
) ? MENU_SELECTED
4176 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_NO
;
4177 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4178 "Prompt, with default answer of \"No\"",
4179 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4180 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_YES
;
4181 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4182 "Prompt, with default answer of \"Yes\"",
4183 (c
== any
.a_char
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4184 if (*disclosure_names
[i
] == 'v') {
4185 any
.a_char
= DISCLOSE_PROMPT_DEFAULT_SPECIAL
; /* '?' */
4186 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, any
.a_char
, ATR_NONE
,
4187 "Prompt, with default answer of \"Ask\" to request sort menu",
4188 (c
== any
.a_char
) ? MENU_SELECTED
4191 end_menu(tmpwin
, buf
);
4192 n
= select_menu(tmpwin
, PICK_ONE
, &disclosure_pick
);
4194 flags
.end_disclose
[i
] = disclosure_pick
[0].item
.a_char
;
4195 if (n
> 1 && flags
.end_disclose
[i
] == c
)
4196 flags
.end_disclose
[i
] = disclosure_pick
[1].item
.a_char
;
4197 free((genericptr_t
) disclosure_pick
);
4199 destroy_nhwindow(tmpwin
);
4202 } else if (!strcmp("runmode", optname
)) {
4203 const char *mode_name
;
4204 menu_item
*mode_pick
= (menu_item
*) 0;
4206 tmpwin
= create_nhwindow(NHW_MENU
);
4209 for (i
= 0; i
< SIZE(runmodes
); i
++) {
4210 mode_name
= runmodes
[i
];
4212 add_menu(tmpwin
, NO_GLYPH
, &any
, *mode_name
, 0, ATR_NONE
,
4213 mode_name
, MENU_UNSELECTED
);
4215 end_menu(tmpwin
, "Select run/travel display mode:");
4216 if (select_menu(tmpwin
, PICK_ONE
, &mode_pick
) > 0) {
4217 flags
.runmode
= mode_pick
->item
.a_int
- 1;
4218 free((genericptr_t
) mode_pick
);
4220 destroy_nhwindow(tmpwin
);
4221 } else if (!strcmp("whatis_coord", optname
)) {
4222 menu_item
*window_pick
= (menu_item
*) 0;
4224 char gp
= iflags
.getpos_coords
;
4226 tmpwin
= create_nhwindow(NHW_MENU
);
4229 any
.a_char
= GPCOORDS_COMPASS
;
4230 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_COMPASS
,
4231 0, ATR_NONE
, "compass ('east' or '3s' or '2n,4w')",
4232 (gp
== GPCOORDS_COMPASS
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4233 any
.a_char
= GPCOORDS_COMFULL
;
4234 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_COMFULL
,
4235 0, ATR_NONE
, "full compass ('east' or '3south' or '2north,4west')",
4236 (gp
== GPCOORDS_COMFULL
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4237 any
.a_char
= GPCOORDS_MAP
;
4238 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_MAP
,
4239 0, ATR_NONE
, "map <x,y>",
4240 (gp
== GPCOORDS_MAP
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4241 any
.a_char
= GPCOORDS_SCREEN
;
4242 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_SCREEN
,
4243 0, ATR_NONE
, "screen [row,column]",
4244 (gp
== GPCOORDS_SCREEN
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4245 any
.a_char
= GPCOORDS_NONE
;
4246 add_menu(tmpwin
, NO_GLYPH
, &any
, GPCOORDS_NONE
,
4247 0, ATR_NONE
, "none (no coordinates displayed)",
4248 (gp
== GPCOORDS_NONE
) ? MENU_SELECTED
: MENU_UNSELECTED
);
4250 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
4251 Sprintf(buf
, "map: upper-left: <%d,%d>, lower-right: <%d,%d>%s",
4252 1, 0, COLNO
- 1, ROWNO
- 1,
4253 flags
.verbose
? "; column 0 unused, off left edge" : "");
4254 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
4255 if (strcmp(windowprocs
.name
, "tty"))
4256 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
4257 "screen: row is offset to accommodate tty interface's use of top line",
4260 #define COL80ARG flags.verbose ? "; column 80 is not used" : ""
4264 Sprintf(buf
, "screen: upper-left: [%02d,%02d], lower-right: [%d,%d]%s",
4265 0 + 2, 1, ROWNO
- 1 + 2, COLNO
- 1, COL80ARG
);
4267 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, MENU_UNSELECTED
);
4268 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
4270 "Select coordinate display when auto-describing a map position:");
4271 if ((pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &window_pick
)) > 0) {
4272 iflags
.getpos_coords
= window_pick
[0].item
.a_char
;
4273 /* PICK_ONE doesn't unselect preselected entry when
4274 selecting another one */
4275 if (pick_cnt
> 1 && iflags
.getpos_coords
== gp
)
4276 iflags
.getpos_coords
= window_pick
[1].item
.a_char
;
4277 free((genericptr_t
) window_pick
);
4279 destroy_nhwindow(tmpwin
);
4280 } else if (!strcmp("msg_window", optname
)) {
4282 /* by Christian W. Cooper */
4283 menu_item
*window_pick
= (menu_item
*) 0;
4285 tmpwin
= create_nhwindow(NHW_MENU
);
4289 add_menu(tmpwin
, NO_GLYPH
, &any
, 's', 0, ATR_NONE
, "single",
4292 add_menu(tmpwin
, NO_GLYPH
, &any
, 'c', 0, ATR_NONE
, "combination",
4295 add_menu(tmpwin
, NO_GLYPH
, &any
, 'f', 0, ATR_NONE
, "full",
4298 add_menu(tmpwin
, NO_GLYPH
, &any
, 'r', 0, ATR_NONE
, "reversed",
4300 end_menu(tmpwin
, "Select message history display type:");
4301 if (select_menu(tmpwin
, PICK_ONE
, &window_pick
) > 0) {
4302 iflags
.prevmsg_window
= window_pick
->item
.a_char
;
4303 free((genericptr_t
) window_pick
);
4305 destroy_nhwindow(tmpwin
);
4307 } else if (!strcmp("sortloot", optname
)) {
4308 const char *sortl_name
;
4309 menu_item
*sortl_pick
= (menu_item
*) 0;
4311 tmpwin
= create_nhwindow(NHW_MENU
);
4314 for (i
= 0; i
< SIZE(sortltype
); i
++) {
4315 sortl_name
= sortltype
[i
];
4316 any
.a_char
= *sortl_name
;
4317 add_menu(tmpwin
, NO_GLYPH
, &any
, *sortl_name
, 0, ATR_NONE
,
4318 sortl_name
, (flags
.sortloot
== *sortl_name
)
4319 ? MENU_SELECTED
: MENU_UNSELECTED
);
4321 end_menu(tmpwin
, "Select loot sorting type:");
4322 n
= select_menu(tmpwin
, PICK_ONE
, &sortl_pick
);
4324 char c
= sortl_pick
[0].item
.a_char
;
4326 if (n
> 1 && c
== flags
.sortloot
)
4327 c
= sortl_pick
[1].item
.a_char
;
4329 free((genericptr_t
) sortl_pick
);
4331 destroy_nhwindow(tmpwin
);
4332 } else if (!strcmp("align_message", optname
)
4333 || !strcmp("align_status", optname
)) {
4334 menu_item
*window_pick
= (menu_item
*) 0;
4336 boolean msg
= (*(optname
+ 6) == 'm');
4338 tmpwin
= create_nhwindow(NHW_MENU
);
4341 any
.a_int
= ALIGN_TOP
;
4342 add_menu(tmpwin
, NO_GLYPH
, &any
, 't', 0, ATR_NONE
, "top",
4344 any
.a_int
= ALIGN_BOTTOM
;
4345 add_menu(tmpwin
, NO_GLYPH
, &any
, 'b', 0, ATR_NONE
, "bottom",
4347 any
.a_int
= ALIGN_LEFT
;
4348 add_menu(tmpwin
, NO_GLYPH
, &any
, 'l', 0, ATR_NONE
, "left",
4350 any
.a_int
= ALIGN_RIGHT
;
4351 add_menu(tmpwin
, NO_GLYPH
, &any
, 'r', 0, ATR_NONE
, "right",
4353 Sprintf(abuf
, "Select %s window placement relative to the map:",
4354 msg
? "message" : "status");
4355 end_menu(tmpwin
, abuf
);
4356 if (select_menu(tmpwin
, PICK_ONE
, &window_pick
) > 0) {
4358 iflags
.wc_align_message
= window_pick
->item
.a_int
;
4360 iflags
.wc_align_status
= window_pick
->item
.a_int
;
4361 free((genericptr_t
) window_pick
);
4363 destroy_nhwindow(tmpwin
);
4364 } else if (!strcmp("number_pad", optname
)) {
4365 static const char *npchoices
[] = {
4366 " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)",
4367 " 3 (on, phone-style digit layout)",
4368 " 4 (on, phone-style layout, MSDOS compatible)",
4369 "-1 (off, 'z' to move upper-left, 'y' to zap wands)"
4371 menu_item
*mode_pick
= (menu_item
*) 0;
4373 tmpwin
= create_nhwindow(NHW_MENU
);
4376 for (i
= 0; i
< SIZE(npchoices
); i
++) {
4378 add_menu(tmpwin
, NO_GLYPH
, &any
, 'a' + i
, 0, ATR_NONE
,
4379 npchoices
[i
], MENU_UNSELECTED
);
4381 end_menu(tmpwin
, "Select number_pad mode:");
4382 if (select_menu(tmpwin
, PICK_ONE
, &mode_pick
) > 0) {
4383 switch (mode_pick
->item
.a_int
- 1) {
4385 iflags
.num_pad
= FALSE
;
4386 iflags
.num_pad_mode
= 0;
4389 iflags
.num_pad
= TRUE
;
4390 iflags
.num_pad_mode
= 0;
4393 iflags
.num_pad
= TRUE
;
4394 iflags
.num_pad_mode
= 1;
4397 iflags
.num_pad
= TRUE
;
4398 iflags
.num_pad_mode
= 2;
4401 iflags
.num_pad
= TRUE
;
4402 iflags
.num_pad_mode
= 3;
4404 /* last menu choice: number_pad == -1 */
4406 iflags
.num_pad
= FALSE
;
4407 iflags
.num_pad_mode
= 1;
4410 reset_commands(FALSE
);
4411 number_pad(iflags
.num_pad
? 1 : 0);
4412 free((genericptr_t
) mode_pick
);
4414 destroy_nhwindow(tmpwin
);
4415 } else if (!strcmp("menu_headings", optname
)) {
4416 int mhattr
= query_attr("How to highlight menu headings:");
4419 iflags
.menu_headings
= mhattr
;
4420 } else if (!strcmp("msgtype", optname
)) {
4421 int opt_idx
, nmt
, mttyp
;
4425 nmt
= msgtype_count();
4426 opt_idx
= handle_add_list_remove("message type", nmt
);
4427 if (opt_idx
== 3) { /* done */
4429 } else if (opt_idx
== 0) { /* add new */
4430 getlin("What new message pattern?", mtbuf
);
4431 if (*mtbuf
== '\033')
4434 && (mttyp
= query_msgtype()) != -1
4435 && !msgtype_add(mttyp
, mtbuf
)) {
4436 pline("Error adding the message type.");
4439 goto msgtypes_again
;
4440 } else { /* list (1) or remove (2) */
4441 int pick_idx
, pick_cnt
;
4445 menu_item
*pick_list
= (menu_item
*) 0;
4446 struct plinemsg_type
*tmp
= plinemsg_types
;
4448 tmpwin
= create_nhwindow(NHW_MENU
);
4453 mtype
= msgtype2name(tmp
->msgtype
);
4454 any
.a_int
= ++mt_idx
;
4455 Sprintf(mtbuf
, "%-5s \"", mtype
);
4456 ln
= sizeof mtbuf
- strlen(mtbuf
) - sizeof "\"";
4457 if (strlen(tmp
->pattern
) > ln
)
4458 Strcat(strncat(mtbuf
, tmp
->pattern
, ln
- 3), "...\"");
4460 Strcat(mtbuf
, "\"");
4461 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, mtbuf
,
4465 Sprintf(mtbuf
, "%s message types",
4466 (opt_idx
== 1) ? "List of" : "Remove which");
4467 end_menu(tmpwin
, mtbuf
);
4468 pick_cnt
= select_menu(tmpwin
,
4469 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4472 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4473 free_one_msgtype(pick_list
[pick_idx
].item
.a_int
- 1
4475 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4477 destroy_nhwindow(tmpwin
);
4479 goto msgtypes_again
;
4481 } else if (!strcmp("menucolors", optname
)) {
4482 int opt_idx
, nmc
, mcclr
, mcattr
;
4486 nmc
= count_menucolors();
4487 opt_idx
= handle_add_list_remove("menucolor", nmc
);
4488 if (opt_idx
== 3) { /* done */
4490 } else if (opt_idx
== 0) { /* add new */
4491 getlin("What new menucolor pattern?", mcbuf
);
4492 if (*mcbuf
== '\033')
4495 && (mcclr
= query_color()) != -1
4496 && (mcattr
= query_attr((char *) 0)) != -1
4497 && !add_menu_coloring_parsed(mcbuf
, mcclr
, mcattr
)) {
4498 pline("Error adding the menu color.");
4501 goto menucolors_again
;
4502 } else { /* list (1) or remove (2) */
4503 int pick_idx
, pick_cnt
;
4506 const char *sattr
, *sclr
;
4507 menu_item
*pick_list
= (menu_item
*) 0;
4508 struct menucoloring
*tmp
= menu_colorings
;
4510 tmpwin
= create_nhwindow(NHW_MENU
);
4515 sattr
= attr2attrname(tmp
->attr
);
4516 sclr
= clr2colorname(tmp
->color
);
4517 any
.a_int
= ++mc_idx
;
4518 /* construct suffix */
4519 Sprintf(buf
, "\"\"=%s%s%s", sclr
,
4520 (tmp
->attr
!= ATR_NONE
) ? " & " : "",
4521 (tmp
->attr
!= ATR_NONE
) ? sattr
: "");
4522 /* now main string */
4523 ln
= sizeof buf
- strlen(buf
) - 1; /* length available */
4524 Strcpy(mcbuf
, "\"");
4525 if (strlen(tmp
->origstr
) > ln
)
4526 Strcat(strncat(mcbuf
, tmp
->origstr
, ln
- 3), "...");
4528 Strcat(mcbuf
, tmp
->origstr
);
4529 /* combine main string and suffix */
4530 Strcat(mcbuf
, &buf
[1]); /* skip buf[]'s initial quote */
4531 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, mcbuf
,
4535 Sprintf(mcbuf
, "%s menu colors",
4536 (opt_idx
== 1) ? "List of" : "Remove which");
4537 end_menu(tmpwin
, mcbuf
);
4538 pick_cnt
= select_menu(tmpwin
,
4539 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4542 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4543 free_one_menu_coloring(pick_list
[pick_idx
].item
.a_int
- 1
4545 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4547 destroy_nhwindow(tmpwin
);
4549 goto menucolors_again
;
4551 } else if (!strcmp("autopickup_exception", optname
)) {
4552 int opt_idx
, pass
, totalapes
= 0, numapes
[2] = { 0, 0 };
4553 char apebuf
[1 + BUFSZ
]; /* so &apebuf[1] is BUFSZ long for getlin() */
4554 struct autopickup_exception
*ape
;
4557 totalapes
= count_ape_maps(&numapes
[AP_LEAVE
], &numapes
[AP_GRAB
]);
4558 opt_idx
= handle_add_list_remove("autopickup exception", totalapes
);
4559 if (opt_idx
== 3) { /* done */
4561 } else if (opt_idx
== 0) { /* add new */
4562 getlin("What new autopickup exception pattern?", &apebuf
[1]);
4563 mungspaces(&apebuf
[1]); /* regularize whitespace */
4564 if (apebuf
[1] == '\033')
4568 /* guarantee room for \" prefix and \"\0 suffix;
4569 -2 is good enough for apebuf[] but -3 makes
4570 sure the whole thing fits within normal BUFSZ */
4571 apebuf
[sizeof apebuf
- 3] = '\0';
4572 Strcat(apebuf
, "\"");
4573 add_autopickup_exception(apebuf
);
4576 } else { /* list (1) or remove (2) */
4577 int pick_idx
, pick_cnt
;
4578 menu_item
*pick_list
= (menu_item
*) 0;
4580 tmpwin
= create_nhwindow(NHW_MENU
);
4582 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
4583 if (numapes
[pass
] == 0)
4585 ape
= iflags
.autopickup_exceptions
[pass
];
4587 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
4588 (pass
== 0) ? "Never pickup" : "Always pickup",
4590 for (i
= 0; i
< numapes
[pass
] && ape
; i
++) {
4591 any
.a_void
= (opt_idx
== 1) ? 0 : ape
;
4592 /* length of pattern plus quotes is less than BUFSZ */
4593 Sprintf(apebuf
, "\"%s\"", ape
->pattern
);
4594 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, apebuf
,
4599 Sprintf(apebuf
, "%s autopickup exceptions",
4600 (opt_idx
== 1) ? "List of" : "Remove which");
4601 end_menu(tmpwin
, apebuf
);
4602 pick_cnt
= select_menu(tmpwin
,
4603 (opt_idx
== 1) ? PICK_NONE
: PICK_ANY
,
4606 for (pick_idx
= 0; pick_idx
< pick_cnt
; ++pick_idx
)
4607 remove_autopickup_exception(
4608 (struct autopickup_exception
*)
4609 pick_list
[pick_idx
].item
.a_void
);
4610 free((genericptr_t
) pick_list
), pick_list
= (menu_item
*) 0;
4612 destroy_nhwindow(tmpwin
);
4616 } else if (!strcmp("symset", optname
)
4617 || !strcmp("roguesymset", optname
)) {
4618 menu_item
*symset_pick
= (menu_item
*) 0;
4619 boolean primaryflag
= (*optname
== 's'),
4620 rogueflag
= (*optname
== 'r'),
4621 ready_to_switch
= FALSE
,
4622 nothing_to_do
= FALSE
;
4623 char *symset_name
, fmtstr
[20];
4624 struct symsetentry
*sl
;
4625 int res
, which_set
, setcount
= 0, chosen
= -2;
4628 which_set
= ROGUESET
;
4630 which_set
= PRIMARY
;
4632 /* clear symset[].name as a flag to read_sym_file() to build list */
4633 symset_name
= symset
[which_set
].name
;
4634 symset
[which_set
].name
= (char *) 0;
4635 symset_list
= (struct symsetentry
*) 0;
4637 res
= read_sym_file(which_set
);
4638 if (res
&& symset_list
) {
4639 char symsetchoice
[BUFSZ
];
4640 int let
= 'a', biggest
= 0, thissize
= 0;
4644 /* check restrictions */
4645 if ((!rogueflag
&& sl
->rogue
)
4646 || (!primaryflag
&& sl
->primary
)) {
4651 /* find biggest name */
4653 thissize
= strlen(sl
->name
);
4654 if (thissize
> biggest
)
4659 pline("There are no appropriate %ssymbol sets available.",
4660 (rogueflag
) ? "rogue level "
4661 : (primaryflag
) ? "primary " : "");
4665 Sprintf(fmtstr
, "%%-%ds %%s", biggest
+ 5);
4666 tmpwin
= create_nhwindow(NHW_MENU
);
4670 add_menu(tmpwin
, NO_GLYPH
, &any
, let
++, 0, ATR_NONE
,
4671 "Default Symbols", MENU_UNSELECTED
);
4675 /* check restrictions */
4676 if ((!rogueflag
&& sl
->rogue
)
4677 || (!primaryflag
&& sl
->primary
)) {
4682 any
.a_int
= sl
->idx
+ 2;
4683 Sprintf(symsetchoice
, fmtstr
, sl
->name
,
4684 sl
->desc
? sl
->desc
: "");
4685 add_menu(tmpwin
, NO_GLYPH
, &any
, let
, 0, ATR_NONE
,
4686 symsetchoice
, MENU_UNSELECTED
);
4694 Sprintf(buf
, "Select %ssymbol set:", rogueflag
? "rogue level " : "");
4695 end_menu(tmpwin
, buf
);
4696 if (select_menu(tmpwin
, PICK_ONE
, &symset_pick
) > 0) {
4697 chosen
= symset_pick
->item
.a_int
- 2;
4698 free((genericptr_t
) symset_pick
);
4700 destroy_nhwindow(tmpwin
);
4703 /* chose an actual symset name from file */
4706 if (sl
->idx
== chosen
) {
4708 free((genericptr_t
) symset_name
);
4709 symset_name
= (char *) 0;
4711 /* free the now stale attributes */
4712 clear_symsetentry(which_set
, TRUE
);
4714 /* transfer only the name of the symbol set */
4715 symset
[which_set
].name
= dupstr(sl
->name
);
4716 ready_to_switch
= TRUE
;
4721 } else if (chosen
== -1) {
4722 /* explicit selection of defaults */
4723 /* free the now stale symset attributes */
4725 free((genericptr_t
) symset_name
);
4726 symset_name
= (char *) 0;
4728 clear_symsetentry(which_set
, TRUE
);
4730 nothing_to_do
= TRUE
;
4732 /* The symbols file could not be accessed */
4733 pline("Unable to access \"%s\" file.", SYMBOLS
);
4735 } else if (!symset_list
) {
4736 /* The symbols file was empty */
4737 pline("There were no symbol sets found in \"%s\".", SYMBOLS
);
4742 while (symset_list
) {
4745 free((genericptr_t
) sl
->name
);
4746 sl
->name
= (char *) 0;
4749 free((genericptr_t
) sl
->desc
);
4750 sl
->desc
= (char *) 0;
4752 symset_list
= sl
->next
;
4753 free((genericptr_t
) sl
);
4759 if (!symset
[which_set
].name
&& symset_name
)
4760 symset
[which_set
].name
= symset_name
; /* not dupstr() here */
4762 /* Set default symbols and clear the handling value */
4768 if (symset
[which_set
].name
) {
4769 if (read_sym_file(which_set
)) {
4770 ready_to_switch
= TRUE
;
4772 clear_symsetentry(which_set
, TRUE
);
4777 if (ready_to_switch
)
4778 switch_symbols(TRUE
);
4780 if (Is_rogue_level(&u
.uz
)) {
4782 assign_graphics(ROGUESET
);
4783 } else if (!rogueflag
)
4784 assign_graphics(PRIMARY
);
4789 /* didn't match any of the special options */
4795 #define rolestring(val, array, field) \
4796 ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none)
4798 /* This is ugly. We have all the option names in the compopt[] array,
4799 but we need to look at each option individually to get the value. */
4800 STATIC_OVL
const char *
4801 get_compopt_value(optname
, buf
)
4802 const char *optname
;
4805 char ocl
[MAXOCLASSES
+ 1];
4806 static const char none
[] = "(none)", randomrole
[] = "random",
4807 to_be_done
[] = "(to be done)", defopt
[] = "default",
4812 if (!strcmp(optname
, "align_message"))
4814 iflags
.wc_align_message
== ALIGN_TOP
4816 : iflags
.wc_align_message
== ALIGN_LEFT
4818 : iflags
.wc_align_message
== ALIGN_BOTTOM
4820 : iflags
.wc_align_message
== ALIGN_RIGHT
4823 else if (!strcmp(optname
, "align_status"))
4825 iflags
.wc_align_status
== ALIGN_TOP
4827 : iflags
.wc_align_status
== ALIGN_LEFT
4829 : iflags
.wc_align_status
== ALIGN_BOTTOM
4831 : iflags
.wc_align_status
== ALIGN_RIGHT
4834 else if (!strcmp(optname
, "align"))
4835 Sprintf(buf
, "%s", rolestring(flags
.initalign
, aligns
, adj
));
4837 else if (!strcmp(optname
, "altkeyhandler"))
4839 iflags
.altkeyhandler
[0] ? iflags
.altkeyhandler
: "default");
4841 #ifdef BACKWARD_COMPAT
4842 else if (!strcmp(optname
, "boulder"))
4846 : showsyms
[(int) objects
[BOULDER
].oc_class
+ SYM_OFF_O
]);
4848 else if (!strcmp(optname
, "catname"))
4849 Sprintf(buf
, "%s", catname
[0] ? catname
: none
);
4850 else if (!strcmp(optname
, "disclose"))
4851 for (i
= 0; i
< NUM_DISCLOSURE_OPTIONS
; i
++) {
4853 (void) strkitten(buf
, ' ');
4854 (void) strkitten(buf
, flags
.end_disclose
[i
]);
4855 (void) strkitten(buf
, disclosure_options
[i
]);
4857 else if (!strcmp(optname
, "dogname"))
4858 Sprintf(buf
, "%s", dogname
[0] ? dogname
: none
);
4859 else if (!strcmp(optname
, "dungeon"))
4860 Sprintf(buf
, "%s", to_be_done
);
4861 else if (!strcmp(optname
, "effects"))
4862 Sprintf(buf
, "%s", to_be_done
);
4863 else if (!strcmp(optname
, "font_map"))
4864 Sprintf(buf
, "%s", iflags
.wc_font_map
? iflags
.wc_font_map
: defopt
);
4865 else if (!strcmp(optname
, "font_message"))
4867 iflags
.wc_font_message
? iflags
.wc_font_message
: defopt
);
4868 else if (!strcmp(optname
, "font_status"))
4870 iflags
.wc_font_status
? iflags
.wc_font_status
: defopt
);
4871 else if (!strcmp(optname
, "font_menu"))
4873 iflags
.wc_font_menu
? iflags
.wc_font_menu
: defopt
);
4874 else if (!strcmp(optname
, "font_text"))
4876 iflags
.wc_font_text
? iflags
.wc_font_text
: defopt
);
4877 else if (!strcmp(optname
, "font_size_map")) {
4878 if (iflags
.wc_fontsiz_map
)
4879 Sprintf(buf
, "%d", iflags
.wc_fontsiz_map
);
4881 Strcpy(buf
, defopt
);
4882 } else if (!strcmp(optname
, "font_size_message")) {
4883 if (iflags
.wc_fontsiz_message
)
4884 Sprintf(buf
, "%d", iflags
.wc_fontsiz_message
);
4886 Strcpy(buf
, defopt
);
4887 } else if (!strcmp(optname
, "font_size_status")) {
4888 if (iflags
.wc_fontsiz_status
)
4889 Sprintf(buf
, "%d", iflags
.wc_fontsiz_status
);
4891 Strcpy(buf
, defopt
);
4892 } else if (!strcmp(optname
, "font_size_menu")) {
4893 if (iflags
.wc_fontsiz_menu
)
4894 Sprintf(buf
, "%d", iflags
.wc_fontsiz_menu
);
4896 Strcpy(buf
, defopt
);
4897 } else if (!strcmp(optname
, "font_size_text")) {
4898 if (iflags
.wc_fontsiz_text
)
4899 Sprintf(buf
, "%d", iflags
.wc_fontsiz_text
);
4901 Strcpy(buf
, defopt
);
4902 } else if (!strcmp(optname
, "fruit"))
4903 Sprintf(buf
, "%s", pl_fruit
);
4904 else if (!strcmp(optname
, "gender"))
4905 Sprintf(buf
, "%s", rolestring(flags
.initgend
, genders
, adj
));
4906 else if (!strcmp(optname
, "horsename"))
4907 Sprintf(buf
, "%s", horsename
[0] ? horsename
: none
);
4908 else if (!strcmp(optname
, "map_mode"))
4910 iflags
.wc_map_mode
== MAP_MODE_TILES
4912 : iflags
.wc_map_mode
== MAP_MODE_ASCII4x6
4914 : iflags
.wc_map_mode
== MAP_MODE_ASCII6x8
4916 : iflags
.wc_map_mode
== MAP_MODE_ASCII8x8
4918 : iflags
.wc_map_mode
== MAP_MODE_ASCII16x8
4920 : iflags
.wc_map_mode
== MAP_MODE_ASCII7x12
4922 : iflags
.wc_map_mode
== MAP_MODE_ASCII8x12
4924 : iflags
.wc_map_mode
4925 == MAP_MODE_ASCII16x12
4927 : iflags
.wc_map_mode
4928 == MAP_MODE_ASCII12x16
4930 : iflags
.wc_map_mode
4931 == MAP_MODE_ASCII10x18
4933 : iflags
.wc_map_mode
4934 == MAP_MODE_ASCII_FIT_TO_SCREEN
4937 else if (!strcmp(optname
, "menustyle"))
4938 Sprintf(buf
, "%s", menutype
[(int) flags
.menu_style
]);
4939 else if (!strcmp(optname
, "menu_deselect_all"))
4940 Sprintf(buf
, "%s", to_be_done
);
4941 else if (!strcmp(optname
, "menu_deselect_page"))
4942 Sprintf(buf
, "%s", to_be_done
);
4943 else if (!strcmp(optname
, "menu_first_page"))
4944 Sprintf(buf
, "%s", to_be_done
);
4945 else if (!strcmp(optname
, "menu_invert_all"))
4946 Sprintf(buf
, "%s", to_be_done
);
4947 else if (!strcmp(optname
, "menu_headings"))
4948 Sprintf(buf
, "%s", attr2attrname(iflags
.menu_headings
));
4949 else if (!strcmp(optname
, "menu_invert_page"))
4950 Sprintf(buf
, "%s", to_be_done
);
4951 else if (!strcmp(optname
, "menu_last_page"))
4952 Sprintf(buf
, "%s", to_be_done
);
4953 else if (!strcmp(optname
, "menu_next_page"))
4954 Sprintf(buf
, "%s", to_be_done
);
4955 else if (!strcmp(optname
, "menu_previous_page"))
4956 Sprintf(buf
, "%s", to_be_done
);
4957 else if (!strcmp(optname
, "menu_search"))
4958 Sprintf(buf
, "%s", to_be_done
);
4959 else if (!strcmp(optname
, "menu_select_all"))
4960 Sprintf(buf
, "%s", to_be_done
);
4961 else if (!strcmp(optname
, "menu_select_page"))
4962 Sprintf(buf
, "%s", to_be_done
);
4963 else if (!strcmp(optname
, "monsters")) {
4964 Sprintf(buf
, "%s", to_be_done
);
4965 } else if (!strcmp(optname
, "msghistory")) {
4966 Sprintf(buf
, "%u", iflags
.msg_history
);
4968 } else if (!strcmp(optname
, "msg_window")) {
4969 Sprintf(buf
, "%s", (iflags
.prevmsg_window
== 's')
4971 : (iflags
.prevmsg_window
== 'c')
4973 : (iflags
.prevmsg_window
== 'f')
4977 } else if (!strcmp(optname
, "name")) {
4978 Sprintf(buf
, "%s", plname
);
4979 } else if (!strcmp(optname
, "number_pad")) {
4980 static const char *numpadmodes
[] = {
4981 "0=off", "1=on", "2=on, MSDOS compatible",
4982 "3=on, phone-style layout",
4983 "4=on, phone layout, MSDOS compatible",
4984 "-1=off, y & z swapped", /*[5]*/
4986 int indx
= Cmd
.num_pad
4987 ? (Cmd
.phone_layout
? (Cmd
.pcHack_compat
? 4 : 3)
4988 : (Cmd
.pcHack_compat
? 2 : 1))
4989 : Cmd
.swap_yz
? 5 : 0;
4991 Strcpy(buf
, numpadmodes
[indx
]);
4992 } else if (!strcmp(optname
, "objects")) {
4993 Sprintf(buf
, "%s", to_be_done
);
4994 } else if (!strcmp(optname
, "packorder")) {
4995 oc_to_str(flags
.inv_order
, ocl
);
4996 Sprintf(buf
, "%s", ocl
);
4998 } else if (!strcmp(optname
, "palette")) {
4999 Sprintf(buf
, "%s", get_color_string());
5001 } else if (!strcmp(optname
, "paranoid_confirmation")) {
5002 char tmpbuf
[QBUFSZ
];
5005 if (ParanoidConfirm
)
5006 Strcat(tmpbuf
, " Confirm");
5008 Strcat(tmpbuf
, " quit");
5010 Strcat(tmpbuf
, " die");
5012 Strcat(tmpbuf
, " bones");
5014 Strcat(tmpbuf
, " attack");
5016 Strcat(tmpbuf
, " pray");
5018 Strcat(tmpbuf
, " Remove");
5019 Strcpy(buf
, tmpbuf
[0] ? &tmpbuf
[1] : "none");
5020 } else if (!strcmp(optname
, "pettype")) {
5021 Sprintf(buf
, "%s", (preferred_pet
== 'c') ? "cat"
5022 : (preferred_pet
== 'd') ? "dog"
5023 : (preferred_pet
== 'h') ? "horse"
5024 : (preferred_pet
== 'n') ? "none"
5026 } else if (!strcmp(optname
, "pickup_burden")) {
5027 Sprintf(buf
, "%s", burdentype
[flags
.pickup_burden
]);
5028 } else if (!strcmp(optname
, "pickup_types")) {
5029 oc_to_str(flags
.pickup_types
, ocl
);
5030 Sprintf(buf
, "%s", ocl
[0] ? ocl
: "all");
5031 } else if (!strcmp(optname
, "pile_limit")) {
5032 Sprintf(buf
, "%d", flags
.pile_limit
);
5033 } else if (!strcmp(optname
, "playmode")) {
5034 Strcpy(buf
, wizard
? "debug" : discover
? "explore" : "normal");
5035 } else if (!strcmp(optname
, "race")) {
5036 Sprintf(buf
, "%s", rolestring(flags
.initrace
, races
, noun
));
5037 } else if (!strcmp(optname
, "roguesymset")) {
5039 symset
[ROGUESET
].name
? symset
[ROGUESET
].name
: "default");
5040 if (currentgraphics
== ROGUESET
&& symset
[ROGUESET
].name
)
5041 Strcat(buf
, ", active");
5042 } else if (!strcmp(optname
, "role")) {
5043 Sprintf(buf
, "%s", rolestring(flags
.initrole
, roles
, name
.m
));
5044 } else if (!strcmp(optname
, "runmode")) {
5045 Sprintf(buf
, "%s", runmodes
[flags
.runmode
]);
5046 } else if (!strcmp(optname
, "whatis_coord")) {
5048 (iflags
.getpos_coords
== GPCOORDS_MAP
) ? "map"
5049 : (iflags
.getpos_coords
== GPCOORDS_COMPASS
) ? "compass"
5050 : (iflags
.getpos_coords
== GPCOORDS_COMFULL
) ? "full compass"
5051 : (iflags
.getpos_coords
== GPCOORDS_SCREEN
) ? "screen"
5053 } else if (!strcmp(optname
, "scores")) {
5054 Sprintf(buf
, "%d top/%d around%s", flags
.end_top
, flags
.end_around
,
5055 flags
.end_own
? "/own" : "");
5056 } else if (!strcmp(optname
, "scroll_amount")) {
5057 if (iflags
.wc_scroll_amount
)
5058 Sprintf(buf
, "%d", iflags
.wc_scroll_amount
);
5060 Strcpy(buf
, defopt
);
5061 } else if (!strcmp(optname
, "scroll_margin")) {
5062 if (iflags
.wc_scroll_margin
)
5063 Sprintf(buf
, "%d", iflags
.wc_scroll_margin
);
5065 Strcpy(buf
, defopt
);
5066 } else if (!strcmp(optname
, "sortloot")) {
5067 for (i
= 0; i
< SIZE(sortltype
); i
++)
5068 if (flags
.sortloot
== sortltype
[i
][0]) {
5069 Strcpy(buf
, sortltype
[i
]);
5072 } else if (!strcmp(optname
, "player_selection")) {
5073 Sprintf(buf
, "%s", iflags
.wc_player_selection
? "prompts" : "dialog");
5075 } else if (!strcmp(optname
, "soundcard")) {
5076 Sprintf(buf
, "%s", to_be_done
);
5078 } else if (!strcmp(optname
, "suppress_alert")) {
5079 if (flags
.suppress_alert
== 0L)
5082 Sprintf(buf
, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ
,
5083 FEATURE_NOTICE_VER_MIN
, FEATURE_NOTICE_VER_PATCH
);
5084 } else if (!strcmp(optname
, "symset")) {
5086 symset
[PRIMARY
].name
? symset
[PRIMARY
].name
: "default");
5087 if (currentgraphics
== PRIMARY
&& symset
[PRIMARY
].name
)
5088 Strcat(buf
, ", active");
5089 } else if (!strcmp(optname
, "tile_file")) {
5091 iflags
.wc_tile_file
? iflags
.wc_tile_file
: defopt
);
5092 } else if (!strcmp(optname
, "tile_height")) {
5093 if (iflags
.wc_tile_height
)
5094 Sprintf(buf
, "%d", iflags
.wc_tile_height
);
5096 Strcpy(buf
, defopt
);
5097 } else if (!strcmp(optname
, "tile_width")) {
5098 if (iflags
.wc_tile_width
)
5099 Sprintf(buf
, "%d", iflags
.wc_tile_width
);
5101 Strcpy(buf
, defopt
);
5102 } else if (!strcmp(optname
, "traps")) {
5103 Sprintf(buf
, "%s", to_be_done
);
5104 } else if (!strcmp(optname
, "vary_msgcount")) {
5105 if (iflags
.wc_vary_msgcount
)
5106 Sprintf(buf
, "%d", iflags
.wc_vary_msgcount
);
5108 Strcpy(buf
, defopt
);
5110 } else if (!strcmp(optname
, "video")) {
5111 Sprintf(buf
, "%s", to_be_done
);
5114 } else if (!strcmp(optname
, "videoshades")) {
5115 Sprintf(buf
, "%s-%s-%s", shade
[0], shade
[1], shade
[2]);
5116 } else if (!strcmp(optname
, "videocolors")) {
5117 Sprintf(buf
, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
5118 ttycolors
[CLR_RED
], ttycolors
[CLR_GREEN
],
5119 ttycolors
[CLR_BROWN
], ttycolors
[CLR_BLUE
],
5120 ttycolors
[CLR_MAGENTA
], ttycolors
[CLR_CYAN
],
5121 ttycolors
[CLR_ORANGE
], ttycolors
[CLR_BRIGHT_GREEN
],
5122 ttycolors
[CLR_YELLOW
], ttycolors
[CLR_BRIGHT_BLUE
],
5123 ttycolors
[CLR_BRIGHT_MAGENTA
], ttycolors
[CLR_BRIGHT_CYAN
]);
5124 #endif /* VIDEOSHADES */
5125 } else if (!strcmp(optname
, "windowtype")) {
5126 Sprintf(buf
, "%s", windowprocs
.name
);
5127 } else if (!strcmp(optname
, "windowcolors")) {
5129 buf
, "%s/%s %s/%s %s/%s %s/%s",
5130 iflags
.wc_foregrnd_menu
? iflags
.wc_foregrnd_menu
: defbrief
,
5131 iflags
.wc_backgrnd_menu
? iflags
.wc_backgrnd_menu
: defbrief
,
5132 iflags
.wc_foregrnd_message
? iflags
.wc_foregrnd_message
5134 iflags
.wc_backgrnd_message
? iflags
.wc_backgrnd_message
5136 iflags
.wc_foregrnd_status
? iflags
.wc_foregrnd_status
: defbrief
,
5137 iflags
.wc_backgrnd_status
? iflags
.wc_backgrnd_status
: defbrief
,
5138 iflags
.wc_foregrnd_text
? iflags
.wc_foregrnd_text
: defbrief
,
5139 iflags
.wc_backgrnd_text
? iflags
.wc_backgrnd_text
: defbrief
);
5140 #ifdef PREFIXES_IN_USE
5142 for (i
= 0; i
< PREFIX_COUNT
; ++i
)
5143 if (!strcmp(optname
, fqn_prefix_names
[i
]) && fqn_prefix
[i
])
5144 Sprintf(buf
, "%s", fqn_prefix
[i
]);
5157 char buf
[BUFSZ
], ocl
[MAXOCLASSES
+ 1];
5159 flags
.pickup
= !flags
.pickup
;
5161 oc_to_str(flags
.pickup_types
, ocl
);
5162 Sprintf(buf
, "ON, for %s objects%s", ocl
[0] ? ocl
: "all",
5163 (iflags
.autopickup_exceptions
[AP_LEAVE
]
5164 || iflags
.autopickup_exceptions
[AP_GRAB
])
5165 ? ((count_ape_maps((int *) 0, (int *) 0) == 1)
5166 ? ", with one exception"
5167 : ", with some exceptions")
5172 pline("Autopickup: %s.", buf
);
5177 add_autopickup_exception(mapping
)
5178 const char *mapping
;
5181 APE_regex_error
[] = "regex error in AUTOPICKUP_EXCEPTION",
5182 APE_syntax_error
[] = "syntax error in AUTOPICKUP_EXCEPTION";
5184 struct autopickup_exception
*ape
, **apehead
;
5185 char text
[256], end
;
5187 boolean grab
= FALSE
;
5189 /* scan length limit used to be 255, but smaller size allows the
5190 quoted value to fit within BUFSZ, simplifying formatting elsewhere;
5191 this used to ignore the possibility of trailing junk but now checks
5192 for it, accepting whitespace but rejecting anything else unless it
5193 starts with '#" for a comment */
5195 if ((n
= sscanf(mapping
, "\"<%253[^\"]\" %c", text
, &end
)) == 1
5196 || (n
== 2 && end
== '#')) {
5198 } else if ((n
= sscanf(mapping
, "\">%253[^\"]\" %c", text
, &end
)) == 1
5199 || (n
= sscanf(mapping
, "\"%253[^\"]\" %c", text
, &end
)) == 1
5200 || (n
== 2 && end
== '#')) {
5203 if (!iflags
.window_inited
)
5204 raw_print(APE_syntax_error
); /* from options file */
5206 pline("%s", APE_syntax_error
); /* via 'O' command */
5210 ape
= (struct autopickup_exception
*) alloc(sizeof *ape
);
5211 ape
->regex
= regex_init();
5212 if (!regex_compile(text
, ape
->regex
)) {
5213 if (!iflags
.window_inited
)
5214 raw_print(APE_regex_error
);
5216 pline("%s", APE_regex_error
);
5217 regex_free(ape
->regex
);
5218 free((genericptr_t
) ape
);
5221 apehead
= (grab
) ? &iflags
.autopickup_exceptions
[AP_GRAB
]
5222 : &iflags
.autopickup_exceptions
[AP_LEAVE
];
5224 ape
->pattern
= dupstr(text
);
5226 ape
->next
= *apehead
;
5232 remove_autopickup_exception(whichape
)
5233 struct autopickup_exception
*whichape
;
5235 struct autopickup_exception
*ape
, *prev
= 0;
5236 int chain
= whichape
->grab
? AP_GRAB
: AP_LEAVE
;
5238 for (ape
= iflags
.autopickup_exceptions
[chain
]; ape
;) {
5239 if (ape
== whichape
) {
5240 struct autopickup_exception
*freeape
= ape
;
5246 iflags
.autopickup_exceptions
[chain
] = ape
;
5247 regex_free(freeape
->regex
);
5248 free((genericptr_t
) freeape
->pattern
);
5249 free((genericptr_t
) freeape
);
5258 count_ape_maps(leave
, grab
)
5261 struct autopickup_exception
*ape
;
5262 int pass
, totalapes
, numapes
[2] = { 0, 0 };
5264 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
5265 ape
= iflags
.autopickup_exceptions
[pass
];
5271 totalapes
= numapes
[AP_LEAVE
] + numapes
[AP_GRAB
];
5273 *leave
= numapes
[AP_LEAVE
];
5275 *grab
= numapes
[AP_GRAB
];
5280 free_autopickup_exceptions()
5282 struct autopickup_exception
*ape
;
5285 for (pass
= AP_LEAVE
; pass
<= AP_GRAB
; ++pass
) {
5286 while ((ape
= iflags
.autopickup_exceptions
[pass
]) != 0) {
5287 regex_free(ape
->regex
);
5288 free((genericptr_t
) ape
->pattern
);
5289 iflags
.autopickup_exceptions
[pass
] = ape
->next
;
5290 free((genericptr_t
) ape
);
5295 /* bundle some common usage into one easy-to-use routine */
5297 load_symset(s
, which_set
)
5301 clear_symsetentry(which_set
, TRUE
);
5303 if (symset
[which_set
].name
)
5304 free((genericptr_t
) symset
[which_set
].name
);
5305 symset
[which_set
].name
= dupstr(s
);
5307 if (read_sym_file(which_set
)) {
5308 switch_symbols(TRUE
);
5310 clear_symsetentry(which_set
, TRUE
);
5319 clear_symsetentry(PRIMARY
, TRUE
);
5320 clear_symsetentry(ROGUESET
, TRUE
);
5322 /* symset_list is cleaned up as soon as it's used, so we shouldn't
5323 have to anything about it here */
5324 /* assert( symset_list == NULL ); */
5327 /* Parse the value of a SYMBOLS line from a config file */
5330 register char *opts
;
5333 char *op
, *symname
, *strval
;
5334 struct symparse
*symp
;
5336 if ((op
= index(opts
, ',')) != 0) {
5338 if (!parsesymbols(op
)) return FALSE
;
5341 /* S_sample:string */
5343 strval
= index(opts
, ':');
5345 strval
= index(opts
, '=');
5350 /* strip leading and trailing white space from symname and strval */
5351 mungspaces(symname
);
5354 symp
= match_sym(symname
);
5358 if (symp
->range
&& symp
->range
!= SYM_CONTROL
) {
5359 val
= sym_val(strval
);
5360 update_l_symset(symp
, val
);
5369 size_t len
= strlen(buf
);
5370 const char *p
= index(buf
, ':'), *q
= index(buf
, '=');
5371 struct symparse
*sp
= loadsyms
;
5373 if (!p
|| (q
&& q
< p
))
5376 /* note: there will be at most one space before the '='
5377 because caller has condensed buf[] with mungspaces() */
5378 if (p
> buf
&& p
[-1] == ' ')
5380 len
= (int) (p
- buf
);
5383 if ((len
>= strlen(sp
->name
)) && !strncmpi(buf
, sp
->name
, len
))
5387 return (struct symparse
*) 0;
5397 if (!strval
[0] || !strval
[1]) { /* empty, or single character */
5398 /* if single char is space or tab, leave buf[0]=='\0' */
5399 if (!isspace((uchar
) strval
[0]))
5401 } else if (strval
[0] == '\'') { /* single quote */
5402 /* simple matching single quote; we know strval[1] isn't '\0' */
5403 if (strval
[2] == '\'' && !strval
[3]) {
5404 /* accepts '\' as backslash and ''' as single quote */
5407 /* if backslash, handle single or double quote or second backslash */
5408 } else if (strval
[1] == '\\' && strval
[2] && strval
[3] == '\''
5409 && index("'\"\\", strval
[2]) && !strval
[4]) {
5412 /* not simple quote or basic backslash;
5413 strip closing quote and let escapes() deal with it */
5415 char *p
, tmp
[QBUFSZ
];
5417 (void) strncpy(tmp
, strval
+ 1, sizeof tmp
- 1);
5418 tmp
[sizeof tmp
- 1] = '\0';
5419 if ((p
= rindex(tmp
, '\'')) != 0) {
5422 } /* else buf[0] stays '\0' */
5424 } else /* not lone char nor single quote */
5425 escapes(strval
, buf
);
5430 /* data for option_help() */
5431 static const char *opt_intro
[] = {
5432 "", " NetHack Options Help:", "",
5433 #define CONFIG_SLOT 3 /* fill in next value at run-time */
5435 #if !defined(MICRO) && !defined(MAC)
5436 "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
5438 "(<options> is a list of options separated by commas)",
5440 "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
5442 "or press \"O\" while playing and use the menu.", "",
5443 "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
5447 static const char *opt_epilog
[] = {
5449 "Some of the options can be set only before the game is started; those",
5450 "items will not be selectable in the 'O' command's menu.", (char *) 0
5456 char buf
[BUFSZ
], buf2
[BUFSZ
];
5460 datawin
= create_nhwindow(NHW_TEXT
);
5461 Sprintf(buf
, "Set options as OPTIONS=<options> in %s", configfile
);
5462 opt_intro
[CONFIG_SLOT
] = (const char *) buf
;
5463 for (i
= 0; opt_intro
[i
]; i
++)
5464 putstr(datawin
, 0, opt_intro
[i
]);
5466 /* Boolean options */
5467 for (i
= 0; boolopt
[i
].name
; i
++) {
5468 if (boolopt
[i
].addr
) {
5469 if (boolopt
[i
].addr
== &iflags
.sanity_check
&& !wizard
)
5471 if (boolopt
[i
].addr
== &iflags
.menu_tab_sep
&& !wizard
)
5473 next_opt(datawin
, boolopt
[i
].name
);
5476 next_opt(datawin
, "");
5478 /* Compound options */
5479 putstr(datawin
, 0, "Compound options:");
5480 for (i
= 0; compopt
[i
].name
; i
++) {
5481 Sprintf(buf2
, "`%s'", compopt
[i
].name
);
5482 Sprintf(buf
, "%-20s - %s%c", buf2
, compopt
[i
].descr
,
5483 compopt
[i
+ 1].name
? ',' : '.');
5484 putstr(datawin
, 0, buf
);
5487 for (i
= 0; opt_epilog
[i
]; i
++)
5488 putstr(datawin
, 0, opt_epilog
[i
]);
5490 display_nhwindow(datawin
, FALSE
);
5491 destroy_nhwindow(datawin
);
5496 * prints the next boolean option, on the same line if possible, on a new
5497 * line if not. End with next_opt("").
5500 next_opt(datawin
, str
)
5504 static char *buf
= 0;
5509 *(buf
= (char *) alloc(BUFSZ
)) = '\0';
5513 if (s
> &buf
[1] && s
[-2] == ',')
5514 Strcpy(s
- 2, "."); /* replace last ", " */
5515 i
= COLNO
; /* (greater than COLNO - 2) */
5517 i
= strlen(buf
) + strlen(str
) + 2;
5520 if (i
> COLNO
- 2) { /* rule of thumb */
5521 putstr(datawin
, 0, buf
);
5528 putstr(datawin
, 0, str
);
5529 free((genericptr_t
) buf
), buf
= 0;
5534 /* Returns the fid of the fruit type; if that type already exists, it
5535 * returns the fid of that one; if it does not exist, it adds a new fruit
5536 * type to the chain and returns the new one.
5537 * If replace_fruit is sent in, replace the fruit in the chain rather than
5538 * adding a new entry--for user specified fruits only.
5541 fruitadd(str
, replace_fruit
)
5543 struct fruit
*replace_fruit
;
5546 register struct fruit
*f
;
5547 int highest_fruit_id
= 0;
5548 char buf
[PL_FSIZ
], altname
[PL_FSIZ
];
5549 boolean user_specified
= (str
== pl_fruit
);
5550 /* if not user-specified, then it's a fruit name for a fruit on
5554 /* Note: every fruit has an id (kept in obj->spe) of at least 1;
5557 if (user_specified
) {
5558 boolean found
= FALSE
, numeric
= FALSE
;
5560 /* force fruit to be singular; this handling is not
5561 needed--or wanted--for fruits from bones because
5562 they already received it in their original game */
5563 nmcpy(pl_fruit
, makesingular(str
), PL_FSIZ
);
5564 /* assert( str == pl_fruit ); */
5566 /* disallow naming after other foods (since it'd be impossible
5567 * to tell the difference)
5570 for (i
= bases
[FOOD_CLASS
]; objects
[i
].oc_class
== FOOD_CLASS
; i
++) {
5571 if (!strcmp(OBJ_NAME(objects
[i
]), pl_fruit
)) {
5581 for (c
= pl_fruit
; *c
>= '0' && *c
<= '9'; c
++)
5583 if (isspace((uchar
) *c
) || *c
== 0)
5586 if (found
|| numeric
|| !strncmp(str
, "cursed ", 7)
5587 || !strncmp(str
, "uncursed ", 9) || !strncmp(str
, "blessed ", 8)
5588 || !strncmp(str
, "partly eaten ", 13)
5589 || (!strncmp(str
, "tin of ", 7)
5590 && (!strcmp(str
+ 7, "spinach")
5591 || name_to_mon(str
+ 7) >= LOW_PM
))
5592 || !strcmp(str
, "empty tin")
5593 || ((str_end_is(str
, " corpse")
5594 || str_end_is(str
, " egg"))
5595 && name_to_mon(str
) >= LOW_PM
)) {
5596 Strcpy(buf
, pl_fruit
);
5597 Strcpy(pl_fruit
, "candied ");
5598 nmcpy(pl_fruit
+ 8, buf
, PL_FSIZ
- 8);
5601 /* This flag indicates that a fruit has been made since the
5602 * last time the user set the fruit. If it hasn't, we can
5603 * safely overwrite the current fruit, preventing the user from
5604 * setting many fruits in a row and overflowing.
5605 * Possible expansion: check for specific fruit IDs, not for
5608 flags
.made_fruit
= FALSE
;
5609 if (replace_fruit
) {
5610 for (f
= ffruit
; f
; f
= f
->nextf
) {
5611 if (f
== replace_fruit
) {
5612 copynchars(f
->fname
, str
, PL_FSIZ
- 1);
5618 /* not user_supplied, so assumed to be from bones */
5619 copynchars(altname
, str
, PL_FSIZ
- 1);
5620 sanitize_name(altname
);
5621 flags
.made_fruit
= TRUE
; /* for safety. Any fruit name added from a
5622 bones level should exist anyway. */
5624 for (f
= ffruit
; f
; f
= f
->nextf
) {
5625 if (f
->fid
> highest_fruit_id
)
5626 highest_fruit_id
= f
->fid
;
5627 if (!strncmp(str
, f
->fname
, PL_FSIZ
- 1)
5628 || (*altname
&& !strcmp(altname
, f
->fname
)))
5631 /* if adding another fruit would overflow spe, use a random
5632 fruit instead... we've got a lot to choose from.
5633 current_fruit remains as is. */
5634 if (highest_fruit_id
>= 127)
5638 (void) memset((genericptr_t
)f
, 0, sizeof(struct fruit
));
5639 copynchars(f
->fname
, *altname
? altname
: str
, PL_FSIZ
- 1);
5640 f
->fid
= ++highest_fruit_id
;
5641 /* we used to go out of our way to add it at the end of the list,
5642 but the order is arbitrary so use simpler insertion at start */
5647 context
.current_fruit
= f
->fid
;
5652 * This is a somewhat generic menu for taking a list of NetHack style
5653 * class choices and presenting them via a description
5654 * rather than the traditional NetHack characters.
5655 * (Benefits users whose first exposure to NetHack is via tiles).
5658 * The title at the top of the menu.
5660 * category: 0 = monster class
5664 * FALSE = PICK_ONE, TRUE = PICK_ANY
5667 * a null terminated string containing the list of choices.
5670 * a null terminated string containing the selected characters.
5672 * Returns number selected.
5675 choose_classes_menu(prompt
, category
, way
, class_list
, class_select
)
5682 menu_item
*pick_list
= (menu_item
*) 0;
5688 int next_accelerator
, accelerator
;
5690 if (class_list
== (char *) 0 || class_select
== (char *) 0)
5693 next_accelerator
= 'a';
5695 win
= create_nhwindow(NHW_MENU
);
5697 while (*class_list
) {
5705 text
= def_monsyms
[def_char_to_monclass(*class_list
)].explain
;
5706 accelerator
= *class_list
;
5707 Sprintf(buf
, "%s", text
);
5710 text
= def_oc_syms
[def_char_to_objclass(*class_list
)].explain
;
5711 accelerator
= next_accelerator
;
5712 Sprintf(buf
, "%c %s", *class_list
, text
);
5715 impossible("choose_classes_menu: invalid category %d", category
);
5717 if (way
&& *class_select
) { /* Selections there already */
5718 if (index(class_select
, *class_list
)) {
5722 any
.a_int
= *class_list
;
5723 add_menu(win
, NO_GLYPH
, &any
, accelerator
, category
? *class_list
: 0,
5724 ATR_NONE
, buf
, selected
);
5728 if (next_accelerator
== ('z' + 1))
5729 next_accelerator
= 'A';
5730 if (next_accelerator
== ('Z' + 1))
5734 end_menu(win
, prompt
);
5735 n
= select_menu(win
, way
? PICK_ANY
: PICK_ONE
, &pick_list
);
5736 destroy_nhwindow(win
);
5738 for (i
= 0; i
< n
; ++i
)
5739 *class_select
++ = (char) pick_list
[i
].item
.a_int
;
5740 free((genericptr_t
) pick_list
);
5742 } else if (n
== -1) {
5743 class_select
= eos(class_select
);
5747 *class_select
= '\0';
5751 struct wc_Opt wc_options
[] = { { "ascii_map", WC_ASCII_MAP
},
5752 { "color", WC_COLOR
},
5753 { "eight_bit_tty", WC_EIGHT_BIT_IN
},
5754 { "hilite_pet", WC_HILITE_PET
},
5755 { "popup_dialog", WC_POPUP_DIALOG
},
5756 { "player_selection", WC_PLAYER_SELECTION
},
5757 { "preload_tiles", WC_PRELOAD_TILES
},
5758 { "tiled_map", WC_TILED_MAP
},
5759 { "tile_file", WC_TILE_FILE
},
5760 { "tile_width", WC_TILE_WIDTH
},
5761 { "tile_height", WC_TILE_HEIGHT
},
5762 { "use_inverse", WC_INVERSE
},
5763 { "align_message", WC_ALIGN_MESSAGE
},
5764 { "align_status", WC_ALIGN_STATUS
},
5765 { "font_map", WC_FONT_MAP
},
5766 { "font_menu", WC_FONT_MENU
},
5767 { "font_message", WC_FONT_MESSAGE
},
5769 {"perm_invent", WC_PERM_INVENT
},
5771 { "font_size_map", WC_FONTSIZ_MAP
},
5772 { "font_size_menu", WC_FONTSIZ_MENU
},
5773 { "font_size_message", WC_FONTSIZ_MESSAGE
},
5774 { "font_size_status", WC_FONTSIZ_STATUS
},
5775 { "font_size_text", WC_FONTSIZ_TEXT
},
5776 { "font_status", WC_FONT_STATUS
},
5777 { "font_text", WC_FONT_TEXT
},
5778 { "map_mode", WC_MAP_MODE
},
5779 { "scroll_amount", WC_SCROLL_AMOUNT
},
5780 { "scroll_margin", WC_SCROLL_MARGIN
},
5781 { "splash_screen", WC_SPLASH_SCREEN
},
5782 { "vary_msgcount", WC_VARY_MSGCOUNT
},
5783 { "windowcolors", WC_WINDOWCOLORS
},
5784 { "mouse_support", WC_MOUSE_SUPPORT
},
5785 { (char *) 0, 0L } };
5787 struct wc_Opt wc2_options
[] = { { "fullscreen", WC2_FULLSCREEN
},
5788 { "softkeyboard", WC2_SOFTKEYBOARD
},
5789 { "wraptext", WC2_WRAPTEXT
},
5790 { "use_darkgray", WC2_DARKGRAY
},
5791 #ifdef STATUS_VIA_WINDOWPORT
5792 { "hilite_status", WC2_HILITE_STATUS
},
5794 { (char *) 0, 0L } };
5797 * If a port wants to change or ensure that the SET_IN_SYS,
5798 * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
5799 * correct (for controlling its display in the option menu) call
5800 * set_option_mod_status()
5801 * with the appropriate second argument.
5804 set_option_mod_status(optnam
, status
)
5810 if (SET__IS_VALUE_VALID(status
)) {
5811 impossible("set_option_mod_status: status out of range %d.", status
);
5814 for (k
= 0; boolopt
[k
].name
; k
++) {
5815 if (!strncmpi(boolopt
[k
].name
, optnam
, strlen(optnam
))) {
5816 boolopt
[k
].optflags
= status
;
5820 for (k
= 0; compopt
[k
].name
; k
++) {
5821 if (!strncmpi(compopt
[k
].name
, optnam
, strlen(optnam
))) {
5822 compopt
[k
].optflags
= status
;
5829 * You can set several wc_options in one call to
5830 * set_wc_option_mod_status() by setting
5831 * the appropriate bits for each option that you
5832 * are setting in the optmask argument
5834 * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN,
5838 set_wc_option_mod_status(optmask
, status
)
5839 unsigned long optmask
;
5844 if (SET__IS_VALUE_VALID(status
)) {
5845 impossible("set_wc_option_mod_status: status out of range %d.",
5849 while (wc_options
[k
].wc_name
) {
5850 if (optmask
& wc_options
[k
].wc_bit
) {
5851 set_option_mod_status(wc_options
[k
].wc_name
, status
);
5858 is_wc_option(optnam
)
5863 while (wc_options
[k
].wc_name
) {
5864 if (strcmp(wc_options
[k
].wc_name
, optnam
) == 0)
5872 wc_supported(optnam
)
5877 while (wc_options
[k
].wc_name
) {
5878 if (!strcmp(wc_options
[k
].wc_name
, optnam
)
5879 && (windowprocs
.wincap
& wc_options
[k
].wc_bit
))
5887 * You can set several wc2_options in one call to
5888 * set_wc2_option_mod_status() by setting
5889 * the appropriate bits for each option that you
5890 * are setting in the optmask argument
5893 * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
5898 set_wc2_option_mod_status(optmask
, status
)
5899 unsigned long optmask
;
5904 if (SET__IS_VALUE_VALID(status
)) {
5905 impossible("set_wc2_option_mod_status: status out of range %d.",
5909 while (wc2_options
[k
].wc_name
) {
5910 if (optmask
& wc2_options
[k
].wc_bit
) {
5911 set_option_mod_status(wc2_options
[k
].wc_name
, status
);
5918 is_wc2_option(optnam
)
5923 while (wc2_options
[k
].wc_name
) {
5924 if (strcmp(wc2_options
[k
].wc_name
, optnam
) == 0)
5932 wc2_supported(optnam
)
5937 while (wc2_options
[k
].wc_name
) {
5938 if (!strcmp(wc2_options
[k
].wc_name
, optnam
)
5939 && (windowprocs
.wincap2
& wc2_options
[k
].wc_bit
))
5947 wc_set_font_name(opttype
, fontname
)
5951 char **fn
= (char **) 0;
5957 fn
= &iflags
.wc_font_map
;
5959 case MESSAGE_OPTION
:
5960 fn
= &iflags
.wc_font_message
;
5963 fn
= &iflags
.wc_font_text
;
5966 fn
= &iflags
.wc_font_menu
;
5969 fn
= &iflags
.wc_font_status
;
5976 free((genericptr_t
) *fn
);
5977 *fn
= dupstr(fontname
);
5983 wc_set_window_colors(op
)
5987 * menu white/black message green/yellow status white/blue text
5992 char *wn
, *tfg
, *tbg
, *newop
;
5993 static const char *wnames
[] = { "menu", "message", "status", "text" };
5994 static const char *shortnames
[] = { "mnu", "msg", "sts", "txt" };
5995 static char **fgp
[] = { &iflags
.wc_foregrnd_menu
,
5996 &iflags
.wc_foregrnd_message
,
5997 &iflags
.wc_foregrnd_status
,
5998 &iflags
.wc_foregrnd_text
};
5999 static char **bgp
[] = { &iflags
.wc_backgrnd_menu
,
6000 &iflags
.wc_backgrnd_message
,
6001 &iflags
.wc_backgrnd_status
,
6002 &iflags
.wc_backgrnd_text
};
6005 newop
= mungspaces(buf
);
6006 while (newop
&& *newop
) {
6007 wn
= tfg
= tbg
= (char *) 0;
6009 /* until first non-space in case there's leading spaces - before
6018 /* until first space - colorname*/
6019 while (*newop
&& *newop
!= ' ')
6027 /* until first non-space - before foreground*/
6035 /* until slash - foreground */
6036 while (*newop
&& *newop
!= '/')
6044 /* until first non-space (in case there's leading space after slash) -
6045 * before background */
6053 /* until first space - background */
6054 while (*newop
&& *newop
!= ' ')
6059 for (j
= 0; j
< 4; ++j
) {
6060 if (!strcmpi(wn
, wnames
[j
]) || !strcmpi(wn
, shortnames
[j
])) {
6061 if (tfg
&& !strstri(tfg
, " ")) {
6063 free((genericptr_t
) *fgp
[j
]);
6064 *fgp
[j
] = dupstr(tfg
);
6066 if (tbg
&& !strstri(tbg
, " ")) {
6068 free((genericptr_t
) *bgp
[j
]);
6069 *bgp
[j
] = dupstr(tbg
);
6078 /* set up for wizard mode if player or save file has requested to it;
6079 called from port-specific startup code to handle `nethack -D' or
6080 OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if
6081 restoring a game which was saved in wizard mode */
6086 if (authorize_wizard_mode())
6087 Strcpy(plname
, "wizard");
6089 wizard
= FALSE
; /* not allowed or not available */
6090 /* force explore mode if we didn't make it into wizard mode */
6092 iflags
.deferred_X
= FALSE
;
6094 /* don't need to do anything special for explore mode or normal play */
6097 #endif /* OPTION_LISTS_ONLY */