Source:NetHack 3.1.0/options.c

Below is the full text to options.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.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.1	92/11/14	*/ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    #include "termcap.h"  7.    #include   8. 9.   /*  10.    *  NOTE:  If you add (or delete) an option, please update the short 11.   *  options help (option_help), the long options help (dat/opthelp), 12.   *  and the current options setting display function (doset). 13.   */  14.    15.   #if defined(TOS) && defined(TEXTCOLOR) 16.  extern boolean colors_changed;	/* in tos.c */ 17.  #endif 18.   19.   extern const char *roles[];	/* from u_init.c */ 20.  extern char inv_order[];	/* from invent.c */ 21.   22.   static boolean initial, from_file; 23.  static boolean NEARDATA set_order; 24.   25.   static void FDECL(nmcpy, (char *, const char *, int)); 26.  static void FDECL(escapes, (const char *, char *)); 27.  static void FDECL(rejectoption, (const char *)); 28.  static void FDECL(badoption, (const char *)); 29.  static char *FDECL(string_for_env_opt, (const char *, char *)); 30.  static int FDECL(change_inv_order, (char *, int)); 31.  static void FDECL(oc_to_str, (char *, char *)); 32.   33.   static struct Bool_Opt 34.  {  35.   	const char *name; 36.  	boolean	*addr, initvalue; 37.  } boolopt[] = { 38.  #if defined(MICRO) && !defined(AMIGA) 39.  	{"BIOS", &flags.BIOS, FALSE}, 40.  #endif 41.  #ifdef INSURANCE 42.  	{"checkpoint", &flags.ins_chkpt, TRUE}, 43.  #endif 44.  #ifdef TEXTCOLOR 45.  # ifdef MICRO 46.  	{"color", &flags.use_color, TRUE}, 47.  # else	/* systems that support multiple terminals, many monochrome */ 48.  	{"color", &flags.use_color, FALSE}, 49.  # endif 50.  #endif 51.  	{"confirm",&flags.confirm, TRUE}, 52.  #ifdef TERMLIB 53.  	{"DECgraphics", &flags.DECgraphics, FALSE}, 54.  #endif 55.  	{"disclose", &flags.end_disclose, TRUE}, 56.  	{"female", &flags.female, FALSE}, 57.  	{"fixinv", &flags.invlet_constant, TRUE}, 58.  #ifdef AMIFLUSH 59.  	{"flush", &flags.amiflush, FALSE}, 60.  #endif 61.  	{"help", &flags.help, TRUE}, 62.  #ifdef TEXTCOLOR 63.  	{"hilite_pet", &flags.hilite_pet, FALSE}, 64.  #endif 65.  #ifdef ASCIIGRAPH 66.  	{"IBMgraphics", &flags.IBMgraphics, FALSE}, 67.  #endif 68.  	{"ignintr", &flags.ignintr, FALSE}, 69.  #ifdef MAC_GRAPHICS_ENV 70.  	{"large_font", &flags.large_font, FALSE}, 71.  #endif 72.  	{"legacy",&flags.legacy, TRUE}, 73.  	{"lit_corridor", &flags.lit_corridor, FALSE}, 74.  #ifdef MAC_GRAPHICS_ENV 75.  	{"MACgraphics", &flags.MACgraphics, TRUE}, 76.  #endif 77.  #ifdef NEWS 78.  	{"news", &flags.news, TRUE}, 79.  #endif 80.  	{"null", &flags.null, TRUE}, 81.  	{"number_pad", &flags.num_pad, FALSE}, 82.  	{"pickup", &flags.pickup, TRUE}, 83.  #ifdef MAC 84.  	{"popup_dialog", &flags.popup_dialog, FALSE}, 85.  #endif 86.  #if defined(MICRO) && !defined(AMIGA) 87.  	{"rawio", &flags.rawio, FALSE}, 88.  #endif 89.  	{"rest_on_space", &flags.rest_on_space, FALSE}, 90.  	{"safepet", &flags.safe_dog, TRUE}, 91.  #ifdef EXP_ON_BOTL 92.  	{"showexp", &flags.showexp, FALSE}, 93.  #endif 94.  #ifdef SCORE_ON_BOTL 95.  	{"showscore", &flags.showscore, FALSE}, 96.  #endif 97.  	{"silent", &flags.silent, TRUE}, 98.  	{"sortpack", &flags.sortpack, TRUE}, 99.  	{"sound", &flags.soundok, TRUE}, 100. 	{"standout", &flags.standout, FALSE}, 101. 	{"time", &flags.time, FALSE}, 102. 	{"tombstone",&flags.tombstone, TRUE}, 103. 	{"verbose", &flags.verbose, TRUE}, 104. 	{NULL, (boolean *)0, FALSE} 105. };  106.   107.  static boolean need_redraw; /* for doset */ 108.  109.  void 110. initoptions 111. {  112.  	register char *opts; 113. 	int i;  114. 115. 	for (i = 0; boolopt[i].name; i++) { 116. 		if (boolopt[i].addr) 117. 			*(boolopt[i].addr) = boolopt[i].initvalue; 118. 	}  119.  	flags.end_own = FALSE; 120. 	flags.end_top = 3; 121. 	flags.end_around = 2; 122. 	flags.msg_history = 20; 123.  124.  	/* Set the default monster and object class symbols. Don't use */ 125. 	/* memcpy --- sizeof char != sizeof uchar on some machines. */ 126.  	for (i = 0; i < MAXOCLASSES; i++) 127. 	    	oc_syms[i] = (uchar) def_oc_syms[i]; 128. 	for (i = 0; i < MAXMCLASSES; i++) 129. 	    	monsyms[i] = (uchar) def_monsyms[i]; 130.  131.  	switch_graphics(ASCII_GRAPHICS);	/* set default characters */ 132. #ifdef UNIX 133. 	/*  134.  	 * Set defaults for some options depending on what we can 135. 	 * detect about the environment's capabilities. 136. 	 * This has to be done after the global initialization above 137. 	 * and before reading user-specific initialization via 138. 	 * config file/environment variable below. 139. 	 */  140.  	/* this detects the IBM-compatible console on most 386 boxes */ 141. 	if (!strncmp(getenv("TERM"), "AT", 2)) { 142. 		switch_graphics(IBM_GRAPHICS); 143. # ifdef TEXTCOLOR 144. 		flags.use_color = TRUE; 145. # endif 146. 	}  147.  #endif /* UNIX */ 148. #if defined(UNIX) || defined(VMS) 149. 	/* detect whether a "vt" terminal can handle alternate charsets */ 150. 	if (!strncmpi(getenv("TERM"), "vt", 2) && (AS && AE) &&  151.  	    !strcmp(AS, "\016") && !strcmp(AE, "\017")) { 152. 		switch_graphics(DEC_GRAPHICS); 153. 	}  154.  #endif /* UNIX || VMS */ 155.  156.  #ifdef MAC_GRAPHICS_ENV 157. 	switch_graphics(MAC_GRAPHICS); 158. #endif /* MAC_GRAPHICS_ENV */ 159.  160.  #ifdef TUTTI_FRUTTI 161. 	/* since this is done before init_objects, do partial init here */ 162. 	objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; 163. 	nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); 164. #endif 165. 	opts = getenv("NETHACKOPTIONS"); 166. 	if (!opts) opts = getenv("HACKOPTIONS"); 167. 	if (opts) 168. 		if (*opts == '/' || *opts == '\\' || *opts == '@') { 169. 			if (*opts == '@') opts++;	/* @filename */ 170. 			/* looks like a filename */ 171. 			read_config_file(opts); 172. 		} else { 173. 			read_config_file(NULL); 174. 			parseoptions(opts, TRUE, FALSE); 175. 		}  176.  	else 177. 		read_config_file(NULL); 178. #ifdef AMIGA 179. 	ami_wbench_init;	/* must be here or can't set fruit */ 180. #endif 181. #ifdef TUTTI_FRUTTI 182. 	(void)fruitadd(pl_fruit); 183. 	/* Remove "slime mold" from list of object names; this will	*/ 184. 	/* prevent it from being wished unless it's actually present	*/ 185. 	/* as a named (or default) fruit. Wishing for "fruit" will	*/ 186. 	/* result in the player's preferred fruit [better than "\033"]. */ 187.  	obj_descr[SLIME_MOLD].oc_name = "fruit"; 188. #endif 189. 	if(flags.female)  {	/* should have been set in NETHACKOPTIONS */ 190. 		roles[2] = "Cavewoman"; 191. 		roles[6] = "Priestess"; 192. 	}  193.  }  194.   195.  static void 196. nmcpy(dest, src, maxlen) 197. 	char	*dest; 198. 	const char *src; 199. 	int	maxlen; 200. {  201.  	int	count; 202.  203.  	for(count = 1; count < maxlen; count++) { 204. 		if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/ 205. 		*dest++ = *src++; 206. 	}  207.  	*dest = 0; 208. }  209.   210.  /*  211.   * escapes: escape expansion for showsyms. C-style escapes understood include 212.  * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix 213.  * for control characters is also understood, and \[mM] followed by any of the 214.  * previous forms or by a character has the effect of 'meta'-ing the value (so  215.   * that the alternate character set will be enabled). 216.  */  217.  static void 218. escapes(cp, tp) 219. const char	*cp; 220. char *tp; 221. {  222.      while (*cp) 223.     {  224.  	int	cval = 0, meta = 0; 225.  226.  	if (*cp == '\\' && index("mM", cp[1])) { 227. 		meta = 1; 228. 		cp += 2; 229. 	}  230.  	if (*cp == '\\' && index("0123456789xXoO", cp[1])) 231. 	{  232.  	    const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF"; 233. 	    int dcount = 0; 234.  235.  	    cp++; 236. 	    if (*cp == 'x' || *cp == 'X') 237. 		for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++) 238. 		    cval = (cval * 16) + (dp - hex) / 2; 239. 	    else if (*cp == 'o' || *cp == 'O') 240. 		for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++) 241. 		    cval = (cval * 8) + (*cp - '0'); 242. 	    else 243. 		for ((index("0123456789",*cp)) && (dcount++ < 3); cp++) 244. 		    cval = (cval * 10) + (*cp - '0'); 245. 	}  246.  	else if (*cp == '\\')		/* C-style character escapes */ 247. 	{  248.  	    switch (*++cp) 249. 	    {  250.  	    case '\\': cval = '\\'; break; 251. 	    case 'n': cval = '\n'; break; 252. 	    case 't': cval = '\t'; break; 253. 	    case 'b': cval = '\b'; break; 254. 	    case 'r': cval = '\r'; break; 255. 	    default: cval = *cp; 256. 	    }  257.  	    cp++; 258. 	}  259.  	else if (*cp == '^')		/* expand control-character syntax */ 260. 	{  261.  	    cval = (*++cp & 0x1f); 262. 	    cp++; 263. 	}  264.  	else 265. 	    cval = *cp++; 266. 	if (meta) 267. 	    cval |= 0x80; 268. 	*tp++ = cval; 269.     }  270.      *tp = '\0'; 271. }  272.   273.  static void 274. rejectoption(optname) 275. const char *optname; 276. {  277.  #ifdef MICRO 278. # ifdef AMIGA 279. 	if(FromWBench){ 280. 		pline("\"%s\" settable only from %s or in icon.",  281.  			optname, configfile); 282. 	} else 283. # endif 284. 		pline("\"%s\" settable only from %s.", optname, configfile); 285. #else 286. 	pline("%s can be set only from NETHACKOPTIONS or %s.", optname,  287.  			configfile); 288. #endif 289. }  290.   291.  static void 292. badoption(opts) 293. const char *opts; 294. {  295.  	if(!initial) { 296. 	    if(!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1)) 297. 		option_help; 298. 	    else 299. 		pline("Unknown option: %s.  Enter \"?g\" for help.", opts); 300. 	    return; 301. 	}  302.  # ifdef AMIGA 303. 	if(ami_wbench_badopt(opts)) { 304. # endif 305. 	if(from_file) 306. 	    raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts); 307. 	else 308. 	    raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts); 309. # ifdef AMIGA 310. 	}  311.  # endif 312. 	wait_synch; 313. }  314.   315.  static char * 316. string_for_env_opt(optname, opts) 317. const char *optname; 318. char *opts; 319. {  320.  	register char *colon; 321.  322.  	if(!initial) { 323. 		rejectoption(optname); 324. 		return NULL; 325. 	}  326.  	colon = index(opts,':'); 327. 	if(!colon) { 328. 		badoption(opts); 329. 		return NULL; 330. 	}  331.  	return ++colon; 332. }  333.   334.  /*  335.   * Change the inventory order, using the given string as the new order. 336.  * Missing characters in the new order are filled in at the end from 337.  * the current inv_order. 338.  *  339.   * This routine always returns 1 unless the parameter 'fail' is true 340.  * and there is a duplicate or bad char in the string. 341.  */  342.  static int 343. change_inv_order(op, fail) 344.     char *op; 345.     int  fail;	/* If TRUE, return 0 if any duplicates or bad chars. */ 346.  {  347.      int oc_sym, num; 348.     char *sp, *tmp, buf[BUFSZ]; 349.  350.      for (sp = op; *sp; sp++) { 351. 	oc_sym = def_char_to_objclass(*sp); 352.  353.  	/* Remove bad or duplicate entries. */ 354.  	if (oc_sym == MAXOCLASSES ||  355.  		(!index(inv_order, oc_sym)) || (index(sp+1, *sp))) { 356.  357.  	    if (fail) return 0; 358. 	    for(tmp = sp; *tmp; tmp++) 359. 		tmp[0] = tmp[1]; 360. 	    sp--; 361. 	} else 362. 	    *sp = (char) oc_sym; 363.     }  364.      Strcpy(buf, op); 365.     for (sp = inv_order, num = strlen(buf); *sp; sp++) 366. 	if (!index(buf, *sp)) 367. 	    buf[num++] = *sp; 368.  369.      buf[num] = 0; 370.     Strcpy(inv_order, buf); 371.     return 1; 372. }  373.   374.  void 375. parseoptions(opts, tinitial, tfrom_file) 376. register char *opts; 377. boolean tinitial, tfrom_file; 378. {  379.  	register char *op; 380. 	unsigned num; 381. 	boolean negated; 382. 	int i;  383. 384. 	initial = tinitial; 385. 	from_file = tfrom_file; 386. 	if ((op = index(opts, ',')) != 0) { 387. 		*op++ = 0; 388. 		parseoptions(op, initial, from_file); 389. 	}  390.   391.  	/* strip leading and trailing white space */ 392. 	while (isspace(*opts)) opts++; 393. 	op = eos(opts); 394. 	while (--op >= opts && isspace(*op)) *op = '\0'; 395.  396.  	if(!*opts) return; 397. 	negated = FALSE; 398. 	while((*opts == '!') || !strncmpi(opts, "no", 2)) { 399. 		if(*opts == '!') opts++; else opts += 2; 400. 		negated = !negated; 401. 	}  402.  	  403.  #if defined(MICRO) && !defined(AMIGA) 404. 	/* included for compatibility with old NetHack.cnf files */ 405. 	if (!strncmp(opts, "IBM_", 4)) { 406. 		flags.BIOS = !negated; 407. 		return; 408. 	}  409.   410.  	/* put here cause it has to come from the config file */ 411. 	if (!strncmpi(opts, "raw", 3)) { 412. 		if (initial) 413. 			flags.rawio = !negated; 414. 		else 415. 			rejectoption("rawio"); 416. 		return; 417. 	}  418.  #endif /* MICRO */ 419.  420.  #if defined(TOS) && defined(TEXTCOLOR) 421. 	if (!strncmpi(opts, "col", 3)) { 422. 		flags.use_color = !negated; 423. 		if (flags.BIOS && !initial) { 424. 			if (colors_changed) 425. 				restore_colors; 426. 			else 427. 				set_colors; 428. 		}  429.  	}  430.  #endif 431. 	/* other special-case boolean options */ 432. #ifdef TERMLIB 433. 	if (!strncmpi(opts, "DEC", 3)) { 434. #ifdef REINCARNATION 435. 		if (!initial && Is_rogue_level(&u.uz)) 436. 			assign_rogue_graphics(FALSE); 437. #endif 438. 		flags.DECgraphics = !negated; 439. 		need_redraw = TRUE; 440. 		switch_graphics(flags.DECgraphics ?  441.  				DEC_GRAPHICS : ASCII_GRAPHICS); 442. #ifdef REINCARNATION 443. 		if (!initial && Is_rogue_level(&u.uz)) 444. 			assign_rogue_graphics(TRUE); 445. #endif 446. 		return; 447. 	}  448.  #endif /* TERMLIB */ 449. #ifdef ASCIIGRAPH 450. 	if (!strncmpi(opts, "IBMg", 4)) { 451. #ifdef REINCARNATION 452. 		if (!initial && Is_rogue_level(&u.uz)) 453. 			assign_rogue_graphics(FALSE); 454. #endif 455. 		flags.IBMgraphics = !negated; 456. 		need_redraw = TRUE; 457. 		switch_graphics(flags.IBMgraphics ?  458.  				IBM_GRAPHICS : ASCII_GRAPHICS); 459. #ifdef REINCARNATION 460. 		if (!initial && Is_rogue_level(&u.uz)) 461. 			assign_rogue_graphics(TRUE); 462. #endif 463. 		return; 464. 	}  465.  #endif /* ASCIIGRAPH */ 466. #ifdef MAC_GRAPHICS_ENV 467. 	if (!strncmpi(opts, "MACg", 4)) { 468. #ifdef REINCARNATION 469. 		if (!initial && Is_rogue_level(&u.uz)) 470. 			assign_rogue_graphics(FALSE); 471. #endif 472. 		flags.MACgraphics = !negated; 473. 		need_redraw = TRUE; 474. 		switch_graphics(flags.MACgraphics ?  475.  				MAC_GRAPHICS : ASCII_GRAPHICS); 476. #ifdef REINCARNATION 477. 		if (!initial && Is_rogue_level(&u.uz)) 478. 			assign_rogue_graphics(TRUE); 479. #endif 480. 		return; 481. 	}  482.  #endif /* MAC_GRAPHICS_ENV */ 483.  484.  	/* common boolean options */ 485.  486.  	if (!strncmpi(opts, "fem", 3)) { 487. 		if(!initial && flags.female == negated) 488. 			pline("That is not anatomically possible."); 489. 		else 490. 			flags.female = !negated; 491. 		return; 492. 	}  493.   494.  	if (!strncmpi(opts, "fix", 3)) { 495. 		flags.invlet_constant = !negated; 496. 		if (!initial && flags.invlet_constant) reassign; 497. 		return; 498. 	}  499.   500.  	if (!strncmpi(opts, "male", 4)) { 501. 		if(!initial && flags.female != negated) 502. 			pline("That is not anatomically possible."); 503. 		else 504. 			flags.female = negated; 505. 		return; 506. 	}  507.   508.  	if (!strncmpi(opts, "num", 3)) { 509. 		flags.num_pad = !negated; 510. 		if (!initial) number_pad(flags.num_pad ? 1 : 0); 511. 		return; 512. 	}  513.  #ifdef EXP_ON_BOTL 514. 	if (!strncmpi(opts, "showexp", 7)) { 515. 		flags.showexp = !negated; 516. 		flags.botl = 1; 517. 		return; 518. 	}  519.  #endif 520. #ifdef SCORE_ON_BOTL 521. 	if (!strncmpi(opts, "showscore", 9)) { 522. 		flags.showscore = !negated; 523. 		flags.botl = 1; 524. 		return; 525. 	}  526.  #endif 527. 	if (!strncmpi(opts, "time", 4)) { 528. 		flags.time = !negated; 529. 		flags.botl = 1; 530. 		return; 531. 	}  532.   533.  	if (!strncmpi(opts, "legacy", 6)) { 534. 	        if(!initial) rejectoption("legacy"); 535. 		else flags.legacy = !negated; 536. 		return; 537. 	}  538.   539.  	/* compound options */ 540.  541.  	if (!strncmpi(opts, "pet", 3)) { 542. 		if ((op = string_for_env_opt("pettype", opts)) != 0) 543. 		    switch (*op) { 544. 			case 'd':	/* dog */ 545. 			case 'D': 546. 			    preferred_pet = 'd'; 547. 			    break; 548. 			case 'c':	/* cat */ 549. 			case 'C': 550. 			case 'f':	/* feline */ 551. 			case 'F': 552. 			    preferred_pet = 'c'; 553. 			    break; 554. 			default: 555. 			    pline("Unrecognized pettype '%s'", op); 556. 			    break; 557. 		    }  558.  		return; 559. 	}  560.   561.  	if (!strncmpi(opts, "cat", 3)) { 562. 		if ((op = string_for_env_opt("catname", opts)) != 0) 563. 			nmcpy(catname, op, 62); 564. 		return; 565. 	}  566.   567.  	if (!strncmpi(opts, "dog", 3)) { 568. 		if ((op = string_for_env_opt("dogname", opts)) != 0) 569. 			nmcpy(dogname, op, 62); 570. 		return; 571. 	}  572.   573.  	if (!strncmpi(opts, "msg", 3)) { 574. 		if ((op = string_for_env_opt("msghistory", opts)) != 0) { 575. 			flags.msg_history = atoi(op); 576. 		}  577.  		return; 578. 	}  579.  #ifdef TUTTI_FRUTTI 580. 	if (!strncmpi(opts, "fr", 2)) { 581. 		op = index(opts, ':'); 582. 		if (!op) { 583. 			badoption(opts); 584. 			return; 585. 		}  586.  		op++; 587. 		if (!initial) { 588. 		    struct fruit *f; 589. 		    int numfruits = 0; 590.  591.  		    for(f=ffruit; f; f=f->nextf) { 592. 			if (!strcmp(op, f->fname)) goto goodfruit; 593. 			numfruits++; 594. 		    }  595.  		    if (numfruits >= 100) { 596. 			pline("Doing that so many times isn't very fruitful."); 597. 			return; 598. 		    }  599.  		}  600.  goodfruit: 601. 		nmcpy(pl_fruit, op, PL_FSIZ); 602. 		if (!*pl_fruit) 603. 		    nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); 604. 		if (!initial) 605. 		    (void)fruitadd(pl_fruit); 606. 		/* If initial, then initoptions is allowed to do it instead 607. 		 * of here (initoptions always has to do it even if there's  608.  		 * no fruit option at all.  Also, we don't want people  609.  		 * setting multiple fruits in their options.) 610. 		 */  611.  		return; 612. 	}  613.  #endif 614. 	/* graphics:string */ 615. 	if (!strncmpi(opts, "gr", 2)) { 616. 		uchar translate[MAXPCHARS+1]; 617. 		int lth; 618.  619.  		if (!(opts = string_for_env_opt("graphics", opts))) 620. 			return; 621. 		escapes(opts, opts); 622.  623.  		lth = strlen(opts); 624. 		if (lth > MAXPCHARS) lth = MAXPCHARS; 625. 		/* match the form obtained from PC configuration files */ 626. 		for (i = 0; i < lth; i++) 627. 			translate[i] = (uchar) opts[i]; 628. 		assign_graphics(translate, lth); 629. 		return; 630. 	}  631.   632.  	/* objects:string */ 633. 	if (!strncmpi(opts, "objects", 7)) { 634. 		int k, length; 635.  636.  		if (!(opts = string_for_env_opt("objects", opts))) 637. 			return; 638. 		escapes(opts, opts); 639.  640.  		/*  641.  		 * Override the default object class symbols. The first 642. 		 * object in the object class is the "random object". I 643. * don't want to use 0 as an object class, so the "random 644.  		 * object" is basically a place holder. 645. 		 *  646.  		 * The object class symbols have already been initialized in  647. * initoptions. 648. 		 */  649.  		length = strlen(opts); 650. 		if (length >= MAXOCLASSES) 651. 		    length = MAXOCLASSES-1;	/* don't count RANDOM_OBJECT */ 652.  653.  		for (k = 0; k < length; k++) 654. 		    oc_syms[k+1] = (uchar) opts[k]; 655. 		return; 656. 	}  657.   658.  	/* monsters:string */ 659. 	if (!strncmpi(opts, "monsters", 8)) { 660. 		int k, length; 661.  662.  		if (!(opts = string_for_env_opt("monsters", opts))) 663. 			return; 664. 		escapes(opts, opts); 665.  666.  		/* Override default mon class symbols set in initoptions. */ 667.  		length = strlen(opts); 668. 		if (length >= MAXMCLASSES) 669. 		    length = MAXMCLASSES-1;	/* mon class 0 unused */ 670.  671.  		for (k = 0; k < length; k++) 672. 		    monsyms[k+1] = (uchar) opts[k]; 673. 		return; 674. 	}  675.   676.  	/* name:string */ 677. 	if (!strncmpi(opts, "name", 4)) { 678. 		if ((op = string_for_env_opt("name", opts)) != 0) 679. 			nmcpy(plname, op, (int)sizeof(plname)-1); 680. 		return; 681. 	}  682.   683.  	/* the order to list the pack */ 684. 	if (!strncmpi(opts, "pack", 4)) { 685. 		op = index(opts,':'); 686. 		if(!op) { 687. 			badoption(opts); 688. 			return; 689. 		}  690.  		op++;			/* skip : */ 691.  692.  		if (!change_inv_order(op, 1)) 693. 		    	set_order = TRUE; 694. 		else 695. 		    	badoption(opts); 696. 		return; 697. 	}  698.   699.  	/* scores:5t[op] 5a[round] o[wn] */ 700. 	if (!strncmpi(opts, "scores", 6)) { 701. 		op = index(opts,':'); 702. 		if(!op) { 703. 			badoption(opts); 704. 			return; 705. 		}  706.  		op++; 707. 		while(*op) { 708. 			num = 1; 709. 			if(digit(*op)) { 710. 				num = atoi(op); 711. 				while(digit(*op)) op++; 712. 			} else if(*op == '!') { 713. 				negated = !negated; 714. 				op++; 715. 			}  716.  			while(*op == ' ') op++; 717.  718.  			switch(*op) { 719. 				case 't': 720. 				case 'T': 721. 					flags.end_top = num; 722. 					break; 723. 				case 'a': 724. 				case 'A': 725. 					flags.end_around = num; 726. 					break; 727. 				case 'o': 728. 				case 'O': 729. 					flags.end_own = !negated; 730. 					break; 731. 				default: 732. 					badoption(opts); 733. 					return; 734. 			}  735.  			while(letter(*++op) || *op == ' ') ; 736. 			if(*op == '/') op++; 737. 		}  738.  		return; 739. 	}  740.  	if (!strncmpi(opts, "win", 3)) { 741. 	    if ((op = string_for_env_opt("windowtype", opts)) != 0) { 742. 		char buf[16]; 743. 		nmcpy(buf, op, 15); 744. 		choose_windows(buf); 745. 	    }  746.  	    return; 747. 	}  748.   749.  	/* OK, if we still haven't recognized the option, check the boolean 750. 	 * options list 751. 	 */  752.  	for (i = 0; boolopt[i].name; i++) { 753. 		if (boolopt[i].addr && !strncmpi(boolopt[i].name, opts, 3)) { 754. 			*(boolopt[i].addr) = !negated; 755. #ifdef TEXTCOLOR 756. 			if((boolopt[i].addr) == &flags.use_color) 757. 			    need_redraw = TRUE; 758.  759.  			if((boolopt[i].addr) == &flags.hilite_pet) 760. 			    need_redraw = TRUE; 761. #endif 762. 			if (!initial && boolopt[i].addr==&flags.lit_corridor) { 763. 			    /*  764.  			     * All corridor squares seen via night vision or  765. * candles & lamps change. Update them by calling 766. 			     * newsym on them. Don't do this if we are 767. 			     * initializing the options --- the vision system 768. 			     * isn't set up yet. 769. 			     */  770.  			    vision_recalc(2);		/* shut down vision */ 771. 			    vision_full_recalc = 1;	/* delayed recalc */ 772. 			}  773.  			return; 774. 		}  775.  	}  776.   777.  	/* out of valid options */ 778. 	badoption(opts); 779. }  780.   781.  /*  782.   * Convert the given string of object classes to a string of default object 783.  * symbols. 784.  */  785.  static void 786. oc_to_str(src,dest) 787.     char *src, *dest; 788. {  789.      int i;  790. 791.     while ((i = (int) *src++) != 0) { 792. 	if (i < 0 || i >= MAXOCLASSES) 793. 	    impossible("oc_to_str:  illegal object class %d", i); 794. 	else 795. 	    *dest++ = def_oc_syms[i]; 796.     }  797.      *dest = '\0'; 798. }  799.   800.  #ifdef MICRO 801. # define OPTIONS_HEADING "OPTIONS" 802. #else 803. # define OPTIONS_HEADING "NETHACKOPTIONS" 804. #endif 805.  806.  int 807. doset 808. {  809.  	char buf[BUFSZ], pack_order[MAXOCLASSES+1], on_off; 810. 	const char *opt_name; 811. 	int i;  812. winid tmpwin; 813.  814.  	switch (yn_function("Show the current settings [c], or set options [s]?", 815. 			    "csq", 'q')) { 816. 	default: 817. 	case 'q': 818. 	    clear_nhwindow(WIN_MESSAGE); 819. 	    return 0; 820. 	case 'c': 821. 	    tmpwin = create_nhwindow(NHW_MENU); 822. 	    putstr(tmpwin, 0, OPTIONS_HEADING); 823. 	    putstr(tmpwin, 0, ""); 824. 	    /* print the booleans */ 825. 	    for (i = 0; boolopt[i].name; i++) { 826. 		if (!boolopt[i].addr) continue; 827. 		opt_name = boolopt[i].name; 828. 		if (*(boolopt[i].addr)) { 829. 		    on_off = ' ';               /* on */ 830. 		} else { 831. 		    if (!strcmp(opt_name, "female")) 832. 			opt_name = "male",  on_off = ' '; 833. 		    else 834. 			on_off = '!';           /* off */ 835. 		}  836.  		Sprintf(buf, "%c%s", on_off, opt_name); 837. 		putstr(tmpwin, 0, buf); 838. 	    }  839.  	    /* print the compounds */ 840. 	    Sprintf(buf, " catname: %s",  841.  			(catname[0] != 0) ? catname : "(null)"); 842. 	    putstr(tmpwin, 0, buf); 843. 	    Sprintf(buf, " dogname: %s",  844.  			(dogname[0] != 0) ? dogname : "(null)"); 845. 	    putstr(tmpwin, 0, buf); 846. #ifdef TUTTI_FRUTTI 847. 	    Sprintf(buf, " fruit: %s", pl_fruit); 848. 	    putstr(tmpwin, 0, buf); 849. #endif 850. 	    Sprintf(buf, " msghistory: %u", flags.msg_history); 851. 	    putstr(tmpwin, 0, buf); 852. 	    Sprintf(buf, " name: %s", plname); 853. 	    putstr(tmpwin, 0, buf); 854. 	    oc_to_str(inv_order, pack_order); 855. 	    Sprintf(buf, " packorder: %s", pack_order); 856. 	    putstr(tmpwin, 0, buf); 857. 	    Sprintf(buf, " pettype: %s", preferred_pet == 'c' ? "cat" :  858.  				    preferred_pet == 'd' ? "dog" : "random"); 859. 	    putstr(tmpwin, 0, buf); 860. 	    Sprintf(buf, " scores: %utop/%uaround%s",  861.  		        flags.end_top, flags.end_around,  862.  		        (flags.end_own ? "/own" : "")); 863. 	    putstr(tmpwin, 0, buf); 864. 	    Sprintf(buf, " windowtype: %s", windowprocs.name); 865. 	    putstr(tmpwin, 0, buf); 866. 	    display_nhwindow(tmpwin, TRUE); 867. 	    destroy_nhwindow(tmpwin); 868. 	    break; 869. 	case 's': 870. 	    clear_nhwindow(WIN_MESSAGE); 871. 	    getlin("What options do you want to set?", buf); 872. 	    clear_nhwindow(WIN_MESSAGE); 873. 	    if(buf[0] == '\033') return 0; 874. 	    need_redraw = FALSE; 875. 	    parseoptions(buf, FALSE, FALSE); 876. 	    if(need_redraw) 877. 		(void) doredraw; 878. 	    break; 879. 	}  880.   881.  	return 0; 882. }  883.   884.  int 885. dotogglepickup { 886. 	flags.pickup = !flags.pickup; 887. 	pline("Pickup: %s.", flags.pickup ? "ON" : "OFF"); 888. 	return 0; 889. }  890.   891.  /* data for option_help */ 892. static const char *opt_intro[] = { 893. 	"",  894.  	"                 NetHack Options Help:", 895. 	"",  896.  #define CONFIG_SLOT 3	/* fill in next value at run-time */ 897. 	NULL, 898. #ifndef MICRO 899. 	"or use `NETHACKOPTIONS=\" \"' in your environment;", 900. # ifdef VMS 901. 	"-- for example, $ DEFINE NETHACKOPTIONS \"nopickup,fruit:kumquat\"", 902. # endif 903. #endif 904. 	"or press \"O\" while playing, and type your at the prompt.", 905. 	"In either case, is a list of options separated by commas.", 906. 	"",  907.   "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", 908. 	NULL 909. };  910.  static const char *opt_compound[] = { 911. 	"Compound options:", 912. 	"`catname'   - the name of your (first) cat (e.g., catname:Tabby),", 913. 	"`dogname'   - the name of your (first) dog (e.g., dogname:Fang),", 914. #ifdef TUTTI_FRUTTI 915. 	"`fruit'     - the name of a fruit you enjoy eating,", 916. # define FRUIT_OFFSET 1 917. #else 918. # define FRUIT_OFFSET 0 919. #endif 920. 	"`graphics'  - defines the symbols to use in drawing the dungeon map,", 921. 	"`monsters'  - defines the symbols to use for monsters,", 922. 	"`msghistory'- number of top line messages to save,", 923. 	"`name'      - your character's name (e.g., name:Merlin-W),", 924. 	"`objects'   - defines the symbols to use for objects,", 925. 	"`packorder' - the inventory order of the items in your pack", 926. #define PCKORD_SLOT 9+FRUIT_OFFSET 927. 	NULL, 928. 	"`pettype'   - your preferred initial pet type,", 929. 	"`scores'    - the parts of the score list you wish to see,", 930. 	"`windowtype'- windowing system to use.", 931. 	"",  932.   "Some of the options can be set only before the game is started.  You will", 933. 	"be so informed, if you attempt to set them while in the game.", 934. 	NULL 935. };  936.   937.  void 938. option_help 939. {  940.      char	buf[BUFSZ], pack_order[MAXOCLASSES+1]; 941.     register int	i; 942.     winid datawin; 943.  944.      datawin = create_nhwindow(NHW_TEXT); 945. #ifdef AMIGA 946.     if(FromWBench){ 947. 	Sprintf(buf,"Set options as OPTIONS= in %s or in icon;",configfile); 948.     } else 949. #endif 950. 	Sprintf(buf, "Set options as OPTIONS= in %s;", configfile); 951.     opt_intro[CONFIG_SLOT] = (const char *) buf; 952.     for (i = 0; opt_intro[i]; i++) 953. 	putstr(datawin, 0, opt_intro[i]); 954.  955.      /* Boolean options */ 956.     for (i = 0; boolopt[i].name; i++) { 957. 	if (boolopt[i].addr) 958. 	    next_opt(datawin, boolopt[i].name); 959.     }  960.      next_opt(datawin, ""); 961.  962.      /* Compound options */ 963.     oc_to_str(inv_order, pack_order); 964.     Sprintf(buf, "              (currently, packorder:%s ),", pack_order); 965. #if 0 966.     assert( opt_compound[PCKORD_SLOT] == NULL ); 967. #endif 968.     opt_compound[PCKORD_SLOT] = (const char *) buf; 969.     for (i = 0; opt_compound[i]; i++) 970. 	putstr(datawin, 0, opt_compound[i]); 971.  972.      display_nhwindow(datawin, FALSE); 973.     destroy_nhwindow(datawin); 974.     return; 975. }  976.   977.  /*  978.   * prints the next boolean option, on the same line if possible, on a new 979.  * line if not. End with next_opt(""). 980.  */  981.  void 982. next_opt(datawin, str) 983. winid datawin; 984. const char *str; 985. {  986.  	static char buf[121]; 987. 	int i;  988. char *s; 989.  990.  	if (!*str) { 991. 		for (s = buf; *s; s++);	/* find end of string */ 992. 		if (s > &buf[1] && s[-2] == ',') 993. 			s[-2] = 0;	/* strip last ", " */ 994. 		i = 121; 995. 	}  996.  	else 997. 		i = strlen(buf) + strlen(str) + 2; 998.  999.  	if (i > COLNO - 2) { /* rule of thumb */ 1000. 		putstr(datawin, 0, buf); 1001. 		buf[0] = 0; 1002. 	} 1003. 	if (*str) { 1004. 		Strcat(buf, str); 1005. 		Strcat(buf, ", "); 1006. 	} 1007. 	else 1008. 		putstr(datawin, 0, str); 1009. 	return; 1010. } 1011.  1012. #ifdef TUTTI_FRUTTI 1013. /* Returns the fid of the fruit type; if that type already exists, it 1014. * returns the fid of that one; if it does not exist, it adds a new fruit 1015. * type to the chain and returns the new one. 1016. */  1017. int 1018. fruitadd(str) 1019. char *str; 1020. { 1021. 	register int i,j; 1022. 	register struct fruit *f; 1023. #ifdef GCC_WARN 1024. 	struct fruit *lastf = (struct fruit *)0; 1025. #else 1026. 	struct fruit *lastf; 1027. #endif 1028. 	int highest_fruit_id = 0; 1029. 	char buf[PL_FSIZ]; 1030. 	boolean user_specified = (str == pl_fruit); 1031. 	/* if not user-specified, then it's a fruit name for a fruit on 1032. * a bones level... 1033. */ 1034.  1035. 	/* Note: every fruit has an id (spe for fruit objects) of at least 1036. 	 * 1; 0 is an error. 1037. 	 */ 1038. 	if (user_specified) { 1039. 		/* disallow naming after other foods (since it'd be impossible 1040. 		 * to tell the difference) 1041. 		 */ 1042.  1043. 		boolean found = FALSE; 1044. 1045. 		for(i = bases[j=letindex(FOOD_CLASS)]; i < bases[j+1]; i++) { 1046. 			if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) { 1047. 				found = TRUE; 1048. 				break; 1049. 			} 1050. 		}  1051. 		if (found ||  1052. 		    (!strncmp(str, "tin of ", 7) && name_to_mon(str+7) > -1) ||  1053. 		    !strcmp(str, "empty tin") ||  1054. 		    !strcmp(str, "tin of spinach") ||  1055. 		    ((!strncmp(eos(str)-6," corpse",7) ||  1056. 						!strncmp(eos(str)-3, " egg",4)) 1057. 			&& name_to_mon(str) > -1)) 1058. 			{ 1059. 				Strcpy(buf, pl_fruit); 1060. 				Strcpy(pl_fruit, "candied "); 1061. 				nmcpy(pl_fruit+8, buf, PL_FSIZ-8); 1062. 		} 1063. 	}  1064. 	for(f=ffruit; f; f = f->nextf) { 1065. 		lastf = f; 1066. if(f->fid > highest_fruit_id) highest_fruit_id = f->fid; 1067. 		if(!strncmp(str, f->fname, PL_FSIZ)) 1068. 			goto nonew; 1069. 	} 1070. 	/* if adding another fruit would overflow spe, use a random 1071. 	  fruit instead... we've got a lot to choose from. */ 1072. 	if (highest_fruit_id >= 127) return rnd(127); 1073. 	highest_fruit_id++; 1074. 	f = newfruit; 1075. 	if (ffruit) lastf->nextf = f; 1076. else ffruit = f; 1077. Strcpy(f->fname, str); 1078. 	f->fid = highest_fruit_id; 1079. 	f->nextf = 0; 1080. nonew: 1081. 	if (user_specified) current_fruit = highest_fruit_id; 1082. 	return f->fid; 1083. } 1084. #endif 1085. 1086. /*options.c*/