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