Source:NetHack 3.3.0/options.c

Below is the full text to options.c from the source code of NetHack 3.3.0. To link to a particular line, write [[NetHack 3.3.0/options.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)options.c	3.3	1999/12/01	*/ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #ifdef OPTION_LISTS_ONLY	/* (AMIGA) external program for opt lists */ 6.   #include "config.h"  7.    #include "objclass.h"  8.    #include "flag.h"  9.    NEARDATA struct flag flags;	/* provide linkage */ 10.  NEARDATA struct instance_flags iflags;	/* provide linkage */ 11.  #define static 12.  #else 13.  #include "hack.h"  14. #include "tcap.h" 15. #include  16. #endif 17.   18.   #define WINTYPELEN 16 19.   20.   /*  21.    *  NOTE:  If you add (or delete) an option, please update the short 22.   *  options help (option_help), the long options help (dat/opthelp), 23.   *  and the current options setting display function (doset), 24.   *  and also the Guidebooks. 25.   */  26.    27.   static struct Bool_Opt 28.  {  29.   	const char *name; 30.  	boolean	*addr, initvalue; 31.  } boolopt[] = { 32.  #ifdef AMIGA 33.  	{"altmeta", &flags.altmeta, TRUE}, 34.  #else 35.  	{"altmeta", (boolean *)0, TRUE}, 36.  #endif 37.  #ifdef MFLOPPY 38.  	{"asksavedisk", &flags.asksavedisk, FALSE}, 39.  #else 40.  	{"asksavedisk", (boolean *)0, FALSE}, 41.  #endif 42.  	{"autopickup", &flags.pickup, TRUE}, 43.  	{"autoquiver", &flags.autoquiver, FALSE}, 44.  #if defined(MICRO) && !defined(AMIGA) 45.  	{"BIOS", &iflags.BIOS, FALSE}, 46.  #else 47.  	{"BIOS", (boolean *)0, FALSE}, 48.  #endif 49.  #ifdef INSURANCE 50.  	{"checkpoint", &flags.ins_chkpt, TRUE}, 51.  #else 52.  	{"checkpoint", (boolean *)0, FALSE}, 53.  #endif 54.  #ifdef TEXTCOLOR 55.  # ifdef MICRO 56.  	{"color", &iflags.use_color, TRUE}, 57.  # else	/* systems that support multiple terminals, many monochrome */ 58.  	{"color", &iflags.use_color, FALSE}, 59.  # endif 60.  #else 61.  	{"color", (boolean *)0, FALSE}, 62.  #endif 63.  	{"confirm",&flags.confirm, TRUE}, 64.  #ifdef TERMLIB 65.  	{"DECgraphics", &iflags.DECgraphics, FALSE}, 66.  #else 67.  	{"DECgraphics", (boolean *)0, FALSE}, 68.  #endif 69.  #ifdef TTY_GRAPHICS 70.  	{"extmenu", &iflags.extmenu, FALSE}, 71.  #endif 72.  #ifdef OPT_DISPMAP 73.  	{"fast_map", &flags.fast_map, TRUE}, 74.  #else 75.  	{"fast_map", (boolean *)0, TRUE}, 76.  #endif 77.  	{"female", &flags.female, FALSE}, 78.  	{"fixinv", &flags.invlet_constant, TRUE}, 79.  #ifdef AMIFLUSH 80.  	{"flush", &flags.amiflush, FALSE}, 81.  #else 82.  	{"flush", (boolean *)0, FALSE}, 83.  #endif 84.  	{"help", &flags.help, TRUE}, 85.  #ifdef TEXTCOLOR 86.  	{"hilite_pet", &iflags.hilite_pet, FALSE}, 87.  #else 88.  	{"hilite_pet", (boolean *)0, FALSE}, 89.  #endif 90.  #ifdef ASCIIGRAPH 91.  	{"IBMgraphics", &iflags.IBMgraphics, FALSE}, 92.  #else 93.  	{"IBMgraphics", (boolean *)0, FALSE}, 94.  #endif 95.  	{"ignintr", &flags.ignintr, FALSE}, 96.  #ifdef MAC_GRAPHICS_ENV 97.  	{"large_font", &iflags.large_font, FALSE}, 98.  #else 99.  	{"large_font", (boolean *)0, FALSE}, 100. #endif 101. 	{"legacy",&flags.legacy, TRUE}, 102. 	{"lit_corridor", &flags.lit_corridor, FALSE}, 103. #ifdef MAC_GRAPHICS_ENV 104. 	{"Macgraphics", &iflags.MACgraphics, TRUE}, 105. #else 106. 	{"Macgraphics", (boolean *)0, FALSE}, 107. #endif 108. #ifdef MAIL 109. 	{"mail", &flags.biff, TRUE}, 110. #else 111. 	{"mail", (boolean *)0, TRUE}, 112. #endif 113. #ifdef NEWS 114. 	{"news", &iflags.news, TRUE}, 115. #else 116. 	{"news", (boolean *)0, FALSE}, 117. #endif 118. 	{"null", &flags.null, TRUE}, 119. 	{"number_pad", &iflags.num_pad, FALSE}, 120. #ifdef MAC 121. 	{"page_wait", &flags.page_wait, TRUE}, 122. #else 123. 	{"page_wait", (boolean *)0, FALSE}, 124. #endif 125. 	{"perm_invent", &flags.perm_invent, FALSE}, 126. #ifdef MAC 127. 	{"popup_dialog", &iflags.popup_dialog, FALSE}, 128. #else 129. 	{"popup_dialog", (boolean *)0, FALSE}, 130. #endif 131. 	{"prayconfirm", &flags.prayconfirm, TRUE}, 132. #if defined(MSDOS) && defined(USE_TILES) 133. 	{"preload_tiles", &iflags.preload_tiles, TRUE}, 134. #else 135. 	{"preload_tiles", (boolean *)0, FALSE}, 136. #endif 137. 	{"pushweapon", &flags.pushweapon, FALSE}, 138. #if defined(MICRO) && !defined(AMIGA) 139. 	{"rawio", &iflags.rawio, FALSE}, 140. #else 141. 	{"rawio", (boolean *)0, FALSE}, 142. #endif 143. 	{"rest_on_space", &flags.rest_on_space, FALSE}, 144. 	{"safe_pet", &flags.safe_dog, TRUE}, 145. #ifdef WIZARD 146. 	{"sanity_check", &iflags.sanity_check, FALSE}, 147. #else 148. 	{"sanity_check", (boolean *)0, FALSE}, 149. #endif 150. #ifdef EXP_ON_BOTL 151. 	{"showexp", &flags.showexp, FALSE}, 152. #else 153. 	{"showexp", (boolean *)0, FALSE}, 154. #endif 155. #ifdef SCORE_ON_BOTL 156. 	{"showscore", &flags.showscore, FALSE}, 157. #else 158. 	{"showscore", (boolean *)0, FALSE}, 159. #endif 160. 	{"silent", &flags.silent, TRUE}, 161. 	{"sortpack", &flags.sortpack, TRUE}, 162. 	{"sound", &flags.soundok, TRUE}, 163. 	{"standout", &flags.standout, FALSE}, 164. 	{"time", &flags.time, FALSE}, 165. #ifdef TIMED_DELAY 166. 	{"timed_delay", &flags.nap, TRUE}, 167. #else 168. 	{"timed_delay", (boolean *)0, FALSE}, 169. #endif 170. 	{"tombstone",&flags.tombstone, TRUE}, 171. 	{"toptenwin",&flags.toptenwin, FALSE}, 172. 	{"verbose", &flags.verbose, TRUE}, 173. 	{(char *)0, (boolean *)0, FALSE} 174. };  175.   176.  /* compound options, for option_help and external programs like Amiga 177.  * frontend */ 178. static struct Comp_Opt 179. {  180.  	const char *name, *descr; 181. 	int size;	/* for frontends and such allocating space -- 182. 			 * usually allowed size of data in game, but 183. 			 * occasionally maximum reasonable size for 184. 			 * typing when game maintains information in  185. * a different format */ 186. } compopt[] = { 187. 	{ "align",    "your starting alignment (lawful, neutral, or chaotic)", 8 }, 188. #ifdef MAC 189. 	{ "background", "the color of the background (black or white),", 6 }, 190. #endif 191. 	{ "catname",  "the name of your (first) cat (e.g., catname:Tabby)", 192. 						PL_PSIZ }, 193. 	{ "disclose", "the kinds of information to disclose at end of game", 194. 						sizeof(flags.end_disclose) }, 195. 	{ "dogname",  "the name of your (first) dog (e.g., dogname:Fang)", 196. 						PL_PSIZ }, 197. 	{ "dungeon",  "the symbols to use in drawing the dungeon map", 198. 						MAXDCHARS+1 }, 199. 	{ "effects",  "the symbols to use in drawing special effects", 200. 						MAXECHARS+1 }, 201. #ifdef MAC 202. 	{ "fontmap", "the font to use in the map window,", 40 }, 203. 	{ "fontmessage", "the font to use in the message window,", 40 }, 204. 	{ "fonttext", "the font to use in text windows,", 40 }, 205. #endif 206. 	{ "fruit",    "the name of a fruit you enjoy eating", PL_FSIZ }, 207. 	{ "gender",   "your starting gender (male or female)", 8 }, 208. 	{ "horsename", "the name of your (first) horse (e.g., horsename:Trigger)", 209. 						PL_PSIZ }, 210. 	{ "menustyle", "user interface for object selection", MENUTYPELEN }, 211. 	{ "menu_deselect_all", "deselect all items in a menu", 4}, 212. 	{ "menu_deselect_page", "deselect all items on this page of a menu", 4}, 213. 	{ "menu_first_page", "jump to the first page in a menu", 4}, 214. 	{ "menu_invert_all", "invert all items in a menu", 4}, 215. 	{ "menu_invert_page", "invert all items on this page of a menu", 4}, 216. 	{ "menu_last_page", "jump to the last page in a menu", 4}, 217. 	{ "menu_next_page", "goto the next menu page", 4}, 218. 	{ "menu_previous_page", "goto the previous menu page", 4}, 219. 	{ "menu_search", "search for a menu item", 4}, 220. 	{ "menu_select_all", "select all items in a menu", 4}, 221. 	{ "menu_select_page", "select all items on this page of a menu", 4}, 222. 	{ "monsters", "the symbols to use for monsters", MAXMCLASSES }, 223. 	{ "msghistory", "number of top line messages to save", 5 }, 224. 	{ "name",     "your character's name (e.g., name:Merlin-W)", PL_NSIZ }, 225. 	{ "objects",  "the symbols to use for objects", MAXOCLASSES }, 226. 	{ "packorder", "the inventory order of the items in your pack", 227. 						MAXOCLASSES }, 228. #ifdef CHANGE_COLOR 229. 	{ "palette",  "palette (00c/880/-fff is blue/yellow/reverse white)", 230. 						15 },  231.  # if defined(MAC) 232. 	{ "hicolor",  "same as palette, only order is reversed", 15 }, 233. # endif 234. #endif 235. 	{ "pettype",  "your preferred initial pet type", 4 }, 236. 	{ "pickup_burden",  "maximum burden picked up before prompt", 20 }, 237. 	{ "pickup_types", "types of objects to pick up automatically", 238. 						MAXOCLASSES }, 239. 	{ "race",     "your starting race (e.g., Human, Elf)", PL_CSIZ }, 240. 	{ "role",     "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ }, 241. 	{ "scores",   "the parts of the score list you wish to see", 32 }, 242. #ifdef MSDOS 243. 	{ "soundcard", "type of sound card to use", 20 }, 244. #endif 245. 	{ "suppress_alert", "suppress alert of new features for version specified and prior", 6}, 246. 	{ "traps",    "the symbols to use in drawing traps", MAXTCHARS+1 }, 247. #ifdef MAC 248. 	{"use_stone", "use stone background patterns", 8}, 249. #endif 250. #ifdef MSDOS 251. 	{ "video",    "method of video updating", 20 }, 252. #endif 253. #ifdef VIDEOSHADES 254. 	{ "videocolors", "color mappings for internal screen routines", 40 }, 255. 	{ "videoshades", "gray shades to map to black/gray/white", 32 }, 256. #endif 257. 	{ "windowtype", "windowing system to use", WINTYPELEN }, 258. 	{ (char *)0, (char *)0, 0 } 259. };  260.   261.  #ifdef OPTION_LISTS_ONLY 262. #undef static 263.  264.  #else	/* use rest of file */ 265.  266.  static boolean need_redraw; /* for doset */ 267.  268.  #if defined(TOS) && defined(TEXTCOLOR) 269. extern boolean colors_changed;	/* in tos.c */ 270. #endif 271.  272.  #ifdef VIDEOSHADES 273. extern char *shade[3];		  /* in sys/msdos/video.c */ 274. extern char ttycolors[CLR_MAX];	/* in sys/msdos/video.c */ 275. #endif 276.  277.  static char def_inv_order[MAXOCLASSES] = { 278. 	GOLD_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, 279. 	SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS, 280. 	TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0, 281. };  282.   283.  /*  284.   * Default menu manipulation command accelerators. These may _not_ be: 285.  *  286.   *	+ a number - reserved for counts 287.  *	+ an upper or lower case US ASCII letter - used for accelerators 288.  *	+ ESC - reserved for escaping the menu 289.  *	+ NULL, CR or LF - reserved for commiting the selection(s). NULL 290.  *	  is kind of odd, but the tty's xwaitforspace will return it if  291. *	 someone hits a. 292.  *	+ a default object class symbol - used for object class accelerators 293.  *  294.   * Standard letters (for now) are: 295.  *  296.   *		<  back 1 page 297.  *		>  forward 1 page 298.  *		^  first page 299.  *		|  last page 300.  *		:  search 301.  *  302.   *		page		all 303.  *		,    select	. 304.  *		 \    deselect	 - 305.  *		 ~    invert	 @ 306.  *  307.   * The command name list is duplicated in the compopt array. 308.  */  309.  typedef struct { 310.     const char *name; 311.     char cmd; 312. } menu_cmd_t; 313.  314.  #define NUM_MENU_CMDS 11 315. static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = { 316. /* 0*/	{ "menu_first_page",	MENU_FIRST_PAGE }, 317. 	{ "menu_last_page",	MENU_LAST_PAGE }, 318. 	{ "menu_next_page",	MENU_NEXT_PAGE }, 319. 	{ "menu_previous_page",	MENU_PREVIOUS_PAGE }, 320. 	{ "menu_select_all",	MENU_SELECT_ALL }, 321. /* 5*/	{ "menu_deselect_all",	MENU_UNSELECT_ALL }, 322. 	{ "menu_invert_all",	MENU_INVERT_ALL }, 323. 	{ "menu_select_page",	MENU_SELECT_PAGE }, 324. 	{ "menu_deselect_page",	MENU_UNSELECT_PAGE }, 325. 	{ "menu_invert_page",	MENU_INVERT_PAGE }, 326. /*10*/	{ "menu_search",		MENU_SEARCH }, 327. };  328.   329.  /*  330.   * Allow the user to map incoming characters to various menu commands. 331.  * The accelerator list must be a valid C string. 332.  */  333.  #define MAX_MENU_MAPPED_CMDS 32	/* some number */ 334.        char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1];	/* exported */ 335. static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1]; 336. static short n_menu_mapped = 0; 337.  338.   339.  static boolean initial, from_file; 340.  341.  STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,const char *,int)); 342. STATIC_DCL void FDECL(nmcpy, (char *, const char *, int)); 343. STATIC_DCL void FDECL(escapes, (const char *, char *)); 344. STATIC_DCL int FDECL(boolopt_only_initial, (int)); 345. STATIC_DCL void FDECL(rejectoption, (const char *)); 346. STATIC_DCL void FDECL(badoption, (const char *)); 347. STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P)); 348. STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P)); 349. STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P)); 350. STATIC_DCL int FDECL(change_inv_order, (char *)); 351. STATIC_DCL void FDECL(oc_to_str, (char *, char *)); 352. STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int)); 353. STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *)); 354.  355.  /* check whether a user-supplied option string is a proper leading 356.    substring of a particular option name; option string might have 357.    a colon or equals sign and arbitrary value appended to it */ 358. boolean 359. match_optname(user_string, opt_name, min_length, val_allowed) 360. const char *user_string, *opt_name; 361. int min_length; 362. boolean val_allowed; 363. {  364.  	int len = (int)strlen(user_string); 365.  366.  	if (val_allowed) { 367. 	    const char *p = index(user_string, ':'), 368. 		       *q = index(user_string, '='); 369.  370.  	    if (!p || (q && q < p)) p = q;  371. while(p && p > user_string && isspace(*(p-1))) p--; 372. 	    if (p) len = (int)(p - user_string); 373. 	}  374.   375.  	return (len >= min_length) && !strncmpi(opt_name, user_string, len); 376. }  377.   378.  void 379. initoptions 380. {  381.  	char *opts; 382. 	int i;  383. 384. 	/* initialize the random number generator */ 385. 	setrandom; 386.  387.  	for (i = 0; boolopt[i].name; i++) { 388. 		if (boolopt[i].addr) 389. 			*(boolopt[i].addr) = boolopt[i].initvalue; 390. 	}  391.  	flags.end_own = FALSE; 392. 	flags.end_top = 3; 393. 	flags.end_around = 2; 394. 	iflags.msg_history = 20; 395.  396.  	/* Use negative indices to indicate not yet selected */ 397. 	flags.initrole = -1; 398. 	flags.initrace = -1; 399. 	flags.initgend = -1; 400. 	flags.initalign = -1; 401.  402.  	/* Set the default monster and object class symbols. Don't use */ 403. 	/* memcpy --- sizeof char != sizeof uchar on some machines. */ 404.  	for (i = 0; i < MAXOCLASSES; i++) 405. 		oc_syms[i] = (uchar) def_oc_syms[i]; 406. 	for (i = 0; i < MAXMCLASSES; i++) 407. 		monsyms[i] = (uchar) def_monsyms[i]; 408.  409.       /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */ 410. 	(void)memcpy((genericptr_t)flags.inv_order,  411.  		     (genericptr_t)def_inv_order, sizeof flags.inv_order); 412. 	flags.pickup_types[0] = '\0'; 413. 	flags.pickup_burden = MOD_ENCUMBER; 414.  415.  	switch_graphics(ASCII_GRAPHICS);	/* set default characters */ 416. #if defined(UNIX) && defined(TTY_GRAPHICS) 417. 	/*  418.  	 * Set defaults for some options depending on what we can 419. 	 * detect about the environment's capabilities. 420. 	 * This has to be done after the global initialization above 421. 	 * and before reading user-specific initialization via 422. 	 * config file/environment variable below. 423. 	 */  424.  	/* this detects the IBM-compatible console on most 386 boxes */ 425. 	if (!strncmp(getenv("TERM"), "AT", 2)) { 426. 		switch_graphics(IBM_GRAPHICS); 427. # ifdef TEXTCOLOR 428. 		iflags.use_color = TRUE; 429. # endif 430. 	}  431.  #endif /* UNIX && TTY_GRAPHICS */ 432. #if defined(UNIX) || defined(VMS) 433. # ifdef TTY_GRAPHICS 434. 	/* detect whether a "vt" terminal can handle alternate charsets */ 435. 	if (!strncmpi(getenv("TERM"), "vt", 2) && (AS && AE) &&  436.  	    index(AS, '\016') && index(AE, '\017')) { 437. 		switch_graphics(DEC_GRAPHICS); 438. 	}  439.  # endif 440. #endif /* UNIX || VMS */ 441.  442.  #ifdef MAC_GRAPHICS_ENV 443. 	switch_graphics(MAC_GRAPHICS); 444. #endif /* MAC_GRAPHICS_ENV */ 445. 	flags.menu_style = MENU_FULL; 446.  447.  	/* since this is done before init_objects, do partial init here */ 448. 	objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; 449. 	nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); 450. #ifndef MAC 451. 	opts = getenv("NETHACKOPTIONS"); 452. 	if (!opts) opts = getenv("HACKOPTIONS"); 453. 	if (opts) { 454. 		if (*opts == '/' || *opts == '\\' || *opts == '@') { 455. 			if (*opts == '@') opts++;	/* @filename */ 456. 			/* looks like a filename */ 457. 			read_config_file(opts); 458. 		} else { 459. 			read_config_file((char *)0); 460. 			parseoptions(opts, TRUE, FALSE); 461. 		}  462.  	} else 463. #endif 464. 		read_config_file((char *)0); 465. #ifdef AMIGA 466. 	ami_wbench_init;	/* must be here or can't set fruit */ 467. #endif 468. 	(void)fruitadd(pl_fruit); 469. 	/* Remove "slime mold" from list of object names; this will	*/ 470. 	/* prevent it from being wished unless it's actually present	*/ 471. 	/* as a named (or default) fruit. Wishing for "fruit" will	*/ 472. 	/* result in the player's preferred fruit [better than "\033"]. */ 473.  	obj_descr[SLIME_MOLD].oc_name = "fruit"; 474.  475.  	return; 476. }  477.   478.  STATIC_OVL void 479. nmcpy(dest, src, maxlen) 480. 	char	*dest; 481. 	const char *src; 482. 	int	maxlen; 483. {  484.  	int	count; 485.  486.  	for(count = 1; count < maxlen; count++) { 487. 		if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/ 488. 		*dest++ = *src++; 489. 	}  490.  	*dest = 0; 491. }  492.   493.  /*  494.   * escapes: escape expansion for showsyms. C-style escapes understood include 495.  * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix 496.  * for control characters is also understood, and \[mM] followed by any of the 497.  * previous forms or by a character has the effect of 'meta'-ing the value (so  498.   * that the alternate character set will be enabled). 499.  */  500.  STATIC_OVL void 501. escapes(cp, tp) 502. const char	*cp; 503. char *tp; 504. {  505.      while (*cp) 506.     {  507.  	int	cval = 0, meta = 0; 508.  509.  	if (*cp == '\\' && index("mM", cp[1])) { 510. 		meta = 1; 511. 		cp += 2; 512. 	}  513.  	if (*cp == '\\' && index("0123456789xXoO", cp[1])) 514. 	{  515.  	    const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF"; 516. 	    int dcount = 0; 517.  518.  	    cp++; 519. 	    if (*cp == 'x' || *cp == 'X') 520. 		for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++) 521. 		    cval = (cval * 16) + (dp - hex) / 2; 522. 	    else if (*cp == 'o' || *cp == 'O') 523. 		for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++) 524. 		    cval = (cval * 8) + (*cp - '0'); 525. 	    else 526. 		for ((index("0123456789",*cp)) && (dcount++ < 3); cp++) 527. 		    cval = (cval * 10) + (*cp - '0'); 528. 	}  529.  	else if (*cp == '\\')		/* C-style character escapes */ 530. 	{  531.  	    switch (*++cp) 532. 	    {  533.  	    case '\\': cval = '\\'; break; 534. 	    case 'n': cval = '\n'; break; 535. 	    case 't': cval = '\t'; break; 536. 	    case 'b': cval = '\b'; break; 537. 	    case 'r': cval = '\r'; break; 538. 	    default: cval = *cp; 539. 	    }  540.  	    cp++; 541. 	}  542.  	else if (*cp == '^')		/* expand control-character syntax */ 543. 	{  544.  	    cval = (*++cp & 0x1f); 545. 	    cp++; 546. 	}  547.  	else 548. 	    cval = *cp++; 549. 	if (meta) 550. 	    cval |= 0x80; 551. 	*tp++ = cval; 552.     }  553.      *tp = '\0'; 554. }  555.   556.  /* some boolean options can only be set on start-up */ 557. STATIC_OVL int 558. boolopt_only_initial(i) 559. int i;  560. { 561.  	return (boolopt[i].addr == &flags.female  562.  	     || boolopt[i].addr == &flags.legacy  563.  #if defined(MICRO) && !defined(AMIGA)  564.  	     || boolopt[i].addr == &iflags.rawio  565.  	     || boolopt[i].addr == &iflags.BIOS  566.  #endif  567.  #if defined(MSDOS) && defined(USE_TILES)  568.  	     || boolopt[i].addr == &iflags.preload_tiles  569.  #endif  570.  	); 571. }  572.   573.  STATIC_OVL void 574. rejectoption(optname) 575. const char *optname; 576. {  577.  #ifdef MICRO 578. # ifdef AMIGA 579. 	if(FromWBench){ 580. 		pline("\"%s\" settable only from %s or in icon.",  581.  			optname, configfile); 582. 	} else 583. # endif 584. 		pline("\"%s\" settable only from %s.", optname, configfile); 585. #else 586. 	pline("%s can be set only from NETHACKOPTIONS or %s.", optname,  587.  			configfile); 588. #endif 589. }  590.   591.  STATIC_OVL void 592. badoption(opts) 593. const char *opts; 594. {  595.  	if (!initial) { 596. 	    if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1)) 597. 		option_help; 598. 	    else 599. 		pline("Bad syntax: %s.  Enter \"?g\" for help.", opts); 600. 	    return; 601. 	}  602.  # ifdef AMIGA 603. 	if(ami_wbench_badopt(opts)) { 604. # endif 605. 	if(from_file) 606. 	    raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts); 607. 	else 608. 	    raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts); 609. # ifdef AMIGA 610. 	}  611.  # endif 612. 	wait_synch; 613. }  614.   615.  STATIC_OVL char * 616. string_for_opt(opts, val_optional) 617. char *opts; 618. boolean val_optional; 619. {  620.  	char *colon, *equals; 621.  622.  	colon = index(opts, ':'); 623. 	equals = index(opts, '='); 624. 	if (!colon || (equals && equals < colon)) colon = equals; 625.  626.  	if (!colon || !*++colon) { 627. 		if (!val_optional) badoption(opts); 628. 		return (char *)0; 629. 	}  630.  	return colon; 631. }  632.   633.  STATIC_OVL char * 634. string_for_env_opt(optname, opts, val_optional) 635. const char *optname; 636. char *opts; 637. boolean val_optional; 638. {  639.  	if(!initial) { 640. 		rejectoption(optname); 641. 		return (char *)0; 642. 	}  643.  	return string_for_opt(opts, val_optional); 644. }  645.   646.  STATIC_OVL void 647. bad_negation(optname, with_parameter) 648. const char *optname; 649. boolean with_parameter; 650. {  651.  	pline_The("%s option may not %sbe negated.",  652.  		optname,  653.  		with_parameter ? "both have a value and " : ""); 654. }  655.   656.  /*  657.   * Change the inventory order, using the given string as the new order. 658.  * Missing characters in the new order are filled in at the end from 659.  * the current inv_order, except for gold, which is forced to be first 660.  * if not explicitly present. 661.  *  662.   * This routine returns 1 unless there is a duplicate or bad char in  663. * the string. 664.  */  665.  STATIC_OVL int 666. change_inv_order(op) 667. char *op; 668. {  669.      int oc_sym, num; 670.     char *sp, buf[BUFSZ]; 671.  672.      num = 0; 673.     if (!index(op, GOLD_SYM)) 674. 	buf[num++] = GOLD_CLASS; 675.  676.      for (sp = op; *sp; sp++) { 677. 	oc_sym = def_char_to_objclass(*sp); 678. 	/* reject bad or duplicate entries */ 679. 	if (oc_sym == MAXOCLASSES ||  680.  		oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS ||  681.  		!index(flags.inv_order, oc_sym) || index(sp+1, *sp)) 682. 	    return 0; 683. 	/* retain good ones */ 684. 	buf[num++] = (char) oc_sym; 685.     }  686.      buf[num] = '\0'; 687.  688.      /* fill in any omitted classes, using previous ordering */ 689.     for (sp = flags.inv_order; *sp; sp++) 690. 	if (!index(buf, *sp)) { 691. 	    buf[num++] = *sp; 692. 	    buf[num] = '\0';	/* explicitly terminate for next index */ 693. 	}  694.   695.      Strcpy(flags.inv_order, buf); 696.     return 1; 697. }  698.   699.  STATIC_OVL void 700. graphics_opts(opts, optype, maxlen, offset) 701. register char *opts; 702. const char *optype; 703. int maxlen, offset; 704. {  705.  	uchar translate[MAXPCHARS+1]; 706. 	int length, i;  707. 708. 	if (!(opts = string_for_env_opt(optype, opts, FALSE))) 709. 		return; 710. 	escapes(opts, opts); 711.  712.  	length = strlen(opts); 713. 	if (length > maxlen) length = maxlen; 714. 	/* match the form obtained from PC configuration files */ 715. 	for (i = 0; i < length; i++) 716. 		translate[i] = (uchar) opts[i]; 717. 	assign_graphics(translate, length, maxlen, offset); 718. }  719.   720.  STATIC_OVL int 721. feature_alert_opts(op, optn) 722. char *op; 723. const char *optn; 724. {  725.  	char buf[BUFSZ]; 726. 	boolean rejectver = FALSE; 727. 	unsigned long fnv = get_feature_notice_ver(op);		/* version.c */ 728. 	if (fnv == 0L) return 0; 729. 	if (fnv > get_current_feature_ver) 730. 		rejectver = TRUE; 731. 	else 732. 		flags.suppress_alert = fnv; 733. 	if (rejectver) { 734. 		if (!initial) 735. 			You_cant("disable new feature alerts for future versions."); 736. 		else { 737. 			Sprintf(buf,  738.  				"\n%s=%s Invalid reference to a future version ignored",  739.  				optn, op); 740. 			badoption(buf); 741. 		}  742.  		return 0; 743. 	}  744.  	if (!initial) { 745. 		Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ,  746.  			FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH); 747. 		pline("Feature change alerts disabled for NetHack %s features and prior.",  748.  			buf); 749. 	}  750.  	return 1; 751. }  752.   753.  void 754. parseoptions(opts, tinitial, tfrom_file) 755. register char *opts; 756. boolean tinitial, tfrom_file; 757. {  758.  	register char *op; 759. 	unsigned num; 760. 	boolean negated; 761. 	int i;  762. const char *fullname; 763.  764.  	initial = tinitial; 765. 	from_file = tfrom_file; 766. 	if ((op = index(opts, ',')) != 0) { 767. 		*op++ = 0; 768. 		parseoptions(op, initial, from_file); 769. 	}  770.   771.  	/* strip leading and trailing white space */ 772. 	while (isspace(*opts)) opts++; 773. 	op = eos(opts); 774. 	while (--op >= opts && isspace(*op)) *op = '\0'; 775.  776.  	if (!*opts) return; 777. 	negated = FALSE; 778. 	while ((*opts == '!') || !strncmpi(opts, "no", 2)) { 779. 		if (*opts == '!') opts++; else opts += 2; 780. 		negated = !negated; 781. 	}  782.   783.  	/* variant spelling */ 784.  785.  	if (match_optname(opts, "colour", 5, FALSE)) 786. 		Strcpy(opts, "color");	/* fortunately this isn't longer */ 787.  788.  	/* special boolean options */ 789.  790.  	if (match_optname(opts, "female", 3, FALSE)) { 791. 		if(!initial && flags.female == negated) 792. 			pline("That is not anatomically possible."); 793. 		else 794. 			flags.initgend = flags.female = !negated; 795. 		return; 796. 	}  797.   798.  	if (match_optname(opts, "male", 4, FALSE)) { 799. 		if(!initial && flags.female != negated) 800. 			pline("That is not anatomically possible."); 801. 		else 802. 			flags.initgend = flags.female = negated; 803. 		return; 804. 	}  805.   806.  #if defined(MICRO) && !defined(AMIGA) 807. 	/* included for compatibility with old NetHack.cnf files */ 808. 	if (match_optname(opts, "IBM_", 4, FALSE)) { 809. 		iflags.BIOS = !negated; 810. 		return; 811. 	}  812.  #endif /* MICRO */ 813.  814.  	/* compound options */ 815.  816.  	fullname = "pettype"; 817. 	if (match_optname(opts, fullname, 3, TRUE)) { 818. 		if ((op = string_for_env_opt(fullname, opts, negated)) != 0) { 819. 		    if (negated) bad_negation(fullname, TRUE); 820. 		    else switch (*op) { 821. 			case 'd':	/* dog */ 822. 			case 'D': 823. 			    preferred_pet = 'd'; 824. 			    break; 825. 			case 'c':	/* cat */ 826. 			case 'C': 827. 			case 'f':	/* feline */ 828. 			case 'F': 829. 			    preferred_pet = 'c'; 830. 			    break; 831. 			default: 832. 			    pline("Unrecognized pet type '%s'", op); 833. 			    break; 834. 		    }  835.  		} else if (negated) preferred_pet = 0; 836. 		return; 837. 	}  838.   839.  	fullname = "catname"; 840. 	if (match_optname(opts, fullname, 3, TRUE)) { 841. 		if (negated) bad_negation(fullname, FALSE); 842. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 843. 			nmcpy(catname, op, PL_PSIZ); 844. 		return; 845. 	}  846.   847.  	fullname = "dogname"; 848. 	if (match_optname(opts, fullname, 3, TRUE)) { 849. 		if (negated) bad_negation(fullname, FALSE); 850. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 851. 			nmcpy(dogname, op, PL_PSIZ); 852. 		return; 853. 	}  854.   855.  	fullname = "horsename"; 856. 	if (match_optname(opts, fullname, 5, TRUE)) { 857. 		if (negated) bad_negation(fullname, FALSE); 858. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 859. 			nmcpy(horsename, op, PL_PSIZ); 860. 		return; 861. 	}  862.   863.  	fullname = "msghistory"; 864. 	if (match_optname(opts, fullname, 3, TRUE)) { 865. 		op = string_for_env_opt(fullname, opts, negated); 866. 		if ((negated && !op) || (!negated && op)) { 867. 			iflags.msg_history = negated ? 0 : atoi(op); 868. 		} else if (negated) bad_negation(fullname, TRUE); 869. 		return; 870. 	}  871.   872.  #ifdef CHANGE_COLOR 873. #ifdef MAC 874. 	fullname = "use_stone"; 875. 	if (match_optname(opts, fullname, 6, TRUE)) { 876. 		op = string_for_env_opt(fullname, opts, negated); 877. 		if ((negated && !op) || (!negated && op)) { 878. 			iflags.use_stone = negated ? 0 : atoi(op); 879. 		} else if (negated) bad_negation(fullname, TRUE); 880. 		return; 881. 	}  882.   883.  	fullname = "background"; 884. 	if (match_optname(opts, fullname, 5,TRUE)) 885. 	{  886.  		if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 887. 		{  888.  			if (!strncmpi (op, "white", 5)) 889. 				change_background (1); 890. 			else if (!strncmpi (op, "black", 5)) 891. 				change_background (0); 892. 		}  893.  		return; 894. 	}  895.  	  896.  	fullname = "font"; 897. 	if (!strncmpi(opts, fullname, 4)) 898. 	{	int wintype = -1; 899. 	  900.  		opts += 4; 901. 		if (!strncmpi (opts, "map", 3)) 902. 			wintype = NHW_MAP; 903. 		else if (!strncmpi (opts, "message", 7)) 904. 			wintype = NHW_MESSAGE; 905. 		else if (!strncmpi (opts, "text", 4)) 906. 			wintype = NHW_TEXT; 907. 				  908.  		if (wintype > 0 && (op = string_for_env_opt(fullname, opts, FALSE)) != 0) 909. 		{	set_font_name (wintype, op); 910. 		}  911.  		return; 912. 	}  913.  #endif 914. 	if (match_optname(opts, "palette", 3, TRUE)  915.  # ifdef MAC  916.  					|| match_optname(opts, "hicolor", 3, TRUE)  917.  # endif  918.  									) { 919. 	    int color_number, color_incr; 920.  921.  # ifdef MAC 922. 	    if (match_optname(opts, "hicolor", 3, TRUE)) { 923. 		if (negated) { 924. 		    bad_negation("hicolor", FALSE); 925. 		    return; 926. 		}  927.  		color_number = CLR_MAX + 4;	/* HARDCODED inverse number */ 928. 		color_incr = -1; 929. 	    } else { 930. # endif 931. 		if (negated) { 932. 		    bad_negation("palette", FALSE); 933. 		    return; 934. 		}  935.  		color_number = 0; 936. 		color_incr = 1; 937. # ifdef MAC 938. 	    }  939.  # endif 940. 	    if ((op = string_for_opt(opts, FALSE)) != (char *)0) { 941. 		char *pt = op; 942. 		int cnt, tmp, reverse; 943. 		long rgb; 944.  945.  		while (*pt && color_number >= 0) { 946. 		    cnt = 3; 947. 		    rgb = 0L; 948. 		    if (*pt == '-') { 949. 			reverse = 1; 950. 			pt++; 951. 		    } else { 952. 			reverse = 0; 953. 		    }  954.  		    while (cnt-- > 0) { 955. 			if (*pt && *pt != '/') { 956. # ifdef AMIGA 957. 			    rgb <<= 4; 958. # else 959. 			    rgb <<= 8; 960. # endif 961. 			    tmp = *(pt++); 962. 			    if (isalpha(tmp)) { 963. 				tmp = (tmp + 9) & 0xf;	/* Assumes ASCII... */ 964.  			    } else { 965. 				tmp &= 0xf;	/* Digits in ASCII too... */ 966.  			    }  967.  # ifndef AMIGA 968. 			    /* Add an extra so we fill f -> ff and 0 -> 00 */ 969. 			    rgb += tmp << 4; 970. # endif 971. 			    rgb += tmp; 972. 			}  973.  		    }  974.  		    if (*pt == '/') { 975. 			pt++; 976. 		    }  977.  		    change_color(color_number, rgb, reverse); 978. 		    color_number += color_incr; 979. 		}  980.  	    }  981.  	    if (!initial) { 982. 		need_redraw = TRUE; 983. 	    }  984.  	    return; 985. 	}  986.  #endif 987.  988.  	if (match_optname(opts, "fruit", 2, TRUE)) { 989. 		char empty_str = '\0'; 990. 		op = string_for_opt(opts, negated); 991. 		if (negated) { 992. 		    if (op) { 993. 			bad_negation("fruit", TRUE); 994. 			return; 995. 		    }  996.  		    op = &empty_str; 997. 		    goto goodfruit; 998. 		}  999.  		if (!op) return; 1000. 		if (!initial) { 1001. 		   struct fruit *f; 1002. 1003. 		    num = 0; 1004. 		   for(f=ffruit; f; f=f->nextf) { 1005. 			if (!strcmp(op, f->fname)) goto goodfruit; 1006. 			num++; 1007. 		   }  1008. 		    if (num >= 100) { 1009. 			pline("Doing that so many times isn't very fruitful."); 1010. 			return; 1011. 		   }  1012. 		}  1013. goodfruit: 1014. 		nmcpy(pl_fruit, op, PL_FSIZ); 1015. 	/* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */ 1016. 		if (!*pl_fruit) 1017. 		   nmcpy(pl_fruit, "slime mold", PL_FSIZ); 1018. 		if (!initial) 1019. 		   (void)fruitadd(pl_fruit); 1020. 		/* If initial, then initoptions is allowed to do it instead 1021. 		 * of here (initoptions always has to do it even if there's 1022. 		 * no fruit option at all.  Also, we don't want people  1023. 		 * setting multiple fruits in their options.) 1024. 		 */ 1025. 		return; 1026. 	} 1027.  1028. 	/* graphics:string */ 1029. 	fullname = "graphics"; 1030. 	if (match_optname(opts, fullname, 2, TRUE)) { 1031. 		if (negated) bad_negation(fullname, FALSE); 1032. 		else graphics_opts(opts, fullname, MAXPCHARS, 0); 1033. 		return; 1034. 	} 1035. 	fullname = "dungeon"; 1036. 	if (match_optname(opts, fullname, 2, TRUE)) { 1037. 		if (negated) bad_negation(fullname, FALSE); 1038. 		else graphics_opts(opts, fullname, MAXDCHARS, 0); 1039. 		return; 1040. 	} 1041. 	fullname = "traps"; 1042. 	if (match_optname(opts, fullname, 2, TRUE)) { 1043. 		if (negated) bad_negation(fullname, FALSE); 1044. 		else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS); 1045. 		return; 1046. 	} 1047. 	fullname = "effects"; 1048. 	if (match_optname(opts, fullname, 2, TRUE)) { 1049. 		if (negated) bad_negation(fullname, FALSE); 1050. 		else 1051. 		 graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS); 1052. 		return; 1053. 	} 1054.  1055. 	/* objects:string */ 1056. 	fullname = "objects"; 1057. 	if (match_optname(opts, fullname, 7, TRUE)) { 1058. 		int length; 1059. 1060. 		if (negated) { 1061. 		   bad_negation(fullname, FALSE); 1062. 		   return; 1063. 		} 1064. 		if (!(opts = string_for_env_opt(fullname, opts, FALSE))) 1065. 			return; 1066. 		escapes(opts, opts); 1067. 1068. 		/*  1069. 		 * Override the default object class symbols. The first 1070. 		 * object in the object class is the "random object". I 1071. * don't want to use 0 as an object class, so the "random 1072. 		 * object" is basically a place holder. 1073. 		 * 1074. 		 * The object class symbols have already been initialized in  1075. * initoptions. 1076. 		 */ 1077. 		length = strlen(opts); 1078. 		if (length >= MAXOCLASSES) 1079. 		   length = MAXOCLASSES-1;	/* don't count RANDOM_OBJECT */ 1080. 1081. 		for (i = 0; i < length; i++) 1082. 		   oc_syms[i+1] = (uchar) opts[i]; 1083. 		return; 1084. 	} 1085.  1086. 	/* monsters:string */ 1087. 	fullname = "monsters"; 1088. 	if (match_optname(opts, fullname, 8, TRUE)) { 1089. 		int length; 1090. 1091. 		if (negated) { 1092. 		   bad_negation(fullname, FALSE); 1093. 		   return; 1094. 		} 1095. 		if (!(opts = string_for_env_opt(fullname, opts, FALSE))) 1096. 			return; 1097. 		escapes(opts, opts); 1098. 1099. 		/* Override default mon class symbols set in initoptions. */ 1100. 		length = strlen(opts); 1101. 		if (length >= MAXMCLASSES) 1102. 		   length = MAXMCLASSES-1;	/* mon class 0 unused */ 1103. 1104. 		for (i = 0; i < length; i++) 1105. 		   monsyms[i+1] = (uchar) opts[i]; 1106. 		return; 1107. 	} 1108.  1109. 	/* name:string */ 1110. 	fullname = "name"; 1111. 	if (match_optname(opts, fullname, 4, TRUE)) { 1112. 		if (negated) bad_negation(fullname, FALSE); 1113. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1114. 			nmcpy(plname, op, PL_NSIZ); 1115. 		return; 1116. 	} 1117.  1118. 	/* role:string or character:string */ 1119. 	fullname = "role"; 1120. 	if (match_optname(opts, fullname, 4, TRUE) || 1121. 	    match_optname(opts, (fullname = "character"), 4, TRUE)) { 1122. 		if (negated) bad_negation(fullname, FALSE); 1123. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1124. 			if ((flags.initrole = str2role(op)) < 0) 1125. 				badoption(opts); 1126. 			else /* Backwards compatibility */ 1127. 				nmcpy(pl_character, op, PL_NSIZ); 1128. 		return; 1129. 	} 1130.  1131. 	/* race:string */ 1132. 	fullname = "race"; 1133. 	if (match_optname(opts, fullname, 4, TRUE)) { 1134. 		if (negated) bad_negation(fullname, FALSE); 1135. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1136. 			if ((flags.initrace = str2race(op)) < 0) 1137. 				badoption(opts); 1138. 			else /* Backwards compatibility */ 1139. 				pl_race = *op; 1140. 		return; 1141. 	} 1142.  1143. 	/* gender:string */ 1144. 	fullname = "gender"; 1145. 	if (match_optname(opts, fullname, 4, TRUE)) { 1146. 		if (negated) bad_negation(fullname, FALSE); 1147. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1148. 			if ((flags.initgend = str2gend(op)) < 0) 1149. 				badoption(opts); 1150. 			else 1151. 				flags.female = flags.initgend; 1152. 		return; 1153. 	} 1154.  1155. 	/* align:string */ 1156. 	fullname = "align"; 1157. 	if (match_optname(opts, fullname, 4, TRUE)) { 1158. 		if (negated) bad_negation(fullname, FALSE); 1159. 		else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) 1160. 			if ((flags.initalign = str2align(op)) < 0) 1161. 				badoption(opts); 1162. 		return; 1163. 	} 1164.  1165. 	/* the order to list the pack */ 1166. 	fullname = "packorder"; 1167. 	if (match_optname(opts, fullname, 4, TRUE)) { 1168. 		if (negated) { 1169. 		   bad_negation(fullname, FALSE); 1170. 		   return; 1171. 		} else if (!(op = string_for_opt(opts, FALSE))) return; 1172. 1173. 		if (!change_inv_order(op)) 1174. 			badoption(opts); 1175. 		return; 1176. 	} 1177.  1178. 	/* maximum burden picked up before prompt (Warren Cheung) */ 1179. 	fullname = "pickup_burden"; 1180. 	if (match_optname(opts, fullname, 8, TRUE)) { 1181. 		if (negated) { 1182. 			bad_negation(fullname, FALSE); 1183. 			return; 1184. 		} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { 1185. 		   switch (tolower(*op)) { 1186. 				/* Unencumbered */ 1187. 				case 'u': 1188. 					flags.pickup_burden = UNENCUMBERED; 1189. 					break; 1190. 				/* Burdened (slight encumberance) */ 1191. 				case 'b': 1192. 					flags.pickup_burden = SLT_ENCUMBER; 1193. 					break; 1194. 				/* streSsed (moderate encumberance) */ 1195. 				case 's': 1196. 					flags.pickup_burden = MOD_ENCUMBER; 1197. 					break; 1198. 				/* straiNed (heavy encumberance) */ 1199. 				case 'n': 1200. 					flags.pickup_burden = HVY_ENCUMBER; 1201. 					break; 1202. 				/* OverTaxed (extreme encumberance) */ 1203. 				case 'o': 1204. 				case 't': 1205. 					flags.pickup_burden = EXT_ENCUMBER; 1206. 					break; 1207. 				/* overLoaded */ 1208. 				case 'l': 1209. 					flags.pickup_burden = OVERLOADED; 1210. 					break; 1211. 				default: 1212. 				badoption(opts); 1213. 		   }  1214. 		}  1215. 		return; 1216. 	} 1217.  1218. 	/* types of objects to pick up automatically */ 1219. 	if (match_optname(opts, "pickup_types", 8, TRUE)) { 1220. 		char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], 1221. 		    qbuf[QBUFSZ], abuf[BUFSZ]; 1222. 		int oc_sym; 1223. 		boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu; 1224. 1225. 		oc_to_str(flags.pickup_types, tbuf); 1226. 		flags.pickup_types[0] = '\0';	/* all */ 1227. 		op = string_for_opt(opts, (compat || !initial)); 1228. 		if (!op) { 1229. 		   if (compat || negated || initial) { 1230. 			/* for backwards compatibility, "pickup" without a 1231. value is a synonym for autopickup of all types 1232. 			  (and during initialization, we can't prompt yet) */ 1233. 			flags.pickup = !negated; 1234. 			return; 1235. 		   }  1236. 		    oc_to_str(flags.inv_order, ocl); 1237. 		   use_menu = TRUE; 1238. 		   if (flags.menu_style == MENU_TRADITIONAL ||  1239. 			    flags.menu_style == MENU_COMBINATION) { 1240. 			use_menu = FALSE; 1241. 			Sprintf(qbuf, "New pickup_types: [%s am] (%s)", 1242. 				ocl, *tbuf ? tbuf : "all"); 1243. 			getlin(qbuf, abuf); 1244. 			op = mungspaces(abuf); 1245. 			if (abuf[0] == '\0' || abuf[0] == '\033') 1246. 			   op = tbuf;		/* restore */ 1247. 			else if (abuf[0] == 'm') 1248. 			   use_menu = TRUE; 1249. 		   }  1250. 		    if (use_menu) { 1251. 			(void) choose_classes_menu("Auto-Pickup what?", 1, 1252. 						   TRUE, ocl, tbuf); 1253. 			op = tbuf; 1254. 		   }  1255. 		}  1256. 		if (negated) { 1257. 		   bad_negation("pickup_types", TRUE); 1258. 		   return; 1259. 		} 1260. 		while (*op == ' ') op++; 1261. 		if (*op != 'a' && *op != 'A') { 1262. 		   num = 0; 1263. 		   while (*op) { 1264. 			oc_sym = def_char_to_objclass(*op); 1265. 			/* make sure all are valid obj symbols occuring once */ 1266. 			if (oc_sym != MAXOCLASSES && 1267. 			    !index(flags.pickup_types, oc_sym)) { 1268. 			   flags.pickup_types[num] = (char)oc_sym; 1269. 			   flags.pickup_types[++num] = '\0'; 1270. 			} else 1271. 			   badopt = TRUE; 1272. 			op++; 1273. 		   }  1274. 		    if (badopt) badoption(opts); 1275. 		} 1276. 		return; 1277. 	} 1278.  1279. 	/* things to disclose at end of game */ 1280. 	if (match_optname(opts, "disclose", 4, TRUE)) { 1281. 		flags.end_disclose[0] = '\0';	/* all */ 1282. 		if (!(op = string_for_opt(opts, TRUE))) { 1283. 			/* for backwards compatibility, "disclose" without a 1284. * value means all (was inventory and attributes, 1285. 			 * the only things available then), but negated 1286. 			 * it means "none" 1287. 			 * (note "none" contains none of "iavkg") 1288. 			 */ 1289. 			if (negated) Strcpy(flags.end_disclose, "none"); 1290. 			return; 1291. 		} 1292. 		if (negated) { 1293. 			bad_negation("disclose", TRUE); 1294. 			return; 1295. 		} 1296. 		num = 0; 1297. 		while (*op && num < sizeof flags.end_disclose - 1) { 1298. 			register char c; 1299. c = lowc(*op); 1300. 			if (c == 'k') c = 'v';	/* killed -> vanquished */ 1301. 			if (!index(flags.end_disclose, c)) { 1302. 				flags.end_disclose[num++] = c; 1303. flags.end_disclose[num] = '\0';	/* for index */ 1304. 			} 1305. 			op++; 1306. 		} 1307. 		return; 1308. 	} 1309.  1310. 	/* scores:5t[op] 5a[round] o[wn] */ 1311. 	if (match_optname(opts, "scores", 4, TRUE)) { 1312. 	   if (negated) { 1313. 		bad_negation("scores", FALSE); 1314. 		return; 1315. 	   }  1316. 	    if (!(op = string_for_opt(opts, FALSE))) return; 1317. 1318. 	    while (*op) { 1319. 		int inum = 1; 1320. 1321. 		if (digit(*op)) { 1322. 		   inum = atoi(op); 1323. 		   while (digit(*op)) op++; 1324. 		} else if (*op == '!') { 1325. 		   negated = !negated; 1326. 		   op++; 1327. 		} 1328. 		while (*op == ' ') op++; 1329. 1330. 		switch (*op) { 1331. 		 case 't': 1332. 		 case 'T': flags.end_top = inum; 1333. 			   break; 1334. 		 case 'a': 1335. 		 case 'A': flags.end_around = inum; 1336. 			   break; 1337. 		 case 'o': 1338. 		 case 'O': flags.end_own = !negated; 1339. 			   break; 1340. 		 default:  badoption(opts); 1341. 			   return; 1342. 		} 1343. 		while (letter(*++op) || *op == ' ') continue; 1344. 		if (*op == '/') op++; 1345. 	   }  1346. 	    return; 1347. 	} 1348.  1349. 	fullname = "suppress_alert"; 1350. 	if (match_optname(opts, fullname, 4, TRUE)) { 1351. 		op = string_for_opt(opts, negated); 1352. 		if (negated) bad_negation(fullname, FALSE); 1353. 		else if (op) (void) feature_alert_opts(op,fullname); 1354. 		return; 1355. 	} 1356. 	  1357. #ifdef VIDEOSHADES 1358. 	/* videocolors:string */ 1359. 	fullname = "videocolors"; 1360. 	if (match_optname(opts, fullname, 6, TRUE) || 1361. 	    match_optname(opts, "videocolours", 10, TRUE)) { 1362. 		if (negated) { 1363. 			bad_negation(fullname, FALSE); 1364. 			return; 1365. 		} 1366. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1367. 			return; 1368. 		} 1369. 		if (!assign_videocolors(opts)) 1370. 			badoption(opts); 1371. 		return; 1372. 	} 1373. 	/* videoshades:string */ 1374. 	fullname = "videoshades"; 1375. 	if (match_optname(opts, fullname, 6, TRUE)) { 1376. 		if (negated) { 1377. 			bad_negation(fullname, FALSE); 1378. 			return; 1379. 		} 1380. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1381. 			return; 1382. 		} 1383. 		if (!assign_videoshades(opts)) 1384. 			badoption(opts); 1385. 		return; 1386. 	} 1387. #endif /* VIDEOSHADES */ 1388. #ifdef MSDOS 1389. # ifdef NO_TERMS 1390. 	/* video:string -- must be after longer tests */ 1391. 	fullname = "video"; 1392. 	if (match_optname(opts, fullname, 5, TRUE)) { 1393. 		if (negated) { 1394. 			bad_negation(fullname, FALSE); 1395. 			return; 1396. 		} 1397. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1398. 			return; 1399. 		} 1400. 		if (!assign_video(opts)) 1401. 			badoption(opts); 1402. 		return; 1403. 	} 1404. # endif /* NO_TERMS */ 1405. 	/* soundcard:string -- careful not to match boolean 'sound' */ 1406. 	fullname = "soundcard"; 1407. 	if (match_optname(opts, fullname, 6, TRUE)) { 1408. 		if (negated) { 1409. 			bad_negation(fullname, FALSE); 1410. 			return; 1411. 		} 1412. 		else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { 1413. 			return; 1414. 		} 1415. 		if (!assign_soundcard(opts)) 1416. 			badoption(opts); 1417. 		return; 1418. 	} 1419. #endif /* MSDOS */ 1420. 1421. 	fullname = "windowtype"; 1422. 	if (match_optname(opts, fullname, 3, TRUE)) { 1423. 	   if (negated) { 1424. 		bad_negation(fullname, FALSE); 1425. 		return; 1426. 	   } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { 1427. 		char buf[WINTYPELEN]; 1428. 		nmcpy(buf, op, WINTYPELEN); 1429. 		choose_windows(buf); 1430. 	   }  1431. 	    return; 1432. 	} 1433.  1434. 	/* menustyle:traditional or combo or full or partial */ 1435. 	if (match_optname(opts, "menustyle", 4, TRUE)) { 1436. 		int tmp; 1437. 		boolean val_required = (strlen(opts) > 5 && !negated); 1438. 1439. 		if (!(op = string_for_opt(opts, !val_required))) { 1440. 		   if (val_required) return; /* string_for_opt gave feedback */ 1441. 		   tmp = negated ? 'n' : 'f'; 1442. 		} else { 1443. 		   tmp = tolower(*op); 1444. 		} 1445. 		switch (tmp) { 1446. 			case 'n':	/* none */ 1447. 			case 't':	/* traditional */ 1448. 				flags.menu_style = MENU_TRADITIONAL; 1449. 				break; 1450. 			case 'c':	/* combo: trad.class sel+menu */ 1451. 				flags.menu_style = MENU_COMBINATION; 1452. 				break; 1453. 			case 'p':	/* partial: no class menu */ 1454. 				flags.menu_style = MENU_PARTIAL; 1455. 				break; 1456. 			case 'f':	/* full: class menu + menu */ 1457. 				flags.menu_style = MENU_FULL; 1458. 				break; 1459. 			default: 1460. 				badoption(opts); 1461. 		} 1462. 		return; 1463. 	} 1464.  1465. 	/* check for menu command mapping */ 1466. 	for (i = 0; i < NUM_MENU_CMDS; i++) { 1467. 	   fullname = default_menu_cmd_info[i].name; 1468. 	   if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) { 1469. 		if (negated) 1470. 		   bad_negation(fullname, FALSE); 1471. 		else if ((op = string_for_opt(opts, FALSE)) != 0) { 1472. 		   int j;  1473. char c, op_buf[BUFSZ]; 1474. 		   boolean isbad = FALSE; 1475. 1476. 		    escapes(op, op_buf); 1477. 		   c = *op_buf; 1478. 1479. 		    if (c == 0 || c == '\r' || c == '\n' || c == '\033' ||  1480. 			    c == ' ' || digit(c) || (letter(c) && c != '@')) 1481. 			isbad = TRUE; 1482. 		   else	/* reject default object class symbols */ 1483. 			for (j = 1; j < MAXOCLASSES; j++) 1484. 			   if (c == def_oc_syms[i]) { 1485. 				isbad = TRUE; 1486. 				break; 1487. 			   }  1488.  1489. 		    if (isbad) 1490. 			badoption(opts); 1491. 		   else 1492. 			add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd); 1493. 		} 1494. 		return; 1495. 	   }  1496. 	}  1497.  1498. 	/* OK, if we still haven't recognized the option, check the boolean 1499. 	 * options list 1500. 	 */ 1501. 	for (i = 0; boolopt[i].name; i++) { 1502. 		if (match_optname(opts, boolopt[i].name, 3, FALSE)) { 1503. 			/* options that don't exist */ 1504. 			if (!boolopt[i].addr) { 1505. 			   if (!initial && !negated) 1506. 				pline_The("\"%s\" option is not available.", 1507. 					boolopt[i].name); 1508. 			   return; 1509. 			} 1510. 			/* options that must come from config file */ 1511. 			if (!initial && boolopt_only_initial(i)) { 1512. 			   rejectoption(boolopt[i].name); 1513. 			   return; 1514. 			} 1515.  1516. 			*(boolopt[i].addr) = !negated; 1517. 1518. #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV) 1519. 			if (FALSE 1520. # ifdef TERMLIB  1521. 				 || (boolopt[i].addr) == &iflags.DECgraphics  1522. # endif  1523. # ifdef ASCIIGRAPH  1524. 				 || (boolopt[i].addr) == &iflags.IBMgraphics  1525. # endif  1526. # ifdef MAC_GRAPHICS_ENV  1527. 				 || (boolopt[i].addr) == &iflags.MACgraphics  1528. # endif  1529. 				) { 1530. # ifdef REINCARNATION 1531. 			   if (!initial && Is_rogue_level(&u.uz)) 1532. 				assign_rogue_graphics(FALSE); 1533. # endif 1534. 			   need_redraw = TRUE; 1535. # ifdef TERMLIB 1536. 			   if ((boolopt[i].addr) == &iflags.DECgraphics) 1537. 				switch_graphics(iflags.DECgraphics ? 1538. 						DEC_GRAPHICS : ASCII_GRAPHICS); 1539. # endif 1540. # ifdef ASCIIGRAPH 1541. 			   if ((boolopt[i].addr) == &iflags.IBMgraphics) 1542. 				switch_graphics(iflags.IBMgraphics ? 1543. 						IBM_GRAPHICS : ASCII_GRAPHICS); 1544. # endif 1545. # ifdef MAC_GRAPHICS_ENV 1546. 			   if ((boolopt[i].addr) == &iflags.MACgraphics) 1547. 				switch_graphics(iflags.MACgraphics ? 1548. 						MAC_GRAPHICS : ASCII_GRAPHICS); 1549. # endif 1550. # ifdef REINCARNATION 1551. 			   if (!initial && Is_rogue_level(&u.uz)) 1552. 				assign_rogue_graphics(TRUE); 1553. # endif 1554. 			} 1555. #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */ 1556. 1557. 			/* only do processing below if setting with doset */ 1558. 			if (initial) return; 1559. 1560. 			if ((boolopt[i].addr) == &flags.time  1561. #ifdef EXP_ON_BOTL  1562. 			 || (boolopt[i].addr) == &flags.showexp  1563. #endif  1564. #ifdef SCORE_ON_BOTL  1565. 			 || (boolopt[i].addr) == &flags.showscore  1566. #endif  1567. 			    ) 1568. 			   flags.botl = TRUE; 1569. 1570. 			else if ((boolopt[i].addr) == &flags.invlet_constant) { 1571. 			   if (flags.invlet_constant) reassign; 1572. 			} 1573. #ifdef LAN_MAIL 1574. 			else if ((boolopt[i].addr) == &flags.biff) { 1575. 			   if (flags.biff) lan_mail_init; 1576. 			   else lan_mail_finish; 1577. 			} 1578. #endif 1579. 			else if ((boolopt[i].addr) == &iflags.num_pad) 1580. 			   number_pad(iflags.num_pad ? 1 : 0); 1581. 1582. 			else if ((boolopt[i].addr) == &flags.lit_corridor) { 1583. 			   /*  1584. 			     * All corridor squares seen via night vision or  1585. * candles & lamps change. Update them by calling 1586. 			    * newsym on them. Don't do this if we are 1587. 			    * initializing the options --- the vision system 1588. 			    * isn't set up yet. 1589. 			    */  1590. 			    vision_recalc(2);		/* shut down vision */ 1591. 			   vision_full_recalc = 1;	/* delayed recalc */ 1592. 			} 1593.  1594. #ifdef TEXTCOLOR 1595. 			else if ((boolopt[i].addr) == &iflags.use_color 1596. 			      || (boolopt[i].addr) == &iflags.hilite_pet) { 1597. 			   need_redraw = TRUE; 1598. # ifdef TOS 1599. 			   if ((boolopt[i].addr) == &iflags.use_color  1600. 				&& iflags.BIOS) { 1601. 				if (colors_changed) 1602. 				   restore_colors; 1603. 				else 1604. 				   set_colors; 1605. 			   }  1606. # endif 1607. 			} 1608. #endif 1609. 1610. 			return; 1611. 		} 1612. 	}  1613.  1614. 	/* out of valid options */ 1615. 	badoption(opts); 1616. } 1617.  1618.  1619. static NEARDATA const char *menutype[] = { 1620. 	"traditional", "combination", "partial", "full" 1621. }; 1622.  1623. static NEARDATA const char *burdentype[] = { 1624. 	"unencumbered", "burdened", "stressed", 1625. 	"strained", "overtaxed", "overloaded" 1626. }; 1627.  1628.  1629. /*  1630.  * Convert the given string of object classes to a string of default object 1631. * symbols. 1632. */  1633. STATIC_OVL void 1634. oc_to_str(src,dest) 1635.    char *src, *dest; 1636. { 1637.     int i;  1638. 1639.    while ((i = (int) *src++) != 0) { 1640. 	if (i < 0 || i >= MAXOCLASSES) 1641. 	   impossible("oc_to_str:  illegal object class %d", i); 1642. 	else 1643. 	   *dest++ = def_oc_syms[i]; 1644.    }  1645.     *dest = '\0'; 1646. } 1647.  1648. /*  1649.  * Add the given mapping to the menu command map list. Always keep the 1650. * maps valid C strings. 1651. */  1652. void 1653. add_menu_cmd_alias(from_ch, to_ch) 1654.    char from_ch, to_ch; 1655. { 1656.     if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) 1657. 	pline("out of menu map space"); 1658.    else { 1659. 	mapped_menu_cmds[n_menu_mapped] = from_ch; 1660. 	mapped_menu_op[n_menu_mapped] = to_ch; 1661. 	n_menu_mapped++; 1662. 	mapped_menu_cmds[n_menu_mapped] = 0; 1663. 	mapped_menu_op[n_menu_mapped] = 0; 1664.    }  1665. }  1666.  1667. /*  1668.  * Map the given character to its corresponding menu command. If it 1669. * doesn't match anything, just return the original. 1670. */  1671. char 1672. map_menu_cmd(ch) 1673.    char ch; 1674. { 1675.     char *found = index(mapped_menu_cmds, ch); 1676.    if (found) { 1677. 	int idx = found - mapped_menu_cmds; 1678. 	ch = mapped_menu_op[idx]; 1679.    }  1680.     return ch; 1681. } 1682.  1683.  1684. #if defined(MICRO) || defined(MAC) 1685. # define OPTIONS_HEADING "OPTIONS" 1686. #else 1687. # define OPTIONS_HEADING "NETHACKOPTIONS" 1688. #endif 1689. 1690. STATIC_OVL void 1691. doset_add_menu(win, option, value, indexoffset) 1692.    winid win;			/* window to add to */ 1693.    const char *option;		/* option name */ 1694.    const char *value;		/* current value */ 1695.    int indexoffset;		/* value to add to index in compopt[], or zero 1696. 				  if option cannot be changed */ 1697. { 1698.     char buf[BUFSZ]; 1699.    anything any; 1700.    int i;  1701. 1702.    any.a_void = 0; 1703.    if (indexoffset == 0) { 1704. 	any.a_int = 0; 1705.    } else { 1706. 	for (i=0; compopt[i].name; i++) 1707. 	   if (strcmp(option, compopt[i].name) == 0) break; 1708. 1709. 	if (compopt[i].name) { 1710. 	   any.a_int = i + 1 + indexoffset; 1711. 	} else { 1712. 	   /* We are trying to add an option not found in compopt[]. 1713. 	      This is almost certainly bad, but we'll let it through anyway 1714. 	      (with a zero value, so it can't be selected). */ 1715. 	    any.a_int = 0; 1716. 	} 1717.     }  1718.  1719.     /* "    " replaces "a - " -- assumes menus follow that style */ 1720.    Sprintf(buf, "%s%-14s [%s]", (any.a_int ? "" : "   "), option, value); 1721.    add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); 1722. } 1723.  1724. /* Changing options via menu by Per Liboriussen */ 1725. int 1726. doset 1727. { 1728. 	char ocl[MAXOCLASSES+1], buf[BUFSZ], buf2[BUFSZ]; 1729. 	int i, pass, boolcount, pick_cnt, pick_idx, opt_indx; 1730. 	boolean *bool_p; 1731. 	winid tmpwin; 1732. 	anything any; 1733. 	menu_item *pick_list; 1734. 1735. 	tmpwin = create_nhwindow(NHW_MENU); 1736. 	start_menu(tmpwin); 1737. 1738. 	any.a_void = 0; 1739. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, 1740. 		 "Booleans (selecting will toggle value):", MENU_UNSELECTED); 1741. 	any.a_int = 0; 1742. 	/* list male/female first, since it's formatted uniquely */ 1743. 	Sprintf(buf, "%s%-13s", "   ", flags.female ? "female" : "male"); 1744. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); 1745. 	/* next list any other non-modifiable booleans, then modifiable ones */ 1746. 	for (pass = 0; pass <= 1; pass++) 1747. 	   for (i = 0; boolopt[i].name; i++) 1748. 		if ((bool_p = boolopt[i].addr) != 0 && 1749. 			(boolopt_only_initial(i) ^ pass)) { 1750. 		   if (bool_p == &flags.female) continue;  /* already done */ 1751. #ifdef WIZARD 1752. 		   if (bool_p == &iflags.sanity_check && !wizard) continue; 1753. #endif 1754. 		   any.a_int = (pass == 0) ? 0 : i + 1; 1755. 		   Sprintf(buf, "%s%-13s [%s]", pass == 0 ? "    " : "",  1756. 			    boolopt[i].name, *bool_p ? "true" : "false"); 1757. 		   add_menu(tmpwin, NO_GLYPH, &any, 0, 0,  1758. 			     ATR_NONE, buf, MENU_UNSELECTED); 1759. 		} 1760.  1761. 	/* This is ugly. We have all the option names in the compopt[] array, 1762. 	  but we need to look at each option individually to get the value. */ 1763. 	boolcount = i;  1764. any.a_void = 0; 1765. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); 1766. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, 1767. 		 "Compounds (selecting will prompt for new value):",  1768. 		 MENU_UNSELECTED); 1769. 	/* non-modifiable compounds; deliberately put `name' first */ 1770. 	doset_add_menu(tmpwin, "name", plname, 0); 1771. 	doset_add_menu(tmpwin, "role", (flags.initrole < 0) ? "(none)" : 1772. 			roles[flags.initrole].name.m, 0); 1773. 	doset_add_menu(tmpwin, "race", (flags.initrace < 0) ? "(none)" : 1774. 			races[flags.initrace].noun, 0); 1775. 	doset_add_menu(tmpwin, "gender", (flags.initgend < 0) ? "(none)" : 1776. 			genders[flags.initgend].adj, 0); 1777. 	doset_add_menu(tmpwin, "align", (flags.initalign < 0) ? "(none)" : 1778. 			aligns[flags.initalign].adj, 0); 1779. 	doset_add_menu(tmpwin, "catname", catname[0] ? catname : "(null)", 0); 1780. 	doset_add_menu(tmpwin, "dogname", dogname[0] ? dogname : "(null)", 0); 1781. 	doset_add_menu(tmpwin, "horsename", horsename[0] ? horsename : "(null)", 0); 1782. 	Sprintf(buf, "%u", iflags.msg_history); 1783. 	doset_add_menu(tmpwin, "msghistory", buf, 0); 1784. 	doset_add_menu(tmpwin, "pettype", 1785. 			(preferred_pet == 'c') ? "cat" :  1786. 			(preferred_pet == 'd') ? "dog" : "random", 0); 1787. #ifdef VIDEOSHADES 1788. 	Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]); 1789. 	doset_add_menu(tmpwin, "videoshades", buf, 0); 1790. 	Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d", 1791. 		ttycolors[CLR_RED], ttycolors[CLR_GREEN], ttycolors[CLR_BROWN],  1792. 		ttycolors[CLR_BLUE], ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN],  1793. 		ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN],  1794. 		ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE],  1795. 		ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]); 1796. 	doset_add_menu(tmpwin, "videocolors", buf, 0); 1797. #endif /* VIDEOSHADES */ 1798. 	doset_add_menu(tmpwin, "windowtype", windowprocs.name, 0); 1799. 1800. 	/* modifiable compounds */ 1801. 	doset_add_menu(tmpwin, "disclose", 1802. 		       flags.end_disclose[0] ? flags.end_disclose : "all",  1803. 		       boolcount); 1804. 	doset_add_menu(tmpwin, "fruit", pl_fruit, boolcount); 1805. 	doset_add_menu(tmpwin, "menustyle", menutype[(int)flags.menu_style], 1806. 		       boolcount); 1807. 	oc_to_str(flags.inv_order, ocl); 1808. 	doset_add_menu(tmpwin, "packorder", ocl, boolcount); 1809. #ifdef CHANGE_COLOR 1810. 	doset_add_menu(tmpwin, "palette", get_color_string, boolcount); 1811. #endif 1812. 	oc_to_str(flags.pickup_types, ocl); 1813. 	doset_add_menu(tmpwin, "pickup_burden", burdentype[flags.pickup_burden], 1814. 			boolcount); 1815. 	doset_add_menu(tmpwin, "pickup_types", ocl[0] ? ocl : "all", 1816. 		       boolcount); 1817. 	Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, 1818. 		flags.end_own ? "/own" : ""); 1819. 	doset_add_menu(tmpwin, "scores", buf, boolcount); 1820. 	Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ, FEATURE_NOTICE_VER_MIN, 1821. 			FEATURE_NOTICE_VER_PATCH); 1822. 	doset_add_menu(tmpwin, "suppress_alert", (flags.suppress_alert == 0L) ? 1823. 				"(null)" : buf, boolcount); 1824. 	end_menu(tmpwin, "Set what options?"); 1825. 1826. 	need_redraw = FALSE; 1827. 	if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) { 1828. 	   /*  1829. 	     * Walk down the selection list and either invert the booleans 1830. 	    * or prompt for new values. In most cases, call parseoptions 1831. 	    * to take care of options that require special attention, like 1832. 	    * redraws. 1833. 	    */  1834. 	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { 1835. 		opt_indx = pick_list[pick_idx].item.a_int - 1; 1836. 		if (opt_indx < boolcount) { 1837. 		   /* boolean option */ 1838. 		   Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",  1839. 			    boolopt[opt_indx].name); 1840. 		   parseoptions(buf, FALSE, FALSE); 1841. 		} else { 1842. 		   /* compound option */ 1843. 		   opt_indx -= boolcount; 1844. 1845. 		    /* Special handling of menustyle, pickup_burden, and pickup_types. */ 1846. 		    if (!strcmp("menustyle", compopt[opt_indx].name)) { 1847. 			const char *style_name; 1848. 			menu_item *style_pick = (menu_item *)0; 1849. 1850. 			start_menu(tmpwin); 1851. 			for (i = 0; i < SIZE(menutype); i++) { 1852. 			   style_name = menutype[i]; 1853. 				/* note: separate `style_name' variable used 1854. 				  to avoid an optimizer bug in VAX C V2.3 */ 1855. 			   any.a_int = i + 1; 1856. 			   add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0,  1857. 				     ATR_NONE, style_name, MENU_UNSELECTED); 1858. 			} 1859. 			end_menu(tmpwin, "Select menustyle:"); 1860. 			if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) { 1861. 			   flags.menu_style = style_pick->item.a_int - 1; 1862. 			   free((genericptr_t)style_pick); 1863. 			} 1864. 			} else if (!strcmp("pickup_burden", compopt[opt_indx].name)) { 1865. 				const char *burden_name, *burden_letters = "ubsntl"; 1866. 				menu_item *burden_pick = (menu_item *)0; 1867. 1868. 				start_menu(tmpwin); 1869. 				for (i = 0; i < SIZE(burdentype); i++) { 1870. 				   burden_name = burdentype[i]; 1871. 					any.a_int = i + 1; 1872. 				   add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0,  1873. 				             ATR_NONE, burden_name, MENU_UNSELECTED); 1874. 				} 1875. 				end_menu(tmpwin, "Select encumberence level:"); 1876. 				if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) { 1877. 				   flags.pickup_burden = burden_pick->item.a_int - 1; 1878. 				   free((genericptr_t)burden_pick); 1879. 				} 1880. 		    } else if (!strcmp("pickup_types", compopt[opt_indx].name)) { 1881. 			/* parseoptions will prompt for the list of types */ 1882. 			parseoptions(strcpy(buf, "pickup_types"), FALSE, FALSE); 1883. 		   } else { 1884. 			Sprintf(buf, "Set %s to what?", compopt[opt_indx].name); 1885. 			getlin(buf, buf2); 1886. 			Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2); 1887. 			/* pass the buck */ 1888. 			parseoptions(buf, FALSE, FALSE); 1889. 		   }  1890. 		}  1891. 	    }  1892.  1893. 	    free((genericptr_t)pick_list); 1894. 	   pick_list = (menu_item *)0; 1895. 	} 1896.  1897. 	destroy_nhwindow(tmpwin); 1898. 	if (need_redraw) 1899. 	   (void) doredraw; 1900. 	return 0; 1901. } 1902.  1903. int 1904. dotogglepickup 1905. { 1906. 	char buf[BUFSZ], ocl[MAXOCLASSES+1]; 1907. 1908. 	flags.pickup = !flags.pickup; 1909. 	if (flags.pickup) { 1910. 	   oc_to_str(flags.pickup_types, ocl); 1911. 	   Sprintf(buf, "ON, for %s objects", ocl[0] ? ocl : "all"); 1912. 	} else { 1913. 	   Strcpy(buf, "OFF"); 1914. 	} 1915. 	pline("Autopickup: %s.", buf); 1916. 	return 0; 1917. } 1918.  1919. /* data for option_help */ 1920. static const char *opt_intro[] = { 1921. 	"", 1922. 	"                 NetHack Options Help:", 1923. 	"", 1924. #define CONFIG_SLOT 3	/* fill in next value at run-time */ 1925. 	(char *)0, 1926. #if !defined(MICRO) && !defined(MAC) 1927. 	"or use `NETHACKOPTIONS=\" \"' in your environment", 1928. #endif 1929. 	"( is a list of options separated by commas)", 1930. #ifdef VMS 1931. 	"-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"", 1932. #endif 1933. 	"or press \"O\" while playing and use the menu.", 1934. 	"", 1935.  "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", 1936. 	(char *)0 1937. }; 1938.  1939. static const char *opt_epilog[] = { 1940. 	"", 1941.  "Some of the options can be set only before the game is started; those", 1942. 	"items will not be selectable in the 'O' command's menu.", 1943. 	(char *)0 1944. }; 1945.  1946. void 1947. option_help 1948. { 1949.     char buf[BUFSZ], buf2[BUFSZ]; 1950.    register int i;  1951. winid datawin; 1952. 1953.     datawin = create_nhwindow(NHW_TEXT); 1954. #ifdef AMIGA 1955.    if (FromWBench) 1956. 	Sprintf(buf, "Set options as OPTIONS= in %s or in icon", configfile); 1957.    else 1958. #endif 1959. 	Sprintf(buf, "Set options as OPTIONS= in %s", configfile); 1960.    opt_intro[CONFIG_SLOT] = (const char *) buf; 1961.    for (i = 0; opt_intro[i]; i++) 1962. 	putstr(datawin, 0, opt_intro[i]); 1963. 1964.     /* Boolean options */ 1965.    for (i = 0; boolopt[i].name; i++) { 1966. 	if (boolopt[i].addr) { 1967. #ifdef WIZARD 1968. 	   if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue; 1969. #endif 1970. 	   next_opt(datawin, boolopt[i].name); 1971. 	} 1972.     }  1973.     next_opt(datawin, ""); 1974. 1975.     /* Compound options */ 1976.    putstr(datawin, 0, "Compound options:"); 1977.    for (i = 0; compopt[i].name; i++) { 1978. 	Sprintf(buf2, "`%s'", compopt[i].name); 1979. 	Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr, 1980. 		compopt[i+1].name ? ',' : '.'); 1981. 	putstr(datawin, 0, buf); 1982.    }  1983.  1984.     for (i = 0; opt_epilog[i]; i++) 1985. 	putstr(datawin, 0, opt_epilog[i]); 1986. 1987.     display_nhwindow(datawin, FALSE); 1988.    destroy_nhwindow(datawin); 1989.    return; 1990. } 1991.  1992. /*  1993.  * prints the next boolean option, on the same line if possible, on a new 1994. * line if not. End with next_opt(""). 1995. */  1996. void 1997. next_opt(datawin, str) 1998. winid datawin; 1999. const char *str; 2000. { 2001. 	static char *buf = 0; 2002. 	int i; 2003. char *s; 2004. 2005. 	if (!buf) buf = (char *)alloc(BUFSZ); 2006. 2007. 	if (!*str) { 2008. 		s = eos(buf); 2009. 		if (s > &buf[1] && s[-2] == ',') 2010. 		   Strcpy(s - 2, ".");	/* replace last ", " */ 2011. 		i = COLNO;	/* (greater than COLNO - 2) */ 2012. 	} else { 2013. 		i = strlen(buf) + strlen(str) + 2; 2014. 	} 2015.  2016. 	if (i > COLNO - 2) { /* rule of thumb */ 2017. 		putstr(datawin, 0, buf); 2018. 		buf[0] = 0; 2019. 	} 2020. 	if (*str) { 2021. 		Strcat(buf, str); 2022. 		Strcat(buf, ", "); 2023. 	} else { 2024. 		putstr(datawin, 0, str); 2025. 		free(buf), buf = 0; 2026. 	} 2027. 	return; 2028. } 2029.  2030. /* Returns the fid of the fruit type; if that type already exists, it  2031. * returns the fid of that one; if it does not exist, it adds a new fruit 2032. * type to the chain and returns the new one. 2033. */  2034. int 2035. fruitadd(str) 2036. char *str; 2037. { 2038. 	register int i;  2039. register struct fruit *f; 2040. 	struct fruit *lastf = 0; 2041. 	int highest_fruit_id = 0; 2042. 	char buf[PL_FSIZ]; 2043. 	boolean user_specified = (str == pl_fruit); 2044. 	/* if not user-specified, then it's a fruit name for a fruit on 2045. * a bones level... 2046. */ 2047.  2048. 	/* Note: every fruit has an id (spe for fruit objects) of at least 2049. 	 * 1; 0 is an error. 2050. 	 */ 2051. 	if (user_specified) { 2052. 		/* disallow naming after other foods (since it'd be impossible 2053. 		 * to tell the difference) 2054. 		 */ 2055.  2056. 		boolean found = FALSE, numeric = FALSE; 2057. 2058. 		for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS;  2059. 						i++) { 2060. 			if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) { 2061. 				found = TRUE; 2062. 				break; 2063. 			} 2064. 		}  2065. 		{  2066. 		    char *c; 2067. 2068. 		    c = pl_fruit; 2069. 2070. 		    for(c = pl_fruit; *c >= '0' && *c <= '9'; c++) 2071. 			; 2072. 		    if (isspace(*c) || *c == 0) numeric = TRUE; 2073. 		} 2074. 		if (found || numeric ||  2075. 		    !strncmp(str, "cursed ", 7) ||  2076. 		    !strncmp(str, "uncursed ", 9) ||  2077. 		    !strncmp(str, "blessed ", 8) ||  2078. 		    !strncmp(str, "partly eaten ", 13) ||  2079. 		    (!strncmp(str, "tin of ", 7) && 2080. 			(!strcmp(str+7, "spinach") || 2081. 			 name_to_mon(str+7) >= LOW_PM)) ||  2082. 		    !strcmp(str, "empty tin") ||  2083. 		    ((!strncmp(eos(str)-7," corpse",7) ||  2084. 			    !strncmp(eos(str)-4, " egg",4)) && 2085. 			name_to_mon(str) >= LOW_PM)) 2086. 			{ 2087. 				Strcpy(buf, pl_fruit); 2088. 				Strcpy(pl_fruit, "candied "); 2089. 				nmcpy(pl_fruit+8, buf, PL_FSIZ-8); 2090. 		} 2091. 	}  2092. 	for(f=ffruit; f; f = f->nextf) { 2093. 		lastf = f; 2094. if(f->fid > highest_fruit_id) highest_fruit_id = f->fid; 2095. 		if(!strncmp(str, f->fname, PL_FSIZ)) 2096. 			goto nonew; 2097. 	} 2098. 	/* if adding another fruit would overflow spe, use a random 2099. 	  fruit instead... we've got a lot to choose from. */ 2100. 	if (highest_fruit_id >= 127) return rnd(127); 2101. 	highest_fruit_id++; 2102. 	f = newfruit; 2103. 	if (ffruit) lastf->nextf = f; 2104. else ffruit = f; 2105. Strcpy(f->fname, str); 2106. 	f->fid = highest_fruit_id; 2107. 	f->nextf = 0; 2108. nonew: 2109. 	if (user_specified) current_fruit = highest_fruit_id; 2110. 	return f->fid; 2111. } 2112.  2113. /*  2114.  * This is a somewhat generic menu for taking a list of NetHack style 2115. * class choices and presenting them via a description 2116. * rather than the traditional NetHack characters. 2117. * (Benefits users whose first exposure to NetHack is via tiles). 2118. *  2119.  * prompt 2120. *	     The title at the top of the menu. 2121. *  2122.  * category: 0 = monster class 2123. *           1 = object  class 2124. *  2125.  * way 2126. *	     FALSE = PICK_ONE, TRUE = PICK_ANY 2127. *  2128.  * class_list 2129. *	     a null terminated string containing the list of choices. 2130. *  2131.  * class_selection 2132. *	     a null terminated string containing the selected characters. 2133. *  2134.  * Returns number selected. 2135. */  2136. int 2137. choose_classes_menu(prompt, category, way, class_list, class_select) 2138. const char *prompt; 2139. int category; 2140. boolean way; 2141. char *class_list; 2142. char *class_select; 2143. { 2144.     menu_item *pick_list = (menu_item *)0; 2145.    winid win; 2146.    anything any; 2147.    char buf[BUFSZ]; 2148.    int i, n;  2149. int ret; 2150.    int next_accelerator, accelerator; 2151. 2152.     if (class_list == (char *)0 || class_select == (char *)0) return 0; 2153.    accelerator = 0; 2154.    next_accelerator = 'a'; 2155.    any.a_void = 0; 2156.    win = create_nhwindow(NHW_MENU); 2157.    start_menu(win); 2158.    while (*class_list) { 2159. 	const char *text; 2160. 	boolean selected; 2161. 2162. 	text = (char *)0; 2163. 	selected = FALSE; 2164. 	switch (category) { 2165. 		case 0: 2166. 			text = monexplain[def_char_to_monclass(*class_list)]; 2167. 			accelerator = *class_list; 2168. 			Sprintf(buf, "%s", text); 2169. 			break; 2170. 		case 1: 2171. 			text = objexplain[def_char_to_objclass(*class_list)]; 2172. 			accelerator = next_accelerator; 2173. 			Sprintf(buf, "%c %s", *class_list, text); 2174. 			break; 2175. 		default: 2176. 			impossible("choose_classes_menu: invalid category %d", 2177. 					category); 2178. 	} 2179. 	if (way && *class_select) {	/* Selections there already */ 2180. 		if (index(class_select, *class_list)) { 2181. 			selected = TRUE; 2182. 		} 2183. 	}  2184. 	any.a_int = *class_list; 2185. 	add_menu(win, NO_GLYPH, &any, accelerator, 2186. 		  category ? *class_list : 0,  2187. 		  ATR_NONE, buf, selected); 2188. 	++class_list; 2189. 	if (category > 0) { 2190. 		++next_accelerator; 2191. 		if (next_accelerator == ('z' + 1)) next_accelerator = 'A'; 2192. 		if (next_accelerator == ('Z' + 1)) break; 2193. 	} 2194.     }  2195.     end_menu(win, prompt); 2196.    n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list); 2197.    destroy_nhwindow(win); 2198.    if (n > 0) { 2199. 	for (i = 0; i < n; ++i) 2200. 	   *class_select++ = (char)pick_list[i].item.a_int; 2201. 	free((genericptr_t)pick_list); 2202. 	ret = n; 2203. } else if (n == -1) { 2204. 	class_select = eos(class_select); 2205. 	ret = -1; 2206.    } else 2207. 	ret = 0; 2208.    *class_select = '\0'; 2209.    return ret; 2210. } 2211.  2212. #endif	/* OPTION_LISTS_ONLY */ 2213. 2214. /*options.c*/