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" 9NEARDATA struct flag flags; /* provide linkage */ 10NEARDATA 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 36static 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 */ 203static 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 343static boolean need_redraw; /* for doset() */ 344 345#if defined(TOS) && defined(TEXTCOLOR) 346extern boolean colors_changed; /* in tos.c */ 347#endif 348 349#ifdef VIDEOSHADES 350extern char *shade[3]; /* in sys/msdos/video.c */ 351extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */ 352#endif 353 354static 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 */ 386typedef struct { 387 const char *name; 388 char cmd; 389} menu_cmd_t; 390 391#define NUM_MENU_CMDS 11 392static 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 */ 412static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1]; 413static short n_menu_mapped = 0; 414 415 416static boolean initial, from_file; 417 418STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int)); 419STATIC_DCL void FDECL(nmcpy, (char *, const char *, int)); 420STATIC_DCL void FDECL(escapes, (const char *, char *)); 421STATIC_DCL void FDECL(rejectoption, (const char *)); 422STATIC_DCL void FDECL(badoption, (const char *)); 423STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P)); 424STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P)); 425STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P)); 426STATIC_DCL int FDECL(change_inv_order, (char *)); 427STATIC_DCL void FDECL(oc_to_str, (char *, char *)); 428STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int)); 429STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *)); 430STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *)); 431STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P)); 432STATIC_DCL void FDECL(warning_opts, (char *,const char *)); 433STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int)); 434 435STATIC_OVL void FDECL(wc_set_font_name, (int, char *)); 436STATIC_OVL int FDECL(wc_set_window_colors, (char *)); 437STATIC_OVL boolean FDECL(is_wc_option, (const char *)); 438STATIC_OVL boolean FDECL(wc_supported, (const char *)); 439STATIC_OVL boolean FDECL(is_wc2_option, (const char *)); 440STATIC_OVL boolean FDECL(wc2_supported, (const char *)); 441#ifdef AUTOPICKUP_EXCEPTIONS 442STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *)); 443STATIC_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 */ 449boolean 450match_optname(user_string, opt_name, min_length, val_allowed) 451const char *user_string, *opt_name; 452int min_length; 453boolean 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 */ 476char * 477nh_getenv(ev) 478const 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 488void 489initoptions() 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 609STATIC_OVL void 610nmcpy(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 */ 631STATIC_OVL void 632escapes(cp, tp) 633const char *cp; 634char *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 687STATIC_OVL void 688rejectoption(optname) 689const 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 699STATIC_OVL void 700badoption(opts) 701const 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 722STATIC_OVL char * 723string_for_opt(opts, val_optional) 724char *opts; 725boolean 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 740STATIC_OVL char * 741string_for_env_opt(optname, opts, val_optional) 742const char *optname; 743char *opts; 744boolean val_optional; 745{ 746 if(!initial) { 747 rejectoption(optname); 748 return (char *)0; 749 } 750 return string_for_opt(opts, val_optional); 751} 752 753STATIC_OVL void 754bad_negation(optname, with_parameter) 755const char *optname; 756boolean 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 */ 772STATIC_OVL int 773change_inv_order(op) 774char *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 810STATIC_OVL void 811graphics_opts(opts, optype, maxlen, offset) 812register char *opts; 813const char *optype; 814int 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 831STATIC_OVL void 832warning_opts(opts, optype) 833register char *opts; 834const 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 852void 853assign_warnings(graph_chars) 854register 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 861STATIC_OVL int 862feature_alert_opts(op, optn) 863char *op; 864const 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 894void 895set_duplicate_opt_detection(on_or_off) 896int 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 923STATIC_OVL void 924duplicate_opt_detection(opts, bool_or_comp) 925const char *opts; 926int 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 967void 968parseoptions(opts, tinitial, tfrom_file) 969register char *opts; 970boolean 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 } 1352goodfruit: 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 2253static NEARDATA const char *menutype[] = { 2254 "traditional", "combination", "partial", "full" 2255}; 2256 2257static NEARDATA const char *burdentype[] = { 2258 "unencumbered", "burdened", "stressed", 2259 "strained", "overtaxed", "overloaded" 2260}; 2261 2262static 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 */ 2270STATIC_OVL void 2271oc_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 */ 2289void 2290add_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 */ 2308char 2309map_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 2327static char fmtstr_doset_add_menu[] = "%s%-15s [%s] "; 2328static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]"; 2329 2330STATIC_OVL void 2331doset_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 */ 2369int 2370doset() 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 2531STATIC_OVL boolean 2532special_handling(optname, setinitial, setfromfile) 2533const char *optname; 2534boolean 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 }; 2809ape_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. */ 2886STATIC_OVL const char * 2887get_compopt_value(optname, buf) 2888const char *optname; 2889char *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 3147int 3148dotogglepickup() 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 3171int 3172add_autopickup_exception(mapping) 3173const 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 3207STATIC_OVL void 3208remove_autopickup_exception(whichape) 3209struct 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 3229STATIC_OVL int 3230count_ape_maps(leave, grab) 3231int *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 3249void 3250free_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() */ 3266static 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 3285static 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 3292void 3293option_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 */ 3338void 3339next_opt(datawin, str) 3340winid datawin; 3341const 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 */ 3376int 3377fruitadd(str) 3378char *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; 3450nonew: 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 */ 3478int 3479choose_classes_menu(prompt, category, way, class_list, class_select) 3480const char *prompt; 3481int category; 3482boolean way; 3483char *class_list; 3484char *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 3554struct 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 3592struct 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 */ 3607void 3608set_option_mod_status(optnam, status) 3609const char *optnam; 3610int 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 */ 3640void 3641set_wc_option_mod_status(optmask, status) 3642unsigned long optmask; 3643int 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 3659STATIC_OVL boolean 3660is_wc_option(optnam) 3661const 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 3672STATIC_OVL boolean 3673wc_supported(optnam) 3674const 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 3696void 3697set_wc2_option_mod_status(optmask, status) 3698unsigned long optmask; 3699int 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 3715STATIC_OVL boolean 3716is_wc2_option(optnam) 3717const 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 3728STATIC_OVL boolean 3729wc2_supported(optnam) 3730const 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 3743STATIC_OVL void 3744wc_set_font_name(wtype, fontname) 3745int wtype; 3746char *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 3777STATIC_OVL int 3778wc_set_window_colors(op) 3779char *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