NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / src / objnam.c
blob65535391e694fe2b1dc3f224823e087289d3f8c4
1 /* aNetHack 0.0.1 objnam.c $ANH-Date: 1471112245 2016/08/13 18:17:25 $ $ANH-Branch: master $:$ANH-Revision: 1.178 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 /* "an uncursed greased partly eaten guardian naga hatchling [corpse]" */
8 #define PREFIX 80 /* (56) */
9 #define SCHAR_LIM 127
10 #define NUMOBUF 12
12 STATIC_DCL char *FDECL(strprepend, (char *, const char *));
13 STATIC_DCL short FDECL(rnd_otyp_by_wpnskill, (SCHAR_P));
14 STATIC_DCL short FDECL(rnd_otyp_by_namedesc, (char *, CHAR_P));
15 STATIC_DCL boolean FDECL(wishymatch, (const char *, const char *, BOOLEAN_P));
16 STATIC_DCL char *NDECL(nextobuf);
17 STATIC_DCL void FDECL(releaseobuf, (char *));
18 STATIC_DCL char *FDECL(minimal_xname, (struct obj *));
19 STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *));
20 STATIC_DCL char *FDECL(doname_base, (struct obj *obj, unsigned));
21 STATIC_DCL boolean FDECL(singplur_lookup, (char *, char *, BOOLEAN_P,
22 const char *const *));
23 STATIC_DCL char *FDECL(singplur_compound, (char *));
24 STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
26 struct Jitem {
27 int item;
28 const char *name;
31 #define BSTRCMPI(base, ptr, str) ((ptr) < base || strcmpi((ptr), str))
32 #define BSTRNCMPI(base, ptr, str, num) \
33 ((ptr) < base || strncmpi((ptr), str, num))
34 #define Strcasecpy(dst, src) (void) strcasecpy(dst, src)
36 /* true for gems/rocks that should have " stone" appended to their names */
37 #define GemStone(typ) \
38 (typ == FLINT \
39 || (objects[typ].oc_material == GEMSTONE \
40 && (typ != DILITHIUM_CRYSTAL && typ != RUBY && typ != DIAMOND \
41 && typ != SAPPHIRE && typ != BLACK_OPAL && typ != EMERALD \
42 && typ != OPAL)))
44 STATIC_OVL struct Jitem Japanese_items[] = { { SHORT_SWORD, "wakizashi" },
45 { BROADSWORD, "ninja-to" },
46 { FLAIL, "nunchaku" },
47 { GLAIVE, "naginata" },
48 { LOCK_PICK, "osaku" },
49 { WOODEN_HARP, "koto" },
50 { KNIFE, "shito" },
51 { PLATE_MAIL, "tanko" },
52 { HELMET, "kabuto" },
53 { LEATHER_GLOVES, "yugake" },
54 { FOOD_RATION, "gunyoki" },
55 { POT_BOOZE, "sake" },
56 { 0, "" } };
58 STATIC_DCL const char *FDECL(Japanese_item_name, (int i));
60 STATIC_OVL char *
61 strprepend(s, pref)
62 register char *s;
63 register const char *pref;
65 register int i = (int) strlen(pref);
67 if (i > PREFIX) {
68 impossible("PREFIX too short (for %d).", i);
69 return s;
71 s -= i;
72 (void) strncpy(s, pref, i); /* do not copy trailing 0 */
73 return s;
76 /* manage a pool of BUFSZ buffers, so callers don't have to */
77 static char NEARDATA obufs[NUMOBUF][BUFSZ];
78 static int obufidx = 0;
80 STATIC_OVL char *
81 nextobuf()
83 obufidx = (obufidx + 1) % NUMOBUF;
84 return obufs[obufidx];
87 /* put the most recently allocated buffer back if possible */
88 STATIC_OVL void
89 releaseobuf(bufp)
90 char *bufp;
92 /* caller may not know whether bufp is the most recently allocated
93 buffer; if it isn't, do nothing */
94 if (bufp == obufs[obufidx])
95 obufidx = (obufidx - 1 + NUMOBUF) % NUMOBUF;
98 char *
99 obj_typename(otyp)
100 register int otyp;
102 char *buf = nextobuf();
103 register struct objclass *ocl = &objects[otyp];
104 register const char *actualn = OBJ_NAME(*ocl);
105 register const char *dn = OBJ_DESCR(*ocl);
106 register const char *un = ocl->oc_uname;
107 register int nn = ocl->oc_name_known;
109 if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
110 actualn = Japanese_item_name(otyp);
111 switch (ocl->oc_class) {
112 case COIN_CLASS:
113 Strcpy(buf, "coin");
114 break;
115 case POTION_CLASS:
116 Strcpy(buf, "potion");
117 break;
118 case SCROLL_CLASS:
119 Strcpy(buf, "scroll");
120 break;
121 case WAND_CLASS:
122 Strcpy(buf, "wand");
123 break;
124 case SPBOOK_CLASS:
125 if (otyp != SPE_NOVEL) {
126 Strcpy(buf, "spellbook");
127 } else {
128 Strcpy(buf, !nn ? "book" : "novel");
129 nn = 0;
131 break;
132 case RING_CLASS:
133 Strcpy(buf, "ring");
134 break;
135 case AMULET_CLASS:
136 if (nn)
137 Strcpy(buf, actualn);
138 else
139 Strcpy(buf, "amulet");
140 if (un)
141 Sprintf(eos(buf), " called %s", un);
142 if (dn)
143 Sprintf(eos(buf), " (%s)", dn);
144 return buf;
145 default:
146 if (nn) {
147 Strcpy(buf, actualn);
148 if (GemStone(otyp))
149 Strcat(buf, " stone");
150 if (un)
151 Sprintf(eos(buf), " called %s", un);
152 if (dn)
153 Sprintf(eos(buf), " (%s)", dn);
154 } else {
155 Strcpy(buf, dn ? dn : actualn);
156 if (ocl->oc_class == GEM_CLASS)
157 Strcat(buf,
158 (ocl->oc_material == MINERAL) ? " stone" : " gem");
159 if (un)
160 Sprintf(eos(buf), " called %s", un);
162 return buf;
164 /* here for ring/scroll/potion/wand */
165 if (nn) {
166 if (ocl->oc_unique)
167 Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */
168 else
169 Sprintf(eos(buf), " of %s", actualn);
171 if (un)
172 Sprintf(eos(buf), " called %s", un);
173 if (dn)
174 Sprintf(eos(buf), " (%s)", dn);
175 return buf;
178 /* less verbose result than obj_typename(); either the actual name
179 or the description (but not both); user-assigned name is ignored */
180 char *
181 simple_typename(otyp)
182 int otyp;
184 char *bufp, *pp, *save_uname = objects[otyp].oc_uname;
186 objects[otyp].oc_uname = 0; /* suppress any name given by user */
187 bufp = obj_typename(otyp);
188 objects[otyp].oc_uname = save_uname;
189 if ((pp = strstri(bufp, " (")) != 0)
190 *pp = '\0'; /* strip the appended description */
191 return bufp;
194 boolean
195 obj_is_pname(obj)
196 struct obj *obj;
198 if (!obj->oartifact || !has_oname(obj))
199 return FALSE;
200 if (!program_state.gameover && !iflags.override_ID) {
201 if (not_fully_identified(obj))
202 return FALSE;
204 return TRUE;
207 /* used by distant_name() to pass extra information to xname_flags();
208 it would be much cleaner if this were a parameter, but that would
209 require all of the xname() and doname() calls to be modified */
210 static int distantname = 0;
212 /* Give the name of an object seen at a distance. Unlike xname/doname,
213 * we don't want to set dknown if it's not set already.
215 char *
216 distant_name(obj, func)
217 struct obj *obj;
218 char *FDECL((*func), (OBJ_P));
220 char *str;
222 /* 3.6.1: this used to save Blind, set it, make the call, then restore
223 * the saved value; but the Eyes of the Overworld override blindness
224 * and let characters wearing them get dknown set for distant items.
226 * TODO? if the hero is wearing those Eyes, figure out whether the
227 * object is within X-ray radius and only treat it as distant when
228 * beyond that radius. Logic is iffy but result might be interesting.
230 ++distantname;
231 str = (*func)(obj);
232 --distantname;
233 return str;
236 /* convert player specified fruit name into corresponding fruit juice name
237 ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
238 char *
239 fruitname(juice)
240 boolean juice; /* whether or not to append " juice" to the name */
242 char *buf = nextobuf();
243 const char *fruit_nam = strstri(pl_fruit, " of ");
245 if (fruit_nam)
246 fruit_nam += 4; /* skip past " of " */
247 else
248 fruit_nam = pl_fruit; /* use it as is */
250 Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : "");
251 return buf;
254 char *
255 xname(obj)
256 struct obj *obj;
258 return xname_flags(obj, CXN_NORMAL);
261 char *
262 xname_flags(obj, cxn_flags)
263 register struct obj *obj;
264 unsigned cxn_flags; /* bitmask of CXN_xxx values */
266 register char *buf;
267 register int typ = obj->otyp;
268 register struct objclass *ocl = &objects[typ];
269 int nn = ocl->oc_name_known, omndx = obj->corpsenm;
270 const char *actualn = OBJ_NAME(*ocl);
271 const char *dn = OBJ_DESCR(*ocl) ? OBJ_DESCR(*ocl) : actualn;
272 const char *un = ocl->oc_uname;
273 boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR);
274 boolean known, dknown, bknown;
276 buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */
277 if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
278 actualn = Japanese_item_name(typ);
280 buf[0] = '\0';
282 * clean up known when it's tied to oc_name_known, eg after AD_DRIN
283 * This is only required for unique objects since the article
284 * printed for the object is tied to the combination of the two
285 * and printing the wrong article gives away information.
287 if (!nn && ocl->oc_uses_known && ocl->oc_unique)
288 obj->known = 0;
289 if (!Blind && !distantname)
290 obj->dknown = TRUE;
291 if (Role_if(PM_PRIEST))
292 obj->bknown = TRUE;
294 if (iflags.override_ID) {
295 known = dknown = bknown = TRUE;
296 nn = 1;
297 } else {
298 known = obj->known;
299 dknown = obj->dknown;
300 bknown = obj->bknown;
303 if (obj_is_pname(obj))
304 goto nameit;
305 switch (obj->oclass) {
306 case AMULET_CLASS:
307 if (!dknown)
308 Strcpy(buf, "amulet");
309 else if (typ == AMULET_OF_YENDOR || typ == FAKE_AMULET_OF_YENDOR)
310 /* each must be identified individually */
311 Strcpy(buf, known ? actualn : dn);
312 else if (nn)
313 Strcpy(buf, actualn);
314 else if (un)
315 Sprintf(buf, "amulet called %s", un);
316 else
317 Sprintf(buf, "%s amulet", dn);
318 break;
319 case WEAPON_CLASS:
320 if (is_poisonable(obj) && obj->opoisoned)
321 Strcpy(buf, "poisoned ");
322 case VENOM_CLASS:
323 case TOOL_CLASS:
324 if (typ == LENSES)
325 Strcpy(buf, "pair of ");
326 else if (is_wet_towel(obj))
327 Strcpy(buf, (obj->spe < 3) ? "moist " : "wet ");
329 if (!dknown)
330 Strcat(buf, dn);
331 else if (nn)
332 Strcat(buf, actualn);
333 else if (un) {
334 Strcat(buf, dn);
335 Strcat(buf, " called ");
336 Strcat(buf, un);
337 } else
338 Strcat(buf, dn);
339 /* If we use an() here we'd have to remember never to use */
340 /* it whenever calling doname() or xname(). */
341 if (typ == FIGURINE && omndx != NON_PM) {
342 Sprintf(eos(buf), " of a%s %s",
343 index(vowels, *mons[omndx].mname) ? "n" : "",
344 mons[omndx].mname);
345 } else if (is_wet_towel(obj)) {
346 if (wizard)
347 Sprintf(eos(buf), " (%d)", obj->spe);
349 break;
350 case ARMOR_CLASS:
351 /* depends on order of the dragon scales objects */
352 if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
353 Sprintf(buf, "set of %s", actualn);
354 break;
356 if (is_boots(obj) || is_gloves(obj))
357 Strcpy(buf, "pair of ");
359 if (obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
360 && !dknown) {
361 Strcpy(buf, "shield");
362 break;
364 if (obj->otyp == SHIELD_OF_REFLECTION && !dknown) {
365 Strcpy(buf, "smooth shield");
366 break;
369 if (nn)
370 Strcat(buf, actualn);
371 else if (un) {
372 if (is_boots(obj))
373 Strcat(buf, "boots");
374 else if (is_gloves(obj))
375 Strcat(buf, "gloves");
376 else if (is_cloak(obj))
377 Strcpy(buf, "cloak");
378 else if (is_helmet(obj))
379 Strcpy(buf, "helmet");
380 else if (is_shield(obj))
381 Strcpy(buf, "shield");
382 else
383 Strcpy(buf, "armor");
384 Strcat(buf, " called ");
385 Strcat(buf, un);
386 } else
387 Strcat(buf, dn);
388 break;
389 case FOOD_CLASS:
390 if (typ == SLIME_MOLD) {
391 register struct fruit *f;
393 for (f = ffruit; f; f = f->nextf) {
394 if (f->fid == obj->spe) {
395 Strcpy(buf, f->fname);
396 break;
399 if (!f) {
400 impossible("Bad fruit #%d?", obj->spe);
401 Strcpy(buf, "fruit");
402 } else if (pluralize) {
403 /* ick; already pluralized fruit names
404 are allowed--we want to try to avoid
405 adding a redundant plural suffix */
406 Strcpy(buf, makeplural(makesingular(buf)));
407 pluralize = FALSE;
409 break;
411 if (obj->globby) {
412 Sprintf(buf, "%s%s",
413 (obj->owt <= 100)
414 ? "small "
415 : (obj->owt > 500)
416 ? "very large "
417 : (obj->owt > 300)
418 ? "large "
419 : "",
420 actualn);
421 break;
424 Strcpy(buf, actualn);
425 if (typ == TIN && known)
426 tin_details(obj, omndx, buf);
427 break;
428 case COIN_CLASS:
429 case CHAIN_CLASS:
430 Strcpy(buf, actualn);
431 break;
432 case ROCK_CLASS:
433 if (typ == STATUE && omndx != NON_PM)
434 Sprintf(buf, "%s%s of %s%s",
435 (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC))
436 ? "historic "
437 : "",
438 actualn,
439 type_is_pname(&mons[omndx])
440 ? ""
441 : the_unique_pm(&mons[omndx])
442 ? "the "
443 : index(vowels, *mons[omndx].mname)
444 ? "an "
445 : "a ",
446 mons[omndx].mname);
447 else
448 Strcpy(buf, actualn);
449 break;
450 case BALL_CLASS:
451 Sprintf(buf, "%sheavy iron ball",
452 (obj->owt > ocl->oc_weight) ? "very " : "");
453 break;
454 case POTION_CLASS:
455 if (dknown && obj->odiluted)
456 Strcpy(buf, "diluted ");
457 if (nn || un || !dknown) {
458 Strcat(buf, "potion");
459 if (!dknown)
460 break;
461 if (nn) {
462 Strcat(buf, " of ");
463 if (typ == POT_WATER && bknown
464 && (obj->blessed || obj->cursed)) {
465 Strcat(buf, obj->blessed ? "holy " : "unholy ");
467 Strcat(buf, actualn);
468 } else {
469 Strcat(buf, " called ");
470 Strcat(buf, un);
472 } else {
473 Strcat(buf, dn);
474 Strcat(buf, " potion");
476 break;
477 case SCROLL_CLASS:
478 Strcpy(buf, "scroll");
479 if (!dknown)
480 break;
481 if (nn) {
482 Strcat(buf, " of ");
483 Strcat(buf, actualn);
484 } else if (un) {
485 Strcat(buf, " called ");
486 Strcat(buf, un);
487 } else if (ocl->oc_magic) {
488 Strcat(buf, " labeled ");
489 Strcat(buf, dn);
490 } else {
491 Strcpy(buf, dn);
492 Strcat(buf, " scroll");
494 break;
495 case WAND_CLASS:
496 if (!dknown)
497 Strcpy(buf, "wand");
498 else if (nn)
499 Sprintf(buf, "wand of %s", actualn);
500 else if (un)
501 Sprintf(buf, "wand called %s", un);
502 else
503 Sprintf(buf, "%s wand", dn);
504 break;
505 case SPBOOK_CLASS:
506 if (typ == SPE_NOVEL) { /* 3.6 tribute */
507 if (!dknown)
508 Strcpy(buf, "book");
509 else if (nn)
510 Strcpy(buf, actualn);
511 else if (un)
512 Sprintf(buf, "novel called %s", un);
513 else
514 Sprintf(buf, "%s book", dn);
515 break;
516 /* end of tribute */
517 } else if (!dknown) {
518 Strcpy(buf, "spellbook");
519 } else if (nn) {
520 if (typ != SPE_BOOK_OF_THE_DEAD)
521 Strcpy(buf, "spellbook of ");
522 Strcat(buf, actualn);
523 } else if (un) {
524 Sprintf(buf, "spellbook called %s", un);
525 } else
526 Sprintf(buf, "%s spellbook", dn);
527 break;
528 case RING_CLASS:
529 if (!dknown)
530 Strcpy(buf, "ring");
531 else if (nn)
532 Sprintf(buf, "ring of %s", actualn);
533 else if (un)
534 Sprintf(buf, "ring called %s", un);
535 else
536 Sprintf(buf, "%s ring", dn);
537 break;
538 case GEM_CLASS: {
539 const char *rock = (ocl->oc_material == MINERAL) ? "stone" : "gem";
541 if (!dknown) {
542 Strcpy(buf, rock);
543 } else if (!nn) {
544 if (un)
545 Sprintf(buf, "%s called %s", rock, un);
546 else
547 Sprintf(buf, "%s %s", dn, rock);
548 } else {
549 Strcpy(buf, actualn);
550 if (GemStone(typ))
551 Strcat(buf, " stone");
553 break;
555 default:
556 Sprintf(buf, "glorkum %d %d %d", obj->oclass, typ, obj->spe);
558 if (pluralize)
559 Strcpy(buf, makeplural(buf));
561 if (obj->otyp == T_SHIRT && program_state.gameover) {
562 char tmpbuf[BUFSZ];
564 Sprintf(eos(buf), " with text \"%s\"", tshirt_text(obj, tmpbuf));
567 if (has_oname(obj) && dknown) {
568 Strcat(buf, " named ");
569 nameit:
570 Strcat(buf, ONAME(obj));
573 if (!strncmpi(buf, "the ", 4))
574 buf += 4;
575 return buf;
578 /* similar to simple_typename but minimal_xname operates on a particular
579 object rather than its general type; it formats the most basic info:
580 potion -- if description not known
581 brown potion -- if oc_name_known not set
582 potion of object detection -- if discovered
584 STATIC_OVL char *
585 minimal_xname(obj)
586 struct obj *obj;
588 char *bufp;
589 struct obj bareobj;
590 struct objclass saveobcls;
591 int otyp = obj->otyp;
593 /* suppress user-supplied name */
594 saveobcls.oc_uname = objects[otyp].oc_uname;
595 objects[otyp].oc_uname = 0;
596 /* suppress actual name if object's description is unknown */
597 saveobcls.oc_name_known = objects[otyp].oc_name_known;
598 if (!obj->dknown)
599 objects[otyp].oc_name_known = 0;
601 /* caveat: this makes a lot of assumptions about which fields
602 are required in order for xname() to yield a sensible result */
603 bareobj = zeroobj;
604 bareobj.otyp = otyp;
605 bareobj.oclass = obj->oclass;
606 bareobj.dknown = obj->dknown;
607 /* suppress known except for amulets (needed for fakes and real A-of-Y) */
608 bareobj.known = (obj->oclass == AMULET_CLASS)
609 ? obj->known
610 /* default is "on" for types which don't use it */
611 : !objects[otyp].oc_uses_known;
612 bareobj.quan = 1L; /* don't want plural */
613 bareobj.corpsenm = NON_PM; /* suppress statue and figurine details */
614 /* but suppressing fruit details leads to "bad fruit #0"
615 [perhaps we should force "slime mold" rather than use xname?] */
616 if (obj->otyp == SLIME_MOLD)
617 bareobj.spe = obj->spe;
619 bufp = distant_name(&bareobj, xname); /* xname(&bareobj) */
620 if (!strncmp(bufp, "uncursed ", 9))
621 bufp += 9; /* Role_if(PM_PRIEST) */
623 objects[otyp].oc_uname = saveobcls.oc_uname;
624 objects[otyp].oc_name_known = saveobcls.oc_name_known;
625 return bufp;
628 /* xname() output augmented for multishot missile feedback */
629 char *
630 mshot_xname(obj)
631 struct obj *obj;
633 char tmpbuf[BUFSZ];
634 char *onm = xname(obj);
636 if (m_shot.n > 1 && m_shot.o == obj->otyp) {
637 /* "the Nth arrow"; value will eventually be passed to an() or
638 The(), both of which correctly handle this "the " prefix */
639 Sprintf(tmpbuf, "the %d%s ", m_shot.i, ordin(m_shot.i));
640 onm = strprepend(onm, tmpbuf);
642 return onm;
645 /* used for naming "the unique_item" instead of "a unique_item" */
646 boolean
647 the_unique_obj(obj)
648 struct obj *obj;
650 boolean known = (obj->known || iflags.override_ID);
652 if (!obj->dknown && !iflags.override_ID)
653 return FALSE;
654 else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !known)
655 return TRUE; /* lie */
656 else
657 return (boolean) (objects[obj->otyp].oc_unique
658 && (known || obj->otyp == AMULET_OF_YENDOR));
661 /* should monster type be prefixed with "the"? (mostly used for corpses) */
662 boolean
663 the_unique_pm(ptr)
664 struct permonst *ptr;
666 boolean uniq;
668 /* even though monsters with personal names are unique, we want to
669 describe them as "Name" rather than "the Name" */
670 if (type_is_pname(ptr))
671 return FALSE;
673 uniq = (ptr->geno & G_UNIQ) ? TRUE : FALSE;
674 /* high priest is unique if it includes "of <deity>", otherwise not
675 (caller needs to handle the 1st possibility; we assume the 2nd);
676 worm tail should be irrelevant but is included for completeness */
677 if (ptr == &mons[PM_HIGH_PRIEST] || ptr == &mons[PM_LONG_WORM_TAIL])
678 uniq = FALSE;
679 /* Wizard no longer needs this; he's flagged as unique these days */
680 if (ptr == &mons[PM_WIZARD_OF_YENDOR])
681 uniq = TRUE;
682 return uniq;
685 STATIC_OVL void
686 add_erosion_words(obj, prefix)
687 struct obj *obj;
688 char *prefix;
690 boolean iscrys = (obj->otyp == CRYSKNIFE);
691 boolean rknown;
693 rknown = (iflags.override_ID == 0) ? obj->rknown : TRUE;
695 if (!is_damageable(obj) && !iscrys)
696 return;
698 /* The only cases where any of these bits do double duty are for
699 * rotted food and diluted potions, which are all not is_damageable().
701 if (obj->oeroded && !iscrys) {
702 switch (obj->oeroded) {
703 case 2:
704 Strcat(prefix, "very ");
705 break;
706 case 3:
707 Strcat(prefix, "thoroughly ");
708 break;
710 Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt ");
712 if (obj->oeroded2 && !iscrys) {
713 switch (obj->oeroded2) {
714 case 2:
715 Strcat(prefix, "very ");
716 break;
717 case 3:
718 Strcat(prefix, "thoroughly ");
719 break;
721 Strcat(prefix, is_corrodeable(obj) ? "corroded " : "rotted ");
723 if (rknown && obj->oerodeproof)
724 Strcat(prefix, iscrys
725 ? "fixed "
726 : is_rustprone(obj)
727 ? "rustproof "
728 : is_corrodeable(obj)
729 ? "corrodeproof " /* "stainless"? */
730 : is_flammable(obj)
731 ? "fireproof "
732 : "");
735 /* used to prevent rust on items where rust makes no difference */
736 boolean
737 erosion_matters(obj)
738 struct obj *obj;
740 switch (obj->oclass) {
741 case TOOL_CLASS:
742 /* it's possible for a rusty weptool to be polymorphed into some
743 non-weptool iron tool, in which case the rust implicitly goes
744 away, but it's also possible for it to be polymorphed into a
745 non-iron tool, in which case rust also implicitly goes away,
746 so there's no particular reason to try to handle the first
747 instance differently [this comment belongs in poly_obj()...] */
748 return is_weptool(obj) ? TRUE : FALSE;
749 case WEAPON_CLASS:
750 case ARMOR_CLASS:
751 case BALL_CLASS:
752 case CHAIN_CLASS:
753 return TRUE;
754 default:
755 break;
757 return FALSE;
760 #define DONAME_WITH_PRICE 1
761 #define DONAME_VAGUE_QUAN 2
763 STATIC_OVL char *
764 doname_base(obj, doname_flags)
765 struct obj *obj;
766 unsigned doname_flags;
768 boolean ispoisoned = FALSE,
769 with_price = (doname_flags & DONAME_WITH_PRICE) != 0,
770 vague_quan = (doname_flags & DONAME_VAGUE_QUAN) != 0;
771 boolean known, dknown, cknown, bknown, lknown;
772 int omndx = obj->corpsenm;
773 char prefix[PREFIX];
774 char tmpbuf[PREFIX + 1]; /* for when we have to add something at
775 the start of prefix instead of the
776 end (Strcat is used on the end) */
777 register char *bp = xname(obj);
779 if (iflags.override_ID) {
780 known = dknown = cknown = bknown = lknown = TRUE;
781 } else {
782 known = obj->known;
783 dknown = obj->dknown;
784 cknown = obj->cknown;
785 bknown = obj->bknown;
786 lknown = obj->lknown;
789 /* When using xname, we want "poisoned arrow", and when using
790 * doname, we want "poisoned +0 arrow". This kludge is about the only
791 * way to do it, at least until someone overhauls xname() and doname(),
792 * combining both into one function taking a parameter.
794 /* must check opoisoned--someone can have a weirdly-named fruit */
795 if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
796 bp += 9;
797 ispoisoned = TRUE;
800 if (obj->quan != 1L) {
801 if (dknown || !vague_quan)
802 Sprintf(prefix, "%ld ", obj->quan);
803 else
804 Strcpy(prefix, "some ");
805 } else if (obj->otyp == CORPSE) {
806 /* skip article prefix for corpses [else corpse_xname()
807 would have to be taught how to strip it off again] */
808 *prefix = '\0';
809 } else if (obj_is_pname(obj) || the_unique_obj(obj)) {
810 if (!strncmpi(bp, "the ", 4))
811 bp += 4;
812 Strcpy(prefix, "the ");
813 } else {
814 Strcpy(prefix, "a ");
817 /* "empty" goes at the beginning, but item count goes at the end */
818 if (cknown
819 /* bag of tricks: include "empty" prefix if it's known to
820 be empty but its precise number of charges isn't known
821 (when that is known, suffix of "(n:0)" will be appended,
822 making the prefix be redundant; note that 'known' flag
823 isn't set when emptiness gets discovered because then
824 charging magic would yield known number of new charges) */
825 && ((obj->otyp == BAG_OF_TRICKS)
826 ? (obj->spe == 0 && !obj->known)
827 /* not bag of tricks: empty if container which has no contents */
828 : ((Is_container(obj) || obj->otyp == STATUE)
829 && !Has_contents(obj))))
830 Strcat(prefix, "empty ");
832 if (bknown && obj->oclass != COIN_CLASS
833 && (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
834 || (!obj->cursed && !obj->blessed))) {
835 /* allow 'blessed clear potion' if we don't know it's holy water;
836 * always allow "uncursed potion of water"
838 if (obj->cursed)
839 Strcat(prefix, "cursed ");
840 else if (obj->blessed)
841 Strcat(prefix, "blessed ");
842 else if (!iflags.implicit_uncursed
843 /* For most items with charges or +/-, if you know how many
844 * charges are left or what the +/- is, then you must have
845 * totally identified the item, so "uncursed" is unnecessary,
846 * because an identified object not described as "blessed" or
847 * "cursed" must be uncursed.
849 * If the charges or +/- is not known, "uncursed" must be
850 * printed to avoid ambiguity between an item whose curse
851 * status is unknown, and an item known to be uncursed.
853 || ((!known || !objects[obj->otyp].oc_charged
854 || obj->oclass == ARMOR_CLASS
855 || obj->oclass == RING_CLASS)
856 #ifdef MAIL
857 && obj->otyp != SCR_MAIL
858 #endif
859 && obj->otyp != FAKE_AMULET_OF_YENDOR
860 && obj->otyp != AMULET_OF_YENDOR
861 && !Role_if(PM_PRIEST)))
862 Strcat(prefix, "uncursed ");
865 if (lknown && Is_box(obj)) {
866 if (obj->obroken)
867 /* 3.6.0 used "unlockable" here but that could be misunderstood
868 to mean "capable of being unlocked" rather than the intended
869 "not capable of being locked" */
870 Strcat(prefix, "broken ");
871 else if (obj->olocked)
872 Strcat(prefix, "locked ");
873 else
874 Strcat(prefix, "unlocked ");
877 if (obj->greased)
878 Strcat(prefix, "greased ");
880 if (cknown && Has_contents(obj)) {
881 /* we count the number of separate stacks, which corresponds
882 to the number of inventory slots needed to be able to take
883 everything out if no merges occur */
884 long itemcount = count_contents(obj, FALSE, FALSE, TRUE);
886 Sprintf(eos(bp), " containing %ld item%s", itemcount,
887 plur(itemcount));
890 switch (is_weptool(obj) ? WEAPON_CLASS : obj->oclass) {
891 case AMULET_CLASS:
892 if (obj->owornmask & W_AMUL)
893 Strcat(bp, " (being worn)");
894 break;
895 case ARMOR_CLASS:
896 if (obj->owornmask & W_ARMOR)
897 Strcat(bp, (obj == uskin) ? " (embedded in your skin)"
898 : " (being worn)");
899 /*FALLTHRU*/
900 case WEAPON_CLASS:
901 if (ispoisoned)
902 Strcat(prefix, "poisoned ");
903 add_erosion_words(obj, prefix);
904 if (known) {
905 Strcat(prefix, sitoa(obj->spe));
906 Strcat(prefix, " ");
908 break;
909 case TOOL_CLASS:
910 if (obj->owornmask & (W_TOOL | W_SADDLE)) { /* blindfold */
911 Strcat(bp, " (being worn)");
912 break;
914 if (obj->otyp == LEASH && obj->leashmon != 0) {
915 struct monst *mlsh = find_mid(obj->leashmon, FM_FMON);
917 if (!mlsh) {
918 impossible("leashed monster not on this level");
919 obj->leashmon = 0;
920 } else {
921 Sprintf(eos(bp), " (attached to %s)",
922 a_monnam(mlsh));
924 break;
926 if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
927 if (!obj->spe)
928 Strcpy(tmpbuf, "no");
929 else
930 Sprintf(tmpbuf, "%d", obj->spe);
931 Sprintf(eos(bp), " (%s candle%s%s)", tmpbuf, plur(obj->spe),
932 !obj->lamplit ? " attached" : ", lit");
933 break;
934 } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
935 || obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
936 if (Is_candle(obj)
937 && obj->age < 20L * (long) objects[obj->otyp].oc_cost)
938 Strcat(prefix, "partly used ");
939 if (obj->lamplit)
940 Strcat(bp, " (lit)");
941 break;
943 if (objects[obj->otyp].oc_charged)
944 goto charges;
945 break;
946 case WAND_CLASS:
947 charges:
948 if (known)
949 Sprintf(eos(bp), " (%d:%d)", (int) obj->recharged, obj->spe);
950 break;
951 case POTION_CLASS:
952 if (obj->otyp == POT_OIL && obj->lamplit)
953 Strcat(bp, " (lit)");
954 break;
955 case RING_CLASS:
956 ring:
957 if (obj->owornmask & W_RINGR)
958 Strcat(bp, " (on right ");
959 if (obj->owornmask & W_RINGL)
960 Strcat(bp, " (on left ");
961 if (obj->owornmask & W_RING) {
962 Strcat(bp, body_part(HAND));
963 Strcat(bp, ")");
965 if (known && objects[obj->otyp].oc_charged) {
966 Strcat(prefix, sitoa(obj->spe));
967 Strcat(prefix, " ");
969 break;
970 case FOOD_CLASS:
971 if (obj->oeaten)
972 Strcat(prefix, "partly eaten ");
973 if (obj->otyp == CORPSE) {
974 /* (quan == 1) => want corpse_xname() to supply article,
975 (quan != 1) => already have count or "some" as prefix;
976 "corpse" is already in the buffer returned by xname() */
977 unsigned cxarg = (((obj->quan != 1L) ? 0 : CXN_ARTICLE)
978 | CXN_NOCORPSE);
980 Sprintf(prefix, "%s ", corpse_xname(obj, prefix, cxarg));
981 } else if (obj->otyp == EGG) {
982 #if 0 /* corpses don't tell if they're stale either */
983 if (known && stale_egg(obj))
984 Strcat(prefix, "stale ");
985 #endif
986 if (omndx >= LOW_PM
987 && (known || (mvitals[omndx].mvflags & MV_KNOWS_EGG))) {
988 Strcat(prefix, mons[omndx].mname);
989 Strcat(prefix, " ");
990 if (obj->spe)
991 Strcat(bp, " (laid by you)");
994 if (obj->otyp == MEAT_RING)
995 goto ring;
996 break;
997 case BALL_CLASS:
998 case CHAIN_CLASS:
999 add_erosion_words(obj, prefix);
1000 if (obj->owornmask & W_BALL)
1001 Strcat(bp, " (chained to you)");
1002 break;
1005 if ((obj->owornmask & W_WEP) && !mrg_to_wielded) {
1006 if (obj->quan != 1L) {
1007 Strcat(bp, " (wielded)");
1008 } else {
1009 const char *hand_s = body_part(HAND);
1011 if (bimanual(obj))
1012 hand_s = makeplural(hand_s);
1013 Sprintf(eos(bp), " (weapon in %s)", hand_s);
1015 if (warn_obj_cnt && obj == uwep && (EWarn_of_mon & W_WEP) != 0L) {
1016 /* presumably can be felt when blind */
1017 Strcat(bp, " (glowing");
1018 if (!Blind)
1019 Sprintf(eos(bp), " %s", glow_color(obj->oartifact));
1020 Strcat(bp, ")");
1024 if (obj->owornmask & W_SWAPWEP) {
1025 if (u.twoweap)
1026 Sprintf(eos(bp), " (wielded in other %s)", body_part(HAND));
1027 else
1028 Strcat(bp, " (alternate weapon; not wielded)");
1030 if (obj->owornmask & W_QUIVER) {
1031 switch (obj->oclass) {
1032 case WEAPON_CLASS:
1033 if (is_ammo(obj)) {
1034 if (objects[obj->otyp].oc_skill == -P_BOW) {
1035 /* Ammo for a bow */
1036 Strcat(bp, " (in quiver)");
1037 break;
1038 } else {
1039 /* Ammo not for a bow */
1040 Strcat(bp, " (in quiver pouch)");
1041 break;
1043 } else {
1044 /* Weapons not considered ammo */
1045 Strcat(bp, " (at the ready)");
1046 break;
1048 /* Small things and ammo not for a bow */
1049 case RING_CLASS:
1050 case AMULET_CLASS:
1051 case WAND_CLASS:
1052 case COIN_CLASS:
1053 case GEM_CLASS:
1054 Strcat(bp, " (in quiver pouch)");
1055 break;
1056 default: /* odd things */
1057 Strcat(bp, " (at the ready)");
1060 if (!iflags.suppress_price && is_unpaid(obj)) {
1061 long quotedprice = unpaid_cost(obj, TRUE);
1063 Sprintf(eos(bp), " (%s, %ld %s)",
1064 obj->unpaid ? "unpaid" : "contents",
1065 quotedprice, currency(quotedprice));
1066 } else if (with_price) {
1067 long price = get_cost_of_shop_item(obj);
1069 if (price > 0)
1070 Sprintf(eos(bp), " (%ld %s)", price, currency(price));
1072 if (!strncmp(prefix, "a ", 2)
1073 && index(vowels, *(prefix + 2) ? *(prefix + 2) : *bp)
1074 && (*(prefix + 2)
1075 || (strncmp(bp, "uranium", 7) && strncmp(bp, "unicorn", 7)
1076 && strncmp(bp, "eucalyptus", 10)))) {
1077 Strcpy(tmpbuf, prefix);
1078 Strcpy(prefix, "an ");
1079 Strcpy(prefix + 3, tmpbuf + 2);
1082 /* show weight for items (debug tourist info)
1083 * aum is stolen from Crawl's "Arbitrary Unit of Measure" */
1084 if (wizard && iflags.wizweight) {
1085 Sprintf(eos(bp), " (%d aum)", obj->owt);
1087 bp = strprepend(bp, prefix);
1088 return bp;
1091 char *
1092 doname(obj)
1093 struct obj *obj;
1095 return doname_base(obj, (unsigned) 0);
1098 /* Name of object including price. */
1099 char *
1100 doname_with_price(obj)
1101 struct obj *obj;
1103 return doname_base(obj, DONAME_WITH_PRICE);
1106 /* "some" instead of precise quantity if obj->dknown not set */
1107 char *
1108 doname_vague_quan(obj)
1109 struct obj *obj;
1111 /* Used by farlook.
1112 * If it hasn't been seen up close and quantity is more than one,
1113 * use "some" instead of the quantity: "some gold pieces" rather
1114 * than "25 gold pieces". This is suboptimal, to put it mildly,
1115 * because lookhere and pickup report the precise amount.
1116 * Picking the item up while blind also shows the precise amount
1117 * for inventory display, then dropping it while still blind leaves
1118 * obj->dknown unset so the count reverts to "some" for farlook.
1120 * TODO: add obj->qknown flag for 'quantity known' on stackable
1121 * items; it could overlay obj->cknown since no containers stack.
1123 return doname_base(obj, DONAME_VAGUE_QUAN);
1126 /* used from invent.c */
1127 boolean
1128 not_fully_identified(otmp)
1129 struct obj *otmp;
1131 /* gold doesn't have any interesting attributes [yet?] */
1132 if (otmp->oclass == COIN_CLASS)
1133 return FALSE; /* always fully ID'd */
1134 /* check fundamental ID hallmarks first */
1135 if (!otmp->known || !otmp->dknown
1136 #ifdef MAIL
1137 || (!otmp->bknown && otmp->otyp != SCR_MAIL)
1138 #else
1139 || !otmp->bknown
1140 #endif
1141 || !objects[otmp->otyp].oc_name_known)
1142 return TRUE;
1143 if ((!otmp->cknown && (Is_container(otmp) || otmp->otyp == STATUE))
1144 || (!otmp->lknown && Is_box(otmp)))
1145 return TRUE;
1146 if (otmp->oartifact && undiscovered_artifact(otmp->oartifact))
1147 return TRUE;
1148 /* otmp->rknown is the only item of interest if we reach here */
1150 * Note: if a revision ever allows scrolls to become fireproof or
1151 * rings to become shockproof, this checking will need to be revised.
1152 * `rknown' ID only matters if xname() will provide the info about it.
1154 if (otmp->rknown
1155 || (otmp->oclass != ARMOR_CLASS && otmp->oclass != WEAPON_CLASS
1156 && !is_weptool(otmp) /* (redundant) */
1157 && otmp->oclass != BALL_CLASS)) /* (useless) */
1158 return FALSE;
1159 else /* lack of `rknown' only matters for vulnerable objects */
1160 return (boolean) (is_rustprone(otmp) || is_corrodeable(otmp)
1161 || is_flammable(otmp));
1164 /* format a corpse name (xname() omits monster type; doname() calls us);
1165 eatcorpse() also uses us for death reason when eating tainted glob */
1166 char *
1167 corpse_xname(otmp, adjective, cxn_flags)
1168 struct obj *otmp;
1169 const char *adjective;
1170 unsigned cxn_flags; /* bitmask of CXN_xxx values */
1172 char *nambuf = nextobuf();
1173 int omndx = otmp->corpsenm;
1174 boolean ignore_quan = (cxn_flags & CXN_SINGULAR) != 0,
1175 /* suppress "the" from "the unique monster corpse" */
1176 no_prefix = (cxn_flags & CXN_NO_PFX) != 0,
1177 /* include "the" for "the woodchuck corpse */
1178 the_prefix = (cxn_flags & CXN_PFX_THE) != 0,
1179 /* include "an" for "an ogre corpse */
1180 any_prefix = (cxn_flags & CXN_ARTICLE) != 0,
1181 /* leave off suffix (do_name() appends "corpse" itself) */
1182 omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0,
1183 possessive = FALSE,
1184 glob = (otmp->otyp != CORPSE && otmp->globby);
1185 const char *mname;
1187 if (glob) {
1188 mname = OBJ_NAME(objects[otmp->otyp]); /* "glob of <monster>" */
1189 } else if (omndx == NON_PM) { /* paranoia */
1190 mname = "thing";
1191 /* [Possible enhancement: check whether corpse has monster traits
1192 attached in order to use priestname() for priests and minions.] */
1193 } else if (omndx == PM_ALIGNED_PRIEST) {
1194 /* avoid "aligned priest"; it just exposes internal details */
1195 mname = "priest";
1196 } else {
1197 mname = mons[omndx].mname;
1198 if (the_unique_pm(&mons[omndx]) || type_is_pname(&mons[omndx])) {
1199 mname = s_suffix(mname);
1200 possessive = TRUE;
1201 /* don't precede personal name like "Medusa" with an article */
1202 if (type_is_pname(&mons[omndx]))
1203 no_prefix = TRUE;
1204 /* always precede non-personal unique monster name like
1205 "Oracle" with "the" unless explicitly overridden */
1206 else if (the_unique_pm(&mons[omndx]) && !no_prefix)
1207 the_prefix = TRUE;
1210 if (no_prefix)
1211 the_prefix = any_prefix = FALSE;
1212 else if (the_prefix)
1213 any_prefix = FALSE; /* mutually exclusive */
1215 *nambuf = '\0';
1216 /* can't use the() the way we use an() below because any capitalized
1217 Name causes it to assume a personal name and return Name as-is;
1218 that's usually the behavior wanted, but here we need to force "the"
1219 to precede capitalized unique monsters (pnames are handled above) */
1220 if (the_prefix)
1221 Strcat(nambuf, "the ");
1223 if (!adjective || !*adjective) {
1224 /* normal case: newt corpse */
1225 Strcat(nambuf, mname);
1226 } else {
1227 /* adjective positioning depends upon format of monster name */
1228 if (possessive) /* Medusa's cursed partly eaten corpse */
1229 Sprintf(eos(nambuf), "%s %s", mname, adjective);
1230 else /* cursed partly eaten troll corpse */
1231 Sprintf(eos(nambuf), "%s %s", adjective, mname);
1232 /* in case adjective has a trailing space, squeeze it out */
1233 mungspaces(nambuf);
1234 /* doname() might include a count in the adjective argument;
1235 if so, don't prepend an article */
1236 if (digit(*adjective))
1237 any_prefix = FALSE;
1240 if (glob) {
1241 ; /* omit_corpse doesn't apply; quantity is always 1 */
1242 } else if (!omit_corpse) {
1243 Strcat(nambuf, " corpse");
1244 /* makeplural(nambuf) => append "s" to "corpse" */
1245 if (otmp->quan > 1L && !ignore_quan) {
1246 Strcat(nambuf, "s");
1247 any_prefix = FALSE; /* avoid "a newt corpses" */
1251 /* it's safe to overwrite our nambuf after an() has copied
1252 its old value into another buffer */
1253 if (any_prefix)
1254 Strcpy(nambuf, an(nambuf));
1256 return nambuf;
1259 /* xname doesn't include monster type for "corpse"; cxname does */
1260 char *
1261 cxname(obj)
1262 struct obj *obj;
1264 if (obj->otyp == CORPSE)
1265 return corpse_xname(obj, (const char *) 0, CXN_NORMAL);
1266 return xname(obj);
1269 /* like cxname, but ignores quantity */
1270 char *
1271 cxname_singular(obj)
1272 struct obj *obj;
1274 if (obj->otyp == CORPSE)
1275 return corpse_xname(obj, (const char *) 0, CXN_SINGULAR);
1276 return xname_flags(obj, CXN_SINGULAR);
1279 /* treat an object as fully ID'd when it might be used as reason for death */
1280 char *
1281 killer_xname(obj)
1282 struct obj *obj;
1284 struct obj save_obj;
1285 unsigned save_ocknown;
1286 char *buf, *save_ocuname, *save_oname = (char *) 0;
1288 /* bypass object twiddling for artifacts */
1289 if (obj->oartifact)
1290 return bare_artifactname(obj);
1292 /* remember original settings for core of the object;
1293 oextra structs other than oname don't matter here--since they
1294 aren't modified they don't need to be saved and restored */
1295 save_obj = *obj;
1296 if (has_oname(obj))
1297 save_oname = ONAME(obj);
1299 /* killer name should be more specific than general xname; however, exact
1300 info like blessed/cursed and rustproof makes things be too verbose */
1301 obj->known = obj->dknown = 1;
1302 obj->bknown = obj->rknown = obj->greased = 0;
1303 /* if character is a priest[ess], bknown will get toggled back on */
1304 if (obj->otyp != POT_WATER)
1305 obj->blessed = obj->cursed = 0;
1306 else
1307 obj->bknown = 1; /* describe holy/unholy water as such */
1308 /* "killed by poisoned <obj>" would be misleading when poison is
1309 not the cause of death and "poisoned by poisoned <obj>" would
1310 be redundant when it is, so suppress "poisoned" prefix */
1311 obj->opoisoned = 0;
1312 /* strip user-supplied name; artifacts keep theirs */
1313 if (!obj->oartifact && save_oname)
1314 ONAME(obj) = (char *) 0;
1315 /* temporarily identify the type of object */
1316 save_ocknown = objects[obj->otyp].oc_name_known;
1317 objects[obj->otyp].oc_name_known = 1;
1318 save_ocuname = objects[obj->otyp].oc_uname;
1319 objects[obj->otyp].oc_uname = 0; /* avoid "foo called bar" */
1321 /* format the object */
1322 if (obj->otyp == CORPSE) {
1323 buf = nextobuf();
1324 Strcpy(buf, corpse_xname(obj, (const char *) 0, CXN_NORMAL));
1325 } else if (obj->otyp == SLIME_MOLD) {
1326 /* concession to "most unique deaths competition" in the annual
1327 devnull tournament, suppress player supplied fruit names because
1328 those can be used to fake other objects and dungeon features */
1329 buf = nextobuf();
1330 Sprintf(buf, "deadly slime mold%s", plur(obj->quan));
1331 } else {
1332 buf = xname(obj);
1334 /* apply an article if appropriate; caller should always use KILLED_BY */
1335 if (obj->quan == 1L && !strstri(buf, "'s ") && !strstri(buf, "s' "))
1336 buf = (obj_is_pname(obj) || the_unique_obj(obj)) ? the(buf) : an(buf);
1338 objects[obj->otyp].oc_name_known = save_ocknown;
1339 objects[obj->otyp].oc_uname = save_ocuname;
1340 *obj = save_obj; /* restore object's core settings */
1341 if (!obj->oartifact && save_oname)
1342 ONAME(obj) = save_oname;
1344 return buf;
1347 /* xname,doname,&c with long results reformatted to omit some stuff */
1348 char *
1349 short_oname(obj, func, altfunc, lenlimit)
1350 struct obj *obj;
1351 char *FDECL((*func), (OBJ_P)), /* main formatting routine */
1352 *FDECL((*altfunc), (OBJ_P)); /* alternate for shortest result */
1353 unsigned lenlimit;
1355 struct obj save_obj;
1356 char unamebuf[12], onamebuf[12], *save_oname, *save_uname, *outbuf;
1358 outbuf = (*func)(obj);
1359 if ((unsigned) strlen(outbuf) <= lenlimit)
1360 return outbuf;
1362 /* shorten called string to fairly small amount */
1363 save_uname = objects[obj->otyp].oc_uname;
1364 if (save_uname && strlen(save_uname) >= sizeof unamebuf) {
1365 (void) strncpy(unamebuf, save_uname, sizeof unamebuf - 4);
1366 Strcpy(unamebuf + sizeof unamebuf - 4, "...");
1367 objects[obj->otyp].oc_uname = unamebuf;
1368 releaseobuf(outbuf);
1369 outbuf = (*func)(obj);
1370 objects[obj->otyp].oc_uname = save_uname; /* restore called string */
1371 if ((unsigned) strlen(outbuf) <= lenlimit)
1372 return outbuf;
1375 /* shorten named string to fairly small amount */
1376 save_oname = has_oname(obj) ? ONAME(obj) : 0;
1377 if (save_oname && strlen(save_oname) >= sizeof onamebuf) {
1378 (void) strncpy(onamebuf, save_oname, sizeof onamebuf - 4);
1379 Strcpy(onamebuf + sizeof onamebuf - 4, "...");
1380 ONAME(obj) = onamebuf;
1381 releaseobuf(outbuf);
1382 outbuf = (*func)(obj);
1383 ONAME(obj) = save_oname; /* restore named string */
1384 if ((unsigned) strlen(outbuf) <= lenlimit)
1385 return outbuf;
1388 /* shorten both called and named strings;
1389 unamebuf and onamebuf have both already been populated */
1390 if (save_uname && strlen(save_uname) >= sizeof unamebuf && save_oname
1391 && strlen(save_oname) >= sizeof onamebuf) {
1392 objects[obj->otyp].oc_uname = unamebuf;
1393 ONAME(obj) = onamebuf;
1394 releaseobuf(outbuf);
1395 outbuf = (*func)(obj);
1396 if ((unsigned) strlen(outbuf) <= lenlimit) {
1397 objects[obj->otyp].oc_uname = save_uname;
1398 ONAME(obj) = save_oname;
1399 return outbuf;
1403 /* still long; strip several name-lengthening attributes;
1404 called and named strings are still in truncated form */
1405 save_obj = *obj;
1406 obj->bknown = obj->rknown = obj->greased = 0;
1407 obj->oeroded = obj->oeroded2 = 0;
1408 releaseobuf(outbuf);
1409 outbuf = (*func)(obj);
1410 if (altfunc && (unsigned) strlen(outbuf) > lenlimit) {
1411 /* still long; use the alternate function (usually one of
1412 the jackets around minimal_xname()) */
1413 releaseobuf(outbuf);
1414 outbuf = (*altfunc)(obj);
1416 /* restore the object */
1417 *obj = save_obj;
1418 if (save_oname)
1419 ONAME(obj) = save_oname;
1420 if (save_uname)
1421 objects[obj->otyp].oc_uname = save_uname;
1423 /* use whatever we've got, whether it's too long or not */
1424 return outbuf;
1428 * Used if only one of a collection of objects is named (e.g. in eat.c).
1430 const char *
1431 singular(otmp, func)
1432 register struct obj *otmp;
1433 char *FDECL((*func), (OBJ_P));
1435 long savequan;
1436 char *nam;
1438 /* using xname for corpses does not give the monster type */
1439 if (otmp->otyp == CORPSE && func == xname)
1440 func = cxname;
1442 savequan = otmp->quan;
1443 otmp->quan = 1L;
1444 nam = (*func)(otmp);
1445 otmp->quan = savequan;
1446 return nam;
1449 char *
1450 an(str)
1451 register const char *str;
1453 char *buf = nextobuf();
1455 buf[0] = '\0';
1457 if (strncmpi(str, "the ", 4) && strcmp(str, "molten lava")
1458 && strcmp(str, "iron bars") && strcmp(str, "ice")) {
1459 if (index(vowels, *str) && strncmp(str, "one-", 4)
1460 && strncmp(str, "useful", 6) && strncmp(str, "unicorn", 7)
1461 && strncmp(str, "uranium", 7) && strncmp(str, "eucalyptus", 10))
1462 Strcpy(buf, "an ");
1463 else
1464 Strcpy(buf, "a ");
1467 Strcat(buf, str);
1468 return buf;
1471 char *
1472 An(str)
1473 const char *str;
1475 char *tmp = an(str);
1477 *tmp = highc(*tmp);
1478 return tmp;
1482 * Prepend "the" if necessary; assumes str is a subject derived from xname.
1483 * Use type_is_pname() for monster names, not the(). the() is idempotent.
1485 char *
1486 the(str)
1487 const char *str;
1489 char *buf = nextobuf();
1490 boolean insert_the = FALSE;
1492 if (!strncmpi(str, "the ", 4)) {
1493 buf[0] = lowc(*str);
1494 Strcpy(&buf[1], str + 1);
1495 return buf;
1496 } else if (*str < 'A' || *str > 'Z') {
1497 /* not a proper name, needs an article */
1498 insert_the = TRUE;
1499 } else {
1500 /* Probably a proper name, might not need an article */
1501 register char *tmp, *named, *called;
1502 int l;
1504 /* some objects have capitalized adjectives in their names */
1505 if (((tmp = rindex(str, ' ')) != 0 || (tmp = rindex(str, '-')) != 0)
1506 && (tmp[1] < 'A' || tmp[1] > 'Z')) {
1507 insert_the = TRUE;
1508 } else if (tmp && index(str, ' ') < tmp) { /* has spaces */
1509 /* it needs an article if the name contains "of" */
1510 tmp = strstri(str, " of ");
1511 named = strstri(str, " named ");
1512 called = strstri(str, " called ");
1513 if (called && (!named || called < named))
1514 named = called;
1516 if (tmp && (!named || tmp < named)) /* found an "of" */
1517 insert_the = TRUE;
1518 /* stupid special case: lacks "of" but needs "the" */
1519 else if (!named && (l = strlen(str)) >= 31
1520 && !strcmp(&str[l - 31],
1521 "Platinum Yendorian Express Card"))
1522 insert_the = TRUE;
1525 if (insert_the)
1526 Strcpy(buf, "the ");
1527 else
1528 buf[0] = '\0';
1529 Strcat(buf, str);
1531 return buf;
1534 char *
1535 The(str)
1536 const char *str;
1538 char *tmp = the(str);
1540 *tmp = highc(*tmp);
1541 return tmp;
1544 /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
1545 char *
1546 aobjnam(otmp, verb)
1547 struct obj *otmp;
1548 const char *verb;
1550 char prefix[PREFIX];
1551 char *bp = cxname(otmp);
1553 if (otmp->quan != 1L) {
1554 Sprintf(prefix, "%ld ", otmp->quan);
1555 bp = strprepend(bp, prefix);
1557 if (verb) {
1558 Strcat(bp, " ");
1559 Strcat(bp, otense(otmp, verb));
1561 return bp;
1564 /* combine yname and aobjnam eg "your count cxname(otmp)" */
1565 char *
1566 yobjnam(obj, verb)
1567 struct obj *obj;
1568 const char *verb;
1570 char *s = aobjnam(obj, verb);
1572 /* leave off "your" for most of your artifacts, but prepend
1573 * "your" for unique objects and "foo of bar" quest artifacts */
1574 if (!carried(obj) || !obj_is_pname(obj)
1575 || obj->oartifact >= ART_ORB_OF_DETECTION) {
1576 char *outbuf = shk_your(nextobuf(), obj);
1577 int space_left = BUFSZ - 1 - strlen(outbuf);
1579 s = strncat(outbuf, s, space_left);
1581 return s;
1584 /* combine Yname2 and aobjnam eg "Your count cxname(otmp)" */
1585 char *
1586 Yobjnam2(obj, verb)
1587 struct obj *obj;
1588 const char *verb;
1590 register char *s = yobjnam(obj, verb);
1592 *s = highc(*s);
1593 return s;
1596 /* like aobjnam, but prepend "The", not count, and use xname */
1597 char *
1598 Tobjnam(otmp, verb)
1599 struct obj *otmp;
1600 const char *verb;
1602 char *bp = The(xname(otmp));
1604 if (verb) {
1605 Strcat(bp, " ");
1606 Strcat(bp, otense(otmp, verb));
1608 return bp;
1611 /* capitalized variant of doname() */
1612 char *
1613 Doname2(obj)
1614 struct obj *obj;
1616 char *s = doname(obj);
1618 *s = highc(*s);
1619 return s;
1622 /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
1623 char *
1624 yname(obj)
1625 struct obj *obj;
1627 char *s = cxname(obj);
1629 /* leave off "your" for most of your artifacts, but prepend
1630 * "your" for unique objects and "foo of bar" quest artifacts */
1631 if (!carried(obj) || !obj_is_pname(obj)
1632 || obj->oartifact >= ART_ORB_OF_DETECTION) {
1633 char *outbuf = shk_your(nextobuf(), obj);
1634 int space_left = BUFSZ - 1 - strlen(outbuf);
1636 s = strncat(outbuf, s, space_left);
1639 return s;
1642 /* capitalized variant of yname() */
1643 char *
1644 Yname2(obj)
1645 struct obj *obj;
1647 char *s = yname(obj);
1649 *s = highc(*s);
1650 return s;
1653 /* returns "your minimal_xname(obj)"
1654 * or "Foobar's minimal_xname(obj)"
1655 * or "the minimal_xname(obj)"
1657 char *
1658 ysimple_name(obj)
1659 struct obj *obj;
1661 char *outbuf = nextobuf();
1662 char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */
1663 int space_left = BUFSZ - 1 - strlen(s);
1665 return strncat(s, minimal_xname(obj), space_left);
1668 /* capitalized variant of ysimple_name() */
1669 char *
1670 Ysimple_name2(obj)
1671 struct obj *obj;
1673 char *s = ysimple_name(obj);
1675 *s = highc(*s);
1676 return s;
1679 /* "scroll" or "scrolls" */
1680 char *
1681 simpleonames(obj)
1682 struct obj *obj;
1684 char *simpleoname = minimal_xname(obj);
1686 if (obj->quan != 1L)
1687 simpleoname = makeplural(simpleoname);
1688 return simpleoname;
1691 /* "a scroll" or "scrolls"; "a silver bell" or "the Bell of Opening" */
1692 char *
1693 ansimpleoname(obj)
1694 struct obj *obj;
1696 char *simpleoname = simpleonames(obj);
1697 int otyp = obj->otyp;
1699 /* prefix with "the" if a unique item, or a fake one imitating same,
1700 has been formatted with its actual name (we let typename() handle
1701 any `known' and `dknown' checking necessary) */
1702 if (otyp == FAKE_AMULET_OF_YENDOR)
1703 otyp = AMULET_OF_YENDOR;
1704 if (objects[otyp].oc_unique
1705 && !strcmp(simpleoname, OBJ_NAME(objects[otyp])))
1706 return the(simpleoname);
1708 /* simpleoname is singular if quan==1, plural otherwise */
1709 if (obj->quan == 1L)
1710 simpleoname = an(simpleoname);
1711 return simpleoname;
1714 /* "the scroll" or "the scrolls" */
1715 char *
1716 thesimpleoname(obj)
1717 struct obj *obj;
1719 char *simpleoname = simpleonames(obj);
1721 return the(simpleoname);
1724 /* artifact's name without any object type or known/dknown/&c feedback */
1725 char *
1726 bare_artifactname(obj)
1727 struct obj *obj;
1729 char *outbuf;
1731 if (obj->oartifact) {
1732 outbuf = nextobuf();
1733 Strcpy(outbuf, artiname(obj->oartifact));
1734 if (!strncmp(outbuf, "The ", 4))
1735 outbuf[0] = lowc(outbuf[0]);
1736 } else {
1737 outbuf = xname(obj);
1739 return outbuf;
1742 static const char *wrp[] = {
1743 "wand", "ring", "potion", "scroll", "gem",
1744 "amulet", "spellbook", "spell book",
1745 /* for non-specific wishes */
1746 "weapon", "armor", "tool", "food", "comestible",
1748 static const char wrpsym[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
1749 SCROLL_CLASS, GEM_CLASS, AMULET_CLASS,
1750 SPBOOK_CLASS, SPBOOK_CLASS, WEAPON_CLASS,
1751 ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
1752 FOOD_CLASS };
1754 /* return form of the verb (input plural) if xname(otmp) were the subject */
1755 char *
1756 otense(otmp, verb)
1757 struct obj *otmp;
1758 const char *verb;
1760 char *buf;
1763 * verb is given in plural (without trailing s). Return as input
1764 * if the result of xname(otmp) would be plural. Don't bother
1765 * recomputing xname(otmp) at this time.
1767 if (!is_plural(otmp))
1768 return vtense((char *) 0, verb);
1770 buf = nextobuf();
1771 Strcpy(buf, verb);
1772 return buf;
1775 /* various singular words that vtense would otherwise categorize as plural;
1776 also used by makesingular() to catch some special cases */
1777 static const char *const special_subjs[] = {
1778 "erinys", "manes", /* this one is ambiguous */
1779 "Cyclops", "Hippocrates", "Pelias", "aklys",
1780 "amnesia", "detect monsters", "paralysis", "shape changers",
1781 "nemesis", 0
1782 /* note: "detect monsters" and "shape changers" are normally
1783 caught via "<something>(s) of <whatever>", but they can be
1784 wished for using the shorter form, so we include them here
1785 to accommodate usage by makesingular during wishing */
1788 /* return form of the verb (input plural) for present tense 3rd person subj */
1789 char *
1790 vtense(subj, verb)
1791 register const char *subj;
1792 register const char *verb;
1794 char *buf = nextobuf(), *bspot;
1795 int len, ltmp;
1796 const char *sp, *spot;
1797 const char *const *spec;
1800 * verb is given in plural (without trailing s). Return as input
1801 * if subj appears to be plural. Add special cases as necessary.
1802 * Many hard cases can already be handled by using otense() instead.
1803 * If this gets much bigger, consider decomposing makeplural.
1804 * Note: monster names are not expected here (except before corpse).
1806 * Special case: allow null sobj to get the singular 3rd person
1807 * present tense form so we don't duplicate this code elsewhere.
1809 if (subj) {
1810 if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3))
1811 goto sing;
1812 spot = (const char *) 0;
1813 for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) {
1814 if (!strncmpi(sp, " of ", 4) || !strncmpi(sp, " from ", 6)
1815 || !strncmpi(sp, " called ", 8) || !strncmpi(sp, " named ", 7)
1816 || !strncmpi(sp, " labeled ", 9)) {
1817 if (sp != subj)
1818 spot = sp - 1;
1819 break;
1822 len = (int) strlen(subj);
1823 if (!spot)
1824 spot = subj + len - 1;
1827 * plural: anything that ends in 's', but not '*us' or '*ss'.
1828 * Guess at a few other special cases that makeplural creates.
1830 if ((lowc(*spot) == 's' && spot != subj
1831 && !index("us", lowc(*(spot - 1))))
1832 || !BSTRNCMPI(subj, spot - 3, "eeth", 4)
1833 || !BSTRNCMPI(subj, spot - 3, "feet", 4)
1834 || !BSTRNCMPI(subj, spot - 1, "ia", 2)
1835 || !BSTRNCMPI(subj, spot - 1, "ae", 2)) {
1836 /* check for special cases to avoid false matches */
1837 len = (int) (spot - subj) + 1;
1838 for (spec = special_subjs; *spec; spec++) {
1839 ltmp = strlen(*spec);
1840 if (len == ltmp && !strncmpi(*spec, subj, len))
1841 goto sing;
1842 /* also check for <prefix><space><special_subj>
1843 to catch things like "the invisible erinys" */
1844 if (len > ltmp && *(spot - ltmp) == ' '
1845 && !strncmpi(*spec, spot - ltmp + 1, ltmp))
1846 goto sing;
1849 return strcpy(buf, verb);
1852 * 3rd person plural doesn't end in telltale 's';
1853 * 2nd person singular behaves as if plural.
1855 if (!strcmpi(subj, "they") || !strcmpi(subj, "you"))
1856 return strcpy(buf, verb);
1859 sing:
1860 Strcpy(buf, verb);
1861 len = (int) strlen(buf);
1862 bspot = buf + len - 1;
1864 if (!strcmpi(buf, "are")) {
1865 Strcasecpy(buf, "is");
1866 } else if (!strcmpi(buf, "have")) {
1867 Strcasecpy(bspot - 1, "s");
1868 } else if (index("zxs", lowc(*bspot))
1869 || (len >= 2 && lowc(*bspot) == 'h'
1870 && index("cs", lowc(*(bspot - 1))))
1871 || (len == 2 && lowc(*bspot) == 'o')) {
1872 /* Ends in z, x, s, ch, sh; add an "es" */
1873 Strcasecpy(bspot + 1, "es");
1874 } else if (lowc(*bspot) == 'y' && !index(vowels, lowc(*(bspot - 1)))) {
1875 /* like "y" case in makeplural */
1876 Strcasecpy(bspot, "ies");
1877 } else {
1878 Strcasecpy(bspot + 1, "s");
1881 return buf;
1884 struct sing_plur {
1885 const char *sing, *plur;
1888 /* word pairs that don't fit into formula-based transformations;
1889 also some suffices which have very few--often one--matches or
1890 which aren't systematically reversible (knives, staves) */
1891 static struct sing_plur one_off[] = {
1892 { "child",
1893 "children" }, /* (for wise guys who give their food funny names) */
1894 { "cubus", "cubi" }, /* in-/suc-cubus */
1895 { "culus", "culi" }, /* homunculus */
1896 { "djinni", "djinn" },
1897 { "erinys", "erinyes" },
1898 { "foot", "feet" },
1899 { "fungus", "fungi" },
1900 { "knife", "knives" },
1901 { "labrum", "labra" }, /* candelabrum */
1902 { "louse", "lice" },
1903 { "mouse", "mice" },
1904 { "mumak", "mumakil" },
1905 { "nemesis", "nemeses" },
1906 { "rtex", "rtices" }, /* vortex */
1907 { "tooth", "teeth" },
1908 { "staff", "staves" },
1909 { 0, 0 }
1912 static const char *const as_is[] = {
1913 /* makesingular() leaves these plural due to how they're used */
1914 "boots", "shoes", "gloves", "lenses", "scales",
1915 "eyes", "gauntlets", "iron bars",
1916 /* both singular and plural are spelled the same */
1917 "deer", "fish", "tuna", "yaki", "-hai",
1918 "krill", "manes", "ninja", "sheep", "ronin",
1919 "roshi", "shito", "tengu", "ki-rin", "Nazgul",
1920 "gunyoki", "piranha", "samurai", "shuriken", 0,
1921 /* Note: "fish" and "piranha" are collective plurals, suitable
1922 for "wiped out all <foo>". For "3 <foo>", they should be
1923 "fishes" and "piranhas" instead. We settle for collective
1924 variant instead of attempting to support both. */
1927 /* singularize/pluralize decisions common to both makesingular & makeplural
1929 STATIC_OVL boolean
1930 singplur_lookup(basestr, endstring, to_plural, alt_as_is)
1931 char *basestr, *endstring; /* base string, pointer to eos(string) */
1932 boolean to_plural; /* true => makeplural, false => makesingular */
1933 const char *const *alt_as_is; /* another set like as_is[] */
1935 const struct sing_plur *sp;
1936 const char *same, *other, *const *as;
1937 int al;
1939 for (as = as_is; *as; ++as) {
1940 al = (int) strlen(*as);
1941 if (!BSTRCMPI(basestr, endstring - al, *as))
1942 return TRUE;
1944 if (alt_as_is) {
1945 for (as = alt_as_is; *as; ++as) {
1946 al = (int) strlen(*as);
1947 if (!BSTRCMPI(basestr, endstring - al, *as))
1948 return TRUE;
1952 /* avoid false hit on one_off[].plur == "lice";
1953 if more of these turn up, one_off[] entries will need to flagged
1954 as to which are whole words and which are matchable as suffices
1955 then matching in the loop below will end up becoming more complex */
1956 if (!strcmpi(basestr, "slice")) {
1957 if (to_plural)
1958 (void) strkitten(basestr, 's');
1959 return TRUE;
1961 for (sp = one_off; sp->sing; sp++) {
1962 /* check whether endstring already matches */
1963 same = to_plural ? sp->plur : sp->sing;
1964 al = (int) strlen(same);
1965 if (!BSTRCMPI(basestr, endstring - al, same))
1966 return TRUE; /* use as-is */
1967 /* check whether it matches the inverse; if so, transform it */
1968 other = to_plural ? sp->sing : sp->plur;
1969 al = (int) strlen(other);
1970 if (!BSTRCMPI(basestr, endstring - al, other)) {
1971 Strcasecpy(endstring - al, same);
1972 return TRUE; /* one_off[] transformation */
1975 return FALSE;
1978 /* searches for common compounds, ex. lump of royal jelly */
1979 STATIC_OVL char *
1980 singplur_compound(str)
1981 char *str;
1983 /* if new entries are added, be sure to keep compound_start[] in sync */
1984 static const char *const compounds[] =
1986 " of ", " labeled ", " called ",
1987 " named ", " above", /* lurkers above */
1988 " versus ", " from ", " in ",
1989 " on ", " a la ", " with", /* " with "? */
1990 " de ", " d'", " du ",
1991 "-in-", "-at-", 0
1992 }, /* list of first characters for all compounds[] entries */
1993 compound_start[] = " -";
1995 const char *const *cmpd;
1996 char *p;
1998 for (p = str; *p; ++p) {
1999 /* substring starting at p can only match if *p is found
2000 within compound_start[] */
2001 if (!index(compound_start, *p))
2002 continue;
2004 /* check current substring against all words in the compound[] list */
2005 for (cmpd = compounds; *cmpd; ++cmpd)
2006 if (!strncmpi(p, *cmpd, (int) strlen(*cmpd)))
2007 return p;
2009 /* wasn't recognized as a compound phrase */
2010 return 0;
2013 /* Plural routine; chiefly used for user-defined fruits. We have to try to
2014 * account for everything reasonable the player has; something unreasonable
2015 * can still break the code. However, it's still a lot more accurate than
2016 * "just add an s at the end", which Rogue uses...
2018 * Also used for plural monster names ("Wiped out all homunculi." or the
2019 * vanquished monsters list) and body parts. A lot of unique monsters have
2020 * names which get mangled by makeplural and/or makesingular. They're not
2021 * genocidable, and vanquished-mon handling does its own special casing
2022 * (for uniques who've been revived and re-killed), so we don't bother
2023 * trying to get those right here.
2025 * Also misused by muse.c to convert 1st person present verbs to 2nd person.
2026 * 3.6.0: made case-insensitive.
2028 char *
2029 makeplural(oldstr)
2030 const char *oldstr;
2032 register char *spot;
2033 char lo_c, *str = nextobuf();
2034 const char *excess = (char *) 0;
2035 int len;
2037 if (oldstr)
2038 while (*oldstr == ' ')
2039 oldstr++;
2040 if (!oldstr || !*oldstr) {
2041 impossible("plural of null?");
2042 Strcpy(str, "s");
2043 return str;
2045 Strcpy(str, oldstr);
2048 * Skip changing "pair of" to "pairs of". According to Webster, usual
2049 * English usage is use pairs for humans, e.g. 3 pairs of dancers,
2050 * and pair for objects and non-humans, e.g. 3 pair of boots. We don't
2051 * refer to pairs of humans in this game so just skip to the bottom.
2053 if (!strncmpi(str, "pair of ", 8))
2054 goto bottom;
2056 /* look for "foo of bar" so that we can focus on "foo" */
2057 if ((spot = singplur_compound(str)) != 0) {
2058 excess = oldstr + (int) (spot - str);
2059 *spot = '\0';
2060 } else
2061 spot = eos(str);
2063 spot--;
2064 while (spot > str && *spot == ' ')
2065 spot--; /* Strip blanks from end */
2066 *(spot + 1) = 0;
2067 /* Now spot is the last character of the string */
2069 len = strlen(str);
2071 /* Single letters */
2072 if (len == 1 || !letter(*spot)) {
2073 Strcpy(spot + 1, "'s");
2074 goto bottom;
2077 /* dispense with some words which don't need pluralization */
2079 static const char *const already_plural[] = {
2080 "ae", /* algae, larvae, &c */
2081 "men", /* also catches women, watchmen */
2082 "matzot", 0,
2085 /* spot+1: synch up with makesingular's usage */
2086 if (singplur_lookup(str, spot + 1, TRUE, already_plural))
2087 goto bottom;
2089 /* more of same, but not suitable for blanket loop checking */
2090 if ((len == 2 && !strcmpi(str, "ya"))
2091 || (len >= 3 && !strcmpi(spot - 2, " ya")))
2092 goto bottom;
2095 /* man/men ("Wiped out all cavemen.") */
2096 if (len >= 3 && !strcmpi(spot - 2, "man")
2097 /* exclude shamans and humans */
2098 && (len < 6 || strcmpi(spot - 5, "shaman"))
2099 && (len < 5 || strcmpi(spot - 4, "human"))) {
2100 Strcasecpy(spot - 1, "en");
2101 goto bottom;
2103 if (lowc(*spot) == 'f') { /* (staff handled via one_off[]) */
2104 lo_c = lowc(*(spot - 1));
2105 if (len >= 3 && !strcmpi(spot - 2, "erf")) {
2106 /* avoid "nerf" -> "nerves", "serf" -> "serves" */
2107 ; /* fall through to default (append 's') */
2108 } else if (index("lr", lo_c) || index(vowels, lo_c)) {
2109 /* [aeioulr]f to [aeioulr]ves */
2110 Strcasecpy(spot, "ves");
2111 goto bottom;
2114 /* ium/ia (mycelia, baluchitheria) */
2115 if (len >= 3 && !strcmpi(spot - 2, "ium")) {
2116 Strcasecpy(spot - 2, "ia");
2117 goto bottom;
2119 /* algae, larvae, hyphae (another fungus part) */
2120 if ((len >= 4 && !strcmpi(spot - 3, "alga"))
2121 || (len >= 5
2122 && (!strcmpi(spot - 4, "hypha") || !strcmpi(spot - 4, "larva")))
2123 || (len >= 6 && !strcmpi(spot - 5, "amoeba"))
2124 || (len >= 8 && (!strcmpi(spot - 7, "vertebra")))) {
2125 /* a to ae */
2126 Strcasecpy(spot + 1, "e");
2127 goto bottom;
2129 /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */
2130 if (len > 3 && !strcmpi(spot - 1, "us")
2131 && !((len >= 5 && !strcmpi(spot - 4, "lotus"))
2132 || (len >= 6 && !strcmpi(spot - 5, "wumpus")))) {
2133 Strcasecpy(spot - 1, "i");
2134 goto bottom;
2136 /* sis/ses (nemesis) */
2137 if (len >= 3 && !strcmpi(spot - 2, "sis")) {
2138 Strcasecpy(spot - 1, "es");
2139 goto bottom;
2141 /* matzoh/matzot, possible food name */
2142 if (len >= 6
2143 && (!strcmpi(spot - 5, "matzoh") || !strcmpi(spot - 5, "matzah"))) {
2144 Strcasecpy(spot - 1, "ot"); /* oh/ah -> ot */
2145 goto bottom;
2147 if (len >= 5
2148 && (!strcmpi(spot - 4, "matzo") || !strcmpi(spot - 4, "matza"))) {
2149 Strcasecpy(spot, "ot"); /* o/a -> ot */
2150 goto bottom;
2153 /* note: -eau/-eaux (gateau, bordeau...) */
2154 /* note: ox/oxen, VAX/VAXen, goose/geese */
2156 lo_c = lowc(*spot);
2158 /* Ends in z, x, s, ch, sh; add an "es" */
2159 if (index("zxs", lo_c)
2160 || (len >= 2 && lo_c == 'h' && index("cs", lowc(*(spot - 1))))
2161 /* Kludge to get "tomatoes" and "potatoes" right */
2162 || (len >= 4 && !strcmpi(spot - 2, "ato"))
2163 || (len >= 5 && !strcmpi(spot - 4, "dingo"))) {
2164 Strcasecpy(spot + 1, "es"); /* append es */
2165 goto bottom;
2167 /* Ends in y preceded by consonant (note: also "qu") change to "ies" */
2168 if (lo_c == 'y' && !index(vowels, lowc(*(spot - 1)))) {
2169 Strcasecpy(spot, "ies"); /* y -> ies */
2170 goto bottom;
2172 /* Default: append an 's' */
2173 Strcasecpy(spot + 1, "s");
2175 bottom:
2176 if (excess)
2177 Strcat(str, excess);
2178 return str;
2182 * Singularize a string the user typed in; this helps reduce the complexity
2183 * of readobjnam, and is also used in pager.c to singularize the string
2184 * for which help is sought.
2186 * "Manes" is ambiguous: monster type (keep s), or horse body part (drop s)?
2187 * Its inclusion in as_is[]/special_subj[] makes it get treated as the former.
2189 * A lot of unique monsters have names ending in s; plural, or singular
2190 * from plural, doesn't make much sense for them so we don't bother trying.
2191 * 3.6.0: made case-insensitive.
2193 char *
2194 makesingular(oldstr)
2195 const char *oldstr;
2197 register char *p, *bp;
2198 const char *excess = 0;
2199 char *str = nextobuf();
2201 if (oldstr)
2202 while (*oldstr == ' ')
2203 oldstr++;
2204 if (!oldstr || !*oldstr) {
2205 impossible("singular of null?");
2206 str[0] = '\0';
2207 return str;
2210 bp = strcpy(str, oldstr);
2212 /* check for "foo of bar" so that we can focus on "foo" */
2213 if ((p = singplur_compound(bp)) != 0) {
2214 excess = oldstr + (int) (p - bp);
2215 *p = '\0';
2216 } else
2217 p = eos(bp);
2219 /* dispense with some words which don't need singularization */
2220 if (singplur_lookup(bp, p, FALSE, special_subjs))
2221 goto bottom;
2223 /* remove -s or -es (boxes) or -ies (rubies) */
2224 if (p >= bp + 1 && lowc(p[-1]) == 's') {
2225 if (p >= bp + 2 && lowc(p[-2]) == 'e') {
2226 if (p >= bp + 3 && lowc(p[-3]) == 'i') { /* "ies" */
2227 if (!BSTRCMPI(bp, p - 7, "cookies")
2228 || !BSTRCMPI(bp, p - 4, "pies")
2229 || !BSTRCMPI(bp, p - 5, "mbies") /* zombie */
2230 || !BSTRCMPI(bp, p - 5, "yries")) /* valkyrie */
2231 goto mins;
2232 Strcasecpy(p - 3, "y"); /* ies -> y */
2233 goto bottom;
2235 /* wolves, but f to ves isn't fully reversible */
2236 if (p - 4 >= bp && (index("lr", lowc(*(p - 4)))
2237 || index(vowels, lowc(*(p - 4))))
2238 && !BSTRCMPI(bp, p - 3, "ves")) {
2239 if (!BSTRCMPI(bp, p - 6, "cloves")
2240 || !BSTRCMPI(bp, p - 6, "nerves"))
2241 goto mins;
2242 Strcasecpy(p - 3, "f"); /* ves -> f */
2243 goto bottom;
2245 /* note: nurses, axes but boxes, wumpuses */
2246 if (!BSTRCMPI(bp, p - 4, "eses")
2247 || !BSTRCMPI(bp, p - 4, "oxes") /* boxes, foxes */
2248 || !BSTRCMPI(bp, p - 4, "nxes") /* lynxes */
2249 || !BSTRCMPI(bp, p - 4, "ches")
2250 || !BSTRCMPI(bp, p - 4, "uses") /* lotuses */
2251 || !BSTRCMPI(bp, p - 4, "sses") /* priestesses */
2252 || !BSTRCMPI(bp, p - 5, "atoes") /* tomatoes */
2253 || !BSTRCMPI(bp, p - 7, "dingoes")
2254 || !BSTRCMPI(bp, p - 7, "Aleaxes")) {
2255 *(p - 2) = '\0'; /* drop es */
2256 goto bottom;
2257 } /* else fall through to mins */
2259 /* ends in 's' but not 'es' */
2260 } else if (!BSTRCMPI(bp, p - 2, "us")) { /* lotus, fungus... */
2261 if (BSTRCMPI(bp, p - 6, "tengus") /* but not these... */
2262 && BSTRCMPI(bp, p - 7, "hezrous"))
2263 goto bottom;
2264 } else if (!BSTRCMPI(bp, p - 2, "ss")
2265 || !BSTRCMPI(bp, p - 5, " lens")
2266 || (p - 4 == bp && !strcmpi(p - 4, "lens"))) {
2267 goto bottom;
2269 mins:
2270 *(p - 1) = '\0'; /* drop s */
2272 } else { /* input doesn't end in 's' */
2274 if (!BSTRCMPI(bp, p - 3, "men")) {
2275 Strcasecpy(p - 2, "an");
2276 goto bottom;
2278 /* matzot -> matzo, algae -> alga */
2279 if (!BSTRCMPI(bp, p - 6, "matzot") || !BSTRCMPI(bp, p - 2, "ae")) {
2280 *(p - 1) = '\0'; /* drop t/e */
2281 goto bottom;
2283 /* balactheria -> balactherium */
2284 if (p - 4 >= bp && !strcmpi(p - 2, "ia")
2285 && index("lr", lowc(*(p - 3))) && lowc(*(p - 4)) == 'e') {
2286 Strcasecpy(p - 1, "um"); /* a -> um */
2289 /* here we cannot find the plural suffix */
2292 bottom:
2293 /* if we stripped off a suffix (" of bar" from "foo of bar"),
2294 put it back now [strcat() isn't actually 100% safe here...] */
2295 if (excess)
2296 Strcat(bp, excess);
2298 return bp;
2301 /* compare user string against object name string using fuzzy matching */
2302 STATIC_OVL boolean
2303 wishymatch(u_str, o_str, retry_inverted)
2304 const char *u_str; /* from user, so might be variant spelling */
2305 const char *o_str; /* from objects[], so is in canonical form */
2306 boolean retry_inverted; /* optional extra "of" handling */
2308 static NEARDATA const char detect_SP[] = "detect ",
2309 SP_detection[] = " detection";
2310 char *p, buf[BUFSZ];
2312 /* ignore spaces & hyphens and upper/lower case when comparing */
2313 if (fuzzymatch(u_str, o_str, " -", TRUE))
2314 return TRUE;
2316 if (retry_inverted) {
2317 const char *u_of, *o_of;
2319 /* when just one of the strings is in the form "foo of bar",
2320 convert it into "bar foo" and perform another comparison */
2321 u_of = strstri(u_str, " of ");
2322 o_of = strstri(o_str, " of ");
2323 if (u_of && !o_of) {
2324 Strcpy(buf, u_of + 4);
2325 p = eos(strcat(buf, " "));
2326 while (u_str < u_of)
2327 *p++ = *u_str++;
2328 *p = '\0';
2329 return fuzzymatch(buf, o_str, " -", TRUE);
2330 } else if (o_of && !u_of) {
2331 Strcpy(buf, o_of + 4);
2332 p = eos(strcat(buf, " "));
2333 while (o_str < o_of)
2334 *p++ = *o_str++;
2335 *p = '\0';
2336 return fuzzymatch(u_str, buf, " -", TRUE);
2340 /* [note: if something like "elven speed boots" ever gets added, these
2341 special cases should be changed to call wishymatch() recursively in
2342 order to get the "of" inversion handling] */
2343 if (!strncmp(o_str, "dwarvish ", 9)) {
2344 if (!strncmpi(u_str, "dwarven ", 8))
2345 return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE);
2346 } else if (!strncmp(o_str, "elven ", 6)) {
2347 if (!strncmpi(u_str, "elvish ", 7))
2348 return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE);
2349 else if (!strncmpi(u_str, "elfin ", 6))
2350 return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE);
2351 } else if (!strncmp(o_str, detect_SP, sizeof detect_SP - 1)) {
2352 /* check for "detect <foo>" vs "<foo> detection" */
2353 if ((p = strstri(u_str, SP_detection)) != 0
2354 && !*(p + sizeof SP_detection - 1)) {
2355 /* convert "<foo> detection" into "detect <foo>" */
2356 *p = '\0';
2357 Strcat(strcpy(buf, detect_SP), u_str);
2358 /* "detect monster" -> "detect monsters" */
2359 if (!strcmpi(u_str, "monster"))
2360 Strcat(buf, "s");
2361 *p = ' ';
2362 return fuzzymatch(buf, o_str, " -", TRUE);
2364 } else if (strstri(o_str, SP_detection)) {
2365 /* and the inverse, "<foo> detection" vs "detect <foo>" */
2366 if (!strncmpi(u_str, detect_SP, sizeof detect_SP - 1)) {
2367 /* convert "detect <foo>s" into "<foo> detection" */
2368 p = makesingular(u_str + sizeof detect_SP - 1);
2369 Strcat(strcpy(buf, p), SP_detection);
2370 /* caller may be looping through objects[], so avoid
2371 churning through all the obufs */
2372 releaseobuf(p);
2373 return fuzzymatch(buf, o_str, " -", TRUE);
2375 } else if (strstri(o_str, "ability")) {
2376 /* when presented with "foo of bar", makesingular() used to
2377 singularize both foo & bar, but now only does so for foo */
2378 /* catch "{potion(s),ring} of {gain,restore,sustain} abilities" */
2379 if ((p = strstri(u_str, "abilities")) != 0
2380 && !*(p + sizeof "abilities" - 1)) {
2381 (void) strncpy(buf, u_str, (unsigned) (p - u_str));
2382 Strcpy(buf + (p - u_str), "ability");
2383 return fuzzymatch(buf, o_str, " -", TRUE);
2385 } else if (!strcmp(o_str, "aluminum")) {
2386 /* this special case doesn't really fit anywhere else... */
2387 /* (note that " wand" will have been stripped off by now) */
2388 if (!strcmpi(u_str, "aluminium"))
2389 return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE);
2392 return FALSE;
2395 struct o_range {
2396 const char *name, oclass;
2397 int f_o_range, l_o_range;
2400 /* wishable subranges of objects */
2401 STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
2402 { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS },
2403 { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP },
2404 { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE },
2405 { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY },
2406 { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION },
2407 { "hat", ARMOR_CLASS, FEDORA, DUNCE_CAP },
2408 { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
2409 { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
2410 { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
2411 { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS },
2412 { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES },
2413 { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
2414 { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT },
2415 { "dragon scales", ARMOR_CLASS, GRAY_DRAGON_SCALES,
2416 YELLOW_DRAGON_SCALES },
2417 { "dragon scale mail", ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL,
2418 YELLOW_DRAGON_SCALE_MAIL },
2419 { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA },
2420 { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM },
2421 { "gray stone", GEM_CLASS, LUCKSTONE, FLINT },
2422 { "grey stone", GEM_CLASS, LUCKSTONE, FLINT },
2425 /* alternate spellings; if the difference is only the presence or
2426 absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
2427 vs "pick-axe") then there is no need for inclusion in this list;
2428 likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */
2429 struct alt_spellings {
2430 const char *sp;
2431 int ob;
2432 } spellings[] = {
2433 { "pickax", PICK_AXE },
2434 { "whip", BULLWHIP },
2435 { "saber", SILVER_SABER },
2436 { "silver sabre", SILVER_SABER },
2437 { "smooth shield", SHIELD_OF_REFLECTION },
2438 { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
2439 { "grey dragon scales", GRAY_DRAGON_SCALES },
2440 { "iron ball", HEAVY_IRON_BALL },
2441 { "lantern", BRASS_LANTERN },
2442 { "mattock", DWARVISH_MATTOCK },
2443 { "amulet of poison resistance", AMULET_VERSUS_POISON },
2444 { "potion of sleep", POT_SLEEPING },
2445 { "stone", ROCK },
2446 { "camera", EXPENSIVE_CAMERA },
2447 { "tee shirt", T_SHIRT },
2448 { "can", TIN },
2449 { "can opener", TIN_OPENER },
2450 { "kelp", KELP_FROND },
2451 { "eucalyptus", EUCALYPTUS_LEAF },
2452 { "royal jelly", LUMP_OF_ROYAL_JELLY },
2453 { "lembas", LEMBAS_WAFER },
2454 { "marker", MAGIC_MARKER },
2455 { "hook", GRAPPLING_HOOK },
2456 { "grappling iron", GRAPPLING_HOOK },
2457 { "grapnel", GRAPPLING_HOOK },
2458 { "grapple", GRAPPLING_HOOK },
2459 { "protection from shape shifters", RIN_PROTECTION_FROM_SHAPE_CHAN },
2460 /* normally we wouldn't have to worry about unnecessary <space>, but
2461 " stone" will get stripped off, preventing a wishymatch; that actually
2462 lets "flint stone" be a match, so we also accept bogus "flintstone" */
2463 { "luck stone", LUCKSTONE },
2464 { "load stone", LOADSTONE },
2465 { "touch stone", TOUCHSTONE },
2466 { "flintstone", FLINT },
2467 { (const char *) 0, 0 },
2470 STATIC_OVL short
2471 rnd_otyp_by_wpnskill(skill)
2472 schar skill;
2474 int i, n = 0;
2475 short otyp = STRANGE_OBJECT;
2476 for (i = bases[WEAPON_CLASS];
2477 i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++)
2478 if (objects[i].oc_skill == skill) {
2479 n++;
2480 otyp = i;
2482 if (n > 0) {
2483 n = rn2(n);
2484 for (i = bases[WEAPON_CLASS];
2485 i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++)
2486 if (objects[i].oc_skill == skill)
2487 if (--n < 0)
2488 return i;
2490 return otyp;
2493 STATIC_OVL short
2494 rnd_otyp_by_namedesc(name, oclass)
2495 char *name;
2496 char oclass;
2498 int i, n = 0;
2499 short validobjs[NUM_OBJECTS];
2500 register const char *zn;
2501 long maxprob = 0;
2503 if (!name)
2504 return STRANGE_OBJECT;
2506 memset((genericptr_t) validobjs, 0, sizeof(validobjs));
2508 for (i = oclass ? bases[(int)oclass] : STRANGE_OBJECT + 1;
2509 i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass);
2510 ++i) {
2511 /* don't match extra descriptions (w/o real name) */
2512 if ((zn = OBJ_NAME(objects[i])) == 0)
2513 continue;
2514 if (wishymatch(name, zn, TRUE)
2515 || ((zn = OBJ_DESCR(objects[i])) != 0
2516 && wishymatch(name, zn, FALSE))
2517 || ((zn = objects[i].oc_uname) != 0
2518 && wishymatch(name, zn, FALSE))) {
2519 validobjs[n++] = (short) i;
2520 maxprob += (objects[i].oc_prob + 1);
2524 if (n > 0 && maxprob) {
2525 long prob = rn2(maxprob);
2527 i = 0;
2528 while (i < n - 1
2529 && (prob -= (objects[validobjs[i]].oc_prob + 1)) >= 0)
2530 i++;
2531 return validobjs[i];
2533 return STRANGE_OBJECT;
2537 * Return something wished for. Specifying a null pointer for
2538 * the user request string results in a random object. Otherwise,
2539 * if asking explicitly for "nothing" (or "nil") return no_wish;
2540 * if not an object return &zeroobj; if an error (no matching object),
2541 * return null.
2543 struct obj *
2544 readobjnam(bp, no_wish)
2545 register char *bp;
2546 struct obj *no_wish;
2548 register char *p;
2549 register int i;
2550 register struct obj *otmp;
2551 int cnt, spe, spesgn, typ, very, rechrg;
2552 int blessed, uncursed, iscursed, ispoisoned, isgreased;
2553 int eroded, eroded2, erodeproof;
2554 int halfeaten, mntmp, contents;
2555 int islit, unlabeled, ishistoric, isdiluted, trapped;
2556 int tmp, tinv, tvariety;
2557 int wetness, gsize = 0;
2558 struct fruit *f;
2559 int ftype = context.current_fruit;
2560 char fruitbuf[BUFSZ];
2561 /* Fruits may not mess up the ability to wish for real objects (since
2562 * you can leave a fruit in a bones file and it will be added to
2563 * another person's game), so they must be checked for last, after
2564 * stripping all the possible prefixes and seeing if there's a real
2565 * name in there. So we have to save the full original name. However,
2566 * it's still possible to do things like "uncursed burnt Alaska",
2567 * or worse yet, "2 burned 5 course meals", so we need to loop to
2568 * strip off the prefixes again, this time stripping only the ones
2569 * possible on food.
2570 * We could get even more detailed so as to allow food names with
2571 * prefixes that _are_ possible on food, so you could wish for
2572 * "2 3 alarm chilis". Currently this isn't allowed; options.c
2573 * automatically sticks 'candied' in front of such names.
2575 char oclass;
2576 char *un, *dn, *actualn, *origbp = bp;
2577 const char *name = 0;
2579 cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed =
2580 ispoisoned = isgreased = eroded = eroded2 = erodeproof = halfeaten =
2581 islit = unlabeled = ishistoric = isdiluted = trapped = 0;
2582 tvariety = RANDOM_TIN;
2583 mntmp = NON_PM;
2584 #define UNDEFINED 0
2585 #define EMPTY 1
2586 #define SPINACH 2
2587 contents = UNDEFINED;
2588 oclass = 0;
2589 actualn = dn = un = 0;
2590 wetness = 0;
2592 if (!bp)
2593 goto any;
2594 /* first, remove extra whitespace they may have typed */
2595 (void) mungspaces(bp);
2596 /* allow wishing for "nothing" to preserve wishless conduct...
2597 [now requires "wand of nothing" if that's what was really wanted] */
2598 if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil")
2599 || !strcmpi(bp, "none"))
2600 return no_wish;
2601 /* save the [nearly] unmodified choice string */
2602 Strcpy(fruitbuf, bp);
2604 for (;;) {
2605 register int l;
2607 if (!bp || !*bp)
2608 goto any;
2609 if (!strncmpi(bp, "an ", l = 3) || !strncmpi(bp, "a ", l = 2)) {
2610 cnt = 1;
2611 } else if (!strncmpi(bp, "the ", l = 4)) {
2612 ; /* just increment `bp' by `l' below */
2613 } else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
2614 cnt = atoi(bp);
2615 while (digit(*bp))
2616 bp++;
2617 while (*bp == ' ')
2618 bp++;
2619 l = 0;
2620 } else if (*bp == '+' || *bp == '-') {
2621 spesgn = (*bp++ == '+') ? 1 : -1;
2622 spe = atoi(bp);
2623 while (digit(*bp))
2624 bp++;
2625 while (*bp == ' ')
2626 bp++;
2627 l = 0;
2628 } else if (!strncmpi(bp, "blessed ", l = 8)
2629 || !strncmpi(bp, "holy ", l = 5)) {
2630 blessed = 1;
2631 } else if (!strncmpi(bp, "moist ", l = 6)
2632 || !strncmpi(bp, "wet ", l = 4)) {
2633 if (!strncmpi(bp, "wet ", 4))
2634 wetness = rn2(3) + 3;
2635 else
2636 wetness = rnd(2);
2637 } else if (!strncmpi(bp, "cursed ", l = 7)
2638 || !strncmpi(bp, "unholy ", l = 7)) {
2639 iscursed = 1;
2640 } else if (!strncmpi(bp, "uncursed ", l = 9)) {
2641 uncursed = 1;
2642 } else if (!strncmpi(bp, "rustproof ", l = 10)
2643 || !strncmpi(bp, "erodeproof ", l = 11)
2644 || !strncmpi(bp, "corrodeproof ", l = 13)
2645 || !strncmpi(bp, "fixed ", l = 6)
2646 || !strncmpi(bp, "fireproof ", l = 10)
2647 || !strncmpi(bp, "rotproof ", l = 9)) {
2648 erodeproof = 1;
2649 } else if (!strncmpi(bp, "lit ", l = 4)
2650 || !strncmpi(bp, "burning ", l = 8)) {
2651 islit = 1;
2652 } else if (!strncmpi(bp, "unlit ", l = 6)
2653 || !strncmpi(bp, "extinguished ", l = 13)) {
2654 islit = 0;
2655 /* "unlabeled" and "blank" are synonymous */
2656 } else if (!strncmpi(bp, "unlabeled ", l = 10)
2657 || !strncmpi(bp, "unlabelled ", l = 11)
2658 || !strncmpi(bp, "blank ", l = 6)) {
2659 unlabeled = 1;
2660 } else if (!strncmpi(bp, "poisoned ", l = 9)) {
2661 ispoisoned = 1;
2662 /* "trapped" recognized but not honored outside wizard mode */
2663 } else if (!strncmpi(bp, "trapped ", l = 8)) {
2664 trapped = 0; /* undo any previous "untrapped" */
2665 if (wizard)
2666 trapped = 1;
2667 } else if (!strncmpi(bp, "untrapped ", l = 10)) {
2668 trapped = 2; /* not trapped */
2669 } else if (!strncmpi(bp, "greased ", l = 8)) {
2670 isgreased = 1;
2671 } else if (!strncmpi(bp, "very ", l = 5)) {
2672 /* very rusted very heavy iron ball */
2673 very = 1;
2674 } else if (!strncmpi(bp, "thoroughly ", l = 11)) {
2675 very = 2;
2676 } else if (!strncmpi(bp, "rusty ", l = 6)
2677 || !strncmpi(bp, "rusted ", l = 7)
2678 || !strncmpi(bp, "burnt ", l = 6)
2679 || !strncmpi(bp, "burned ", l = 7)) {
2680 eroded = 1 + very;
2681 very = 0;
2682 } else if (!strncmpi(bp, "corroded ", l = 9)
2683 || !strncmpi(bp, "rotted ", l = 7)) {
2684 eroded2 = 1 + very;
2685 very = 0;
2686 } else if (!strncmpi(bp, "partly eaten ", l = 13)
2687 || !strncmpi(bp, "partially eaten ", l = 16)) {
2688 halfeaten = 1;
2689 } else if (!strncmpi(bp, "historic ", l = 9)) {
2690 ishistoric = 1;
2691 } else if (!strncmpi(bp, "diluted ", l = 8)) {
2692 isdiluted = 1;
2693 } else if (!strncmpi(bp, "empty ", l = 6)) {
2694 contents = EMPTY;
2695 } else if (!strncmpi(bp, "small ", l = 6)) { /* glob sizes */
2696 gsize = 1;
2697 } else if (!strncmpi(bp, "medium ", l = 7)) {
2698 /* xname() doesn't display "medium" but without this
2699 there'd be no way to ask for the intermediate size */
2700 gsize = 2;
2701 } else if (!strncmpi(bp, "large ", l = 6)) {
2702 /* "very large " had "very " peeled off on previous iteration */
2703 gsize = (very != 1) ? 3 : 4;
2704 } else
2705 break;
2706 bp += l;
2708 if (!cnt)
2709 cnt = 1; /* %% what with "gems" etc. ? */
2710 if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) {
2711 boolean keeptrailingchars = TRUE;
2713 p[(p > bp && p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */
2714 ++p; /* advance past '(' */
2715 if (!strncmpi(p, "lit)", 4)) {
2716 islit = 1;
2717 p += 4 - 1; /* point at ')' */
2718 } else {
2719 spe = atoi(p);
2720 while (digit(*p))
2721 p++;
2722 if (*p == ':') {
2723 p++;
2724 rechrg = spe;
2725 spe = atoi(p);
2726 while (digit(*p))
2727 p++;
2729 if (*p != ')') {
2730 spe = rechrg = 0;
2731 /* mis-matched parentheses; rest of string will be ignored
2732 * [probably we should restore everything back to '('
2733 * instead since it might be part of "named ..."]
2735 keeptrailingchars = FALSE;
2736 } else {
2737 spesgn = 1;
2740 if (keeptrailingchars) {
2741 char *pp = eos(bp);
2743 /* 'pp' points at 'pb's terminating '\0',
2744 'p' points at ')' and will be incremented past it */
2745 do {
2746 *pp++ = *++p;
2747 } while (*p);
2751 * otmp->spe is type schar, so we don't want spe to be any bigger or
2752 * smaller. Also, spe should always be positive --some cheaters may
2753 * try to confuse atoi().
2755 if (spe < 0) {
2756 spesgn = -1; /* cheaters get what they deserve */
2757 spe = abs(spe);
2759 if (spe > SCHAR_LIM)
2760 spe = SCHAR_LIM;
2761 if (rechrg < 0 || rechrg > 7)
2762 rechrg = 7; /* recharge_limit */
2764 /* now we have the actual name, as delivered by xname, say
2765 * green potions called whisky
2766 * scrolls labeled "QWERTY"
2767 * egg
2768 * fortune cookies
2769 * very heavy iron ball named hoei
2770 * wand of wishing
2771 * elven cloak
2773 if ((p = strstri(bp, " named ")) != 0) {
2774 *p = 0;
2775 name = p + 7;
2777 if ((p = strstri(bp, " called ")) != 0) {
2778 *p = 0;
2779 un = p + 8;
2780 /* "helmet called telepathy" is not "helmet" (a specific type)
2781 * "shield called reflection" is not "shield" (a general type)
2783 for (i = 0; i < SIZE(o_ranges); i++)
2784 if (!strcmpi(bp, o_ranges[i].name)) {
2785 oclass = o_ranges[i].oclass;
2786 goto srch;
2789 if ((p = strstri(bp, " labeled ")) != 0) {
2790 *p = 0;
2791 dn = p + 9;
2792 } else if ((p = strstri(bp, " labelled ")) != 0) {
2793 *p = 0;
2794 dn = p + 10;
2796 if ((p = strstri(bp, " of spinach")) != 0) {
2797 *p = 0;
2798 contents = SPINACH;
2802 * Skip over "pair of ", "pairs of", "set of" and "sets of".
2804 * Accept "3 pair of boots" as well as "3 pairs of boots". It is
2805 * valid English either way. See makeplural() for more on pair/pairs.
2807 * We should only double count if the object in question is not
2808 * referred to as a "pair of". E.g. We should double if the player
2809 * types "pair of spears", but not if the player types "pair of
2810 * lenses". Luckily (?) all objects that are referred to as pairs
2811 * -- boots, gloves, and lenses -- are also not mergable, so cnt is
2812 * ignored anyway.
2814 if (!strncmpi(bp, "pair of ", 8)) {
2815 bp += 8;
2816 cnt *= 2;
2817 } else if (!strncmpi(bp, "pairs of ", 9)) {
2818 bp += 9;
2819 if (cnt > 1)
2820 cnt *= 2;
2821 } else if (!strncmpi(bp, "set of ", 7)) {
2822 bp += 7;
2823 } else if (!strncmpi(bp, "sets of ", 8)) {
2824 bp += 8;
2827 /* intercept pudding globs here; they're a valid wish target,
2828 * but we need them to not get treated like a corpse.
2830 * also don't let player wish for multiple globs.
2832 if ((p = strstri(bp, "glob of ")) != 0
2833 || (p = strstri(bp, "globs of ")) != 0) {
2834 int globoffset = (*(p + 4) == 's') ? 9 : 8;
2836 if ((mntmp = name_to_mon(p + globoffset)) >= PM_GRAY_OOZE
2837 && mntmp <= PM_BLACK_PUDDING) {
2838 mntmp = NON_PM; /* lie to ourselves */
2839 cnt = 0; /* force only one */
2841 } else {
2843 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
2844 * Don't check if it's a wand or spellbook.
2845 * (avoid "wand/finger of death" confusion).
2847 if (!strstri(bp, "wand ") && !strstri(bp, "spellbook ")
2848 && !strstri(bp, "finger ")) {
2849 if ((p = strstri(bp, "tin of ")) != 0) {
2850 tmp = tin_variety_txt(p + 7, &tinv);
2851 tvariety = tinv;
2852 mntmp = name_to_mon(p + 7 + tmp);
2853 typ = TIN;
2854 goto typfnd;
2855 } else if ((p = strstri(bp, " of ")) != 0
2856 && (mntmp = name_to_mon(p + 4)) >= LOW_PM)
2857 *p = 0;
2860 /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
2861 if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
2862 if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
2863 if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
2864 if (strncmpi(bp, "master key",
2865 10)) /* not the "master" rank */
2866 if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */
2867 if (mntmp < LOW_PM && strlen(bp) > 2
2868 && (mntmp = name_to_mon(bp)) >= LOW_PM) {
2869 int mntmptoo,
2870 mntmplen; /* double check for rank title */
2871 char *obp = bp;
2872 mntmptoo = title_to_mon(bp, (int *) 0, &mntmplen);
2873 bp += mntmp != mntmptoo
2874 ? (int) strlen(mons[mntmp].mname)
2875 : mntmplen;
2876 if (*bp == ' ')
2877 bp++;
2878 else if (!strncmpi(bp, "s ", 2))
2879 bp += 2;
2880 else if (!strncmpi(bp, "es ", 3))
2881 bp += 3;
2882 else if (!*bp && !actualn && !dn && !un
2883 && !oclass) {
2884 /* no referent; they don't really mean a
2885 * monster type */
2886 bp = obp;
2887 mntmp = NON_PM;
2891 /* first change to singular if necessary */
2892 if (*bp) {
2893 char *sng = makesingular(bp);
2894 if (strcmp(bp, sng)) {
2895 if (cnt == 1)
2896 cnt = 2;
2897 Strcpy(bp, sng);
2901 /* Alternate spellings (pick-ax, silver sabre, &c) */
2903 struct alt_spellings *as = spellings;
2905 while (as->sp) {
2906 if (fuzzymatch(bp, as->sp, " -", TRUE)) {
2907 typ = as->ob;
2908 goto typfnd;
2910 as++;
2912 /* can't use spellings list for this one due to shuffling */
2913 if (!strncmpi(bp, "grey spell", 10))
2914 *(bp + 2) = 'a';
2916 if ((p = strstri(bp, "armour")) != 0) {
2917 /* skip past "armo", then copy remainder beyond "u" */
2918 p += 4;
2919 while ((*p = *(p + 1)) != '\0')
2920 ++p; /* self terminating */
2924 /* dragon scales - assumes order of dragons */
2925 if (!strcmpi(bp, "scales") && mntmp >= PM_GRAY_DRAGON
2926 && mntmp <= PM_YELLOW_DRAGON) {
2927 typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
2928 mntmp = NON_PM; /* no monster */
2929 goto typfnd;
2932 p = eos(bp);
2933 if (!BSTRCMPI(bp, p - 10, "holy water")) {
2934 typ = POT_WATER;
2935 if ((p - bp) >= 12 && *(p - 12) == 'u')
2936 iscursed = 1; /* unholy water */
2937 else
2938 blessed = 1;
2939 goto typfnd;
2941 if (unlabeled && !BSTRCMPI(bp, p - 6, "scroll")) {
2942 typ = SCR_BLANK_PAPER;
2943 goto typfnd;
2945 if (unlabeled && !BSTRCMPI(bp, p - 9, "spellbook")) {
2946 typ = SPE_BLANK_PAPER;
2947 goto typfnd;
2950 * NOTE: Gold pieces are handled as objects nowadays, and therefore
2951 * this section should probably be reconsidered as well as the entire
2952 * gold/money concept. Maybe we want to add other monetary units as
2953 * well in the future. (TH)
2955 if (!BSTRCMPI(bp, p - 10, "gold piece") || !BSTRCMPI(bp, p - 7, "zorkmid")
2956 || !strcmpi(bp, "gold") || !strcmpi(bp, "money")
2957 || !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
2958 if (cnt > 5000 && !wizard)
2959 cnt = 5000;
2960 else if (cnt < 1)
2961 cnt = 1;
2962 otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
2963 otmp->quan = (long) cnt;
2964 otmp->owt = weight(otmp);
2965 context.botl = 1;
2966 return otmp;
2969 /* check for single character object class code ("/" for wand, &c) */
2970 if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES
2971 && i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) {
2972 oclass = i;
2973 goto any;
2976 /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */
2977 /* false hits on, e.g., rings for "ring mail". */
2978 if (strncmpi(bp, "enchant ", 8) && strncmpi(bp, "destroy ", 8)
2979 && strncmpi(bp, "detect food", 11)
2980 && strncmpi(bp, "food detection", 14) && strncmpi(bp, "ring mail", 9)
2981 && strncmpi(bp, "studded leather armor", 21)
2982 && strncmpi(bp, "leather armor", 13)
2983 && strncmpi(bp, "tooled horn", 11) && strncmpi(bp, "food ration", 11)
2984 && strncmpi(bp, "meat ring", 9))
2985 for (i = 0; i < (int) (sizeof wrpsym); i++) {
2986 register int j = strlen(wrp[i]);
2987 if (!strncmpi(bp, wrp[i], j)) {
2988 oclass = wrpsym[i];
2989 if (oclass != AMULET_CLASS) {
2990 bp += j;
2991 if (!strncmpi(bp, " of ", 4))
2992 actualn = bp + 4;
2993 /* else if(*bp) ?? */
2994 } else
2995 actualn = bp;
2996 goto srch;
2998 if (!BSTRCMPI(bp, p - j, wrp[i])) {
2999 oclass = wrpsym[i];
3000 p -= j;
3001 *p = 0;
3002 if (p > bp && p[-1] == ' ')
3003 p[-1] = 0;
3004 actualn = dn = bp;
3005 goto srch;
3009 /* Wishing in wizard mode can create traps and furniture.
3010 * Part I: distinguish between trap and object for the two
3011 * types of traps which have corresponding objects: bear trap
3012 * and land mine. "beartrap" (object) and "bear trap" (trap)
3013 * have a difference in spelling which we used to exploit by
3014 * adding a special case in wishymatch(), but "land mine" is
3015 * spelled the same either way so needs different handing.
3016 * Since we need something else for land mine, we've dropped
3017 * the bear trap hack so that both are handled exactly the
3018 * same. To get an armed trap instead of a disarmed object,
3019 * the player can prefix either the object name or the trap
3020 * name with "trapped " (which ordinarily applies to chests
3021 * and tins), or append something--anything at all except for
3022 * " object", but " trap" is suggested--to either the trap
3023 * name or the object name.
3025 if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) {
3026 boolean beartrap = (lowc(*bp) == 'b');
3027 char *zp = bp + 4; /* skip "bear"/"land" */
3029 if (*zp == ' ')
3030 ++zp; /* embedded space is optional */
3031 if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) {
3032 zp += 4;
3033 if (trapped == 2 || !strcmpi(zp, " object")) {
3034 /* "untrapped <foo>" or "<foo> object" */
3035 typ = beartrap ? BEARTRAP : LAND_MINE;
3036 goto typfnd;
3037 } else if (trapped == 1 || *zp != '\0') {
3038 /* "trapped <foo>" or "<foo> trap" (actually "<foo>*") */
3039 int idx = trap_to_defsym(beartrap ? BEAR_TRAP : LANDMINE);
3041 /* use canonical trap spelling, skip object matching */
3042 Strcpy(bp, defsyms[idx].explanation);
3043 goto wiztrap;
3045 /* [no prefix or suffix; we're going to end up matching
3046 the object name and getting a disarmed trap object] */
3050 retry:
3051 /* "grey stone" check must be before general "stone" */
3052 for (i = 0; i < SIZE(o_ranges); i++)
3053 if (!strcmpi(bp, o_ranges[i].name)) {
3054 typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
3055 goto typfnd;
3058 if (!BSTRCMPI(bp, p - 6, " stone") || !BSTRCMPI(bp, p - 4, " gem")) {
3059 p[!strcmpi(p - 4, " gem") ? -4 : -6] = '\0';
3060 oclass = GEM_CLASS;
3061 dn = actualn = bp;
3062 goto srch;
3063 } else if (!strcmpi(bp, "looking glass")) {
3064 ; /* avoid false hit on "* glass" */
3065 } else if (!BSTRCMPI(bp, p - 6, " glass") || !strcmpi(bp, "glass")) {
3066 register char *g = bp;
3067 if (strstri(g, "broken"))
3068 return (struct obj *) 0;
3069 if (!strncmpi(g, "worthless ", 10))
3070 g += 10;
3071 if (!strncmpi(g, "piece of ", 9))
3072 g += 9;
3073 if (!strncmpi(g, "colored ", 8))
3074 g += 8;
3075 else if (!strncmpi(g, "coloured ", 9))
3076 g += 9;
3077 if (!strcmpi(g, "glass")) { /* choose random color */
3078 /* 9 different kinds */
3079 typ = LAST_GEM + rnd(9);
3080 if (objects[typ].oc_class == GEM_CLASS)
3081 goto typfnd;
3082 else
3083 typ = 0; /* somebody changed objects[]? punt */
3084 } else { /* try to construct canonical form */
3085 char tbuf[BUFSZ];
3087 Strcpy(tbuf, "worthless piece of ");
3088 Strcat(tbuf, g); /* assume it starts with the color */
3089 Strcpy(bp, tbuf);
3093 actualn = bp;
3094 if (!dn)
3095 dn = actualn; /* ex. "skull cap" */
3096 srch:
3097 /* check real names of gems first */
3098 if (!oclass && actualn) {
3099 for (i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
3100 register const char *zn;
3102 if ((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
3103 typ = i;
3104 goto typfnd;
3109 if (((typ = rnd_otyp_by_namedesc(actualn, oclass)) != STRANGE_OBJECT)
3110 || ((typ = rnd_otyp_by_namedesc(dn, oclass)) != STRANGE_OBJECT)
3111 || ((typ = rnd_otyp_by_namedesc(un, oclass)) != STRANGE_OBJECT)
3112 || ((typ = rnd_otyp_by_namedesc(origbp, oclass)) != STRANGE_OBJECT))
3113 goto typfnd;
3114 typ = 0;
3116 if (actualn) {
3117 struct Jitem *j = Japanese_items;
3119 while (j->item) {
3120 if (actualn && !strcmpi(actualn, j->name)) {
3121 typ = j->item;
3122 goto typfnd;
3124 j++;
3127 /* if we've stripped off "armor" and failed to match anything
3128 in objects[], append "mail" and try again to catch misnamed
3129 requests like "plate armor" and "yellow dragon scale armor" */
3130 if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) {
3131 /* modifying bp's string is ok; we're about to resort
3132 to random armor if this also fails to match anything */
3133 Strcat(bp, " mail");
3134 goto retry;
3136 if (!strcmpi(bp, "spinach")) {
3137 contents = SPINACH;
3138 typ = TIN;
3139 goto typfnd;
3141 /* Note: not strcmpi. 2 fruits, one capital, one not, are possible.
3142 Also not strncmp. We used to ignore trailing text with it, but
3143 that resulted in "grapefruit" matching "grape" if the latter came
3144 earlier than the former in the fruit list. */
3146 char *fp;
3147 int l, cntf;
3148 int blessedf, iscursedf, uncursedf, halfeatenf;
3150 blessedf = iscursedf = uncursedf = halfeatenf = 0;
3151 cntf = 0;
3153 fp = fruitbuf;
3154 for (;;) {
3155 if (!fp || !*fp)
3156 break;
3157 if (!strncmpi(fp, "an ", l = 3) || !strncmpi(fp, "a ", l = 2)) {
3158 cntf = 1;
3159 } else if (!cntf && digit(*fp)) {
3160 cntf = atoi(fp);
3161 while (digit(*fp))
3162 fp++;
3163 while (*fp == ' ')
3164 fp++;
3165 l = 0;
3166 } else if (!strncmpi(fp, "blessed ", l = 8)) {
3167 blessedf = 1;
3168 } else if (!strncmpi(fp, "cursed ", l = 7)) {
3169 iscursedf = 1;
3170 } else if (!strncmpi(fp, "uncursed ", l = 9)) {
3171 uncursedf = 1;
3172 } else if (!strncmpi(fp, "partly eaten ", l = 13)
3173 || !strncmpi(fp, "partially eaten ", l = 16)) {
3174 halfeatenf = 1;
3175 } else
3176 break;
3177 fp += l;
3180 for (f = ffruit; f; f = f->nextf) {
3181 /* match type: 0=none, 1=exact, 2=singular, 3=plural */
3182 int ftyp = 0;
3184 if (!strcmp(fp, f->fname))
3185 ftyp = 1;
3186 else if (!strcmp(fp, makesingular(f->fname)))
3187 ftyp = 2;
3188 else if (!strcmp(fp, makeplural(f->fname)))
3189 ftyp = 3;
3190 if (ftyp) {
3191 typ = SLIME_MOLD;
3192 blessed = blessedf;
3193 iscursed = iscursedf;
3194 uncursed = uncursedf;
3195 halfeaten = halfeatenf;
3196 /* adjust count if user explicitly asked for
3197 singular amount (can't happen unless fruit
3198 has been given an already pluralized name)
3199 or for plural amount */
3200 if (ftyp == 2 && !cntf)
3201 cntf = 1;
3202 else if (ftyp == 3 && !cntf)
3203 cntf = 2;
3204 cnt = cntf;
3205 ftype = f->fid;
3206 goto typfnd;
3211 if (!oclass && actualn) {
3212 short objtyp;
3214 /* Perhaps it's an artifact specified by name, not type */
3215 name = artifact_name(actualn, &objtyp);
3216 if (name) {
3217 typ = objtyp;
3218 goto typfnd;
3221 /* Let wizards wish for traps and furniture.
3222 * Must come after objects check so wizards can still wish for
3223 * trap objects like beartraps.
3224 * Disallow such topology tweaks for WIZKIT startup wishes.
3226 wiztrap:
3227 if (wizard && !program_state.wizkit_wishing) {
3228 struct rm *lev;
3229 int trap, x = u.ux, y = u.uy;
3231 for (trap = NO_TRAP + 1; trap < TRAPNUM; trap++) {
3232 struct trap *t;
3233 const char *tname;
3235 tname = defsyms[trap_to_defsym(trap)].explanation;
3236 if (strncmpi(tname, bp, strlen(tname)))
3237 continue;
3238 /* found it; avoid stupid mistakes */
3239 if ((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz))
3240 trap = ROCKTRAP;
3241 if ((t = maketrap(x, y, trap)) != 0) {
3242 trap = t->ttyp;
3243 tname = defsyms[trap_to_defsym(trap)].explanation;
3244 pline("%s%s.", An(tname),
3245 (trap != MAGIC_PORTAL) ? "" : " to nowhere");
3246 } else
3247 pline("Creation of %s failed.", an(tname));
3248 return &zeroobj;
3251 /* furniture and terrain */
3252 lev = &levl[x][y];
3253 p = eos(bp);
3254 if (!BSTRCMPI(bp, p - 8, "fountain")) {
3255 lev->typ = FOUNTAIN;
3256 level.flags.nfountains++;
3257 if (!strncmpi(bp, "magic ", 6))
3258 lev->blessedftn = 1;
3259 pline("A %sfountain.", lev->blessedftn ? "magic " : "");
3260 newsym(x, y);
3261 return &zeroobj;
3263 if (!BSTRCMPI(bp, p - 6, "throne")) {
3264 lev->typ = THRONE;
3265 pline("A throne.");
3266 newsym(x, y);
3267 return &zeroobj;
3269 if (!BSTRCMPI(bp, p - 4, "sink")) {
3270 lev->typ = SINK;
3271 level.flags.nsinks++;
3272 pline("A sink.");
3273 newsym(x, y);
3274 return &zeroobj;
3276 /* ("water" matches "potion of water" rather than terrain) */
3277 if (!BSTRCMPI(bp, p - 4, "pool") || !BSTRCMPI(bp, p - 4, "moat")) {
3278 lev->typ = !BSTRCMPI(bp, p - 4, "pool") ? POOL : MOAT;
3279 del_engr_at(x, y);
3280 pline("A %s.", (lev->typ == POOL) ? "pool" : "moat");
3281 /* Must manually make kelp! */
3282 water_damage_chain(level.objects[x][y], TRUE);
3283 newsym(x, y);
3284 return &zeroobj;
3286 if (!BSTRCMPI(bp, p - 4, "lava")) { /* also matches "molten lava" */
3287 lev->typ = LAVAPOOL;
3288 del_engr_at(x, y);
3289 pline("A pool of molten lava.");
3290 if (!(Levitation || Flying))
3291 (void) lava_effects();
3292 newsym(x, y);
3293 return &zeroobj;
3296 if (!BSTRCMPI(bp, p - 5, "altar")) {
3297 aligntyp al;
3299 lev->typ = ALTAR;
3300 if (!strncmpi(bp, "chaotic ", 8))
3301 al = A_CHAOTIC;
3302 else if (!strncmpi(bp, "neutral ", 8))
3303 al = A_NEUTRAL;
3304 else if (!strncmpi(bp, "lawful ", 7))
3305 al = A_LAWFUL;
3306 else if (!strncmpi(bp, "unaligned ", 10))
3307 al = A_NONE;
3308 else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
3309 al = (!rn2(6)) ? A_NONE : rn2((int) A_LAWFUL + 2) - 1;
3310 lev->altarmask = Align2amask(al);
3311 pline("%s altar.", An(align_str(al)));
3312 newsym(x, y);
3313 return &zeroobj;
3316 if (!BSTRCMPI(bp, p - 5, "grave")
3317 || !BSTRCMPI(bp, p - 9, "headstone")) {
3318 make_grave(x, y, (char *) 0);
3319 pline("%s.", IS_GRAVE(lev->typ) ? "A grave"
3320 : "Can't place a grave here");
3321 newsym(x, y);
3322 return &zeroobj;
3325 if (!BSTRCMPI(bp, p - 4, "tree")) {
3326 lev->typ = TREE;
3327 pline("A tree.");
3328 newsym(x, y);
3329 block_point(x, y);
3330 return &zeroobj;
3333 if (!BSTRCMPI(bp, p - 4, "bars")) {
3334 lev->typ = IRONBARS;
3335 pline("Iron bars.");
3336 newsym(x, y);
3337 return &zeroobj;
3341 if (!oclass && !typ) {
3342 if (!strncmpi(bp, "polearm", 7)) {
3343 typ = rnd_otyp_by_wpnskill(P_POLEARMS);
3344 goto typfnd;
3345 } else if (!strncmpi(bp, "hammer", 6)) {
3346 typ = rnd_otyp_by_wpnskill(P_HAMMER);
3347 goto typfnd;
3351 if (!oclass)
3352 return ((struct obj *) 0);
3353 any:
3354 if (!oclass)
3355 oclass = wrpsym[rn2((int) sizeof(wrpsym))];
3356 typfnd:
3357 if (typ)
3358 oclass = objects[typ].oc_class;
3360 /* handle some objects that are only allowed in wizard mode */
3361 if (typ && !wizard) {
3362 switch (typ) {
3363 case AMULET_OF_YENDOR:
3364 typ = FAKE_AMULET_OF_YENDOR;
3365 break;
3366 case CANDELABRUM_OF_INVOCATION:
3367 typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
3368 break;
3369 case BELL_OF_OPENING:
3370 typ = BELL;
3371 break;
3372 case SPE_BOOK_OF_THE_DEAD:
3373 typ = SPE_BLANK_PAPER;
3374 break;
3375 case MAGIC_LAMP:
3376 typ = OIL_LAMP;
3377 break;
3378 default:
3379 /* catch any other non-wishable objects (venom) */
3380 if (objects[typ].oc_nowish)
3381 return (struct obj *) 0;
3382 break;
3387 * Create the object, then fine-tune it.
3389 otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE);
3390 typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */
3392 if (islit && (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN
3393 || Is_candle(otmp) || typ == POT_OIL)) {
3394 place_object(otmp, u.ux, u.uy); /* make it viable light source */
3395 begin_burn(otmp, FALSE);
3396 obj_extract_self(otmp); /* now release it for caller's use */
3399 /* if player specified a reasonable count, maybe honor it */
3400 if (cnt > 0 && objects[typ].oc_merge
3401 && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp))
3402 || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp))
3403 || typ == ROCK || is_missile(otmp)))))
3404 otmp->quan = (long) cnt;
3406 if (oclass == VENOM_CLASS)
3407 otmp->spe = 1;
3409 if (spesgn == 0) {
3410 spe = otmp->spe;
3411 } else if (wizard) {
3412 ; /* no alteration to spe */
3413 } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS
3414 || is_weptool(otmp)
3415 || (oclass == RING_CLASS && objects[typ].oc_charged)) {
3416 if (spe > rnd(5) && spe > otmp->spe)
3417 spe = 0;
3418 if (spe > 2 && Luck < 0)
3419 spesgn = -1;
3420 } else {
3421 if (oclass == WAND_CLASS) {
3422 if (spe > 1 && spesgn == -1)
3423 spe = 1;
3424 } else {
3425 if (spe > 0 && spesgn == -1)
3426 spe = 0;
3428 if (spe > otmp->spe)
3429 spe = otmp->spe;
3432 if (spesgn == -1)
3433 spe = -spe;
3435 /* set otmp->spe. This may, or may not, use spe... */
3436 switch (typ) {
3437 case TIN:
3438 if (contents == EMPTY) {
3439 otmp->corpsenm = NON_PM;
3440 otmp->spe = 0;
3441 } else if (contents == SPINACH) {
3442 otmp->corpsenm = NON_PM;
3443 otmp->spe = 1;
3445 break;
3446 case TOWEL:
3447 if (wetness)
3448 otmp->spe = wetness;
3449 break;
3450 case SLIME_MOLD:
3451 otmp->spe = ftype;
3452 /* Fall through */
3453 case SKELETON_KEY:
3454 case CHEST:
3455 case LARGE_BOX:
3456 case HEAVY_IRON_BALL:
3457 case IRON_CHAIN:
3458 case STATUE:
3459 /* otmp->cobj already done in mksobj() */
3460 break;
3461 #ifdef MAIL
3462 case SCR_MAIL:
3463 /* 0: delivered in-game via external event (or randomly for fake mail);
3464 1: from bones or wishing; 2: written with marker */
3465 otmp->spe = 1;
3466 break;
3467 #endif
3468 case WAN_WISHING:
3469 if (!wizard) {
3470 otmp->spe = (rn2(10) ? -1 : 0);
3471 break;
3473 /* fall through, if wizard */
3474 default:
3475 otmp->spe = spe;
3478 /* set otmp->corpsenm or dragon scale [mail] */
3479 if (mntmp >= LOW_PM) {
3480 if (mntmp == PM_LONG_WORM_TAIL)
3481 mntmp = PM_LONG_WORM;
3483 switch (typ) {
3484 case TIN:
3485 otmp->spe = 0; /* No spinach */
3486 if (dead_species(mntmp, FALSE)) {
3487 otmp->corpsenm = NON_PM; /* it's empty */
3488 } else if ((!(mons[mntmp].geno & G_UNIQ) || wizard)
3489 && !(mvitals[mntmp].mvflags & G_NOCORPSE)
3490 && mons[mntmp].cnutrit != 0) {
3491 otmp->corpsenm = mntmp;
3493 break;
3494 case CORPSE:
3495 if ((!(mons[mntmp].geno & G_UNIQ) || wizard)
3496 && !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
3497 if (mons[mntmp].msound == MS_GUARDIAN)
3498 mntmp = genus(mntmp, 1);
3499 set_corpsenm(otmp, mntmp);
3501 break;
3502 case EGG:
3503 mntmp = can_be_hatched(mntmp);
3504 /* this also sets hatch timer if appropriate */
3505 set_corpsenm(otmp, mntmp);
3506 break;
3507 case FIGURINE:
3508 if (!(mons[mntmp].geno & G_UNIQ) && !is_human(&mons[mntmp])
3509 #ifdef MAIL
3510 && mntmp != PM_MAIL_DAEMON
3511 #endif
3513 otmp->corpsenm = mntmp;
3514 break;
3515 case STATUE:
3516 otmp->corpsenm = mntmp;
3517 if (Has_contents(otmp) && verysmall(&mons[mntmp]))
3518 delete_contents(otmp); /* no spellbook */
3519 otmp->spe = ishistoric ? STATUE_HISTORIC : 0;
3520 break;
3521 case SCALE_MAIL:
3522 /* Dragon mail - depends on the order of objects & dragons. */
3523 if (mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON)
3524 otmp->otyp = GRAY_DRAGON_SCALE_MAIL + mntmp - PM_GRAY_DRAGON;
3525 break;
3529 /* set blessed/cursed -- setting the fields directly is safe
3530 * since weight() is called below and addinv() will take care
3531 * of luck */
3532 if (iscursed) {
3533 curse(otmp);
3534 } else if (uncursed) {
3535 otmp->blessed = 0;
3536 otmp->cursed = (Luck < 0 && !wizard);
3537 } else if (blessed) {
3538 otmp->blessed = (Luck >= 0 || wizard);
3539 otmp->cursed = (Luck < 0 && !wizard);
3540 } else if (spesgn < 0) {
3541 curse(otmp);
3544 /* set eroded and erodeproof */
3545 if (erosion_matters(otmp)) {
3546 if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
3547 otmp->oeroded = eroded;
3548 if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
3549 otmp->oeroded2 = eroded2;
3551 * 3.6.1: earlier versions included `&& !eroded && !eroded2' here,
3552 * but damageproof combined with damaged is feasible (eroded
3553 * armor modified by confused reading of cursed destroy armor)
3554 * so don't prevent player from wishing for such a combination.
3556 if (erodeproof && (is_damageable(otmp) || otmp->otyp == CRYSKNIFE))
3557 otmp->oerodeproof = (Luck >= 0 || wizard);
3560 /* set otmp->recharged */
3561 if (oclass == WAND_CLASS) {
3562 /* prevent wishing abuse */
3563 if (otmp->otyp == WAN_WISHING && !wizard)
3564 rechrg = 1;
3565 otmp->recharged = (unsigned) rechrg;
3568 /* set poisoned */
3569 if (ispoisoned) {
3570 if (is_poisonable(otmp))
3571 otmp->opoisoned = (Luck >= 0);
3572 else if (oclass == FOOD_CLASS)
3573 /* try to taint by making it as old as possible */
3574 otmp->age = 1L;
3576 /* and [un]trapped */
3577 if (trapped) {
3578 if (Is_box(otmp) || typ == TIN)
3579 otmp->otrapped = (trapped == 1);
3582 if (isgreased)
3583 otmp->greased = 1;
3585 if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER)
3586 otmp->odiluted = 1;
3588 /* set tin variety */
3589 if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard))
3590 set_tin_variety(otmp, tvariety);
3592 if (name) {
3593 const char *aname;
3594 short objtyp;
3596 /* an artifact name might need capitalization fixing */
3597 aname = artifact_name(name, &objtyp);
3598 if (aname && objtyp == otmp->otyp)
3599 name = aname;
3601 /* 3.6 tribute - fix up novel */
3602 if (otmp->otyp == SPE_NOVEL) {
3603 const char *novelname;
3605 novelname = lookup_novel(name, &otmp->novelidx);
3606 if (novelname)
3607 name = novelname;
3610 otmp = oname(otmp, name);
3611 /* name==aname => wished for artifact (otmp->oartifact => got it) */
3612 if (otmp->oartifact || name == aname) {
3613 otmp->quan = 1L;
3614 u.uconduct.wisharti++; /* KMH, conduct */
3618 /* more wishing abuse: don't allow wishing for certain artifacts */
3619 /* and make them pay; charge them for the wish anyway! */
3620 if ((is_quest_artifact(otmp)
3621 || (otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) {
3622 artifact_exists(otmp, safe_oname(otmp), FALSE);
3623 obfree(otmp, (struct obj *) 0);
3624 otmp = &zeroobj;
3625 pline("For a moment, you feel %s in your %s, but it disappears!",
3626 something, makeplural(body_part(HAND)));
3629 if (halfeaten && otmp->oclass == FOOD_CLASS) {
3630 if (otmp->otyp == CORPSE)
3631 otmp->oeaten = mons[otmp->corpsenm].cnutrit;
3632 else
3633 otmp->oeaten = objects[otmp->otyp].oc_nutrition;
3634 /* (do this adjustment before setting up object's weight) */
3635 consume_oeaten(otmp, 1);
3637 otmp->owt = weight(otmp);
3638 if (very && otmp->otyp == HEAVY_IRON_BALL)
3639 otmp->owt += IRON_BALL_W_INCR;
3640 else if (gsize > 1 && otmp->globby)
3641 /* 0: unspecified => small; 1: small => keep default owt of 20;
3642 2: medium => 120; 3: large => 320; 4: very large => 520 */
3643 otmp->owt += 100 + (gsize - 2) * 200;
3645 return otmp;
3649 rnd_class(first, last)
3650 int first, last;
3652 int i, x, sum = 0;
3654 if (first == last)
3655 return first;
3656 for (i = first; i <= last; i++)
3657 sum += objects[i].oc_prob;
3658 if (!sum) /* all zero */
3659 return first + rn2(last - first + 1);
3660 x = rnd(sum);
3661 for (i = first; i <= last; i++)
3662 if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
3663 return i;
3664 return 0;
3667 STATIC_OVL const char *
3668 Japanese_item_name(i)
3669 int i;
3671 struct Jitem *j = Japanese_items;
3673 while (j->item) {
3674 if (i == j->item)
3675 return j->name;
3676 j++;
3678 return (const char *) 0;
3681 const char *
3682 suit_simple_name(suit)
3683 struct obj *suit;
3685 const char *suitnm, *esuitp;
3687 if (Is_dragon_mail(suit))
3688 return "dragon mail"; /* <color> dragon scale mail */
3689 else if (Is_dragon_scales(suit))
3690 return "dragon scales";
3691 suitnm = OBJ_NAME(objects[suit->otyp]);
3692 esuitp = eos((char *) suitnm);
3693 if (strlen(suitnm) > 5 && !strcmp(esuitp - 5, " mail"))
3694 return "mail"; /* most suits fall into this category */
3695 else if (strlen(suitnm) > 7 && !strcmp(esuitp - 7, " jacket"))
3696 return "jacket"; /* leather jacket */
3697 /* suit is lame but armor is ambiguous and body armor is absurd */
3698 return "suit";
3701 const char *
3702 cloak_simple_name(cloak)
3703 struct obj *cloak;
3705 if (cloak) {
3706 switch (cloak->otyp) {
3707 case ROBE:
3708 return "robe";
3709 case MUMMY_WRAPPING:
3710 return "wrapping";
3711 case ALCHEMY_SMOCK:
3712 return (objects[cloak->otyp].oc_name_known && cloak->dknown)
3713 ? "smock"
3714 : "apron";
3715 default:
3716 break;
3719 return "cloak";
3722 /* helm vs hat for messages */
3723 const char *
3724 helm_simple_name(helmet)
3725 struct obj *helmet;
3728 * There is some wiggle room here; the result has been chosen
3729 * for consistency with the "protected by hard helmet" messages
3730 * given for various bonks on the head: headgear that provides
3731 * such protection is a "helm", that which doesn't is a "hat".
3733 * elven leather helm / leather hat -> hat
3734 * dwarvish iron helm / hard hat -> helm
3735 * The rest are completely straightforward:
3736 * fedora, cornuthaum, dunce cap -> hat
3737 * all other types of helmets -> helm
3739 return (helmet && !is_metallic(helmet)) ? "hat" : "helm";
3742 const char *
3743 mimic_obj_name(mtmp)
3744 struct monst *mtmp;
3746 if (mtmp->m_ap_type == M_AP_OBJECT) {
3747 if (mtmp->mappearance == GOLD_PIECE)
3748 return "gold";
3749 if (mtmp->mappearance != STRANGE_OBJECT)
3750 return simple_typename(mtmp->mappearance);
3752 return "whatcha-may-callit";
3756 * Construct a query prompt string, based around an object name, which is
3757 * guaranteed to fit within [QBUFSZ]. Takes an optional prefix, three
3758 * choices for filling in the middle (two object formatting functions and a
3759 * last resort literal which should be very short), and an optional suffix.
3761 char *
3762 safe_qbuf(qbuf, qprefix, qsuffix, obj, func, altfunc, lastR)
3763 char *qbuf; /* output buffer */
3764 const char *qprefix, *qsuffix;
3765 struct obj *obj;
3766 char *FDECL((*func), (OBJ_P)), *FDECL((*altfunc), (OBJ_P));
3767 const char *lastR;
3769 char *bufp, *endp;
3770 /* convert size_t (or int for ancient systems) to ordinary unsigned */
3771 unsigned len, lenlimit,
3772 len_qpfx = (unsigned) (qprefix ? strlen(qprefix) : 0),
3773 len_qsfx = (unsigned) (qsuffix ? strlen(qsuffix) : 0),
3774 len_lastR = (unsigned) strlen(lastR);
3776 lenlimit = QBUFSZ - 1;
3777 endp = qbuf + lenlimit;
3778 /* sanity check, aimed mainly at paniclog (it's conceivable for
3779 the result of short_oname() to be shorter than the length of
3780 the last resort string, but we ignore that possibility here) */
3781 if (len_qpfx > lenlimit)
3782 impossible("safe_qbuf: prefix too long (%u characters).", len_qpfx);
3783 else if (len_qpfx + len_qsfx > lenlimit)
3784 impossible("safe_qbuf: suffix too long (%u + %u characters).",
3785 len_qpfx, len_qsfx);
3786 else if (len_qpfx + len_lastR + len_qsfx > lenlimit)
3787 impossible("safe_qbuf: filler too long (%u + %u + %u characters).",
3788 len_qpfx, len_lastR, len_qsfx);
3790 /* the output buffer might be the same as the prefix if caller
3791 has already partially filled it */
3792 if (qbuf == qprefix) {
3793 /* prefix is already in the buffer */
3794 *endp = '\0';
3795 } else if (qprefix) {
3796 /* put prefix into the buffer */
3797 (void) strncpy(qbuf, qprefix, lenlimit);
3798 *endp = '\0';
3799 } else {
3800 /* no prefix; output buffer starts out empty */
3801 qbuf[0] = '\0';
3803 len = (unsigned) strlen(qbuf);
3805 if (len + len_lastR + len_qsfx > lenlimit) {
3806 /* too long; skip formatting, last resort output is truncated */
3807 if (len < lenlimit) {
3808 (void) strncpy(&qbuf[len], lastR, lenlimit - len);
3809 *endp = '\0';
3810 len = (unsigned) strlen(qbuf);
3811 if (qsuffix && len < lenlimit) {
3812 (void) strncpy(&qbuf[len], qsuffix, lenlimit - len);
3813 *endp = '\0';
3814 /* len = (unsigned) strlen(qbuf); */
3817 } else {
3818 /* suffix and last resort are guaranteed to fit */
3819 len += len_qsfx; /* include the pending suffix */
3820 /* format the object */
3821 bufp = short_oname(obj, func, altfunc, lenlimit - len);
3822 if (len + strlen(bufp) <= lenlimit)
3823 Strcat(qbuf, bufp); /* formatted name fits */
3824 else
3825 Strcat(qbuf, lastR); /* use last resort */
3826 releaseobuf(bufp);
3828 if (qsuffix)
3829 Strcat(qbuf, qsuffix);
3831 /* assert( strlen(qbuf) < QBUFSZ ); */
3832 return qbuf;
3835 /*objnam.c*/