OSDN Git Service

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