Source:NetHack 3.0.0/objnam.c

From NetHackWiki
Revision as of 05:09, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.0.0/objnam.c moved to Source:NetHack 3.0.0/objnam.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 objnam.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.0/objnam.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: @(#)objnam.c	3.0	88/11/30
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include	"hack.h"
6.    
7.    #define	PREFIX	30
8.    
9.    /*	We want the player to be able to learn what key goes in what lock.  */
10.   const char *keystr[N_LOX] = { "round", "square", "triangular", "oval",
11.   			    "octagonal", "hexagonal", "cylindrical",
12.   			    "irregular", "conical", "wedge-shaped" },
13.   	   *lockstr[N_LOX] = { "round", "square", "triangular", "oval",
14.   			    "octagonal", "hexagonal", "wide",
15.   			    "notched", "large round", "large square" };
16.   
17.   static int rnd_class P((int,int));
18.   
19.   static int
20.   named_key(s) register char *s; {
21.   	char tc[BUFSZ];
22.   	register int i;
23.   
24.   	for(i=0; i<10; i++) {
25.   		Strcpy(tc, keystr[i]);
26.   		Strcat(tc, " key");
27.   		if(!strcmp(s,tc)) return(i+1);
28.   	}
29.   	return(0);
30.   }
31.   
32.   static int
33.   named_box(s)
34.   register char *s;
35.   {
36.   	char tc[BUFSZ];
37.   	register int i;
38.   
39.   	for(i=0; i<10; i++) {
40.   		Strcpy(tc, lockstr[i]);
41.   		Strcat(tc, " keyhole)");
42.   		if(!strcmp(s,tc)) return(i+1);
43.   	}
44.   	return(0);
45.   }
46.   
47.   static char *
48.   strprepend(s,pref) register char *s, *pref; {
49.   register int i = strlen(pref);
50.   	if(i > PREFIX) {
51.   		pline("WARNING: prefix too short.");
52.   		return(s);
53.   	}
54.   	s -= i;
55.   	(void) strncpy(s, pref, i);	/* do not copy trailing 0 */
56.   	return(s);
57.   }
58.   
59.   static char *
60.   sitoa(a) int a; {
61.   #ifdef LINT	/* static char buf[13]; */
62.   	char buf[13];
63.   #else
64.   	static char buf[13];
65.   #endif
66.   	Sprintf(buf, (a < 0) ? "%d" : "+%d", a);
67.   	return(buf);
68.   }
69.   
70.   char *
71.   typename(otyp)
72.   register int otyp;
73.   {
74.   #ifdef LINT	/* static char buf[BUFSZ]; */
75.   char buf[BUFSZ];
76.   #else
77.   static char buf[BUFSZ];
78.   #endif
79.   register struct objclass *ocl = &objects[otyp];
80.   register char *an = ocl->oc_name;
81.   register char *dn = ocl->oc_descr;
82.   register char *un = ocl->oc_uname;
83.   register int nn = ocl->oc_name_known;
84.   	switch(ocl->oc_olet) {
85.   	case POTION_SYM:
86.   		Strcpy(buf, "potion");
87.   		break;
88.   	case SCROLL_SYM:
89.   		Strcpy(buf, "scroll");
90.   		break;
91.   	case WAND_SYM:
92.   		Strcpy(buf, "wand");
93.   		break;
94.   #ifdef SPELLS
95.   	case SPBOOK_SYM:
96.   		Strcpy(buf, "spellbook");
97.   		break;
98.   #endif
99.   	case RING_SYM:
100.  		Strcpy(buf, "ring");
101.  		break;
102.  	case AMULET_SYM:
103.  		if(nn)
104.  			Strcpy(buf,an);
105.  		else
106.  			Strcpy(buf,"amulet");
107.  		if(un)
108.  			Sprintf(eos(buf)," called %s",un);
109.  		if(dn)
110.  			Sprintf(eos(buf)," (%s)",dn);
111.  		return(buf);
112.  	default:
113.  		if(nn) {
114.  			Strcpy(buf, an);
115.  			if(otyp >= TURQUOISE && otyp <= JADE)
116.  				Strcat(buf, " stone");
117.  			if(un)
118.  				Sprintf(eos(buf), " called %s", un);
119.  			if(dn)
120.  				Sprintf(eos(buf), " (%s)", dn);
121.  		} else {
122.  			Strcpy(buf, dn ? dn : an);
123.  			if(ocl->oc_olet == GEM_SYM) {
124.  				if (otyp == LOADSTONE || otyp == LUCKSTONE)
125.  					Strcat(buf, " stone");
126.  				else
127.  					Strcat(buf, " gem");
128.  			}
129.  			if(un)
130.  				Sprintf(eos(buf), " called %s", un);
131.  		}
132.  		return(buf);
133.  	}
134.  	/* here for ring/scroll/potion/wand */
135.  	if(nn)
136.  		Sprintf(eos(buf), " of %s", an);
137.  	if(un)
138.  		Sprintf(eos(buf), " called %s", un);
139.  	if(dn)
140.  		Sprintf(eos(buf), " (%s)", dn);
141.  	return(buf);
142.  }
143.  
144.  /* Give the name of an object seen at a distance.  Unlike xname/doname,
145.   * we don't want to set dknown if it's not set already.  The kludge used is
146.   * to temporarily set Blind so that xname() skips the dknown setting.  This
147.   * assumes that we don't want to do this too often; if this function becomes
148.   * frequently used, it'd probably be better to pass a parameter to xname()
149.   * or doname() instead.
150.   */
151.  char *
152.  distant_name(obj, func)
153.  register struct obj *obj;
154.  char *(*func) P((struct obj *));
155.  {
156.  	char *str;
157.  
158.  	long save_Blinded = Blinded;
159.  	Blinded = 1;
160.  	str = func(obj);
161.  	Blinded = save_Blinded;
162.  	return str;
163.  }
164.  
165.  char *
166.  xname(obj)
167.  register struct obj *obj;
168.  {
169.  #ifdef LINT	/* lint may handle static decl poorly -- static char bufr[]; */
170.  char bufr[BUFSZ];
171.  #else
172.  static char bufr[BUFSZ];
173.  #endif
174.  register char *buf = &(bufr[PREFIX]);	/* leave room for "17 -3 " */
175.  register int nn = objects[obj->otyp].oc_name_known;
176.  register char *an = objects[obj->otyp].oc_name;
177.  register char *dn = objects[obj->otyp].oc_descr;
178.  register char *un = objects[obj->otyp].oc_uname;
179.  
180.  	buf[0] = 0;
181.  	if(!Blind) obj->dknown=1;
182.  	switch(obj->olet) {
183.  	    case AMULET_SYM:
184.  		if(obj->otyp == AMULET_OF_YENDOR) {
185.  		    Strcpy(buf, (obj->spe < 0 && obj->known) ?
186.  			   "cheap plastic imitation of the " : "");
187.  		    Strcat(buf, an);
188.  		} else if (!obj->dknown)
189.  			Strcpy(buf, "amulet");
190.  		else if (nn)
191.  			Strcpy(buf, an);
192.  		else if (un)
193.  			Sprintf(buf,"amulet called %s", un);
194.  		else
195.  			Sprintf(buf,"%s amulet", dn);
196.  		break;
197.  	    case WEAPON_SYM:
198.  		if(obj->otyp <= SHURIKEN && obj->opoisoned)
199.  			Strcpy(buf, "poisoned ");
200.  	    case VENOM_SYM:
201.  	    case TOOL_SYM:
202.  		if(nn)	Strcat(buf, an);
203.  		else	Strcat(buf, dn);
204.  		if(obj->otyp == FIGURINE && obj->known) {
205.  			Sprintf(eos(buf), " of a%s %s",
206.  				index(vowels, *mons[obj->corpsenm].mname)
207.  								? "n" : "",
208.  				mons[obj->corpsenm].mname);
209.  			break;
210.  		}
211.  		break;
212.  	    case ARMOR_SYM:
213.  		if(obj->otyp==DRAGON_SCALE_MAIL) {
214.  			Sprintf(buf, "%s scale mail",
215.  						mons[obj->corpsenm].mname);
216.  			break;
217.  		}
218.  
219.  		if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
220.  
221.  		if(nn)	Strcat(buf, an);
222.  		else if(un) {
223.  			if(is_boots(obj))
224.  				Strcat(buf,"boots");
225.  			else if(is_gloves(obj))
226.  				Strcat(buf,"gloves");
227.  			else if(is_cloak(obj))
228.  				Strcpy(buf,"cloak");
229.  			else if(is_helmet(obj))
230.  				Strcpy(buf,"helmet");
231.  			else if(is_shield(obj))
232.  				Strcpy(buf,"shield");
233.  			else
234.  				Strcpy(buf,"armor");
235.  			Strcat(buf, " called ");
236.  			Strcat(buf, un);
237.  		} else	Strcat(buf, dn);
238.  		break;
239.  	    case FOOD_SYM:
240.  		if (obj->otyp == SLIME_MOLD) {
241.  			register struct fruit *f;
242.  
243.  			for(f=ffruit; f; f = f->nextf) {
244.  				if(f->fid == obj->spe) {
245.  					Strcpy(buf, f->fname);
246.  					break;
247.  				}
248.  			}
249.  			if (!f) impossible("Bad fruit #%d?", obj->spe);
250.  			break;
251.  		}
252.  		Strcpy(buf, an);
253.  		if(obj->otyp == TIN && obj->known) {
254.  		    if(obj->spe > 0)
255.  			Strcat(buf, " of spinach");
256.  		    else if (mons[obj->corpsenm].mlet == S_FUNGUS)
257.  			Sprintf(eos(buf), " of %s", mons[obj->corpsenm].mname);
258.  		    else if(obj->corpsenm >= 0)
259.  			Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname);
260.  		    else Strcpy(buf, "empty tin");
261.  		}
262.  		break;
263.  	    case CHAIN_SYM:
264.  		Strcpy(buf, an);
265.  		break;
266.  	    case ROCK_SYM:
267.  		if(obj->otyp == STATUE)
268.  		    Sprintf(buf, "%s of a%s %s", an,
269.  			    (index(vowels, *(mons[obj->corpsenm].mname))) ? "n" : "",
270.  			    mons[obj->corpsenm].mname);
271.  		else Strcpy(buf, an);
272.  		break;
273.  	    case BALL_SYM:
274.  		Sprintf(buf, "%sheavy iron ball",
275.  		  (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
276.  		break;
277.  	    case POTION_SYM:
278.  		if(nn || un || !obj->dknown) {
279.  			Strcpy(buf, "potion");
280.  			if(!obj->dknown) break;
281.  			if(nn) {
282.  			    Strcat(buf, " of ");
283.  			    if(obj->otyp == POT_WATER &&
284.  			       objects[POT_WATER].oc_name_known &&
285.  			       (obj->bknown || pl_character[0] == 'P') &&
286.  			       (obj->blessed || obj->cursed)) {
287.  				Strcat(buf, obj->blessed ? "holy " : "unholy ");
288.  			    }
289.  			    Strcat(buf, an);
290.  			} else {
291.  				Strcat(buf, " called ");
292.  				Strcat(buf, un);
293.  			}
294.  		} else {
295.  			Strcpy(buf, dn);
296.  			Strcat(buf, " potion");
297.  		}
298.  		break;
299.  	case SCROLL_SYM:
300.  		Strcpy(buf, "scroll");
301.  		if(!obj->dknown) break;
302.  		if(nn) {
303.  			Strcat(buf, " of ");
304.  			Strcat(buf, an);
305.  		} else if(un) {
306.  			Strcat(buf, " called ");
307.  			Strcat(buf, un);
308.  		} else {
309.  			Strcat(buf, " labeled ");
310.  			Strcat(buf, dn);
311.  		}
312.  		break;
313.  	case WAND_SYM:
314.  		if(!obj->dknown)
315.  			Sprintf(buf, "wand");
316.  		else if(nn)
317.  			Sprintf(buf, "wand of %s", an);
318.  		else if(un)
319.  			Sprintf(buf, "wand called %s", un);
320.  		else
321.  			Sprintf(buf, "%s wand", dn);
322.  		break;
323.  #ifdef SPELLS
324.  	case SPBOOK_SYM:
325.  		if(!obj->dknown)
326.  			Sprintf(buf, "spellbook");
327.  		else if(nn)
328.  			Sprintf(buf, "spellbook of %s", an);
329.  		else if(un)
330.  			Sprintf(buf, "spellbook called %s", un);
331.  		else
332.  			Sprintf(buf, "%s spellbook", dn);
333.  		break;
334.  #endif
335.  	case RING_SYM:
336.  		if(!obj->dknown)
337.  			Sprintf(buf, "ring");
338.  		else if(nn)
339.  			Sprintf(buf, "ring of %s", an);
340.  		else if(un)
341.  			Sprintf(buf, "ring called %s", un);
342.  		else
343.  			Sprintf(buf, "%s ring", dn);
344.  		break;
345.  	case GEM_SYM:
346.  		if(!obj->dknown) {
347.  			if (obj->otyp == ROCK || obj->otyp == LOADSTONE
348.  					|| obj->otyp == LUCKSTONE)
349.  				Strcpy(buf, "stone");
350.  			else
351.  				Strcpy(buf, "gem");
352.  			break;
353.  		}
354.  		if(!nn) {
355.  			char *rock=(obj->otyp==LOADSTONE||obj->otyp==LUCKSTONE)
356.  				? "stone" : "gem";
357.  			if(un)	Sprintf(buf,"%s called %s", rock, un);
358.  			else	Sprintf(buf, "%s %s", dn, rock);
359.  			break;
360.  		}
361.  		Strcpy(buf, an);
362.  		if(obj->otyp >= TURQUOISE && obj->otyp <= JADE)
363.  			Strcat(buf, " stone");
364.  		break;
365.  	default:
366.  		Sprintf(buf,"glorkum %c (0%o) %u %d",
367.  			obj->olet,obj->olet,obj->otyp,obj->spe);
368.  	}
369.  	if(obj->quan != 1) Strcpy(buf, makeplural(buf));
370.  
371.  	if(obj->onamelth) {
372.  		Strcat(buf, " named ");
373.  		Strcat(buf, ONAME(obj));
374.  	}
375.  	return(buf);
376.  }
377.  
378.  char *
379.  doname(obj)
380.  register struct obj *obj;
381.  {
382.  	boolean ispoisoned = FALSE;
383.  	char prefix[PREFIX];
384.  	char tmpbuf[PREFIX+1];
385.  	/* when we have to add something at the start of prefix instead of the
386.  	 * end (Strcat is used on the end)
387.  	 */
388.  	register char *bp = xname(obj);
389.  	/* When using xname, we want "poisoned arrow", and when using
390.  	 * doname, we want "poisoned +0 arrow".  This kludge is about the only
391.  	 * way to do it, at least until someone overhauls xname() and doname(),
392.  	 * combining both into one function taking a parameter.
393.  	 */
394.  	if (!strncmp(bp, "poisoned ", 9)) {
395.  		bp += 9;
396.  		ispoisoned = TRUE;
397.  	}
398.  
399.  	if(obj->quan != 1)
400.  		Sprintf(prefix, "%u ", obj->quan);
401.  	else
402.  		Strcpy(prefix, "a ");
403.  	if((obj->bknown || pl_character[0] == 'P') &&
404.  	    (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
405.  		|| (!obj->cursed && !obj->blessed))) {
406.  	    /* allow 'blessed clear potion' if we don't know it's holy water;
407.  	     * always allow "uncursed potion of water"
408.  	     */
409.  	    if(obj->cursed)
410.  		Strcat(prefix, "cursed ");
411.  	    else if(obj->blessed)
412.  		Strcat(prefix, "blessed ");
413.  	    else if (((obj->olet != ARMOR_SYM
414.  			&& obj->olet != WAND_SYM
415.  			&& obj->olet != WEAPON_SYM
416.  			&& ((obj->olet != TOOL_SYM &&
417.  			     obj->olet != RING_SYM) ||
418.  			     !objects[obj->otyp].oc_charged))
419.  			    || !obj->known)
420.  		/* For items with charges or +/-, knowing the +/- means that
421.  		 * the item has been totally identified, and therefore there
422.  		 * is no doubt as to the object being uncursed if it's
423.  		 * not described as "blessed" or "cursed".
424.  		 *
425.  		 * If the +/- isn't known, "uncursed" must be printed to
426.  		 * avoid ambiguity between an item whose curse status is
427.  		 * unknown, and an item known to be uncursed.
428.  		 */
429.  #ifdef MAIL
430.  			&& obj->otyp != SCR_MAIL
431.  #endif
432.  			&& obj->otyp != AMULET_OF_YENDOR &&
433.  			pl_character[0] != 'P')
434.  		Strcat(prefix, "uncursed ");
435.  	}
436.  	switch(obj->olet) {
437.  	case AMULET_SYM:
438.  		if(obj->otyp == AMULET_OF_YENDOR)
439.  		    if(strncmp(bp, "cheap ", 6)) {
440.  			Strcpy(tmpbuf, "the ");
441.  			Strcat(tmpbuf, prefix+2); /* skip the "a " */
442.  			Strcpy(prefix, tmpbuf);
443.  		    }
444.  		if(obj->owornmask & W_AMUL)
445.  			Strcat(bp, " (being worn)");
446.  		break;
447.  	case WEAPON_SYM:
448.  		if(ispoisoned)
449.  			Strcat(prefix, "poisoned ");
450.  plus:
451.  		if(obj->known) {
452.  			Strcat(prefix, sitoa(obj->spe));
453.  			Strcat(prefix, " ");
454.  		}
455.  		break;
456.  	case ARMOR_SYM:
457.  		if(obj->owornmask & W_ARMOR)
458.  			Strcat(bp, " (being worn)");
459.  		goto plus;
460.  	case TOOL_SYM:			/* temp. hack by GAN 11/18/86 */
461.  		if(obj->owornmask & W_TOOL) { /* blindfold */
462.  			Strcat(bp, " (being worn)");
463.  			break;
464.  		}
465.  #ifdef WALKIES
466.  		if(obj->otyp == LEASH && obj->leashmon != 0) {
467.  			Strcat(bp, " (in use)");
468.  			break;
469.  		}
470.  #endif
471.  		if(obj->otyp == KEY ||
472.  		   (obj->otyp == SKELETON_KEY &&
473.  		    !objects[obj->otyp].oc_name_known)) {
474.  			Strcat(prefix, keystr[obj->spe]);
475.  			Strcat(prefix, " ");
476.  			break;
477.  		}
478.  		if(obj->otyp == LARGE_BOX || obj->otyp == CHEST) {
479.  			Sprintf(eos(bp), " (%s keyhole)", lockstr[obj->spe]);
480.  			break;
481.  		}
482.  		if(obj->otyp == PICK_AXE) goto plus;
483.  		if(!objects[obj->otyp].oc_charged) break;
484.  		/* if special tool, fall through to show charges */
485.  	case WAND_SYM:
486.  		if(obj->known)
487.  			Sprintf(eos(bp), " (%d)", obj->spe);
488.  		break;
489.  	case RING_SYM:
490.  		if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
491.  		if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
492.  		if(obj->owornmask & W_RING) {
493.  		    Strcat(bp, body_part(HAND));
494.  		    Strcat(bp, ")");
495.  		}
496.  		if(obj->known && objects[obj->otyp].oc_charged) {
497.  			Strcat(prefix, sitoa(obj->spe));
498.  			Strcat(prefix, " ");
499.  		}
500.  		break;
501.  	case FOOD_SYM:
502.  		if(obj->otyp == CORPSE) {
503.  		    Strcat(prefix, mons[obj->corpsenm].mname);
504.  		    Strcat(prefix, " ");
505.  		} else if(obj->otyp == EGG && obj->known) {
506.  		    if(obj->corpsenm >= 0) {
507.  			Strcat(prefix, mons[obj->corpsenm].mname);
508.  			Strcat(prefix, " ");
509.  #ifdef POLYSELF
510.  			if (obj->spe)
511.  			    Strcat(bp, " (laid by you)");
512.  #endif
513.  		    }
514.  		}
515.  		break;
516.  	case BALL_SYM:
517.  		if(obj->owornmask & W_BALL)
518.  			Strcat(bp, " (chained to you)");
519.  			break;
520.  	}
521.  
522.  	if(obj->owornmask & W_WEP) {
523.  		Strcat(bp, " (weapon in ");
524.  		Strcat(bp, body_part(HAND));
525.  		Strcat(bp, ")");
526.  	}
527.  	if(obj->unpaid)
528.  		Strcat(bp, " (unpaid)");
529.  	if (!strncmp(prefix, "a ", 2) &&
530.  			index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
531.  			&& (*(prefix+2) || strncmp(bp, "uranium", 7))) {
532.  		Strcpy(tmpbuf, prefix);
533.  		Strcpy(prefix, "an ");
534.  		Strcpy(prefix+3, tmpbuf+2);
535.  	}
536.  	bp = strprepend(bp, prefix);
537.  	return(bp);
538.  }
539.  
540.  /* used only in fight.c (thitu) */
541.  void
542.  setan(str,buf)
543.  register char *str,*buf;
544.  {
545.  	if(index(vowels,*str))
546.  		Sprintf(buf, "an %s", str);
547.  	else
548.  		Sprintf(buf, "a %s", str);
549.  }
550.  
551.  char *
552.  aobjnam(otmp,verb) register struct obj *otmp; register char *verb; {
553.  register char *bp = xname(otmp);
554.  char prefix[PREFIX];
555.  	if(otmp->quan != 1) {
556.  		Sprintf(prefix, "%u ", otmp->quan);
557.  		bp = strprepend(bp, prefix);
558.  	}
559.  
560.  	if(verb) {
561.  		/* verb is given in plural (i.e., without trailing s) */
562.  		Strcat(bp, " ");
563.  		if(otmp->quan != 1)
564.  			Strcat(bp, verb);
565.  		else if(!strcmp(verb, "are"))
566.  			Strcat(bp, "is");
567.  		else {
568.  			Strcat(bp, verb);
569.  			Strcat(bp, "s");
570.  		}
571.  	}
572.  	return(bp);
573.  }
574.  
575.  char *
576.  Doname2(obj)
577.  register struct obj *obj;
578.  {
579.  	register char *s = doname(obj);
580.  
581.  	if('a' <= *s && *s <= 'z') *s -= ('a' - 'A');
582.  	return(s);
583.  }
584.  
585.  const char *wrp[] = { "wand", "ring", "potion", "scroll", "gem", "amulet",
586.  #ifdef SPELLS
587.  		"spellbook",
588.  #endif
589.  		/* for non-specific wishes */
590.  		"weapon", "armor", "tool", "food", "comestible",
591.  	      };
592.  const char wrpsym[] = {WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM, AMULET_SYM,
593.  #ifdef SPELLS
594.  		 SPBOOK_SYM,
595.  #endif
596.  		 WEAPON_SYM, ARMOR_SYM, TOOL_SYM, FOOD_SYM, FOOD_SYM
597.  		};
598.  
599.  void
600.  lcase(str)
601.  register char *str;
602.  {
603.  	register char *p;
604.  	for (p = str; *p; p++)
605.  		if('A' <= *p && *p <= 'Z') *p += 'a'-'A';
606.  }
607.  
608.  /* Plural routine; chiefly used for user-defined fruits.  We have to try to
609.   * account for everything reasonable the player has; something unreasonable
610.   * can still break the code.  However, it's still a lot more accurate than
611.   * "just add an s at the end", which Rogue uses...
612.   *
613.   * Also used for plural monster names ("Wiped out all homunculi.")
614.   * and body parts.
615.   */
616.  char *
617.  makeplural(oldstr)
618.  char *oldstr;
619.  {
620.  	register char *spot;
621.  	static char str[BUFSZ];
622.  	static char *excess;
623.  	int len;
624.  
625.  	while (*oldstr==' ') oldstr++;
626.  	if (!oldstr || !*oldstr) {
627.  		impossible("plural of null?");
628.  		return("s");
629.  	}
630.  	Strcpy(str, oldstr);
631.  
632.  	/* Search for common compounds, i.e. lump of royal jelly */
633.  	for(excess=0, spot=str; *spot; spot++) {
634.  		if (!strncmp(spot, " of ", 4) || !strncmp(spot, " with ", 6)
635.  				|| !strncmp(spot, " a la ", 6)
636.  				|| !strncmp(spot, " from ", 6)
637.  				|| !strncmp(spot, " in ", 4)
638.  				|| !strncmp(spot, " labeled ", 9)
639.  				|| !strncmp(spot, " called ", 8)
640.  				|| !strncmp(spot, " named ", 7)
641.  				|| !strncmp(spot, " on ", 4)
642.  				|| !strcmp(spot, " above") /* lurkers above */
643.  				|| !strncmp(spot, " versus ", 8)
644.  				|| !strncmp(spot, " de ", 4)
645.  				|| !strncmp(spot, " d'", 3)
646.  				|| !strncmp(spot, " du ", 4)) {
647.  			excess = oldstr + (spot - str);
648.  			*spot = 0;
649.  			break;
650.  		}
651.  	}
652.  	spot--;
653.  	while (*spot==' ') spot--; /* Strip blanks from end */
654.  	*(spot+1) = 0;
655.  	/* Now spot is the last character of the string */
656.  
657.  	/* Single letters */
658.  	len = strlen(str);
659.  	if (len==1) {
660.  		Strcpy(spot+1, "'s");
661.  		goto bottom;
662.  	}
663.  
664.  	/* man/men ("Wiped out all cavemen.") */
665.  	if (len >= 3 && !strcmp(spot-2, "man") &&
666.  			(len<6 || strcmp(spot-5, "shaman")) &&
667.  			(len<5 || strcmp(spot-4, "human"))) {
668.  		*(spot-1) = 'e';
669.  		goto bottom;
670.  	}
671.  
672.  	/* mouse/mice,louse/lice (not a monster, but possible in a food name) */
673.  	if (len >= 5 && !strcmp(spot-3, "ouse") && index("MmLl", *(spot-4))) {
674.  		Strcpy(spot-3, "ice");
675.  		goto bottom;
676.  	}
677.  
678.  	/* matzoh/matzot, possible food name */
679.  	if (len >= 6 && !strcmp(spot-5, "matzoh")) {
680.  		*(spot) = 't';
681.  		goto bottom;
682.  	}
683.  
684.  	/* child/children (for the wise guys who give their food funny names) */
685.  	if (len >= 5 && !strcmp(spot-4, "child")) {
686.  		Strcpy(spot, "dren");
687.  		goto bottom;
688.  	}
689.  
690.  	/* tooth/teeth */
691.  	if (len >= 5 && !strcmp(spot-4, "tooth")) {
692.  		Strcpy(spot-3, "eeth");
693.  		goto bottom;
694.  	}
695.  
696.  	/* knife/knives, etc... */
697.  	if (!strcmp(spot-1, "fe"))
698.  		*(spot-1) = 'v';
699.  	else if (*spot == 'f')
700.  		if (index("lr", *(spot-1)) || index(vowels, *(spot-1)))
701.  			*spot = 'v';
702.  		else if (!strncmp(spot-4, "staf", 4))
703.  			Strcpy(spot-1, "ve");
704.  
705.  	/* foot/feet (body part) */
706.  	if (len >= 4 && !strcmp(spot-3, "foot")) {
707.  		Strcpy(spot-2, "eet");
708.  		goto bottom;
709.  	}
710.  
711.  	/* ium/ia (mycelia, baluchitheria) */
712.  	if (len >= 3 && !strcmp(spot-2, "ium")) {
713.  		*(spot--) = (char)0;
714.  		*spot = 'a';
715.  		goto bottom;
716.  	}
717.  
718.  	/* algae, larvae, hyphae (another fungus part) */
719.  	if ((len >= 4 && !strcmp(spot-3, "alga")) ||
720.  	    (len >= 5 &&
721.  	     (!strcmp(spot-4, "hypha") || !strcmp(spot-4, "larva")))) {
722.  		Strcpy(spot, "ae");
723.  		goto bottom;
724.  	}
725.  
726.  	/* fungus/fungi, homunculus/homunculi */
727.  	if (!strcmp(spot-1, "us")) {
728.  		*(spot--) = (char)0;
729.  		*spot = 'i';
730.  		goto bottom;
731.  	}
732.  
733.  	/* vortex/vortices */
734.  	if (len >= 6 && !strcmp(spot-3, "rtex")) {
735.  		Strcpy(spot-1, "ices");
736.  		goto bottom;
737.  	}
738.  
739.  	/* djinni/djinn (note: also efreeti/efreet) */
740.  	if (len >= 6 && !strcmp(spot-5, "djinni")) {
741.  		*(spot--) = (char)0;
742.  		goto bottom;
743.  	}
744.  
745.  	/* same singular and plural */
746.  	/* note: also swine, trout, grouse */
747.  	if ((len >= 7 && !strcmp(spot-6, "samurai")) ||
748.  	    (len >= 5 &&
749.  	     (!strcmp(spot-4, "manes") || !strcmp(spot-4, "sheep"))) ||
750.  	    (len >= 4 &&
751.  	     (!strcmp(spot-3, "fish") || !strcmp(spot-3, "tuna") ||
752.  	      !strcmp(spot-3, "deer"))))
753.  		goto bottom;
754.  
755.  	/* Aren't the following two going a bit far?  --KAA */
756.  	/* eau/eaux (gateau) */
757.  	if (len >= 3 && !strcmp(spot-2, "eau")) {
758.  		Strcpy(spot, "ux");
759.  		goto bottom;
760.  	}
761.  
762.  	/* sis/ses (oasis, nemesis) */
763.  	if (len >= 3 && !strcmp(spot-2, "sis")) {
764.  		*(spot-1) = 'e';
765.  		goto bottom;
766.  	}
767.  
768.  	/* note: ox/oxen, VAX/VAXen, goose/geese */
769.  
770.  	/* Ends in z, x, s, ch, sh; add an "es" */
771.  	if (index("zxsv", *spot) || (*spot=='h' && index("cs", *(spot-1))) ||
772.  	/* Kludge to get "tomatoes" and "potatoes" right */
773.  				(len >= 4 && !strcmp(spot-2, "ato"))) {
774.  		Strcpy(spot+1, "es");
775.  		goto bottom;
776.  	}
777.  
778.  	/* Ends in y preceded by consonant or "qu"; change to "ies" */
779.  	if (*spot == 'y' &&
780.  	    (!index(vowels, *(spot-1)) || !strncmp("qu", spot-2, 2))) {
781.  		Strcpy(spot, "ies");
782.  		goto bottom;
783.  	}
784.  
785.  	/* Default: append an 's' */
786.  	Strcpy(spot+1, "s");
787.  
788.  bottom:	if (excess) Strcpy(str+strlen(str), excess);
789.  	return str;
790.  }
791.  
792.  static const char *armor_classes[] = {
793.  	/* "shield called reflection" gives a specific type of shield.
794.  	 * "shield" gives a random type of shield--but not of all armor.
795.  	 */
796.  	"gloves", "boots", "cloak", "shield", "helmet"
797.  };
798.  #define ARMOR_CLASSES 5
799.  
800.  /* Return something wished for.  If not an object, return &zeroobj; if an error
801.   * (no matching object), return (struct obj *)0.  Giving readobjnam() a null
802.   * pointer skips the error return and creates a random object instead.
803.   */
804.  struct obj *
805.  readobjnam(bp)
806.  register char *bp;
807.  {
808.  	register char *p;
809.  	register int i;
810.  	register struct obj *otmp;
811.  	struct fruit *f;
812.  	int cnt, spe, spesgn, typ, heavy, blessed, uncursed;
813.  	int iscursed, ispoisoned, mntmp, contents, iskey=0;
814.  	int  isnamedbox=0, ftype = current_fruit;
815.  	char let;
816.  	char *un, *dn, *an;
817.  	char *name=0;
818.  	char fruitbuf[BUFSZ];
819.  	/* We want to check for fruits last so that, for example, someone
820.  	 * who names their fruit "katana" and wishes for a katana gets a real
821.  	 * one.  But, we have to keep around the old buf since in the meantime
822.  	 * we have deleted "empty", "+6", etc...
823.  	 */
824.  #ifdef WIZARD
825.  	int fake=0;
826.  #endif
827.  
828.  	cnt = spe = spesgn = typ = heavy = 
829.  		blessed = uncursed = iscursed = ispoisoned = 0;
830.  	mntmp = -1;
831.  #define UNDEFINED 0
832.  #define EMPTY 1
833.  #define SPINACH 2
834.  	contents = UNDEFINED;
835.  	let = 0;
836.  	an = dn = un = 0;
837.  	
838.  	for(;;) {
839.  		if (!bp) goto any;
840.  		if(!strncmp(bp, "an ", 3)) {
841.  			cnt = 1;
842.  			bp += 3;
843.  		} else if(!strncmp(bp, "a ", 2)) {
844.  			cnt = 1;
845.  			bp += 2;
846.  		} else if(!strncmp(bp, "cheap plastic imitation of ", 27)) {
847.  #ifdef WIZARD
848.  			fake = 1;
849.  #endif
850.  			bp += 27;
851.  		} else if(!strncmp(bp, "the ", 4)){
852.  	/*		the = 1; */
853.  			bp += 4;
854.  		} else if(!cnt && digit(*bp)){
855.  			cnt = atoi(bp);
856.  			while(digit(*bp)) bp++;
857.  			while(*bp == ' ') bp++;
858.  		} else if(!strncmp(bp,"blessed ",8) || !strncmp(bp,"holy ",5)) {
859.  			blessed=1;
860.  			bp += 8;
861.  		} else if(!strncmp(bp,"cursed ",7) || !strncmp(bp,"unholy ",7)){
862.  			iscursed=1;
863.  			bp += 7;
864.  		} else if(!strncmp(bp, "uncursed ",9)) {
865.  			uncursed=1;
866.  			bp += 9;
867.  		} else break;
868.  	}
869.  	if(!cnt) cnt = 1;		/* %% what with "gems" etc. ? */
870.  	Strcpy(fruitbuf, bp);
871.  	if(!strncmp(bp, "empty ", 6)) {
872.  		contents = EMPTY;
873.  		bp += 6;
874.  	} else if(!strncmp(bp, "poisoned ",9)) {
875.  		ispoisoned=1;
876.  		bp += 9;
877.  #ifdef WIZARD
878.  	} else if(wizard && !strncmp(bp, "trapped ",8)) {
879.  		ispoisoned=1;
880.  		bp += 8;
881.  #endif
882.  	}
883.  	if(*bp == '+' || *bp == '-'){
884.  		spesgn = (*bp++ == '+') ? 1 : -1;
885.  		spe = atoi(bp);
886.  		while(digit(*bp)) bp++;
887.  		while(*bp == ' ') bp++;
888.  	} else {
889.  		p = rindex(bp, '(');
890.  		if(p) {
891.  			if(p > bp && p[-1] == ' ') p[-1] = 0;
892.  			else *p = 0;
893.  			p++;
894.  			if (!(isnamedbox = named_box(p))) {
895.  				spe = atoi(p);
896.  				while(digit(*p)) p++;
897.  				if (*p != ')') spe = 0;
898.  				else {
899.  				    spesgn = 1;
900.  				    p++; 
901.  				    if (*p) Strcat(bp, p);
902.  				}
903.  			}
904.  		}
905.  	}
906.  	/* now we have the actual name, as delivered by xname, say
907.  		green potions called whisky
908.  		scrolls labeled "QWERTY"
909.  		egg
910.  		fortune cookies
911.  		very heavy iron ball named hoei
912.  		wand of wishing
913.  		elven cloak
914.  	*/
915.  	for(p = bp; *p; p++) if(!strncmp(p, " named ", 7)) {
916.  		*p = 0;
917.  		name = p+7;
918.  	}
919.  	for(p = bp; *p; p++) if(!strncmp(p, " called ", 8)) {
920.  		*p = 0;
921.  		un = p+8;
922.  		/* "helmet called telepathy" is not "helmet" (a specific type)
923.  		 * "shield called reflection" is not "shield" (a general type)
924.  		 */
925.  		for(i=0; i<ARMOR_CLASSES; i++)
926.  		    if(!strncmp(bp,armor_classes[i], strlen(armor_classes[i]))){
927.  			let = ARMOR_SYM;
928.  			goto srch;
929.  		    }
930.  	}
931.  	for(p = bp; *p; p++) if(!strncmp(p, " labeled ", 9)) {
932.  		*p = 0;
933.  		dn = p+9;
934.  	}
935.  	for(p = bp; *p; p++) if(!strncmp(p, " labelled ", 10)) {
936.  		*p = 0;
937.  		dn = p+10;
938.  	}
939.  	for(p = bp; *p; p++) if(!strncmp(p, " of spinach", 11)) {
940.  		*p = 0;
941.  		contents = SPINACH;
942.  	}
943.  
944.  	/* Skip over "pair of ", then jump to the singular so we don't
945.  	   try to convert "gloves" or "boots". */
946.  	if(cnt == 1 && !strncmp(bp, "pair of ",8)) {
947.  		bp += 8;
948.  		cnt = 2;
949.  		/* cnt is ignored for armor and other non-stackable objects;
950.  		   DTRT for stackable objects */
951.  	} else if(cnt > 1 && !strncmp(bp, "pairs of ",9)) {
952.  		bp += 9;
953.  		cnt *= 2;
954.  	}
955.  
956.  	/* Find corpse type using "of" (figurine of an orc, tin of orc meat) */
957.  	for(p = bp; *p; p++)
958.  		if (!strncmp(p, " of ", 4) && (mntmp = name_to_mon(p+4)) >= 0) {
959.  			*p = 0;
960.  			break;
961.  	}
962.  	/* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
963.  	if (strncmp(bp, "samurai sword", 13)) /* not the "samurai" monster! */
964.  	if (strncmp(bp, "orcish", 6)) /* not the "orc" monster! */
965.  	if (mntmp < 0) if ((mntmp = name_to_mon(bp)) >= 0) {
966.  		bp += strlen(mons[mntmp].mname);
967.  		if (*bp==' ') bp++;
968.  	}
969.  
970.  	/* first change to singular if necessary */
971.  	if(cnt != 1) {
972.  		/* find "cloves of garlic", "worthless pieces of blue glass" */
973.  		for(p = bp; *p; p++) 
974.  		    if(!strncmp(p, "s of ", 5)){
975.  			/* but don't singularize "gauntlets" */
976.  			if(strncmp(p-8, "gauntlet", 8))
977.  				while(*p = p[1]) p++;
978.  			goto sing;
979.  		    }
980.  		/* remove -s or -es (boxes) or -ies (rubies) */
981.  		p = eos(bp);
982.  		if(p[-1] == 's') {
983.  			if(p[-2] == 'e') {
984.  				if(p[-3] == 'i') {
985.  
986.  					if(!strcmp(p-7, "cookies") ||
987.  					   !strcmp(p-4, "pies"))
988.  						goto mins;
989.  					Strcpy(p-3, "y");
990.  					goto sing;
991.  				}
992.  
993.  				/* note: cloves / knives from clove / knife */
994.  				if(!strcmp(p-6, "knives")) {
995.  					Strcpy(p-3, "fe");
996.  					goto sing;
997.  				}
998.  
999.  				/* note: nurses, axes but boxes */
1000. 				if(!strcmp(p-5, "boxes")) {
1001. 					p[-2] = 0;
1002. 					goto sing;
1003. 				}
1004. 			}
1005. 			/* but don't singularize boots or gloves */
1006. 			else if(!strcmp(p-5, "boots") ||
1007. 				!strcmp(p-6, "gloves"))
1008. 					goto sing;
1009. 		mins:
1010. 			p[-1] = 0;
1011. 		} else {
1012. 			if(!strcmp(p-5, "teeth")) {
1013. 				Strcpy(p-5, "tooth");
1014. 				goto sing;
1015. 			}
1016. 			/* here we cannot find the plural suffix */
1017. 		}
1018. 	}
1019. sing:
1020. 	/* Maybe we need a special strcmp() which ignores capitalization and
1021. 	 * dashes/spaces/underscores, so the below 3 special cases would be
1022. 	 * unnecessary.
1023. 	 */
1024. 	/* Alternate spellings (two-handed sword vs. two handed sword) */
1025. 	if(!strcmp(bp, "two handed sword")) {
1026. 		typ = TWO_HANDED_SWORD;
1027. 		goto typfnd;
1028. 	}
1029. 	/* pick-axe vs. pick axe */
1030. 	if(!strcmp(bp, "pick axe")) {
1031. 		typ = PICK_AXE;
1032. 		goto typfnd;
1033. 	}
1034. 	if(!strcmp(bp, "luck stone")){
1035. 		typ = LUCKSTONE;
1036. 		goto typfnd;
1037. 	}
1038. 	if(!strcmp(bp, "load stone")){
1039. 		typ = LOADSTONE;
1040. 		goto typfnd;
1041. 	}
1042. 	/* Alternate capitalizations (Amulet of Yendor, amulet of esp) */
1043. 	if(!strcmp(bp, "amulet of Yendor")) {
1044. 		typ = AMULET_OF_YENDOR;
1045. 		goto typfnd;
1046. 	}
1047. 	if(!strcmp(bp, "amulet of ESP")) {
1048. 		typ = AMULET_OF_ESP;
1049. 		goto typfnd;
1050. 	}
1051. 	if(!strcmp(bp, "ring mail") ||	/* Note: ring mail is not a ring ! */
1052. 	   !strcmp(bp, "leather armor") || /* Prevent falling to 'armor'. */
1053. 	   !strcmp(bp, "studded leather armor")) {
1054. 		let = ARMOR_SYM;
1055. 		an = bp;
1056. 		goto srch;
1057. 	}
1058. 	if(!strcmp(bp, "food ration")){
1059. 		let = FOOD_SYM;
1060. 		an = bp;
1061. 		goto srch;
1062. 	}
1063. 	if((iskey = named_key(bp)) > 0) {
1064. 		typ = KEY;
1065. 		goto typfnd;
1066. 	}
1067. 	p = eos(bp);
1068. 	if(!strcmp(p-10, "holy water")) {
1069. 		typ = POT_WATER;
1070. 		if (*(p-12) == 'u') iscursed = 1; /* unholy water */
1071. 		else blessed = 1;
1072. 		goto typfnd;
1073. 	}
1074. #ifdef SHIRT
1075. 	if (!strcmp(p-5, "shirt")) {
1076. 		typ = HAWAIIAN_SHIRT;
1077. 		goto typfnd;
1078. 	}
1079. #endif
1080. 	if (strlen(bp) == 1 && index(obj_symbols, *bp)) {
1081. 		let = *bp;
1082. 		goto any;
1083. 	}
1084. 	if(strncmp(bp, "enchant ", 8) &&
1085. 	   strncmp(bp, "destroy ", 8) &&
1086. 	   strncmp(bp, "food detection", 14))
1087. 	/* allow wishes for "enchant weapon" and "food detection" */
1088. 	for(i = 0; i < sizeof(wrpsym); i++) {
1089. 		register int j = strlen(wrp[i]);
1090. 		if(!strncmp(bp, wrp[i], j)){
1091. 			let = wrpsym[i];
1092. 			if(let != AMULET_SYM) {
1093. 			    bp += j;
1094. 			    if(!strncmp(bp, " of ", 4)) an = bp+4;
1095. 			    /* else if(*bp) ?? */
1096. 			} else
1097. 			    an = bp;
1098. 			goto srch;
1099. 		}
1100. 		if(!strcmp(p-j, wrp[i])){
1101. 			let = wrpsym[i];
1102. 			p -= j;
1103. 			*p = 0;
1104. 			if(p[-1] == ' ') p[-1] = 0;
1105. 			dn = bp;
1106. 			goto srch;
1107. 		}
1108. 	}
1109. 	if(!strcmp(p-6, " stone")){
1110. 		p[-6] = 0;
1111. 		let = GEM_SYM;
1112. 		dn = an = bp;
1113. 		goto srch;
1114. 	}
1115. 	if(!strcmp(p-10, "gold piece") || !strcmp(p-7, "zorkmid") ||
1116. 		   !strcmp(bp, "Zorkmid") ||
1117. 		   !strcmp(bp, "gold") || !strcmp(bp, "money") || *bp == GOLD_SYM) {
1118. 			if (cnt > 5000
1119. #ifdef WIZARD
1120. 					&& !wizard
1121. #endif
1122. 						) cnt=5000;
1123. 		if (cnt < 1) cnt=1;
1124. 		pline("%d gold piece%s.", cnt, cnt==1 ? "" : "s");
1125. 		u.ugold += cnt;
1126. 		flags.botl=1;
1127. 		return (&zeroobj);
1128. 	}
1129. #ifdef WIZARD
1130. 	/* Let wizards wish for traps --KAA */
1131. 	if (wizard) {
1132. 		int trap;
1133. 		char *tname;
1134. 
1135. 		for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) {
1136. 			tname = index(traps[trap], ' ');
1137. 			if (tname) {
1138. 				if (!strncmp(tname+1, bp, strlen(tname+1))) {
1139. 					(void) maketrap(u.ux, u.uy, trap);
1140. 					pline("A%s.", traps[trap]);
1141. 					if (Invisible) newsym(u.ux,u.uy);
1142. 					return(&zeroobj);
1143. 				}
1144. 			}
1145. 		}
1146. 	}
1147. #endif
1148. 	if(!strcmp(bp, "very heavy iron ball")) {
1149. 		heavy = 1;
1150. 		typ = HEAVY_IRON_BALL;
1151. 		goto typfnd;
1152. 	}
1153. 	if(!strcmp(bp, "bag")) {
1154. 		typ = rnd_class(SACK, BAG_OF_TRICKS);
1155. 		goto typfnd;
1156. 	}
1157. 	if(!strcmp(bp, armor_classes[0])){ /* pair of gloves */
1158. 		typ = rnd_class(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY);
1159. 		goto typfnd;
1160. 	}
1161. 	if(!strcmp(bp, armor_classes[1])){ /* pair of boots */
1162. 		typ = rnd_class(LOW_BOOTS, LEVITATION_BOOTS);
1163. 		goto typfnd;
1164. 	}
1165. 	if(!strcmp(bp, armor_classes[2])){ /* cloak */
1166. 		typ = rnd_class(MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT);
1167. 		goto typfnd;
1168. 	}
1169. 	if(!strcmp(bp, armor_classes[3])){ /* shield */
1170. 		typ = rnd_class(SMALL_SHIELD, SHIELD_OF_REFLECTION);
1171. 		goto typfnd;
1172. 	}
1173. 	/* helmet is not generic */
1174. 
1175. 	an = bp;
1176. 	if (!dn) dn = an; /* i.e., "black cap" */
1177. srch:
1178. 	i = 1;
1179. 	if(let) i = bases[letindex(let)];
1180. 	while(i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)){
1181. 		register char *zn;
1182. 
1183. 		if(an && (zn = objects[i].oc_name) && !strcmp(an, zn)) {
1184. 			typ = i;
1185. 			goto typfnd;
1186. 		}
1187. 		if(dn && (zn = objects[i].oc_descr) && !strcmp(dn, zn)) {
1188. 			typ = i;
1189. 			goto typfnd;
1190. 		}
1191. 		if(un && (zn = objects[i].oc_uname) && !strcmp(un, zn)) {
1192. 			typ = i;
1193. 			goto typfnd;
1194. 		}
1195. 		i++;
1196. 	}
1197. 	for(f=ffruit; f; f = f->nextf) {
1198. 		char *f1 = f->fname, *f2 = makeplural(f->fname);
1199. 
1200. 		if(!strncmp(fruitbuf, f1, strlen(f1)) ||
1201. 					!strncmp(fruitbuf, f2, strlen(f2))) {
1202. 			typ = SLIME_MOLD;
1203. 			ftype = f->fid;
1204. 			goto typfnd;
1205. 		}
1206. 	}
1207. 	if(!let) return((struct obj *)0);
1208. any:
1209. 	if(!let) let = wrpsym[rn2(sizeof(wrpsym))];
1210. typfnd:
1211. 	if(typ) {
1212. 		let = objects[typ].oc_olet;
1213. 		otmp = mksobj(typ,FALSE);
1214. 	} else {
1215. 		otmp = mkobj(let,FALSE);
1216. 		typ = otmp->otyp;
1217. 	}
1218. 
1219. 	/* venom isn't really an object and can't be wished for; but allow
1220. 	 * wizards to wish for it since it's faster than polymorphing and
1221. 	 * spitting.
1222. 	 */
1223. 	if(otmp->olet==VENOM_SYM
1224. #ifdef WIZARD
1225. 				&& !wizard
1226. #endif
1227. 						) {
1228. 		free((genericptr_t) otmp);
1229. 		return((struct obj *)0);
1230. 	}
1231. 	if(iskey) otmp->spe = (iskey-1);
1232. 	if(isnamedbox && (otmp->otyp==LARGE_BOX || otmp->otyp==CHEST))
1233. 		otmp->spe = (isnamedbox-1);
1234. 
1235. 	if(cnt > 0 && objects[typ].oc_merge && 
1236. #ifdef SPELLS
1237. 	        let != SPBOOK_SYM &&
1238. #endif
1239. 		(cnt < rnd(6) ||
1240. #ifdef WIZARD
1241. 		wizard ||
1242. #endif
1243. 		 (cnt <= 20 &&
1244. 		  (let == WEAPON_SYM && typ <= SHURIKEN) || (typ == ROCK))))
1245. 			otmp->quan = cnt;
1246. 
1247. 	if (spesgn == 0) spe = otmp->spe;
1248. #ifdef WIZARD
1249. 	else if (wizard) /* no alteration to spe */ ;
1250. #endif
1251. 	else if (let == ARMOR_SYM || let == WEAPON_SYM || typ == PICK_AXE ||
1252. 			(let==RING_SYM && objects[typ].oc_charged)) {
1253. 		if(spe > rnd(5) && spe > otmp->spe) spe = 0;
1254. 		if(spe > 2 && u.uluck < 0) spesgn = -1;
1255. 	} else {
1256. 		if (let == WAND_SYM) {
1257. 			if (spe > 1 && spesgn == -1) spe = 1;
1258. 		} else {
1259. 			if (spe > 0 && spesgn == -1) spe = 0;
1260. 		}
1261. 		if (spe > otmp->spe) spe = otmp->spe;
1262. 	}
1263. 
1264. 	if (spesgn == -1) spe = -spe;
1265. 
1266. 	/* set otmp->spe.  This may, or may not, use spe... */
1267. 	switch (typ) {
1268. 		case TIN: if (contents==EMPTY) {
1269. 				otmp->corpsenm = -1;
1270. 				otmp->spe = 0;
1271. 			} else if (contents==SPINACH) {
1272. 				otmp->corpsenm = -1;
1273. 				otmp->spe = 1;
1274. 			}
1275. 			break;
1276. 		case SLIME_MOLD: otmp->spe = ftype;
1277. 			/* Fall through */
1278. 		case SKELETON_KEY: case KEY: case CHEST: case LARGE_BOX:
1279. 		case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE:
1280. 			/* otmp->spe already done in mksobj() */
1281. 				break;
1282. #ifdef MAIL
1283. 		case SCR_MAIL: otmp->spe = 1; break;
1284. #endif
1285. 		case AMULET_OF_YENDOR:
1286. #ifdef WIZARD
1287. 			if (fake || !wizard)
1288. #endif
1289. 				otmp->spe = -1;
1290. #ifdef WIZARD
1291. 			else otmp->spe = 0;
1292. #endif
1293. 			break;
1294. 		case WAN_WISHING:
1295. #ifdef WIZARD
1296. 			if (!wizard)
1297. #endif
1298. 				otmp->spe = (rn2(10) ? -1 : 0); break;
1299. 			/* fall through, if wizard */
1300. 		default: otmp->spe = spe;
1301. 	}
1302. 
1303. 	/* set otmp->corpsenm */
1304. 	if (mntmp > -1) switch(typ) {
1305. 		case TIN:
1306. 			otmp->spe = 0; /* No spinach */
1307. 		case CORPSE:
1308. 			if (!(mons[mntmp].geno & G_NOCORPSE))
1309. 				otmp->corpsenm = mntmp;
1310. 			break;
1311. 		case FIGURINE:
1312. 			if (!is_dlord(&mons[mntmp]) && !is_dprince(&mons[mntmp])
1313. 					&& !is_human(&mons[mntmp])
1314. #ifdef WORM
1315. 					&& mntmp != PM_LONG_WORM
1316. #endif
1317. 					)
1318. 				otmp->corpsenm = mntmp;
1319. 			break;
1320. 		case EGG: if (lays_eggs(&mons[mntmp]) || mntmp==PM_KILLER_BEE)
1321. 				otmp->corpsenm = mntmp;
1322. 			break;
1323. 		case STATUE: otmp->corpsenm = mntmp;
1324. 			break;
1325. 		case DRAGON_SCALE_MAIL: /* Not actually possible unless they
1326. 				   typed "red dragon dragon scale mail" */
1327. 		case SCALE_MAIL:
1328. 			if (mntmp >= PM_GREY_DRAGON &&
1329. 			    mntmp <= PM_YELLOW_DRAGON)
1330. 				otmp->corpsenm = mntmp;
1331. 			if (otmp->corpsenm >= 0)
1332. 				otmp->otyp = DRAGON_SCALE_MAIL;
1333. 			break;
1334. 	}
1335. 
1336. 	/* set blessed/cursed */
1337. 	if (iscursed) {
1338. 		curse(otmp);
1339. 	} else if (uncursed) {
1340. 		otmp->blessed = 0;
1341. 		otmp->cursed = (u.uluck < 0);
1342. 	} else if (blessed) {
1343. 		otmp->blessed = (u.uluck >= 0);
1344. 		otmp->cursed = (u.uluck < 0);
1345. 	} else if (spesgn < 0) {
1346. 		curse(otmp);
1347. 	}
1348. 
1349. 	/* set poisoned */
1350. 	if (ispoisoned) {
1351. 	    if (let == WEAPON_SYM && typ <= SHURIKEN)
1352. 		otmp->opoisoned = (u.uluck >= 0);
1353. #ifdef WIZARD
1354. 	    else if (Is_box(otmp))
1355. 		otmp->otrapped = 1;
1356. 	    else if (let == FOOD_SYM)
1357. 		/* try to taint by making it as old as possible */
1358. 	    	otmp->age = 1L;
1359. #endif
1360. 	}
1361. 
1362. 	if (name) otmp = oname(otmp, name, 0);
1363. 	otmp->owt = weight(otmp);
1364. 	if (heavy) otmp->owt += 15;
1365. 	return(otmp);
1366. }
1367. 
1368. boolean
1369. uses_known(otmp)
1370. register struct obj *otmp;
1371. /* returns TRUE if otmp->known would be used to affect the full description
1372.  * of the item
1373.  * if not, otmp->dknown and otmp->bknown give all the information of otmp->known
1374.  * and otmp->known should always be set to avoid problems with items not
1375.  * merging due to different values of otmp->known
1376.  */
1377. {
1378. 	return (otmp->olet == ARMOR_SYM ||
1379. 		otmp->olet == WAND_SYM ||
1380. 		otmp->olet == WEAPON_SYM ||
1381. 		((otmp->olet == TOOL_SYM || otmp->olet == RING_SYM) &&
1382. 		    objects[otmp->otyp].oc_charged) ||
1383. 		otmp->otyp == FIGURINE ||
1384. 		otmp->otyp == EGG ||
1385. 		otmp->otyp == TIN ||
1386. 		otmp->otyp == AMULET_OF_YENDOR);
1387. }
1388. 
1389. static int
1390. rnd_class(first,last)
1391. int first,last;
1392. {
1393. 	int i, x, sum=0;
1394. 	for(i=first; i<=last; i++)
1395. 		sum += objects[i].oc_prob;
1396. 	x = rnd(sum);
1397. 	for(i=first; i<=last; i++)
1398. 		if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
1399. 			return i;
1400. 	return 0;
1401. }