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 *
strprepend(s,pref)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 *
obj_typename(otyp)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 *
simple_typename(otyp)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
obj_is_pname(obj)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 *
distant_name(obj,func)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 *
xname(obj)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
the_unique_obj(obj)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
add_erosion_words(obj,prefix)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 *
doname(obj)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
not_fully_identified(otmp)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 *
corpse_xname(otmp,ignore_oquan)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 *
singular(otmp,func)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 *
an(str)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 *
An(str)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 *
the(str)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 *
The(str)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 *
aobjnam(otmp,verb)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 *
Doname2(obj)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 *
yname(obj)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 *
Yname2(obj)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 *
makeplural(oldstr)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 *
makesingular(oldstr)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
wishymatch(u_str,o_str,retry_inverted)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 *
readobjnam(bp)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
rnd_class(first,last)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 *
Japanese_item_name(i)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*/
2429