1/*	SCCS Id: @(#)objnam.c	3.4	2003/12/04	*/
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 greased partly eaten guardian naga hatchling [corpse]" */
8#define PREFIX	80	/* (56) */
9#define SCHAR_LIM 127
10#define NUMOBUF 12
11
12STATIC_DCL char *FDECL(strprepend,(char *,const char *));
13#ifdef OVLB
14static boolean FDECL(wishymatch, (const char *,const char *,BOOLEAN_P));
15#endif
16static char *NDECL(nextobuf);
17static void FDECL(add_erosion_words, (struct obj *, char *));
18
19struct Jitem {
20	int item;
21	const char *name;
22};
23
24/* true for gems/rocks that should have " stone" appended to their names */
25#define GemStone(typ)	(typ == FLINT ||				\
26			 (objects[typ].oc_material == GEMSTONE &&	\
27			  (typ != DILITHIUM_CRYSTAL && typ != RUBY &&	\
28			   typ != DIAMOND && typ != SAPPHIRE &&		\
29			   typ != BLACK_OPAL && 	\
30			   typ != EMERALD && typ != OPAL)))
31
32#ifndef OVLB
33
34STATIC_DCL struct Jitem Japanese_items[];
35
36#else /* OVLB */
37
38STATIC_OVL struct Jitem Japanese_items[] = {
39	{ SHORT_SWORD, "wakizashi" },
40	{ BROADSWORD, "ninja-to" },
41	{ FLAIL, "nunchaku" },
42	{ GLAIVE, "naginata" },
43	{ LOCK_PICK, "osaku" },
44	{ WOODEN_HARP, "koto" },
45	{ KNIFE, "shito" },
46	{ PLATE_MAIL, "tanko" },
47	{ HELMET, "kabuto" },
48	{ LEATHER_GLOVES, "yugake" },
49	{ FOOD_RATION, "gunyoki" },
50	{ POT_BOOZE, "sake" },
51	{0, "" }
52};
53
54#endif /* OVLB */
55
56STATIC_DCL const char *FDECL(Japanese_item_name,(int i));
57
58#ifdef OVL1
59
60STATIC_OVL char *
61strprepend(s,pref)
62register char *s;
63register const char *pref;
64{
65	register int i = (int)strlen(pref);
66
67	if(i > PREFIX) {
68		impossible("PREFIX too short (for %d).", i);
69		return(s);
70	}
71	s -= i;
72	(void) strncpy(s, pref, i);	/* do not copy trailing 0 */
73	return(s);
74}
75
76#endif /* OVL1 */
77#ifdef OVLB
78
79/* manage a pool of BUFSZ buffers, so callers don't have to */
80static char *
81nextobuf()
82{
83	static char NEARDATA bufs[NUMOBUF][BUFSZ];
84	static int bufidx = 0;
85
86	bufidx = (bufidx + 1) % NUMOBUF;
87	return bufs[bufidx];
88}
89
90char *
91obj_typename(otyp)
92register int otyp;
93{
94	char *buf = nextobuf();
95	register struct objclass *ocl = &objects[otyp];
96	register const char *actualn = OBJ_NAME(*ocl);
97	register const char *dn = OBJ_DESCR(*ocl);
98	register const char *un = ocl->oc_uname;
99	register int nn = ocl->oc_name_known;
100
101	if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
102		actualn = Japanese_item_name(otyp);
103	switch(ocl->oc_class) {
104	case COIN_CLASS:
105		Strcpy(buf, "coin");
106		break;
107	case POTION_CLASS:
108		Strcpy(buf, "potion");
109		break;
110	case SCROLL_CLASS:
111		Strcpy(buf, "scroll");
112		break;
113	case WAND_CLASS:
114		Strcpy(buf, "wand");
115		break;
116	case SPBOOK_CLASS:
117		Strcpy(buf, "spellbook");
118		break;
119	case RING_CLASS:
120		Strcpy(buf, "ring");
121		break;
122	case AMULET_CLASS:
123		if(nn)
124			Strcpy(buf,actualn);
125		else
126			Strcpy(buf,"amulet");
127		if(un)
128			Sprintf(eos(buf)," called %s",un);
129		if(dn)
130			Sprintf(eos(buf)," (%s)",dn);
131		return(buf);
132	default:
133		if(nn) {
134			Strcpy(buf, actualn);
135			if (GemStone(otyp))
136				Strcat(buf, " stone");
137			if(un)
138				Sprintf(eos(buf), " called %s", un);
139			if(dn)
140				Sprintf(eos(buf), " (%s)", dn);
141		} else {
142			Strcpy(buf, dn ? dn : actualn);
143			if(ocl->oc_class == GEM_CLASS)
144				Strcat(buf, (ocl->oc_material == MINERAL) ?
145						" stone" : " gem");
146			if(un)
147				Sprintf(eos(buf), " called %s", un);
148		}
149		return(buf);
150	}
151	/* here for ring/scroll/potion/wand */
152	if(nn) {
153	    if (ocl->oc_unique)
154		Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */
155	    else
156		Sprintf(eos(buf), " of %s", actualn);
157	}
158	if(un)
159		Sprintf(eos(buf), " called %s", un);
160	if(dn)
161		Sprintf(eos(buf), " (%s)", dn);
162	return(buf);
163}
164
165/* less verbose result than obj_typename(); either the actual name
166   or the description (but not both); user-assigned name is ignored */
167char *
168simple_typename(otyp)
169int otyp;
170{
171    char *bufp, *pp, *save_uname = objects[otyp].oc_uname;
172
173    objects[otyp].oc_uname = 0;		/* suppress any name given by user */
174    bufp = obj_typename(otyp);
175    objects[otyp].oc_uname = save_uname;
176    if ((pp = strstri(bufp, " (")) != 0)
177	*pp = '\0';		/* strip the appended description */
178    return bufp;
179}
180
181boolean
182obj_is_pname(obj)
183register struct obj *obj;
184{
185    return((boolean)(obj->dknown && obj->known && obj->onamelth &&
186		     /* Since there aren't any objects which are both
187		        artifacts and unique, the last check is redundant. */
188		     obj->oartifact && !objects[obj->otyp].oc_unique));
189}
190
191/* Give the name of an object seen at a distance.  Unlike xname/doname,
192 * we don't want to set dknown if it's not set already.  The kludge used is
193 * to temporarily set Blind so that xname() skips the dknown setting.  This
194 * assumes that we don't want to do this too often; if this function becomes
195 * frequently used, it'd probably be better to pass a parameter to xname()
196 * or doname() instead.
197 */
198char *
199distant_name(obj, func)
200register struct obj *obj;
201char *FDECL((*func), (OBJ_P));
202{
203	char *str;
204
205	long save_Blinded = Blinded;
206	Blinded = 1;
207	str = (*func)(obj);
208	Blinded = save_Blinded;
209	return str;
210}
211
212/* convert player specified fruit name into corresponding fruit juice name
213   ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
214char *
215fruitname(juice)
216boolean juice;	/* whether or not to append " juice" to the name */
217{
218    char *buf = nextobuf();
219    const char *fruit_nam = strstri(pl_fruit, " of ");
220
221    if (fruit_nam)
222	fruit_nam += 4;		/* skip past " of " */
223    else
224	fruit_nam = pl_fruit;	/* use it as is */
225
226    Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : "");
227    return buf;
228}
229
230#endif /* OVLB */
231#ifdef OVL1
232
233char *
234xname(obj)
235register struct obj *obj;
236{
237	register char *buf;
238	register int typ = obj->otyp;
239	register struct objclass *ocl = &objects[typ];
240	register int nn = ocl->oc_name_known;
241	register const char *actualn = OBJ_NAME(*ocl);
242	register const char *dn = OBJ_DESCR(*ocl);
243	register const char *un = ocl->oc_uname;
244
245	buf = nextobuf() + PREFIX;	/* leave room for "17 -3 " */
246	if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
247		actualn = Japanese_item_name(typ);
248
249	buf[0] = '\0';
250	/*
251	 * clean up known when it's tied to oc_name_known, eg after AD_DRIN
252	 * This is only required for unique objects since the article
253	 * printed for the object is tied to the combination of the two
254	 * and printing the wrong article gives away information.
255	 */
256	if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0;
257	if (!Blind) obj->dknown = TRUE;
258	if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
259	if (obj_is_pname(obj))
260	    goto nameit;
261	switch (obj->oclass) {
262	    case AMULET_CLASS:
263		if (!obj->dknown)
264			Strcpy(buf, "amulet");
265		else if (typ == AMULET_OF_YENDOR ||
266			 typ == FAKE_AMULET_OF_YENDOR)
267			/* each must be identified individually */
268			Strcpy(buf, obj->known ? actualn : dn);
269		else if (nn)
270			Strcpy(buf, actualn);
271		else if (un)
272			Sprintf(buf,"amulet called %s", un);
273		else
274			Sprintf(buf,"%s amulet", dn);
275		break;
276	    case WEAPON_CLASS:
277		if (is_poisonable(obj) && obj->opoisoned)
278			Strcpy(buf, "poisoned ");
279	    case VENOM_CLASS:
280	    case TOOL_CLASS:
281		if (typ == LENSES)
282			Strcpy(buf, "pair of ");
283
284		if (!obj->dknown)
285			Strcat(buf, dn ? dn : actualn);
286		else if (nn)
287			Strcat(buf, actualn);
288		else if (un) {
289			Strcat(buf, dn ? dn : actualn);
290			Strcat(buf, " called ");
291			Strcat(buf, un);
292		} else
293			Strcat(buf, dn ? dn : actualn);
294		/* If we use an() here we'd have to remember never to use */
295		/* it whenever calling doname() or xname(). */
296		if (typ == FIGURINE)
297		    Sprintf(eos(buf), " of a%s %s",
298			index(vowels,*(mons[obj->corpsenm].mname)) ? "n" : "",
299			mons[obj->corpsenm].mname);
300		break;
301	    case ARMOR_CLASS:
302		/* depends on order of the dragon scales objects */
303		if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
304			Sprintf(buf, "set of %s", actualn);
305			break;
306		}
307		if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
308
309		if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
310				&& !obj->dknown) {
311			Strcpy(buf, "shield");
312			break;
313		}
314		if(obj->otyp == SHIELD_OF_REFLECTION && !obj->dknown) {
315			Strcpy(buf, "smooth shield");
316			break;
317		}
318
319		if(nn)	Strcat(buf, actualn);
320		else if(un) {
321			if(is_boots(obj))
322				Strcat(buf,"boots");
323			else if(is_gloves(obj))
324				Strcat(buf,"gloves");
325			else if(is_cloak(obj))
326				Strcpy(buf,"cloak");
327			else if(is_helmet(obj))
328				Strcpy(buf,"helmet");
329			else if(is_shield(obj))
330				Strcpy(buf,"shield");
331			else
332				Strcpy(buf,"armor");
333			Strcat(buf, " called ");
334			Strcat(buf, un);
335		} else	Strcat(buf, dn);
336		break;
337	    case FOOD_CLASS:
338		if (typ == SLIME_MOLD) {
339			register struct fruit *f;
340
341			for(f=ffruit; f; f = f->nextf) {
342				if(f->fid == obj->spe) {
343					Strcpy(buf, f->fname);
344					break;
345				}
346			}
347			if (!f) impossible("Bad fruit #%d?", obj->spe);
348			break;
349		}
350
351		Strcpy(buf, actualn);
352		if (typ == TIN && obj->known) {
353		    if(obj->spe > 0)
354			Strcat(buf, " of spinach");
355		    else if (obj->corpsenm == NON_PM)
356		        Strcpy(buf, "empty tin");
357		    else if (vegetarian(&mons[obj->corpsenm]))
358			Sprintf(eos(buf), " of %s", mons[obj->corpsenm].mname);
359		    else
360			Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname);
361		}
362		break;
363	    case COIN_CLASS:
364	    case CHAIN_CLASS:
365		Strcpy(buf, actualn);
366		break;
367	    case ROCK_CLASS:
368		if (typ == STATUE)
369		    Sprintf(buf, "%s%s of %s%s",
370			(Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) ? "historic " : "" ,
371			actualn,
372			type_is_pname(&mons[obj->corpsenm]) ? "" :
373			  (mons[obj->corpsenm].geno & G_UNIQ) ? "the " :
374			    (index(vowels,*(mons[obj->corpsenm].mname)) ?
375								"an " : "a "),
376			mons[obj->corpsenm].mname);
377		else Strcpy(buf, actualn);
378		break;
379	    case BALL_CLASS:
380		Sprintf(buf, "%sheavy iron ball",
381			(obj->owt > ocl->oc_weight) ? "very " : "");
382		break;
383	    case POTION_CLASS:
384		if (obj->dknown && obj->odiluted)
385			Strcpy(buf, "diluted ");
386		if(nn || un || !obj->dknown) {
387			Strcat(buf, "potion");
388			if(!obj->dknown) break;
389			if(nn) {
390			    Strcat(buf, " of ");
391			    if (typ == POT_WATER &&
392				obj->bknown && (obj->blessed || obj->cursed)) {
393				Strcat(buf, obj->blessed ? "holy " : "unholy ");
394			    }
395			    Strcat(buf, actualn);
396			} else {
397				Strcat(buf, " called ");
398				Strcat(buf, un);
399			}
400		} else {
401			Strcat(buf, dn);
402			Strcat(buf, " potion");
403		}
404		break;
405	case SCROLL_CLASS:
406		Strcpy(buf, "scroll");
407		if(!obj->dknown) break;
408		if(nn) {
409			Strcat(buf, " of ");
410			Strcat(buf, actualn);
411		} else if(un) {
412			Strcat(buf, " called ");
413			Strcat(buf, un);
414		} else if (ocl->oc_magic) {
415			Strcat(buf, " labeled ");
416			Strcat(buf, dn);
417		} else {
418			Strcpy(buf, dn);
419			Strcat(buf, " scroll");
420		}
421		break;
422	case WAND_CLASS:
423		if(!obj->dknown)
424			Strcpy(buf, "wand");
425		else if(nn)
426			Sprintf(buf, "wand of %s", actualn);
427		else if(un)
428			Sprintf(buf, "wand called %s", un);
429		else
430			Sprintf(buf, "%s wand", dn);
431		break;
432	case SPBOOK_CLASS:
433		if (!obj->dknown) {
434			Strcpy(buf, "spellbook");
435		} else if (nn) {
436			if (typ != SPE_BOOK_OF_THE_DEAD)
437			    Strcpy(buf, "spellbook of ");
438			Strcat(buf, actualn);
439		} else if (un) {
440			Sprintf(buf, "spellbook called %s", un);
441		} else
442			Sprintf(buf, "%s spellbook", dn);
443		break;
444	case RING_CLASS:
445		if(!obj->dknown)
446			Strcpy(buf, "ring");
447		else if(nn)
448			Sprintf(buf, "ring of %s", actualn);
449		else if(un)
450			Sprintf(buf, "ring called %s", un);
451		else
452			Sprintf(buf, "%s ring", dn);
453		break;
454	case GEM_CLASS:
455	    {
456		const char *rock =
457			    (ocl->oc_material == MINERAL) ? "stone" : "gem";
458		if (!obj->dknown) {
459		    Strcpy(buf, rock);
460		} else if (!nn) {
461		    if (un) Sprintf(buf,"%s called %s", rock, un);
462		    else Sprintf(buf, "%s %s", dn, rock);
463		} else {
464		    Strcpy(buf, actualn);
465		    if (GemStone(typ)) Strcat(buf, " stone");
466		}
467		break;
468	    }
469	default:
470		Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe);
471	}
472	if (obj->quan != 1L) Strcpy(buf, makeplural(buf));
473
474	if (obj->onamelth && obj->dknown) {
475		Strcat(buf, " named ");
476nameit:
477		Strcat(buf, ONAME(obj));
478	}
479
480	if (!strncmpi(buf, "the ", 4)) buf += 4;
481	return(buf);
482}
483
484/* xname() output augmented for multishot missile feedback */
485char *
486mshot_xname(obj)
487struct obj *obj;
488{
489    char tmpbuf[BUFSZ];
490    char *onm = xname(obj);
491
492    if (m_shot.n > 1 && m_shot.o == obj->otyp) {
493	/* copy xname's result so that we can reuse its return buffer */
494	Strcpy(tmpbuf, onm);
495	/* "the Nth arrow"; value will eventually be passed to an() or
496	   The(), both of which correctly handle this "the " prefix */
497	Sprintf(onm, "the %d%s %s", m_shot.i, ordin(m_shot.i), tmpbuf);
498    }
499
500    return onm;
501}
502
503#endif /* OVL1 */
504#ifdef OVL0
505
506/* used for naming "the unique_item" instead of "a unique_item" */
507boolean
508the_unique_obj(obj)
509register struct obj *obj;
510{
511    if (!obj->dknown)
512	return FALSE;
513    else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known)
514	return TRUE;		/* lie */
515    else
516	return (boolean)(objects[obj->otyp].oc_unique &&
517			 (obj->known || obj->otyp == AMULET_OF_YENDOR));
518}
519
520static void
521add_erosion_words(obj,prefix)
522struct obj *obj;
523char *prefix;
524{
525	boolean iscrys = (obj->otyp == CRYSKNIFE);
526
527
528	if (!is_damageable(obj) && !iscrys) return;
529
530	/* The only cases where any of these bits do double duty are for
531	 * rotted food and diluted potions, which are all not is_damageable().
532	 */
533	if (obj->oeroded && !iscrys) {
534		switch (obj->oeroded) {
535			case 2:	Strcat(prefix, "very "); break;
536			case 3:	Strcat(prefix, "thoroughly "); break;
537		}
538		Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt ");
539	}
540	if (obj->oeroded2 && !iscrys) {
541		switch (obj->oeroded2) {
542			case 2:	Strcat(prefix, "very "); break;
543			case 3:	Strcat(prefix, "thoroughly "); break;
544		}
545		Strcat(prefix, is_corrodeable(obj) ? "corroded " :
546			"rotted ");
547	}
548	if (obj->rknown && obj->oerodeproof)
549		Strcat(prefix,
550		       iscrys ? "fixed " :
551		       is_rustprone(obj) ? "rustproof " :
552		       is_corrodeable(obj) ? "corrodeproof " :	/* "stainless"? */
553		       is_flammable(obj) ? "fireproof " : "");
554}
555
556char *
557doname(obj)
558register struct obj *obj;
559{
560	boolean ispoisoned = FALSE;
561	char prefix[PREFIX];
562	char tmpbuf[PREFIX+1];
563	/* when we have to add something at the start of prefix instead of the
564	 * end (Strcat is used on the end)
565	 */
566	register char *bp = xname(obj);
567
568	/* When using xname, we want "poisoned arrow", and when using
569	 * doname, we want "poisoned +0 arrow".  This kludge is about the only
570	 * way to do it, at least until someone overhauls xname() and doname(),
571	 * combining both into one function taking a parameter.
572	 */
573	/* must check opoisoned--someone can have a weirdly-named fruit */
574	if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
575		bp += 9;
576		ispoisoned = TRUE;
577	}
578
579	if(obj->quan != 1L)
580		Sprintf(prefix, "%ld ", obj->quan);
581	else if (obj_is_pname(obj) || the_unique_obj(obj)) {
582		if (!strncmpi(bp, "the ", 4))
583		    bp += 4;
584		Strcpy(prefix, "the ");
585	} else
586		Strcpy(prefix, "a ");
587
588#ifdef INVISIBLE_OBJECTS
589	if (obj->oinvis) Strcat(prefix,"invisible ");
590#endif
591
592	if (obj->bknown &&
593	    obj->oclass != COIN_CLASS &&
594	    (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
595		|| (!obj->cursed && !obj->blessed))) {
596	    /* allow 'blessed clear potion' if we don't know it's holy water;
597	     * always allow "uncursed potion of water"
598	     */
599	    if (obj->cursed)
600		Strcat(prefix, "cursed ");
601	    else if (obj->blessed)
602		Strcat(prefix, "blessed ");
603	    else if ((!obj->known || !objects[obj->otyp].oc_charged ||
604		      (obj->oclass == ARMOR_CLASS ||
605		       obj->oclass == RING_CLASS))
606		/* For most items with charges or +/-, if you know how many
607		 * charges are left or what the +/- is, then you must have
608		 * totally identified the item, so "uncursed" is unneccesary,
609		 * because an identified object not described as "blessed" or
610		 * "cursed" must be uncursed.
611		 *
612		 * If the charges or +/- is not known, "uncursed" must be
613		 * printed to avoid ambiguity between an item whose curse
614		 * status is unknown, and an item known to be uncursed.
615		 */
616#ifdef MAIL
617			&& obj->otyp != SCR_MAIL
618#endif
619			&& obj->otyp != FAKE_AMULET_OF_YENDOR
620			&& obj->otyp != AMULET_OF_YENDOR
621			&& !Role_if(PM_PRIEST))
622		Strcat(prefix, "uncursed ");
623	}
624
625	if (obj->greased) Strcat(prefix, "greased ");
626
627	switch(obj->oclass) {
628	case AMULET_CLASS:
629		if(obj->owornmask & W_AMUL)
630			Strcat(bp, " (being worn)");
631		break;
632	case WEAPON_CLASS:
633		if(ispoisoned)
634			Strcat(prefix, "poisoned ");
635plus:
636		add_erosion_words(obj, prefix);
637		if(obj->known) {
638			Strcat(prefix, sitoa(obj->spe));
639			Strcat(prefix, " ");
640		}
641		break;
642	case ARMOR_CLASS:
643		if(obj->owornmask & W_ARMOR)
644			Strcat(bp, (obj == uskin) ? " (embedded in your skin)" :
645				" (being worn)");
646		goto plus;
647	case TOOL_CLASS:
648		/* weptools already get this done when we go to the +n code */
649		if (!is_weptool(obj))
650		    add_erosion_words(obj, prefix);
651		if(obj->owornmask & (W_TOOL /* blindfold */
652#ifdef STEED
653				| W_SADDLE
654#endif
655				)) {
656			Strcat(bp, " (being worn)");
657			break;
658		}
659		if (obj->otyp == LEASH && obj->leashmon != 0) {
660			Strcat(bp, " (in use)");
661			break;
662		}
663		if (is_weptool(obj))
664			goto plus;
665		if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
666			if (!obj->spe)
667			    Strcpy(tmpbuf, "no");
668			else
669			    Sprintf(tmpbuf, "%d", obj->spe);
670			Sprintf(eos(bp), " (%s candle%s%s)",
671				tmpbuf, plur(obj->spe),
672				!obj->lamplit ? " attached" : ", lit");
673			break;
674		} else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
675			obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
676			if (Is_candle(obj) &&
677			    obj->age < 20L * (long)objects[obj->otyp].oc_cost)
678				Strcat(prefix, "partly used ");
679			if(obj->lamplit)
680				Strcat(bp, " (lit)");
681			break;
682		}
683		if(objects[obj->otyp].oc_charged)
684		    goto charges;
685		break;
686	case WAND_CLASS:
687		add_erosion_words(obj, prefix);
688charges:
689		if(obj->known)
690		    Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe);
691		break;
692	case POTION_CLASS:
693		if (obj->otyp == POT_OIL && obj->lamplit)
694		    Strcat(bp, " (lit)");
695		break;
696	case RING_CLASS:
697		add_erosion_words(obj, prefix);
698ring:
699		if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
700		if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
701		if(obj->owornmask & W_RING) {
702		    Strcat(bp, body_part(HAND));
703		    Strcat(bp, ")");
704		}
705		if(obj->known && objects[obj->otyp].oc_charged) {
706			Strcat(prefix, sitoa(obj->spe));
707			Strcat(prefix, " ");
708		}
709		break;
710	case FOOD_CLASS:
711		if (obj->oeaten)
712		    Strcat(prefix, "partly eaten ");
713		if (obj->otyp == CORPSE) {
714		    if (mons[obj->corpsenm].geno & G_UNIQ) {
715			Sprintf(prefix, "%s%s ",
716				(type_is_pname(&mons[obj->corpsenm]) ?
717					"" : "the "),
718				s_suffix(mons[obj->corpsenm].mname));
719			if (obj->oeaten) Strcat(prefix, "partly eaten ");
720		    } else {
721			Strcat(prefix, mons[obj->corpsenm].mname);
722			Strcat(prefix, " ");
723		    }
724		} else if (obj->otyp == EGG) {
725#if 0	/* corpses don't tell if they're stale either */
726		    if (obj->known && stale_egg(obj))
727			Strcat(prefix, "stale ");
728#endif
729		    if (obj->corpsenm >= LOW_PM &&
730			    (obj->known ||
731			    mvitals[obj->corpsenm].mvflags & MV_KNOWS_EGG)) {
732			Strcat(prefix, mons[obj->corpsenm].mname);
733			Strcat(prefix, " ");
734			if (obj->spe)
735			    Strcat(bp, " (laid by you)");
736		    }
737		}
738		if (obj->otyp == MEAT_RING) goto ring;
739		break;
740	case BALL_CLASS:
741	case CHAIN_CLASS:
742		add_erosion_words(obj, prefix);
743		if(obj->owornmask & W_BALL)
744			Strcat(bp, " (chained to you)");
745			break;
746	}
747
748	if((obj->owornmask & W_WEP) && !mrg_to_wielded) {
749		if (obj->quan != 1L) {
750			Strcat(bp, " (wielded)");
751		} else {
752			const char *hand_s = body_part(HAND);
753
754			if (bimanual(obj)) hand_s = makeplural(hand_s);
755			Sprintf(eos(bp), " (weapon in %s)", hand_s);
756		}
757	}
758	if(obj->owornmask & W_SWAPWEP) {
759		if (u.twoweap)
760			Sprintf(eos(bp), " (wielded in other %s)",
761				body_part(HAND));
762		else
763			Strcat(bp, " (alternate weapon; not wielded)");
764	}
765	if(obj->owornmask & W_QUIVER) Strcat(bp, " (in quiver)");
766	if(obj->unpaid) {
767		xchar ox, oy;
768		long quotedprice = unpaid_cost(obj);
769		struct monst *shkp = (struct monst *)0;
770
771		if (Has_contents(obj) &&
772		    get_obj_location(obj, &ox, &oy, BURIED_TOO|CONTAINED_TOO) &&
773		    costly_spot(ox, oy) &&
774		    (shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))))
775			quotedprice += contained_cost(obj, shkp, 0L, FALSE, TRUE);
776		Sprintf(eos(bp), " (unpaid, %ld %s)",
777			quotedprice, currency(quotedprice));
778	}
779	if (!strncmp(prefix, "a ", 2) &&
780			index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
781			&& (*(prefix+2) || (strncmp(bp, "uranium", 7)
782				&& strncmp(bp, "unicorn", 7)
783				&& strncmp(bp, "eucalyptus", 10)))) {
784		Strcpy(tmpbuf, prefix);
785		Strcpy(prefix, "an ");
786		Strcpy(prefix+3, tmpbuf+2);
787	}
788	bp = strprepend(bp, prefix);
789	return(bp);
790}
791
792#endif /* OVL0 */
793#ifdef OVLB
794
795/* used from invent.c */
796boolean
797not_fully_identified(otmp)
798register struct obj *otmp;
799{
800#ifdef GOLDOBJ
801    /* gold doesn't have any interesting attributes [yet?] */
802    if (otmp->oclass == COIN_CLASS) return FALSE;	/* always fully ID'd */
803#endif
804    /* check fundamental ID hallmarks first */
805    if (!otmp->known || !otmp->dknown ||
806#ifdef MAIL
807	    (!otmp->bknown && otmp->otyp != SCR_MAIL) ||
808#else
809	    !otmp->bknown ||
810#endif
811	    !objects[otmp->otyp].oc_name_known)	/* ?redundant? */
812	return TRUE;
813    if (otmp->oartifact && undiscovered_artifact(otmp->oartifact))
814	return TRUE;
815    /* otmp->rknown is the only item of interest if we reach here */
816       /*
817	*  Note:  if a revision ever allows scrolls to become fireproof or
818	*  rings to become shockproof, this checking will need to be revised.
819	*  `rknown' ID only matters if xname() will provide the info about it.
820	*/
821    if (otmp->rknown || (otmp->oclass != ARMOR_CLASS &&
822			 otmp->oclass != WEAPON_CLASS &&
823			 !is_weptool(otmp) &&		    /* (redunant) */
824			 otmp->oclass != BALL_CLASS))	    /* (useless) */
825	return FALSE;
826    else	/* lack of `rknown' only matters for vulnerable objects */
827	return (boolean)(is_rustprone(otmp) ||
828			 is_corrodeable(otmp) ||
829			 is_flammable(otmp));
830}
831
832char *
833corpse_xname(otmp, ignore_oquan)
834struct obj *otmp;
835boolean ignore_oquan;	/* to force singular */
836{
837	char *nambuf = nextobuf();
838
839	Sprintf(nambuf, "%s corpse", mons[otmp->corpsenm].mname);
840
841	if (ignore_oquan || otmp->quan < 2)
842	    return nambuf;
843	else
844	    return makeplural(nambuf);
845}
846
847/* xname, unless it's a corpse, then corpse_xname(obj, FALSE) */
848char *
849cxname(obj)
850struct obj *obj;
851{
852	if (obj->otyp == CORPSE)
853	    return corpse_xname(obj, FALSE);
854	return xname(obj);
855}
856
857/* treat an object as fully ID'd when it might be used as reason for death */
858char *
859killer_xname(obj)
860struct obj *obj;
861{
862    struct obj save_obj;
863    unsigned save_ocknown;
864    char *buf, *save_ocuname;
865
866    /* remember original settings for core of the object;
867       oname and oattached extensions don't matter here--since they
868       aren't modified they don't need to be saved and restored */
869    save_obj = *obj;
870    /* killer name should be more specific than general xname; however, exact
871       info like blessed/cursed and rustproof makes things be too verbose */
872    obj->known = obj->dknown = 1;
873    obj->bknown = obj->rknown = obj->greased = 0;
874    /* if character is a priest[ess], bknown will get toggled back on */
875    obj->blessed = obj->cursed = 0;
876    /* "killed by poisoned <obj>" would be misleading when poison is
877       not the cause of death and "poisoned by poisoned <obj>" would
878       be redundant when it is, so suppress "poisoned" prefix */
879    obj->opoisoned = 0;
880    /* strip user-supplied name; artifacts keep theirs */
881    if (!obj->oartifact) obj->onamelth = 0;
882    /* temporarily identify the type of object */
883    save_ocknown = objects[obj->otyp].oc_name_known;
884    objects[obj->otyp].oc_name_known = 1;
885    save_ocuname = objects[obj->otyp].oc_uname;
886    objects[obj->otyp].oc_uname = 0;	/* avoid "foo called bar" */
887
888    buf = xname(obj);
889    if (obj->quan == 1L) buf = obj_is_pname(obj) ? the(buf) : an(buf);
890
891    objects[obj->otyp].oc_name_known = save_ocknown;
892    objects[obj->otyp].oc_uname = save_ocuname;
893    *obj = save_obj;	/* restore object's core settings */
894
895    return buf;
896}
897
898/*
899 * Used if only one of a collection of objects is named (e.g. in eat.c).
900 */
901const char *
902singular(otmp, func)
903register struct obj *otmp;
904char *FDECL((*func), (OBJ_P));
905{
906	long savequan;
907	char *nam;
908
909	/* Note: using xname for corpses will not give the monster type */
910	if (otmp->otyp == CORPSE && func == xname)
911		return corpse_xname(otmp, TRUE);
912
913	savequan = otmp->quan;
914	otmp->quan = 1L;
915	nam = (*func)(otmp);
916	otmp->quan = savequan;
917	return nam;
918}
919
920char *
921an(str)
922register const char *str;
923{
924	char *buf = nextobuf();
925
926	buf[0] = '\0';
927
928	if (strncmpi(str, "the ", 4) &&
929	    strcmp(str, "molten lava") &&
930	    strcmp(str, "iron bars") &&
931	    strcmp(str, "ice")) {
932		if (index(vowels, *str) &&
933		    strncmp(str, "one-", 4) &&
934		    strncmp(str, "useful", 6) &&
935		    strncmp(str, "unicorn", 7) &&
936		    strncmp(str, "uranium", 7) &&
937		    strncmp(str, "eucalyptus", 10))
938			Strcpy(buf, "an ");
939		else
940			Strcpy(buf, "a ");
941	}
942
943	Strcat(buf, str);
944	return buf;
945}
946
947char *
948An(str)
949const char *str;
950{
951	register char *tmp = an(str);
952	*tmp = highc(*tmp);
953	return tmp;
954}
955
956/*
957 * Prepend "the" if necessary; assumes str is a subject derived from xname.
958 * Use type_is_pname() for monster names, not the().  the() is idempotent.
959 */
960char *
961the(str)
962const char *str;
963{
964	char *buf = nextobuf();
965	boolean insert_the = FALSE;
966
967	if (!strncmpi(str, "the ", 4)) {
968	    buf[0] = lowc(*str);
969	    Strcpy(&buf[1], str+1);
970	    return buf;
971	} else if (*str < 'A' || *str > 'Z') {
972	    /* not a proper name, needs an article */
973	    insert_the = TRUE;
974	} else {
975	    /* Probably a proper name, might not need an article */
976	    register char *tmp, *named, *called;
977	    int l;
978
979	    /* some objects have capitalized adjectives in their names */
980	    if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) &&
981	       (tmp[1] < 'A' || tmp[1] > 'Z'))
982		insert_the = TRUE;
983	    else if (tmp && index(str, ' ') < tmp) {	/* has spaces */
984		/* it needs an article if the name contains "of" */
985		tmp = strstri(str, " of ");
986		named = strstri(str, " named ");
987		called = strstri(str, " called ");
988		if (called && (!named || called < named)) named = called;
989
990		if (tmp && (!named || tmp < named))	/* found an "of" */
991		    insert_the = TRUE;
992		/* stupid special case: lacks "of" but needs "the" */
993		else if (!named && (l = strlen(str)) >= 31 &&
994		      !strcmp(&str[l - 31], "Platinum Yendorian Express Card"))
995		    insert_the = TRUE;
996	    }
997	}
998	if (insert_the)
999	    Strcpy(buf, "the ");
1000	else
1001	    buf[0] = '\0';
1002	Strcat(buf, str);
1003
1004	return buf;
1005}
1006
1007char *
1008The(str)
1009const char *str;
1010{
1011    register char *tmp = the(str);
1012    *tmp = highc(*tmp);
1013    return tmp;
1014}
1015
1016/* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
1017char *
1018aobjnam(otmp,verb)
1019register struct obj *otmp;
1020register const char *verb;
1021{
1022	register char *bp = cxname(otmp);
1023	char prefix[PREFIX];
1024
1025	if(otmp->quan != 1L) {
1026		Sprintf(prefix, "%ld ", otmp->quan);
1027		bp = strprepend(bp, prefix);
1028	}
1029
1030	if(verb) {
1031	    Strcat(bp, " ");
1032	    Strcat(bp, otense(otmp, verb));
1033	}
1034	return(bp);
1035}
1036
1037/* like aobjnam, but prepend "The", not count, and use xname */
1038char *
1039Tobjnam(otmp, verb)
1040register struct obj *otmp;
1041register const char *verb;
1042{
1043	char *bp = The(xname(otmp));
1044
1045	if(verb) {
1046	    Strcat(bp, " ");
1047	    Strcat(bp, otense(otmp, verb));
1048	}
1049	return(bp);
1050}
1051
1052/* return form of the verb (input plural) if xname(otmp) were the subject */
1053char *
1054otense(otmp, verb)
1055register struct obj *otmp;
1056register const char *verb;
1057{
1058	char *buf;
1059
1060	/*
1061	 * verb is given in plural (without trailing s).  Return as input
1062	 * if the result of xname(otmp) would be plural.  Don't bother
1063	 * recomputing xname(otmp) at this time.
1064	 */
1065	if (!is_plural(otmp))
1066	    return vtense((char *)0, verb);
1067
1068	buf = nextobuf();
1069	Strcpy(buf, verb);
1070	return buf;
1071}
1072
1073/* various singular words that vtense would otherwise categorize as plural */
1074static const char * const special_subjs[] = {
1075	"erinys",
1076	"manes",		/* this one is ambiguous */
1077	"Cyclops",
1078	"Hippocrates",
1079	"Pelias",
1080	"aklys",
1081	"amnesia",
1082	"paralysis",
1083	0
1084};
1085
1086/* return form of the verb (input plural) for present tense 3rd person subj */
1087char *
1088vtense(subj, verb)
1089register const char *subj;
1090register const char *verb;
1091{
1092	char *buf = nextobuf();
1093	int len, ltmp;
1094	const char *sp, *spot;
1095	const char * const *spec;
1096
1097	/*
1098	 * verb is given in plural (without trailing s).  Return as input
1099	 * if subj appears to be plural.  Add special cases as necessary.
1100	 * Many hard cases can already be handled by using otense() instead.
1101	 * If this gets much bigger, consider decomposing makeplural.
1102	 * Note: monster names are not expected here (except before corpse).
1103	 *
1104	 * special case: allow null sobj to get the singular 3rd person
1105	 * present tense form so we don't duplicate this code elsewhere.
1106	 */
1107	if (subj) {
1108	    if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3))
1109		goto sing;
1110	    spot = (const char *)0;
1111	    for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) {
1112		if (!strncmp(sp, " of ", 4) ||
1113		    !strncmp(sp, " from ", 6) ||
1114		    !strncmp(sp, " called ", 8) ||
1115		    !strncmp(sp, " named ", 7) ||
1116		    !strncmp(sp, " labeled ", 9)) {
1117		    if (sp != subj) spot = sp - 1;
1118		    break;
1119		}
1120	    }
1121	    len = (int) strlen(subj);
1122	    if (!spot) spot = subj + len - 1;
1123
1124	    /*
1125	     * plural: anything that ends in 's', but not '*us' or '*ss'.
1126	     * Guess at a few other special cases that makeplural creates.
1127	     */
1128	    if ((*spot == 's' && spot != subj &&
1129			(*(spot-1) != 'u' && *(spot-1) != 's')) ||
1130		((spot - subj) >= 4 && !strncmp(spot-3, "eeth", 4)) ||
1131		((spot - subj) >= 3 && !strncmp(spot-3, "feet", 4)) ||
1132		((spot - subj) >= 2 && !strncmp(spot-1, "ia", 2)) ||
1133		((spot - subj) >= 2 && !strncmp(spot-1, "ae", 2))) {
1134		/* check for special cases to avoid false matches */
1135		len = (int)(spot - subj) + 1;
1136		for (spec = special_subjs; *spec; spec++) {
1137		    ltmp = strlen(*spec);
1138		    if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing;
1139		    /* also check for <prefix><space><special_subj>
1140		       to catch things like "the invisible erinys" */
1141		    if (len > ltmp && *(spot - ltmp) == ' ' &&
1142			   !strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing;
1143		}
1144
1145		return strcpy(buf, verb);
1146	    }
1147	    /*
1148	     * 3rd person plural doesn't end in telltale 's';
1149	     * 2nd person singular behaves as if plural.
1150	     */
1151	    if (!strcmpi(subj, "they") || !strcmpi(subj, "you"))
1152		return strcpy(buf, verb);
1153	}
1154
1155 sing:
1156	len = strlen(verb);
1157	spot = verb + len - 1;
1158
1159	if (!strcmp(verb, "are"))
1160	    Strcpy(buf, "is");
1161	else if (!strcmp(verb, "have"))
1162	    Strcpy(buf, "has");
1163	else if (index("zxs", *spot) ||
1164		 (len >= 2 && *spot=='h' && index("cs", *(spot-1))) ||
1165		 (len == 2 && *spot == 'o')) {
1166	    /* Ends in z, x, s, ch, sh; add an "es" */
1167	    Strcpy(buf, verb);
1168	    Strcat(buf, "es");
1169	} else if (*spot == 'y' && (!index(vowels, *(spot-1)))) {
1170	    /* like "y" case in makeplural */
1171	    Strcpy(buf, verb);
1172	    Strcpy(buf + len - 1, "ies");
1173	} else {
1174	    Strcpy(buf, verb);
1175	    Strcat(buf, "s");
1176	}
1177
1178	return buf;
1179}
1180
1181/* capitalized variant of doname() */
1182char *
1183Doname2(obj)
1184register struct obj *obj;
1185{
1186	register char *s = doname(obj);
1187
1188	*s = highc(*s);
1189	return(s);
1190}
1191
1192/* returns "your xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
1193char *
1194yname(obj)
1195struct obj *obj;
1196{
1197	char *outbuf = nextobuf();
1198	char *s = shk_your(outbuf, obj);	/* assert( s == outbuf ); */
1199	int space_left = BUFSZ - strlen(s) - sizeof " ";
1200
1201	return strncat(strcat(s, " "), cxname(obj), space_left);
1202}
1203
1204/* capitalized variant of yname() */
1205char *
1206Yname2(obj)
1207struct obj *obj;
1208{
1209	char *s = yname(obj);
1210
1211	*s = highc(*s);
1212	return s;
1213}
1214
1215/* returns "your simple_typename(obj->otyp)"
1216 * or "Foobar's simple_typename(obj->otyp)"
1217 * or "the simple_typename(obj-otyp)"
1218 */
1219char *
1220ysimple_name(obj)
1221struct obj *obj;
1222{
1223	char *outbuf = nextobuf();
1224	char *s = shk_your(outbuf, obj);	/* assert( s == outbuf ); */
1225	int space_left = BUFSZ - strlen(s) - sizeof " ";
1226
1227	return strncat(strcat(s, " "), simple_typename(obj->otyp), space_left);
1228}
1229
1230/* capitalized variant of ysimple_name() */
1231char *
1232Ysimple_name2(obj)
1233struct obj *obj;
1234{
1235	char *s = ysimple_name(obj);
1236
1237	*s = highc(*s);
1238	return s;
1239}
1240
1241static const char *wrp[] = {
1242	"wand", "ring", "potion", "scroll", "gem", "amulet",
1243	"spellbook", "spell book",
1244	/* for non-specific wishes */
1245	"weapon", "armor", "armour", "tool", "food", "comestible",
1246};
1247static const char wrpsym[] = {
1248	WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS,
1249	AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS,
1250	WEAPON_CLASS, ARMOR_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
1251	FOOD_CLASS
1252};
1253
1254#endif /* OVLB */
1255#ifdef OVL0
1256
1257/* Plural routine; chiefly used for user-defined fruits.  We have to try to
1258 * account for everything reasonable the player has; something unreasonable
1259 * can still break the code.  However, it's still a lot more accurate than
1260 * "just add an s at the end", which Rogue uses...
1261 *
1262 * Also used for plural monster names ("Wiped out all homunculi.")
1263 * and body parts.
1264 *
1265 * Also misused by muse.c to convert 1st person present verbs to 2nd person.
1266 */
1267char *
1268makeplural(oldstr)
1269const char *oldstr;
1270{
1271	/* Note: cannot use strcmpi here -- it'd give MATZot, CAVEMeN,... */
1272	register char *spot;
1273	char *str = nextobuf();
1274	const char *excess = (char *)0;
1275	int len;
1276
1277	while (*oldstr==' ') oldstr++;
1278	if (!oldstr || !*oldstr) {
1279		impossible("plural of null?");
1280		Strcpy(str, "s");
1281		return str;
1282	}
1283	Strcpy(str, oldstr);
1284
1285	/*
1286	 * Skip changing "pair of" to "pairs of".  According to Webster, usual
1287	 * English usage is use pairs for humans, e.g. 3 pairs of dancers,
1288	 * and pair for objects and non-humans, e.g. 3 pair of boots.  We don't
1289	 * refer to pairs of humans in this game so just skip to the bottom.
1290	 */
1291	if (!strncmp(str, "pair of ", 8))
1292		goto bottom;
1293
1294	/* Search for common compounds, ex. lump of royal jelly */
1295	for(spot=str; *spot; spot++) {
1296		if (!strncmp(spot, " of ", 4)
1297				|| !strncmp(spot, " labeled ", 9)
1298				|| !strncmp(spot, " called ", 8)
1299				|| !strncmp(spot, " named ", 7)
1300				|| !strcmp(spot, " above") /* lurkers above */
1301				|| !strncmp(spot, " versus ", 8)
1302				|| !strncmp(spot, " from ", 6)
1303				|| !strncmp(spot, " in ", 4)
1304				|| !strncmp(spot, " on ", 4)
1305				|| !strncmp(spot, " a la ", 6)
1306				|| !strncmp(spot, " with", 5)	/* " with "? */
1307				|| !strncmp(spot, " de ", 4)
1308				|| !strncmp(spot, " d'", 3)
1309				|| !strncmp(spot, " du ", 4)) {
1310			excess = oldstr + (int) (spot - str);
1311			*spot = 0;
1312			break;
1313		}
1314	}
1315	spot--;
1316	while (*spot==' ') spot--; /* Strip blanks from end */
1317	*(spot+1) = 0;
1318	/* Now spot is the last character of the string */
1319
1320	len = strlen(str);
1321
1322	/* Single letters */
1323	if (len==1 || !letter(*spot)) {
1324		Strcpy(spot+1, "'s");
1325		goto bottom;
1326	}
1327
1328	/* Same singular and plural; mostly Japanese words except for "manes" */
1329	if ((len == 2 && !strcmp(str, "ya")) ||
1330	    (len >= 2 && !strcmp(spot-1, "ai")) || /* samurai, Uruk-hai */
1331	    (len >= 3 && !strcmp(spot-2, " ya")) ||
1332	    (len >= 4 &&
1333	     (!strcmp(spot-3, "fish") || !strcmp(spot-3, "tuna") ||
1334	      !strcmp(spot-3, "deer") || !strcmp(spot-3, "yaki"))) ||
1335	    (len >= 5 && (!strcmp(spot-4, "sheep") ||
1336			!strcmp(spot-4, "ninja") ||
1337			!strcmp(spot-4, "ronin") ||
1338			!strcmp(spot-4, "shito") ||
1339			!strcmp(spot-7, "shuriken") ||
1340			!strcmp(spot-4, "tengu") ||
1341			!strcmp(spot-4, "manes"))) ||
1342	    (len >= 6 && !strcmp(spot-5, "ki-rin")) ||
1343	    (len >= 7 && !strcmp(spot-6, "gunyoki")))
1344		goto bottom;
1345
1346	/* man/men ("Wiped out all cavemen.") */
1347	if (len >= 3 && !strcmp(spot-2, "man") &&
1348			(len<6 || strcmp(spot-5, "shaman")) &&
1349			(len<5 || strcmp(spot-4, "human"))) {
1350		*(spot-1) = 'e';
1351		goto bottom;
1352	}
1353
1354	/* tooth/teeth */
1355	if (len >= 5 && !strcmp(spot-4, "tooth")) {
1356		Strcpy(spot-3, "eeth");
1357		goto bottom;
1358	}
1359
1360	/* knife/knives, etc... */
1361	if (!strcmp(spot-1, "fe")) {
1362		Strcpy(spot-1, "ves");
1363		goto bottom;
1364	} else if (*spot == 'f') {
1365		if (index("lr", *(spot-1)) || index(vowels, *(spot-1))) {
1366			Strcpy(spot, "ves");
1367			goto bottom;
1368		} else if (len >= 5 && !strncmp(spot-4, "staf", 4)) {
1369			Strcpy(spot-1, "ves");
1370			goto bottom;
1371		}
1372	}
1373
1374	/* foot/feet (body part) */
1375	if (len >= 4 && !strcmp(spot-3, "foot")) {
1376		Strcpy(spot-2, "eet");
1377		goto bottom;
1378	}
1379
1380	/* ium/ia (mycelia, baluchitheria) */
1381	if (len >= 3 && !strcmp(spot-2, "ium")) {
1382		*(spot--) = (char)0;
1383		*spot = 'a';
1384		goto bottom;
1385	}
1386
1387	/* algae, larvae, hyphae (another fungus part) */
1388	if ((len >= 4 && !strcmp(spot-3, "alga")) ||
1389	    (len >= 5 &&
1390	     (!strcmp(spot-4, "hypha") || !strcmp(spot-4, "larva")))) {
1391		Strcpy(spot, "ae");
1392		goto bottom;
1393	}
1394
1395	/* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */
1396	if (len > 3 && !strcmp(spot-1, "us") &&
1397	    (len < 5 || (strcmp(spot-4, "lotus") &&
1398			 (len < 6 || strcmp(spot-5, "wumpus"))))) {
1399		*(spot--) = (char)0;
1400		*spot = 'i';
1401		goto bottom;
1402	}
1403
1404	/* vortex/vortices */
1405	if (len >= 6 && !strcmp(spot-3, "rtex")) {
1406		Strcpy(spot-1, "ices");
1407		goto bottom;
1408	}
1409
1410	/* djinni/djinn (note: also efreeti/efreet) */
1411	if (len >= 6 && !strcmp(spot-5, "djinni")) {
1412		*spot = (char)0;
1413		goto bottom;
1414	}
1415
1416	/* mumak/mumakil */
1417	if (len >= 5 && !strcmp(spot-4, "mumak")) {
1418		Strcpy(spot+1, "il");
1419		goto bottom;
1420	}
1421
1422	/* sis/ses (nemesis) */
1423	if (len >= 3 && !strcmp(spot-2, "sis")) {
1424		*(spot-1) = 'e';
1425		goto bottom;
1426	}
1427
1428	/* erinys/erinyes */
1429	if (len >= 6 && !strcmp(spot-5, "erinys")) {
1430		Strcpy(spot, "es");
1431		goto bottom;
1432	}
1433
1434	/* mouse/mice,louse/lice (not a monster, but possible in food names) */
1435	if (len >= 5 && !strcmp(spot-3, "ouse") && index("MmLl", *(spot-4))) {
1436		Strcpy(spot-3, "ice");
1437		goto bottom;
1438	}
1439
1440	/* matzoh/matzot, possible food name */
1441	if (len >= 6 && (!strcmp(spot-5, "matzoh")
1442					|| !strcmp(spot-5, "matzah"))) {
1443		Strcpy(spot-1, "ot");
1444		goto bottom;
1445	}
1446	if (len >= 5 && (!strcmp(spot-4, "matzo")
1447					|| !strcmp(spot-5, "matza"))) {
1448		Strcpy(spot, "ot");
1449		goto bottom;
1450	}
1451
1452	/* child/children (for wise guys who give their food funny names) */
1453	if (len >= 5 && !strcmp(spot-4, "child")) {
1454		Strcpy(spot, "dren");
1455		goto bottom;
1456	}
1457
1458	/* note: -eau/-eaux (gateau, bordeau...) */
1459	/* note: ox/oxen, VAX/VAXen, goose/geese */
1460
1461	/* Ends in z, x, s, ch, sh; add an "es" */
1462	if (index("zxs", *spot)
1463			|| (len >= 2 && *spot=='h' && index("cs", *(spot-1)))
1464	/* Kludge to get "tomatoes" and "potatoes" right */
1465			|| (len >= 4 && !strcmp(spot-2, "ato"))) {
1466		Strcpy(spot+1, "es");
1467		goto bottom;
1468	}
1469
1470	/* Ends in y preceded by consonant (note: also "qu") change to "ies" */
1471	if (*spot == 'y' &&
1472	    (!index(vowels, *(spot-1)))) {
1473		Strcpy(spot, "ies");
1474		goto bottom;
1475	}
1476
1477	/* Default: append an 's' */
1478	Strcpy(spot+1, "s");
1479
1480bottom:	if (excess) Strcpy(eos(str), excess);
1481	return str;
1482}
1483
1484#endif /* OVL0 */
1485
1486struct o_range {
1487	const char *name, oclass;
1488	int  f_o_range, l_o_range;
1489};
1490
1491#ifndef OVLB
1492
1493STATIC_DCL const struct o_range o_ranges[];
1494
1495#else /* OVLB */
1496
1497/* wishable subranges of objects */
1498STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
1499	{ "bag",	TOOL_CLASS,   SACK,	      BAG_OF_TRICKS },
1500	{ "lamp",	TOOL_CLASS,   OIL_LAMP,	      MAGIC_LAMP },
1501	{ "candle",	TOOL_CLASS,   TALLOW_CANDLE,  WAX_CANDLE },
1502	{ "horn",	TOOL_CLASS,   TOOLED_HORN,    HORN_OF_PLENTY },
1503	{ "shield",	ARMOR_CLASS,  SMALL_SHIELD,   SHIELD_OF_REFLECTION },
1504	{ "helm",	ARMOR_CLASS,  ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
1505	{ "gloves",	ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1506	{ "gauntlets",	ARMOR_CLASS,  LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1507	{ "boots",	ARMOR_CLASS,  LOW_BOOTS,      LEVITATION_BOOTS },
1508	{ "shoes",	ARMOR_CLASS,  LOW_BOOTS,      IRON_SHOES },
1509	{ "cloak",	ARMOR_CLASS,  MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
1510#ifdef TOURIST
1511	{ "shirt",	ARMOR_CLASS,  HAWAIIAN_SHIRT, T_SHIRT },
1512#endif
1513	{ "dragon scales",
1514			ARMOR_CLASS,  GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES },
1515	{ "dragon scale mail",
1516			ARMOR_CLASS,  GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL },
1517	{ "sword",	WEAPON_CLASS, SHORT_SWORD,    KATANA },
1518#ifdef WIZARD
1519	{ "venom",	VENOM_CLASS,  BLINDING_VENOM, ACID_VENOM },
1520#endif
1521	{ "gray stone",	GEM_CLASS,    LUCKSTONE,      FLINT },
1522	{ "grey stone",	GEM_CLASS,    LUCKSTONE,      FLINT },
1523};
1524
1525#define BSTRCMP(base,ptr,string) ((ptr) < base || strcmp((ptr),string))
1526#define BSTRCMPI(base,ptr,string) ((ptr) < base || strcmpi((ptr),string))
1527#define BSTRNCMP(base,ptr,string,num) ((ptr)<base || strncmp((ptr),string,num))
1528#define BSTRNCMPI(base,ptr,string,num) ((ptr)<base||strncmpi((ptr),string,num))
1529
1530/*
1531 * Singularize a string the user typed in; this helps reduce the complexity
1532 * of readobjnam, and is also used in pager.c to singularize the string
1533 * for which help is sought.
1534 */
1535char *
1536makesingular(oldstr)
1537const char *oldstr;
1538{
1539	register char *p, *bp;
1540	char *str = nextobuf();
1541
1542	if (!oldstr || !*oldstr) {
1543		impossible("singular of null?");
1544		str[0] = 0;
1545		return str;
1546	}
1547	Strcpy(str, oldstr);
1548	bp = str;
1549
1550	while (*bp == ' ') bp++;
1551	/* find "cloves of garlic", "worthless pieces of blue glass" */
1552	if ((p = strstri(bp, "s of ")) != 0) {
1553	    /* but don't singularize "gauntlets", "boots", "Eyes of the.." */
1554	    if (BSTRNCMPI(bp, p-3, "Eye", 3) &&
1555		BSTRNCMP(bp, p-4, "boot", 4) &&
1556		BSTRNCMP(bp, p-8, "gauntlet", 8))
1557		while ((*p = *(p+1)) != 0) p++;
1558	    return bp;
1559	}
1560
1561	/* remove -s or -es (boxes) or -ies (rubies) */
1562	p = eos(bp);
1563	if (p >= bp+1 && p[-1] == 's') {
1564		if (p >= bp+2 && p[-2] == 'e') {
1565			if (p >= bp+3 && p[-3] == 'i') {
1566				if(!BSTRCMP(bp, p-7, "cookies") ||
1567				   !BSTRCMP(bp, p-4, "pies"))
1568					goto mins;
1569				Strcpy(p-3, "y");
1570				return bp;
1571			}
1572
1573			/* note: cloves / knives from clove / knife */
1574			if(!BSTRCMP(bp, p-6, "knives")) {
1575				Strcpy(p-3, "fe");
1576				return bp;
1577			}
1578			if(!BSTRCMP(bp, p-6, "staves")) {
1579				Strcpy(p-3, "ff");
1580				return bp;
1581			}
1582			if (!BSTRCMPI(bp, p-6, "leaves")) {
1583				Strcpy(p-3, "f");
1584				return bp;
1585			}
1586			if (!BSTRCMP(bp, p-8, "vortices")) {
1587				Strcpy(p-4, "ex");
1588				return bp;
1589			}
1590
1591			/* note: nurses, axes but boxes */
1592			if (!BSTRCMP(bp, p-5, "boxes") ||
1593			    !BSTRCMP(bp, p-4, "ches")) {
1594				p[-2] = '\0';
1595				return bp;
1596			}
1597
1598			if (!BSTRCMP(bp, p-6, "gloves") ||
1599			    !BSTRCMP(bp, p-6, "lenses") ||
1600			    !BSTRCMP(bp, p-5, "shoes") ||
1601			    !BSTRCMP(bp, p-6, "scales"))
1602				return bp;
1603
1604		} else if (!BSTRCMP(bp, p-5, "boots") ||
1605			   !BSTRCMP(bp, p-9, "gauntlets") ||
1606			   !BSTRCMP(bp, p-6, "tricks") ||
1607			   !BSTRCMP(bp, p-9, "paralysis") ||
1608			   !BSTRCMP(bp, p-5, "glass") ||
1609			   !BSTRCMP(bp, p-4, "ness") ||
1610			   !BSTRCMP(bp, p-14, "shape changers") ||
1611			   !BSTRCMP(bp, p-15, "detect monsters") ||
1612			   !BSTRCMPI(bp, p-11, "Aesculapius") || /* staff */
1613			   !BSTRCMP(bp, p-10, "eucalyptus") ||
1614#ifdef WIZARD
1615			   !BSTRCMP(bp, p-9, "iron bars") ||
1616#endif
1617			   !BSTRCMP(bp, p-5, "aklys") ||
1618			   !BSTRCMP(bp, p-6, "fungus"))
1619				return bp;
1620	mins:
1621		p[-1] = '\0';
1622
1623	} else {
1624
1625		if(!BSTRCMP(bp, p-5, "teeth")) {
1626			Strcpy(p-5, "tooth");
1627			return bp;
1628		}
1629
1630		if (!BSTRCMP(bp, p-5, "fungi")) {
1631			Strcpy(p-5, "fungus");
1632			return bp;
1633		}
1634
1635		/* here we cannot find the plural suffix */
1636	}
1637	return bp;
1638}
1639
1640/* compare user string against object name string using fuzzy matching */
1641static boolean
1642wishymatch(u_str, o_str, retry_inverted)
1643const char *u_str;	/* from user, so might be variant spelling */
1644const char *o_str;	/* from objects[], so is in canonical form */
1645boolean retry_inverted;	/* optional extra "of" handling */
1646{
1647	/* special case: wizards can wish for traps.  The object is "beartrap"
1648	 * and the trap is "bear trap", so to let wizards wish for both we
1649	 * must not fuzzymatch.
1650	 */
1651#ifdef WIZARD
1652	if (wizard && !strcmp(o_str, "beartrap"))
1653	    return !strncmpi(o_str, u_str, 8);
1654#endif
1655
1656	/* ignore spaces & hyphens and upper/lower case when comparing */
1657	if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE;
1658
1659	if (retry_inverted) {
1660	    const char *u_of, *o_of;
1661	    char *p, buf[BUFSZ];
1662
1663	    /* when just one of the strings is in the form "foo of bar",
1664	       convert it into "bar foo" and perform another comparison */
1665	    u_of = strstri(u_str, " of ");
1666	    o_of = strstri(o_str, " of ");
1667	    if (u_of && !o_of) {
1668		Strcpy(buf, u_of + 4);
1669		p = eos(strcat(buf, " "));
1670		while (u_str < u_of) *p++ = *u_str++;
1671		*p = '\0';
1672		return fuzzymatch(buf, o_str, " -", TRUE);
1673	    } else if (o_of && !u_of) {
1674		Strcpy(buf, o_of + 4);
1675		p = eos(strcat(buf, " "));
1676		while (o_str < o_of) *p++ = *o_str++;
1677		*p = '\0';
1678		return fuzzymatch(u_str, buf, " -", TRUE);
1679	    }
1680	}
1681
1682	/* [note: if something like "elven speed boots" ever gets added, these
1683	   special cases should be changed to call wishymatch() recursively in
1684	   order to get the "of" inversion handling] */
1685	if (!strncmp(o_str, "dwarvish ", 9)) {
1686	    if (!strncmpi(u_str, "dwarven ", 8))
1687		return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE);
1688	} else if (!strncmp(o_str, "elven ", 6)) {
1689	    if (!strncmpi(u_str, "elvish ", 7))
1690		return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE);
1691	    else if (!strncmpi(u_str, "elfin ", 6))
1692		return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE);
1693	} else if (!strcmp(o_str, "aluminum")) {
1694		/* this special case doesn't really fit anywhere else... */
1695		/* (note that " wand" will have been stripped off by now) */
1696	    if (!strcmpi(u_str, "aluminium"))
1697		return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE);
1698	}
1699
1700	return FALSE;
1701}
1702
1703/* alternate spellings; if the difference is only the presence or
1704   absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
1705   vs "pick-axe") then there is no need for inclusion in this list;
1706   likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */
1707struct alt_spellings {
1708	const char *sp;
1709	int ob;
1710} spellings[] = {
1711	{ "pickax", PICK_AXE },
1712	{ "whip", BULLWHIP },
1713	{ "saber", SILVER_SABER },
1714	{ "silver sabre", SILVER_SABER },
1715	{ "smooth shield", SHIELD_OF_REFLECTION },
1716	{ "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
1717	{ "grey dragon scales", GRAY_DRAGON_SCALES },
1718	{ "enchant armour", SCR_ENCHANT_ARMOR },
1719	{ "destroy armour", SCR_DESTROY_ARMOR },
1720	{ "scroll of enchant armour", SCR_ENCHANT_ARMOR },
1721	{ "scroll of destroy armour", SCR_DESTROY_ARMOR },
1722	{ "leather armour", LEATHER_ARMOR },
1723	{ "studded leather armour", STUDDED_LEATHER_ARMOR },
1724	{ "iron ball", HEAVY_IRON_BALL },
1725	{ "lantern", BRASS_LANTERN },
1726	{ "mattock", DWARVISH_MATTOCK },
1727	{ "amulet of poison resistance", AMULET_VERSUS_POISON },
1728	{ "stone", ROCK },
1729#ifdef TOURIST
1730	{ "camera", EXPENSIVE_CAMERA },
1731	{ "tee shirt", T_SHIRT },
1732#endif
1733	{ "can", TIN },
1734	{ "can opener", TIN_OPENER },
1735	{ "kelp", KELP_FROND },
1736	{ "eucalyptus", EUCALYPTUS_LEAF },
1737	{ "grapple", GRAPPLING_HOOK },
1738	{ (const char *)0, 0 },
1739};
1740
1741/*
1742 * Return something wished for.  Specifying a null pointer for
1743 * the user request string results in a random object.  Otherwise,
1744 * if asking explicitly for "nothing" (or "nil") return no_wish;
1745 * if not an object return &zeroobj; if an error (no matching object),
1746 * return null.
1747 * If from_user is false, we're reading from the wizkit, nothing was typed in.
1748 */
1749struct obj *
1750readobjnam(bp, no_wish, from_user)
1751register char *bp;
1752struct obj *no_wish;
1753boolean from_user;
1754{
1755	register char *p;
1756	register int i;
1757	register struct obj *otmp;
1758	int cnt, spe, spesgn, typ, very, rechrg;
1759	int blessed, uncursed, iscursed, ispoisoned, isgreased;
1760	int eroded, eroded2, erodeproof;
1761#ifdef INVISIBLE_OBJECTS
1762	int isinvisible;
1763#endif
1764	int halfeaten, mntmp, contents;
1765	int islit, unlabeled, ishistoric, isdiluted;
1766	struct fruit *f;
1767	int ftype = current_fruit;
1768	char fruitbuf[BUFSZ];
1769	/* Fruits may not mess up the ability to wish for real objects (since
1770	 * you can leave a fruit in a bones file and it will be added to
1771	 * another person's game), so they must be checked for last, after
1772	 * stripping all the possible prefixes and seeing if there's a real
1773	 * name in there.  So we have to save the full original name.  However,
1774	 * it's still possible to do things like "uncursed burnt Alaska",
1775	 * or worse yet, "2 burned 5 course meals", so we need to loop to
1776	 * strip off the prefixes again, this time stripping only the ones
1777	 * possible on food.
1778	 * We could get even more detailed so as to allow food names with
1779	 * prefixes that _are_ possible on food, so you could wish for
1780	 * "2 3 alarm chilis".  Currently this isn't allowed; options.c
1781	 * automatically sticks 'candied' in front of such names.
1782	 */
1783
1784	char oclass;
1785	char *un, *dn, *actualn;
1786	const char *name=0;
1787
1788	cnt = spe = spesgn = typ = very = rechrg =
1789		blessed = uncursed = iscursed =
1790#ifdef INVISIBLE_OBJECTS
1791		isinvisible =
1792#endif
1793		ispoisoned = isgreased = eroded = eroded2 = erodeproof =
1794		halfeaten = islit = unlabeled = ishistoric = isdiluted = 0;
1795	mntmp = NON_PM;
1796#define UNDEFINED 0
1797#define EMPTY 1
1798#define SPINACH 2
1799	contents = UNDEFINED;
1800	oclass = 0;
1801	actualn = dn = un = 0;
1802
1803	if (!bp) goto any;
1804	/* first, remove extra whitespace they may have typed */
1805	(void)mungspaces(bp);
1806	/* allow wishing for "nothing" to preserve wishless conduct...
1807	   [now requires "wand of nothing" if that's what was really wanted] */
1808	if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") ||
1809	    !strcmpi(bp, "none")) return no_wish;
1810	/* save the [nearly] unmodified choice string */
1811	Strcpy(fruitbuf, bp);
1812
1813	for(;;) {
1814		register int l;
1815
1816		if (!bp || !*bp) goto any;
1817		if (!strncmpi(bp, "an ", l=3) ||
1818		    !strncmpi(bp, "a ", l=2)) {
1819			cnt = 1;
1820		} else if (!strncmpi(bp, "the ", l=4)) {
1821			;	/* just increment `bp' by `l' below */
1822		} else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
1823			cnt = atoi(bp);
1824			while(digit(*bp)) bp++;
1825			while(*bp == ' ') bp++;
1826			l = 0;
1827		} else if (*bp == '+' || *bp == '-') {
1828			spesgn = (*bp++ == '+') ? 1 : -1;
1829			spe = atoi(bp);
1830			while(digit(*bp)) bp++;
1831			while(*bp == ' ') bp++;
1832			l = 0;
1833		} else if (!strncmpi(bp, "blessed ", l=8) ||
1834			   !strncmpi(bp, "holy ", l=5)) {
1835			blessed = 1;
1836		} else if (!strncmpi(bp, "cursed ", l=7) ||
1837			   !strncmpi(bp, "unholy ", l=7)) {
1838			iscursed = 1;
1839		} else if (!strncmpi(bp, "uncursed ", l=9)) {
1840			uncursed = 1;
1841#ifdef INVISIBLE_OBJECTS
1842		} else if (!strncmpi(bp, "invisible ", l=10)) {
1843			isinvisible = 1;
1844#endif
1845		} else if (!strncmpi(bp, "rustproof ", l=10) ||
1846			   !strncmpi(bp, "erodeproof ", l=11) ||
1847			   !strncmpi(bp, "corrodeproof ", l=13) ||
1848			   !strncmpi(bp, "fixed ", l=6) ||
1849			   !strncmpi(bp, "fireproof ", l=10) ||
1850			   !strncmpi(bp, "rotproof ", l=9)) {
1851			erodeproof = 1;
1852		} else if (!strncmpi(bp,"lit ", l=4) ||
1853			   !strncmpi(bp,"burning ", l=8)) {
1854			islit = 1;
1855		} else if (!strncmpi(bp,"unlit ", l=6) ||
1856			   !strncmpi(bp,"extinguished ", l=13)) {
1857			islit = 0;
1858		/* "unlabeled" and "blank" are synonymous */
1859		} else if (!strncmpi(bp,"unlabeled ", l=10) ||
1860			   !strncmpi(bp,"unlabelled ", l=11) ||
1861			   !strncmpi(bp,"blank ", l=6)) {
1862			unlabeled = 1;
1863		} else if(!strncmpi(bp, "poisoned ",l=9)
1864#ifdef WIZARD
1865			  || (wizard && !strncmpi(bp, "trapped ",l=8))
1866#endif
1867			  ) {
1868			ispoisoned=1;
1869		} else if(!strncmpi(bp, "greased ",l=8)) {
1870			isgreased=1;
1871		} else if (!strncmpi(bp, "very ", l=5)) {
1872			/* very rusted very heavy iron ball */
1873			very = 1;
1874		} else if (!strncmpi(bp, "thoroughly ", l=11)) {
1875			very = 2;
1876		} else if (!strncmpi(bp, "rusty ", l=6) ||
1877			   !strncmpi(bp, "rusted ", l=7) ||
1878			   !strncmpi(bp, "burnt ", l=6) ||
1879			   !strncmpi(bp, "burned ", l=7)) {
1880			eroded = 1 + very;
1881			very = 0;
1882		} else if (!strncmpi(bp, "corroded ", l=9) ||
1883			   !strncmpi(bp, "rotted ", l=7)) {
1884			eroded2 = 1 + very;
1885			very = 0;
1886		} else if (!strncmpi(bp, "partly eaten ", l=13)) {
1887			halfeaten = 1;
1888		} else if (!strncmpi(bp, "historic ", l=9)) {
1889			ishistoric = 1;
1890		} else if (!strncmpi(bp, "diluted ", l=8)) {
1891			isdiluted = 1;
1892		} else if(!strncmpi(bp, "empty ", l=6)) {
1893			contents = EMPTY;
1894		} else break;
1895		bp += l;
1896	}
1897	if(!cnt) cnt = 1;		/* %% what with "gems" etc. ? */
1898	if (strlen(bp) > 1) {
1899	    if ((p = rindex(bp, '(')) != 0) {
1900		if (p > bp && p[-1] == ' ') p[-1] = 0;
1901		else *p = 0;
1902		p++;
1903		if (!strcmpi(p, "lit)")) {
1904		    islit = 1;
1905		} else {
1906		    spe = atoi(p);
1907		    while (digit(*p)) p++;
1908		    if (*p == ':') {
1909			p++;
1910			rechrg = spe;
1911			spe = atoi(p);
1912			while (digit(*p)) p++;
1913		    }
1914		    if (*p != ')') {
1915			spe = rechrg = 0;
1916		    } else {
1917			spesgn = 1;
1918			p++;
1919			if (*p) Strcat(bp, p);
1920		    }
1921		}
1922	    }
1923	}
1924/*
1925   otmp->spe is type schar; so we don't want spe to be any bigger or smaller.
1926   also, spe should always be positive  -- some cheaters may try to confuse
1927   atoi()
1928*/
1929	if (spe < 0) {
1930		spesgn = -1;	/* cheaters get what they deserve */
1931		spe = abs(spe);
1932	}
1933	if (spe > SCHAR_LIM)
1934		spe = SCHAR_LIM;
1935	if (rechrg < 0 || rechrg > 7) rechrg = 7;	/* recharge_limit */
1936
1937	/* now we have the actual name, as delivered by xname, say
1938		green potions called whisky
1939		scrolls labeled "QWERTY"
1940		egg
1941		fortune cookies
1942		very heavy iron ball named hoei
1943		wand of wishing
1944		elven cloak
1945	*/
1946	if ((p = strstri(bp, " named ")) != 0) {
1947		*p = 0;
1948		name = p+7;
1949	}
1950	if ((p = strstri(bp, " called ")) != 0) {
1951		*p = 0;
1952		un = p+8;
1953		/* "helmet called telepathy" is not "helmet" (a specific type)
1954		 * "shield called reflection" is not "shield" (a general type)
1955		 */
1956		for(i = 0; i < SIZE(o_ranges); i++)
1957		    if(!strcmpi(bp, o_ranges[i].name)) {
1958			oclass = o_ranges[i].oclass;
1959			goto srch;
1960		    }
1961	}
1962	if ((p = strstri(bp, " labeled ")) != 0) {
1963		*p = 0;
1964		dn = p+9;
1965	} else if ((p = strstri(bp, " labelled ")) != 0) {
1966		*p = 0;
1967		dn = p+10;
1968	}
1969	if ((p = strstri(bp, " of spinach")) != 0) {
1970		*p = 0;
1971		contents = SPINACH;
1972	}
1973
1974	/*
1975	Skip over "pair of ", "pairs of", "set of" and "sets of".
1976
1977	Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
1978	English either way.  See makeplural() for more on pair/pairs.
1979
1980	We should only double count if the object in question is not
1981	refered to as a "pair of".  E.g. We should double if the player
1982	types "pair of spears", but not if the player types "pair of
1983	lenses".  Luckily (?) all objects that are refered to as pairs
1984	-- boots, gloves, and lenses -- are also not mergable, so cnt is
1985	ignored anyway.
1986	*/
1987	if(!strncmpi(bp, "pair of ",8)) {
1988		bp += 8;
1989		cnt *= 2;
1990	} else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) {
1991		bp += 9;
1992		cnt *= 2;
1993	} else if (!strncmpi(bp, "set of ",7)) {
1994		bp += 7;
1995	} else if (!strncmpi(bp, "sets of ",8)) {
1996		bp += 8;
1997	}
1998
1999	/*
2000	 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
2001	 * Don't check if it's a wand or spellbook.
2002	 * (avoid "wand/finger of death" confusion).
2003	 */
2004	if (!strstri(bp, "wand ")
2005	 && !strstri(bp, "spellbook ")
2006	 && !strstri(bp, "finger ")) {
2007	    if ((p = strstri(bp, " of ")) != 0
2008		&& (mntmp = name_to_mon(p+4)) >= LOW_PM)
2009		*p = 0;
2010	}
2011	/* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
2012	if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
2013	if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
2014	if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
2015	if (strncmpi(bp, "master key", 10)) /* not the "master" rank */
2016	if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */
2017	if (mntmp < LOW_PM && strlen(bp) > 2 &&
2018	    (mntmp = name_to_mon(bp)) >= LOW_PM) {
2019		int mntmptoo, mntmplen;	/* double check for rank title */
2020		char *obp = bp;
2021		mntmptoo = title_to_mon(bp, (int *)0, &mntmplen);
2022		bp += mntmp != mntmptoo ? (int)strlen(mons[mntmp].mname) : mntmplen;
2023		if (*bp == ' ') bp++;
2024		else if (!strncmpi(bp, "s ", 2)) bp += 2;
2025		else if (!strncmpi(bp, "es ", 3)) bp += 3;
2026		else if (!*bp && !actualn && !dn && !un && !oclass) {
2027		    /* no referent; they don't really mean a monster type */
2028		    bp = obp;
2029		    mntmp = NON_PM;
2030		}
2031	}
2032
2033	/* first change to singular if necessary */
2034	if (*bp) {
2035		char *sng = makesingular(bp);
2036		if (strcmp(bp, sng)) {
2037			if (cnt == 1) cnt = 2;
2038			Strcpy(bp, sng);
2039		}
2040	}
2041
2042	/* Alternate spellings (pick-ax, silver sabre, &c) */
2043    {
2044	struct alt_spellings *as = spellings;
2045
2046	while (as->sp) {
2047		if (fuzzymatch(bp, as->sp, " -", TRUE)) {
2048			typ = as->ob;
2049			goto typfnd;
2050		}
2051		as++;
2052	}
2053	/* can't use spellings list for this one due to shuffling */
2054	if (!strncmpi(bp, "grey spell", 10))
2055		*(bp + 2) = 'a';
2056    }
2057
2058	/* dragon scales - assumes order of dragons */
2059	if(!strcmpi(bp, "scales") &&
2060			mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) {
2061		typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
2062		mntmp = NON_PM;	/* no monster */
2063		goto typfnd;
2064	}
2065
2066	p = eos(bp);
2067	if(!BSTRCMPI(bp, p-10, "holy water")) {
2068		typ = POT_WATER;
2069		if ((p-bp) >= 12 && *(p-12) == 'u')
2070			iscursed = 1; /* unholy water */
2071		else blessed = 1;
2072		goto typfnd;
2073	}
2074	if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) {
2075		typ = SCR_BLANK_PAPER;
2076		goto typfnd;
2077	}
2078	if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) {
2079		typ = SPE_BLANK_PAPER;
2080		goto typfnd;
2081	}
2082	/*
2083	 * NOTE: Gold pieces are handled as objects nowadays, and therefore
2084	 * this section should probably be reconsidered as well as the entire
2085	 * gold/money concept.  Maybe we want to add other monetary units as
2086	 * well in the future. (TH)
2087	 */
2088	if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") ||
2089	   !strcmpi(bp, "gold") || !strcmpi(bp, "money") ||
2090	   !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
2091			if (cnt > 5000
2092#ifdef WIZARD
2093					&& !wizard
2094#endif
2095						) cnt=5000;
2096		if (cnt < 1) cnt=1;
2097#ifndef GOLDOBJ
2098		if (from_user)
2099		    pline("%d gold piece%s.", cnt, plur(cnt));
2100		u.ugold += cnt;
2101		flags.botl=1;
2102		return (&zeroobj);
2103#else
2104                otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
2105		otmp->quan = cnt;
2106                otmp->owt = weight(otmp);
2107		flags.botl=1;
2108		return (otmp);
2109#endif
2110	}
2111	if (strlen(bp) == 1 &&
2112	   (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS
2113#ifdef WIZARD
2114	    && (wizard || i != VENOM_CLASS)
2115#else
2116	    && i != VENOM_CLASS
2117#endif
2118	    ) {
2119		oclass = i;
2120		goto any;
2121	}
2122
2123	/* Search for class names: XXXXX potion, scroll of XXXXX.  Avoid */
2124	/* false hits on, e.g., rings for "ring mail". */
2125	if(strncmpi(bp, "enchant ", 8) &&
2126	   strncmpi(bp, "destroy ", 8) &&
2127	   strncmpi(bp, "food detection", 14) &&
2128	   strncmpi(bp, "ring mail", 9) &&
2129	   strncmpi(bp, "studded leather arm", 19) &&
2130	   strncmpi(bp, "leather arm", 11) &&
2131	   strncmpi(bp, "tooled horn", 11) &&
2132	   strncmpi(bp, "food ration", 11) &&
2133	   strncmpi(bp, "meat ring", 9)
2134	)
2135	for (i = 0; i < (int)(sizeof wrpsym); i++) {
2136		register int j = strlen(wrp[i]);
2137		if(!strncmpi(bp, wrp[i], j)){
2138			oclass = wrpsym[i];
2139			if(oclass != AMULET_CLASS) {
2140			    bp += j;
2141			    if(!strncmpi(bp, " of ", 4)) actualn = bp+4;
2142			    /* else if(*bp) ?? */
2143			} else
2144			    actualn = bp;
2145			goto srch;
2146		}
2147		if(!BSTRCMPI(bp, p-j, wrp[i])){
2148			oclass = wrpsym[i];
2149			p -= j;
2150			*p = 0;
2151			if(p > bp && p[-1] == ' ') p[-1] = 0;
2152			actualn = dn = bp;
2153			goto srch;
2154		}
2155	}
2156
2157	/* "grey stone" check must be before general "stone" */
2158	for (i = 0; i < SIZE(o_ranges); i++)
2159	    if(!strcmpi(bp, o_ranges[i].name)) {
2160		typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
2161		goto typfnd;
2162	    }
2163
2164	if (!BSTRCMPI(bp, p-6, " stone")) {
2165		p[-6] = 0;
2166		oclass = GEM_CLASS;
2167		dn = actualn = bp;
2168		goto srch;
2169	} else if (!strcmpi(bp, "looking glass")) {
2170		;	/* avoid false hit on "* glass" */
2171	} else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) {
2172		register char *g = bp;
2173		if (strstri(g, "broken")) return (struct obj *)0;
2174		if (!strncmpi(g, "worthless ", 10)) g += 10;
2175		if (!strncmpi(g, "piece of ", 9)) g += 9;
2176		if (!strncmpi(g, "colored ", 8)) g += 8;
2177		else if (!strncmpi(g, "coloured ", 9)) g += 9;
2178		if (!strcmpi(g, "glass")) {	/* choose random color */
2179			/* 9 different kinds */
2180			typ = LAST_GEM + rnd(9);
2181			if (objects[typ].oc_class == GEM_CLASS) goto typfnd;
2182			else typ = 0;	/* somebody changed objects[]? punt */
2183		} else {		/* try to construct canonical form */
2184			char tbuf[BUFSZ];
2185			Strcpy(tbuf, "worthless piece of ");
2186			Strcat(tbuf, g);  /* assume it starts with the color */
2187			Strcpy(bp, tbuf);
2188		}
2189	}
2190
2191	actualn = bp;
2192	if (!dn) dn = actualn; /* ex. "skull cap" */
2193srch:
2194	/* check real names of gems first */
2195	if(!oclass && actualn) {
2196	    for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
2197		register const char *zn;
2198
2199		if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
2200		    typ = i;
2201		    goto typfnd;
2202		}
2203	    }
2204	}
2205	i = oclass ? bases[(int)oclass] : 1;
2206	while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){
2207		register const char *zn;
2208
2209		if (actualn && (zn = OBJ_NAME(objects[i])) != 0 &&
2210			    wishymatch(actualn, zn, TRUE)) {
2211			typ = i;
2212			goto typfnd;
2213		}
2214		if (dn && (zn = OBJ_DESCR(objects[i])) != 0 &&
2215			    wishymatch(dn, zn, FALSE)) {
2216			/* don't match extra descriptions (w/o real name) */
2217			if (!OBJ_NAME(objects[i])) return (struct obj *)0;
2218			typ = i;
2219			goto typfnd;
2220		}
2221		if (un && (zn = objects[i].oc_uname) != 0 &&
2222			    wishymatch(un, zn, FALSE)) {
2223			typ = i;
2224			goto typfnd;
2225		}
2226		i++;
2227	}
2228	if (actualn) {
2229		struct Jitem *j = Japanese_items;
2230		while(j->item) {
2231			if (actualn && !strcmpi(actualn, j->name)) {
2232				typ = j->item;
2233				goto typfnd;
2234			}
2235			j++;
2236		}
2237	}
2238	if (!strcmpi(bp, "spinach")) {
2239		contents = SPINACH;
2240		typ = TIN;
2241		goto typfnd;
2242	}
2243	/* Note: not strncmpi.  2 fruits, one capital, one not, are possible. */
2244	{
2245	    char *fp;
2246	    int l, cntf;
2247	    int blessedf, iscursedf, uncursedf, halfeatenf;
2248
2249	    blessedf = iscursedf = uncursedf = halfeatenf = 0;
2250	    cntf = 0;
2251
2252	    fp = fruitbuf;
2253	    for(;;) {
2254		if (!fp || !*fp) break;
2255		if (!strncmpi(fp, "an ", l=3) ||
2256		    !strncmpi(fp, "a ", l=2)) {
2257			cntf = 1;
2258		} else if (!cntf && digit(*fp)) {
2259			cntf = atoi(fp);
2260			while(digit(*fp)) fp++;
2261			while(*fp == ' ') fp++;
2262			l = 0;
2263		} else if (!strncmpi(fp, "blessed ", l=8)) {
2264			blessedf = 1;
2265		} else if (!strncmpi(fp, "cursed ", l=7)) {
2266			iscursedf = 1;
2267		} else if (!strncmpi(fp, "uncursed ", l=9)) {
2268			uncursedf = 1;
2269		} else if (!strncmpi(fp, "partly eaten ", l=13)) {
2270			halfeatenf = 1;
2271		} else break;
2272		fp += l;
2273	    }
2274
2275	    for(f=ffruit; f; f = f->nextf) {
2276		char *f1 = f->fname, *f2 = makeplural(f->fname);
2277
2278		if(!strncmp(fp, f1, strlen(f1)) ||
2279					!strncmp(fp, f2, strlen(f2))) {
2280			typ = SLIME_MOLD;
2281			blessed = blessedf;
2282			iscursed = iscursedf;
2283			uncursed = uncursedf;
2284			halfeaten = halfeatenf;
2285			cnt = cntf;
2286			ftype = f->fid;
2287			goto typfnd;
2288		}
2289	    }
2290	}
2291
2292	if(!oclass && actualn) {
2293	    short objtyp;
2294
2295	    /* Perhaps it's an artifact specified by name, not type */
2296	    name = artifact_name(actualn, &objtyp);
2297	    if(name) {
2298		typ = objtyp;
2299		goto typfnd;
2300	    }
2301	}
2302#ifdef WIZARD
2303	/* Let wizards wish for traps --KAA */
2304	/* must come after objects check so wizards can still wish for
2305	 * trap objects like beartraps
2306	 */
2307	if (wizard && from_user) {
2308		int trap;
2309
2310		for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) {
2311			const char *tname;
2312
2313			tname = defsyms[trap_to_defsym(trap)].explanation;
2314			if (!strncmpi(tname, bp, strlen(tname))) {
2315				/* avoid stupid mistakes */
2316				if((trap == TRAPDOOR || trap == HOLE)
2317				      && !Can_fall_thru(&u.uz)) trap = ROCKTRAP;
2318				(void) maketrap(u.ux, u.uy, trap);
2319				pline("%s.", An(tname));
2320				return(&zeroobj);
2321			}
2322		}
2323		/* or some other dungeon features -dlc */
2324		p = eos(bp);
2325		if(!BSTRCMP(bp, p-8, "fountain")) {
2326			levl[u.ux][u.uy].typ = FOUNTAIN;
2327			level.flags.nfountains++;
2328			if(!strncmpi(bp, "magic ", 6))
2329				levl[u.ux][u.uy].blessedftn = 1;
2330			pline("A %sfountain.",
2331			      levl[u.ux][u.uy].blessedftn ? "magic " : "");
2332			newsym(u.ux, u.uy);
2333			return(&zeroobj);
2334		}
2335		if(!BSTRCMP(bp, p-6, "throne")) {
2336			levl[u.ux][u.uy].typ = THRONE;
2337			pline("A throne.");
2338			newsym(u.ux, u.uy);
2339			return(&zeroobj);
2340		}
2341# ifdef SINKS
2342		if(!BSTRCMP(bp, p-4, "sink")) {
2343			levl[u.ux][u.uy].typ = SINK;
2344			level.flags.nsinks++;
2345			pline("A sink.");
2346			newsym(u.ux, u.uy);
2347			return &zeroobj;
2348		}
2349# endif
2350		if(!BSTRCMP(bp, p-4, "pool")) {
2351			levl[u.ux][u.uy].typ = POOL;
2352			del_engr_at(u.ux, u.uy);
2353			pline("A pool.");
2354			/* Must manually make kelp! */
2355			water_damage(level.objects[u.ux][u.uy], FALSE, TRUE);
2356			newsym(u.ux, u.uy);
2357			return &zeroobj;
2358		}
2359		if (!BSTRCMP(bp, p-4, "lava")) {  /* also matches "molten lava" */
2360			levl[u.ux][u.uy].typ = LAVAPOOL;
2361			del_engr_at(u.ux, u.uy);
2362			pline("A pool of molten lava.");
2363			if (!(Levitation || Flying)) (void) lava_effects();
2364			newsym(u.ux, u.uy);
2365			return &zeroobj;
2366		}
2367
2368		if(!BSTRCMP(bp, p-5, "altar")) {
2369		    aligntyp al;
2370
2371		    levl[u.ux][u.uy].typ = ALTAR;
2372		    if(!strncmpi(bp, "chaotic ", 8))
2373			al = A_CHAOTIC;
2374		    else if(!strncmpi(bp, "neutral ", 8))
2375			al = A_NEUTRAL;
2376		    else if(!strncmpi(bp, "lawful ", 7))
2377			al = A_LAWFUL;
2378		    else if(!strncmpi(bp, "unaligned ", 10))
2379			al = A_NONE;
2380		    else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
2381			al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1;
2382		    levl[u.ux][u.uy].altarmask = Align2amask( al );
2383		    pline("%s altar.", An(align_str(al)));
2384		    newsym(u.ux, u.uy);
2385		    return(&zeroobj);
2386		}
2387
2388		if(!BSTRCMP(bp, p-5, "grave") || !BSTRCMP(bp, p-9, "headstone")) {
2389		    make_grave(u.ux, u.uy, (char *) 0);
2390		    pline("A grave.");
2391		    newsym(u.ux, u.uy);
2392		    return(&zeroobj);
2393		}
2394
2395		if(!BSTRCMP(bp, p-4, "tree")) {
2396		    levl[u.ux][u.uy].typ = TREE;
2397		    pline("A tree.");
2398		    newsym(u.ux, u.uy);
2399		    block_point(u.ux, u.uy);
2400		    return &zeroobj;
2401		}
2402
2403		if(!BSTRCMP(bp, p-4, "bars")) {
2404		    levl[u.ux][u.uy].typ = IRONBARS;
2405		    pline("Iron bars.");
2406		    newsym(u.ux, u.uy);
2407		    return &zeroobj;
2408		}
2409	}
2410#endif
2411	if(!oclass) return((struct obj *)0);
2412any:
2413	if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))];
2414typfnd:
2415	if (typ) oclass = objects[typ].oc_class;
2416
2417	/* check for some objects that are not allowed */
2418	if (typ && objects[typ].oc_unique) {
2419#ifdef WIZARD
2420	    if (wizard)
2421		;	/* allow unique objects */
2422	    else
2423#endif
2424	    switch (typ) {
2425		case AMULET_OF_YENDOR:
2426		    typ = FAKE_AMULET_OF_YENDOR;
2427		    break;
2428		case CANDELABRUM_OF_INVOCATION:
2429		    typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
2430		    break;
2431		case BELL_OF_OPENING:
2432		    typ = BELL;
2433		    break;
2434		case SPE_BOOK_OF_THE_DEAD:
2435		    typ = SPE_BLANK_PAPER;
2436		    break;
2437	    }
2438	}
2439
2440	/* catch any other non-wishable objects */
2441	if (objects[typ].oc_nowish
2442#ifdef WIZARD
2443	    && !wizard
2444#endif
2445	    )
2446	    return((struct obj *)0);
2447
2448	/* convert magic lamps to regular lamps before lighting them or setting
2449	   the charges */
2450	if (typ == MAGIC_LAMP
2451#ifdef WIZARD
2452				&& !wizard
2453#endif
2454						)
2455	    typ = OIL_LAMP;
2456
2457	if(typ) {
2458		otmp = mksobj(typ, TRUE, FALSE);
2459	} else {
2460		otmp = mkobj(oclass, FALSE);
2461		if (otmp) typ = otmp->otyp;
2462	}
2463
2464	if (islit &&
2465		(typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN ||
2466		 Is_candle(otmp) || typ == POT_OIL)) {
2467	    place_object(otmp, u.ux, u.uy);  /* make it viable light source */
2468	    begin_burn(otmp, FALSE);
2469	    obj_extract_self(otmp);	 /* now release it for caller's use */
2470	}
2471
2472	if(cnt > 0 && objects[typ].oc_merge && oclass != SPBOOK_CLASS &&
2473		(cnt < rnd(6) ||
2474#ifdef WIZARD
2475		wizard ||
2476#endif
2477		 (cnt <= 7 && Is_candle(otmp)) ||
2478		 (cnt <= 20 &&
2479		  ((oclass == WEAPON_CLASS && is_ammo(otmp))
2480				|| typ == ROCK || is_missile(otmp)))))
2481			otmp->quan = (long) cnt;
2482
2483#ifdef WIZARD
2484	if (oclass == VENOM_CLASS) otmp->spe = 1;
2485#endif
2486
2487	if (spesgn == 0) spe = otmp->spe;
2488#ifdef WIZARD
2489	else if (wizard) /* no alteration to spe */ ;
2490#endif
2491	else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS ||
2492		 is_weptool(otmp) ||
2493			(oclass==RING_CLASS && objects[typ].oc_charged)) {
2494		if(spe > rnd(5) && spe > otmp->spe) spe = 0;
2495		if(spe > 2 && Luck < 0) spesgn = -1;
2496	} else {
2497		if (oclass == WAND_CLASS) {
2498			if (spe > 1 && spesgn == -1) spe = 1;
2499		} else {
2500			if (spe > 0 && spesgn == -1) spe = 0;
2501		}
2502		if (spe > otmp->spe) spe = otmp->spe;
2503	}
2504
2505	if (spesgn == -1) spe = -spe;
2506
2507	/* set otmp->spe.  This may, or may not, use spe... */
2508	switch (typ) {
2509		case TIN: if (contents==EMPTY) {
2510				otmp->corpsenm = NON_PM;
2511				otmp->spe = 0;
2512			} else if (contents==SPINACH) {
2513				otmp->corpsenm = NON_PM;
2514				otmp->spe = 1;
2515			}
2516			break;
2517		case SLIME_MOLD: otmp->spe = ftype;
2518			/* Fall through */
2519		case SKELETON_KEY: case CHEST: case LARGE_BOX:
2520		case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE:
2521			/* otmp->cobj already done in mksobj() */
2522				break;
2523#ifdef MAIL
2524		case SCR_MAIL: otmp->spe = 1; break;
2525#endif
2526		case WAN_WISHING:
2527#ifdef WIZARD
2528			if (!wizard) {
2529#endif
2530				otmp->spe = (rn2(10) ? -1 : 0);
2531				break;
2532#ifdef WIZARD
2533			}
2534			/* fall through, if wizard */
2535#endif
2536		default: otmp->spe = spe;
2537	}
2538
2539	/* set otmp->corpsenm or dragon scale [mail] */
2540	if (mntmp >= LOW_PM) {
2541		if (mntmp == PM_LONG_WORM_TAIL) mntmp = PM_LONG_WORM;
2542
2543		switch (typ) {
2544		case TIN:
2545			otmp->spe = 0; /* No spinach */
2546			if (dead_species(mntmp, FALSE)) {
2547			    otmp->corpsenm = NON_PM;	/* it's empty */
2548			} else if (!(mons[mntmp].geno & G_UNIQ) &&
2549				   !(mvitals[mntmp].mvflags & G_NOCORPSE) &&
2550				   mons[mntmp].cnutrit != 0) {
2551			    otmp->corpsenm = mntmp;
2552			}
2553			break;
2554		case CORPSE:
2555			if (!(mons[mntmp].geno & G_UNIQ) &&
2556				   !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
2557			    /* beware of random troll or lizard corpse,
2558			       or of ordinary one being forced to such */
2559			    if (otmp->timed) obj_stop_timers(otmp);
2560			    if (mons[mntmp].msound == MS_GUARDIAN)
2561			    	otmp->corpsenm = genus(mntmp,1);
2562			    else
2563				otmp->corpsenm = mntmp;
2564			    start_corpse_timeout(otmp);
2565			}
2566			break;
2567		case FIGURINE:
2568			if (!(mons[mntmp].geno & G_UNIQ)
2569			    && !is_human(&mons[mntmp])
2570#ifdef MAIL
2571			    && mntmp != PM_MAIL_DAEMON
2572#endif
2573							)
2574				otmp->corpsenm = mntmp;
2575			break;
2576		case EGG:
2577			mntmp = can_be_hatched(mntmp);
2578			if (mntmp != NON_PM) {
2579			    otmp->corpsenm = mntmp;
2580			    if (!dead_species(mntmp, TRUE))
2581				attach_egg_hatch_timeout(otmp);
2582			    else
2583				kill_egg(otmp);
2584			}
2585			break;
2586		case STATUE: otmp->corpsenm = mntmp;
2587			if (Has_contents(otmp) && verysmall(&mons[mntmp]))
2588			    delete_contents(otmp);	/* no spellbook */
2589			otmp->spe = ishistoric ? STATUE_HISTORIC : 0;
2590			break;
2591		case SCALE_MAIL:
2592			/* Dragon mail - depends on the order of objects */
2593			/*		 & dragons.			 */
2594			if (mntmp >= PM_GRAY_DRAGON &&
2595						mntmp <= PM_YELLOW_DRAGON)
2596			    otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
2597						    mntmp - PM_GRAY_DRAGON;
2598			break;
2599		}
2600	}
2601
2602	/* set blessed/cursed -- setting the fields directly is safe
2603	 * since weight() is called below and addinv() will take care
2604	 * of luck */
2605	if (iscursed) {
2606		curse(otmp);
2607	} else if (uncursed) {
2608		otmp->blessed = 0;
2609		otmp->cursed = (Luck < 0
2610#ifdef WIZARD
2611					 && !wizard
2612#endif
2613							);
2614	} else if (blessed) {
2615		otmp->blessed = (Luck >= 0
2616#ifdef WIZARD
2617					 || wizard
2618#endif
2619							);
2620		otmp->cursed = (Luck < 0
2621#ifdef WIZARD
2622					 && !wizard
2623#endif
2624							);
2625	} else if (spesgn < 0) {
2626		curse(otmp);
2627	}
2628
2629#ifdef INVISIBLE_OBJECTS
2630	if (isinvisible) otmp->oinvis = 1;
2631#endif
2632
2633	/* set eroded */
2634	if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) {
2635	    if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
2636		    otmp->oeroded = eroded;
2637	    if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
2638		    otmp->oeroded2 = eroded2;
2639
2640	    /* set erodeproof */
2641	    if (erodeproof && !eroded && !eroded2)
2642		    otmp->oerodeproof = (Luck >= 0
2643#ifdef WIZARD
2644					     || wizard
2645#endif
2646					);
2647	}
2648
2649	/* set otmp->recharged */
2650	if (oclass == WAND_CLASS) {
2651	    /* prevent wishing abuse */
2652	    if (otmp->otyp == WAN_WISHING
2653#ifdef WIZARD
2654		    && !wizard
2655#endif
2656		) rechrg = 1;
2657	    otmp->recharged = (unsigned)rechrg;
2658	}
2659
2660	/* set poisoned */
2661	if (ispoisoned) {
2662	    if (is_poisonable(otmp))
2663		otmp->opoisoned = (Luck >= 0);
2664	    else if (Is_box(otmp) || typ == TIN)
2665		otmp->otrapped = 1;
2666	    else if (oclass == FOOD_CLASS)
2667		/* try to taint by making it as old as possible */
2668		otmp->age = 1L;
2669	}
2670
2671	if (isgreased) otmp->greased = 1;
2672
2673	if (isdiluted && otmp->oclass == POTION_CLASS &&
2674			otmp->otyp != POT_WATER)
2675		otmp->odiluted = 1;
2676
2677	if (name) {
2678		const char *aname;
2679		short objtyp;
2680
2681		/* an artifact name might need capitalization fixing */
2682		aname = artifact_name(name, &objtyp);
2683		if (aname && objtyp == otmp->otyp) name = aname;
2684
2685		otmp = oname(otmp, name);
2686		if (otmp->oartifact) {
2687			otmp->quan = 1L;
2688			u.uconduct.wisharti++;	/* KMH, conduct */
2689		}
2690	}
2691
2692	/* more wishing abuse: don't allow wishing for certain artifacts */
2693	/* and make them pay; charge them for the wish anyway! */
2694	if ((is_quest_artifact(otmp) ||
2695	     (otmp->oartifact && rn2(nartifact_exist()) > 1))
2696#ifdef WIZARD
2697	    && !wizard
2698#endif
2699	    ) {
2700	    artifact_exists(otmp, ONAME(otmp), FALSE);
2701	    obfree(otmp, (struct obj *) 0);
2702	    otmp = &zeroobj;
2703	    pline("For a moment, you feel %s in your %s, but it disappears!",
2704		  something,
2705		  makeplural(body_part(HAND)));
2706	}
2707
2708	if (halfeaten && otmp->oclass == FOOD_CLASS) {
2709		if (otmp->otyp == CORPSE)
2710			otmp->oeaten = mons[otmp->corpsenm].cnutrit;
2711		else otmp->oeaten = objects[otmp->otyp].oc_nutrition;
2712		/* (do this adjustment before setting up object's weight) */
2713		consume_oeaten(otmp, 1);
2714	}
2715	otmp->owt = weight(otmp);
2716	if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160;
2717
2718	return(otmp);
2719}
2720
2721int
2722rnd_class(first,last)
2723int first,last;
2724{
2725	int i, x, sum=0;
2726
2727	if (first == last)
2728	    return (first);
2729	for(i=first; i<=last; i++)
2730		sum += objects[i].oc_prob;
2731	if (!sum) /* all zero */
2732		return first + rn2(last-first+1);
2733	x = rnd(sum);
2734	for(i=first; i<=last; i++)
2735		if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
2736			return i;
2737	return 0;
2738}
2739
2740STATIC_OVL const char *
2741Japanese_item_name(i)
2742int i;
2743{
2744	struct Jitem *j = Japanese_items;
2745
2746	while(j->item) {
2747		if (i == j->item)
2748			return j->name;
2749		j++;
2750	}
2751	return (const char *)0;
2752}
2753
2754const char *
2755cloak_simple_name(cloak)
2756struct obj *cloak;
2757{
2758    if (cloak) {
2759	switch (cloak->otyp) {
2760	case ROBE:
2761	    return "robe";
2762	case MUMMY_WRAPPING:
2763	    return "wrapping";
2764	case ALCHEMY_SMOCK:
2765	    return (objects[cloak->otyp].oc_name_known &&
2766			cloak->dknown) ? "smock" : "apron";
2767	default:
2768	    break;
2769	}
2770    }
2771    return "cloak";
2772}
2773
2774const char *
2775mimic_obj_name(mtmp)
2776struct monst *mtmp;
2777{
2778	if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) {
2779		int idx = objects[mtmp->mappearance].oc_descr_idx;
2780		if (mtmp->mappearance == GOLD_PIECE) return "gold";
2781		return obj_descr[idx].oc_name;
2782	}
2783	return "whatcha-may-callit";
2784}
2785#endif /* OVLB */
2786
2787/*objnam.c*/
2788