Source:NetHack 3.2.0/objnam.c

From NetHackWiki
Revision as of 09:11, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.2.0/objnam.c moved to Source:NetHack 3.2.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.2.0. To link to a particular line, write [[NetHack 3.2.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.2	96/03/17	*/
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.    /* "an uncursed partly eaten guardian naga hatchling corpse" */
8.    #define PREFIX	50
9.    #define SCHAR_LIM 127
10.   
11.   STATIC_DCL char *FDECL(strprepend,(char *,const char *));
12.   #ifdef OVL0
13.   static boolean FDECL(the_unique_obj, (struct obj *obj));
14.   #endif
15.   
16.   struct Jitem {
17.   	int item;
18.   	const char *name;
19.   };
20.   
21.   /* true for gems/rocks that should have " stone" appended to their names */
22.   #define GemStone(typ)	(typ == FLINT ||				\
23.   			 (objects[typ].oc_material == GEMSTONE &&	\
24.   			  (typ != DILITHIUM_CRYSTAL && typ != RUBY &&	\
25.   			   typ != DIAMOND && typ != SAPPHIRE &&		\
26.   			   typ != EMERALD && typ != OPAL)))
27.   
28.   #ifndef OVLB
29.   
30.   STATIC_DCL struct Jitem Japanese_items[];
31.   
32.   #else /* OVLB */
33.   
34.   STATIC_OVL struct Jitem Japanese_items[] = {
35.   	{ SHORT_SWORD, "wakizashi" },
36.   	{ BROADSWORD, "ninja-to" },
37.   	{ FLAIL, "nunchaku" },
38.   	{ GLAIVE, "naginata" },
39.   	{ LOCK_PICK, "osaku" },
40.   	{ WOODEN_HARP, "koto" },
41.   	{ KNIFE, "shito" },
42.   	{ PLATE_MAIL, "tanko" },
43.   	{ HELMET, "kabuto" },
44.   	{ LEATHER_GLOVES, "yugake" },
45.   	{ FOOD_RATION, "gunyoki" },
46.   	{ POT_BOOZE, "sake" },
47.   	{0, "" }
48.   };
49.   
50.   #endif /* OVLB */
51.   
52.   STATIC_DCL const char *FDECL(Japanese_item_name,(int i));
53.   
54.   #ifdef OVL1
55.   
56.   STATIC_OVL char *
57.   strprepend(s,pref)
58.   register char *s;
59.   register const char *pref; {
60.   register int i = strlen(pref);
61.   	if(i > PREFIX) {
62.   		pline("WARNING: prefix too short.");
63.   		return(s);
64.   	}
65.   	s -= i;
66.   	(void) strncpy(s, pref, i);	/* do not copy trailing 0 */
67.   	return(s);
68.   }
69.   
70.   #endif /* OVL1 */
71.   #ifdef OVLB
72.   
73.   char *
74.   typename(otyp)
75.   register int otyp;
76.   {
77.   #ifdef LINT	/* static char buf[BUFSZ]; */
78.   char buf[BUFSZ];
79.   #else
80.   static char NEARDATA buf[BUFSZ];
81.   #endif
82.   register struct objclass *ocl = &objects[otyp];
83.   register const char *actualn = OBJ_NAME(*ocl);
84.   register const char *dn = OBJ_DESCR(*ocl);
85.   register const char *un = ocl->oc_uname;
86.   register int nn = ocl->oc_name_known;
87.   
88.   	if (Role_is('S') && Japanese_item_name(otyp))
89.   		actualn = Japanese_item_name(otyp);
90.   	switch(ocl->oc_class) {
91.   	case GOLD_CLASS:
92.   		Strcpy(buf, "coin");
93.   		break;
94.   	case POTION_CLASS:
95.   		Strcpy(buf, "potion");
96.   		break;
97.   	case SCROLL_CLASS:
98.   		Strcpy(buf, "scroll");
99.   		break;
100.  	case WAND_CLASS:
101.  		Strcpy(buf, "wand");
102.  		break;
103.  	case SPBOOK_CLASS:
104.  		Strcpy(buf, "spellbook");
105.  		break;
106.  	case RING_CLASS:
107.  		Strcpy(buf, "ring");
108.  		break;
109.  	case AMULET_CLASS:
110.  		if(nn)
111.  			Strcpy(buf,actualn);
112.  		else
113.  			Strcpy(buf,"amulet");
114.  		if(un)
115.  			Sprintf(eos(buf)," called %s",un);
116.  		if(dn)
117.  			Sprintf(eos(buf)," (%s)",dn);
118.  		return(buf);
119.  	default:
120.  		if(nn) {
121.  			Strcpy(buf, actualn);
122.  			if (GemStone(otyp))
123.  				Strcat(buf, " stone");
124.  			if(un)
125.  				Sprintf(eos(buf), " called %s", un);
126.  			if(dn)
127.  				Sprintf(eos(buf), " (%s)", dn);
128.  		} else {
129.  			Strcpy(buf, dn ? dn : actualn);
130.  			if(ocl->oc_class == GEM_CLASS)
131.  				Strcat(buf, (ocl->oc_material == MINERAL) ?
132.  						" stone" : " gem");
133.  			if(un)
134.  				Sprintf(eos(buf), " called %s", un);
135.  		}
136.  		return(buf);
137.  	}
138.  	/* here for ring/scroll/potion/wand */
139.  	if(nn)
140.  		Sprintf(eos(buf), " of %s", actualn);
141.  	if(un)
142.  		Sprintf(eos(buf), " called %s", un);
143.  	if(dn)
144.  		Sprintf(eos(buf), " (%s)", dn);
145.  	return(buf);
146.  }
147.  
148.  boolean
149.  obj_is_pname(obj)
150.  register struct obj *obj;
151.  {
152.      return((boolean)(obj->dknown && obj->known && obj->onamelth &&
153.  		     /* Since there aren't any objects which are both
154.  		        artifacts and unique, the last check is redundant. */
155.  		     obj->oartifact && !objects[obj->otyp].oc_unique));
156.  }
157.  
158.  /* Give the name of an object seen at a distance.  Unlike xname/doname,
159.   * we don't want to set dknown if it's not set already.  The kludge used is
160.   * to temporarily set Blind so that xname() skips the dknown setting.  This
161.   * assumes that we don't want to do this too often; if this function becomes
162.   * frequently used, it'd probably be better to pass a parameter to xname()
163.   * or doname() instead.
164.   */
165.  char *
166.  distant_name(obj, func)
167.  register struct obj *obj;
168.  char *FDECL((*func), (OBJ_P));
169.  {
170.  	char *str;
171.  
172.  	long save_Blinded = Blinded;
173.  	Blinded = 1;
174.  	str = (*func)(obj);
175.  	Blinded = save_Blinded;
176.  	return str;
177.  }
178.  
179.  #endif /* OVLB */
180.  #ifdef OVL1
181.  
182.  char *
183.  xname(obj)
184.  register struct obj *obj;
185.  {
186.  #ifdef LINT	/* lint may handle static decl poorly -- static char bufr[]; */
187.  	char bufr[BUFSZ];
188.  #else
189.  	static char bufr[BUFSZ];
190.  #endif
191.  	register char *buf = &(bufr[PREFIX]);	/* leave room for "17 -3 " */
192.  	register int typ = obj->otyp;
193.  	register struct objclass *ocl = &objects[typ];
194.  	register int nn = ocl->oc_name_known;
195.  	register const char *actualn = OBJ_NAME(*ocl);
196.  	register const char *dn = OBJ_DESCR(*ocl);
197.  	register const char *un = ocl->oc_uname;
198.  
199.  	if (Role_is('S') && Japanese_item_name(typ))
200.  		actualn = Japanese_item_name(typ);
201.  
202.  	buf[0] = '\0';
203.  	if (!Blind) obj->dknown = TRUE;
204.  	if (Role_is('P')) obj->bknown = TRUE;
205.  	if (obj_is_pname(obj))
206.  	    goto nameit;
207.  	switch (obj->oclass) {
208.  	    case AMULET_CLASS:
209.  		if (!obj->dknown)
210.  			Strcpy(buf, "amulet");
211.  		else if (typ == FAKE_AMULET_OF_YENDOR)
212.  			/* each must be identified individually */
213.  			Strcpy(buf, obj->known ? actualn : dn);
214.  		else if (nn) /* should be true for the Amulet of Yendor */
215.  			Strcpy(buf, actualn);
216.  		else if (un)
217.  			Sprintf(buf,"amulet called %s", un);
218.  		else
219.  			Sprintf(buf,"%s amulet", dn);
220.  		break;
221.  	    case WEAPON_CLASS:
222.  		if (typ <= SHURIKEN && obj->opoisoned)
223.  			Strcpy(buf, "poisoned ");
224.  	    case VENOM_CLASS:
225.  	    case TOOL_CLASS:
226.  		if (!obj->dknown)
227.  			Strcpy(buf, !dn ? actualn : dn);
228.  		else if (nn)
229.  			Strcat(buf, actualn);
230.  		else if (un)
231.  			Sprintf(buf, "%s called %s", !dn ? actualn : dn, un);
232.  		else
233.  			Strcat(buf, !dn ? actualn : dn);
234.  		/* If we use an() here we'd have to remember never to use */
235.  		/* it whenever calling doname() or xname(). */
236.  		if (typ == FIGURINE)
237.  		    Sprintf(eos(buf), " of a%s %s",
238.  			index(vowels,*(mons[obj->corpsenm].mname)) ? "n" : "",
239.  			mons[obj->corpsenm].mname);
240.  		break;
241.  	    case ARMOR_CLASS:
242.  		/* depends on order of the dragon scales objects */
243.  		if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
244.  			Sprintf(buf, "set of %s", actualn);
245.  			break;
246.  		}
247.  		if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
248.  
249.  		if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
250.  				&& !obj->dknown) {
251.  			Strcpy(buf, "shield");
252.  			break;
253.  		}
254.  		if(obj->otyp == SHIELD_OF_REFLECTION && !obj->dknown) {
255.  			Strcpy(buf, "smooth shield");
256.  			break;
257.  		}
258.  
259.  		if(nn)	Strcat(buf, actualn);
260.  		else if(un) {
261.  			if(is_boots(obj))
262.  				Strcat(buf,"boots");
263.  			else if(is_gloves(obj))
264.  				Strcat(buf,"gloves");
265.  			else if(is_cloak(obj))
266.  				Strcpy(buf,"cloak");
267.  			else if(is_helmet(obj))
268.  				Strcpy(buf,"helmet");
269.  			else if(is_shield(obj))
270.  				Strcpy(buf,"shield");
271.  			else
272.  				Strcpy(buf,"armor");
273.  			Strcat(buf, " called ");
274.  			Strcat(buf, un);
275.  		} else	Strcat(buf, dn);
276.  		break;
277.  	    case FOOD_CLASS:
278.  		if (typ == SLIME_MOLD) {
279.  			register struct fruit *f;
280.  
281.  			for(f=ffruit; f; f = f->nextf) {
282.  				if(f->fid == obj->spe) {
283.  					Strcpy(buf, f->fname);
284.  					break;
285.  				}
286.  			}
287.  			if (!f) impossible("Bad fruit #%d?", obj->spe);
288.  			break;
289.  		}
290.  
291.  		Strcpy(buf, actualn);
292.  		if (typ == TIN && obj->known) {
293.  		    if(obj->spe > 0)
294.  			Strcat(buf, " of spinach");
295.  		    else if (obj->corpsenm == NON_PM)
296.  		        Strcpy(buf, "empty tin");
297.  		    else if (is_meaty(&mons[obj->corpsenm]))
298.  			Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname);
299.  		    else
300.  			Sprintf(eos(buf), " of %s", mons[obj->corpsenm].mname);
301.  		}
302.  		break;
303.  	    case GOLD_CLASS:
304.  	    case CHAIN_CLASS:
305.  		Strcpy(buf, actualn);
306.  		break;
307.  	    case ROCK_CLASS:
308.  		if (typ == STATUE)
309.  		    Sprintf(buf, "%s of %s%s", actualn,
310.  			type_is_pname(&mons[obj->corpsenm]) ? "" :
311.  			  (mons[obj->corpsenm].geno & G_UNIQ) ? "the " :
312.  			    (index(vowels,*(mons[obj->corpsenm].mname)) ?
313.  								"an " : "a "),
314.  			mons[obj->corpsenm].mname);
315.  		else Strcpy(buf, actualn);
316.  		break;
317.  	    case BALL_CLASS:
318.  		Sprintf(buf, "%sheavy iron ball",
319.  			(obj->owt > ocl->oc_weight) ? "very " : "");
320.  		break;
321.  	    case POTION_CLASS:
322.  		if (obj->dknown && obj->odiluted)
323.  			Strcpy(buf, "diluted ");
324.  		if(nn || un || !obj->dknown) {
325.  			Strcat(buf, "potion");
326.  			if(!obj->dknown) break;
327.  			if(nn) {
328.  			    Strcat(buf, " of ");
329.  			    if (typ == POT_WATER &&
330.  				obj->bknown && (obj->blessed || obj->cursed)) {
331.  				Strcat(buf, obj->blessed ? "holy " : "unholy ");
332.  			    }
333.  			    Strcat(buf, actualn);
334.  			} else {
335.  				Strcat(buf, " called ");
336.  				Strcat(buf, un);
337.  			}
338.  		} else {
339.  			Strcat(buf, dn);
340.  			Strcat(buf, " potion");
341.  		}
342.  		break;
343.  	case SCROLL_CLASS:
344.  		Strcpy(buf, "scroll");
345.  		if(!obj->dknown) break;
346.  		if(nn) {
347.  			Strcat(buf, " of ");
348.  			Strcat(buf, actualn);
349.  		} else if(un) {
350.  			Strcat(buf, " called ");
351.  			Strcat(buf, un);
352.  		} else if (ocl->oc_magic) {
353.  			Strcat(buf, " labeled ");
354.  			Strcat(buf, dn);
355.  		} else {
356.  			Strcpy(buf, dn);
357.  			Strcat(buf, " scroll");
358.  		}
359.  		break;
360.  	case WAND_CLASS:
361.  		if(!obj->dknown)
362.  			Strcpy(buf, "wand");
363.  		else if(nn)
364.  			Sprintf(buf, "wand of %s", actualn);
365.  		else if(un)
366.  			Sprintf(buf, "wand called %s", un);
367.  		else
368.  			Sprintf(buf, "%s wand", dn);
369.  		break;
370.  	case SPBOOK_CLASS:
371.  		if (!obj->dknown) {
372.  			Strcpy(buf, "spellbook");
373.  		} else if (nn) {
374.  			if (typ != SPE_BOOK_OF_THE_DEAD)
375.  			    Strcpy(buf, "spellbook of ");
376.  			Strcat(buf, actualn);
377.  		} else if (un) {
378.  			Sprintf(buf, "spellbook called %s", un);
379.  		} else
380.  			Sprintf(buf, "%s spellbook", dn);
381.  		break;
382.  	case RING_CLASS:
383.  		if(!obj->dknown)
384.  			Strcpy(buf, "ring");
385.  		else if(nn)
386.  			Sprintf(buf, "ring of %s", actualn);
387.  		else if(un)
388.  			Sprintf(buf, "ring called %s", un);
389.  		else
390.  			Sprintf(buf, "%s ring", dn);
391.  		break;
392.  	case GEM_CLASS:
393.  	    {
394.  		const char *rock =
395.  			    (ocl->oc_material == MINERAL) ? "stone" : "gem";
396.  		if (!obj->dknown) {
397.  		    Strcpy(buf, rock);
398.  		} else if (!nn) {
399.  		    if (un) Sprintf(buf,"%s called %s", rock, un);
400.  		    else Sprintf(buf, "%s %s", dn, rock);
401.  		} else {
402.  		    Strcpy(buf, actualn);
403.  		    if (GemStone(typ)) Strcat(buf, " stone");
404.  		}
405.  		break;
406.  	    }
407.  	default:
408.  		Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe);
409.  	}
410.  	if (obj->quan != 1L) Strcpy(buf, makeplural(buf));
411.  
412.  	if (obj->onamelth && obj->dknown) {
413.  		Strcat(buf, " named ");
414.  nameit:
415.  		Strcat(buf, ONAME(obj));
416.  	}
417.  
418.  	if (!strncmpi(buf, "the ", 4)) buf += 4;
419.  	return(buf);
420.  }
421.  
422.  #endif /* OVL1 */
423.  #ifdef OVL0
424.  
425.  /* used for naming "the unique_item" instead of "a unique_item" */
426.  static boolean
427.  the_unique_obj(obj)
428.  register struct obj *obj;
429.  {
430.      if (!obj->dknown)
431.  	return FALSE;
432.      else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known)
433.  	return TRUE;		/* lie */
434.      else
435.  	return (boolean)(objects[obj->otyp].oc_unique &&
436.  			 (obj->known || obj->otyp == AMULET_OF_YENDOR));
437.  }
438.  
439.  char *
440.  doname(obj)
441.  register struct obj *obj;
442.  {
443.  	boolean ispoisoned = FALSE;
444.  	char prefix[PREFIX];
445.  	char tmpbuf[PREFIX+1];
446.  	/* when we have to add something at the start of prefix instead of the
447.  	 * end (Strcat is used on the end)
448.  	 */
449.  	register char *bp = xname(obj);
450.  
451.  	/* When using xname, we want "poisoned arrow", and when using
452.  	 * doname, we want "poisoned +0 arrow".  This kludge is about the only
453.  	 * way to do it, at least until someone overhauls xname() and doname(),
454.  	 * combining both into one function taking a parameter.
455.  	 */
456.  	if (!strncmp(bp, "poisoned ", 9)) {
457.  		bp += 9;
458.  		ispoisoned = TRUE;
459.  	}
460.  
461.  	if(obj->quan != 1L)
462.  		Sprintf(prefix, "%ld ", obj->quan);
463.  	else if (obj_is_pname(obj) || the_unique_obj(obj)) {
464.  		if (!strncmpi(bp, "the ", 4))
465.  		    bp += 4;
466.  		Strcpy(prefix, "the ");
467.  	} else
468.  		Strcpy(prefix, "a ");
469.  
470.  	if (obj->bknown &&
471.  	    obj->oclass != GOLD_CLASS &&
472.  	    (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
473.  		|| (!obj->cursed && !obj->blessed))) {
474.  	    /* allow 'blessed clear potion' if we don't know it's holy water;
475.  	     * always allow "uncursed potion of water"
476.  	     */
477.  	    if (obj->cursed)
478.  		Strcat(prefix, "cursed ");
479.  	    else if (obj->blessed)
480.  		Strcat(prefix, "blessed ");
481.  	    else if ((!obj->known || !objects[obj->otyp].oc_charged ||
482.  		      (obj->oclass == ARMOR_CLASS ||
483.  		       obj->oclass == RING_CLASS))
484.  		/* For most items with charges or +/-, if you know how many
485.  		 * charges are left or what the +/- is, then you must have
486.  		 * totally identified the item, so "uncursed" is unneccesary,
487.  		 * because an identified object not described as "blessed" or
488.  		 * "cursed" must be uncursed.
489.  		 *
490.  		 * If the charges or +/- is not known, "uncursed" must be
491.  		 * printed to avoid ambiguity between an item whose curse
492.  		 * status is unknown, and an item known to be uncursed.
493.  		 */
494.  #ifdef MAIL
495.  			&& obj->otyp != SCR_MAIL
496.  #endif
497.  			&& obj->otyp != FAKE_AMULET_OF_YENDOR
498.  			&& obj->otyp != AMULET_OF_YENDOR
499.  			&& !Role_is('P'))
500.  		Strcat(prefix, "uncursed ");
501.  	}
502.  
503.  	if (obj->greased) Strcat(prefix, "greased ");
504.  
505.  	switch(obj->oclass) {
506.  	case AMULET_CLASS:
507.  		if(obj->owornmask & W_AMUL)
508.  			Strcat(bp, " (being worn)");
509.  		break;
510.  	case WEAPON_CLASS:
511.  		if(ispoisoned)
512.  			Strcat(prefix, "poisoned ");
513.  plus:
514.  		if (obj->oeroded) {
515.  			switch (obj->oeroded) {
516.  				case 2:	Strcat(prefix, "very "); break;
517.  				case 3:	Strcat(prefix, "thoroughly "); break;
518.  			}			
519.  			Strcat(prefix,
520.  			       is_rustprone(obj) ? "rusty " :
521.  			       is_corrodeable(obj) ? "corroded " :
522.  			    /* is_flammable(obj) ? "burnt " : "eroded " */
523.  			       "damaged ");
524.  		} else if (obj->rknown && obj->oerodeproof)
525.  			Strcat(prefix,
526.  			       is_rustprone(obj) ? "rustproof " :
527.  			       is_corrodeable(obj) ? "corrodeproof " :	/* "stainless"? */
528.  			       is_flammable(obj) ? "fireproof " : "");
529.  		if(obj->known) {
530.  			Strcat(prefix, sitoa(obj->spe));
531.  			Strcat(prefix, " ");
532.  		}
533.  		break;
534.  	case ARMOR_CLASS:
535.  		if(obj->owornmask & W_ARMOR)
536.  			Strcat(bp, (obj == uskin) ? " (embedded in your skin)" :
537.  				" (being worn)");
538.  		goto plus;
539.  	case TOOL_CLASS:		/* temp. hack by GAN 11/18/86 */
540.  		if(obj->owornmask & W_TOOL) { /* blindfold */
541.  			Strcat(bp, " (being worn)");
542.  			break;
543.  		}
544.  		if(obj->otyp == LEASH && obj->leashmon != 0) {
545.  			Strcat(bp, " (in use)");
546.  			break;
547.  		}
548.  		if (is_weptool(obj))
549.  			goto plus;
550.  		if (Is_candle(obj) &&
551.  		    obj->age < 20L * (long)objects[obj->otyp].oc_cost)
552.  			Strcat(prefix, "partly used ");
553.  		if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
554.  			obj->otyp == BRASS_LANTERN ||
555.  		    Is_candle(obj) || obj->otyp == CANDELABRUM_OF_INVOCATION) {
556.  			if(obj->lamplit)
557.  				Strcat(bp, " (lit)");
558.  			break;
559.  		}
560.  		if(!objects[obj->otyp].oc_charged) break;
561.  		/* if special tool, fall through to show charges */
562.  	case WAND_CLASS:
563.  		if(obj->known)
564.  			Sprintf(eos(bp), " (%d)", obj->spe);
565.  		break;
566.  	case POTION_CLASS:
567.  		if (obj->otyp == POT_OIL && obj->lamplit)
568.  		    Strcat(bp, " (lit)");
569.  		break;
570.  	case RING_CLASS:
571.  		if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
572.  		if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
573.  		if(obj->owornmask & W_RING) {
574.  		    Strcat(bp, body_part(HAND));
575.  		    Strcat(bp, ")");
576.  		}
577.  		if(obj->known && objects[obj->otyp].oc_charged) {
578.  			Strcat(prefix, sitoa(obj->spe));
579.  			Strcat(prefix, " ");
580.  		}
581.  		break;
582.  	case FOOD_CLASS:
583.  		if (obj->oeaten)
584.  		    Strcat(prefix, "partly eaten ");
585.  		if (obj->otyp == CORPSE) {
586.  		    if (mons[obj->corpsenm].geno & G_UNIQ) {
587.  			Sprintf(prefix, "%s%s ",
588.  				(type_is_pname(&mons[obj->corpsenm]) ?
589.  					"" : "the "),
590.  				s_suffix(mons[obj->corpsenm].mname));
591.  			if (obj->oeaten) Strcat(prefix, "partly eaten ");
592.  		    } else {
593.  			Strcat(prefix, mons[obj->corpsenm].mname);
594.  			Strcat(prefix, " ");
595.  		    }
596.  		} else if (obj->otyp == EGG) {
597.  #if 0	/* corpses don't tell if they're stale either */
598.  		    if (obj->known && stale_egg(obj))
599.  			Strcat(prefix, "stale ");
600.  #endif
601.  		    if (obj->corpsenm >= LOW_PM &&
602.  			    (obj->known ||
603.  			    mvitals[obj->corpsenm].mvflags & MV_KNOWS_EGG)) {
604.  			Strcat(prefix, mons[obj->corpsenm].mname);
605.  			Strcat(prefix, " ");
606.  			if (obj->spe)
607.  			    Strcat(bp, " (laid by you)");
608.  		    }
609.  		}
610.  		break;
611.  	case BALL_CLASS:
612.  	case CHAIN_CLASS:
613.  		if (obj->oeroded) {
614.  		    switch(obj->oeroded) {
615.  			case 2: Strcat(prefix, "very "); break;
616.  			case 3: Strcat(prefix, "thoroughly "); break;
617.  		    }
618.  		    Strcat(prefix, "rusty ");
619.  		}
620.  		if(obj->owornmask & W_BALL)
621.  			Strcat(bp, " (chained to you)");
622.  			break;
623.  	}
624.  
625.  	if((obj->owornmask & W_WEP) && !mrg_to_wielded) {
626.  		if (obj->quan != 1L)
627.  			Strcat(bp, " (wielded)");
628.  		else {
629.  			Strcat(bp, " (weapon in ");
630.  			Strcat(bp, body_part(HAND));
631.  			Strcat(bp, ")");
632.  		}
633.  	}
634.  	if(obj->unpaid)
635.  		Strcat(bp, " (unpaid)");
636.  	if (!strncmp(prefix, "a ", 2) &&
637.  			index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
638.  			&& (*(prefix+2) || (strncmp(bp, "uranium", 7)
639.  				&& strncmp(bp, "unicorn", 7)))) {
640.  		Strcpy(tmpbuf, prefix);
641.  		Strcpy(prefix, "an ");
642.  		Strcpy(prefix+3, tmpbuf+2);
643.  	}
644.  	bp = strprepend(bp, prefix);
645.  	return(bp);
646.  }
647.  
648.  #endif /* OVL0 */
649.  #ifdef OVLB
650.  
651.  /* used from invent.c */
652.  boolean
653.  not_fully_identified(otmp)
654.  register struct obj *otmp;
655.  {
656.      /* check fundamental ID hallmarks first */
657.      if (!otmp->known || !otmp->dknown ||
658.  #ifdef MAIL
659.  	    (!otmp->bknown && otmp->otyp != SCR_MAIL) ||
660.  #else
661.  	    !otmp->bknown ||
662.  #endif
663.  	    !objects[otmp->otyp].oc_name_known)	/* ?redundant? */
664.  	return TRUE;
665.      /* otmp->rknown is the only item of interest if we reach here */
666.         /*
667.  	*  Note:  if a revision ever allows scrolls to become fireproof or
668.  	*  rings to become shockproof, this checking will need to be revised.
669.  	*  `rknown' ID only matters if xname() will provide the info about it.
670.  	*/
671.      if (otmp->rknown || (otmp->oclass != ARMOR_CLASS &&
672.  			 otmp->oclass != WEAPON_CLASS &&
673.  			 !is_weptool(otmp) &&		    /* (redunant) */
674.  			 otmp->oclass != BALL_CLASS))	    /* (useless) */
675.  	return FALSE;
676.      else	/* lack of `rknown' only matters for vulnerable objects */
677.  	return (boolean)(is_rustprone(otmp) ||
678.  			 is_corrodeable(otmp) ||
679.  			 is_flammable(otmp));
680.  }
681.  
682.  /* The result is actually modifiable, but caller shouldn't rely on that
683.   * due to the small buffer size.
684.   */
685.  const char *
686.  corpse_xname(otmp, ignore_oquan)
687.  struct obj *otmp;
688.  boolean ignore_oquan;	/* to force singular */
689.  {
690.  	static char NEARDATA nambuf[40];
691.  
692.       /* assert( strlen(mons[otmp->corpsenm].mname) <= 32 ); */
693.  	Sprintf(nambuf, "%s corpse", mons[otmp->corpsenm].mname);
694.  
695.  	if (ignore_oquan || otmp->quan < 2)
696.  	    return nambuf;
697.  	else
698.  	    return makeplural(nambuf);
699.  }
700.  
701.  /*
702.   * Used if only one of a collection of objects is named (e.g. in eat.c).
703.   */
704.  const char *
705.  singular(otmp, func)
706.  register struct obj *otmp;
707.  char *FDECL((*func), (OBJ_P));
708.  {
709.  	long savequan;
710.  	char *nam;
711.  
712.  	/* Note: using xname for corpses will not give the monster type */
713.  	if (otmp->otyp == CORPSE && func == xname)
714.  		return corpse_xname(otmp, TRUE);
715.  
716.  	savequan = otmp->quan;
717.  	otmp->quan = 1L;
718.  	nam = (*func)(otmp);
719.  	otmp->quan = savequan;
720.  	return nam;
721.  }
722.  
723.  char *
724.  an(str)
725.  register const char *str;
726.  {
727.  	static char NEARDATA buf[BUFSZ];
728.  
729.  	buf[0] = '\0';
730.  
731.  	if (strncmpi(str, "the ", 4) &&
732.  	    strcmp(str, "molten lava") &&
733.  	    strcmp(str, "ice")) {
734.  		if (index(vowels, *str) &&
735.  		    strncmp(str, "useful", 6) &&
736.  		    strncmp(str, "unicorn", 7) &&
737.  		    strncmp(str, "uranium", 7))
738.  			Strcpy(buf, "an ");
739.  		else
740.  			Strcpy(buf, "a ");
741.  	}
742.  
743.  	Strcat(buf, str);
744.  	return buf;
745.  }
746.  
747.  char *
748.  An(str)
749.  const char *str;
750.  {
751.  	register char *tmp = an(str);
752.  	*tmp = highc(*tmp);
753.  	return tmp;
754.  }
755.  
756.  /*
757.   * Prepend "the" if necessary; assumes str is a subject derived from xname.
758.   * Use type_is_pname() for monster names, not the().  the() is idempotent.
759.   */
760.  char *
761.  the(str)
762.  const char *str;
763.  {
764.  	static char NEARDATA buf[BUFSZ];
765.  	boolean insert_the = FALSE;
766.  
767.  	if (!strncmpi(str, "the ", 4)) {
768.  	    buf[0] = lowc(*str);
769.  	    Strcpy(&buf[1], str+1);
770.  	    return buf;
771.  	} else if (*str < 'A' || *str > 'Z') {
772.  	    /* not a proper name, needs an article */
773.  	    insert_the = TRUE;
774.  	} else {
775.  	    /* Probably a proper name, might not need an article */
776.  	    register char *tmp, *named, *called;
777.  	    int l;
778.  
779.  	    /* some objects have capitalized adjectives in their names */
780.  	    if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) &&
781.  	       (tmp[1] < 'A' || tmp[1] > 'Z'))
782.  		insert_the = TRUE;
783.  	    else if (tmp && index(str, ' ') < tmp) {	/* has spaces */
784.  		/* it needs an article if the name contains "of" */
785.  		tmp = strstri(str, " of ");
786.  		named = strstri(str, " named ");
787.  		called = strstri(str, " called ");
788.  		if (called && (!named || called < named)) named = called;
789.  
790.  		if (tmp && (!named || tmp < named))	/* found an "of" */
791.  		    insert_the = TRUE;
792.  		/* stupid special case: lacks "of" but needs "the" */
793.  		else if (!named && (l = strlen(str)) >= 31 &&
794.  		      !strcmp(&str[l - 31], "Platinum Yendorian Express Card"))
795.  		    insert_the = TRUE;
796.  	    }
797.  	}
798.  	if (insert_the)
799.  	    Strcpy(buf, "the ");
800.  	else
801.  	    buf[0] = '\0';
802.  	Strcat(buf, str);
803.  
804.  	return buf;
805.  }
806.  
807.  char *
808.  The(str)
809.  const char *str;
810.  {
811.      register char *tmp = the(str);
812.      *tmp = highc(*tmp);
813.      return tmp;
814.  }
815.  
816.  char *
817.  aobjnam(otmp,verb)
818.  register struct obj *otmp;
819.  register const char *verb;
820.  {
821.  	register char *bp = xname(otmp);
822.  	char prefix[PREFIX];
823.  
824.  	if(otmp->quan != 1L) {
825.  		Sprintf(prefix, "%ld ", otmp->quan);
826.  		bp = strprepend(bp, prefix);
827.  	}
828.  
829.  	if(verb) {
830.  		/* verb is given in plural (without trailing s) */
831.  		Strcat(bp, " ");
832.  		if(otmp->quan != 1L)
833.  			Strcat(bp, verb);
834.  		else if(!strcmp(verb, "are"))
835.  			Strcat(bp, "is");
836.  		else {
837.  			Strcat(bp, verb);
838.  			Strcat(bp, "s");
839.  		}
840.  	}
841.  	return(bp);
842.  }
843.  
844.  char *
845.  Doname2(obj)
846.  register struct obj *obj;
847.  {
848.  	register char *s = doname(obj);
849.  
850.  	if('a' <= *s && *s <= 'z') *s -= ('a' - 'A');
851.  	return(s);
852.  }
853.  
854.  static const char *wrp[] = {
855.  	"wand", "ring", "potion", "scroll", "gem", "amulet",
856.  	"spellbook", "spell book",
857.  	/* for non-specific wishes */
858.  	"weapon", "armor", "armour", "tool", "food", "comestible",
859.  };
860.  static const char wrpsym[] = {
861.  	WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS,
862.  	AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS,
863.  	WEAPON_CLASS, ARMOR_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
864.  	FOOD_CLASS
865.  };
866.  
867.  #endif /* OVLB */
868.  #ifdef OVL0
869.  
870.  /* Plural routine; chiefly used for user-defined fruits.  We have to try to
871.   * account for everything reasonable the player has; something unreasonable
872.   * can still break the code.  However, it's still a lot more accurate than
873.   * "just add an s at the end", which Rogue uses...
874.   *
875.   * Also used for plural monster names ("Wiped out all homunculi.")
876.   * and body parts.
877.   *
878.   * Also misused by muse.c to convert 1st person present verbs to 2nd person.
879.   */
880.  char *
881.  makeplural(oldstr)
882.  const char *oldstr;
883.  {
884.  	/* Note: cannot use strcmpi here -- it'd give MATZot, CAVEMeN,... */
885.  	register char *spot;
886.  	static char NEARDATA str[BUFSZ];
887.  	const char *excess;
888.  	int len;
889.  
890.  	while (*oldstr==' ') oldstr++;
891.  	if (!oldstr || !*oldstr) {
892.  		impossible("plural of null?");
893.  		Strcpy(str, "s");
894.  		return str;
895.  	}
896.  	Strcpy(str, oldstr);
897.  
898.  	/* Search for common compounds, ex. lump of royal jelly */
899.  	for(excess=(char *)0, spot=str; *spot; spot++) {
900.  		if (!strncmp(spot, " of ", 4)
901.  				|| !strncmp(spot, " labeled ", 9)
902.  				|| !strncmp(spot, " called ", 8)
903.  				|| !strncmp(spot, " named ", 7)
904.  				|| !strcmp(spot, " above") /* lurkers above */
905.  				|| !strncmp(spot, " versus ", 8)
906.  				|| !strncmp(spot, " from ", 6)
907.  				|| !strncmp(spot, " in ", 4)
908.  				|| !strncmp(spot, " on ", 4)
909.  				|| !strncmp(spot, " a la ", 6)
910.  				|| !strncmp(spot, " with", 5)	/* " with "? */
911.  				|| !strncmp(spot, " de ", 4)
912.  				|| !strncmp(spot, " d'", 3)
913.  				|| !strncmp(spot, " du ", 4)) {
914.  			excess = oldstr + (int) (spot - str);
915.  			*spot = 0;
916.  			break;
917.  		}
918.  	}
919.  	spot--;
920.  	while (*spot==' ') spot--; /* Strip blanks from end */
921.  	*(spot+1) = 0;
922.  	/* Now spot is the last character of the string */
923.  
924.  	len = strlen(str);
925.  
926.  	/* Single letters */
927.  	if (len==1 || !letter(*spot)) {
928.  		Strcpy(spot+1, "'s");
929.  		goto bottom;
930.  	}
931.  
932.  	/* Same singular and plural; mostly Japanese words except for "manes" */
933.  	if ((len == 2 && !strcmp(str, "ya")) ||
934.  	    (len >= 2 && !strcmp(spot-1, "ai")) || /* samurai, Uruk-hai */
935.  	    (len >= 3 && !strcmp(spot-2, " ya")) ||
936.  	    (len >= 4 &&
937.  	     (!strcmp(spot-3, "fish") || !strcmp(spot-3, "tuna") ||
938.  	      !strcmp(spot-3, "deer"))) ||
939.  	    (len >= 5 && (!strcmp(spot-4, "sheep") ||
940.  			!strcmp(spot-4, "ninja") ||
941.  			!strcmp(spot-4, "ronin") ||
942.  			!strcmp(spot-4, "shito") ||
943.  			!strcmp(spot-4, "tengu") ||
944.  			!strcmp(spot-4, "manes"))) ||
945.  	    (len >= 6 && !strcmp(spot-5, "ki-rin")) ||
946.  	    (len >= 7 && !strcmp(spot-6, "gunyoki")))
947.  		goto bottom;
948.  
949.  	/* man/men ("Wiped out all cavemen.") */
950.  	if (len >= 3 && !strcmp(spot-2, "man") &&
951.  			(len<6 || strcmp(spot-5, "shaman")) &&
952.  			(len<5 || strcmp(spot-4, "human"))) {
953.  		*(spot-1) = 'e';
954.  		goto bottom;
955.  	}
956.  
957.  	/* tooth/teeth */
958.  	if (len >= 5 && !strcmp(spot-4, "tooth")) {
959.  		Strcpy(spot-3, "eeth");
960.  		goto bottom;
961.  	}
962.  
963.  	/* knife/knives, etc... */
964.  	if (!strcmp(spot-1, "fe"))
965.  		*(spot-1) = 'v';
966.  	else if (*spot == 'f')
967.  		if (index("lr", *(spot-1)) || index(vowels, *(spot-1)))
968.  			*spot = 'v';
969.  		else if (len >= 5 && !strncmp(spot-4, "staf", 4))
970.  			Strcpy(spot-1, "ve");
971.  
972.  	/* foot/feet (body part) */
973.  	if (len >= 4 && !strcmp(spot-3, "foot")) {
974.  		Strcpy(spot-2, "eet");
975.  		goto bottom;
976.  	}
977.  
978.  	/* ium/ia (mycelia, baluchitheria) */
979.  	if (len >= 3 && !strcmp(spot-2, "ium")) {
980.  		*(spot--) = (char)0;
981.  		*spot = 'a';
982.  		goto bottom;
983.  	}
984.  
985.  	/* algae, larvae, hyphae (another fungus part) */
986.  	if ((len >= 4 && !strcmp(spot-3, "alga")) ||
987.  	    (len >= 5 &&
988.  	     (!strcmp(spot-4, "hypha") || !strcmp(spot-4, "larva")))) {
989.  		Strcpy(spot, "ae");
990.  		goto bottom;
991.  	}
992.  
993.  	/* fungus/fungi, homunculus/homunculi, but wumpuses */
994.  	if (!strcmp(spot-1, "us") && (len < 6 || strcmp(spot-5, "wumpus"))) {
995.  		*(spot--) = (char)0;
996.  		*spot = 'i';
997.  		goto bottom;
998.  	}
999.  
1000. 	/* vortex/vortices */
1001. 	if (len >= 6 && !strcmp(spot-3, "rtex")) {
1002. 		Strcpy(spot-1, "ices");
1003. 		goto bottom;
1004. 	}
1005. 
1006. 	/* djinni/djinn (note: also efreeti/efreet) */
1007. 	if (len >= 6 && !strcmp(spot-5, "djinni")) {
1008. 		*spot = (char)0;
1009. 		goto bottom;
1010. 	}
1011. 
1012. 	/* mumak/mumakil */
1013. 	if (len >= 5 && !strcmp(spot-4, "mumak")) {
1014. 		Strcpy(spot+1, "il");
1015. 		goto bottom;
1016. 	}
1017. 
1018. 	/* sis/ses (nemesis) */
1019. 	if (len >= 3 && !strcmp(spot-2, "sis")) {
1020. 		*(spot-1) = 'e';
1021. 		goto bottom;
1022. 	}
1023. 
1024. 	/* erinys/erinyes */
1025. 	if (len >= 6 && !strcmp(spot-5, "erinys")) {
1026. 		Strcpy(spot, "es");
1027. 		goto bottom;
1028. 	}
1029. 
1030. 	/* mouse/mice,louse/lice (not a monster, but possible in food names) */
1031. 	if (len >= 5 && !strcmp(spot-3, "ouse") && index("MmLl", *(spot-4))) {
1032. 		Strcpy(spot-3, "ice");
1033. 		goto bottom;
1034. 	}
1035. 
1036. 	/* matzoh/matzot, possible food name */
1037. 	if (len >= 6 && (!strcmp(spot-5, "matzoh")
1038. 					|| !strcmp(spot-5, "matzah"))) {
1039. 		Strcpy(spot-1, "ot");
1040. 		goto bottom;
1041. 	}
1042. 	if (len >= 5 && (!strcmp(spot-4, "matzo")
1043. 					|| !strcmp(spot-5, "matza"))) {
1044. 		Strcpy(spot, "ot");
1045. 		goto bottom;
1046. 	}
1047. 
1048. 	/* child/children (for wise guys who give their food funny names) */
1049. 	if (len >= 5 && !strcmp(spot-4, "child")) {
1050. 		Strcpy(spot, "dren");
1051. 		goto bottom;
1052. 	}
1053. 
1054. 	/* note: -eau/-eaux (gateau, bordeau...) */
1055. 	/* note: ox/oxen, VAX/VAXen, goose/geese */
1056. 
1057. 	/* Ends in z, x, s, ch, sh; add an "es" */
1058. 	if (index("zxsv", *spot)
1059. 			|| (len >= 2 && *spot=='h' && index("cs", *(spot-1)))
1060. 	/* Kludge to get "tomatoes" and "potatoes" right */
1061. 			|| (len >= 4 && !strcmp(spot-2, "ato"))) {
1062. 		Strcpy(spot+1, "es");
1063. 		goto bottom;
1064. 	}
1065. 
1066. 	/* Ends in y preceded by consonant (note: also "qu") change to "ies" */
1067. 	if (*spot == 'y' &&
1068. 	    (!index(vowels, *(spot-1)))) {
1069. 		Strcpy(spot, "ies");
1070. 		goto bottom;
1071. 	}
1072. 
1073. 	/* Default: append an 's' */
1074. 	Strcpy(spot+1, "s");
1075. 
1076. bottom:	if (excess) Strcpy(eos(str), excess);
1077. 	return str;
1078. }
1079. 
1080. #endif /* OVL0 */
1081. 
1082. struct o_range {
1083. 	const char *name, oclass;
1084. 	int  f_o_range, l_o_range;
1085. };
1086. 
1087. #ifndef OVLB
1088. 
1089. STATIC_DCL const struct o_range o_ranges[];
1090. 
1091. #else /* OVLB */
1092. 
1093. /* wishable subranges of objects */
1094. STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
1095. 	{ "bag",	TOOL_CLASS,   SACK,	      BAG_OF_TRICKS },
1096. 	{ "lamp",	TOOL_CLASS,   OIL_LAMP,	      MAGIC_LAMP },
1097. 	{ "candle",	TOOL_CLASS,   TALLOW_CANDLE,  WAX_CANDLE },
1098. 	{ "horn",	TOOL_CLASS,   TOOLED_HORN,    HORN_OF_PLENTY },
1099. 	{ "shield",	ARMOR_CLASS,  SMALL_SHIELD,   SHIELD_OF_REFLECTION },
1100. 	{ "helm",	ARMOR_CLASS,  ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
1101. 	{ "gloves",	ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1102. 	{ "gauntlets",	ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1103. 	{ "boots",	ARMOR_CLASS,  LOW_BOOTS,      LEVITATION_BOOTS },
1104. 	{ "shoes",	ARMOR_CLASS,  LOW_BOOTS,      IRON_SHOES },
1105. 	{ "cloak",	ARMOR_CLASS,  MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
1106. #ifdef TOURIST
1107. 	{ "shirt",	ARMOR_CLASS,  HAWAIIAN_SHIRT, T_SHIRT },
1108. #endif
1109. 	{ "dragon scales",
1110. 			ARMOR_CLASS,  GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES },
1111. 	{ "dragon scale mail",
1112. 			ARMOR_CLASS,  GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL },
1113. 	{ "sword",	WEAPON_CLASS, SHORT_SWORD,    KATANA },
1114. #ifdef WIZARD
1115. 	{ "venom",	VENOM_CLASS,  BLINDING_VENOM, ACID_VENOM },
1116. #endif
1117. 	{ "gray stone",	GEM_CLASS,    LUCKSTONE,      FLINT },
1118. 	{ "grey stone",	GEM_CLASS,    LUCKSTONE,      FLINT },
1119. };
1120. 
1121. #define BSTRCMP(base,ptr,string) ((ptr) < base || strcmp((ptr),string))
1122. #define BSTRCMPI(base,ptr,string) ((ptr) < base || strcmpi((ptr),string))
1123. #define BSTRNCMP(base,ptr,string,num) ((ptr)<base || strncmp((ptr),string,num))
1124. 
1125. /*
1126.  * Singularize a string the user typed in; this helps reduce the complexity
1127.  * of readobjnam, and is also used in pager.c to singularize the string
1128.  * for which help is sought.
1129.  */
1130. 
1131. char *
1132. makesingular(oldstr)
1133. const char *oldstr;
1134. {
1135. 	register char *p, *bp;
1136. 	static char NEARDATA str[BUFSZ];
1137. 
1138. 	if (!oldstr || !*oldstr) {
1139. 		impossible("singular of null?");
1140. 		str[0] = 0;
1141. 		return str;
1142. 	}
1143. 	Strcpy(str, oldstr);
1144. 	bp = str;
1145. 
1146. 	while (*bp == ' ') bp++;
1147. 	/* find "cloves of garlic", "worthless pieces of blue glass" */
1148. 	if ((p = strstri(bp, "s of ")) != 0) {
1149. 	    /* but don't singularize "gauntlets" */
1150. 	    if (BSTRNCMP(bp, p-8, "gauntlet", 8))
1151. 		while ((*p = *(p+1)) != 0) p++;
1152. 	    return bp;
1153. 	}
1154. 
1155. 	/* remove -s or -es (boxes) or -ies (rubies) */
1156. 	p = eos(bp);
1157. 	if (p >= bp+1 && p[-1] == 's') {
1158. 		if (p >= bp+2 && p[-2] == 'e') {
1159. 			if (p >= bp+3 && p[-3] == 'i') {
1160. 				if(!BSTRCMP(bp, p-7, "cookies") ||
1161. 				   !BSTRCMP(bp, p-4, "pies"))
1162. 					goto mins;
1163. 				Strcpy(p-3, "y");
1164. 				return bp;
1165. 			}
1166. 
1167. 			/* note: cloves / knives from clove / knife */
1168. 			if(!BSTRCMP(bp, p-6, "knives")) {
1169. 				Strcpy(p-3, "fe");
1170. 				return bp;
1171. 			}
1172. 
1173. 			if(!BSTRCMP(bp, p-6, "staves")) {
1174. 				Strcpy(p-3, "ff");
1175. 				return bp;
1176. 			}
1177. 
1178. 			/* note: nurses, axes but boxes */
1179. 			if(!BSTRCMP(bp, p-5, "boxes")) {
1180. 				p[-2] = 0;
1181. 				return bp;
1182. 			}
1183. 			if (!BSTRCMP(bp, p-6, "gloves") ||
1184. 			    !BSTRCMP(bp, p-5, "shoes") ||
1185. 			    !BSTRCMP(bp, p-6, "scales"))
1186. 				return bp;
1187. 		} else if (!BSTRCMP(bp, p-5, "boots") ||
1188. 			   !BSTRCMP(bp, p-6, "tricks") ||
1189. 			   !BSTRCMP(bp, p-9, "paralysis") ||
1190. 			   !BSTRCMP(bp, p-5, "glass") ||
1191. 			   !BSTRCMP(bp, p-4, "ness") ||
1192. 			   !BSTRCMP(bp, p-14, "shape changers") ||
1193. 			   !BSTRCMP(bp, p-15, "detect monsters") ||
1194. 			   !BSTRCMPI(bp, p-11, "Aesculapius"))	/* staff */
1195. 				return bp;
1196. 	mins:
1197. 		p[-1] = 0;
1198. 	} else {
1199. 		if(!BSTRCMP(bp, p-5, "teeth")) {
1200. 			Strcpy(p-5, "tooth");
1201. 			return bp;
1202. 		}
1203. 		/* here we cannot find the plural suffix */
1204. 	}
1205. 	return bp;
1206. }
1207. 
1208. /* alternate spellings: extra space, space instead of hyphen, etc */
1209. struct alt_spellings {
1210. 	const char *sp;
1211. 	int ob;
1212. } spellings[] = {
1213. 	{ "two handed sword", TWO_HANDED_SWORD },
1214. 	{ "battle axe", BATTLE_AXE },
1215. 	{ "lockpick", LOCK_PICK },
1216. 	{ "pick axe", PICK_AXE },
1217. 	{ "luck stone", LUCKSTONE },
1218. 	{ "load stone", LOADSTONE },
1219. 	{ "broad sword", BROADSWORD },
1220. 	{ "elven broad sword", ELVEN_BROADSWORD },
1221. 	{ "longsword", LONG_SWORD },
1222. 	{ "shortsword", SHORT_SWORD },
1223. 	{ "elven shortsword", ELVEN_SHORT_SWORD },
1224. 	{ "dwarvish shortsword", DWARVISH_SHORT_SWORD },
1225. 	{ "orcish shortsword", ORCISH_SHORT_SWORD },
1226. 	{ "warhammer", WAR_HAMMER },
1227. 	{ "whip", BULLWHIP },
1228. 	{ "saber", SILVER_SABER },
1229. 	{ "silver sabre", SILVER_SABER },
1230. 	{ "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
1231. 	{ "grey dragon scales", GRAY_DRAGON_SCALES },
1232. 	{ "enchant armour", SCR_ENCHANT_ARMOR },
1233. 	{ "destroy armour", SCR_DESTROY_ARMOR },
1234. 	{ "smooth shield", SHIELD_OF_REFLECTION },
1235. 	{ "scroll of enchant armour", SCR_ENCHANT_ARMOR },
1236. 	{ "scroll of destroy armour", SCR_DESTROY_ARMOR },
1237. 	{ "leather armour", LEATHER_ARMOR },
1238. 	{ "studded leather armour", STUDDED_LEATHER_ARMOR },
1239. 	{ "iron ball", HEAVY_IRON_BALL },
1240. 	{ "lantern", BRASS_LANTERN },
1241. 	{ "amulet of poison resistance", AMULET_VERSUS_POISON },
1242. 	{ "amulet of lifesaving", AMULET_OF_LIFE_SAVING },
1243. 	{ "stone", ROCK },
1244. #ifdef TOURIST
1245. 	{ "camera", EXPENSIVE_CAMERA },
1246. 	{ "T shirt", T_SHIRT },
1247. 	{ "tee shirt", T_SHIRT },
1248. #endif
1249. 	{ (const char *)0, 0 },
1250. };
1251. 
1252. /* Return something wished for.  If not an object, return &zeroobj; if an error
1253.  * (no matching object), return (struct obj *)0.  Giving readobjnam() a null
1254.  * pointer skips the error return and creates a random object instead.
1255.  */
1256. struct obj *
1257. readobjnam(bp)
1258. register char *bp;
1259. {
1260. 	register char *p;
1261. 	register int i;
1262. 	register struct obj *otmp;
1263. 	int cnt, spe, spesgn, typ, very;
1264. 	int blessed, uncursed, iscursed, ispoisoned, isgreased;
1265. 	int eroded, erodeproof;
1266. 	int halfeaten, mntmp, contents;
1267. 	int islit, unlabeled;
1268. 	int isdiluted;
1269. 	struct fruit *f;
1270. 	int ftype = current_fruit;
1271. 	char fruitbuf[BUFSZ];
1272. 	/* We want to check for fruits last so that, for example, someone
1273. 	 * who names their fruit "katana" and wishes for a katana gets a real
1274. 	 * one.  But, we have to keep around the old buf since in the meantime
1275. 	 * we have deleted "empty", "+6", etc...
1276. 	 */
1277. 
1278. 	char oclass;
1279. 	char *un, *dn, *actualn;
1280. 	const char *name=0;
1281. 
1282. 	cnt = spe = spesgn = typ = very =
1283. 		blessed = uncursed = iscursed =
1284. 		ispoisoned = isgreased = eroded = erodeproof =
1285. 		halfeaten = islit = unlabeled = isdiluted = 0;
1286. 	mntmp = NON_PM;
1287. #define UNDEFINED 0
1288. #define EMPTY 1
1289. #define SPINACH 2
1290. 	contents = UNDEFINED;
1291. 	oclass = 0;
1292. 	actualn = dn = un = 0;
1293. 
1294. 	/* first, remove extra whitespace they may have typed */
1295. 	if (bp) {
1296. 		char c, *p2;
1297. 		boolean was_space = TRUE;
1298. 
1299. 		for (p = p2 = bp; (c = *p) != '\0'; p++) {
1300. 		     /* if (c == '\t') c = ' '; */
1301. 			if (c != ' ' || !was_space)  *p2++ = c;
1302. 			was_space = (c == ' ');
1303. 		}
1304. 		if (was_space && p2 > bp)  p2--;
1305. 		*p2 = '\0';
1306. 	}
1307. 
1308. 	for(;;) {
1309. 		register int l;
1310. 
1311. 		if (!bp || !*bp) goto any;
1312. 		if (!strncmpi(bp, "an ", l=3) ||
1313. 		    !strncmpi(bp, "a ", l=2)) {
1314. 			cnt = 1;
1315. 		} else if (!strncmpi(bp, "the ", l=4)) {
1316. 			;	/* just increment `bp' by `l' below */
1317. 		} else if (!cnt && digit(*bp)) {
1318. 			cnt = atoi(bp);
1319. 			while(digit(*bp)) bp++;
1320. 			while(*bp == ' ') bp++;
1321. 			l = 0;
1322. 		} else if (!strncmpi(bp, "blessed ", l=8) ||
1323. 			   !strncmpi(bp, "holy ", l=5)) {
1324. 			blessed = 1;
1325. 		} else if (!strncmpi(bp, "cursed ", l=7) ||
1326. 			   !strncmpi(bp, "unholy ", l=7)) {
1327. 			iscursed = 1;
1328. 		} else if (!strncmpi(bp, "uncursed ", l=9)) {
1329. 			uncursed = 1;
1330. 		} else if (!strncmp(bp, "rustproof ", l=10) ||
1331. 			   !strncmp(bp, "erodeproof ", l=11) ||
1332. 			   !strncmp(bp, "corrodeproof ", l=13) ||
1333. 			   !strncmp(bp, "fireproof ", l=10)) {
1334. 			erodeproof = 1;
1335. 		} else if (!strncmpi(bp,"lit ", l=4) ||
1336. 			   !strncmpi(bp,"burning ", l=8)) {
1337. 			islit = 1;
1338. 		} else if (!strncmpi(bp,"unlit ", l=6) ||
1339. 			   !strncmpi(bp,"extinguished ", l=13)) {
1340. 			islit = 0;
1341. 		/* "unlabeled" and "blank" are synonymous */
1342. 		} else if (!strncmpi(bp,"unlabeled ", l=10) ||
1343. 			   !strncmpi(bp,"unlabelled ", l=11) ||
1344. 			   !strncmpi(bp,"blank ", l=6)) {
1345. 			unlabeled = 1;
1346. 		} else if(!strncmpi(bp, "poisoned ",l=9)
1347. #ifdef WIZARD
1348. 			  || (wizard && !strncmpi(bp, "trapped ",l=8))
1349. #endif
1350. 			  ) {
1351. 			ispoisoned=1;
1352. 		} else if(!strncmpi(bp, "greased ",l=8)) {
1353. 			isgreased=1;
1354. 		} else if (!strncmpi(bp, "very ", l=5)) {
1355. 			/* very rusted very heavy iron ball */
1356. 			very = 1;
1357. 		} else if (!strncmpi(bp, "thoroughly ", l=11)) {
1358. 			very = 2;
1359. 		} else if (!strncmp(bp, "rusty ", l=6) ||
1360. 			   !strncmp(bp, "rusted ", l=7) ||
1361. 			   !strncmp(bp, "eroded ", l=7) ||
1362. 			   !strncmp(bp, "corroded ", l=9) ||
1363. 			   !strncmp(bp, "burnt ", l=6) ||
1364. 			   !strncmp(bp, "burned ", l=7) ||
1365. 			   !strncmp(bp, "rotted ", l=7) ||
1366. 			   !strncmp(bp, "damaged ", l=8)) {
1367. 			eroded = 1 + very; very = 0;
1368. 		} else if (!strncmpi(bp, "partly eaten ", l=13)) {
1369. 			halfeaten = 1;
1370. 		} else if (!strncmpi(bp, "diluted ", l=8)) {
1371. 			isdiluted = 1;
1372. 		} else break;
1373. 		bp += l;
1374. 	}
1375. 	if(!cnt) cnt = 1;		/* %% what with "gems" etc. ? */
1376. 	Strcpy(fruitbuf, bp);
1377. 	if(!strncmpi(bp, "empty ", 6)) {
1378. 		contents = EMPTY;
1379. 		bp += 6;
1380. 	}
1381. 	if (strlen(bp) > 1) {
1382. 	    if (*bp == '+' || *bp == '-') {
1383. 		spesgn = (*bp++ == '+') ? 1 : -1;
1384. 		spe = atoi(bp);
1385. 		while(digit(*bp)) bp++;
1386. 		while(*bp == ' ') bp++;
1387. 	    } else if ((p = rindex(bp, '(')) != 0) {
1388. 		if (p > bp && p[-1] == ' ') p[-1] = 0;
1389. 		else *p = 0;
1390. 		p++;
1391. 		if (!strcmpi(p, "lit)"))
1392. 		    islit = 1;
1393. 		else {
1394. 		    spe = atoi(p);
1395. 		    while(digit(*p)) p++;
1396. 		    if (*p != ')') spe = 0;
1397. 		    else {
1398. 			spesgn = 1;
1399. 			p++;
1400. 			if (*p) Strcat(bp, p);
1401. 		    }
1402. 		}
1403. 	    }
1404. 	}
1405. /*
1406.    otmp->spe is type schar; so we don't want spe to be any bigger or smaller.
1407.    also, spe should always be positive  -- some cheaters may try to confuse
1408.    atoi()
1409. */
1410. 	if (spe < 0) {
1411. 		spesgn = -1;	/* cheaters get what they deserve */
1412. 		spe = abs(spe);
1413. 	}
1414. 	if (spe > SCHAR_LIM)
1415. 		spe = SCHAR_LIM;
1416. 
1417. 	/* now we have the actual name, as delivered by xname, say
1418. 		green potions called whisky
1419. 		scrolls labeled "QWERTY"
1420. 		egg
1421. 		fortune cookies
1422. 		very heavy iron ball named hoei
1423. 		wand of wishing
1424. 		elven cloak
1425. 	*/
1426. 	if ((p = strstri(bp, " named ")) != 0) {
1427. 		*p = 0;
1428. 		name = p+7;
1429. 	}
1430. 	if ((p = strstri(bp, " called ")) != 0) {
1431. 		*p = 0;
1432. 		un = p+8;
1433. 		/* "helmet called telepathy" is not "helmet" (a specific type)
1434. 		 * "shield called reflection" is not "shield" (a general type)
1435. 		 */
1436. 		for(i = 0; i < SIZE(o_ranges); i++)
1437. 		    if(!strcmpi(bp, o_ranges[i].name)) {
1438. 			oclass = o_ranges[i].oclass;
1439. 			goto srch;
1440. 		    }
1441. 	}
1442. 	if ((p = strstri(bp, " labeled ")) != 0) {
1443. 		*p = 0;
1444. 		dn = p+9;
1445. 	} else if ((p = strstri(bp, " labelled ")) != 0) {
1446. 		*p = 0;
1447. 		dn = p+10;
1448. 	}
1449. 	if ((p = strstri(bp, " of spinach")) != 0) {
1450. 		*p = 0;
1451. 		contents = SPINACH;
1452. 	}
1453. 
1454. 	/* Skip over "pair of ", then jump to the singular since we don't
1455. 	   need to convert "gloves" or "boots". */
1456. 	if(cnt == 1 && !strncmpi(bp, "pair of ",8)) {
1457. 		bp += 8;
1458. 		cnt = 2;
1459. 		goto sing;
1460. 		/* cnt is ignored for armor and other non-stackable objects;
1461. 		   DTRT for stackable objects */
1462. 	} else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) {
1463. 		bp += 9;
1464. 		cnt *= 2;
1465. 	} else if (!strncmpi(bp, "set of ",7)) {
1466. 		bp += 7;
1467. 	} else if (!strncmpi(bp, "sets of ",8)) {
1468. 		bp += 8;
1469. 	}
1470. 
1471. 	/*
1472. 	 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
1473. 	 * Don't check if it's a wand or spellbook.
1474. 	 * (avoid "wand/finger of death" confusion).
1475. 	 */
1476. 	if (!strstri(bp, "wand ")
1477. 	 && !strstri(bp, "spellbook ")
1478. 	 && !strstri(bp, "finger ")) {
1479. 	    if ((p = strstri(bp, " of ")) != 0
1480. 		&& (mntmp = name_to_mon(p+4)) >= LOW_PM)
1481. 		*p = 0;
1482. 	}
1483. 	/* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
1484. 	if (strncmp(bp, "samurai sword", 13)) /* not the "samurai" monster! */
1485. 	if (strncmp(bp, "wizard lock", 11)) /* not the "wizard" monster! */
1486. 	if (strncmp(bp, "ninja-to", 8)) /* not the "ninja" rank */
1487. 	if (mntmp < LOW_PM && strlen(bp) > 2 &&
1488. 	    (mntmp = name_to_mon(bp)) >= LOW_PM) {
1489. 		int mntmptoo, mntmplen;	/* double check for rank title */
1490. 		char *obp = bp;
1491. 		mntmptoo = title_to_mon(bp, (int *)0, &mntmplen);
1492. 		bp += mntmp != mntmptoo ? strlen(mons[mntmp].mname) : mntmplen;
1493. 		if (*bp == ' ') bp++;
1494. 		else if (!strncmpi(bp, "s ", 2)) bp += 2;
1495. 		else if (!strncmpi(bp, "es ", 3)) bp += 3;
1496. 		else if (!*bp && !actualn && !dn && !un && !oclass) {
1497. 		    /* no referent; they don't really mean a monster type */
1498. 		    bp = obp;
1499. 		    mntmp = NON_PM;
1500. 		}
1501. 	}
1502. 
1503. 	/* first change to singular if necessary */
1504. 	if (*bp) {
1505. 		char *sng = makesingular(bp);
1506. 		if (strcmp(bp, sng)) {
1507. 			if (cnt == 1) cnt = 2;
1508. 			Strcpy(bp, sng);
1509. 		}
1510. 	}
1511. 
1512. sing:
1513. 	/* Alternate spellings (two-handed sword vs. two handed sword) */
1514. 	{struct alt_spellings *as = spellings;
1515. 		while(as->sp) {
1516. 			if (!strcmpi(bp, as->sp)) {
1517. 				typ = as->ob;
1518. 				goto typfnd;
1519. 			}
1520. 			as++;
1521. 		}
1522. 	}
1523. 
1524. 	/* dragon scales - assumes order of dragons */
1525. 	if(!strcmpi(bp, "scales") &&
1526. 			mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) {
1527. 		typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
1528. 		mntmp = NON_PM;	/* no monster */
1529. 		goto typfnd;
1530. 	}
1531. 
1532. 	p = eos(bp);
1533. 	if(!BSTRCMPI(bp, p-10, "holy water")) {
1534. 		typ = POT_WATER;
1535. 		if ((p-bp) >= 12 && *(p-12) == 'u')
1536. 			iscursed = 1; /* unholy water */
1537. 		else blessed = 1;
1538. 		goto typfnd;
1539. 	}
1540. 	if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) {
1541. 		typ = SCR_BLANK_PAPER;
1542. 		goto typfnd;
1543. 	}
1544. 	if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) {
1545. 		typ = SPE_BLANK_PAPER;
1546. 		goto typfnd;
1547. 	}
1548. #if 0
1549. #ifdef TOURIST
1550. 	if (!BSTRCMPI(bp, p-5, "shirt")) {
1551. 		typ = HAWAIIAN_SHIRT;
1552. 		goto typfnd;
1553. 	}
1554. #endif
1555. #endif
1556. 	/*
1557. 	 * NOTE: Gold pieces are handled as objects nowadays, and therefore
1558. 	 * this section should probably be reconsidered as well as the entire
1559. 	 * gold/money concept.  Maybe we want to add other monetary units as
1560. 	 * well in the future. (TH)
1561. 	 */
1562. 	if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") ||
1563. 	   !strcmpi(bp, "gold") || !strcmpi(bp, "money") ||
1564. 	   !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
1565. 			if (cnt > 5000
1566. #ifdef WIZARD
1567. 					&& !wizard
1568. #endif
1569. 						) cnt=5000;
1570. 		if (cnt < 1) cnt=1;
1571. 		pline("%d gold piece%s.", cnt, plur(cnt));
1572. 		u.ugold += cnt;
1573. 		flags.botl=1;
1574. 		return (&zeroobj);
1575. 	}
1576. 	if (strlen(bp) == 1 &&
1577. 	   (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS) {
1578. 		oclass = i;
1579. 		goto any;
1580. 	}
1581. 
1582. 	/* Search for class names: XXXXX potion, scroll of XXXXX.  Avoid */
1583. 	/* false hits on, e.g., rings for "ring mail". */
1584. 	if(strncmpi(bp, "enchant ", 8) &&
1585. 	   strncmpi(bp, "destroy ", 8) &&
1586. 	   strncmpi(bp, "food detection", 14) &&
1587. 	   strncmpi(bp, "ring mail", 9) &&
1588. 	   strncmpi(bp, "studded leather arm", 19) &&
1589. 	   strncmpi(bp, "leather arm", 11) &&
1590. 	   strncmpi(bp, "tooled horn", 11) &&
1591. 	   strncmpi(bp, "food ration", 11)
1592. 	)
1593. 	for (i = 0; i < (int)(sizeof wrpsym); i++) {
1594. 		register int j = strlen(wrp[i]);
1595. 		if(!strncmpi(bp, wrp[i], j)){
1596. 			oclass = wrpsym[i];
1597. 			if(oclass != AMULET_CLASS) {
1598. 			    bp += j;
1599. 			    if(!strncmpi(bp, " of ", 4)) actualn = bp+4;
1600. 			    /* else if(*bp) ?? */
1601. 			} else
1602. 			    actualn = bp;
1603. 			goto srch;
1604. 		}
1605. 		if(!BSTRCMPI(bp, p-j, wrp[i])){
1606. 			oclass = wrpsym[i];
1607. 			p -= j;
1608. 			*p = 0;
1609. 			if(p > bp && p[-1] == ' ') p[-1] = 0;
1610. 			actualn = dn = bp;
1611. 			goto srch;
1612. 		}
1613. 	}
1614. 
1615. 	/* "grey stone" check must be before general "stone" */
1616. 	for (i = 0; i < SIZE(o_ranges); i++)
1617. 	    if(!strcmpi(bp, o_ranges[i].name)) {
1618. 		typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
1619. 		goto typfnd;
1620. 	    }
1621. 
1622. 	if (!BSTRCMPI(bp, p-6, " stone")) {
1623. 		p[-6] = 0;
1624. 		oclass = GEM_CLASS;
1625. 		dn = actualn = bp;
1626. 		goto srch;
1627. 	} else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) {
1628. 		register char *g = bp;
1629. 		if (strstri(g, "broken")) return (struct obj *)0;
1630. 		if (!strncmpi(g, "worthless ", 10)) g += 10;
1631. 		if (!strncmpi(g, "piece of ", 9)) g += 9;
1632. 		if (!strncmpi(g, "colored ", 8)) g += 8;
1633. 		else if (!strncmpi(g, "coloured ", 9)) g += 9;
1634. 		if (!strcmpi(g, "glass")) {	/* choose random color */
1635. 			/* white, blue, red, yellowish brown, green, violet */
1636. 			typ = LAST_GEM + rnd(6);
1637. 			if (objects[typ].oc_class == GEM_CLASS) goto typfnd;
1638. 			else typ = 0;	/* somebody changed objects[]? punt */
1639. 		} else if (g > bp) {	/* try to construct canonical form */
1640. 			char tbuf[BUFSZ];
1641. 			Strcpy(tbuf, "worthless piece of ");
1642. 			Strcat(tbuf, g);  /* assume it starts with the color */
1643. 			Strcpy(bp, tbuf);
1644. 		}
1645. 	}
1646. 
1647. 	actualn = bp;
1648. 	if (!dn) dn = actualn; /* ex. "skull cap" */
1649. srch:
1650. 	/* check real names of gems first */
1651. 	if(!oclass && actualn) {
1652. 	    for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
1653. 		register const char *zn;
1654. 
1655. 		if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
1656. 		    typ = i;
1657. 		    goto typfnd;
1658. 		}
1659. 	    }
1660. 	}
1661. 	i = oclass ? bases[(int)oclass] : 1;
1662. 	while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){
1663. 		register const char *zn;
1664. 
1665. 		if(actualn && (zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
1666. 			typ = i;
1667. 			goto typfnd;
1668. 		}
1669. 		if(dn && (zn = OBJ_DESCR(objects[i])) && !strcmpi(dn, zn)) {
1670. 			/* don't match extra descriptions (w/o real name) */
1671. 			if (!OBJ_NAME(objects[i])) return (struct obj *)0;
1672. 			typ = i;
1673. 			goto typfnd;
1674. 		}
1675. 		if(un && (zn = objects[i].oc_uname) && !strcmpi(un, zn)) {
1676. 			typ = i;
1677. 			goto typfnd;
1678. 		}
1679. 		i++;
1680. 	}
1681. 	if (actualn) {
1682. 		struct Jitem *j = Japanese_items;
1683. 		while(j->item) {
1684. 			if (actualn && !strcmpi(actualn, j->name)) {
1685. 				typ = j->item;
1686. 				goto typfnd;
1687. 			}
1688. 			j++;
1689. 		}
1690. 	}
1691. 	/* Note: not strncmpi.  2 fruits, one capital, one not, is possible. */
1692. 	for(f=ffruit; f; f = f->nextf) {
1693. 		char *f1 = f->fname, *f2 = makeplural(f->fname);
1694. 
1695. 		if(!strncmp(fruitbuf, f1, strlen(f1)) ||
1696. 					!strncmp(fruitbuf, f2, strlen(f2))) {
1697. 			typ = SLIME_MOLD;
1698. 			ftype = f->fid;
1699. 			goto typfnd;
1700. 		}
1701. 	}
1702. 	if (!strcmpi(bp, "spinach")) {
1703. 		contents = SPINACH;
1704. 		typ = TIN;
1705. 		goto typfnd;
1706. 	}
1707. 
1708. 	if(!oclass && actualn) {
1709. 	    short objtyp;
1710. 
1711. 	    /* Perhaps it's an artifact specified by name, not type */
1712. 	    name = artifact_name(actualn, &objtyp);
1713. 	    if(name) {
1714. 		typ = objtyp;
1715. 		goto typfnd;
1716. 	    }
1717. 	}
1718. #ifdef WIZARD
1719. 	/* Let wizards wish for traps --KAA */
1720. 	/* must come after objects check so wizards can still wish for
1721. 	 * trap objects like beartraps
1722. 	 */
1723. 	if (wizard) {
1724. 		int trap;
1725. 
1726. 		for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) {
1727. 			const char *tname;
1728. 
1729. 			tname = defsyms[trap_to_defsym(trap)].explanation;
1730. 			if (!strncmpi(tname, bp, strlen(tname))) {
1731. 				/* avoid stupid mistakes */
1732. 				if((trap == TRAPDOOR || trap == HOLE)
1733. 				      && !Can_fall_thru(&u.uz)) trap = ROCKTRAP;
1734. 				(void) maketrap(u.ux, u.uy, trap);
1735. 				pline("%s.", An(tname));
1736. 				return(&zeroobj);
1737. 			}
1738. 		}
1739. 		/* or some other dungeon features -dlc */
1740. 		p = eos(bp);
1741. 		if(!BSTRCMP(bp, p-8, "fountain")) {
1742. 			levl[u.ux][u.uy].typ = FOUNTAIN;
1743. 			level.flags.nfountains++;
1744. 			if(!strncmpi(bp, "magic ", 6))
1745. 				levl[u.ux][u.uy].blessedftn = 1;
1746. 			pline("A %sfountain.",
1747. 			      levl[u.ux][u.uy].blessedftn ? "magic " : "");
1748. 			newsym(u.ux, u.uy);
1749. 			return(&zeroobj);
1750. 		}
1751. 		if(!BSTRCMP(bp, p-6, "throne")) {
1752. 			levl[u.ux][u.uy].typ = THRONE;
1753. 			pline("A throne.");
1754. 			newsym(u.ux, u.uy);
1755. 			return(&zeroobj);
1756. 		}
1757. # ifdef SINKS
1758. 		if(!BSTRCMP(bp, p-4, "sink")) {
1759. 			levl[u.ux][u.uy].typ = SINK;
1760. 			level.flags.nsinks++;
1761. 			pline("A sink.");
1762. 			newsym(u.ux, u.uy);
1763. 			return &zeroobj;
1764. 		}
1765. # endif
1766. 		if(!BSTRCMP(bp, p-4, "pool")) {
1767. 			levl[u.ux][u.uy].typ = POOL;
1768. 			del_engr_at(u.ux, u.uy);
1769. 			pline("A pool.");
1770. 			water_damage(level.objects[u.ux][u.uy], FALSE, TRUE);
1771. 			newsym(u.ux, u.uy);
1772. 			return &zeroobj;
1773. 		}
1774. 
1775. 		if(!BSTRCMP(bp, p-5, "altar")) {
1776. 		    aligntyp al;
1777. 
1778. 		    levl[u.ux][u.uy].typ = ALTAR;
1779. 		    if(!strncmpi(bp, "chaotic ", 8))
1780. 			al = A_CHAOTIC;
1781. 		    else if(!strncmpi(bp, "neutral ", 8))
1782. 			al = A_NEUTRAL;
1783. 		    else if(!strncmpi(bp, "lawful ", 7))
1784. 			al = A_LAWFUL;
1785. 		    else if(!strncmpi(bp, "unaligned ", 10))
1786. 			al = A_NONE;
1787. 		    else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
1788. 			al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1;
1789. 		    levl[u.ux][u.uy].altarmask = Align2amask( al );
1790. 		    pline("%s altar.", An(align_str(al)));
1791. 		    newsym(u.ux, u.uy);
1792. 		    return(&zeroobj);
1793. 		}
1794. 	}
1795. #endif
1796. 	if(!oclass) return((struct obj *)0);
1797. any:
1798. 	if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))];
1799. typfnd:
1800. 	if (typ) oclass = objects[typ].oc_class;
1801. 
1802. 	/* check for some objects that are not allowed */
1803. 	if (typ && objects[typ].oc_unique
1804. #ifdef WIZARD
1805. 	    && !wizard
1806. 	    /* should check flags.made_amulet, but it's not set anywhere */
1807. #endif
1808. 	   )
1809. 	    switch (typ) {
1810. 		case AMULET_OF_YENDOR:
1811. 		    typ = FAKE_AMULET_OF_YENDOR;
1812. 		    break;
1813. 		case CANDELABRUM_OF_INVOCATION:
1814. 		    typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
1815. 		    break;
1816. 		case BELL_OF_OPENING:
1817. 		    typ = BELL;
1818. 		    break;
1819. 		case SPE_BOOK_OF_THE_DEAD:
1820. 		    typ = SPE_BLANK_PAPER;
1821. 		    break;
1822. 	    }
1823. 	/* catch any other non-wishable objects */
1824. 	if (objects[typ].oc_nowish
1825. #ifdef WIZARD
1826. 	    && !wizard
1827. #endif
1828. 	    )
1829. 	    return((struct obj *)0);
1830. 
1831. 	if(typ) {
1832. 		otmp = mksobj(typ, TRUE, FALSE);
1833. 	} else {
1834. 		otmp = mkobj(oclass, FALSE);
1835. 		if (otmp) typ = otmp->otyp;
1836. 	}
1837. 
1838. 	if (islit &&
1839. 		(typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN ||
1840. 		 Is_candle(otmp) || typ == POT_OIL)) {
1841. 	    place_object(otmp, u.ux, u.uy);  /* make it viable light source */
1842. 	    begin_burn(otmp, FALSE);
1843. 	    obj_extract_self(otmp);	 /* now release it for caller's use */
1844. 	}
1845. 
1846. 	if(cnt > 0 && objects[typ].oc_merge && oclass != SPBOOK_CLASS &&
1847. 		(cnt < rnd(6) ||
1848. #ifdef WIZARD
1849. 		wizard ||
1850. #endif
1851. 		 (cnt <= 7 && Is_candle(otmp)) ||
1852. 		 (cnt <= 20 &&
1853. 		  ((oclass == WEAPON_CLASS &&
1854. 		    (objects[typ].oc_wepcat == WEP_AMMO ||
1855. 		     objects[typ].oc_wepcat == WEP_MISSILE)) || (typ == ROCK)))))
1856. 			otmp->quan = (long) cnt;
1857. 
1858. #ifdef WIZARD
1859. 	if (oclass == VENOM_CLASS) otmp->spe = 1;
1860. #endif
1861. 
1862. 	if (spesgn == 0) spe = otmp->spe;
1863. #ifdef WIZARD
1864. 	else if (wizard) /* no alteration to spe */ ;
1865. #endif
1866. 	else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS ||
1867. 		 is_weptool(otmp) ||
1868. 			(oclass==RING_CLASS && objects[typ].oc_charged)) {
1869. 		if(spe > rnd(5) && spe > otmp->spe) spe = 0;
1870. 		if(spe > 2 && Luck < 0) spesgn = -1;
1871. 	} else {
1872. 		if (oclass == WAND_CLASS) {
1873. 			if (spe > 1 && spesgn == -1) spe = 1;
1874. 		} else {
1875. 			if (spe > 0 && spesgn == -1) spe = 0;
1876. 		}
1877. 		if (spe > otmp->spe) spe = otmp->spe;
1878. 	}
1879. 
1880. 	if (spesgn == -1) spe = -spe;
1881. 
1882. 	/* set otmp->spe.  This may, or may not, use spe... */
1883. 	switch (typ) {
1884. 		case TIN: if (contents==EMPTY) {
1885. 				otmp->corpsenm = NON_PM;
1886. 				otmp->spe = 0;
1887. 			} else if (contents==SPINACH) {
1888. 				otmp->corpsenm = NON_PM;
1889. 				otmp->spe = 1;
1890. 			}
1891. 			break;
1892. 		case SLIME_MOLD: otmp->spe = ftype;
1893. 			/* Fall through */
1894. 		case SKELETON_KEY: case CHEST: case LARGE_BOX:
1895. 		case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE:
1896. 			/* otmp->cobj already done in mksobj() */
1897. 				break;
1898. #ifdef MAIL
1899. 		case SCR_MAIL: otmp->spe = 1; break;
1900. #endif
1901. 		case WAN_WISHING:
1902. #ifdef WIZARD
1903. 			if (!wizard) {
1904. #endif
1905. 				otmp->spe = (rn2(10) ? -1 : 0);
1906. 				break;
1907. #ifdef WIZARD
1908. 			}
1909. 			/* fall through (twice), if wizard */
1910. #endif
1911. 		case MAGIC_LAMP:
1912. #ifdef WIZARD
1913. 			if (!wizard) {
1914. #endif
1915. 				otmp->spe = 0;
1916. 				break;
1917. #ifdef WIZARD
1918. 			}
1919. 			/* fall through, if wizard */
1920. #endif
1921. 		default: otmp->spe = spe;
1922. 	}
1923. 
1924. 	/* set otmp->corpsenm or dragon scale [mail] */
1925. 	if (mntmp >= LOW_PM) switch(typ) {
1926. 		case TIN:
1927. 			otmp->spe = 0; /* No spinach */
1928. 			if (dead_species(mntmp, FALSE)) {
1929. 			    otmp->corpsenm = NON_PM;	/* it's empty */
1930. 			} else if (!(mons[mntmp].geno & G_UNIQ) &&
1931. 				   !(mvitals[mntmp].mvflags & G_NOCORPSE))
1932. 			    otmp->corpsenm = mntmp;
1933. 			break;
1934. 		case CORPSE:
1935. 			if (!(mons[mntmp].geno & G_UNIQ) &&
1936. 				   !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
1937. 			    /* beware of random troll or lizard corpse,
1938. 			       or of ordinary one being forced to such */
1939. 			    if (otmp->timed) obj_stop_timers(otmp);
1940. 			    otmp->corpsenm = mntmp;
1941. 			    start_corpse_timeout(otmp);
1942. 			}
1943. 			break;
1944. 		case FIGURINE:
1945. 			if (!(mons[mntmp].geno & G_UNIQ)
1946. 			    && !is_human(&mons[mntmp])
1947. #ifdef MAIL
1948. 			    && mntmp != PM_MAIL_DAEMON
1949. #endif
1950. 							)
1951. 				otmp->corpsenm = mntmp;
1952. 			break;
1953. 		case EGG:
1954. 			mntmp = can_be_hatched(mntmp);
1955. 			if (mntmp != NON_PM && !dead_species(mntmp, TRUE)) {
1956. 			    otmp->corpsenm = mntmp;
1957. 			    /* replace timeout (if any) */
1958. 			    attach_egg_hatch_timeout(otmp);
1959. 			}
1960. 			break;
1961. 		case STATUE: otmp->corpsenm = mntmp;
1962. 			break;
1963. 		case SCALE_MAIL:
1964. 			/* Dragon mail - depends on the order of objects */
1965. 			/*		 & dragons.			 */
1966. 			if (mntmp >= PM_GRAY_DRAGON &&
1967. 						mntmp <= PM_YELLOW_DRAGON)
1968. 			    otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
1969. 						    mntmp - PM_GRAY_DRAGON;
1970. 			break;
1971. 	}
1972. 
1973. 	/* set blessed/cursed -- setting the fields directly is safe
1974. 	 * since weight() is called below and addinv() will take care
1975. 	 * of luck */
1976. 	if (iscursed) {
1977. 		curse(otmp);
1978. 	} else if (uncursed) {
1979. 		otmp->blessed = 0;
1980. 		otmp->cursed = (Luck < 0
1981. #ifdef WIZARD
1982. 					 && !wizard
1983. #endif
1984. 							);
1985. 	} else if (blessed) {
1986. 		otmp->blessed = (Luck >= 0
1987. #ifdef WIZARD
1988. 					 || wizard
1989. #endif
1990. 							);
1991. 		otmp->cursed = (Luck < 0
1992. #ifdef WIZARD
1993. 					 && !wizard
1994. #endif
1995. 							);
1996. 	} else if (spesgn < 0) {
1997. 		curse(otmp);
1998. 	}
1999. 
2000. 	/* set eroded */
2001. 	if (eroded)
2002. 		otmp->oeroded = eroded;
2003. 
2004. 	/* set erodeproof */
2005. 	else if (erodeproof)
2006. 		otmp->oerodeproof = (Luck >= 0
2007. #ifdef WIZARD
2008. 					 || wizard
2009. #endif
2010. 				    );
2011. 
2012. 	/* prevent wishing abuse */
2013. 	if (
2014. #ifdef WIZARD
2015. 		!wizard &&
2016. #endif
2017. 			otmp->otyp == WAN_WISHING)
2018. 		otmp->recharged = 1;
2019. 
2020. 	/* set poisoned */
2021. 	if (ispoisoned) {
2022. 	    if (oclass == WEAPON_CLASS && typ <= SHURIKEN)
2023. 		otmp->opoisoned = (Luck >= 0);
2024. 	    else if (Is_box(otmp) || typ == TIN)
2025. 		otmp->otrapped = 1;
2026. 	    else if (oclass == FOOD_CLASS)
2027. 		/* try to taint by making it as old as possible */
2028. 		otmp->age = 1L;
2029. 	}
2030. 
2031. 	if (isgreased) otmp->greased = 1;
2032. 
2033. 	if (isdiluted && otmp->oclass == POTION_CLASS &&
2034. 			otmp->otyp != POT_WATER)
2035. 		otmp->odiluted = 1;
2036. 
2037. 	if (name) {
2038. 		const char *aname;
2039. 		short objtyp;
2040. 
2041. 		/* an artifact name might need capitalization fixing */
2042. 		aname = artifact_name(name, &objtyp);
2043. 		if (aname && objtyp == otmp->otyp) name = aname;
2044. 
2045. 		otmp = oname(otmp, name);
2046. 		if (otmp->oartifact) otmp->quan = 1L;
2047. 	}
2048. 
2049. 	/* more wishing abuse: don't allow wishing for certain artifacts */
2050. 	/* and make them pay; charge them for the wish anyway! */
2051. 	if ((is_quest_artifact(otmp) ||
2052. 	     (otmp->oartifact && rn2(nartifact_exist()) > 1))
2053. #ifdef WIZARD
2054. 	    && !wizard
2055. #endif
2056. 	    ) {
2057. 	    artifact_unexist(otmp);
2058. 	    obfree(otmp, (struct obj *) 0);
2059. 	    otmp = &zeroobj;
2060. 	    pline(
2061. 	     "For a moment, you feel %s in your %s, but it disappears!",
2062. 		  something,
2063. 		  makeplural(body_part(HAND)));
2064. 	}
2065. 
2066. 	otmp->owt = weight(otmp);
2067. 	if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160;
2068. 	if (halfeaten && otmp->oclass == FOOD_CLASS) {
2069. 		if (otmp->otyp == CORPSE)
2070. 			otmp->oeaten = mons[otmp->corpsenm].cnutrit;
2071. 		else otmp->oeaten = objects[otmp->otyp].oc_nutrition;
2072. 		otmp->owt /= 2;
2073. 		otmp->oeaten /= 2;
2074. 		if (!otmp->owt) otmp->owt = 1;
2075. 		if (!otmp->oeaten) otmp->oeaten = 1;
2076. 	}
2077. 	return(otmp);
2078. }
2079. 
2080. int
2081. rnd_class(first,last)
2082. int first,last;
2083. {
2084. 	int i, x, sum=0;
2085. 	for(i=first; i<=last; i++)
2086. 		sum += objects[i].oc_prob;
2087. 	if (!sum) /* all zero */
2088. 		return first + rn2(last-first+1);
2089. 	x = rnd(sum);
2090. 	for(i=first; i<=last; i++)
2091. 		if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
2092. 			return i;
2093. 	return 0;
2094. }
2095. 
2096. STATIC_OVL const char *
2097. Japanese_item_name(i)
2098. int i;
2099. {
2100. 	struct Jitem *j = Japanese_items;
2101. 
2102. 	while(j->item) {
2103. 		if (i == j->item)
2104. 			return j->name;
2105. 		j++;
2106. 	}
2107. 	return (const char *)0;
2108. }
2109. #endif /* OVLB */
2110. 
2111. /*objnam.c*/