Source:NetHack 3.0.0/options.c

Below is the full text to options.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.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.0	88/11/09 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    static boolean set_order; 7.    8.    static void nmcpy; 9.    10.   void 11.  initoptions 12.  {  13.   	register char *opts; 14.   15.   	flags.time = flags.nonews = flags.notombstone = flags.end_own = 16.  	flags.standout = flags.nonull = flags.ignintr = FALSE; 17.  	flags.no_rest_on_space = flags.invlet_constant = TRUE; 18.  	flags.end_top = 5; 19.  	flags.end_around = 4; 20.  	flags.female = FALSE;			/* players are usually male */ 21.  	flags.sortpack = TRUE; 22.  	flags.soundok = TRUE; 23.  	flags.verbose = TRUE; 24.  	flags.confirm = TRUE; 25.  	flags.safe_dog = TRUE; 26.  	flags.silent = 	flags.pickup = TRUE; 27.  	nmcpy(pl_fruit, objects[SLIME_MOLD].oc_name, PL_FSIZ); 28.  	flags.num_pad = FALSE; 29.  #ifdef MSDOS 30.  #ifdef DECRAINBOW 31.  	flags.DECRainbow = FALSE; 32.  #endif 33.  #ifdef DGK 34.  	flags.IBMBIOS = 35.  	flags.rawio = FALSE; 36.  #endif 37.  	read_config_file; 38.  #endif /* MSDOS */ 39.  	if(opts = getenv("NETHACKOPTIONS")) 40.  		parseoptions(opts,TRUE); 41.  	(void)fruitadd(pl_fruit); 42.  	objects[SLIME_MOLD].oc_name = "\033"; 43.  	/* Put something untypable in there */ 44.  	/* We cannot just use NULL because that marks the end of objects */ 45.  }  46.    47.   static void 48.  nmcpy(dest, source, maxlen) 49.  	char	*dest, *source; 50.  	int	maxlen; 51.  {  52.   	char	*cs, *cd; 53.  	int	count; 54.   55.   	cd = dest; 56.  	cs = source; 57.  	for(count = 1; count < maxlen; count++) { 58.  		if(*cs == ',' || *cs == '\0') break; /*exit on \0 terminator*/ 59.  		*cd++ = *cs++; 60.  	}  61.   	*cd = 0; 62.  }  63.    64.   /*  65.    * escapes: escape expansion for showsyms. C-style escapes understood include 66.   * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix 67.   * for control characters is also understood, and \[mM] followed by any of the 68.   * previous forms or by a character has the effect of 'meta'-ing the value (so  69.    * that the alternate character set will be enabled). 70.   */  71.   void 72.  escapes(cp, tp) 73.  char	*cp, *tp; 74.  {  75.       while (*cp) 76.      {  77.   	int	cval = 0, meta = 0; 78.   79.   	if (*cp == '\\' && index("mM", cp[1])) { 80.  		meta = 1; 81.  		cp += 2; 82.  	}  83.   	if (*cp == '\\' && index("0123456789xXoO", cp[1])) 84.  	{  85.   	    char *dp, *hex = "00112233445566778899aAbBcCdDeEfF"; 86.  	    int dcount = 0; 87.   88.   	    cp++; 89.  	    if (*cp == 'x' || *cp == 'X') 90.  		for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++) 91.  		    cval = (cval * 16) + (dp - hex) / 2; 92.  	    else if (*cp == 'o' || *cp == 'O') 93.  		for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++) 94.  		    cval = (cval * 8) + (*cp - '0'); 95.  	    else 96.  		for ((index("0123456789",*cp)) && (dcount++ < 3); cp++) 97.  		    cval = (cval * 10) + (*cp - '0'); 98.  	}  99.   	else if (*cp == '\\')		/* C-style character escapes */ 100. 	{  101.  	    switch (*++cp) 102. 	    {  103.  	    case '\\': cval = '\\'; break; 104. 	    case 'n': cval = '\n'; break; 105. 	    case 't': cval = '\t'; break; 106. 	    case 'b': cval = '\b'; break; 107. 	    case 'r': cval = '\r'; break; 108. 	    default: cval = *cp; 109. 	    }  110.  	    cp++; 111. 	}  112.  	else if (*cp == '^')		/* expand control-character syntax */ 113. 	{  114.  	    cval = (*++cp & 0x1f); 115. 	    cp++; 116. 	}  117.  	else 118. 	    cval = *cp++; 119. 	if (meta) 120. 	    cval |= 0x80; 121. 	*tp++ = cval; 122.     }  123.      *tp = '\0'; 124. }  125.   126.  void 127. parseoptions(opts, from_env) 128. register char *opts; 129. boolean from_env; 130. {  131.  	register char *op; 132. /*  133.  	register char *op2; 134. */  135.  	unsigned num; 136. 	boolean negated; 137.  138.  	if(op = index(opts, ',')) { 139. 		*op++ = 0; 140. 		parseoptions(op, from_env); 141. 	}  142.  /*  143.  	if(op = index(opts, ' ')) { 144. 		op2 = op; 145. 		while(*op++) 146. 			if(*op != ' ') *op2++ = *op; 147. 	}  148.  */  149.  	if(!*opts) return; 150. 	negated = FALSE; 151. 	while((*opts == '!') || !strncmp(opts, "no", 2)) { 152. 		if(*opts == '!') opts++; else opts += 2; 153. 		negated = !negated; 154. 	}  155.  	  156.  #ifndef MSDOS 157. 	if (!strncmp(opts, "standout", 4)) { 158. 		flags.standout = !negated; 159. 		return; 160. 	}  161.   162.  	if (!strncmp(opts, "null", 4)) { 163. 		flags.nonull = negated; 164. 		return; 165. 	}  166.  #endif 167.  168.  	if (!strncmp(opts, "ignintr", 3)) { 169. 		flags.ignintr = !negated; 170. 		return; 171. 	}  172.   173.  	if (!strncmp(opts, "tombstone", 4)) { 174. 		flags.notombstone = negated; 175. 		return; 176. 	}  177.   178.  #ifdef NEWS 179. 	if (!strncmp(opts, "news", 4)) { 180. 		flags.nonews = negated; 181. 		return; 182. 	}  183.  #endif 184.  185.  	if (!strncmp(opts, "confirm", 4)) { 186. 		flags.confirm = !negated; 187. 		return; 188. 	}  189.  	if (!strncmp(opts, "safe", 4)) { 190. 		flags.safe_dog = !negated; 191. 		return; 192. 	}  193.   194.  	if (!strncmp(opts, "silent", 4)) { 195. 		flags.silent = !negated; 196. 		return; 197. 	}  198.   199.  	if (!strncmp(opts, "verbose", 4)) { 200. 		flags.verbose = !negated; 201. 		return; 202. 	}  203.   204.  	if (!strncmp(opts, "pickup", 4)) { 205. 		flags.pickup = !negated; 206. 		return; 207. 	}  208.   209.  	if (!strncmp(opts, "number_pad", 4)) { 210. 		flags.num_pad = !negated; 211. 		return; 212. 	}  213.   214.  #ifdef DGK 215. 	if (!strncmp(opts, "IBM", 3)) { 216. 		flags.IBMBIOS = !negated; 217. 		return; 218. 	}  219.   220.  	if (!strncmp(opts, "rawio", 4)) { 221. 		if (from_env) 222. 			flags.rawio = !negated; 223. 		else 224. 			pline("\"rawio\" settable only from %s.", configfile); 225. 		return; 226. 	}  227.   228.  #ifdef DECRAINBOW 229. 	if (!strncmp(opts, "DEC", 3)) { 230. 		flags.DECRainbow = !negated; 231. 		return; 232. 	}  233.  #endif /* DECRAINBOW */ 234. #endif 235.  236.  	if (!strncmp(opts, "sort", 4)) { 237. 		flags.sortpack = !negated; 238. 		return; 239. 	}  240.   241.  	/*  242.  	 * the order to list the pack 243. 	 */  244.  	if (!strncmp(opts, "packorder", 4)) { 245. 		register char	*sp, *tmp; 246. 		int tmpend; 247.  248.  		op = index(opts,':'); 249. 		if(!op) goto bad; 250. 		op++;			/* skip : */ 251.  252.  		/* Missing characters in new order are filled in at the end 253. 		 * from inv_order. 254. 		 */  255.  		for (sp = op; *sp; sp++) 256. 			if (!index(inv_order, *sp)) 257. 				goto bad;		/* bad char in order */ 258. 			else if (index(sp + 1, *sp)) 259. 				goto bad;		/* dup char in order */ 260. 		tmp = (char *) alloc((unsigned)(strlen(inv_order)+1)); 261. 		Strcpy(tmp, op); 262. 		for (sp = inv_order, tmpend = strlen(tmp); *sp; sp++) 263. 			if (!index(tmp, *sp)) { 264. 				tmp[tmpend++] = *sp; 265. 				tmp[tmpend] = 0; 266. 			}  267.  		Strcpy(inv_order, tmp); 268. 		free((genericptr_t)tmp); 269. 		set_order = TRUE; 270. 		return; 271. 	}  272.   273.  	if (!strncmp(opts, "time", 4)) { 274. 		flags.time = !negated; 275. 		flags.botl = 1; 276. 		return; 277. 	}  278.   279.  	if (!strncmp(opts, "rest_on_space", 4)) { 280. 		flags.no_rest_on_space = negated; 281. 		return; 282. 	}  283.   284.  	if (!strncmp(opts, "fixinv", 3)) { 285. 		flags.invlet_constant = !negated; 286. 		if(!from_env && flags.invlet_constant) reassign ; 287. 		return; 288. 	}  289.   290.  	if (!strncmp(opts, "male", 4)) { 291. 		if(!from_env && flags.female != negated) 292. 			pline("That is not anatomically possible."); 293. 		else 294. 			flags.female = negated; 295. 		return; 296. 	}  297.  	if (!strncmp(opts, "female", 3)) { 298. 		if(!from_env && flags.female == negated) 299. 			pline("That is not anatomically possible."); 300. 		else 301. 			flags.female = !negated; 302. 		return; 303. 	}  304.   305.  	/* name:string */ 306. 	if (!strncmp(opts, "name", 4)) { 307. 		if(!from_env) { 308. #ifdef MSDOS 309. 		  pline("\"name\" settable only from %s.", configfile); 310. #else 311. 		  pline("The playername can be set only from NETHACKOPTIONS."); 312. #endif 313. 		  return; 314. 		}  315.  		op = index(opts,':'); 316. 		if(!op) goto bad; 317. 		nmcpy(plname, op+1, sizeof(plname)-1); 318. 		return; 319. 	}  320.   321.  	/* graphics:string */ 322. 	if (!strncmp(opts, "graphics", 4)) { 323. 		if(!from_env) { 324. #ifdef MSDOS 325. 		  pline("\"graphics\" settable only from %s.", configfile); 326. #else 327. 		  pline("The graphics string can be set only from NETHACKOPTIONS."); 328. #endif 329. 		  return; 330. 		}  331.  		op = index(opts,':'); 332. 		if(!op) 333. 		    goto bad; 334. 		else 335. 		    opts = op + 1; 336. 		escapes(opts, opts); 337. #define SETPCHAR(f, n)	showsyms.f = (strlen(opts) > n) ? opts[n] : defsyms.f 338. SETPCHAR(stone, 0); 339. 		SETPCHAR(vwall, 1); 340. 		SETPCHAR(hwall, 2); 341. 		SETPCHAR(tlcorn, 3); 342. 		SETPCHAR(trcorn, 4); 343. 		SETPCHAR(blcorn, 5); 344. 		SETPCHAR(brcorn, 6); 345. 		SETPCHAR(crwall, 7); 346. 		SETPCHAR(tuwall, 8); 347. 		SETPCHAR(tdwall, 9); 348. 		SETPCHAR(tlwall, 10); 349. 		SETPCHAR(trwall, 11); 350. 		SETPCHAR(vbeam, 12); 351. 		SETPCHAR(hbeam, 13); 352. 		SETPCHAR(lslant, 14); 353. 		SETPCHAR(rslant, 15); 354. 		SETPCHAR(door, 16); 355. 		SETPCHAR(room, 17); 356. 		SETPCHAR(corr, 18); 357. 		SETPCHAR(upstair, 19); 358. 		SETPCHAR(dnstair, 20); 359. 		SETPCHAR(trap, 21); 360. 		SETPCHAR(web, 22); 361. 		SETPCHAR(pool, 23); 362. #ifdef FOUNTAINS 363. 		SETPCHAR(fountain, 24); 364. #endif 365. #ifdef SINKS 366. 		SETPCHAR(sink, 25); 367. #endif 368. #ifdef THRONES 369. 		SETPCHAR(throne, 26); 370. #endif 371. #ifdef ALTARS 372. 		SETPCHAR(altar, 27); 373. #endif 374. #ifdef STRONGHOLD 375. 		SETPCHAR(upladder, 28); 376. 		SETPCHAR(dnladder, 29); 377. 		SETPCHAR(dbvwall, 30); 378. 		SETPCHAR(dbhwall, 31); 379. #endif 380. #undef SETPCHAR 381. 		return; 382. 	}  383.   384.  	/* endgame:5t[op] 5a[round] o[wn] */ 385. 	if (!strncmp(opts, "endgame", 3)) { 386. 		op = index(opts,':'); 387. 		if(!op) goto bad; 388. 		op++; 389. 		while(*op) { 390. 			num = 1; 391. 			if(digit(*op)) { 392. 				num = atoi(op); 393. 				while(digit(*op)) op++; 394. 			} else 395. 			if(*op == '!') { 396. 				negated = !negated; 397. 				op++; 398. 			}  399.  			switch(*op) { 400. 			case 't': 401. 				flags.end_top = num; 402. 				break; 403. 			case 'a': 404. 				flags.end_around = num; 405. 				break; 406. 			case 'o': 407. 				flags.end_own = !negated; 408. 				break; 409. 			default: 410. 				goto bad; 411. 			}  412.  			while(letter(*++op)) ; 413. 			if(*op == '/') op++; 414. 		}  415.  		return; 416. 	}  417.  	if (!strncmp(opts, "dogname", 3)) { 418. 		if(!from_env) { 419. #ifdef MSDOS 420. 		  pline("\"dogname\" settable only from %s.", configfile); 421. #else 422. 		  Your("dog's name can be set only from NETHACKOPTIONS."); 423. #endif 424. 		  return; 425. 		}  426.  		op = index(opts, ':'); 427. 		if (!op) goto bad; 428. 		nmcpy(dogname, ++op, 62); 429. 		return; 430. 	}  431.  	if (!strncmp(opts, "catname", 3)) { 432. 		if(!from_env) { 433. #ifdef MSDOS 434. 		  pline("\"catname\" settable only from %s.", configfile); 435. #else 436. 		  Your("cat's name can be set only from NETHACKOPTIONS."); 437. #endif 438. 		  return; 439. 		}  440.  		op = index(opts, ':'); 441. 		if (!op) goto bad; 442. 		nmcpy(catname, ++op, 62); 443. 		return; 444. 	}  445.  	if (!strncmp(opts, "fruit", 2)) { 446. 		op = index(opts, ':'); 447. 		if (!op++) goto bad; 448. 		if (!from_env) { 449. 		    struct fruit *f; 450. 		    int numfruits = 0; 451.  452.  		    for(f=ffruit; f; f=f->nextf) { 453. 			if (!strcmp(op, f->fname)) goto goodfruit; 454. 			numfruits++; 455. 		    }  456.  		    if (numfruits >= 100) { 457. 			pline("Doing that so many times isn't very fruitful."); 458. 			return; 459. 		    }  460.  		}  461.  goodfruit: 462. 		nmcpy(pl_fruit, op, PL_FSIZ); 463. 		if (!from_env) 464. 		    (void)fruitadd(pl_fruit); 465. 		/* If from_env, then initoptions is allowed to do it instead 466. 		 * of here (initoptions always has to do it even if there's  467.  		 * no fruit option at all.  Also, we don't want people  468.  		 * setting multiple fruits in their options.) 469. 		 */  470.  		return; 471. 	}  472.  bad: 473. 	if(!from_env) { 474. 		if(!strncmp(opts, "h", 1) ||  475.  		   !strncmp(opts, "?", 1)) { 476. 			option_help; 477. 			return; 478. 		}  479.  		pline("Unknown option: %s.  Enter \"O?\" for help.", opts); 480. 		return; 481. 	}  482.  #ifdef MSDOS 483. 	Printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts); 484. #else 485. 	Printf("Bad syntax in NETHACKOPTIONS: %s.", opts); 486. 	(void) puts("Use for example:"); 487. 	(void) puts(  488.  "NETHACKOPTIONS=\"!rest_on_space,notombstone,endgame:own/5 topscorers/4 around me\""  489.  	); 490. #endif 491. 	getret; 492. }  493.   494.  int 495. doset 496. {  497.  	char buf[BUFSZ]; 498.  499.  	pline("What options do you want to set? "); 500. 	getlin(buf); 501. 	if(!buf[0] || buf[0] == '\033') { 502. #ifdef MSDOS 503. 	    Strcpy(buf,"OPTIONS="); 504. #ifdef DGK 505. 	    if (flags.rawio) Strcat(buf,"rawio,"); 506. 	    if (flags.IBMBIOS) Strcat(buf,"IBM_BIOS,"); 507. #endif /* DGK */ 508. #ifdef DECRAINBOW 509. 	    if (flags.DECRainbow) Strcat(buf,"DEC_Rainbow,"); 510. #endif /* DECRAINBOW */ 511. #else /* MSDOS */ 512. 	    Strcpy(buf,"NETHACKOPTIONS="); 513. 	    if(flags.standout) Strcat(buf,"standout,"); 514. 	    if(flags.nonull) Strcat(buf,"nonull,"); 515. #endif /* MSDOS */ 516. 	    if(flags.ignintr) Strcat(buf,"ignintr,"); 517. 	    if(flags.num_pad) Strcat(buf,"number_pad,"); 518. #ifdef NEWS 519. 	    if(flags.nonews) Strcat(buf,"nonews,"); 520. #endif 521. 	    if(flags.notombstone) Strcat(buf,"notombstone,"); 522. 	    Strcat(buf, flags.female ? "female," : "male,"); 523. 	    if(flags.no_rest_on_space)	Strcat(buf,"!rest_on_space,"); 524. 	    if (flags.invlet_constant) Strcat(buf,"fixinv,"); 525. 	    if (flags.sortpack) Strcat(buf,"sortpack,"); 526. 	    if (set_order){ 527. 		Strcat(buf, "packorder: "); 528. 		Strcat(buf, inv_order); 529. 		Strcat(buf, ","); 530. 	    }  531.  	    if (flags.confirm) Strcat(buf,"confirm,"); 532. 	    if (flags.safe_dog) Strcat(buf,"safe_pet,"); 533. 	    if (flags.pickup) Strcat(buf,"pickup,"); 534. 	    if (flags.silent) Strcat(buf,"silent,"); 535. 	    if (flags.time) Strcat(buf,"time,"); 536. 	    if (flags.verbose) Strcat(buf,"verbose,"); 537. 	    Sprintf(eos(buf), "fruit:%s,", pl_fruit); 538. 	    if(flags.end_top != 5 || flags.end_around != 4 || flags.end_own){ 539. 		Sprintf(eos(buf), "endgame: %u top scores/%u around me",  540.  			flags.end_top, flags.end_around); 541. 		if(flags.end_own) Strcat(buf, "/own scores"); 542. 	    } else { 543. 		register char *eop = eos(buf); 544. 		if(*--eop == ',') *eop = 0; 545. 	    }  546.  	    pline(buf); 547. 	} else { 548. 	    clrlin; 549. 	    parseoptions(buf, FALSE); 550. 	}  551.   552.  	return 0; 553. }  554.   555.  int 556. dotogglepickup { 557. 	flags.pickup = !flags.pickup; 558. 	pline("Pickup: %s.", flags.pickup ? "ON" : "OFF"); 559. 	return 0; 560. }  561.   562.  char	packorder[] =	{ 563. 	AMULET_SYM, WEAPON_SYM, ARMOR_SYM, FOOD_SYM, SCROLL_SYM, 564. # ifdef SPELLS 565. 	SPBOOK_SYM, 566. # endif 567. 	WAND_SYM, RING_SYM, POTION_SYM, TOOL_SYM, GEM_SYM, BALL_SYM, ROCK_SYM }; 568. #define Page_line(x)	if(page_line(x)) goto quit 569.  570.  void 571. option_help { 572. 	char	buf[BUFSZ]; 573.  574.  	set_pager(0); 575. 	Sprintf(buf, "                 NetHack Options Help:"); 576. 	if(page_line("") || page_line(buf) || page_line(""))	 goto quit; 577.  578.  #ifdef MSDOS 579. 	Sprintf(buf, "To set options use OPTIONS= in %s;", configfile); 580. 	Page_line(buf); 581. #else 582. 	Page_line("To set options use `NETHACKOPTIONS=\" \"' in your environment;"); 583. #endif 584.  585.  	Page_line("or press \"O\" while playing, and type your at the prompt."); 586. 	Page_line("In either case, is a list of options separated by commas."); 587. 	Page_line(""); 588.  589.  	Page_line("Boolean options (which can be negated by prefixing them with '!' or \"no\"):"); 590. 	Page_line("confirm, (fe)male, fixinv, pickup, rest_on_space, safe_pet, silent, sortpack,"); 591. #ifdef MSDOS 592. #ifdef NEWS 593. 	Page_line("time, tombstone, verbose, news, number_pad, rawio, and IBM_BIOS"); 594. #else 595. 	Page_line("time, tombstone, verbose, number_pad, rawio, and IBM_BIOS"); 596. #endif 597. #ifdef DECRAINBOW 598. 	Page_line("and DEC_Rainbow."); 599. #endif /* DECRAINBOW */ 600. #else /* MSDOS */ 601. #ifdef NEWS 602. 	Page_line("time, tombstone, verbose, news, null, ignintr, and standout."); 603. #else 604. 	Page_line("time, tombstone, verbose, null, ignintr, and standout."); 605. #endif 606. #endif /* MSDOS */ 607. 	Page_line(""); 608.  609.  	Page_line("Compound options:"); 610. 	Page_line("`name'      - your character's name (e.g., name:Merlin-W),"); 611. 	Page_line("`dogname'   - the name of your (first) dog (e.g., dogname:Fang),"); 612.  613.  	Page_line("`packorder' - the inventory order of the items in your pack"); 614. 	Sprintf(buf, "              (currently, packorder:%s ),", packorder); 615. 	Page_line(buf); 616. 	Page_line("`fruit'     - the name of a fruit you enjoy eating,"); 617.  618.  	Page_line("`endgame'   - the parts of the score list you wish to see,"); 619.  620.  	Page_line("`graphics'  - defines the symbols to use in drawing the dungeon map."); 621. 	Page_line(""); 622. 	Page_line("Some of the options can be set only before the game is started.  You will"); 623. 	Page_line("be so informed, if you attempt to set them while in the game."); 624. 	set_pager(1); 625. 	return; 626. quit: 627. 	set_pager(2); 628. 	return; 629. }  630.   631.  /* Returns the fid of the fruit type; if that type already exists, it  632. * returns the fid of that one; if it does not exist, it adds a new fruit 633.  * type to the chain and returns the new one. 634.  */  635.  int 636. fruitadd(str) 637. char *str; 638. {  639.  	register int i,j; 640. 	register struct fruit *f; 641. 	struct fruit *lastf; 642. 	int highest_fruit_id = 0; 643. 	char buf[PL_FSIZ]; 644. 	boolean user_specified = (str == pl_fruit); 645. 	/* if not user-specified, then it's a fruit name for a fruit on  646. * a bones level... 647. */ 648.   649.  	/* Note: every fruit has an id (spe for fruit objects) of at least 650. 	 * 1; 0 is an error. 651. 	 */  652.  	if (user_specified) { 653. 		/* disallow naming after other foods (since it'd be impossible  654.  		 * to tell the difference) 655. 		 */  656.   657.  		boolean found = FALSE; 658.  659.  		for(i = bases[j=letindex(FOOD_SYM)]; i < bases[j+1]; i++) { 660. 			if (!strcmp(objects[i].oc_name, pl_fruit)) { 661. 				found = TRUE; 662. 				break; 663. 			}  664.  		}  665.  		if (found ||  666.  		    (!strncmp(buf, "tin of ", 7) && name_to_mon(buf+7) > -1) ||  667.  		    !strcmp(buf, "empty tin") ||  668.  		    !strcmp(buf, "tin of spinach") ||  669.  		    (!strncmp(eos(buf)-6," corpse",6) && name_to_mon(buf) > -1)) 670. 			{  671.  				Strcpy(buf, pl_fruit); 672. 				Strcpy(pl_fruit, "candied "); 673. 				nmcpy(pl_fruit+8, buf, PL_FSIZ-8); 674. 		}  675.  	}  676.  	for(f=ffruit; f; f = f->nextf) { 677. 		lastf = f;  678. if(f->fid > highest_fruit_id) highest_fruit_id = f->fid; 679. 		if(!strncmp(str, f->fname, PL_FSIZ)) 680. 			goto nonew; 681. 	}  682.  	/* if adding another fruit would overflow spe, use a random 683. 	   fruit instead... we've got a lot to choose from. */ 684.  	if (highest_fruit_id >= 127) return rnd(127); 685. 	highest_fruit_id++; 686. 	f = newfruit; 687. 	if (ffruit) lastf->nextf = f;  688. else ffruit = f; 689. Strcpy(f->fname, str); 690. 	f->fid = highest_fruit_id; 691. 	f->nextf = 0; 692. nonew: 693. 	if (user_specified) current_fruit = highest_fruit_id; 694. 	return f->fid; 695. }