Source:NetHack 3.0.0/options.c

From NetHackWiki
Revision as of 05:10, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.0.0/options.c moved to Source:NetHack 3.0.0/options.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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=<options> in %s;", configfile);
580.  	Page_line(buf);
581.  #else
582.  	Page_line("To set options use `NETHACKOPTIONS=\"<options>\"' in your environment;");
583.  #endif
584.  
585.  	Page_line("or press \"O\" while playing, and type your <options> at the prompt.");
586.  	Page_line("In either case, <options> 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.  }