1 /* SCCS Id: @(#)options.c 3.4 2003/11/14 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */
6 #include "config.h"
7 #include "objclass.h"
8 #include "flag.h"
9 NEARDATA struct flag flags; /* provide linkage */
10 NEARDATA struct instance_flags iflags; /* provide linkage */
11 #define static
12 #else
13 #include "hack.h"
14 #include "tcap.h"
15 #include <ctype.h>
16 #endif
17
18 #define WINTYPELEN 16
19
20 #ifdef DEFAULT_WC_TILED_MAP
21 #define PREFER_TILED TRUE
22 #else
23 #define PREFER_TILED FALSE
24 #endif
25
26 /*
27 * NOTE: If you add (or delete) an option, please update the short
28 * options help (option_help()), the long options help (dat/opthelp),
29 * and the current options setting display function (doset()),
30 * and also the Guidebooks.
31 *
32 * The order matters. If an option is a an initial substring of another
33 * option (e.g. time and timed_delay) the shorter one must come first.
34 */
35
36 static struct Bool_Opt
37 {
38 const char *name;
39 boolean *addr, initvalue;
40 int optflags;
41 } boolopt[] = {
42 #ifdef AMIGA
43 {"altmeta", &flags.altmeta, TRUE, DISP_IN_GAME},
44 #else
45 {"altmeta", (boolean *)0, TRUE, DISP_IN_GAME},
46 #endif
47 {"ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME}, /*WC*/
48 #ifdef MFLOPPY
49 {"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME},
50 #else
51 {"asksavedisk", (boolean *)0, FALSE, SET_IN_FILE},
52 #endif
53 {"autodig", &flags.autodig, FALSE, SET_IN_GAME},
54 {"autopickup", &flags.pickup, TRUE, SET_IN_GAME},
55 {"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME},
56 #if defined(MICRO) && !defined(AMIGA)
57 {"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE},
58 #else
59 {"BIOS", (boolean *)0, FALSE, SET_IN_FILE},
60 #endif
61 #ifdef INSURANCE
62 {"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME},
63 #else
64 {"checkpoint", (boolean *)0, FALSE, SET_IN_FILE},
65 #endif
66 #ifdef MFLOPPY
67 {"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME},
68 #else
69 {"checkspace", (boolean *)0, FALSE, SET_IN_FILE},
70 #endif
71 {"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME},
72 # if defined(MICRO) || defined(WIN32)
73 {"color", &iflags.wc_color,TRUE, SET_IN_GAME}, /*WC*/
74 # else /* systems that support multiple terminals, many monochrome */
75 {"color", &iflags.wc_color, FALSE, SET_IN_GAME}, /*WC*/
76 # endif
77 {"confirm",&flags.confirm, TRUE, SET_IN_GAME},
78 #if defined(TERMLIB) && !defined(MAC_GRAPHICS_ENV)
79 {"DECgraphics", &iflags.DECgraphics, FALSE, SET_IN_GAME},
80 #else
81 {"DECgraphics", (boolean *)0, FALSE, SET_IN_FILE},
82 #endif
83 {"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME}, /*WC*/
84 #ifdef TTY_GRAPHICS
85 {"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME},
86 #else
87 {"extmenu", (boolean *)0, FALSE, SET_IN_FILE},
88 #endif
89 #ifdef OPT_DISPMAP
90 {"fast_map", &flags.fast_map, TRUE, SET_IN_GAME},
91 #else
92 {"fast_map", (boolean *)0, TRUE, SET_IN_FILE},
93 #endif
94 {"female", &flags.female, FALSE, DISP_IN_GAME},
95 {"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME},
96 #ifdef AMIFLUSH
97 {"flush", &flags.amiflush, FALSE, SET_IN_GAME},
98 #else
99 {"flush", (boolean *)0, FALSE, SET_IN_FILE},
100 #endif
101 {"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE},
102 {"help", &flags.help, TRUE, SET_IN_GAME},
103 {"hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME}, /*WC*/
104 #ifdef ASCIIGRAPH
105 {"IBMgraphics", &iflags.IBMgraphics, FALSE, SET_IN_GAME},
106 #else
107 {"IBMgraphics", (boolean *)0, FALSE, SET_IN_FILE},
108 #endif
109 #ifndef MAC
110 {"ignintr", &flags.ignintr, FALSE, SET_IN_GAME},
111 #else
112 {"ignintr", (boolean *)0, FALSE, SET_IN_FILE},
113 #endif
114 {"large_font", &iflags.obsolete, FALSE, SET_IN_FILE}, /* OBSOLETE */
115 {"legacy", &flags.legacy, TRUE, DISP_IN_GAME},
116 {"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME},
117 {"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME},
118 #ifdef MAC_GRAPHICS_ENV
119 {"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME},
120 #else
121 {"Macgraphics", (boolean *)0, FALSE, SET_IN_FILE},
122 #endif
123 #ifdef MAIL
124 {"mail", &flags.biff, TRUE, SET_IN_GAME},
125 #else
126 {"mail", (boolean *)0, TRUE, SET_IN_FILE},
127 #endif
128 #ifdef WIZARD
129 /* for menu debugging only*/
130 {"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
131 #else
132 {"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE},
133 #endif
134 {"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME}, /*WC*/
135 #ifdef NEWS
136 {"news", &iflags.news, TRUE, DISP_IN_GAME},
137 #else
138 {"news", (boolean *)0, FALSE, SET_IN_FILE},
139 #endif
140 {"null", &flags.null, TRUE, SET_IN_GAME},
141 #ifdef MAC
142 {"page_wait", &flags.page_wait, TRUE, SET_IN_GAME},
143 #else
144 {"page_wait", (boolean *)0, FALSE, SET_IN_FILE},
145 #endif
146 {"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME},
147 {"popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME}, /*WC*/
148 {"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME},
149 {"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME}, /*WC*/
150 {"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME},
151 #if defined(MICRO) && !defined(AMIGA)
152 {"rawio", &iflags.rawio, FALSE, DISP_IN_GAME},
153 #else
154 {"rawio", (boolean *)0, FALSE, SET_IN_FILE},
155 #endif
156 {"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
157 {"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
158 #ifdef WIZARD
159 {"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
160 #else
161 {"sanity_check", (boolean *)0, FALSE, SET_IN_FILE},
162 #endif
163 #ifdef EXP_ON_BOTL
164 {"showexp", &flags.showexp, FALSE, SET_IN_GAME},
165 #else
166 {"showexp", (boolean *)0, FALSE, SET_IN_FILE},
167 #endif
168 {"showrace", &iflags.showrace, FALSE, SET_IN_GAME},
169 #ifdef SCORE_ON_BOTL
170 {"showscore", &flags.showscore, FALSE, SET_IN_GAME},
171 #else
172 {"showscore", (boolean *)0, FALSE, SET_IN_FILE},
173 #endif
174 {"silent", &flags.silent, TRUE, SET_IN_GAME},
175 {"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE},
176 {"sortpack", &flags.sortpack, TRUE, SET_IN_GAME},
177 {"sound", &flags.soundok, TRUE, SET_IN_GAME},
178 {"sparkle", &flags.sparkle, TRUE, SET_IN_GAME},
179 {"standout", &flags.standout, FALSE, SET_IN_GAME},
180 {"splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME}, /*WC*/
181 {"tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME}, /*WC*/
182 {"time", &flags.time, FALSE, SET_IN_GAME},
183 #ifdef TIMED_DELAY
184 {"timed_delay", &flags.nap, TRUE, SET_IN_GAME},
185 #else
186 {"timed_delay", (boolean *)0, FALSE, SET_IN_GAME},
187 #endif
188 {"tombstone",&flags.tombstone, TRUE, SET_IN_GAME},
189 {"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME},
190 {"travel", &iflags.travelcmd, TRUE, SET_IN_GAME},
191 #ifdef WIN32CON
192 {"use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME}, /*WC*/
193 #else
194 {"use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME}, /*WC*/
195 #endif
196 {"verbose", &flags.verbose, TRUE, SET_IN_GAME},
197 {"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
198 {(char *)0, (boolean *)0, FALSE, 0}
199 };
200
201 /* compound options, for option_help() and external programs like Amiga
202 * frontend */
203 static struct Comp_Opt
204 {
205 const char *name, *descr;
206 int size; /* for frontends and such allocating space --
207 * usually allowed size of data in game, but
208 * occasionally maximum reasonable size for
209 * typing when game maintains information in
210 * a different format */
211 int optflags;
212 } compopt[] = {
213 { "align", "your starting alignment (lawful, neutral, or chaotic)",
214 8, DISP_IN_GAME },
215 { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/
216 { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/
217 { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
218 { "boulder", "the symbol to use for displaying boulders",
219 1, SET_IN_GAME },
220 { "catname", "the name of your (first) cat (e.g., catname:Tabby)",
221 PL_PSIZ, DISP_IN_GAME },
222 { "disclose", "the kinds of information to disclose at end of game",
223 sizeof(flags.end_disclose) * 2,
224 SET_IN_GAME },
225 { "dogname", "the name of your (first) dog (e.g., dogname:Fang)",
226 PL_PSIZ, DISP_IN_GAME },
227 { "dungeon", "the symbols to use in drawing the dungeon map",
228 MAXDCHARS+1, SET_IN_FILE },
229 { "effects", "the symbols to use in drawing special effects",
230 MAXECHARS+1, SET_IN_FILE },
231 { "font_map", "the font to use in the map window", 40, DISP_IN_GAME }, /*WC*/
232 { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/
233 { "font_message", "the font to use in the message window",
234 40, DISP_IN_GAME }, /*WC*/
235 { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/
236 { "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME }, /*WC*/
237 { "font_size_message", "the size of the message font", 20, DISP_IN_GAME }, /*WC*/
238 { "font_size_status", "the size of the status font", 20, DISP_IN_GAME }, /*WC*/
239 { "font_size_text", "the size of the text font", 20, DISP_IN_GAME }, /*WC*/
240 { "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/
241 { "font_text", "the font to use in text windows", 40, DISP_IN_GAME }, /*WC*/
242 { "fruit", "the name of a fruit you enjoy eating",
243 PL_FSIZ, SET_IN_GAME },
244 { "gender", "your starting gender (male or female)",
245 8, DISP_IN_GAME },
246 { "horsename", "the name of your (first) horse (e.g., horsename:Silver)",
247 PL_PSIZ, DISP_IN_GAME },
248 { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/
249 { "menustyle", "user interface for object selection",
250 MENUTYPELEN, SET_IN_GAME },
251 { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE },
252 { "menu_deselect_page", "deselect all items on this page of a menu",
253 4, SET_IN_FILE },
254 { "menu_first_page", "jump to the first page in a menu",
255 4, SET_IN_FILE },
256 { "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME },
257 { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE },
258 { "menu_invert_page", "invert all items on this page of a menu",
259 4, SET_IN_FILE },
260 { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE },
261 { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE },
262 { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE },
263 { "menu_search", "search for a menu item", 4, SET_IN_FILE },
264 { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE },
265 { "menu_select_page", "select all items on this page of a menu",
266 4, SET_IN_FILE },
267 { "monsters", "the symbols to use for monsters",
268 MAXMCLASSES, SET_IN_FILE },
269 { "msghistory", "number of top line messages to save",
270 5, DISP_IN_GAME },
271 # ifdef TTY_GRAPHICS
272 {"msg_window", "the type of message window required",1, SET_IN_GAME},
273 # else
274 {"msg_window", "the type of message window required", 1, SET_IN_FILE},
275 # endif
276 { "name", "your character's name (e.g., name:Merlin-W)",
277 PL_NSIZ, DISP_IN_GAME },
278 { "number_pad", "use the number pad", 1, SET_IN_GAME},
279 { "objects", "the symbols to use for objects",
280 MAXOCLASSES, SET_IN_FILE },
281 { "packorder", "the inventory order of the items in your pack",
282 MAXOCLASSES, SET_IN_GAME },
283 #ifdef CHANGE_COLOR
284 { "palette", "palette (00c/880/-fff is blue/yellow/reverse white)",
285 15 , SET_IN_GAME },
286 # if defined(MAC)
287 { "hicolor", "same as palette, only order is reversed",
288 15, SET_IN_FILE },
289 # endif
290 #endif
291 { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
292 { "pickup_burden", "maximum burden picked up before prompt",
293 20, SET_IN_GAME },
294 { "pickup_types", "types of objects to pick up automatically",
295 MAXOCLASSES, SET_IN_GAME },
296 { "player_selection", "choose character via dialog or prompts",
297 12, DISP_IN_GAME },
298 { "race", "your starting race (e.g., Human, Elf)",
299 PL_CSIZ, DISP_IN_GAME },
300 { "role", "your starting role (e.g., Barbarian, Valkyrie)",
301 PL_CSIZ, DISP_IN_GAME },
302 { "runmode", "display frequency when `running' or `travelling'",
303 sizeof "teleport", SET_IN_GAME },
304 { "scores", "the parts of the score list you wish to see",
305 32, SET_IN_GAME },
306 { "scroll_amount", "amount to scroll map when scroll_margin is reached",
307 20, DISP_IN_GAME }, /*WC*/
308 { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
309 #ifdef MSDOS
310 { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
311 #endif
312 { "suppress_alert", "suppress alerts about version-specific features",
313 8, SET_IN_GAME },
314 { "tile_width", "width of tiles", 20, DISP_IN_GAME}, /*WC*/
315 { "tile_height", "height of tiles", 20, DISP_IN_GAME}, /*WC*/
316 { "tile_file", "name of tile file", 70, DISP_IN_GAME}, /*WC*/
317 { "traps", "the symbols to use in drawing traps",
318 MAXTCHARS+1, SET_IN_FILE },
319 { "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/
320 #ifdef MSDOS
321 { "video", "method of video updating", 20, SET_IN_FILE },
322 #endif
323 #ifdef VIDEOSHADES
324 { "videocolors", "color mappings for internal screen routines",
325 40, DISP_IN_GAME },
326 { "videoshades", "gray shades to map to black/gray/white",
327 32, DISP_IN_GAME },
328 #endif
329 #ifdef WIN32CON
330 {"subkeyvalue", "override keystroke value", 7, SET_IN_FILE},
331 #endif
332 { "windowcolors", "the foreground/background colors of windows", /*WC*/
333 80, DISP_IN_GAME },
334 { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
335 { (char *)0, (char *)0, 0, 0 }
336 };
337
338 #ifdef OPTION_LISTS_ONLY
339 #undef static
340
341 #else /* use rest of file */
342
343 static boolean need_redraw; /* for doset() */
344
345 #if defined(TOS) && defined(TEXTCOLOR)
346 extern boolean colors_changed; /* in tos.c */
347 #endif
348
349 #ifdef VIDEOSHADES
350 extern char *shade[3]; /* in sys/msdos/video.c */
351 extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
352 #endif
353
354 static char def_inv_order[MAXOCLASSES] = {
355 COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
356 SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS,
357 TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
358 };
359
360 /*
361 * Default menu manipulation command accelerators. These may _not_ be:
362 *
363 * + a number - reserved for counts
364 * + an upper or lower case US ASCII letter - used for accelerators
365 * + ESC - reserved for escaping the menu
366 * + NULL, CR or LF - reserved for commiting the selection(s). NULL
367 * is kind of odd, but the tty's xwaitforspace() will return it if
368 * someone hits a <ret>.
369 * + a default object class symbol - used for object class accelerators
370 *
371 * Standard letters (for now) are:
372 *
373 * < back 1 page
374 * > forward 1 page
375 * ^ first page
376 * | last page
377 * : search
378 *
379 * page all
380 * , select .
381 * \ deselect -
382 * ~ invert @
383 *
384 * The command name list is duplicated in the compopt array.
385 */
386 typedef struct {
387 const char *name;
388 char cmd;
389 } menu_cmd_t;
390
391 #define NUM_MENU_CMDS 11
392 static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = {
393 /* 0*/ { "menu_first_page", MENU_FIRST_PAGE },
394 { "menu_last_page", MENU_LAST_PAGE },
395 { "menu_next_page", MENU_NEXT_PAGE },
396 { "menu_previous_page", MENU_PREVIOUS_PAGE },
397 { "menu_select_all", MENU_SELECT_ALL },
398 /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL },
399 { "menu_invert_all", MENU_INVERT_ALL },
400 { "menu_select_page", MENU_SELECT_PAGE },
401 { "menu_deselect_page", MENU_UNSELECT_PAGE },
402 { "menu_invert_page", MENU_INVERT_PAGE },
403 /*10*/ { "menu_search", MENU_SEARCH },
404 };
405
406 /*
407 * Allow the user to map incoming characters to various menu commands.
408 * The accelerator list must be a valid C string.
409 */
410 #define MAX_MENU_MAPPED_CMDS 32 /* some number */
411 char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1]; /* exported */
412 static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1];
413 static short n_menu_mapped = 0;
414
415
416 static boolean initial, from_file;
417
418 STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int));
419 STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
420 STATIC_DCL void FDECL(escapes, (const char *, char *));
421 STATIC_DCL void FDECL(rejectoption, (const char *));
422 STATIC_DCL void FDECL(badoption, (const char *));
423 STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P));
424 STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P));
425 STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P));
426 STATIC_DCL int FDECL(change_inv_order, (char *));
427 STATIC_DCL void FDECL(oc_to_str, (char *, char *));
428 STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int));
429 STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
430 STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
431 STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P));
432 STATIC_DCL void FDECL(warning_opts, (char *,const char *));
433 STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int));
434
435 STATIC_OVL void FDECL(wc_set_font_name, (int, char *));
436 STATIC_OVL int FDECL(wc_set_window_colors, (char *));
437 STATIC_OVL boolean FDECL(is_wc_option, (const char *));
438 STATIC_OVL boolean FDECL(wc_supported, (const char *));
439 STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
440 STATIC_OVL boolean FDECL(wc2_supported, (const char *));
441 #ifdef AUTOPICKUP_EXCEPTIONS
442 STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
443 STATIC_OVL int FDECL(count_ape_maps, (int *, int *));
444 #endif
445
446 /* check whether a user-supplied option string is a proper leading
447 substring of a particular option name; option string might have
448 a colon or equals sign and arbitrary value appended to it */
449 boolean
match_optname(user_string,opt_name,min_length,val_allowed)450 match_optname(user_string, opt_name, min_length, val_allowed)
451 const char *user_string, *opt_name;
452 int min_length;
453 boolean val_allowed;
454 {
455 int len = (int)strlen(user_string);
456
457 if (val_allowed) {
458 const char *p = index(user_string, ':'),
459 *q = index(user_string, '=');
460
461 if (!p || (q && q < p)) p = q;
462 while(p && p > user_string && isspace(*(p-1))) p--;
463 if (p) len = (int)(p - user_string);
464 }
465
466 return (len >= min_length) && !strncmpi(opt_name, user_string, len);
467 }
468
469 /* most environment variables will eventually be printed in an error
470 * message if they don't work, and most error message paths go through
471 * BUFSZ buffers, which could be overflowed by a maliciously long
472 * environment variable. if a variable can legitimately be long, or
473 * if it's put in a smaller buffer, the responsible code will have to
474 * bounds-check itself.
475 */
476 char *
nh_getenv(ev)477 nh_getenv(ev)
478 const char *ev;
479 {
480 char *getev = getenv(ev);
481
482 if (getev && strlen(getev) <= (BUFSZ / 2))
483 return getev;
484 else
485 return (char *)0;
486 }
487
488 void
initoptions()489 initoptions()
490 {
491 #ifndef MAC
492 char *opts;
493 #endif
494 int i;
495
496 /* initialize the random number generator */
497 setrandom();
498
499 /* for detection of configfile options specified multiple times */
500 iflags.opt_booldup = iflags.opt_compdup = (int *)0;
501
502 for (i = 0; boolopt[i].name; i++) {
503 if (boolopt[i].addr)
504 *(boolopt[i].addr) = boolopt[i].initvalue;
505 }
506 flags.end_own = FALSE;
507 flags.end_top = 3;
508 flags.end_around = 2;
509 iflags.runmode = RUN_LEAP;
510 iflags.msg_history = 20;
511 #ifdef TTY_GRAPHICS
512 iflags.prevmsg_window = 's';
513 #endif
514 iflags.menu_headings = ATR_INVERSE;
515
516 /* Use negative indices to indicate not yet selected */
517 flags.initrole = -1;
518 flags.initrace = -1;
519 flags.initgend = -1;
520 flags.initalign = -1;
521
522 /* Set the default monster and object class symbols. Don't use */
523 /* memcpy() --- sizeof char != sizeof uchar on some machines. */
524 for (i = 0; i < MAXOCLASSES; i++)
525 oc_syms[i] = (uchar) def_oc_syms[i];
526 for (i = 0; i < MAXMCLASSES; i++)
527 monsyms[i] = (uchar) def_monsyms[i];
528 for (i = 0; i < WARNCOUNT; i++)
529 warnsyms[i] = def_warnsyms[i].sym;
530 iflags.bouldersym = 0;
531 iflags.travelcc.x = iflags.travelcc.y = -1;
532 flags.warnlevel = 1;
533 flags.warntype = 0L;
534
535 /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */
536 (void)memcpy((genericptr_t)flags.inv_order,
537 (genericptr_t)def_inv_order, sizeof flags.inv_order);
538 flags.pickup_types[0] = '\0';
539 flags.pickup_burden = MOD_ENCUMBER;
540
541 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
542 flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
543 switch_graphics(ASCII_GRAPHICS); /* set default characters */
544 #if defined(UNIX) && defined(TTY_GRAPHICS)
545 /*
546 * Set defaults for some options depending on what we can
547 * detect about the environment's capabilities.
548 * This has to be done after the global initialization above
549 * and before reading user-specific initialization via
550 * config file/environment variable below.
551 */
552 /* this detects the IBM-compatible console on most 386 boxes */
553 if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) {
554 switch_graphics(IBM_GRAPHICS);
555 # ifdef TEXTCOLOR
556 iflags.use_color = TRUE;
557 # endif
558 }
559 #endif /* UNIX && TTY_GRAPHICS */
560 #if defined(UNIX) || defined(VMS)
561 # ifdef TTY_GRAPHICS
562 /* detect whether a "vt" terminal can handle alternate charsets */
563 if ((opts = nh_getenv("TERM")) &&
564 !strncmpi(opts, "vt", 2) && AS && AE &&
565 index(AS, '\016') && index(AE, '\017')) {
566 switch_graphics(DEC_GRAPHICS);
567 }
568 # endif
569 #endif /* UNIX || VMS */
570
571 #ifdef MAC_GRAPHICS_ENV
572 switch_graphics(MAC_GRAPHICS);
573 #endif /* MAC_GRAPHICS_ENV */
574 flags.menu_style = MENU_FULL;
575
576 /* since this is done before init_objects(), do partial init here */
577 objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
578 nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
579 #ifndef MAC
580 opts = getenv("NETHACKOPTIONS");
581 if (!opts) opts = getenv("HACKOPTIONS");
582 if (opts) {
583 if (*opts == '/' || *opts == '\\' || *opts == '@') {
584 if (*opts == '@') opts++; /* @filename */
585 /* looks like a filename */
586 if (strlen(opts) < BUFSZ/2)
587 read_config_file(opts);
588 } else {
589 read_config_file((char *)0);
590 /* let the total length of options be long;
591 * parseoptions() will check each individually
592 */
593 parseoptions(opts, TRUE, FALSE);
594 }
595 } else
596 #endif
597 read_config_file((char *)0);
598
599 (void)fruitadd(pl_fruit);
600 /* Remove "slime mold" from list of object names; this will */
601 /* prevent it from being wished unless it's actually present */
602 /* as a named (or default) fruit. Wishing for "fruit" will */
603 /* result in the player's preferred fruit [better than "\033"]. */
604 obj_descr[SLIME_MOLD].oc_name = "fruit";
605
606 return;
607 }
608
609 STATIC_OVL void
nmcpy(dest,src,maxlen)610 nmcpy(dest, src, maxlen)
611 char *dest;
612 const char *src;
613 int maxlen;
614 {
615 int count;
616
617 for(count = 1; count < maxlen; count++) {
618 if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
619 *dest++ = *src++;
620 }
621 *dest = 0;
622 }
623
624 /*
625 * escapes: escape expansion for showsyms. C-style escapes understood include
626 * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
627 * for control characters is also understood, and \[mM] followed by any of the
628 * previous forms or by a character has the effect of 'meta'-ing the value (so
629 * that the alternate character set will be enabled).
630 */
631 STATIC_OVL void
escapes(cp,tp)632 escapes(cp, tp)
633 const char *cp;
634 char *tp;
635 {
636 while (*cp)
637 {
638 int cval = 0, meta = 0;
639
640 if (*cp == '\\' && index("mM", cp[1])) {
641 meta = 1;
642 cp += 2;
643 }
644 if (*cp == '\\' && index("0123456789xXoO", cp[1]))
645 {
646 const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
647 int dcount = 0;
648
649 cp++;
650 if (*cp == 'x' || *cp == 'X')
651 for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
652 cval = (cval * 16) + (dp - hex) / 2;
653 else if (*cp == 'o' || *cp == 'O')
654 for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
655 cval = (cval * 8) + (*cp - '0');
656 else
657 for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
658 cval = (cval * 10) + (*cp - '0');
659 }
660 else if (*cp == '\\') /* C-style character escapes */
661 {
662 switch (*++cp)
663 {
664 case '\\': cval = '\\'; break;
665 case 'n': cval = '\n'; break;
666 case 't': cval = '\t'; break;
667 case 'b': cval = '\b'; break;
668 case 'r': cval = '\r'; break;
669 default: cval = *cp;
670 }
671 cp++;
672 }
673 else if (*cp == '^') /* expand control-character syntax */
674 {
675 cval = (*++cp & 0x1f);
676 cp++;
677 }
678 else
679 cval = *cp++;
680 if (meta)
681 cval |= 0x80;
682 *tp++ = cval;
683 }
684 *tp = '\0';
685 }
686
687 STATIC_OVL void
rejectoption(optname)688 rejectoption(optname)
689 const char *optname;
690 {
691 #ifdef MICRO
692 pline("\"%s\" settable only from %s.", optname, configfile);
693 #else
694 pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
695 configfile);
696 #endif
697 }
698
699 STATIC_OVL void
badoption(opts)700 badoption(opts)
701 const char *opts;
702 {
703 if (!initial) {
704 if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
705 option_help();
706 else
707 pline("Bad syntax: %s. Enter \"?g\" for help.", opts);
708 return;
709 }
710 #ifdef MAC
711 else return;
712 #endif
713
714 if(from_file)
715 raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
716 else
717 raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts);
718
719 wait_synch();
720 }
721
722 STATIC_OVL char *
string_for_opt(opts,val_optional)723 string_for_opt(opts, val_optional)
724 char *opts;
725 boolean val_optional;
726 {
727 char *colon, *equals;
728
729 colon = index(opts, ':');
730 equals = index(opts, '=');
731 if (!colon || (equals && equals < colon)) colon = equals;
732
733 if (!colon || !*++colon) {
734 if (!val_optional) badoption(opts);
735 return (char *)0;
736 }
737 return colon;
738 }
739
740 STATIC_OVL char *
string_for_env_opt(optname,opts,val_optional)741 string_for_env_opt(optname, opts, val_optional)
742 const char *optname;
743 char *opts;
744 boolean val_optional;
745 {
746 if(!initial) {
747 rejectoption(optname);
748 return (char *)0;
749 }
750 return string_for_opt(opts, val_optional);
751 }
752
753 STATIC_OVL void
bad_negation(optname,with_parameter)754 bad_negation(optname, with_parameter)
755 const char *optname;
756 boolean with_parameter;
757 {
758 pline_The("%s option may not %sbe negated.",
759 optname,
760 with_parameter ? "both have a value and " : "");
761 }
762
763 /*
764 * Change the inventory order, using the given string as the new order.
765 * Missing characters in the new order are filled in at the end from
766 * the current inv_order, except for gold, which is forced to be first
767 * if not explicitly present.
768 *
769 * This routine returns 1 unless there is a duplicate or bad char in
770 * the string.
771 */
772 STATIC_OVL int
change_inv_order(op)773 change_inv_order(op)
774 char *op;
775 {
776 int oc_sym, num;
777 char *sp, buf[BUFSZ];
778
779 num = 0;
780 #ifndef GOLDOBJ
781 if (!index(op, GOLD_SYM))
782 buf[num++] = COIN_CLASS;
783 #else
784 /* !!!! probably unnecessary with gold as normal inventory */
785 #endif
786
787 for (sp = op; *sp; sp++) {
788 oc_sym = def_char_to_objclass(*sp);
789 /* reject bad or duplicate entries */
790 if (oc_sym == MAXOCLASSES ||
791 oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||
792 !index(flags.inv_order, oc_sym) || index(sp+1, *sp))
793 return 0;
794 /* retain good ones */
795 buf[num++] = (char) oc_sym;
796 }
797 buf[num] = '\0';
798
799 /* fill in any omitted classes, using previous ordering */
800 for (sp = flags.inv_order; *sp; sp++)
801 if (!index(buf, *sp)) {
802 buf[num++] = *sp;
803 buf[num] = '\0'; /* explicitly terminate for next index() */
804 }
805
806 Strcpy(flags.inv_order, buf);
807 return 1;
808 }
809
810 STATIC_OVL void
graphics_opts(opts,optype,maxlen,offset)811 graphics_opts(opts, optype, maxlen, offset)
812 register char *opts;
813 const char *optype;
814 int maxlen, offset;
815 {
816 uchar translate[MAXPCHARS+1];
817 int length, i;
818
819 if (!(opts = string_for_env_opt(optype, opts, FALSE)))
820 return;
821 escapes(opts, opts);
822
823 length = strlen(opts);
824 if (length > maxlen) length = maxlen;
825 /* match the form obtained from PC configuration files */
826 for (i = 0; i < length; i++)
827 translate[i] = (uchar) opts[i];
828 assign_graphics(translate, length, maxlen, offset);
829 }
830
831 STATIC_OVL void
warning_opts(opts,optype)832 warning_opts(opts, optype)
833 register char *opts;
834 const char *optype;
835 {
836 uchar translate[MAXPCHARS+1];
837 int length, i;
838
839 if (!(opts = string_for_env_opt(optype, opts, FALSE)))
840 return;
841 escapes(opts, opts);
842
843 length = strlen(opts);
844 if (length > WARNCOUNT) length = WARNCOUNT;
845 /* match the form obtained from PC configuration files */
846 for (i = 0; i < length; i++)
847 translate[i] = (((i < WARNCOUNT) && opts[i]) ?
848 (uchar) opts[i] : def_warnsyms[i].sym);
849 assign_warnings(translate);
850 }
851
852 void
assign_warnings(graph_chars)853 assign_warnings(graph_chars)
854 register uchar *graph_chars;
855 {
856 int i;
857 for (i = 0; i < WARNCOUNT; i++)
858 if (graph_chars[i]) warnsyms[i] = graph_chars[i];
859 }
860
861 STATIC_OVL int
feature_alert_opts(op,optn)862 feature_alert_opts(op, optn)
863 char *op;
864 const char *optn;
865 {
866 char buf[BUFSZ];
867 boolean rejectver = FALSE;
868 unsigned long fnv = get_feature_notice_ver(op); /* version.c */
869 if (fnv == 0L) return 0;
870 if (fnv > get_current_feature_ver())
871 rejectver = TRUE;
872 else
873 flags.suppress_alert = fnv;
874 if (rejectver) {
875 if (!initial)
876 You_cant("disable new feature alerts for future versions.");
877 else {
878 Sprintf(buf,
879 "\n%s=%s Invalid reference to a future version ignored",
880 optn, op);
881 badoption(buf);
882 }
883 return 0;
884 }
885 if (!initial) {
886 Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,
887 FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH);
888 pline("Feature change alerts disabled for NetHack %s features and prior.",
889 buf);
890 }
891 return 1;
892 }
893
894 void
set_duplicate_opt_detection(on_or_off)895 set_duplicate_opt_detection(on_or_off)
896 int on_or_off;
897 {
898 int k, *optptr;
899 if (on_or_off != 0) {
900 /*-- ON --*/
901 if (iflags.opt_booldup)
902 impossible("iflags.opt_booldup already on (memory leak)");
903 iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int));
904 optptr = iflags.opt_booldup;
905 for (k = 0; k < SIZE(boolopt); ++k)
906 *optptr++ = 0;
907
908 if (iflags.opt_compdup)
909 impossible("iflags.opt_compdup already on (memory leak)");
910 iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int));
911 optptr = iflags.opt_compdup;
912 for (k = 0; k < SIZE(compopt); ++k)
913 *optptr++ = 0;
914 } else {
915 /*-- OFF --*/
916 if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup);
917 iflags.opt_booldup = (int *)0;
918 if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup);
919 iflags.opt_compdup = (int *)0;
920 }
921 }
922
923 STATIC_OVL void
duplicate_opt_detection(opts,bool_or_comp)924 duplicate_opt_detection(opts, bool_or_comp)
925 const char *opts;
926 int bool_or_comp; /* 0 == boolean option, 1 == compound */
927 {
928 int i, *optptr;
929 #if defined(MAC)
930 /* the Mac has trouble dealing with the output of messages while
931 * processing the config file. That should get fixed one day.
932 * For now just return.
933 */
934 return;
935 #endif
936 if ((bool_or_comp == 0) && iflags.opt_booldup && initial && from_file) {
937 for (i = 0; boolopt[i].name; i++) {
938 if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
939 optptr = iflags.opt_booldup + i;
940 if (*optptr == 1) {
941 raw_printf(
942 "\nWarning - Boolean option specified multiple times: %s.\n",
943 opts);
944 wait_synch();
945 }
946 *optptr += 1;
947 break; /* don't match multiple options */
948 }
949 }
950 } else if ((bool_or_comp == 1) && iflags.opt_compdup && initial && from_file) {
951 for (i = 0; compopt[i].name; i++) {
952 if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) {
953 optptr = iflags.opt_compdup + i;
954 if (*optptr == 1) {
955 raw_printf(
956 "\nWarning - compound option specified multiple times: %s.\n",
957 compopt[i].name);
958 wait_synch();
959 }
960 *optptr += 1;
961 break; /* don't match multiple options */
962 }
963 }
964 }
965 }
966
967 void
parseoptions(opts,tinitial,tfrom_file)968 parseoptions(opts, tinitial, tfrom_file)
969 register char *opts;
970 boolean tinitial, tfrom_file;
971 {
972 register char *op;
973 unsigned num;
974 boolean negated;
975 int i;
976 const char *fullname;
977
978 initial = tinitial;
979 from_file = tfrom_file;
980 if ((op = index(opts, ',')) != 0) {
981 *op++ = 0;
982 parseoptions(op, initial, from_file);
983 }
984 if (strlen(opts) > BUFSZ/2) {
985 badoption("option too long");
986 return;
987 }
988
989 /* strip leading and trailing white space */
990 while (isspace(*opts)) opts++;
991 op = eos(opts);
992 while (--op >= opts && isspace(*op)) *op = '\0';
993
994 if (!*opts) return;
995 negated = FALSE;
996 while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
997 if (*opts == '!') opts++; else opts += 2;
998 negated = !negated;
999 }
1000
1001 /* variant spelling */
1002
1003 if (match_optname(opts, "colour", 5, FALSE))
1004 Strcpy(opts, "color"); /* fortunately this isn't longer */
1005
1006 if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */
1007 duplicate_opt_detection(opts, 1); /* 1 means compound opts */
1008
1009 /* special boolean options */
1010
1011 if (match_optname(opts, "female", 3, FALSE)) {
1012 if(!initial && flags.female == negated)
1013 pline("That is not anatomically possible.");
1014 else
1015 flags.initgend = flags.female = !negated;
1016 return;
1017 }
1018
1019 if (match_optname(opts, "male", 4, FALSE)) {
1020 if(!initial && flags.female != negated)
1021 pline("That is not anatomically possible.");
1022 else
1023 flags.initgend = flags.female = negated;
1024 return;
1025 }
1026
1027 #if defined(MICRO) && !defined(AMIGA)
1028 /* included for compatibility with old NetHack.cnf files */
1029 if (match_optname(opts, "IBM_", 4, FALSE)) {
1030 iflags.BIOS = !negated;
1031 return;
1032 }
1033 #endif /* MICRO */
1034
1035 /* compound options */
1036
1037 fullname = "pettype";
1038 if (match_optname(opts, fullname, 3, TRUE)) {
1039 if ((op = string_for_env_opt(fullname, opts, negated)) != 0) {
1040 if (negated) bad_negation(fullname, TRUE);
1041 else switch (*op) {
1042 case 'd': /* dog */
1043 case 'D':
1044 preferred_pet = 'd';
1045 break;
1046 case 'c': /* cat */
1047 case 'C':
1048 case 'f': /* feline */
1049 case 'F':
1050 preferred_pet = 'c';
1051 break;
1052 case 'n': /* no pet */
1053 case 'N':
1054 preferred_pet = 'n';
1055 break;
1056 default:
1057 pline("Unrecognized pet type '%s'.", op);
1058 break;
1059 }
1060 } else if (negated) preferred_pet = 'n';
1061 return;
1062 }
1063
1064 fullname = "catname";
1065 if (match_optname(opts, fullname, 3, TRUE)) {
1066 if (negated) bad_negation(fullname, FALSE);
1067 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1068 nmcpy(catname, op, PL_PSIZ);
1069 return;
1070 }
1071
1072 fullname = "dogname";
1073 if (match_optname(opts, fullname, 3, TRUE)) {
1074 if (negated) bad_negation(fullname, FALSE);
1075 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1076 nmcpy(dogname, op, PL_PSIZ);
1077 return;
1078 }
1079
1080 fullname = "horsename";
1081 if (match_optname(opts, fullname, 5, TRUE)) {
1082 if (negated) bad_negation(fullname, FALSE);
1083 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1084 nmcpy(horsename, op, PL_PSIZ);
1085 return;
1086 }
1087
1088 fullname = "number_pad";
1089 if (match_optname(opts, fullname, 10, TRUE)) {
1090 boolean compat = (strlen(opts) <= 10);
1091 number_pad(iflags.num_pad ? 1 : 0);
1092 op = string_for_opt(opts, (compat || !initial));
1093 if (!op) {
1094 if (compat || negated || initial) {
1095 /* for backwards compatibility, "number_pad" without a
1096 value is a synonym for number_pad:1 */
1097 iflags.num_pad = !negated;
1098 if (iflags.num_pad) iflags.num_pad_mode = 0;
1099 }
1100 return;
1101 }
1102 if (negated) {
1103 bad_negation("number_pad", TRUE);
1104 return;
1105 }
1106 if (*op == '1' || *op == '2') {
1107 iflags.num_pad = 1;
1108 if (*op == '2') iflags.num_pad_mode = 1;
1109 else iflags.num_pad_mode = 0;
1110 } else if (*op == '0') {
1111 iflags.num_pad = 0;
1112 iflags.num_pad_mode = 0;
1113 } else badoption(opts);
1114 return;
1115 }
1116
1117 fullname = "runmode";
1118 if (match_optname(opts, fullname, 4, TRUE)) {
1119 if (negated) {
1120 iflags.runmode = RUN_TPORT;
1121 } else if ((op = string_for_opt(opts, FALSE)) != 0) {
1122 if (!strncmpi(op, "teleport", strlen(op)))
1123 iflags.runmode = RUN_TPORT;
1124 else if (!strncmpi(op, "run", strlen(op)))
1125 iflags.runmode = RUN_LEAP;
1126 else if (!strncmpi(op, "walk", strlen(op)))
1127 iflags.runmode = RUN_STEP;
1128 else if (!strncmpi(op, "crawl", strlen(op)))
1129 iflags.runmode = RUN_CRAWL;
1130 else
1131 badoption(opts);
1132 }
1133 return;
1134 }
1135
1136 fullname = "msghistory";
1137 if (match_optname(opts, fullname, 3, TRUE)) {
1138 op = string_for_env_opt(fullname, opts, negated);
1139 if ((negated && !op) || (!negated && op)) {
1140 iflags.msg_history = negated ? 0 : atoi(op);
1141 } else if (negated) bad_negation(fullname, TRUE);
1142 return;
1143 }
1144
1145 fullname="msg_window";
1146 /* msg_window:single, combo, full or reversed */
1147 if (match_optname(opts, fullname, 4, TRUE)) {
1148 /* allow option to be silently ignored by non-tty ports */
1149 #ifdef TTY_GRAPHICS
1150 int tmp;
1151 if (!(op = string_for_opt(opts, TRUE))) {
1152 tmp = negated ? 's' : 'f';
1153 } else {
1154 if (negated) {
1155 bad_negation(fullname, TRUE);
1156 return;
1157 }
1158 tmp = tolower(*op);
1159 }
1160 switch (tmp) {
1161 case 's': /* single message history cycle (default if negated) */
1162 iflags.prevmsg_window = 's';
1163 break;
1164 case 'c': /* combination: two singles, then full page reversed */
1165 iflags.prevmsg_window = 'c';
1166 break;
1167 case 'f': /* full page (default if no opts) */
1168 iflags.prevmsg_window = 'f';
1169 break;
1170 case 'r': /* full page (reversed) */
1171 iflags.prevmsg_window = 'r';
1172 break;
1173 default:
1174 badoption(opts);
1175 }
1176 #endif
1177 return;
1178 }
1179
1180 /* WINCAP
1181 * setting font options */
1182 fullname = "font";
1183 if (!strncmpi(opts, fullname, 4))
1184 {
1185 int wintype = -1;
1186 char *fontopts = opts + 4;
1187
1188 if (!strncmpi(fontopts, "map", 3) ||
1189 !strncmpi(fontopts, "_map", 4))
1190 wintype = NHW_MAP;
1191 else if (!strncmpi(fontopts, "message", 7) ||
1192 !strncmpi(fontopts, "_message", 8))
1193 wintype = NHW_MESSAGE;
1194 else if (!strncmpi(fontopts, "text", 4) ||
1195 !strncmpi(fontopts, "_text", 5))
1196 wintype = NHW_TEXT;
1197 else if (!strncmpi(fontopts, "menu", 4) ||
1198 !strncmpi(fontopts, "_menu", 5))
1199 wintype = NHW_MENU;
1200 else if (!strncmpi(fontopts, "status", 6) ||
1201 !strncmpi(fontopts, "_status", 7))
1202 wintype = NHW_STATUS;
1203 else if (!strncmpi(fontopts, "_size", 5)) {
1204 if (!strncmpi(fontopts, "_size_map", 8))
1205 wintype = NHW_MAP;
1206 else if (!strncmpi(fontopts, "_size_message", 12))
1207 wintype = NHW_MESSAGE;
1208 else if (!strncmpi(fontopts, "_size_text", 9))
1209 wintype = NHW_TEXT;
1210 else if (!strncmpi(fontopts, "_size_menu", 9))
1211 wintype = NHW_MENU;
1212 else if (!strncmpi(fontopts, "_size_status", 11))
1213 wintype = NHW_STATUS;
1214 else {
1215 badoption(opts);
1216 return;
1217 }
1218 if (wintype > 0 && !negated &&
1219 (op = string_for_opt(opts, FALSE)) != 0) {
1220 switch(wintype) {
1221 case NHW_MAP:
1222 iflags.wc_fontsiz_map = atoi(op);
1223 break;
1224 case NHW_MESSAGE:
1225 iflags.wc_fontsiz_message = atoi(op);
1226 break;
1227 case NHW_TEXT:
1228 iflags.wc_fontsiz_text = atoi(op);
1229 break;
1230 case NHW_MENU:
1231 iflags.wc_fontsiz_menu = atoi(op);
1232 break;
1233 case NHW_STATUS:
1234 iflags.wc_fontsiz_status = atoi(op);
1235 break;
1236 }
1237 }
1238 return;
1239 } else {
1240 badoption(opts);
1241 }
1242 if (wintype > 0 &&
1243 (op = string_for_opt(opts, FALSE)) != 0) {
1244 wc_set_font_name(wintype, op);
1245 #ifdef MAC
1246 set_font_name (wintype, op);
1247 #endif
1248 return;
1249 } else if (negated) bad_negation(fullname, TRUE);
1250 return;
1251 }
1252 #ifdef CHANGE_COLOR
1253 if (match_optname(opts, "palette", 3, TRUE)
1254 # ifdef MAC
1255 || match_optname(opts, "hicolor", 3, TRUE)
1256 # endif
1257 ) {
1258 int color_number, color_incr;
1259
1260 # ifdef MAC
1261 if (match_optname(opts, "hicolor", 3, TRUE)) {
1262 if (negated) {
1263 bad_negation("hicolor", FALSE);
1264 return;
1265 }
1266 color_number = CLR_MAX + 4; /* HARDCODED inverse number */
1267 color_incr = -1;
1268 } else {
1269 # endif
1270 if (negated) {
1271 bad_negation("palette", FALSE);
1272 return;
1273 }
1274 color_number = 0;
1275 color_incr = 1;
1276 # ifdef MAC
1277 }
1278 # endif
1279 if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
1280 char *pt = op;
1281 int cnt, tmp, reverse;
1282 long rgb;
1283
1284 while (*pt && color_number >= 0) {
1285 cnt = 3;
1286 rgb = 0L;
1287 if (*pt == '-') {
1288 reverse = 1;
1289 pt++;
1290 } else {
1291 reverse = 0;
1292 }
1293 while (cnt-- > 0) {
1294 if (*pt && *pt != '/') {
1295 # ifdef AMIGA
1296 rgb <<= 4;
1297 # else
1298 rgb <<= 8;
1299 # endif
1300 tmp = *(pt++);
1301 if (isalpha(tmp)) {
1302 tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
1303 } else {
1304 tmp &= 0xf; /* Digits in ASCII too... */
1305 }
1306 # ifndef AMIGA
1307 /* Add an extra so we fill f -> ff and 0 -> 00 */
1308 rgb += tmp << 4;
1309 # endif
1310 rgb += tmp;
1311 }
1312 }
1313 if (*pt == '/') {
1314 pt++;
1315 }
1316 change_color(color_number, rgb, reverse);
1317 color_number += color_incr;
1318 }
1319 }
1320 if (!initial) {
1321 need_redraw = TRUE;
1322 }
1323 return;
1324 }
1325 #endif /* CHANGE_COLOR */
1326
1327 if (match_optname(opts, "fruit", 2, TRUE)) {
1328 char empty_str = '\0';
1329 op = string_for_opt(opts, negated);
1330 if (negated) {
1331 if (op) {
1332 bad_negation("fruit", TRUE);
1333 return;
1334 }
1335 op = &empty_str;
1336 goto goodfruit;
1337 }
1338 if (!op) return;
1339 if (!initial) {
1340 struct fruit *f;
1341
1342 num = 0;
1343 for(f=ffruit; f; f=f->nextf) {
1344 if (!strcmp(op, f->fname)) goto goodfruit;
1345 num++;
1346 }
1347 if (num >= 100) {
1348 pline("Doing that so many times isn't very fruitful.");
1349 return;
1350 }
1351 }
1352 goodfruit:
1353 nmcpy(pl_fruit, op, PL_FSIZ);
1354 /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */
1355 if (!*pl_fruit)
1356 nmcpy(pl_fruit, "slime mold", PL_FSIZ);
1357 if (!initial)
1358 (void)fruitadd(pl_fruit);
1359 /* If initial, then initoptions is allowed to do it instead
1360 * of here (initoptions always has to do it even if there's
1361 * no fruit option at all. Also, we don't want people
1362 * setting multiple fruits in their options.)
1363 */
1364 return;
1365 }
1366
1367 /* graphics:string */
1368 fullname = "graphics";
1369 if (match_optname(opts, fullname, 2, TRUE)) {
1370 if (negated) bad_negation(fullname, FALSE);
1371 else graphics_opts(opts, fullname, MAXPCHARS, 0);
1372 return;
1373 }
1374 fullname = "dungeon";
1375 if (match_optname(opts, fullname, 2, TRUE)) {
1376 if (negated) bad_negation(fullname, FALSE);
1377 else graphics_opts(opts, fullname, MAXDCHARS, 0);
1378 return;
1379 }
1380 fullname = "traps";
1381 if (match_optname(opts, fullname, 2, TRUE)) {
1382 if (negated) bad_negation(fullname, FALSE);
1383 else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS);
1384 return;
1385 }
1386 fullname = "effects";
1387 if (match_optname(opts, fullname, 2, TRUE)) {
1388 if (negated) bad_negation(fullname, FALSE);
1389 else
1390 graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS);
1391 return;
1392 }
1393
1394 /* objects:string */
1395 fullname = "objects";
1396 if (match_optname(opts, fullname, 7, TRUE)) {
1397 int length;
1398
1399 if (negated) {
1400 bad_negation(fullname, FALSE);
1401 return;
1402 }
1403 if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
1404 return;
1405 escapes(opts, opts);
1406
1407 /*
1408 * Override the default object class symbols. The first
1409 * object in the object class is the "random object". I
1410 * don't want to use 0 as an object class, so the "random
1411 * object" is basically a place holder.
1412 *
1413 * The object class symbols have already been initialized in
1414 * initoptions().
1415 */
1416 length = strlen(opts);
1417 if (length >= MAXOCLASSES)
1418 length = MAXOCLASSES-1; /* don't count RANDOM_OBJECT */
1419
1420 for (i = 0; i < length; i++)
1421 oc_syms[i+1] = (uchar) opts[i];
1422 return;
1423 }
1424
1425 /* monsters:string */
1426 fullname = "monsters";
1427 if (match_optname(opts, fullname, 8, TRUE)) {
1428 int length;
1429
1430 if (negated) {
1431 bad_negation(fullname, FALSE);
1432 return;
1433 }
1434 if (!(opts = string_for_env_opt(fullname, opts, FALSE)))
1435 return;
1436 escapes(opts, opts);
1437
1438 /* Override default mon class symbols set in initoptions(). */
1439 length = strlen(opts);
1440 if (length >= MAXMCLASSES)
1441 length = MAXMCLASSES-1; /* mon class 0 unused */
1442
1443 for (i = 0; i < length; i++)
1444 monsyms[i+1] = (uchar) opts[i];
1445 return;
1446 }
1447 fullname = "warnings";
1448 if (match_optname(opts, fullname, 5, TRUE)) {
1449 if (negated) bad_negation(fullname, FALSE);
1450 else warning_opts(opts, fullname);
1451 return;
1452 }
1453 /* boulder:symbol */
1454 fullname = "boulder";
1455 if (match_optname(opts, fullname, 7, TRUE)) {
1456 int clash = 0;
1457 if (negated) {
1458 bad_negation(fullname, FALSE);
1459 return;
1460 }
1461 /* if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */
1462 if (!(opts = string_for_opt(opts, FALSE)))
1463 return;
1464 escapes(opts, opts);
1465 if (def_char_to_monclass(opts[0]) != MAXMCLASSES)
1466 clash = 1;
1467 else if (opts[0] >= '1' && opts[0] <= '5')
1468 clash = 2;
1469 if (clash) {
1470 /* symbol chosen matches a used monster or warning
1471 symbol which is not good - reject it*/
1472 pline(
1473 "Badoption - boulder symbol '%c' conflicts with a %s symbol.",
1474 opts[0], (clash == 1) ? "monster" : "warning");
1475 } else {
1476 /*
1477 * Override the default boulder symbol.
1478 */
1479 iflags.bouldersym = (uchar) opts[0];
1480 }
1481 if (!initial) need_redraw = TRUE;
1482 return;
1483 }
1484
1485 /* name:string */
1486 fullname = "name";
1487 if (match_optname(opts, fullname, 4, TRUE)) {
1488 if (negated) bad_negation(fullname, FALSE);
1489 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1490 nmcpy(plname, op, PL_NSIZ);
1491 return;
1492 }
1493
1494 /* role:string or character:string */
1495 fullname = "role";
1496 if (match_optname(opts, fullname, 4, TRUE) ||
1497 match_optname(opts, (fullname = "character"), 4, TRUE)) {
1498 if (negated) bad_negation(fullname, FALSE);
1499 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1500 if ((flags.initrole = str2role(op)) == ROLE_NONE)
1501 badoption(opts);
1502 else /* Backwards compatibility */
1503 nmcpy(pl_character, op, PL_NSIZ);
1504 }
1505 return;
1506 }
1507
1508 /* race:string */
1509 fullname = "race";
1510 if (match_optname(opts, fullname, 4, TRUE)) {
1511 if (negated) bad_negation(fullname, FALSE);
1512 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1513 if ((flags.initrace = str2race(op)) == ROLE_NONE)
1514 badoption(opts);
1515 else /* Backwards compatibility */
1516 pl_race = *op;
1517 }
1518 return;
1519 }
1520
1521 /* gender:string */
1522 fullname = "gender";
1523 if (match_optname(opts, fullname, 4, TRUE)) {
1524 if (negated) bad_negation(fullname, FALSE);
1525 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1526 if ((flags.initgend = str2gend(op)) == ROLE_NONE)
1527 badoption(opts);
1528 else
1529 flags.female = flags.initgend;
1530 }
1531 return;
1532 }
1533
1534 /* altkeyhandler:string */
1535 fullname = "altkeyhandler";
1536 if (match_optname(opts, fullname, 4, TRUE)) {
1537 if (negated) bad_negation(fullname, FALSE);
1538 else if ((op = string_for_opt(opts, negated))) {
1539 #ifdef WIN32CON
1540 (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
1541 load_keyboard_handler();
1542 #endif
1543 }
1544 return;
1545 }
1546
1547 /* WINCAP
1548 * align_status:[left|top|right|bottom] */
1549 fullname = "align_status";
1550 if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) {
1551 op = string_for_opt(opts, negated);
1552 if (op && !negated) {
1553 if (!strncmpi (op, "left", sizeof("left")-1))
1554 iflags.wc_align_status = ALIGN_LEFT;
1555 else if (!strncmpi (op, "top", sizeof("top")-1))
1556 iflags.wc_align_status = ALIGN_TOP;
1557 else if (!strncmpi (op, "right", sizeof("right")-1))
1558 iflags.wc_align_status = ALIGN_RIGHT;
1559 else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
1560 iflags.wc_align_status = ALIGN_BOTTOM;
1561 else
1562 badoption(opts);
1563 } else if (negated) bad_negation(fullname, TRUE);
1564 return;
1565 }
1566 /* WINCAP
1567 * align_message:[left|top|right|bottom] */
1568 fullname = "align_message";
1569 if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) {
1570 op = string_for_opt(opts, negated);
1571 if (op && !negated) {
1572 if (!strncmpi (op, "left", sizeof("left")-1))
1573 iflags.wc_align_message = ALIGN_LEFT;
1574 else if (!strncmpi (op, "top", sizeof("top")-1))
1575 iflags.wc_align_message = ALIGN_TOP;
1576 else if (!strncmpi (op, "right", sizeof("right")-1))
1577 iflags.wc_align_message = ALIGN_RIGHT;
1578 else if (!strncmpi (op, "bottom", sizeof("bottom")-1))
1579 iflags.wc_align_message = ALIGN_BOTTOM;
1580 else
1581 badoption(opts);
1582 } else if (negated) bad_negation(fullname, TRUE);
1583 return;
1584 }
1585 /* align:string */
1586 fullname = "align";
1587 if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) {
1588 if (negated) bad_negation(fullname, FALSE);
1589 else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
1590 if ((flags.initalign = str2align(op)) == ROLE_NONE)
1591 badoption(opts);
1592 return;
1593 }
1594
1595 /* the order to list the pack */
1596 fullname = "packorder";
1597 if (match_optname(opts, fullname, 4, TRUE)) {
1598 if (negated) {
1599 bad_negation(fullname, FALSE);
1600 return;
1601 } else if (!(op = string_for_opt(opts, FALSE))) return;
1602
1603 if (!change_inv_order(op))
1604 badoption(opts);
1605 return;
1606 }
1607
1608 /* maximum burden picked up before prompt (Warren Cheung) */
1609 fullname = "pickup_burden";
1610 if (match_optname(opts, fullname, 8, TRUE)) {
1611 if (negated) {
1612 bad_negation(fullname, FALSE);
1613 return;
1614 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
1615 switch (tolower(*op)) {
1616 /* Unencumbered */
1617 case 'u':
1618 flags.pickup_burden = UNENCUMBERED;
1619 break;
1620 /* Burdened (slight encumbrance) */
1621 case 'b':
1622 flags.pickup_burden = SLT_ENCUMBER;
1623 break;
1624 /* streSsed (moderate encumbrance) */
1625 case 's':
1626 flags.pickup_burden = MOD_ENCUMBER;
1627 break;
1628 /* straiNed (heavy encumbrance) */
1629 case 'n':
1630 flags.pickup_burden = HVY_ENCUMBER;
1631 break;
1632 /* OverTaxed (extreme encumbrance) */
1633 case 'o':
1634 case 't':
1635 flags.pickup_burden = EXT_ENCUMBER;
1636 break;
1637 /* overLoaded */
1638 case 'l':
1639 flags.pickup_burden = OVERLOADED;
1640 break;
1641 default:
1642 badoption(opts);
1643 }
1644 }
1645 return;
1646 }
1647
1648 /* types of objects to pick up automatically */
1649 if (match_optname(opts, "pickup_types", 8, TRUE)) {
1650 char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1],
1651 qbuf[QBUFSZ], abuf[BUFSZ];
1652 int oc_sym;
1653 boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu;
1654
1655 oc_to_str(flags.pickup_types, tbuf);
1656 flags.pickup_types[0] = '\0'; /* all */
1657 op = string_for_opt(opts, (compat || !initial));
1658 if (!op) {
1659 if (compat || negated || initial) {
1660 /* for backwards compatibility, "pickup" without a
1661 value is a synonym for autopickup of all types
1662 (and during initialization, we can't prompt yet) */
1663 flags.pickup = !negated;
1664 return;
1665 }
1666 oc_to_str(flags.inv_order, ocl);
1667 use_menu = TRUE;
1668 if (flags.menu_style == MENU_TRADITIONAL ||
1669 flags.menu_style == MENU_COMBINATION) {
1670 use_menu = FALSE;
1671 Sprintf(qbuf, "New pickup_types: [%s am] (%s)",
1672 ocl, *tbuf ? tbuf : "all");
1673 getlin(qbuf, abuf);
1674 op = mungspaces(abuf);
1675 if (abuf[0] == '\0' || abuf[0] == '\033')
1676 op = tbuf; /* restore */
1677 else if (abuf[0] == 'm')
1678 use_menu = TRUE;
1679 }
1680 if (use_menu) {
1681 (void) choose_classes_menu("Auto-Pickup what?", 1,
1682 TRUE, ocl, tbuf);
1683 op = tbuf;
1684 }
1685 }
1686 if (negated) {
1687 bad_negation("pickup_types", TRUE);
1688 return;
1689 }
1690 while (*op == ' ') op++;
1691 if (*op != 'a' && *op != 'A') {
1692 num = 0;
1693 while (*op) {
1694 oc_sym = def_char_to_objclass(*op);
1695 /* make sure all are valid obj symbols occuring once */
1696 if (oc_sym != MAXOCLASSES &&
1697 !index(flags.pickup_types, oc_sym)) {
1698 flags.pickup_types[num] = (char)oc_sym;
1699 flags.pickup_types[++num] = '\0';
1700 } else
1701 badopt = TRUE;
1702 op++;
1703 }
1704 if (badopt) badoption(opts);
1705 }
1706 return;
1707 }
1708 /* WINCAP
1709 * player_selection: dialog | prompts */
1710 fullname = "player_selection";
1711 if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) {
1712 op = string_for_opt(opts, negated);
1713 if (op && !negated) {
1714 if (!strncmpi (op, "dialog", sizeof("dialog")-1))
1715 iflags.wc_player_selection = VIA_DIALOG;
1716 else if (!strncmpi (op, "prompt", sizeof("prompt")-1))
1717 iflags.wc_player_selection = VIA_PROMPTS;
1718 else
1719 badoption(opts);
1720 } else if (negated) bad_negation(fullname, TRUE);
1721 return;
1722 }
1723
1724 /* things to disclose at end of game */
1725 if (match_optname(opts, "disclose", 7, TRUE)) {
1726 /*
1727 * The order that the end_disclore options are stored:
1728 * inventory, attribs, vanquished, genocided, conduct
1729 * There is an array in flags:
1730 * end_disclose[NUM_DISCLOSURE_OPT];
1731 * with option settings for the each of the following:
1732 * iagvc [see disclosure_options in decl.c]:
1733 * Legal setting values in that array are:
1734 * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes
1735 * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no
1736 * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask
1737 * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask
1738 *
1739 * Those setting values can be used in the option
1740 * string as a prefix to get the desired behaviour.
1741 *
1742 * For backward compatibility, no prefix is required,
1743 * and the presence of a i,a,g,v, or c without a prefix
1744 * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT.
1745 */
1746 boolean badopt = FALSE;
1747 int idx, prefix_val;
1748
1749 op = string_for_opt(opts, TRUE);
1750 if (op && negated) {
1751 bad_negation("disclose", TRUE);
1752 return;
1753 }
1754 /* "disclose" without a value means "all with prompting"
1755 and negated means "none without prompting" */
1756 if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) {
1757 if (op && !strcmpi(op, "none")) negated = TRUE;
1758 for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++)
1759 flags.end_disclose[num] = negated ?
1760 DISCLOSE_NO_WITHOUT_PROMPT :
1761 DISCLOSE_PROMPT_DEFAULT_YES;
1762 return;
1763 }
1764
1765 num = 0;
1766 prefix_val = -1;
1767 while (*op && num < sizeof flags.end_disclose - 1) {
1768 register char c, *dop;
1769 static char valid_settings[] = {
1770 DISCLOSE_PROMPT_DEFAULT_YES,
1771 DISCLOSE_PROMPT_DEFAULT_NO,
1772 DISCLOSE_YES_WITHOUT_PROMPT,
1773 DISCLOSE_NO_WITHOUT_PROMPT,
1774 '\0'
1775 };
1776 c = lowc(*op);
1777 if (c == 'k') c = 'v'; /* killed -> vanquished */
1778 dop = index(disclosure_options, c);
1779 if (dop) {
1780 idx = dop - disclosure_options;
1781 if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) {
1782 impossible("bad disclosure index %d %c",
1783 idx, c);
1784 continue;
1785 }
1786 if (prefix_val != -1) {
1787 flags.end_disclose[idx] = prefix_val;
1788 prefix_val = -1;
1789 } else
1790 flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT;
1791 } else if (index(valid_settings, c)) {
1792 prefix_val = c;
1793 } else if (c == ' ') {
1794 /* do nothing */
1795 } else
1796 badopt = TRUE;
1797 op++;
1798 }
1799 if (badopt) badoption(opts);
1800 return;
1801 }
1802
1803 /* scores:5t[op] 5a[round] o[wn] */
1804 if (match_optname(opts, "scores", 4, TRUE)) {
1805 if (negated) {
1806 bad_negation("scores", FALSE);
1807 return;
1808 }
1809 if (!(op = string_for_opt(opts, FALSE))) return;
1810
1811 while (*op) {
1812 int inum = 1;
1813
1814 if (digit(*op)) {
1815 inum = atoi(op);
1816 while (digit(*op)) op++;
1817 } else if (*op == '!') {
1818 negated = !negated;
1819 op++;
1820 }
1821 while (*op == ' ') op++;
1822
1823 switch (*op) {
1824 case 't':
1825 case 'T': flags.end_top = inum;
1826 break;
1827 case 'a':
1828 case 'A': flags.end_around = inum;
1829 break;
1830 case 'o':
1831 case 'O': flags.end_own = !negated;
1832 break;
1833 default: badoption(opts);
1834 return;
1835 }
1836 while (letter(*++op) || *op == ' ') continue;
1837 if (*op == '/') op++;
1838 }
1839 return;
1840 }
1841
1842 fullname = "suppress_alert";
1843 if (match_optname(opts, fullname, 4, TRUE)) {
1844 op = string_for_opt(opts, negated);
1845 if (negated) bad_negation(fullname, FALSE);
1846 else if (op) (void) feature_alert_opts(op,fullname);
1847 return;
1848 }
1849
1850 #ifdef VIDEOSHADES
1851 /* videocolors:string */
1852 fullname = "videocolors";
1853 if (match_optname(opts, fullname, 6, TRUE) ||
1854 match_optname(opts, "videocolours", 10, TRUE)) {
1855 if (negated) {
1856 bad_negation(fullname, FALSE);
1857 return;
1858 }
1859 else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
1860 return;
1861 }
1862 if (!assign_videocolors(opts))
1863 badoption(opts);
1864 return;
1865 }
1866 /* videoshades:string */
1867 fullname = "videoshades";
1868 if (match_optname(opts, fullname, 6, TRUE)) {
1869 if (negated) {
1870 bad_negation(fullname, FALSE);
1871 return;
1872 }
1873 else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
1874 return;
1875 }
1876 if (!assign_videoshades(opts))
1877 badoption(opts);
1878 return;
1879 }
1880 #endif /* VIDEOSHADES */
1881 #ifdef MSDOS
1882 # ifdef NO_TERMS
1883 /* video:string -- must be after longer tests */
1884 fullname = "video";
1885 if (match_optname(opts, fullname, 5, TRUE)) {
1886 if (negated) {
1887 bad_negation(fullname, FALSE);
1888 return;
1889 }
1890 else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
1891 return;
1892 }
1893 if (!assign_video(opts))
1894 badoption(opts);
1895 return;
1896 }
1897 # endif /* NO_TERMS */
1898 /* soundcard:string -- careful not to match boolean 'sound' */
1899 fullname = "soundcard";
1900 if (match_optname(opts, fullname, 6, TRUE)) {
1901 if (negated) {
1902 bad_negation(fullname, FALSE);
1903 return;
1904 }
1905 else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
1906 return;
1907 }
1908 if (!assign_soundcard(opts))
1909 badoption(opts);
1910 return;
1911 }
1912 #endif /* MSDOS */
1913
1914 /* WINCAP
1915 * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12|
1916 ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */
1917 fullname = "map_mode";
1918 if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) {
1919 op = string_for_opt(opts, negated);
1920 if (op && !negated) {
1921 if (!strncmpi (op, "tiles", sizeof("tiles")-1))
1922 iflags.wc_map_mode = MAP_MODE_TILES;
1923 else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1))
1924 iflags.wc_map_mode = MAP_MODE_ASCII4x6;
1925 else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1))
1926 iflags.wc_map_mode = MAP_MODE_ASCII6x8;
1927 else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1))
1928 iflags.wc_map_mode = MAP_MODE_ASCII8x8;
1929 else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1))
1930 iflags.wc_map_mode = MAP_MODE_ASCII16x8;
1931 else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1))
1932 iflags.wc_map_mode = MAP_MODE_ASCII7x12;
1933 else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1))
1934 iflags.wc_map_mode = MAP_MODE_ASCII8x12;
1935 else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1))
1936 iflags.wc_map_mode = MAP_MODE_ASCII16x12;
1937 else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1))
1938 iflags.wc_map_mode = MAP_MODE_ASCII12x16;
1939 else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1))
1940 iflags.wc_map_mode = MAP_MODE_ASCII10x18;
1941 else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1))
1942 iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN;
1943 else
1944 badoption(opts);
1945 } else if (negated) bad_negation(fullname, TRUE);
1946 return;
1947 }
1948 /* WINCAP
1949 * scroll_amount:nn */
1950 fullname = "scroll_amount";
1951 if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) {
1952 op = string_for_opt(opts, negated);
1953 if ((negated && !op) || (!negated && op)) {
1954 iflags.wc_scroll_amount = negated ? 1 : atoi(op);
1955 } else if (negated) bad_negation(fullname, TRUE);
1956 return;
1957 }
1958 /* WINCAP
1959 * scroll_margin:nn */
1960 fullname = "scroll_margin";
1961 if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) {
1962 op = string_for_opt(opts, negated);
1963 if ((negated && !op) || (!negated && op)) {
1964 iflags.wc_scroll_margin = negated ? 5 : atoi(op);
1965 } else if (negated) bad_negation(fullname, TRUE);
1966 return;
1967 }
1968 fullname = "subkeyvalue";
1969 if (match_optname(opts, fullname, 5, TRUE)) {
1970 if (negated) bad_negation(fullname, FALSE);
1971 else {
1972 #if defined(WIN32CON)
1973 op = string_for_opt(opts, 0);
1974 map_subkeyvalue(op);
1975 #endif
1976 }
1977 return;
1978 }
1979 /* WINCAP
1980 * tile_width:nn */
1981 fullname = "tile_width";
1982 if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) {
1983 op = string_for_opt(opts, negated);
1984 if ((negated && !op) || (!negated && op)) {
1985 iflags.wc_tile_width = negated ? 0 : atoi(op);
1986 } else if (negated) bad_negation(fullname, TRUE);
1987 return;
1988 }
1989 /* WINCAP
1990 * tile_file:name */
1991 fullname = "tile_file";
1992 if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) {
1993 if ((op = string_for_opt(opts, FALSE)) != 0) {
1994 if (iflags.wc_tile_file) free(iflags.wc_tile_file);
1995 iflags.wc_tile_file = (char *)alloc(strlen(op) + 1);
1996 Strcpy(iflags.wc_tile_file, op);
1997 }
1998 return;
1999 }
2000 /* WINCAP
2001 * tile_height:nn */
2002 fullname = "tile_height";
2003 if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) {
2004 op = string_for_opt(opts, negated);
2005 if ((negated && !op) || (!negated && op)) {
2006 iflags.wc_tile_height = negated ? 0 : atoi(op);
2007 } else if (negated) bad_negation(fullname, TRUE);
2008 return;
2009 }
2010 /* WINCAP
2011 * vary_msgcount:nn */
2012 fullname = "vary_msgcount";
2013 if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) {
2014 op = string_for_opt(opts, negated);
2015 if ((negated && !op) || (!negated && op)) {
2016 iflags.wc_vary_msgcount = negated ? 0 : atoi(op);
2017 } else if (negated) bad_negation(fullname, TRUE);
2018 return;
2019 }
2020 fullname = "windowtype";
2021 if (match_optname(opts, fullname, 3, TRUE)) {
2022 if (negated) {
2023 bad_negation(fullname, FALSE);
2024 return;
2025 } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
2026 char buf[WINTYPELEN];
2027 nmcpy(buf, op, WINTYPELEN);
2028 choose_windows(buf);
2029 }
2030 return;
2031 }
2032
2033 /* WINCAP
2034 * setting window colors
2035 * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd
2036 */
2037 fullname = "windowcolors";
2038 if (match_optname(opts, fullname, 7, TRUE)) {
2039 if ((op = string_for_opt(opts, FALSE)) != 0) {
2040 if (!wc_set_window_colors(op))
2041 badoption(opts);
2042 } else if (negated) bad_negation(fullname, TRUE);
2043 return;
2044 }
2045
2046 /* menustyle:traditional or combo or full or partial */
2047 if (match_optname(opts, "menustyle", 4, TRUE)) {
2048 int tmp;
2049 boolean val_required = (strlen(opts) > 5 && !negated);
2050
2051 if (!(op = string_for_opt(opts, !val_required))) {
2052 if (val_required) return; /* string_for_opt gave feedback */
2053 tmp = negated ? 'n' : 'f';
2054 } else {
2055 tmp = tolower(*op);
2056 }
2057 switch (tmp) {
2058 case 'n': /* none */
2059 case 't': /* traditional */
2060 flags.menu_style = MENU_TRADITIONAL;
2061 break;
2062 case 'c': /* combo: trad.class sel+menu */
2063 flags.menu_style = MENU_COMBINATION;
2064 break;
2065 case 'p': /* partial: no class menu */
2066 flags.menu_style = MENU_PARTIAL;
2067 break;
2068 case 'f': /* full: class menu + menu */
2069 flags.menu_style = MENU_FULL;
2070 break;
2071 default:
2072 badoption(opts);
2073 }
2074 return;
2075 }
2076
2077 fullname = "menu_headings";
2078 if (match_optname(opts, fullname, 12, TRUE)) {
2079 if (negated) {
2080 bad_negation(fullname, FALSE);
2081 return;
2082 }
2083 else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) {
2084 return;
2085 }
2086 if (!strcmpi(opts,"bold"))
2087 iflags.menu_headings = ATR_BOLD;
2088 else if (!strcmpi(opts,"inverse"))
2089 iflags.menu_headings = ATR_INVERSE;
2090 else if (!strcmpi(opts,"underline"))
2091 iflags.menu_headings = ATR_ULINE;
2092 else
2093 badoption(opts);
2094 return;
2095 }
2096
2097 /* check for menu command mapping */
2098 for (i = 0; i < NUM_MENU_CMDS; i++) {
2099 fullname = default_menu_cmd_info[i].name;
2100 if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) {
2101 if (negated)
2102 bad_negation(fullname, FALSE);
2103 else if ((op = string_for_opt(opts, FALSE)) != 0) {
2104 int j;
2105 char c, op_buf[BUFSZ];
2106 boolean isbad = FALSE;
2107
2108 escapes(op, op_buf);
2109 c = *op_buf;
2110
2111 if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||
2112 c == ' ' || digit(c) || (letter(c) && c != '@'))
2113 isbad = TRUE;
2114 else /* reject default object class symbols */
2115 for (j = 1; j < MAXOCLASSES; j++)
2116 if (c == def_oc_syms[i]) {
2117 isbad = TRUE;
2118 break;
2119 }
2120
2121 if (isbad)
2122 badoption(opts);
2123 else
2124 add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd);
2125 }
2126 return;
2127 }
2128 }
2129
2130 /* OK, if we still haven't recognized the option, check the boolean
2131 * options list
2132 */
2133 for (i = 0; boolopt[i].name; i++) {
2134 if (match_optname(opts, boolopt[i].name, 3, FALSE)) {
2135 /* options that don't exist */
2136 if (!boolopt[i].addr) {
2137 if (!initial && !negated)
2138 pline_The("\"%s\" option is not available.",
2139 boolopt[i].name);
2140 return;
2141 }
2142 /* options that must come from config file */
2143 if (!initial && (boolopt[i].optflags == SET_IN_FILE)) {
2144 rejectoption(boolopt[i].name);
2145 return;
2146 }
2147
2148 *(boolopt[i].addr) = !negated;
2149
2150 duplicate_opt_detection(boolopt[i].name, 0);
2151
2152 #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV)
2153 if (FALSE
2154 # ifdef TERMLIB
2155 || (boolopt[i].addr) == &iflags.DECgraphics
2156 # endif
2157 # ifdef ASCIIGRAPH
2158 || (boolopt[i].addr) == &iflags.IBMgraphics
2159 # endif
2160 # ifdef MAC_GRAPHICS_ENV
2161 || (boolopt[i].addr) == &iflags.MACgraphics
2162 # endif
2163 ) {
2164 # ifdef REINCARNATION
2165 if (!initial && Is_rogue_level(&u.uz))
2166 assign_rogue_graphics(FALSE);
2167 # endif
2168 need_redraw = TRUE;
2169 # ifdef TERMLIB
2170 if ((boolopt[i].addr) == &iflags.DECgraphics)
2171 switch_graphics(iflags.DECgraphics ?
2172 DEC_GRAPHICS : ASCII_GRAPHICS);
2173 # endif
2174 # ifdef ASCIIGRAPH
2175 if ((boolopt[i].addr) == &iflags.IBMgraphics)
2176 switch_graphics(iflags.IBMgraphics ?
2177 IBM_GRAPHICS : ASCII_GRAPHICS);
2178 # endif
2179 # ifdef MAC_GRAPHICS_ENV
2180 if ((boolopt[i].addr) == &iflags.MACgraphics)
2181 switch_graphics(iflags.MACgraphics ?
2182 MAC_GRAPHICS : ASCII_GRAPHICS);
2183 # endif
2184 # ifdef REINCARNATION
2185 if (!initial && Is_rogue_level(&u.uz))
2186 assign_rogue_graphics(TRUE);
2187 # endif
2188 }
2189 #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */
2190
2191 /* only do processing below if setting with doset() */
2192 if (initial) return;
2193
2194 if ((boolopt[i].addr) == &flags.time
2195 #ifdef EXP_ON_BOTL
2196 || (boolopt[i].addr) == &flags.showexp
2197 #endif
2198 #ifdef SCORE_ON_BOTL
2199 || (boolopt[i].addr) == &flags.showscore
2200 #endif
2201 )
2202 flags.botl = TRUE;
2203
2204 else if ((boolopt[i].addr) == &flags.invlet_constant) {
2205 if (flags.invlet_constant) reassign();
2206 }
2207 #ifdef LAN_MAIL
2208 else if ((boolopt[i].addr) == &flags.biff) {
2209 if (flags.biff) lan_mail_init();
2210 else lan_mail_finish();
2211 }
2212 #endif
2213 else if ((boolopt[i].addr) == &flags.lit_corridor) {
2214 /*
2215 * All corridor squares seen via night vision or
2216 * candles & lamps change. Update them by calling
2217 * newsym() on them. Don't do this if we are
2218 * initializing the options --- the vision system
2219 * isn't set up yet.
2220 */
2221 vision_recalc(2); /* shut down vision */
2222 vision_full_recalc = 1; /* delayed recalc */
2223 }
2224 else if ((boolopt[i].addr) == &iflags.use_inverse ||
2225 (boolopt[i].addr) == &iflags.showrace ||
2226 (boolopt[i].addr) == &iflags.hilite_pet) {
2227 need_redraw = TRUE;
2228 }
2229 #ifdef TEXTCOLOR
2230 else if ((boolopt[i].addr) == &iflags.use_color) {
2231 need_redraw = TRUE;
2232 # ifdef TOS
2233 if ((boolopt[i].addr) == &iflags.use_color
2234 && iflags.BIOS) {
2235 if (colors_changed)
2236 restore_colors();
2237 else
2238 set_colors();
2239 }
2240 # endif
2241 }
2242 #endif
2243
2244 return;
2245 }
2246 }
2247
2248 /* out of valid options */
2249 badoption(opts);
2250 }
2251
2252
2253 static NEARDATA const char *menutype[] = {
2254 "traditional", "combination", "partial", "full"
2255 };
2256
2257 static NEARDATA const char *burdentype[] = {
2258 "unencumbered", "burdened", "stressed",
2259 "strained", "overtaxed", "overloaded"
2260 };
2261
2262 static NEARDATA const char *runmodes[] = {
2263 "teleport", "run", "walk", "crawl"
2264 };
2265
2266 /*
2267 * Convert the given string of object classes to a string of default object
2268 * symbols.
2269 */
2270 STATIC_OVL void
oc_to_str(src,dest)2271 oc_to_str(src,dest)
2272 char *src, *dest;
2273 {
2274 int i;
2275
2276 while ((i = (int) *src++) != 0) {
2277 if (i < 0 || i >= MAXOCLASSES)
2278 impossible("oc_to_str: illegal object class %d", i);
2279 else
2280 *dest++ = def_oc_syms[i];
2281 }
2282 *dest = '\0';
2283 }
2284
2285 /*
2286 * Add the given mapping to the menu command map list. Always keep the
2287 * maps valid C strings.
2288 */
2289 void
add_menu_cmd_alias(from_ch,to_ch)2290 add_menu_cmd_alias(from_ch, to_ch)
2291 char from_ch, to_ch;
2292 {
2293 if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS)
2294 pline("out of menu map space.");
2295 else {
2296 mapped_menu_cmds[n_menu_mapped] = from_ch;
2297 mapped_menu_op[n_menu_mapped] = to_ch;
2298 n_menu_mapped++;
2299 mapped_menu_cmds[n_menu_mapped] = 0;
2300 mapped_menu_op[n_menu_mapped] = 0;
2301 }
2302 }
2303
2304 /*
2305 * Map the given character to its corresponding menu command. If it
2306 * doesn't match anything, just return the original.
2307 */
2308 char
map_menu_cmd(ch)2309 map_menu_cmd(ch)
2310 char ch;
2311 {
2312 char *found = index(mapped_menu_cmds, ch);
2313 if (found) {
2314 int idx = found - mapped_menu_cmds;
2315 ch = mapped_menu_op[idx];
2316 }
2317 return ch;
2318 }
2319
2320
2321 #if defined(MICRO) || defined(MAC) || defined(WIN32)
2322 # define OPTIONS_HEADING "OPTIONS"
2323 #else
2324 # define OPTIONS_HEADING "NETHACKOPTIONS"
2325 #endif
2326
2327 static char fmtstr_doset_add_menu[] = "%s%-15s [%s] ";
2328 static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]";
2329
2330 STATIC_OVL void
doset_add_menu(win,option,indexoffset)2331 doset_add_menu(win, option, indexoffset)
2332 winid win; /* window to add to */
2333 const char *option; /* option name */
2334 int indexoffset; /* value to add to index in compopt[], or zero
2335 if option cannot be changed */
2336 {
2337 const char *value = "unknown"; /* current value */
2338 char buf[BUFSZ], buf2[BUFSZ];
2339 anything any;
2340 int i;
2341
2342 any.a_void = 0;
2343 if (indexoffset == 0) {
2344 any.a_int = 0;
2345 value = get_compopt_value(option, buf2);
2346 } else {
2347 for (i=0; compopt[i].name; i++)
2348 if (strcmp(option, compopt[i].name) == 0) break;
2349
2350 if (compopt[i].name) {
2351 any.a_int = i + 1 + indexoffset;
2352 value = get_compopt_value(option, buf2);
2353 } else {
2354 /* We are trying to add an option not found in compopt[].
2355 This is almost certainly bad, but we'll let it through anyway
2356 (with a zero value, so it can't be selected). */
2357 any.a_int = 0;
2358 }
2359 }
2360 /* " " replaces "a - " -- assumes menus follow that style */
2361 if (!iflags.menu_tab_sep)
2362 Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", option, value);
2363 else
2364 Sprintf(buf, fmtstr_doset_add_menu_tab, option, value);
2365 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
2366 }
2367
2368 /* Changing options via menu by Per Liboriussen */
2369 int
doset()2370 doset()
2371 {
2372 char buf[BUFSZ], buf2[BUFSZ];
2373 int i, pass, boolcount, pick_cnt, pick_idx, opt_indx;
2374 boolean *bool_p;
2375 winid tmpwin;
2376 anything any;
2377 menu_item *pick_list;
2378 int indexoffset, startpass, endpass;
2379 boolean setinitial = FALSE, fromfile = FALSE;
2380 int biggest_name = 0;
2381
2382 tmpwin = create_nhwindow(NHW_MENU);
2383 start_menu(tmpwin);
2384
2385 any.a_void = 0;
2386 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2387 "Booleans (selecting will toggle value):", MENU_UNSELECTED);
2388 any.a_int = 0;
2389 /* first list any other non-modifiable booleans, then modifiable ones */
2390 for (pass = 0; pass <= 1; pass++)
2391 for (i = 0; boolopt[i].name; i++)
2392 if ((bool_p = boolopt[i].addr) != 0 &&
2393 ((boolopt[i].optflags == DISP_IN_GAME && pass == 0) ||
2394 (boolopt[i].optflags == SET_IN_GAME && pass == 1))) {
2395 if (bool_p == &flags.female) continue; /* obsolete */
2396 #ifdef WIZARD
2397 if (bool_p == &iflags.sanity_check && !wizard) continue;
2398 if (bool_p == &iflags.menu_tab_sep && !wizard) continue;
2399 #endif
2400 if (is_wc_option(boolopt[i].name) &&
2401 !wc_supported(boolopt[i].name)) continue;
2402 if (is_wc2_option(boolopt[i].name) &&
2403 !wc2_supported(boolopt[i].name)) continue;
2404 any.a_int = (pass == 0) ? 0 : i + 1;
2405 if (!iflags.menu_tab_sep)
2406 Sprintf(buf, "%s%-13s [%s]",
2407 pass == 0 ? " " : "",
2408 boolopt[i].name, *bool_p ? "true" : "false");
2409 else
2410 Sprintf(buf, "%s\t[%s]",
2411 boolopt[i].name, *bool_p ? "true" : "false");
2412 add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
2413 ATR_NONE, buf, MENU_UNSELECTED);
2414 }
2415
2416 boolcount = i;
2417 indexoffset = boolcount;
2418 any.a_void = 0;
2419 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2420 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2421 "Compounds (selecting will prompt for new value):",
2422 MENU_UNSELECTED);
2423
2424 startpass = DISP_IN_GAME;
2425 endpass = SET_IN_GAME;
2426
2427 /* spin through the options to find the biggest name
2428 and adjust the format string accordingly if needed */
2429 biggest_name = 0;
2430 for (i = 0; compopt[i].name; i++)
2431 if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass &&
2432 strlen(compopt[i].name) > (unsigned) biggest_name)
2433 biggest_name = (int) strlen(compopt[i].name);
2434 if (biggest_name > 30) biggest_name = 30;
2435 if (!iflags.menu_tab_sep)
2436 Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name);
2437
2438 /* deliberately put `name', `role', `race', `gender' first */
2439 doset_add_menu(tmpwin, "name", 0);
2440 doset_add_menu(tmpwin, "role", 0);
2441 doset_add_menu(tmpwin, "race", 0);
2442 doset_add_menu(tmpwin, "gender", 0);
2443
2444 for (pass = startpass; pass <= endpass; pass++)
2445 for (i = 0; compopt[i].name; i++)
2446 if (compopt[i].optflags == pass) {
2447 if (!strcmp(compopt[i].name, "name") ||
2448 !strcmp(compopt[i].name, "role") ||
2449 !strcmp(compopt[i].name, "race") ||
2450 !strcmp(compopt[i].name, "gender"))
2451 continue;
2452 else if (is_wc_option(compopt[i].name) &&
2453 !wc_supported(compopt[i].name))
2454 continue;
2455 else if (is_wc2_option(compopt[i].name) &&
2456 !wc2_supported(compopt[i].name))
2457 continue;
2458 else
2459 doset_add_menu(tmpwin, compopt[i].name,
2460 (pass == DISP_IN_GAME) ? 0 : indexoffset);
2461 }
2462 #ifdef AUTOPICKUP_EXCEPTIONS
2463 any.a_int = -1;
2464 Sprintf(buf, "autopickup exceptions (%d currently set)",
2465 count_ape_maps((int *)0, (int *)0));
2466 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
2467
2468 #endif /* AUTOPICKUP_EXCEPTIONS */
2469 #ifdef PREFIXES_IN_USE
2470 any.a_void = 0;
2471 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2472 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2473 "Variable playground locations:", MENU_UNSELECTED);
2474 for (i = 0; i < PREFIX_COUNT; i++)
2475 doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
2476 #endif
2477 end_menu(tmpwin, "Set what options?");
2478 need_redraw = FALSE;
2479 if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
2480 /*
2481 * Walk down the selection list and either invert the booleans
2482 * or prompt for new values. In most cases, call parseoptions()
2483 * to take care of options that require special attention, like
2484 * redraws.
2485 */
2486 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
2487 opt_indx = pick_list[pick_idx].item.a_int - 1;
2488 #ifdef AUTOPICKUP_EXCEPTIONS
2489 if (opt_indx == -2) {
2490 special_handling("autopickup_exception",
2491 setinitial, fromfile);
2492 } else
2493 #endif
2494 if (opt_indx < boolcount) {
2495 /* boolean option */
2496 Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
2497 boolopt[opt_indx].name);
2498 parseoptions(buf, setinitial, fromfile);
2499 if (wc_supported(boolopt[opt_indx].name) ||
2500 wc2_supported(boolopt[opt_indx].name))
2501 preference_update(boolopt[opt_indx].name);
2502 } else {
2503 /* compound option */
2504 opt_indx -= boolcount;
2505
2506 if (!special_handling(compopt[opt_indx].name,
2507 setinitial, fromfile)) {
2508 Sprintf(buf, "Set %s to what?", compopt[opt_indx].name);
2509 getlin(buf, buf2);
2510 if (buf2[0] == '\033')
2511 continue;
2512 Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2);
2513 /* pass the buck */
2514 parseoptions(buf, setinitial, fromfile);
2515 }
2516 if (wc_supported(compopt[opt_indx].name) ||
2517 wc2_supported(compopt[opt_indx].name))
2518 preference_update(compopt[opt_indx].name);
2519 }
2520 }
2521 free((genericptr_t)pick_list);
2522 pick_list = (menu_item *)0;
2523 }
2524
2525 destroy_nhwindow(tmpwin);
2526 if (need_redraw)
2527 (void) doredraw();
2528 return 0;
2529 }
2530
2531 STATIC_OVL boolean
special_handling(optname,setinitial,setfromfile)2532 special_handling(optname, setinitial, setfromfile)
2533 const char *optname;
2534 boolean setinitial,setfromfile;
2535 {
2536 winid tmpwin;
2537 anything any;
2538 int i;
2539 char buf[BUFSZ];
2540 boolean retval = FALSE;
2541
2542 /* Special handling of menustyle, pickup_burden, pickup_types,
2543 * disclose, runmode, msg_window, menu_headings, and number_pad options.
2544 #ifdef AUTOPICKUP_EXCEPTIONS
2545 * Also takes care of interactive autopickup_exception_handling changes.
2546 #endif
2547 */
2548 if (!strcmp("menustyle", optname)) {
2549 const char *style_name;
2550 menu_item *style_pick = (menu_item *)0;
2551 tmpwin = create_nhwindow(NHW_MENU);
2552 start_menu(tmpwin);
2553 for (i = 0; i < SIZE(menutype); i++) {
2554 style_name = menutype[i];
2555 /* note: separate `style_name' variable used
2556 to avoid an optimizer bug in VAX C V2.3 */
2557 any.a_int = i + 1;
2558 add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,
2559 ATR_NONE, style_name, MENU_UNSELECTED);
2560 }
2561 end_menu(tmpwin, "Select menustyle:");
2562 if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) {
2563 flags.menu_style = style_pick->item.a_int - 1;
2564 free((genericptr_t)style_pick);
2565 }
2566 destroy_nhwindow(tmpwin);
2567 retval = TRUE;
2568 } else if (!strcmp("pickup_burden", optname)) {
2569 const char *burden_name, *burden_letters = "ubsntl";
2570 menu_item *burden_pick = (menu_item *)0;
2571 tmpwin = create_nhwindow(NHW_MENU);
2572 start_menu(tmpwin);
2573 for (i = 0; i < SIZE(burdentype); i++) {
2574 burden_name = burdentype[i];
2575 any.a_int = i + 1;
2576 add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,
2577 ATR_NONE, burden_name, MENU_UNSELECTED);
2578 }
2579 end_menu(tmpwin, "Select encumbrance level:");
2580 if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) {
2581 flags.pickup_burden = burden_pick->item.a_int - 1;
2582 free((genericptr_t)burden_pick);
2583 }
2584 destroy_nhwindow(tmpwin);
2585 retval = TRUE;
2586 } else if (!strcmp("pickup_types", optname)) {
2587 /* parseoptions will prompt for the list of types */
2588 parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile);
2589 retval = TRUE;
2590 } else if (!strcmp("disclose", optname)) {
2591 int pick_cnt, pick_idx, opt_idx;
2592 menu_item *disclosure_category_pick = (menu_item *)0;
2593 /*
2594 * The order of disclose_names[]
2595 * must correspond to disclosure_options in decl.h
2596 */
2597 static const char *disclosure_names[] = {
2598 "inventory", "attributes", "vanquished", "genocides", "conduct"
2599 };
2600 int disc_cat[NUM_DISCLOSURE_OPTIONS];
2601 const char *disclosure_name;
2602
2603 tmpwin = create_nhwindow(NHW_MENU);
2604 start_menu(tmpwin);
2605 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
2606 disclosure_name = disclosure_names[i];
2607 any.a_int = i + 1;
2608 add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0,
2609 ATR_NONE, disclosure_name, MENU_UNSELECTED);
2610 disc_cat[i] = 0;
2611 }
2612 end_menu(tmpwin, "Change which disclosure options categories:");
2613 if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) {
2614 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
2615 opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1;
2616 disc_cat[opt_idx] = 1;
2617 }
2618 free((genericptr_t)disclosure_category_pick);
2619 disclosure_category_pick = (menu_item *)0;
2620 }
2621 destroy_nhwindow(tmpwin);
2622
2623 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
2624 if (disc_cat[i]) {
2625 char dbuf[BUFSZ];
2626 menu_item *disclosure_option_pick = (menu_item *)0;
2627 Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]);
2628 tmpwin = create_nhwindow(NHW_MENU);
2629 start_menu(tmpwin);
2630 any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
2631 add_menu(tmpwin, NO_GLYPH, &any, 'a', 0,
2632 ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED);
2633 any.a_void = 0;
2634 any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
2635 add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
2636 ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED);
2637 any.a_void = 0;
2638 any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
2639 add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
2640 ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED);
2641 any.a_void = 0;
2642 any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
2643 add_menu(tmpwin, NO_GLYPH, &any, 'd', 0,
2644 ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED);
2645 end_menu(tmpwin, dbuf);
2646 if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) {
2647 flags.end_disclose[i] = disclosure_option_pick->item.a_char;
2648 free((genericptr_t)disclosure_option_pick);
2649 }
2650 destroy_nhwindow(tmpwin);
2651 }
2652 }
2653 retval = TRUE;
2654 } else if (!strcmp("runmode", optname)) {
2655 const char *mode_name;
2656 menu_item *mode_pick = (menu_item *)0;
2657 tmpwin = create_nhwindow(NHW_MENU);
2658 start_menu(tmpwin);
2659 for (i = 0; i < SIZE(runmodes); i++) {
2660 mode_name = runmodes[i];
2661 any.a_int = i + 1;
2662 add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0,
2663 ATR_NONE, mode_name, MENU_UNSELECTED);
2664 }
2665 end_menu(tmpwin, "Select run/travel display mode:");
2666 if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
2667 iflags.runmode = mode_pick->item.a_int - 1;
2668 free((genericptr_t)mode_pick);
2669 }
2670 destroy_nhwindow(tmpwin);
2671 retval = TRUE;
2672 }
2673 #ifdef TTY_GRAPHICS
2674 else if (!strcmp("msg_window", optname)) {
2675 /* by Christian W. Cooper */
2676 menu_item *window_pick = (menu_item *)0;
2677 tmpwin = create_nhwindow(NHW_MENU);
2678 start_menu(tmpwin);
2679 any.a_char = 's';
2680 add_menu(tmpwin, NO_GLYPH, &any, 's', 0,
2681 ATR_NONE, "single", MENU_UNSELECTED);
2682 any.a_char = 'c';
2683 add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
2684 ATR_NONE, "combination", MENU_UNSELECTED);
2685 any.a_char = 'f';
2686 add_menu(tmpwin, NO_GLYPH, &any, 'f', 0,
2687 ATR_NONE, "full", MENU_UNSELECTED);
2688 any.a_char = 'r';
2689 add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
2690 ATR_NONE, "reversed", MENU_UNSELECTED);
2691 end_menu(tmpwin, "Select message history display type:");
2692 if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
2693 iflags.prevmsg_window = window_pick->item.a_char;
2694 free((genericptr_t)window_pick);
2695 }
2696 destroy_nhwindow(tmpwin);
2697 retval = TRUE;
2698 }
2699 #endif
2700 else if (!strcmp("align_message", optname) ||
2701 !strcmp("align_status", optname)) {
2702 menu_item *window_pick = (menu_item *)0;
2703 char abuf[BUFSZ];
2704 boolean msg = (*(optname+6) == 'm');
2705
2706 tmpwin = create_nhwindow(NHW_MENU);
2707 start_menu(tmpwin);
2708 any.a_int = ALIGN_TOP;
2709 add_menu(tmpwin, NO_GLYPH, &any, 't', 0,
2710 ATR_NONE, "top", MENU_UNSELECTED);
2711 any.a_int = ALIGN_BOTTOM;
2712 add_menu(tmpwin, NO_GLYPH, &any, 'b', 0,
2713 ATR_NONE, "bottom", MENU_UNSELECTED);
2714 any.a_int = ALIGN_LEFT;
2715 add_menu(tmpwin, NO_GLYPH, &any, 'l', 0,
2716 ATR_NONE, "left", MENU_UNSELECTED);
2717 any.a_int = ALIGN_RIGHT;
2718 add_menu(tmpwin, NO_GLYPH, &any, 'r', 0,
2719 ATR_NONE, "right", MENU_UNSELECTED);
2720 Sprintf(abuf, "Select %s window placement relative to the map:",
2721 msg ? "message" : "status");
2722 end_menu(tmpwin, abuf);
2723 if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) {
2724 if (msg) iflags.wc_align_message = window_pick->item.a_int;
2725 else iflags.wc_align_status = window_pick->item.a_int;
2726 free((genericptr_t)window_pick);
2727 }
2728 destroy_nhwindow(tmpwin);
2729 retval = TRUE;
2730 } else if (!strcmp("number_pad", optname)) {
2731 static const char *npchoices[3] =
2732 {"0 (off)", "1 (on)", "2 (on, DOS compatible)"};
2733 const char *npletters = "abc";
2734 menu_item *mode_pick = (menu_item *)0;
2735
2736 tmpwin = create_nhwindow(NHW_MENU);
2737 start_menu(tmpwin);
2738 for (i = 0; i < SIZE(npchoices); i++) {
2739 any.a_int = i + 1;
2740 add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
2741 ATR_NONE, npchoices[i], MENU_UNSELECTED);
2742 }
2743 end_menu(tmpwin, "Select number_pad mode:");
2744 if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
2745 int mode = mode_pick->item.a_int - 1;
2746 switch(mode) {
2747 case 2:
2748 iflags.num_pad = 1;
2749 iflags.num_pad_mode = 1;
2750 break;
2751 case 1:
2752 iflags.num_pad = 1;
2753 iflags.num_pad_mode = 0;
2754 break;
2755 case 0:
2756 default:
2757 iflags.num_pad = 0;
2758 iflags.num_pad_mode = 0;
2759 }
2760 free((genericptr_t)mode_pick);
2761 }
2762 destroy_nhwindow(tmpwin);
2763 retval = TRUE;
2764 } else if (!strcmp("menu_headings", optname)) {
2765 static const char *mhchoices[3] = {"bold", "inverse", "underline"};
2766 const char *npletters = "biu";
2767 menu_item *mode_pick = (menu_item *)0;
2768
2769 tmpwin = create_nhwindow(NHW_MENU);
2770 start_menu(tmpwin);
2771 for (i = 0; i < SIZE(mhchoices); i++) {
2772 any.a_int = i + 1;
2773 add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0,
2774 ATR_NONE, mhchoices[i], MENU_UNSELECTED);
2775 }
2776 end_menu(tmpwin, "How to highlight menu headings:");
2777 if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) {
2778 int mode = mode_pick->item.a_int - 1;
2779 switch(mode) {
2780 case 2:
2781 iflags.menu_headings = ATR_ULINE;
2782 break;
2783 case 0:
2784 iflags.menu_headings = ATR_BOLD;
2785 break;
2786 case 1:
2787 default:
2788 iflags.menu_headings = ATR_INVERSE;
2789 }
2790 free((genericptr_t)mode_pick);
2791 }
2792 destroy_nhwindow(tmpwin);
2793 retval = TRUE;
2794 #ifdef AUTOPICKUP_EXCEPTIONS
2795 } else if (!strcmp("autopickup_exception", optname)) {
2796 boolean retval;
2797 int pick_cnt, pick_idx, opt_idx, pass;
2798 int totalapes = 0, numapes[2] = {0,0};
2799 menu_item *pick_list = (menu_item *)0;
2800 anything any;
2801 char apebuf[BUFSZ];
2802 struct autopickup_exception *ape;
2803 static const char *action_titles[] = {
2804 "a", "add new autopickup exception",
2805 "l", "list autopickup exceptions",
2806 "r", "remove existing autopickup exception",
2807 "e", "exit this menu",
2808 };
2809 ape_again:
2810 opt_idx = 0;
2811 totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
2812 tmpwin = create_nhwindow(NHW_MENU);
2813 start_menu(tmpwin);
2814 any.a_int = 0;
2815 for (i = 0; i < SIZE(action_titles) ; i += 2) {
2816 any.a_int++;
2817 if (!totalapes && (i >= 2 && i < 6)) continue;
2818 add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i],
2819 0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED);
2820 }
2821 end_menu(tmpwin, "Do what?");
2822 if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
2823 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
2824 opt_idx = pick_list[pick_idx].item.a_int - 1;
2825 }
2826 free((genericptr_t)pick_list);
2827 pick_list = (menu_item *)0;
2828 }
2829 destroy_nhwindow(tmpwin);
2830 if (pick_cnt < 1) return FALSE;
2831
2832 if (opt_idx == 0) { /* add new */
2833 getlin("What new autopickup exception pattern?", &apebuf[1]);
2834 if (apebuf[1] == '\033') return FALSE;
2835 apebuf[0] = '"';
2836 Strcat(apebuf,"\"");
2837 add_autopickup_exception(apebuf);
2838 goto ape_again;
2839 } else if (opt_idx == 3) {
2840 retval = TRUE;
2841 } else { /* remove */
2842 tmpwin = create_nhwindow(NHW_MENU);
2843 start_menu(tmpwin);
2844 for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
2845 if (numapes[pass] == 0) continue;
2846 ape = iflags.autopickup_exceptions[pass];
2847 any.a_void = 0;
2848 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2849 (pass == 0) ? "Never pickup" : "Always pickup",
2850 MENU_UNSELECTED);
2851 for (i = 0; i < numapes[pass] && ape; i++) {
2852 any.a_void = (opt_idx == 1) ? 0 : ape;
2853 Sprintf(apebuf, "\"%s\"", ape->pattern);
2854 add_menu(tmpwin, NO_GLYPH, &any,
2855 0, 0, ATR_NONE, apebuf, MENU_UNSELECTED);
2856 ape = ape->next;
2857 }
2858 }
2859 Sprintf(apebuf, "%s autopickup exceptions",
2860 (opt_idx == 1) ? "List of" : "Remove which");
2861 end_menu(tmpwin, apebuf);
2862 pick_cnt = select_menu(tmpwin,
2863 (opt_idx == 1) ? PICK_NONE : PICK_ANY,
2864 &pick_list);
2865 if (pick_cnt > 0) {
2866 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
2867 remove_autopickup_exception(
2868 (struct autopickup_exception *)pick_list[pick_idx].item.a_void);
2869 }
2870 free((genericptr_t)pick_list);
2871 pick_list = (menu_item *)0;
2872 destroy_nhwindow(tmpwin);
2873 goto ape_again;
2874 }
2875 retval = TRUE;
2876 #endif /* AUTOPICKUP_EXCEPTIONS */
2877 }
2878 return retval;
2879 }
2880
2881 #define rolestring(val,array,field) ((val >= 0) ? array[val].field : \
2882 (val == ROLE_RANDOM) ? randomrole : none)
2883
2884 /* This is ugly. We have all the option names in the compopt[] array,
2885 but we need to look at each option individually to get the value. */
2886 STATIC_OVL const char *
get_compopt_value(optname,buf)2887 get_compopt_value(optname, buf)
2888 const char *optname;
2889 char *buf;
2890 {
2891 char ocl[MAXOCLASSES+1];
2892 static const char none[] = "(none)", randomrole[] = "random",
2893 to_be_done[] = "(to be done)",
2894 defopt[] = "default",
2895 defbrief[] = "def";
2896 int i;
2897
2898 buf[0] = '\0';
2899 if (!strcmp(optname,"align_message"))
2900 Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP ? "top" :
2901 iflags.wc_align_message == ALIGN_LEFT ? "left" :
2902 iflags.wc_align_message == ALIGN_BOTTOM ? "bottom" :
2903 iflags.wc_align_message == ALIGN_RIGHT ? "right" :
2904 defopt);
2905 else if (!strcmp(optname,"align_status"))
2906 Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP ? "top" :
2907 iflags.wc_align_status == ALIGN_LEFT ? "left" :
2908 iflags.wc_align_status == ALIGN_BOTTOM ? "bottom" :
2909 iflags.wc_align_status == ALIGN_RIGHT ? "right" :
2910 defopt);
2911 else if (!strcmp(optname,"align"))
2912 Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj));
2913 #ifdef WIN32CON
2914 else if (!strcmp(optname,"altkeyhandler"))
2915 Sprintf(buf, "%s", iflags.altkeyhandler[0] ?
2916 iflags.altkeyhandler : "default");
2917 #endif
2918 else if (!strcmp(optname, "boulder"))
2919 Sprintf(buf, "%c", iflags.bouldersym ?
2920 iflags.bouldersym : oc_syms[(int)objects[BOULDER].oc_class]);
2921 else if (!strcmp(optname, "catname"))
2922 Sprintf(buf, "%s", catname[0] ? catname : none );
2923 else if (!strcmp(optname, "disclose")) {
2924 for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
2925 char topt[2];
2926 if (i) Strcat(buf," ");
2927 topt[1] = '\0';
2928 topt[0] = flags.end_disclose[i];
2929 Strcat(buf, topt);
2930 topt[0] = disclosure_options[i];
2931 Strcat(buf, topt);
2932 }
2933 }
2934 else if (!strcmp(optname, "dogname"))
2935 Sprintf(buf, "%s", dogname[0] ? dogname : none );
2936 else if (!strcmp(optname, "dungeon"))
2937 Sprintf(buf, "%s", to_be_done);
2938 else if (!strcmp(optname, "effects"))
2939 Sprintf(buf, "%s", to_be_done);
2940 else if (!strcmp(optname, "font_map"))
2941 Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt);
2942 else if (!strcmp(optname, "font_message"))
2943 Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt);
2944 else if (!strcmp(optname, "font_status"))
2945 Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt);
2946 else if (!strcmp(optname, "font_menu"))
2947 Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt);
2948 else if (!strcmp(optname, "font_text"))
2949 Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt);
2950 else if (!strcmp(optname, "font_size_map")) {
2951 if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map);
2952 else Strcpy(buf, defopt);
2953 }
2954 else if (!strcmp(optname, "font_size_message")) {
2955 if (iflags.wc_fontsiz_message) Sprintf(buf, "%d",
2956 iflags.wc_fontsiz_message);
2957 else Strcpy(buf, defopt);
2958 }
2959 else if (!strcmp(optname, "font_size_status")) {
2960 if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status);
2961 else Strcpy(buf, defopt);
2962 }
2963 else if (!strcmp(optname, "font_size_menu")) {
2964 if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu);
2965 else Strcpy(buf, defopt);
2966 }
2967 else if (!strcmp(optname, "font_size_text")) {
2968 if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text);
2969 else Strcpy(buf, defopt);
2970 }
2971 else if (!strcmp(optname, "fruit"))
2972 Sprintf(buf, "%s", pl_fruit);
2973 else if (!strcmp(optname, "gender"))
2974 Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj));
2975 else if (!strcmp(optname, "horsename"))
2976 Sprintf(buf, "%s", horsename[0] ? horsename : none);
2977 else if (!strcmp(optname, "map_mode"))
2978 Sprintf(buf, "%s",
2979 iflags.wc_map_mode == MAP_MODE_TILES ? "tiles" :
2980 iflags.wc_map_mode == MAP_MODE_ASCII4x6 ? "ascii4x6" :
2981 iflags.wc_map_mode == MAP_MODE_ASCII6x8 ? "ascii6x8" :
2982 iflags.wc_map_mode == MAP_MODE_ASCII8x8 ? "ascii8x8" :
2983 iflags.wc_map_mode == MAP_MODE_ASCII16x8 ? "ascii16x8" :
2984 iflags.wc_map_mode == MAP_MODE_ASCII7x12 ? "ascii7x12" :
2985 iflags.wc_map_mode == MAP_MODE_ASCII8x12 ? "ascii8x12" :
2986 iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" :
2987 iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" :
2988 iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" :
2989 iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ?
2990 "fit_to_screen" : defopt);
2991 else if (!strcmp(optname, "menustyle"))
2992 Sprintf(buf, "%s", menutype[(int)flags.menu_style] );
2993 else if (!strcmp(optname, "menu_deselect_all"))
2994 Sprintf(buf, "%s", to_be_done);
2995 else if (!strcmp(optname, "menu_deselect_page"))
2996 Sprintf(buf, "%s", to_be_done);
2997 else if (!strcmp(optname, "menu_first_page"))
2998 Sprintf(buf, "%s", to_be_done);
2999 else if (!strcmp(optname, "menu_invert_all"))
3000 Sprintf(buf, "%s", to_be_done);
3001 else if (!strcmp(optname, "menu_headings")) {
3002 Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ?
3003 "bold" : (iflags.menu_headings == ATR_INVERSE) ?
3004 "inverse" : (iflags.menu_headings == ATR_ULINE) ?
3005 "underline" : "unknown");
3006 }
3007 else if (!strcmp(optname, "menu_invert_page"))
3008 Sprintf(buf, "%s", to_be_done);
3009 else if (!strcmp(optname, "menu_last_page"))
3010 Sprintf(buf, "%s", to_be_done);
3011 else if (!strcmp(optname, "menu_next_page"))
3012 Sprintf(buf, "%s", to_be_done);
3013 else if (!strcmp(optname, "menu_previous_page"))
3014 Sprintf(buf, "%s", to_be_done);
3015 else if (!strcmp(optname, "menu_search"))
3016 Sprintf(buf, "%s", to_be_done);
3017 else if (!strcmp(optname, "menu_select_all"))
3018 Sprintf(buf, "%s", to_be_done);
3019 else if (!strcmp(optname, "menu_select_page"))
3020 Sprintf(buf, "%s", to_be_done);
3021 else if (!strcmp(optname, "monsters"))
3022 Sprintf(buf, "%s", to_be_done);
3023 else if (!strcmp(optname, "msghistory"))
3024 Sprintf(buf, "%u", iflags.msg_history);
3025 #ifdef TTY_GRAPHICS
3026 else if (!strcmp(optname, "msg_window"))
3027 Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" :
3028 (iflags.prevmsg_window=='c') ? "combination" :
3029 (iflags.prevmsg_window=='f') ? "full" : "reversed");
3030 #endif
3031 else if (!strcmp(optname, "name"))
3032 Sprintf(buf, "%s", plname);
3033 else if (!strcmp(optname, "number_pad"))
3034 Sprintf(buf, "%s",
3035 (!iflags.num_pad) ? "0=off" :
3036 (iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on");
3037 else if (!strcmp(optname, "objects"))
3038 Sprintf(buf, "%s", to_be_done);
3039 else if (!strcmp(optname, "packorder")) {
3040 oc_to_str(flags.inv_order, ocl);
3041 Sprintf(buf, "%s", ocl);
3042 }
3043 #ifdef CHANGE_COLOR
3044 else if (!strcmp(optname, "palette"))
3045 Sprintf(buf, "%s", get_color_string());
3046 #endif
3047 else if (!strcmp(optname, "pettype"))
3048 Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" :
3049 (preferred_pet == 'd') ? "dog" :
3050 (preferred_pet == 'n') ? "none" : "random");
3051 else if (!strcmp(optname, "pickup_burden"))
3052 Sprintf(buf, "%s", burdentype[flags.pickup_burden] );
3053 else if (!strcmp(optname, "pickup_types")) {
3054 oc_to_str(flags.pickup_types, ocl);
3055 Sprintf(buf, "%s", ocl[0] ? ocl : "all" );
3056 }
3057 else if (!strcmp(optname, "race"))
3058 Sprintf(buf, "%s", rolestring(flags.initrace, races, noun));
3059 else if (!strcmp(optname, "role"))
3060 Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m));
3061 else if (!strcmp(optname, "runmode"))
3062 Sprintf(buf, "%s", runmodes[iflags.runmode]);
3063 else if (!strcmp(optname, "scores")) {
3064 Sprintf(buf, "%d top/%d around%s", flags.end_top,
3065 flags.end_around, flags.end_own ? "/own" : "");
3066 }
3067 else if (!strcmp(optname, "scroll_amount")) {
3068 if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount);
3069 else Strcpy(buf, defopt);
3070 }
3071 else if (!strcmp(optname, "scroll_margin")) {
3072 if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
3073 else Strcpy(buf, defopt);
3074 }
3075 else if (!strcmp(optname, "player_selection"))
3076 Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
3077 #ifdef MSDOS
3078 else if (!strcmp(optname, "soundcard"))
3079 Sprintf(buf, "%s", to_be_done);
3080 #endif
3081 else if (!strcmp(optname, "suppress_alert")) {
3082 if (flags.suppress_alert == 0L)
3083 Strcpy(buf, none);
3084 else
3085 Sprintf(buf, "%lu.%lu.%lu",
3086 FEATURE_NOTICE_VER_MAJ,
3087 FEATURE_NOTICE_VER_MIN,
3088 FEATURE_NOTICE_VER_PATCH);
3089 }
3090 else if (!strcmp(optname, "tile_file"))
3091 Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
3092 else if (!strcmp(optname, "tile_height")) {
3093 if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height);
3094 else Strcpy(buf, defopt);
3095 }
3096 else if (!strcmp(optname, "tile_width")) {
3097 if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width);
3098 else Strcpy(buf, defopt);
3099 }
3100 else if (!strcmp(optname, "traps"))
3101 Sprintf(buf, "%s", to_be_done);
3102 else if (!strcmp(optname, "vary_msgcount")) {
3103 if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount);
3104 else Strcpy(buf, defopt);
3105 }
3106 #ifdef MSDOS
3107 else if (!strcmp(optname, "video"))
3108 Sprintf(buf, "%s", to_be_done);
3109 #endif
3110 #ifdef VIDEOSHADES
3111 else if (!strcmp(optname, "videoshades"))
3112 Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]);
3113 else if (!strcmp(optname, "videocolors"))
3114 Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
3115 ttycolors[CLR_RED], ttycolors[CLR_GREEN],
3116 ttycolors[CLR_BROWN], ttycolors[CLR_BLUE],
3117 ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],
3118 ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],
3119 ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],
3120 ttycolors[CLR_BRIGHT_MAGENTA],
3121 ttycolors[CLR_BRIGHT_CYAN]);
3122 #endif /* VIDEOSHADES */
3123 else if (!strcmp(optname, "windowtype"))
3124 Sprintf(buf, "%s", windowprocs.name);
3125 else if (!strcmp(optname, "windowcolors"))
3126 Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s",
3127 iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief,
3128 iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief,
3129 iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief,
3130 iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief,
3131 iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief,
3132 iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief,
3133 iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief,
3134 iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief);
3135 #ifdef PREFIXES_IN_USE
3136 else {
3137 for (i = 0; i < PREFIX_COUNT; ++i)
3138 if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i])
3139 Sprintf(buf, "%s", fqn_prefix[i]);
3140 }
3141 #endif
3142
3143 if (buf[0]) return buf;
3144 else return "unknown";
3145 }
3146
3147 int
dotogglepickup()3148 dotogglepickup()
3149 {
3150 char buf[BUFSZ], ocl[MAXOCLASSES+1];
3151
3152 flags.pickup = !flags.pickup;
3153 if (flags.pickup) {
3154 oc_to_str(flags.pickup_types, ocl);
3155 Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
3156 #ifdef AUTOPICKUP_EXCEPTIONS
3157 (iflags.autopickup_exceptions[AP_LEAVE] ||
3158 iflags.autopickup_exceptions[AP_GRAB]) ?
3159 ((count_ape_maps((int *)0, (int *)0) == 1) ?
3160 ", with one exception" : ", with some exceptions") :
3161 #endif
3162 "");
3163 } else {
3164 Strcpy(buf, "OFF");
3165 }
3166 pline("Autopickup: %s.", buf);
3167 return 0;
3168 }
3169
3170 #ifdef AUTOPICKUP_EXCEPTIONS
3171 int
add_autopickup_exception(mapping)3172 add_autopickup_exception(mapping)
3173 const char *mapping;
3174 {
3175 struct autopickup_exception *ape, **apehead;
3176 char text[256], *text2;
3177 int textsize = 0;
3178 boolean grab = FALSE;
3179
3180 if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
3181 text2 = &text[0];
3182 if (*text2 == '<') { /* force autopickup */
3183 grab = TRUE;
3184 ++text2;
3185 } else if (*text2 == '>') { /* default - Do not pickup */
3186 grab = FALSE;
3187 ++text2;
3188 }
3189 textsize = strlen(text2);
3190 apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] :
3191 &iflags.autopickup_exceptions[AP_LEAVE];
3192 ape = (struct autopickup_exception *)
3193 alloc(sizeof(struct autopickup_exception));
3194 ape->pattern = (char *) alloc(textsize+1);
3195 Strcpy(ape->pattern, text2);
3196 ape->grab = grab;
3197 if (!*apehead) ape->next = (struct autopickup_exception *)0;
3198 else ape->next = *apehead;
3199 *apehead = ape;
3200 } else {
3201 raw_print("syntax error in AUTOPICKUP_EXCEPTION");
3202 return 0;
3203 }
3204 return 1;
3205 }
3206
3207 STATIC_OVL void
remove_autopickup_exception(whichape)3208 remove_autopickup_exception(whichape)
3209 struct autopickup_exception *whichape;
3210 {
3211 struct autopickup_exception *ape, *prev = 0;
3212 int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
3213
3214 for (ape = iflags.autopickup_exceptions[chain]; ape;) {
3215 if (ape == whichape) {
3216 struct autopickup_exception *freeape = ape;
3217 ape = ape->next;
3218 if (prev) prev->next = ape;
3219 else iflags.autopickup_exceptions[chain] = ape;
3220 free(freeape->pattern);
3221 free(freeape);
3222 } else {
3223 prev = ape;
3224 ape = ape->next;
3225 }
3226 }
3227 }
3228
3229 STATIC_OVL int
count_ape_maps(leave,grab)3230 count_ape_maps(leave, grab)
3231 int *leave, *grab;
3232 {
3233 struct autopickup_exception *ape;
3234 int pass, totalapes, numapes[2] = {0,0};
3235
3236 for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
3237 ape = iflags.autopickup_exceptions[pass];
3238 while(ape) {
3239 ape = ape->next;
3240 numapes[pass]++;
3241 }
3242 }
3243 totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB];
3244 if (leave) *leave = numapes[AP_LEAVE];
3245 if (grab) *grab = numapes[AP_GRAB];
3246 return totalapes;
3247 }
3248
3249 void
free_autopickup_exceptions()3250 free_autopickup_exceptions()
3251 {
3252 struct autopickup_exception *ape;
3253 int pass;
3254
3255 for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
3256 while((ape = iflags.autopickup_exceptions[pass]) != 0) {
3257 free(ape->pattern);
3258 iflags.autopickup_exceptions[pass] = ape->next;
3259 free(ape);
3260 }
3261 }
3262 }
3263 #endif /* AUTOPICKUP_EXCEPTIONS */
3264
3265 /* data for option_help() */
3266 static const char *opt_intro[] = {
3267 "",
3268 " NetHack Options Help:",
3269 "",
3270 #define CONFIG_SLOT 3 /* fill in next value at run-time */
3271 (char *)0,
3272 #if !defined(MICRO) && !defined(MAC)
3273 "or use `NETHACKOPTIONS=\"<options>\"' in your environment",
3274 #endif
3275 "(<options> is a list of options separated by commas)",
3276 #ifdef VMS
3277 "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"",
3278 #endif
3279 "or press \"O\" while playing and use the menu.",
3280 "",
3281 "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
3282 (char *)0
3283 };
3284
3285 static const char *opt_epilog[] = {
3286 "",
3287 "Some of the options can be set only before the game is started; those",
3288 "items will not be selectable in the 'O' command's menu.",
3289 (char *)0
3290 };
3291
3292 void
option_help()3293 option_help()
3294 {
3295 char buf[BUFSZ], buf2[BUFSZ];
3296 register int i;
3297 winid datawin;
3298
3299 datawin = create_nhwindow(NHW_TEXT);
3300 Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
3301 opt_intro[CONFIG_SLOT] = (const char *) buf;
3302 for (i = 0; opt_intro[i]; i++)
3303 putstr(datawin, 0, opt_intro[i]);
3304
3305 /* Boolean options */
3306 for (i = 0; boolopt[i].name; i++) {
3307 if (boolopt[i].addr) {
3308 #ifdef WIZARD
3309 if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue;
3310 if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue;
3311 #endif
3312 next_opt(datawin, boolopt[i].name);
3313 }
3314 }
3315 next_opt(datawin, "");
3316
3317 /* Compound options */
3318 putstr(datawin, 0, "Compound options:");
3319 for (i = 0; compopt[i].name; i++) {
3320 Sprintf(buf2, "`%s'", compopt[i].name);
3321 Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr,
3322 compopt[i+1].name ? ',' : '.');
3323 putstr(datawin, 0, buf);
3324 }
3325
3326 for (i = 0; opt_epilog[i]; i++)
3327 putstr(datawin, 0, opt_epilog[i]);
3328
3329 display_nhwindow(datawin, FALSE);
3330 destroy_nhwindow(datawin);
3331 return;
3332 }
3333
3334 /*
3335 * prints the next boolean option, on the same line if possible, on a new
3336 * line if not. End with next_opt("").
3337 */
3338 void
next_opt(datawin,str)3339 next_opt(datawin, str)
3340 winid datawin;
3341 const char *str;
3342 {
3343 static char *buf = 0;
3344 int i;
3345 char *s;
3346
3347 if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0';
3348
3349 if (!*str) {
3350 s = eos(buf);
3351 if (s > &buf[1] && s[-2] == ',')
3352 Strcpy(s - 2, "."); /* replace last ", " */
3353 i = COLNO; /* (greater than COLNO - 2) */
3354 } else {
3355 i = strlen(buf) + strlen(str) + 2;
3356 }
3357
3358 if (i > COLNO - 2) { /* rule of thumb */
3359 putstr(datawin, 0, buf);
3360 buf[0] = 0;
3361 }
3362 if (*str) {
3363 Strcat(buf, str);
3364 Strcat(buf, ", ");
3365 } else {
3366 putstr(datawin, 0, str);
3367 free(buf), buf = 0;
3368 }
3369 return;
3370 }
3371
3372 /* Returns the fid of the fruit type; if that type already exists, it
3373 * returns the fid of that one; if it does not exist, it adds a new fruit
3374 * type to the chain and returns the new one.
3375 */
3376 int
fruitadd(str)3377 fruitadd(str)
3378 char *str;
3379 {
3380 register int i;
3381 register struct fruit *f;
3382 struct fruit *lastf = 0;
3383 int highest_fruit_id = 0;
3384 char buf[PL_FSIZ];
3385 boolean user_specified = (str == pl_fruit);
3386 /* if not user-specified, then it's a fruit name for a fruit on
3387 * a bones level...
3388 */
3389
3390 /* Note: every fruit has an id (spe for fruit objects) of at least
3391 * 1; 0 is an error.
3392 */
3393 if (user_specified) {
3394 /* disallow naming after other foods (since it'd be impossible
3395 * to tell the difference)
3396 */
3397
3398 boolean found = FALSE, numeric = FALSE;
3399
3400 for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;
3401 i++) {
3402 if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
3403 found = TRUE;
3404 break;
3405 }
3406 }
3407 {
3408 char *c;
3409
3410 c = pl_fruit;
3411
3412 for(c = pl_fruit; *c >= '0' && *c <= '9'; c++)
3413 ;
3414 if (isspace(*c) || *c == 0) numeric = TRUE;
3415 }
3416 if (found || numeric ||
3417 !strncmp(str, "cursed ", 7) ||
3418 !strncmp(str, "uncursed ", 9) ||
3419 !strncmp(str, "blessed ", 8) ||
3420 !strncmp(str, "partly eaten ", 13) ||
3421 (!strncmp(str, "tin of ", 7) &&
3422 (!strcmp(str+7, "spinach") ||
3423 name_to_mon(str+7) >= LOW_PM)) ||
3424 !strcmp(str, "empty tin") ||
3425 ((!strncmp(eos(str)-7," corpse",7) ||
3426 !strncmp(eos(str)-4, " egg",4)) &&
3427 name_to_mon(str) >= LOW_PM))
3428 {
3429 Strcpy(buf, pl_fruit);
3430 Strcpy(pl_fruit, "candied ");
3431 nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
3432 }
3433 }
3434 for(f=ffruit; f; f = f->nextf) {
3435 lastf = f;
3436 if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
3437 if(!strncmp(str, f->fname, PL_FSIZ))
3438 goto nonew;
3439 }
3440 /* if adding another fruit would overflow spe, use a random
3441 fruit instead... we've got a lot to choose from. */
3442 if (highest_fruit_id >= 127) return rnd(127);
3443 highest_fruit_id++;
3444 f = newfruit();
3445 if (ffruit) lastf->nextf = f;
3446 else ffruit = f;
3447 Strcpy(f->fname, str);
3448 f->fid = highest_fruit_id;
3449 f->nextf = 0;
3450 nonew:
3451 if (user_specified) current_fruit = highest_fruit_id;
3452 return f->fid;
3453 }
3454
3455 /*
3456 * This is a somewhat generic menu for taking a list of NetHack style
3457 * class choices and presenting them via a description
3458 * rather than the traditional NetHack characters.
3459 * (Benefits users whose first exposure to NetHack is via tiles).
3460 *
3461 * prompt
3462 * The title at the top of the menu.
3463 *
3464 * category: 0 = monster class
3465 * 1 = object class
3466 *
3467 * way
3468 * FALSE = PICK_ONE, TRUE = PICK_ANY
3469 *
3470 * class_list
3471 * a null terminated string containing the list of choices.
3472 *
3473 * class_selection
3474 * a null terminated string containing the selected characters.
3475 *
3476 * Returns number selected.
3477 */
3478 int
choose_classes_menu(prompt,category,way,class_list,class_select)3479 choose_classes_menu(prompt, category, way, class_list, class_select)
3480 const char *prompt;
3481 int category;
3482 boolean way;
3483 char *class_list;
3484 char *class_select;
3485 {
3486 menu_item *pick_list = (menu_item *)0;
3487 winid win;
3488 anything any;
3489 char buf[BUFSZ];
3490 int i, n;
3491 int ret;
3492 int next_accelerator, accelerator;
3493
3494 if (class_list == (char *)0 || class_select == (char *)0) return 0;
3495 accelerator = 0;
3496 next_accelerator = 'a';
3497 any.a_void = 0;
3498 win = create_nhwindow(NHW_MENU);
3499 start_menu(win);
3500 while (*class_list) {
3501 const char *text;
3502 boolean selected;
3503
3504 text = (char *)0;
3505 selected = FALSE;
3506 switch (category) {
3507 case 0:
3508 text = monexplain[def_char_to_monclass(*class_list)];
3509 accelerator = *class_list;
3510 Sprintf(buf, "%s", text);
3511 break;
3512 case 1:
3513 text = objexplain[def_char_to_objclass(*class_list)];
3514 accelerator = next_accelerator;
3515 Sprintf(buf, "%c %s", *class_list, text);
3516 break;
3517 default:
3518 impossible("choose_classes_menu: invalid category %d",
3519 category);
3520 }
3521 if (way && *class_select) { /* Selections there already */
3522 if (index(class_select, *class_list)) {
3523 selected = TRUE;
3524 }
3525 }
3526 any.a_int = *class_list;
3527 add_menu(win, NO_GLYPH, &any, accelerator,
3528 category ? *class_list : 0,
3529 ATR_NONE, buf, selected);
3530 ++class_list;
3531 if (category > 0) {
3532 ++next_accelerator;
3533 if (next_accelerator == ('z' + 1)) next_accelerator = 'A';
3534 if (next_accelerator == ('Z' + 1)) break;
3535 }
3536 }
3537 end_menu(win, prompt);
3538 n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list);
3539 destroy_nhwindow(win);
3540 if (n > 0) {
3541 for (i = 0; i < n; ++i)
3542 *class_select++ = (char)pick_list[i].item.a_int;
3543 free((genericptr_t)pick_list);
3544 ret = n;
3545 } else if (n == -1) {
3546 class_select = eos(class_select);
3547 ret = -1;
3548 } else
3549 ret = 0;
3550 *class_select = '\0';
3551 return ret;
3552 }
3553
3554 struct wc_Opt wc_options[] = {
3555 {"ascii_map", WC_ASCII_MAP},
3556 {"color", WC_COLOR},
3557 {"eight_bit_tty", WC_EIGHT_BIT_IN},
3558 {"hilite_pet", WC_HILITE_PET},
3559 {"popup_dialog", WC_POPUP_DIALOG},
3560 {"player_selection", WC_PLAYER_SELECTION},
3561 {"preload_tiles", WC_PRELOAD_TILES},
3562 {"tiled_map", WC_TILED_MAP},
3563 {"tile_file", WC_TILE_FILE},
3564 {"tile_width", WC_TILE_WIDTH},
3565 {"tile_height", WC_TILE_HEIGHT},
3566 {"use_inverse", WC_INVERSE},
3567 {"align_message", WC_ALIGN_MESSAGE},
3568 {"align_status", WC_ALIGN_STATUS},
3569 {"font_map", WC_FONT_MAP},
3570 {"font_menu", WC_FONT_MENU},
3571 {"font_message",WC_FONT_MESSAGE},
3572 #if 0
3573 {"perm_invent",WC_PERM_INVENT},
3574 #endif
3575 {"font_size_map", WC_FONTSIZ_MAP},
3576 {"font_size_menu", WC_FONTSIZ_MENU},
3577 {"font_size_message", WC_FONTSIZ_MESSAGE},
3578 {"font_size_status", WC_FONTSIZ_STATUS},
3579 {"font_size_text", WC_FONTSIZ_TEXT},
3580 {"font_status", WC_FONT_STATUS},
3581 {"font_text", WC_FONT_TEXT},
3582 {"map_mode", WC_MAP_MODE},
3583 {"scroll_amount", WC_SCROLL_AMOUNT},
3584 {"scroll_margin", WC_SCROLL_MARGIN},
3585 {"splash_screen", WC_SPLASH_SCREEN},
3586 {"vary_msgcount",WC_VARY_MSGCOUNT},
3587 {"windowcolors", WC_WINDOWCOLORS},
3588 {"mouse_support", WC_MOUSE_SUPPORT},
3589 {(char *)0, 0L}
3590 };
3591
3592 struct wc_Opt wc2_options[] = {
3593 {"fullscreen", WC2_FULLSCREEN},
3594 {"softkeyboard", WC2_SOFTKEYBOARD},
3595 {"wraptext", WC2_WRAPTEXT},
3596 {(char *)0, 0L}
3597 };
3598
3599
3600 /*
3601 * If a port wants to change or ensure that the
3602 * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is
3603 * correct (for controlling its display in the option menu) call
3604 * set_option_mod_status()
3605 * with the second argument of 0,2, or 3 respectively.
3606 */
3607 void
set_option_mod_status(optnam,status)3608 set_option_mod_status(optnam, status)
3609 const char *optnam;
3610 int status;
3611 {
3612 int k;
3613 if (status < SET_IN_FILE || status > SET_IN_GAME) {
3614 impossible("set_option_mod_status: status out of range %d.",
3615 status);
3616 return;
3617 }
3618 for (k = 0; boolopt[k].name; k++) {
3619 if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) {
3620 boolopt[k].optflags = status;
3621 return;
3622 }
3623 }
3624 for (k = 0; compopt[k].name; k++) {
3625 if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) {
3626 compopt[k].optflags = status;
3627 return;
3628 }
3629 }
3630 }
3631
3632 /*
3633 * You can set several wc_options in one call to
3634 * set_wc_option_mod_status() by setting
3635 * the appropriate bits for each option that you
3636 * are setting in the optmask argument
3637 * prior to calling.
3638 * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME);
3639 */
3640 void
set_wc_option_mod_status(optmask,status)3641 set_wc_option_mod_status(optmask, status)
3642 unsigned long optmask;
3643 int status;
3644 {
3645 int k = 0;
3646 if (status < SET_IN_FILE || status > SET_IN_GAME) {
3647 impossible("set_wc_option_mod_status: status out of range %d.",
3648 status);
3649 return;
3650 }
3651 while (wc_options[k].wc_name) {
3652 if (optmask & wc_options[k].wc_bit) {
3653 set_option_mod_status(wc_options[k].wc_name, status);
3654 }
3655 k++;
3656 }
3657 }
3658
3659 STATIC_OVL boolean
is_wc_option(optnam)3660 is_wc_option(optnam)
3661 const char *optnam;
3662 {
3663 int k = 0;
3664 while (wc_options[k].wc_name) {
3665 if (strcmp(wc_options[k].wc_name, optnam) == 0)
3666 return TRUE;
3667 k++;
3668 }
3669 return FALSE;
3670 }
3671
3672 STATIC_OVL boolean
wc_supported(optnam)3673 wc_supported(optnam)
3674 const char *optnam;
3675 {
3676 int k = 0;
3677 while (wc_options[k].wc_name) {
3678 if (!strcmp(wc_options[k].wc_name, optnam) &&
3679 (windowprocs.wincap & wc_options[k].wc_bit))
3680 return TRUE;
3681 k++;
3682 }
3683 return FALSE;
3684 }
3685
3686
3687 /*
3688 * You can set several wc2_options in one call to
3689 * set_wc2_option_mod_status() by setting
3690 * the appropriate bits for each option that you
3691 * are setting in the optmask argument
3692 * prior to calling.
3693 * example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE);
3694 */
3695
3696 void
set_wc2_option_mod_status(optmask,status)3697 set_wc2_option_mod_status(optmask, status)
3698 unsigned long optmask;
3699 int status;
3700 {
3701 int k = 0;
3702 if (status < SET_IN_FILE || status > SET_IN_GAME) {
3703 impossible("set_wc2_option_mod_status: status out of range %d.",
3704 status);
3705 return;
3706 }
3707 while (wc2_options[k].wc_name) {
3708 if (optmask & wc2_options[k].wc_bit) {
3709 set_option_mod_status(wc2_options[k].wc_name, status);
3710 }
3711 k++;
3712 }
3713 }
3714
3715 STATIC_OVL boolean
is_wc2_option(optnam)3716 is_wc2_option(optnam)
3717 const char *optnam;
3718 {
3719 int k = 0;
3720 while (wc2_options[k].wc_name) {
3721 if (strcmp(wc2_options[k].wc_name, optnam) == 0)
3722 return TRUE;
3723 k++;
3724 }
3725 return FALSE;
3726 }
3727
3728 STATIC_OVL boolean
wc2_supported(optnam)3729 wc2_supported(optnam)
3730 const char *optnam;
3731 {
3732 int k = 0;
3733 while (wc2_options[k].wc_name) {
3734 if (!strcmp(wc2_options[k].wc_name, optnam) &&
3735 (windowprocs.wincap2 & wc2_options[k].wc_bit))
3736 return TRUE;
3737 k++;
3738 }
3739 return FALSE;
3740 }
3741
3742
3743 STATIC_OVL void
wc_set_font_name(wtype,fontname)3744 wc_set_font_name(wtype, fontname)
3745 int wtype;
3746 char *fontname;
3747 {
3748 char **fn = (char **)0;
3749 if (!fontname) return;
3750 switch(wtype) {
3751 case NHW_MAP:
3752 fn = &iflags.wc_font_map;
3753 break;
3754 case NHW_MESSAGE:
3755 fn = &iflags.wc_font_message;
3756 break;
3757 case NHW_TEXT:
3758 fn = &iflags.wc_font_text;
3759 break;
3760 case NHW_MENU:
3761 fn = &iflags.wc_font_menu;
3762 break;
3763 case NHW_STATUS:
3764 fn = &iflags.wc_font_status;
3765 break;
3766 default:
3767 return;
3768 }
3769 if (fn) {
3770 if (*fn) free(*fn);
3771 *fn = (char *)alloc(strlen(fontname) + 1);
3772 Strcpy(*fn, fontname);
3773 }
3774 return;
3775 }
3776
3777 STATIC_OVL int
wc_set_window_colors(op)3778 wc_set_window_colors(op)
3779 char *op;
3780 {
3781 /* syntax:
3782 * menu white/black message green/yellow status white/blue text white/black
3783 */
3784
3785 int j;
3786 char buf[BUFSZ];
3787 char *wn, *tfg, *tbg, *newop;
3788 static const char *wnames[] = { "menu", "message", "status", "text" };
3789 static const char *shortnames[] = { "mnu", "msg", "sts", "txt" };
3790 static char **fgp[] = {
3791 &iflags.wc_foregrnd_menu,
3792 &iflags.wc_foregrnd_message,
3793 &iflags.wc_foregrnd_status,
3794 &iflags.wc_foregrnd_text
3795 };
3796 static char **bgp[] = {
3797 &iflags.wc_backgrnd_menu,
3798 &iflags.wc_backgrnd_message,
3799 &iflags.wc_backgrnd_status,
3800 &iflags.wc_backgrnd_text
3801 };
3802
3803 Strcpy(buf, op);
3804 newop = mungspaces(buf);
3805 while (newop && *newop) {
3806
3807 wn = tfg = tbg = (char *)0;
3808
3809 /* until first non-space in case there's leading spaces - before colorname*/
3810 while(*newop && isspace(*newop)) newop++;
3811 if (*newop) wn = newop;
3812 else return 0;
3813
3814 /* until first space - colorname*/
3815 while(*newop && !isspace(*newop)) newop++;
3816 if (*newop) *newop = '\0';
3817 else return 0;
3818 newop++;
3819
3820 /* until first non-space - before foreground*/
3821 while(*newop && isspace(*newop)) newop++;
3822 if (*newop) tfg = newop;
3823 else return 0;
3824
3825 /* until slash - foreground */
3826 while(*newop && *newop != '/') newop++;
3827 if (*newop) *newop = '\0';
3828 else return 0;
3829 newop++;
3830
3831 /* until first non-space (in case there's leading space after slash) - before background */
3832 while(*newop && isspace(*newop)) newop++;
3833 if (*newop) tbg = newop;
3834 else return 0;
3835
3836 /* until first space - background */
3837 while(*newop && !isspace(*newop)) newop++;
3838 if (*newop) *newop++ = '\0';
3839
3840 for (j = 0; j < 4; ++j) {
3841 if (!strcmpi(wn, wnames[j]) ||
3842 !strcmpi(wn, shortnames[j])) {
3843 if (tfg && !strstri(tfg, " ")) {
3844 if (*fgp[j]) free(*fgp[j]);
3845 *fgp[j] = (char *)alloc(strlen(tfg) + 1);
3846 Strcpy(*fgp[j], tfg);
3847 }
3848 if (tbg && !strstri(tbg, " ")) {
3849 if (*bgp[j]) free(*bgp[j]);
3850 *bgp[j] = (char *)alloc(strlen(tbg) + 1);
3851 Strcpy(*bgp[j], tbg);
3852 }
3853 break;
3854 }
3855 }
3856 }
3857 return 1;
3858 }
3859
3860 #endif /* OPTION_LISTS_ONLY */
3861
3862 /*options.c*/
3863