option parsing buffer overflow vulnerability
[aNetHack.git] / src / objnam.c
blob59982a4ae6720d2377c3138f9047f567bb56e576
1 /* NetHack 3.6 objnam.c $NHDT-Date: 1462067746 2016/05/01 01:55:46 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.169 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack 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));
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 boolean
21 FDECL(singplur_lookup, (char *, char *, BOOLEAN_P, const char *const *));
22 STATIC_DCL char *FDECL(singplur_compound, (char *));
23 STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
25 struct Jitem {
26 int item;
27 const char *name;
30 #define BSTRCMPI(base, ptr, str) ((ptr) < base || strcmpi((ptr), str))
31 #define BSTRNCMPI(base, ptr, str, num) \
32 ((ptr) < base || strncmpi((ptr), str, num))
33 #define Strcasecpy(dst, src) (void) strcasecpy(dst, src)
35 /* true for gems/rocks that should have " stone" appended to their names */
36 #define GemStone(typ) \
37 (typ == FLINT \
38 || (objects[typ].oc_material == GEMSTONE \
39 && (typ != DILITHIUM_CRYSTAL && typ != RUBY && typ != DIAMOND \
40 && typ != SAPPHIRE && typ != BLACK_OPAL && typ != EMERALD \
41 && typ != OPAL)))
43 STATIC_OVL struct Jitem Japanese_items[] = { { SHORT_SWORD, "wakizashi" },
44 { BROADSWORD, "ninja-to" },
45 { FLAIL, "nunchaku" },
46 { GLAIVE, "naginata" },
47 { LOCK_PICK, "osaku" },
48 { WOODEN_HARP, "koto" },
49 { KNIFE, "shito" },
50 { PLATE_MAIL, "tanko" },
51 { HELMET, "kabuto" },
52 { LEATHER_GLOVES, "yugake" },
53 { FOOD_RATION, "gunyoki" },
54 { POT_BOOZE, "sake" },
55 { 0, "" } };
57 STATIC_DCL const char *FDECL(Japanese_item_name, (int i));
59 STATIC_OVL char *
60 strprepend(s, pref)
61 register char *s;
62 register const char *pref;
64 register int i = (int) strlen(pref);
66 if (i > PREFIX) {
67 impossible("PREFIX too short (for %d).", i);
68 return s;
70 s -= i;
71 (void) strncpy(s, pref, i); /* do not copy trailing 0 */
72 return s;
75 /* manage a pool of BUFSZ buffers, so callers don't have to */
76 static char NEARDATA obufs[NUMOBUF][BUFSZ];
77 static int obufidx = 0;
79 STATIC_OVL char *
80 nextobuf()
82 obufidx = (obufidx + 1) % NUMOBUF;
83 return obufs[obufidx];
86 /* put the most recently allocated buffer back if possible */
87 STATIC_OVL void
88 releaseobuf(bufp)
89 char *bufp;
91 /* caller may not know whether bufp is the most recently allocated
92 buffer; if it isn't, do nothing */
93 if (bufp == obufs[obufidx])
94 obufidx = (obufidx - 1 + NUMOBUF) % NUMOBUF;
97 char *
98 obj_typename(otyp)
99 register int otyp;
101 char *buf = nextobuf();
102 register struct objclass *ocl = &objects[otyp];
103 register const char *actualn = OBJ_NAME(*ocl);
104 register const char *dn = OBJ_DESCR(*ocl);
105 register const char *un = ocl->oc_uname;
106 register int nn = ocl->oc_name_known;
108 if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
109 actualn = Japanese_item_name(otyp);
110 switch (ocl->oc_class) {
111 case COIN_CLASS:
112 Strcpy(buf, "coin");
113 break;
114 case POTION_CLASS:
115 Strcpy(buf, "potion");
116 break;
117 case SCROLL_CLASS:
118 Strcpy(buf, "scroll");
119 break;
120 case WAND_CLASS:
121 Strcpy(buf, "wand");
122 break;
123 case SPBOOK_CLASS:
124 if (otyp != SPE_NOVEL) {
125 Strcpy(buf, "spellbook");
126 } else {
127 Strcpy(buf, !nn ? "book" : "novel");
128 nn = 0;
130 break;
131 case RING_CLASS:
132 Strcpy(buf, "ring");
133 break;
134 case AMULET_CLASS:
135 if (nn)
136 Strcpy(buf, actualn);
137 else
138 Strcpy(buf, "amulet");
139 if (un)
140 Sprintf(eos(buf), " called %s", un);
141 if (dn)
142 Sprintf(eos(buf), " (%s)", dn);
143 return buf;
144 default:
145 if (nn) {
146 Strcpy(buf, actualn);
147 if (GemStone(otyp))
148 Strcat(buf, " stone");
149 if (un)
150 Sprintf(eos(buf), " called %s", un);
151 if (dn)
152 Sprintf(eos(buf), " (%s)", dn);
153 } else {
154 Strcpy(buf, dn ? dn : actualn);
155 if (ocl->oc_class == GEM_CLASS)
156 Strcat(buf,
157 (ocl->oc_material == MINERAL) ? " stone" : " gem");
158 if (un)
159 Sprintf(eos(buf), " called %s", un);
161 return buf;
163 /* here for ring/scroll/potion/wand */
164 if (nn) {
165 if (ocl->oc_unique)
166 Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */
167 else
168 Sprintf(eos(buf), " of %s", actualn);
170 if (un)
171 Sprintf(eos(buf), " called %s", un);
172 if (dn)
173 Sprintf(eos(buf), " (%s)", dn);
174 return buf;
177 /* less verbose result than obj_typename(); either the actual name
178 or the description (but not both); user-assigned name is ignored */
179 char *
180 simple_typename(otyp)
181 int otyp;
183 char *bufp, *pp, *save_uname = objects[otyp].oc_uname;
185 objects[otyp].oc_uname = 0; /* suppress any name given by user */
186 bufp = obj_typename(otyp);
187 objects[otyp].oc_uname = save_uname;
188 if ((pp = strstri(bufp, " (")) != 0)
189 *pp = '\0'; /* strip the appended description */
190 return bufp;
193 boolean
194 obj_is_pname(obj)
195 struct obj *obj;
197 if (!obj->oartifact || !has_oname(obj))
198 return FALSE;
199 if (!program_state.gameover && !iflags.override_ID) {
200 if (not_fully_identified(obj))
201 return FALSE;
203 return TRUE;
206 /* used by distant_name() to pass extra information to xname_flags();
207 it would be much cleaner if this were a parameter, but that would
208 require all of the xname() and doname() calls to be modified */
209 static int distantname = 0;
211 /* Give the name of an object seen at a distance. Unlike xname/doname,
212 * we don't want to set dknown if it's not set already.
214 char *
215 distant_name(obj, func)
216 struct obj *obj;
217 char *FDECL((*func), (OBJ_P));
219 char *str;
221 /* 3.6.1: this used to save Blind, set it, make the call, then restore
222 * the saved value; but the Eyes of the Overworld override blindness
223 * and let characters wearing them get dknown set for distant items.
225 * TODO? if the hero is wearing those Eyes, figure out whether the
226 * object is within X-ray radius and only treat it as distant when
227 * beyond that radius. Logic is iffy but result might be interesting.
229 ++distantname;
230 str = (*func)(obj);
231 --distantname;
232 return str;
235 /* convert player specified fruit name into corresponding fruit juice name
236 ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
237 char *
238 fruitname(juice)
239 boolean juice; /* whether or not to append " juice" to the name */
241 char *buf = nextobuf();
242 const char *fruit_nam = strstri(pl_fruit, " of ");
244 if (fruit_nam)
245 fruit_nam += 4; /* skip past " of " */
246 else
247 fruit_nam = pl_fruit; /* use it as is */
249 Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : "");
250 return buf;
253 char *
254 xname(obj)
255 struct obj *obj;
257 return xname_flags(obj, CXN_NORMAL);
260 char *
261 xname_flags(obj, cxn_flags)
262 register struct obj *obj;
263 unsigned cxn_flags; /* bitmask of CXN_xxx values */
265 register char *buf;
266 register int typ = obj->otyp;
267 register struct objclass *ocl = &objects[typ];
268 int nn = ocl->oc_name_known, omndx = obj->corpsenm;
269 const char *actualn = OBJ_NAME(*ocl);
270 const char *dn = OBJ_DESCR(*ocl);
271 const char *un = ocl->oc_uname;
272 boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR);
273 boolean known, dknown, bknown;
275 buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */
276 if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
277 actualn = Japanese_item_name(typ);
279 buf[0] = '\0';
281 * clean up known when it's tied to oc_name_known, eg after AD_DRIN
282 * This is only required for unique objects since the article
283 * printed for the object is tied to the combination of the two
284 * and printing the wrong article gives away information.
286 if (!nn && ocl->oc_uses_known && ocl->oc_unique)
287 obj->known = 0;
288 if (!Blind && !distantname)
289 obj->dknown = TRUE;
290 if (Role_if(PM_PRIEST))
291 obj->bknown = TRUE;
293 if (iflags.override_ID) {
294 known = dknown = bknown = TRUE;
295 nn = 1;
296 } else {
297 known = obj->known;
298 dknown = obj->dknown;
299 bknown = obj->bknown;
302 if (obj_is_pname(obj))
303 goto nameit;
304 switch (obj->oclass) {
305 case AMULET_CLASS:
306 if (!dknown)
307 Strcpy(buf, "amulet");
308 else if (typ == AMULET_OF_YENDOR || typ == FAKE_AMULET_OF_YENDOR)
309 /* each must be identified individually */
310 Strcpy(buf, known ? actualn : dn);
311 else if (nn)
312 Strcpy(buf, actualn);
313 else if (un)
314 Sprintf(buf, "amulet called %s", un);
315 else
316 Sprintf(buf, "%s amulet", dn);
317 break;
318 case WEAPON_CLASS:
319 if (is_poisonable(obj) && obj->opoisoned)
320 Strcpy(buf, "poisoned ");
321 case VENOM_CLASS:
322 case TOOL_CLASS:
323 if (typ == LENSES)
324 Strcpy(buf, "pair of ");
325 else if (is_wet_towel(obj))
326 Strcpy(buf, (obj->spe < 3) ? "moist " : "wet ");
328 if (!dknown)
329 Strcat(buf, dn ? dn : actualn);
330 else if (nn)
331 Strcat(buf, actualn);
332 else if (un) {
333 Strcat(buf, dn ? dn : actualn);
334 Strcat(buf, " called ");
335 Strcat(buf, un);
336 } else
337 Strcat(buf, dn ? dn : actualn);
338 /* If we use an() here we'd have to remember never to use */
339 /* it whenever calling doname() or xname(). */
340 if (typ == FIGURINE && omndx != NON_PM) {
341 Sprintf(eos(buf), " of a%s %s",
342 index(vowels, *mons[omndx].mname) ? "n" : "",
343 mons[omndx].mname);
344 } else if (is_wet_towel(obj)) {
345 if (wizard)
346 Sprintf(eos(buf), " (%d)", obj->spe);
348 break;
349 case ARMOR_CLASS:
350 /* depends on order of the dragon scales objects */
351 if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
352 Sprintf(buf, "set of %s", actualn);
353 break;
355 if (is_boots(obj) || is_gloves(obj))
356 Strcpy(buf, "pair of ");
358 if (obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
359 && !dknown) {
360 Strcpy(buf, "shield");
361 break;
363 if (obj->otyp == SHIELD_OF_REFLECTION && !dknown) {
364 Strcpy(buf, "smooth shield");
365 break;
368 if (nn)
369 Strcat(buf, actualn);
370 else if (un) {
371 if (is_boots(obj))
372 Strcat(buf, "boots");
373 else if (is_gloves(obj))
374 Strcat(buf, "gloves");
375 else if (is_cloak(obj))
376 Strcpy(buf, "cloak");
377 else if (is_helmet(obj))
378 Strcpy(buf, "helmet");
379 else if (is_shield(obj))
380 Strcpy(buf, "shield");
381 else
382 Strcpy(buf, "armor");
383 Strcat(buf, " called ");
384 Strcat(buf, un);
385 } else
386 Strcat(buf, dn);
387 break;
388 case FOOD_CLASS:
389 if (typ == SLIME_MOLD) {
390 register struct fruit *f;
392 for (f = ffruit; f; f = f->nextf) {
393 if (f->fid == obj->spe) {
394 Strcpy(buf, f->fname);
395 break;
398 if (!f) {
399 impossible("Bad fruit #%d?", obj->spe);
400 Strcpy(buf, "fruit");
401 } else if (pluralize) {
402 /* ick; already pluralized fruit names
403 are allowed--we want to try to avoid
404 adding a redundant plural suffix */
405 Strcpy(buf, makeplural(makesingular(buf)));
406 pluralize = FALSE;
408 break;
410 if (Is_pudding(obj)) {
411 Sprintf(buf, "%s%s",
412 (obj->owt < 100)
413 ? "small "
414 : (obj->owt > 500)
415 ? "very large "
416 : (obj->owt > 300)
417 ? "large "
418 : "",
419 actualn);
420 break;
423 Strcpy(buf, actualn);
424 if (typ == TIN && known)
425 tin_details(obj, omndx, buf);
426 break;
427 case COIN_CLASS:
428 case CHAIN_CLASS:
429 Strcpy(buf, actualn);
430 break;
431 case ROCK_CLASS:
432 if (typ == STATUE && omndx != NON_PM)
433 Sprintf(buf, "%s%s of %s%s",
434 (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC))
435 ? "historic "
436 : "",
437 actualn,
438 type_is_pname(&mons[omndx])
439 ? ""
440 : the_unique_pm(&mons[omndx])
441 ? "the "
442 : index(vowels, *mons[omndx].mname)
443 ? "an "
444 : "a ",
445 mons[omndx].mname);
446 else
447 Strcpy(buf, actualn);
448 break;
449 case BALL_CLASS:
450 Sprintf(buf, "%sheavy iron ball",
451 (obj->owt > ocl->oc_weight) ? "very " : "");
452 break;
453 case POTION_CLASS:
454 if (dknown && obj->odiluted)
455 Strcpy(buf, "diluted ");
456 if (nn || un || !dknown) {
457 Strcat(buf, "potion");
458 if (!dknown)
459 break;
460 if (nn) {
461 Strcat(buf, " of ");
462 if (typ == POT_WATER && bknown
463 && (obj->blessed || obj->cursed)) {
464 Strcat(buf, obj->blessed ? "holy " : "unholy ");
466 Strcat(buf, actualn);
467 } else {
468 Strcat(buf, " called ");
469 Strcat(buf, un);
471 } else {
472 Strcat(buf, dn);
473 Strcat(buf, " potion");
475 break;
476 case SCROLL_CLASS:
477 Strcpy(buf, "scroll");
478 if (!dknown)
479 break;
480 if (nn) {
481 Strcat(buf, " of ");
482 Strcat(buf, actualn);
483 } else if (un) {
484 Strcat(buf, " called ");
485 Strcat(buf, un);
486 } else if (ocl->oc_magic) {
487 Strcat(buf, " labeled ");
488 Strcat(buf, dn);
489 } else {
490 Strcpy(buf, dn);
491 Strcat(buf, " scroll");
493 break;
494 case WAND_CLASS:
495 if (!dknown)
496 Strcpy(buf, "wand");
497 else if (nn)
498 Sprintf(buf, "wand of %s", actualn);
499 else if (un)
500 Sprintf(buf, "wand called %s", un);
501 else
502 Sprintf(buf, "%s wand", dn);
503 break;
504 case SPBOOK_CLASS:
505 if (typ == SPE_NOVEL) { /* 3.6 tribute */
506 if (!dknown)
507 Strcpy(buf, "book");
508 else if (nn)
509 Strcpy(buf, actualn);
510 else if (un)
511 Sprintf(buf, "novel called %s", un);
512 else
513 Sprintf(buf, "%s book", dn);
514 break;
515 /* end of tribute */
516 } else if (!dknown) {
517 Strcpy(buf, "spellbook");
518 } else if (nn) {
519 if (typ != SPE_BOOK_OF_THE_DEAD)
520 Strcpy(buf, "spellbook of ");
521 Strcat(buf, actualn);
522 } else if (un) {
523 Sprintf(buf, "spellbook called %s", un);
524 } else
525 Sprintf(buf, "%s spellbook", dn);
526 break;
527 case RING_CLASS:
528 if (!dknown)
529 Strcpy(buf, "ring");
530 else if (nn)
531 Sprintf(buf, "ring of %s", actualn);
532 else if (un)
533 Sprintf(buf, "ring called %s", un);
534 else
535 Sprintf(buf, "%s ring", dn);
536 break;
537 case GEM_CLASS: {
538 const char *rock = (ocl->oc_material == MINERAL) ? "stone" : "gem";
540 if (!dknown) {
541 Strcpy(buf, rock);
542 } else if (!nn) {
543 if (un)
544 Sprintf(buf, "%s called %s", rock, un);
545 else
546 Sprintf(buf, "%s %s", dn, rock);
547 } else {
548 Strcpy(buf, actualn);
549 if (GemStone(typ))
550 Strcat(buf, " stone");
552 break;
554 default:
555 Sprintf(buf, "glorkum %d %d %d", obj->oclass, typ, obj->spe);
557 if (pluralize)
558 Strcpy(buf, makeplural(buf));
560 if (obj->otyp == T_SHIRT && program_state.gameover) {
561 char tmpbuf[BUFSZ];
563 Sprintf(eos(buf), " with text \"%s\"", tshirt_text(obj, tmpbuf));
566 if (has_oname(obj) && dknown) {
567 Strcat(buf, " named ");
568 nameit:
569 Strcat(buf, ONAME(obj));
572 if (!strncmpi(buf, "the ", 4))
573 buf += 4;
574 return buf;
577 /* similar to simple_typename but minimal_xname operates on a particular
578 object rather than its general type; it formats the most basic info:
579 potion -- if description not known
580 brown potion -- if oc_name_known not set
581 potion of object detection -- if discovered
583 static char *
584 minimal_xname(obj)
585 struct obj *obj;
587 char *bufp;
588 struct obj bareobj;
589 struct objclass saveobcls;
590 int otyp = obj->otyp;
592 /* suppress user-supplied name */
593 saveobcls.oc_uname = objects[otyp].oc_uname;
594 objects[otyp].oc_uname = 0;
595 /* suppress actual name if object's description is unknown */
596 saveobcls.oc_name_known = objects[otyp].oc_name_known;
597 if (!obj->dknown)
598 objects[otyp].oc_name_known = 0;
600 /* caveat: this makes a lot of assumptions about which fields
601 are required in order for xname() to yield a sensible result */
602 bareobj = zeroobj;
603 bareobj.otyp = otyp;
604 bareobj.oclass = obj->oclass;
605 bareobj.dknown = obj->dknown;
606 /* suppress known except for amulets (needed for fakes and real A-of-Y) */
607 bareobj.known = (obj->oclass == AMULET_CLASS)
608 ? obj->known
609 /* default is "on" for types which don't use it */
610 : !objects[otyp].oc_uses_known;
611 bareobj.quan = 1L; /* don't want plural */
612 bareobj.corpsenm = NON_PM; /* suppress statue and figurine details */
613 /* but suppressing fruit details leads to "bad fruit #0"
614 [perhaps we should force "slime mold" rather than use xname?] */
615 if (obj->otyp == SLIME_MOLD)
616 bareobj.spe = obj->spe;
618 bufp = distant_name(&bareobj, xname); /* xname(&bareobj) */
619 if (!strncmp(bufp, "uncursed ", 9))
620 bufp += 9; /* Role_if(PM_PRIEST) */
622 objects[otyp].oc_uname = saveobcls.oc_uname;
623 objects[otyp].oc_name_known = saveobcls.oc_name_known;
624 return bufp;
627 /* xname() output augmented for multishot missile feedback */
628 char *
629 mshot_xname(obj)
630 struct obj *obj;
632 char tmpbuf[BUFSZ];
633 char *onm = xname(obj);
635 if (m_shot.n > 1 && m_shot.o == obj->otyp) {
636 /* "the Nth arrow"; value will eventually be passed to an() or
637 The(), both of which correctly handle this "the " prefix */
638 Sprintf(tmpbuf, "the %d%s ", m_shot.i, ordin(m_shot.i));
639 onm = strprepend(onm, tmpbuf);
641 return onm;
644 /* used for naming "the unique_item" instead of "a unique_item" */
645 boolean
646 the_unique_obj(obj)
647 struct obj *obj;
649 boolean known = (obj->known || iflags.override_ID);
651 if (!obj->dknown && !iflags.override_ID)
652 return FALSE;
653 else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !known)
654 return TRUE; /* lie */
655 else
656 return (boolean) (objects[obj->otyp].oc_unique
657 && (known || obj->otyp == AMULET_OF_YENDOR));
660 /* should monster type be prefixed with "the"? (mostly used for corpses) */
661 boolean
662 the_unique_pm(ptr)
663 struct permonst *ptr;
665 boolean uniq;
667 /* even though monsters with personal names are unique, we want to
668 describe them as "Name" rather than "the Name" */
669 if (type_is_pname(ptr))
670 return FALSE;
672 uniq = (ptr->geno & G_UNIQ) ? TRUE : FALSE;
673 /* high priest is unique if it includes "of <deity>", otherwise not
674 (caller needs to handle the 1st possibility; we assume the 2nd);
675 worm tail should be irrelevant but is included for completeness */
676 if (ptr == &mons[PM_HIGH_PRIEST] || ptr == &mons[PM_LONG_WORM_TAIL])
677 uniq = FALSE;
678 /* Wizard no longer needs this; he's flagged as unique these days */
679 if (ptr == &mons[PM_WIZARD_OF_YENDOR])
680 uniq = TRUE;
681 return uniq;
684 STATIC_OVL void
685 add_erosion_words(obj, prefix)
686 struct obj *obj;
687 char *prefix;
689 boolean iscrys = (obj->otyp == CRYSKNIFE);
690 boolean rknown;
692 rknown = (iflags.override_ID == 0) ? obj->rknown : TRUE;
694 if (!is_damageable(obj) && !iscrys)
695 return;
697 /* The only cases where any of these bits do double duty are for
698 * rotted food and diluted potions, which are all not is_damageable().
700 if (obj->oeroded && !iscrys) {
701 switch (obj->oeroded) {
702 case 2:
703 Strcat(prefix, "very ");
704 break;
705 case 3:
706 Strcat(prefix, "thoroughly ");
707 break;
709 Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt ");
711 if (obj->oeroded2 && !iscrys) {
712 switch (obj->oeroded2) {
713 case 2:
714 Strcat(prefix, "very ");
715 break;
716 case 3:
717 Strcat(prefix, "thoroughly ");
718 break;
720 Strcat(prefix, is_corrodeable(obj) ? "corroded " : "rotted ");
722 if (rknown && obj->oerodeproof)
723 Strcat(prefix, iscrys
724 ? "fixed "
725 : is_rustprone(obj)
726 ? "rustproof "
727 : is_corrodeable(obj)
728 ? "corrodeproof " /* "stainless"? */
729 : is_flammable(obj)
730 ? "fireproof "
731 : "");
734 /* used to prevent rust on items where rust makes no difference */
735 boolean
736 erosion_matters(obj)
737 struct obj *obj;
739 switch (obj->oclass) {
740 case TOOL_CLASS:
741 /* it's possible for a rusty weptool to be polymorphed into some
742 non-weptool iron tool, in which case the rust implicitly goes
743 away, but it's also possible for it to be polymorphed into a
744 non-iron tool, in which case rust also implicitly goes away,
745 so there's no particular reason to try to handle the first
746 instance differently [this comment belongs in poly_obj()...] */
747 return is_weptool(obj) ? TRUE : FALSE;
748 case WEAPON_CLASS:
749 case ARMOR_CLASS:
750 case BALL_CLASS:
751 case CHAIN_CLASS:
752 return TRUE;
753 default:
754 break;
756 return FALSE;
759 static char *
760 doname_base(obj, with_price)
761 register struct obj *obj;
762 boolean with_price;
764 boolean ispoisoned = FALSE;
765 boolean known, dknown, cknown, bknown, lknown;
766 int omndx = obj->corpsenm;
767 char prefix[PREFIX];
768 char tmpbuf[PREFIX + 1]; /* for when we have to add something at
769 the start of prefix instead of the
770 end (Strcat is used on the end) */
771 register char *bp = xname(obj);
773 if (iflags.override_ID) {
774 known = dknown = cknown = bknown = lknown = TRUE;
775 } else {
776 known = obj->known;
777 dknown = obj->dknown;
778 cknown = obj->cknown;
779 bknown = obj->bknown;
780 lknown = obj->lknown;
783 /* When using xname, we want "poisoned arrow", and when using
784 * doname, we want "poisoned +0 arrow". This kludge is about the only
785 * way to do it, at least until someone overhauls xname() and doname(),
786 * combining both into one function taking a parameter.
788 /* must check opoisoned--someone can have a weirdly-named fruit */
789 if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
790 bp += 9;
791 ispoisoned = TRUE;
794 if (obj->quan != 1L) {
795 if (dknown)
796 Sprintf(prefix, "%ld ", obj->quan);
797 else
798 Strcpy(prefix, "some ");
799 } else if (obj->otyp == CORPSE) {
800 /* skip article prefix for corpses [else corpse_xname()
801 would have to be taught how to strip it off again] */
802 *prefix = '\0';
803 } else if (obj_is_pname(obj) || the_unique_obj(obj)) {
804 if (!strncmpi(bp, "the ", 4))
805 bp += 4;
806 Strcpy(prefix, "the ");
807 } else {
808 Strcpy(prefix, "a ");
811 /* "empty" goes at the beginning, but item count goes at the end */
812 if (cknown
813 /* bag of tricks: include "empty" prefix if it's known to
814 be empty but its precise number of charges isn't known
815 (when that is known, suffix of "(n:0)" will be appended,
816 making the prefix be redundant; note that 'known' flag
817 isn't set when emptiness gets discovered because then
818 charging magic would yield known number of new charges) */
819 && (obj->otyp == BAG_OF_TRICKS
820 ? (obj->spe == 0 && !obj->known)
821 /* not bag of tricks: empty if container which has no contents */
822 : (Is_container(obj) || obj->otyp == STATUE)
823 && !Has_contents(obj)))
824 Strcat(prefix, "empty ");
826 if (bknown && obj->oclass != COIN_CLASS
827 && (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
828 || (!obj->cursed && !obj->blessed))) {
829 /* allow 'blessed clear potion' if we don't know it's holy water;
830 * always allow "uncursed potion of water"
832 if (obj->cursed)
833 Strcat(prefix, "cursed ");
834 else if (obj->blessed)
835 Strcat(prefix, "blessed ");
836 else if (!iflags.implicit_uncursed
837 /* For most items with charges or +/-, if you know how many
838 * charges are left or what the +/- is, then you must have
839 * totally identified the item, so "uncursed" is unnecessary,
840 * because an identified object not described as "blessed" or
841 * "cursed" must be uncursed.
843 * If the charges or +/- is not known, "uncursed" must be
844 * printed to avoid ambiguity between an item whose curse
845 * status is unknown, and an item known to be uncursed.
847 || ((!known || !objects[obj->otyp].oc_charged
848 || obj->oclass == ARMOR_CLASS
849 || obj->oclass == RING_CLASS)
850 #ifdef MAIL
851 && obj->otyp != SCR_MAIL
852 #endif
853 && obj->otyp != FAKE_AMULET_OF_YENDOR
854 && obj->otyp != AMULET_OF_YENDOR
855 && !Role_if(PM_PRIEST)))
856 Strcat(prefix, "uncursed ");
859 if (lknown && Is_box(obj)) {
860 if (obj->obroken)
861 /* 3.6.0 used "unlockable" here but that could be misunderstood
862 to mean "capable of being unlocked" rather than the intended
863 "not capable of being locked" */
864 Strcat(prefix, "broken ");
865 else if (obj->olocked)
866 Strcat(prefix, "locked ");
867 else
868 Strcat(prefix, "unlocked ");
871 if (obj->greased)
872 Strcat(prefix, "greased ");
874 if (cknown && Has_contents(obj)) {
875 /* we count all objects (obj->quantity); perhaps we should
876 count separate stacks instead (or even introduce a user
877 preference option to choose between the two alternatives)
878 since it's somewhat odd so see "containing 1002 items"
879 when there are 2 scrolls plus 1000 gold pieces */
880 long itemcount = count_contents(obj, FALSE, FALSE, TRUE);
882 Sprintf(eos(bp), " containing %ld item%s", itemcount,
883 plur(itemcount));
886 switch (is_weptool(obj) ? WEAPON_CLASS : obj->oclass) {
887 case AMULET_CLASS:
888 if (obj->owornmask & W_AMUL)
889 Strcat(bp, " (being worn)");
890 break;
891 case ARMOR_CLASS:
892 if (obj->owornmask & W_ARMOR)
893 Strcat(bp, (obj == uskin) ? " (embedded in your skin)"
894 : " (being worn)");
895 /*FALLTHRU*/
896 case WEAPON_CLASS:
897 if (ispoisoned)
898 Strcat(prefix, "poisoned ");
899 add_erosion_words(obj, prefix);
900 if (known) {
901 Strcat(prefix, sitoa(obj->spe));
902 Strcat(prefix, " ");
904 break;
905 case TOOL_CLASS:
906 if (obj->owornmask & (W_TOOL | W_SADDLE)) { /* blindfold */
907 Strcat(bp, " (being worn)");
908 break;
910 if (obj->otyp == LEASH && obj->leashmon != 0) {
911 Strcat(bp, " (in use)");
912 break;
914 if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
915 if (!obj->spe)
916 Strcpy(tmpbuf, "no");
917 else
918 Sprintf(tmpbuf, "%d", obj->spe);
919 Sprintf(eos(bp), " (%s candle%s%s)", tmpbuf, plur(obj->spe),
920 !obj->lamplit ? " attached" : ", lit");
921 break;
922 } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
923 || obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
924 if (Is_candle(obj)
925 && obj->age < 20L * (long) objects[obj->otyp].oc_cost)
926 Strcat(prefix, "partly used ");
927 if (obj->lamplit)
928 Strcat(bp, " (lit)");
929 break;
931 if (objects[obj->otyp].oc_charged)
932 goto charges;
933 break;
934 case WAND_CLASS:
935 charges:
936 if (known)
937 Sprintf(eos(bp), " (%d:%d)", (int) obj->recharged, obj->spe);
938 break;
939 case POTION_CLASS:
940 if (obj->otyp == POT_OIL && obj->lamplit)
941 Strcat(bp, " (lit)");
942 break;
943 case RING_CLASS:
944 ring:
945 if (obj->owornmask & W_RINGR)
946 Strcat(bp, " (on right ");
947 if (obj->owornmask & W_RINGL)
948 Strcat(bp, " (on left ");
949 if (obj->owornmask & W_RING) {
950 Strcat(bp, body_part(HAND));
951 Strcat(bp, ")");
953 if (known && objects[obj->otyp].oc_charged) {
954 Strcat(prefix, sitoa(obj->spe));
955 Strcat(prefix, " ");
957 break;
958 case FOOD_CLASS:
959 if (obj->oeaten)
960 Strcat(prefix, "partly eaten ");
961 if (obj->otyp == CORPSE) {
962 Sprintf(prefix, "%s ",
963 corpse_xname(obj, prefix, CXN_ARTICLE | CXN_NOCORPSE));
964 } else if (obj->otyp == EGG) {
965 #if 0 /* corpses don't tell if they're stale either */
966 if (known && stale_egg(obj))
967 Strcat(prefix, "stale ");
968 #endif
969 if (omndx >= LOW_PM
970 && (known || (mvitals[omndx].mvflags & MV_KNOWS_EGG))) {
971 Strcat(prefix, mons[omndx].mname);
972 Strcat(prefix, " ");
973 if (obj->spe)
974 Strcat(bp, " (laid by you)");
977 if (obj->otyp == MEAT_RING)
978 goto ring;
979 break;
980 case BALL_CLASS:
981 case CHAIN_CLASS:
982 add_erosion_words(obj, prefix);
983 if (obj->owornmask & W_BALL)
984 Strcat(bp, " (chained to you)");
985 break;
988 if ((obj->owornmask & W_WEP) && !mrg_to_wielded) {
989 if (obj->quan != 1L) {
990 Strcat(bp, " (wielded)");
991 } else {
992 const char *hand_s = body_part(HAND);
994 if (bimanual(obj))
995 hand_s = makeplural(hand_s);
996 Sprintf(eos(bp), " (weapon in %s)", hand_s);
998 if (warn_obj_cnt && obj == uwep && (EWarn_of_mon & W_WEP) != 0L) {
999 /* presumably can be felt when blind */
1000 Strcat(bp, " (glowing");
1001 if (!Blind)
1002 Sprintf(eos(bp), " %s", glow_color(obj->oartifact));
1003 Strcat(bp, ")");
1007 if (obj->owornmask & W_SWAPWEP) {
1008 if (u.twoweap)
1009 Sprintf(eos(bp), " (wielded in other %s)", body_part(HAND));
1010 else
1011 Strcat(bp, " (alternate weapon; not wielded)");
1013 if (obj->owornmask & W_QUIVER) {
1014 switch (obj->oclass) {
1015 case WEAPON_CLASS:
1016 if (is_ammo(obj)) {
1017 if (objects[obj->otyp].oc_skill == -P_BOW) {
1018 /* Ammo for a bow */
1019 Strcat(bp, " (in quiver)");
1020 break;
1021 } else {
1022 /* Ammo not for a bow */
1023 Strcat(bp, " (in quiver pouch)");
1024 break;
1026 } else {
1027 /* Weapons not considered ammo */
1028 Strcat(bp, " (at the ready)");
1029 break;
1031 /* Small things and ammo not for a bow */
1032 case RING_CLASS:
1033 case AMULET_CLASS:
1034 case WAND_CLASS:
1035 case COIN_CLASS:
1036 case GEM_CLASS:
1037 Strcat(bp, " (in quiver pouch)");
1038 break;
1039 default: /* odd things */
1040 Strcat(bp, " (at the ready)");
1043 if (!iflags.suppress_price && is_unpaid(obj)) {
1044 long quotedprice = unpaid_cost(obj, TRUE);
1046 Sprintf(eos(bp), " (%s, %ld %s)",
1047 obj->unpaid ? "unpaid" : "contents",
1048 quotedprice, currency(quotedprice));
1049 } else if (with_price) {
1050 long price = get_cost_of_shop_item(obj);
1052 if (price > 0)
1053 Sprintf(eos(bp), " (%ld %s)", price, currency(price));
1055 if (!strncmp(prefix, "a ", 2)
1056 && index(vowels, *(prefix + 2) ? *(prefix + 2) : *bp)
1057 && (*(prefix + 2)
1058 || (strncmp(bp, "uranium", 7) && strncmp(bp, "unicorn", 7)
1059 && strncmp(bp, "eucalyptus", 10)))) {
1060 Strcpy(tmpbuf, prefix);
1061 Strcpy(prefix, "an ");
1062 Strcpy(prefix + 3, tmpbuf + 2);
1065 /* show weight for items (debug tourist info)
1066 * aum is stolen from Crawl's "Arbitrary Unit of Measure" */
1067 if (wizard && iflags.wizweight) {
1068 Sprintf(eos(bp), " (%d aum)", obj->owt);
1070 bp = strprepend(bp, prefix);
1071 return bp;
1074 char *
1075 doname(obj)
1076 register struct obj *obj;
1078 return doname_base(obj, FALSE);
1081 /* Name of object including price. */
1082 char *
1083 doname_with_price(obj)
1084 register struct obj *obj;
1086 return doname_base(obj, TRUE);
1089 /* used from invent.c */
1090 boolean
1091 not_fully_identified(otmp)
1092 register struct obj *otmp;
1094 /* gold doesn't have any interesting attributes [yet?] */
1095 if (otmp->oclass == COIN_CLASS)
1096 return FALSE; /* always fully ID'd */
1097 /* check fundamental ID hallmarks first */
1098 if (!otmp->known || !otmp->dknown
1099 #ifdef MAIL
1100 || (!otmp->bknown && otmp->otyp != SCR_MAIL)
1101 #else
1102 || !otmp->bknown
1103 #endif
1104 || !objects[otmp->otyp].oc_name_known)
1105 return TRUE;
1106 if ((!otmp->cknown && (Is_container(otmp) || otmp->otyp == STATUE))
1107 || (!otmp->lknown && Is_box(otmp)))
1108 return TRUE;
1109 if (otmp->oartifact && undiscovered_artifact(otmp->oartifact))
1110 return TRUE;
1111 /* otmp->rknown is the only item of interest if we reach here */
1113 * Note: if a revision ever allows scrolls to become fireproof or
1114 * rings to become shockproof, this checking will need to be revised.
1115 * `rknown' ID only matters if xname() will provide the info about it.
1117 if (otmp->rknown
1118 || (otmp->oclass != ARMOR_CLASS && otmp->oclass != WEAPON_CLASS
1119 && !is_weptool(otmp) /* (redundant) */
1120 && otmp->oclass != BALL_CLASS)) /* (useless) */
1121 return FALSE;
1122 else /* lack of `rknown' only matters for vulnerable objects */
1123 return (boolean) (is_rustprone(otmp) || is_corrodeable(otmp)
1124 || is_flammable(otmp));
1127 /* format a corpse name (xname() omits monster type; doname() calls us);
1128 eatcorpse() also uses us for death reason when eating tainted glob */
1129 char *
1130 corpse_xname(otmp, adjective, cxn_flags)
1131 struct obj *otmp;
1132 const char *adjective;
1133 unsigned cxn_flags; /* bitmask of CXN_xxx values */
1135 char *nambuf = nextobuf();
1136 int omndx = otmp->corpsenm;
1137 boolean ignore_quan = (cxn_flags & CXN_SINGULAR) != 0,
1138 /* suppress "the" from "the unique monster corpse" */
1139 no_prefix = (cxn_flags & CXN_NO_PFX) != 0,
1140 /* include "the" for "the woodchuck corpse */
1141 the_prefix = (cxn_flags & CXN_PFX_THE) != 0,
1142 /* include "an" for "an ogre corpse */
1143 any_prefix = (cxn_flags & CXN_ARTICLE) != 0,
1144 /* leave off suffix (do_name() appends "corpse" itself) */
1145 omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0,
1146 possessive = FALSE,
1147 glob = (otmp->otyp != CORPSE && otmp->globby);
1148 const char *mname;
1150 if (glob) {
1151 mname = OBJ_NAME(objects[otmp->otyp]); /* "glob of <monster>" */
1152 } else if (omndx == NON_PM) { /* paranoia */
1153 mname = "thing";
1154 /* [Possible enhancement: check whether corpse has monster traits
1155 attached in order to use priestname() for priests and minions.] */
1156 } else if (omndx == PM_ALIGNED_PRIEST) {
1157 /* avoid "aligned priest"; it just exposes internal details */
1158 mname = "priest";
1159 } else {
1160 mname = mons[omndx].mname;
1161 if (the_unique_pm(&mons[omndx]) || type_is_pname(&mons[omndx])) {
1162 mname = s_suffix(mname);
1163 possessive = TRUE;
1164 /* don't precede personal name like "Medusa" with an article */
1165 if (type_is_pname(&mons[omndx]))
1166 no_prefix = TRUE;
1167 /* always precede non-personal unique monster name like
1168 "Oracle" with "the" unless explicitly overridden */
1169 else if (the_unique_pm(&mons[omndx]) && !no_prefix)
1170 the_prefix = TRUE;
1173 if (no_prefix)
1174 the_prefix = any_prefix = FALSE;
1175 else if (the_prefix)
1176 any_prefix = FALSE; /* mutually exclusive */
1178 *nambuf = '\0';
1179 /* can't use the() the way we use an() below because any capitalized
1180 Name causes it to assume a personal name and return Name as-is;
1181 that's usually the behavior wanted, but here we need to force "the"
1182 to precede capitalized unique monsters (pnames are handled above) */
1183 if (the_prefix)
1184 Strcat(nambuf, "the ");
1186 if (!adjective || !*adjective) {
1187 /* normal case: newt corpse */
1188 Strcat(nambuf, mname);
1189 } else {
1190 /* adjective positioning depends upon format of monster name */
1191 if (possessive) /* Medusa's cursed partly eaten corpse */
1192 Sprintf(eos(nambuf), "%s %s", mname, adjective);
1193 else /* cursed partly eaten troll corpse */
1194 Sprintf(eos(nambuf), "%s %s", adjective, mname);
1195 /* in case adjective has a trailing space, squeeze it out */
1196 mungspaces(nambuf);
1197 /* doname() might include a count in the adjective argument;
1198 if so, don't prepend an article */
1199 if (digit(*adjective))
1200 any_prefix = FALSE;
1203 if (glob) {
1204 ; /* omit_corpse doesn't apply; quantity is always 1 */
1205 } else if (!omit_corpse) {
1206 Strcat(nambuf, " corpse");
1207 /* makeplural(nambuf) => append "s" to "corpse" */
1208 if (otmp->quan > 1L && !ignore_quan) {
1209 Strcat(nambuf, "s");
1210 any_prefix = FALSE; /* avoid "a newt corpses" */
1214 /* it's safe to overwrite our nambuf after an() has copied
1215 its old value into another buffer */
1216 if (any_prefix)
1217 Strcpy(nambuf, an(nambuf));
1219 return nambuf;
1222 /* xname doesn't include monster type for "corpse"; cxname does */
1223 char *
1224 cxname(obj)
1225 struct obj *obj;
1227 if (obj->otyp == CORPSE)
1228 return corpse_xname(obj, (const char *) 0, CXN_NORMAL);
1229 return xname(obj);
1232 /* like cxname, but ignores quantity */
1233 char *
1234 cxname_singular(obj)
1235 struct obj *obj;
1237 if (obj->otyp == CORPSE)
1238 return corpse_xname(obj, (const char *) 0, CXN_SINGULAR);
1239 return xname_flags(obj, CXN_SINGULAR);
1242 /* treat an object as fully ID'd when it might be used as reason for death */
1243 char *
1244 killer_xname(obj)
1245 struct obj *obj;
1247 struct obj save_obj;
1248 unsigned save_ocknown;
1249 char *buf, *save_ocuname, *save_oname = (char *) 0;
1251 /* bypass object twiddling for artifacts */
1252 if (obj->oartifact)
1253 return bare_artifactname(obj);
1255 /* remember original settings for core of the object;
1256 oextra structs other than oname don't matter here--since they
1257 aren't modified they don't need to be saved and restored */
1258 save_obj = *obj;
1259 if (has_oname(obj))
1260 save_oname = ONAME(obj);
1262 /* killer name should be more specific than general xname; however, exact
1263 info like blessed/cursed and rustproof makes things be too verbose */
1264 obj->known = obj->dknown = 1;
1265 obj->bknown = obj->rknown = obj->greased = 0;
1266 /* if character is a priest[ess], bknown will get toggled back on */
1267 if (obj->otyp != POT_WATER)
1268 obj->blessed = obj->cursed = 0;
1269 else
1270 obj->bknown = 1; /* describe holy/unholy water as such */
1271 /* "killed by poisoned <obj>" would be misleading when poison is
1272 not the cause of death and "poisoned by poisoned <obj>" would
1273 be redundant when it is, so suppress "poisoned" prefix */
1274 obj->opoisoned = 0;
1275 /* strip user-supplied name; artifacts keep theirs */
1276 if (!obj->oartifact && save_oname)
1277 ONAME(obj) = (char *) 0;
1278 /* temporarily identify the type of object */
1279 save_ocknown = objects[obj->otyp].oc_name_known;
1280 objects[obj->otyp].oc_name_known = 1;
1281 save_ocuname = objects[obj->otyp].oc_uname;
1282 objects[obj->otyp].oc_uname = 0; /* avoid "foo called bar" */
1284 /* format the object */
1285 if (obj->otyp == CORPSE) {
1286 buf = nextobuf();
1287 Strcpy(buf, corpse_xname(obj, (const char *) 0, CXN_NORMAL));
1288 } else if (obj->otyp == SLIME_MOLD) {
1289 /* concession to "most unique deaths competition" in the annual
1290 devnull tournament, suppress player supplied fruit names because
1291 those can be used to fake other objects and dungeon features */
1292 buf = nextobuf();
1293 Sprintf(buf, "deadly slime mold%s", plur(obj->quan));
1294 } else {
1295 buf = xname(obj);
1297 /* apply an article if appropriate; caller should always use KILLED_BY */
1298 if (obj->quan == 1L && !strstri(buf, "'s ") && !strstri(buf, "s' "))
1299 buf = (obj_is_pname(obj) || the_unique_obj(obj)) ? the(buf) : an(buf);
1301 objects[obj->otyp].oc_name_known = save_ocknown;
1302 objects[obj->otyp].oc_uname = save_ocuname;
1303 *obj = save_obj; /* restore object's core settings */
1304 if (!obj->oartifact && save_oname)
1305 ONAME(obj) = save_oname;
1307 return buf;
1310 /* xname,doname,&c with long results reformatted to omit some stuff */
1311 char *
1312 short_oname(obj, func, altfunc, lenlimit)
1313 struct obj *obj;
1314 char *FDECL((*func), (OBJ_P)), /* main formatting routine */
1315 *FDECL((*altfunc), (OBJ_P)); /* alternate for shortest result */
1316 unsigned lenlimit;
1318 struct obj save_obj;
1319 char unamebuf[12], onamebuf[12], *save_oname, *save_uname, *outbuf;
1321 outbuf = (*func)(obj);
1322 if ((unsigned) strlen(outbuf) <= lenlimit)
1323 return outbuf;
1325 /* shorten called string to fairly small amount */
1326 save_uname = objects[obj->otyp].oc_uname;
1327 if (save_uname && strlen(save_uname) >= sizeof unamebuf) {
1328 (void) strncpy(unamebuf, save_uname, sizeof unamebuf - 4);
1329 Strcpy(unamebuf + sizeof unamebuf - 4, "...");
1330 objects[obj->otyp].oc_uname = unamebuf;
1331 releaseobuf(outbuf);
1332 outbuf = (*func)(obj);
1333 objects[obj->otyp].oc_uname = save_uname; /* restore called string */
1334 if ((unsigned) strlen(outbuf) <= lenlimit)
1335 return outbuf;
1338 /* shorten named string to fairly small amount */
1339 save_oname = has_oname(obj) ? ONAME(obj) : 0;
1340 if (save_oname && strlen(save_oname) >= sizeof onamebuf) {
1341 (void) strncpy(onamebuf, save_oname, sizeof onamebuf - 4);
1342 Strcpy(onamebuf + sizeof onamebuf - 4, "...");
1343 ONAME(obj) = onamebuf;
1344 releaseobuf(outbuf);
1345 outbuf = (*func)(obj);
1346 ONAME(obj) = save_oname; /* restore named string */
1347 if ((unsigned) strlen(outbuf) <= lenlimit)
1348 return outbuf;
1351 /* shorten both called and named strings;
1352 unamebuf and onamebuf have both already been populated */
1353 if (save_uname && strlen(save_uname) >= sizeof unamebuf && save_oname
1354 && strlen(save_oname) >= sizeof onamebuf) {
1355 objects[obj->otyp].oc_uname = unamebuf;
1356 ONAME(obj) = onamebuf;
1357 releaseobuf(outbuf);
1358 outbuf = (*func)(obj);
1359 if ((unsigned) strlen(outbuf) <= lenlimit) {
1360 objects[obj->otyp].oc_uname = save_uname;
1361 ONAME(obj) = save_oname;
1362 return outbuf;
1366 /* still long; strip several name-lengthening attributes;
1367 called and named strings are still in truncated form */
1368 save_obj = *obj;
1369 obj->bknown = obj->rknown = obj->greased = 0;
1370 obj->oeroded = obj->oeroded2 = 0;
1371 releaseobuf(outbuf);
1372 outbuf = (*func)(obj);
1373 if (altfunc && (unsigned) strlen(outbuf) > lenlimit) {
1374 /* still long; use the alternate function (usually one of
1375 the jackets around minimal_xname()) */
1376 releaseobuf(outbuf);
1377 outbuf = (*altfunc)(obj);
1379 /* restore the object */
1380 *obj = save_obj;
1381 if (save_oname)
1382 ONAME(obj) = save_oname;
1383 if (save_uname)
1384 objects[obj->otyp].oc_uname = save_uname;
1386 /* use whatever we've got, whether it's too long or not */
1387 return outbuf;
1391 * Used if only one of a collection of objects is named (e.g. in eat.c).
1393 const char *
1394 singular(otmp, func)
1395 register struct obj *otmp;
1396 char *FDECL((*func), (OBJ_P));
1398 long savequan;
1399 char *nam;
1401 /* using xname for corpses does not give the monster type */
1402 if (otmp->otyp == CORPSE && func == xname)
1403 func = cxname;
1405 savequan = otmp->quan;
1406 otmp->quan = 1L;
1407 nam = (*func)(otmp);
1408 otmp->quan = savequan;
1409 return nam;
1412 char *
1413 an(str)
1414 register const char *str;
1416 char *buf = nextobuf();
1418 buf[0] = '\0';
1420 if (strncmpi(str, "the ", 4) && strcmp(str, "molten lava")
1421 && strcmp(str, "iron bars") && strcmp(str, "ice")) {
1422 if (index(vowels, *str) && strncmp(str, "one-", 4)
1423 && strncmp(str, "useful", 6) && strncmp(str, "unicorn", 7)
1424 && strncmp(str, "uranium", 7) && strncmp(str, "eucalyptus", 10))
1425 Strcpy(buf, "an ");
1426 else
1427 Strcpy(buf, "a ");
1430 Strcat(buf, str);
1431 return buf;
1434 char *
1435 An(str)
1436 const char *str;
1438 char *tmp = an(str);
1440 *tmp = highc(*tmp);
1441 return tmp;
1445 * Prepend "the" if necessary; assumes str is a subject derived from xname.
1446 * Use type_is_pname() for monster names, not the(). the() is idempotent.
1448 char *
1449 the(str)
1450 const char *str;
1452 char *buf = nextobuf();
1453 boolean insert_the = FALSE;
1455 if (!strncmpi(str, "the ", 4)) {
1456 buf[0] = lowc(*str);
1457 Strcpy(&buf[1], str + 1);
1458 return buf;
1459 } else if (*str < 'A' || *str > 'Z') {
1460 /* not a proper name, needs an article */
1461 insert_the = TRUE;
1462 } else {
1463 /* Probably a proper name, might not need an article */
1464 register char *tmp, *named, *called;
1465 int l;
1467 /* some objects have capitalized adjectives in their names */
1468 if (((tmp = rindex(str, ' ')) != 0 || (tmp = rindex(str, '-')) != 0)
1469 && (tmp[1] < 'A' || tmp[1] > 'Z')) {
1470 insert_the = TRUE;
1471 } else if (tmp && index(str, ' ') < tmp) { /* has spaces */
1472 /* it needs an article if the name contains "of" */
1473 tmp = strstri(str, " of ");
1474 named = strstri(str, " named ");
1475 called = strstri(str, " called ");
1476 if (called && (!named || called < named))
1477 named = called;
1479 if (tmp && (!named || tmp < named)) /* found an "of" */
1480 insert_the = TRUE;
1481 /* stupid special case: lacks "of" but needs "the" */
1482 else if (!named && (l = strlen(str)) >= 31
1483 && !strcmp(&str[l - 31],
1484 "Platinum Yendorian Express Card"))
1485 insert_the = TRUE;
1488 if (insert_the)
1489 Strcpy(buf, "the ");
1490 else
1491 buf[0] = '\0';
1492 Strcat(buf, str);
1494 return buf;
1497 char *
1498 The(str)
1499 const char *str;
1501 char *tmp = the(str);
1503 *tmp = highc(*tmp);
1504 return tmp;
1507 /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
1508 char *
1509 aobjnam(otmp, verb)
1510 struct obj *otmp;
1511 const char *verb;
1513 char prefix[PREFIX];
1514 char *bp = cxname(otmp);
1516 if (otmp->quan != 1L) {
1517 Sprintf(prefix, "%ld ", otmp->quan);
1518 bp = strprepend(bp, prefix);
1520 if (verb) {
1521 Strcat(bp, " ");
1522 Strcat(bp, otense(otmp, verb));
1524 return bp;
1527 /* combine yname and aobjnam eg "your count cxname(otmp)" */
1528 char *
1529 yobjnam(obj, verb)
1530 struct obj *obj;
1531 const char *verb;
1533 char *s = aobjnam(obj, verb);
1535 /* leave off "your" for most of your artifacts, but prepend
1536 * "your" for unique objects and "foo of bar" quest artifacts */
1537 if (!carried(obj) || !obj_is_pname(obj)
1538 || obj->oartifact >= ART_ORB_OF_DETECTION) {
1539 char *outbuf = shk_your(nextobuf(), obj);
1540 int space_left = BUFSZ - 1 - strlen(outbuf);
1542 s = strncat(outbuf, s, space_left);
1544 return s;
1547 /* combine Yname2 and aobjnam eg "Your count cxname(otmp)" */
1548 char *
1549 Yobjnam2(obj, verb)
1550 struct obj *obj;
1551 const char *verb;
1553 register char *s = yobjnam(obj, verb);
1555 *s = highc(*s);
1556 return s;
1559 /* like aobjnam, but prepend "The", not count, and use xname */
1560 char *
1561 Tobjnam(otmp, verb)
1562 struct obj *otmp;
1563 const char *verb;
1565 char *bp = The(xname(otmp));
1567 if (verb) {
1568 Strcat(bp, " ");
1569 Strcat(bp, otense(otmp, verb));
1571 return bp;
1574 /* capitalized variant of doname() */
1575 char *
1576 Doname2(obj)
1577 struct obj *obj;
1579 char *s = doname(obj);
1581 *s = highc(*s);
1582 return s;
1585 /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
1586 char *
1587 yname(obj)
1588 struct obj *obj;
1590 char *s = cxname(obj);
1592 /* leave off "your" for most of your artifacts, but prepend
1593 * "your" for unique objects and "foo of bar" quest artifacts */
1594 if (!carried(obj) || !obj_is_pname(obj)
1595 || obj->oartifact >= ART_ORB_OF_DETECTION) {
1596 char *outbuf = shk_your(nextobuf(), obj);
1597 int space_left = BUFSZ - 1 - strlen(outbuf);
1599 s = strncat(outbuf, s, space_left);
1602 return s;
1605 /* capitalized variant of yname() */
1606 char *
1607 Yname2(obj)
1608 struct obj *obj;
1610 char *s = yname(obj);
1612 *s = highc(*s);
1613 return s;
1616 /* returns "your minimal_xname(obj)"
1617 * or "Foobar's minimal_xname(obj)"
1618 * or "the minimal_xname(obj)"
1620 char *
1621 ysimple_name(obj)
1622 struct obj *obj;
1624 char *outbuf = nextobuf();
1625 char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */
1626 int space_left = BUFSZ - 1 - strlen(s);
1628 return strncat(s, minimal_xname(obj), space_left);
1631 /* capitalized variant of ysimple_name() */
1632 char *
1633 Ysimple_name2(obj)
1634 struct obj *obj;
1636 char *s = ysimple_name(obj);
1638 *s = highc(*s);
1639 return s;
1642 /* "scroll" or "scrolls" */
1643 char *
1644 simpleonames(obj)
1645 struct obj *obj;
1647 char *simpleoname = minimal_xname(obj);
1649 if (obj->quan != 1L)
1650 simpleoname = makeplural(simpleoname);
1651 return simpleoname;
1654 /* "a scroll" or "scrolls"; "a silver bell" or "the Bell of Opening" */
1655 char *
1656 ansimpleoname(obj)
1657 struct obj *obj;
1659 char *simpleoname = simpleonames(obj);
1660 int otyp = obj->otyp;
1662 /* prefix with "the" if a unique item, or a fake one imitating same,
1663 has been formatted with its actual name (we let typename() handle
1664 any `known' and `dknown' checking necessary) */
1665 if (otyp == FAKE_AMULET_OF_YENDOR)
1666 otyp = AMULET_OF_YENDOR;
1667 if (objects[otyp].oc_unique
1668 && !strcmp(simpleoname, OBJ_NAME(objects[otyp])))
1669 return the(simpleoname);
1671 /* simpleoname is singular if quan==1, plural otherwise */
1672 if (obj->quan == 1L)
1673 simpleoname = an(simpleoname);
1674 return simpleoname;
1677 /* "the scroll" or "the scrolls" */
1678 char *
1679 thesimpleoname(obj)
1680 struct obj *obj;
1682 char *simpleoname = simpleonames(obj);
1684 return the(simpleoname);
1687 /* artifact's name without any object type or known/dknown/&c feedback */
1688 char *
1689 bare_artifactname(obj)
1690 struct obj *obj;
1692 char *outbuf;
1694 if (obj->oartifact) {
1695 outbuf = nextobuf();
1696 Strcpy(outbuf, artiname(obj->oartifact));
1697 if (!strncmp(outbuf, "The ", 4))
1698 outbuf[0] = lowc(outbuf[0]);
1699 } else {
1700 outbuf = xname(obj);
1702 return outbuf;
1705 static const char *wrp[] = {
1706 "wand", "ring", "potion", "scroll", "gem",
1707 "amulet", "spellbook", "spell book",
1708 /* for non-specific wishes */
1709 "weapon", "armor", "tool", "food", "comestible",
1711 static const char wrpsym[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
1712 SCROLL_CLASS, GEM_CLASS, AMULET_CLASS,
1713 SPBOOK_CLASS, SPBOOK_CLASS, WEAPON_CLASS,
1714 ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
1715 FOOD_CLASS };
1717 /* return form of the verb (input plural) if xname(otmp) were the subject */
1718 char *
1719 otense(otmp, verb)
1720 struct obj *otmp;
1721 const char *verb;
1723 char *buf;
1726 * verb is given in plural (without trailing s). Return as input
1727 * if the result of xname(otmp) would be plural. Don't bother
1728 * recomputing xname(otmp) at this time.
1730 if (!is_plural(otmp))
1731 return vtense((char *) 0, verb);
1733 buf = nextobuf();
1734 Strcpy(buf, verb);
1735 return buf;
1738 /* various singular words that vtense would otherwise categorize as plural;
1739 also used by makesingular() to catch some special cases */
1740 static const char *const special_subjs[] = {
1741 "erinys", "manes", /* this one is ambiguous */
1742 "Cyclops", "Hippocrates", "Pelias", "aklys",
1743 "amnesia", "detect monsters", "paralysis", "shape changers",
1744 "nemesis", 0
1745 /* note: "detect monsters" and "shape changers" are normally
1746 caught via "<something>(s) of <whatever>", but they can be
1747 wished for using the shorter form, so we include them here
1748 to accommodate usage by makesingular during wishing */
1751 /* return form of the verb (input plural) for present tense 3rd person subj */
1752 char *
1753 vtense(subj, verb)
1754 register const char *subj;
1755 register const char *verb;
1757 char *buf = nextobuf(), *bspot;
1758 int len, ltmp;
1759 const char *sp, *spot;
1760 const char *const *spec;
1763 * verb is given in plural (without trailing s). Return as input
1764 * if subj appears to be plural. Add special cases as necessary.
1765 * Many hard cases can already be handled by using otense() instead.
1766 * If this gets much bigger, consider decomposing makeplural.
1767 * Note: monster names are not expected here (except before corpse).
1769 * Special case: allow null sobj to get the singular 3rd person
1770 * present tense form so we don't duplicate this code elsewhere.
1772 if (subj) {
1773 if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3))
1774 goto sing;
1775 spot = (const char *) 0;
1776 for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) {
1777 if (!strncmpi(sp, " of ", 4) || !strncmpi(sp, " from ", 6)
1778 || !strncmpi(sp, " called ", 8) || !strncmpi(sp, " named ", 7)
1779 || !strncmpi(sp, " labeled ", 9)) {
1780 if (sp != subj)
1781 spot = sp - 1;
1782 break;
1785 len = (int) strlen(subj);
1786 if (!spot)
1787 spot = subj + len - 1;
1790 * plural: anything that ends in 's', but not '*us' or '*ss'.
1791 * Guess at a few other special cases that makeplural creates.
1793 if ((lowc(*spot) == 's' && spot != subj
1794 && !index("us", lowc(*(spot - 1))))
1795 || !BSTRNCMPI(subj, spot - 3, "eeth", 4)
1796 || !BSTRNCMPI(subj, spot - 3, "feet", 4)
1797 || !BSTRNCMPI(subj, spot - 1, "ia", 2)
1798 || !BSTRNCMPI(subj, spot - 1, "ae", 2)) {
1799 /* check for special cases to avoid false matches */
1800 len = (int) (spot - subj) + 1;
1801 for (spec = special_subjs; *spec; spec++) {
1802 ltmp = strlen(*spec);
1803 if (len == ltmp && !strncmpi(*spec, subj, len))
1804 goto sing;
1805 /* also check for <prefix><space><special_subj>
1806 to catch things like "the invisible erinys" */
1807 if (len > ltmp && *(spot - ltmp) == ' '
1808 && !strncmpi(*spec, spot - ltmp + 1, ltmp))
1809 goto sing;
1812 return strcpy(buf, verb);
1815 * 3rd person plural doesn't end in telltale 's';
1816 * 2nd person singular behaves as if plural.
1818 if (!strcmpi(subj, "they") || !strcmpi(subj, "you"))
1819 return strcpy(buf, verb);
1822 sing:
1823 Strcpy(buf, verb);
1824 len = (int) strlen(buf);
1825 bspot = buf + len - 1;
1827 if (!strcmpi(buf, "are")) {
1828 Strcasecpy(buf, "is");
1829 } else if (!strcmpi(buf, "have")) {
1830 Strcasecpy(bspot - 1, "s");
1831 } else if (index("zxs", lowc(*bspot))
1832 || (len >= 2 && lowc(*bspot) == 'h'
1833 && index("cs", lowc(*(bspot - 1))))
1834 || (len == 2 && lowc(*bspot) == 'o')) {
1835 /* Ends in z, x, s, ch, sh; add an "es" */
1836 Strcasecpy(bspot + 1, "es");
1837 } else if (lowc(*bspot) == 'y' && !index(vowels, lowc(*(bspot - 1)))) {
1838 /* like "y" case in makeplural */
1839 Strcasecpy(bspot, "ies");
1840 } else {
1841 Strcasecpy(bspot + 1, "s");
1844 return buf;
1847 struct sing_plur {
1848 const char *sing, *plur;
1851 /* word pairs that don't fit into formula-based transformations;
1852 also some suffices which have very few--often one--matches or
1853 which aren't systematically reversible (knives, staves) */
1854 static struct sing_plur one_off[] = {
1855 { "child",
1856 "children" }, /* (for wise guys who give their food funny names) */
1857 { "cubus", "cubi" }, /* in-/suc-cubus */
1858 { "culus", "culi" }, /* homunculus */
1859 { "djinni", "djinn" },
1860 { "erinys", "erinyes" },
1861 { "foot", "feet" },
1862 { "fungus", "fungi" },
1863 { "knife", "knives" },
1864 { "labrum", "labra" }, /* candelabrum */
1865 { "louse", "lice" },
1866 { "mouse", "mice" },
1867 { "mumak", "mumakil" },
1868 { "nemesis", "nemeses" },
1869 { "rtex", "rtices" }, /* vortex */
1870 { "tooth", "teeth" },
1871 { "staff", "staves" },
1872 { 0, 0 }
1875 static const char *const as_is[] = {
1876 /* makesingular() leaves these plural due to how they're used */
1877 "boots", "shoes", "gloves", "lenses", "scales",
1878 "eyes", "gauntlets", "iron bars",
1879 /* both singular and plural are spelled the same */
1880 "deer", "fish", "tuna", "yaki", "-hai",
1881 "krill", "manes", "ninja", "sheep", "ronin",
1882 "roshi", "shito", "tengu", "ki-rin", "Nazgul",
1883 "gunyoki", "piranha", "samurai", "shuriken", 0,
1884 /* Note: "fish" and "piranha" are collective plurals, suitable
1885 for "wiped out all <foo>". For "3 <foo>", they should be
1886 "fishes" and "piranhas" instead. We settle for collective
1887 variant instead of attempting to support both. */
1890 /* singularize/pluralize decisions common to both makesingular & makeplural
1892 STATIC_OVL boolean
1893 singplur_lookup(basestr, endstring, to_plural, alt_as_is)
1894 char *basestr, *endstring; /* base string, pointer to eos(string) */
1895 boolean to_plural; /* true => makeplural, false => makesingular */
1896 const char *const *alt_as_is; /* another set like as_is[] */
1898 const struct sing_plur *sp;
1899 const char *same, *other, *const *as;
1900 int al;
1902 for (as = as_is; *as; ++as) {
1903 al = (int) strlen(*as);
1904 if (!BSTRCMPI(basestr, endstring - al, *as))
1905 return TRUE;
1907 if (alt_as_is) {
1908 for (as = alt_as_is; *as; ++as) {
1909 al = (int) strlen(*as);
1910 if (!BSTRCMPI(basestr, endstring - al, *as))
1911 return TRUE;
1915 /* avoid false hit on one_off[].plur == "lice";
1916 if more of these turn up, one_off[] entries will need to flagged
1917 as to which are whole words and which are matchable as suffices
1918 then matching in the loop below will end up becoming more complex */
1919 if (!strcmpi(basestr, "slice")) {
1920 if (to_plural)
1921 (void) strkitten(basestr, 's');
1922 return TRUE;
1924 for (sp = one_off; sp->sing; sp++) {
1925 /* check whether endstring already matches */
1926 same = to_plural ? sp->plur : sp->sing;
1927 al = (int) strlen(same);
1928 if (!BSTRCMPI(basestr, endstring - al, same))
1929 return TRUE; /* use as-is */
1930 /* check whether it matches the inverse; if so, transform it */
1931 other = to_plural ? sp->sing : sp->plur;
1932 al = (int) strlen(other);
1933 if (!BSTRCMPI(basestr, endstring - al, other)) {
1934 Strcasecpy(endstring - al, same);
1935 return TRUE; /* one_off[] transformation */
1938 return FALSE;
1941 /* searches for common compounds, ex. lump of royal jelly */
1942 STATIC_OVL char *
1943 singplur_compound(str)
1944 char *str;
1946 /* if new entries are added, be sure to keep compound_start[] in sync */
1947 static const char *const compounds[] =
1949 " of ", " labeled ", " called ",
1950 " named ", " above", /* lurkers above */
1951 " versus ", " from ", " in ",
1952 " on ", " a la ", " with", /* " with "? */
1953 " de ", " d'", " du ",
1954 "-in-", "-at-", 0
1955 }, /* list of first characters for all compounds[] entries */
1956 compound_start[] = " -";
1958 const char *const *cmpd;
1959 char *p;
1961 for (p = str; *p; ++p) {
1962 /* substring starting at p can only match if *p is found
1963 within compound_start[] */
1964 if (!index(compound_start, *p))
1965 continue;
1967 /* check current substring against all words in the compound[] list */
1968 for (cmpd = compounds; *cmpd; ++cmpd)
1969 if (!strncmpi(p, *cmpd, (int) strlen(*cmpd)))
1970 return p;
1972 /* wasn't recognized as a compound phrase */
1973 return 0;
1976 /* Plural routine; chiefly used for user-defined fruits. We have to try to
1977 * account for everything reasonable the player has; something unreasonable
1978 * can still break the code. However, it's still a lot more accurate than
1979 * "just add an s at the end", which Rogue uses...
1981 * Also used for plural monster names ("Wiped out all homunculi." or the
1982 * vanquished monsters list) and body parts. A lot of unique monsters have
1983 * names which get mangled by makeplural and/or makesingular. They're not
1984 * genocidable, and vanquished-mon handling does its own special casing
1985 * (for uniques who've been revived and re-killed), so we don't bother
1986 * trying to get those right here.
1988 * Also misused by muse.c to convert 1st person present verbs to 2nd person.
1989 * 3.6.0: made case-insensitive.
1991 char *
1992 makeplural(oldstr)
1993 const char *oldstr;
1995 register char *spot;
1996 char lo_c, *str = nextobuf();
1997 const char *excess = (char *) 0;
1998 int len;
2000 if (oldstr)
2001 while (*oldstr == ' ')
2002 oldstr++;
2003 if (!oldstr || !*oldstr) {
2004 impossible("plural of null?");
2005 Strcpy(str, "s");
2006 return str;
2008 Strcpy(str, oldstr);
2011 * Skip changing "pair of" to "pairs of". According to Webster, usual
2012 * English usage is use pairs for humans, e.g. 3 pairs of dancers,
2013 * and pair for objects and non-humans, e.g. 3 pair of boots. We don't
2014 * refer to pairs of humans in this game so just skip to the bottom.
2016 if (!strncmpi(str, "pair of ", 8))
2017 goto bottom;
2019 /* look for "foo of bar" so that we can focus on "foo" */
2020 if ((spot = singplur_compound(str)) != 0) {
2021 excess = oldstr + (int) (spot - str);
2022 *spot = '\0';
2023 } else
2024 spot = eos(str);
2026 spot--;
2027 while (spot > str && *spot == ' ')
2028 spot--; /* Strip blanks from end */
2029 *(spot + 1) = 0;
2030 /* Now spot is the last character of the string */
2032 len = strlen(str);
2034 /* Single letters */
2035 if (len == 1 || !letter(*spot)) {
2036 Strcpy(spot + 1, "'s");
2037 goto bottom;
2040 /* dispense with some words which don't need pluralization */
2042 static const char *const already_plural[] = {
2043 "ae", /* algae, larvae, &c */
2044 "men", /* also catches women, watchmen */
2045 "matzot", 0,
2048 /* spot+1: synch up with makesingular's usage */
2049 if (singplur_lookup(str, spot + 1, TRUE, already_plural))
2050 goto bottom;
2052 /* more of same, but not suitable for blanket loop checking */
2053 if ((len == 2 && !strcmpi(str, "ya"))
2054 || (len >= 3 && !strcmpi(spot - 2, " ya")))
2055 goto bottom;
2058 /* man/men ("Wiped out all cavemen.") */
2059 if (len >= 3 && !strcmpi(spot - 2, "man")
2060 /* exclude shamans and humans */
2061 && (len < 6 || strcmpi(spot - 5, "shaman"))
2062 && (len < 5 || strcmpi(spot - 4, "human"))) {
2063 Strcasecpy(spot - 1, "en");
2064 goto bottom;
2066 if (lowc(*spot) == 'f') { /* (staff handled via one_off[]) */
2067 lo_c = lowc(*(spot - 1));
2068 if (len >= 3 && !strcmpi(spot - 2, "erf")) {
2069 /* avoid "nerf" -> "nerves", "serf" -> "serves" */
2070 ; /* fall through to default (append 's') */
2071 } else if (index("lr", lo_c) || index(vowels, lo_c)) {
2072 /* [aeioulr]f to [aeioulr]ves */
2073 Strcasecpy(spot, "ves");
2074 goto bottom;
2077 /* ium/ia (mycelia, baluchitheria) */
2078 if (len >= 3 && !strcmpi(spot - 2, "ium")) {
2079 Strcasecpy(spot - 2, "ia");
2080 goto bottom;
2082 /* algae, larvae, hyphae (another fungus part) */
2083 if ((len >= 4 && !strcmpi(spot - 3, "alga"))
2084 || (len >= 5
2085 && (!strcmpi(spot - 4, "hypha") || !strcmpi(spot - 4, "larva")))
2086 || (len >= 6 && !strcmpi(spot - 5, "amoeba"))
2087 || (len >= 8 && (!strcmpi(spot - 7, "vertebra")))) {
2088 /* a to ae */
2089 Strcasecpy(spot + 1, "e");
2090 goto bottom;
2092 /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */
2093 if (len > 3 && !strcmpi(spot - 1, "us")
2094 && !((len >= 5 && !strcmpi(spot - 4, "lotus"))
2095 || (len >= 6 && !strcmpi(spot - 5, "wumpus")))) {
2096 Strcasecpy(spot - 1, "i");
2097 goto bottom;
2099 /* sis/ses (nemesis) */
2100 if (len >= 3 && !strcmpi(spot - 2, "sis")) {
2101 Strcasecpy(spot - 1, "es");
2102 goto bottom;
2104 /* matzoh/matzot, possible food name */
2105 if (len >= 6
2106 && (!strcmpi(spot - 5, "matzoh") || !strcmpi(spot - 5, "matzah"))) {
2107 Strcasecpy(spot - 1, "ot"); /* oh/ah -> ot */
2108 goto bottom;
2110 if (len >= 5
2111 && (!strcmpi(spot - 4, "matzo") || !strcmpi(spot - 4, "matza"))) {
2112 Strcasecpy(spot, "ot"); /* o/a -> ot */
2113 goto bottom;
2116 /* note: -eau/-eaux (gateau, bordeau...) */
2117 /* note: ox/oxen, VAX/VAXen, goose/geese */
2119 lo_c = lowc(*spot);
2121 /* Ends in z, x, s, ch, sh; add an "es" */
2122 if (index("zxs", lo_c)
2123 || (len >= 2 && lo_c == 'h' && index("cs", lowc(*(spot - 1))))
2124 /* Kludge to get "tomatoes" and "potatoes" right */
2125 || (len >= 4 && !strcmpi(spot - 2, "ato"))
2126 || (len >= 5 && !strcmpi(spot - 4, "dingo"))) {
2127 Strcasecpy(spot + 1, "es"); /* append es */
2128 goto bottom;
2130 /* Ends in y preceded by consonant (note: also "qu") change to "ies" */
2131 if (lo_c == 'y' && !index(vowels, lowc(*(spot - 1)))) {
2132 Strcasecpy(spot, "ies"); /* y -> ies */
2133 goto bottom;
2135 /* Default: append an 's' */
2136 Strcasecpy(spot + 1, "s");
2138 bottom:
2139 if (excess)
2140 Strcat(str, excess);
2141 return str;
2145 * Singularize a string the user typed in; this helps reduce the complexity
2146 * of readobjnam, and is also used in pager.c to singularize the string
2147 * for which help is sought.
2149 * "Manes" is ambiguous: monster type (keep s), or horse body part (drop s)?
2150 * Its inclusion in as_is[]/special_subj[] makes it get treated as the former.
2152 * A lot of unique monsters have names ending in s; plural, or singular
2153 * from plural, doesn't make much sense for them so we don't bother trying.
2154 * 3.6.0: made case-insensitive.
2156 char *
2157 makesingular(oldstr)
2158 const char *oldstr;
2160 register char *p, *bp;
2161 const char *excess = 0;
2162 char *str = nextobuf();
2164 if (oldstr)
2165 while (*oldstr == ' ')
2166 oldstr++;
2167 if (!oldstr || !*oldstr) {
2168 impossible("singular of null?");
2169 str[0] = '\0';
2170 return str;
2173 bp = strcpy(str, oldstr);
2175 /* check for "foo of bar" so that we can focus on "foo" */
2176 if ((p = singplur_compound(bp)) != 0) {
2177 excess = oldstr + (int) (p - bp);
2178 *p = '\0';
2179 } else
2180 p = eos(bp);
2182 /* dispense with some words which don't need singularization */
2183 if (singplur_lookup(bp, p, FALSE, special_subjs))
2184 goto bottom;
2186 /* remove -s or -es (boxes) or -ies (rubies) */
2187 if (p >= bp + 1 && lowc(p[-1]) == 's') {
2188 if (p >= bp + 2 && lowc(p[-2]) == 'e') {
2189 if (p >= bp + 3 && lowc(p[-3]) == 'i') { /* "ies" */
2190 if (!BSTRCMPI(bp, p - 7, "cookies")
2191 || !BSTRCMPI(bp, p - 4, "pies")
2192 || !BSTRCMPI(bp, p - 5, "mbies") /* zombie */
2193 || !BSTRCMPI(bp, p - 5, "yries")) /* valkyrie */
2194 goto mins;
2195 Strcasecpy(p - 3, "y"); /* ies -> y */
2196 goto bottom;
2198 /* wolves, but f to ves isn't fully reversible */
2199 if (p - 4 >= bp && (index("lr", lowc(*(p - 4)))
2200 || index(vowels, lowc(*(p - 4))))
2201 && !BSTRCMPI(bp, p - 3, "ves")) {
2202 if (!BSTRCMPI(bp, p - 6, "cloves")
2203 || !BSTRCMPI(bp, p - 6, "nerves"))
2204 goto mins;
2205 Strcasecpy(p - 3, "f"); /* ves -> f */
2206 goto bottom;
2208 /* note: nurses, axes but boxes, wumpuses */
2209 if (!BSTRCMPI(bp, p - 4, "eses")
2210 || !BSTRCMPI(bp, p - 4, "oxes") /* boxes, foxes */
2211 || !BSTRCMPI(bp, p - 4, "nxes") /* lynxes */
2212 || !BSTRCMPI(bp, p - 4, "ches")
2213 || !BSTRCMPI(bp, p - 4, "uses") /* lotuses */
2214 || !BSTRCMPI(bp, p - 4, "sses") /* priestesses */
2215 || !BSTRCMPI(bp, p - 5, "atoes") /* tomatoes */
2216 || !BSTRCMPI(bp, p - 7, "dingoes")
2217 || !BSTRCMPI(bp, p - 7, "Aleaxes")) {
2218 *(p - 2) = '\0'; /* drop es */
2219 goto bottom;
2220 } /* else fall through to mins */
2222 /* ends in 's' but not 'es' */
2223 } else if (!BSTRCMPI(bp, p - 2, "us")) { /* lotus, fungus... */
2224 if (BSTRCMPI(bp, p - 6, "tengus") /* but not these... */
2225 && BSTRCMPI(bp, p - 7, "hezrous"))
2226 goto bottom;
2227 } else if (!BSTRCMPI(bp, p - 2, "ss")
2228 || !BSTRCMPI(bp, p - 5, " lens")
2229 || (p - 4 == bp && !strcmpi(p - 4, "lens"))) {
2230 goto bottom;
2232 mins:
2233 *(p - 1) = '\0'; /* drop s */
2235 } else { /* input doesn't end in 's' */
2237 if (!BSTRCMPI(bp, p - 3, "men")) {
2238 Strcasecpy(p - 2, "an");
2239 goto bottom;
2241 /* matzot -> matzo, algae -> alga */
2242 if (!BSTRCMPI(bp, p - 6, "matzot") || !BSTRCMPI(bp, p - 2, "ae")) {
2243 *(p - 1) = '\0'; /* drop t/e */
2244 goto bottom;
2246 /* balactheria -> balactherium */
2247 if (p - 4 >= bp && !strcmpi(p - 2, "ia")
2248 && index("lr", lowc(*(p - 3))) && lowc(*(p - 4)) == 'e') {
2249 Strcasecpy(p - 1, "um"); /* a -> um */
2252 /* here we cannot find the plural suffix */
2255 bottom:
2256 /* if we stripped off a suffix (" of bar" from "foo of bar"),
2257 put it back now [strcat() isn't actually 100% safe here...] */
2258 if (excess)
2259 Strcat(bp, excess);
2261 return bp;
2264 /* compare user string against object name string using fuzzy matching */
2265 STATIC_OVL boolean
2266 wishymatch(u_str, o_str, retry_inverted)
2267 const char *u_str; /* from user, so might be variant spelling */
2268 const char *o_str; /* from objects[], so is in canonical form */
2269 boolean retry_inverted; /* optional extra "of" handling */
2271 static NEARDATA const char detect_SP[] = "detect ",
2272 SP_detection[] = " detection";
2273 char *p, buf[BUFSZ];
2275 /* ignore spaces & hyphens and upper/lower case when comparing */
2276 if (fuzzymatch(u_str, o_str, " -", TRUE))
2277 return TRUE;
2279 if (retry_inverted) {
2280 const char *u_of, *o_of;
2282 /* when just one of the strings is in the form "foo of bar",
2283 convert it into "bar foo" and perform another comparison */
2284 u_of = strstri(u_str, " of ");
2285 o_of = strstri(o_str, " of ");
2286 if (u_of && !o_of) {
2287 Strcpy(buf, u_of + 4);
2288 p = eos(strcat(buf, " "));
2289 while (u_str < u_of)
2290 *p++ = *u_str++;
2291 *p = '\0';
2292 return fuzzymatch(buf, o_str, " -", TRUE);
2293 } else if (o_of && !u_of) {
2294 Strcpy(buf, o_of + 4);
2295 p = eos(strcat(buf, " "));
2296 while (o_str < o_of)
2297 *p++ = *o_str++;
2298 *p = '\0';
2299 return fuzzymatch(u_str, buf, " -", TRUE);
2303 /* [note: if something like "elven speed boots" ever gets added, these
2304 special cases should be changed to call wishymatch() recursively in
2305 order to get the "of" inversion handling] */
2306 if (!strncmp(o_str, "dwarvish ", 9)) {
2307 if (!strncmpi(u_str, "dwarven ", 8))
2308 return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE);
2309 } else if (!strncmp(o_str, "elven ", 6)) {
2310 if (!strncmpi(u_str, "elvish ", 7))
2311 return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE);
2312 else if (!strncmpi(u_str, "elfin ", 6))
2313 return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE);
2314 } else if (!strncmp(o_str, detect_SP, sizeof detect_SP - 1)) {
2315 /* check for "detect <foo>" vs "<foo> detection" */
2316 if ((p = strstri(u_str, SP_detection)) != 0
2317 && !*(p + sizeof SP_detection - 1)) {
2318 /* convert "<foo> detection" into "detect <foo>" */
2319 *p = '\0';
2320 Strcat(strcpy(buf, detect_SP), u_str);
2321 /* "detect monster" -> "detect monsters" */
2322 if (!strcmpi(u_str, "monster"))
2323 Strcat(buf, "s");
2324 *p = ' ';
2325 return fuzzymatch(buf, o_str, " -", TRUE);
2327 } else if (strstri(o_str, SP_detection)) {
2328 /* and the inverse, "<foo> detection" vs "detect <foo>" */
2329 if (!strncmpi(u_str, detect_SP, sizeof detect_SP - 1)) {
2330 /* convert "detect <foo>s" into "<foo> detection" */
2331 p = makesingular(u_str + sizeof detect_SP - 1);
2332 Strcat(strcpy(buf, p), SP_detection);
2333 /* caller may be looping through objects[], so avoid
2334 churning through all the obufs */
2335 releaseobuf(p);
2336 return fuzzymatch(buf, o_str, " -", TRUE);
2338 } else if (strstri(o_str, "ability")) {
2339 /* when presented with "foo of bar", makesingular() used to
2340 singularize both foo & bar, but now only does so for foo */
2341 /* catch "{potion(s),ring} of {gain,restore,sustain} abilities" */
2342 if ((p = strstri(u_str, "abilities")) != 0
2343 && !*(p + sizeof "abilities" - 1)) {
2344 (void) strncpy(buf, u_str, (unsigned) (p - u_str));
2345 Strcpy(buf + (p - u_str), "ability");
2346 return fuzzymatch(buf, o_str, " -", TRUE);
2348 } else if (!strcmp(o_str, "aluminum")) {
2349 /* this special case doesn't really fit anywhere else... */
2350 /* (note that " wand" will have been stripped off by now) */
2351 if (!strcmpi(u_str, "aluminium"))
2352 return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE);
2355 return FALSE;
2358 struct o_range {
2359 const char *name, oclass;
2360 int f_o_range, l_o_range;
2363 /* wishable subranges of objects */
2364 STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
2365 { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS },
2366 { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP },
2367 { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE },
2368 { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY },
2369 { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION },
2370 { "hat", ARMOR_CLASS, FEDORA, DUNCE_CAP },
2371 { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
2372 { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
2373 { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
2374 { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS },
2375 { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES },
2376 { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
2377 { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT },
2378 { "dragon scales", ARMOR_CLASS, GRAY_DRAGON_SCALES,
2379 YELLOW_DRAGON_SCALES },
2380 { "dragon scale mail", ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL,
2381 YELLOW_DRAGON_SCALE_MAIL },
2382 { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA },
2383 { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM },
2384 { "gray stone", GEM_CLASS, LUCKSTONE, FLINT },
2385 { "grey stone", GEM_CLASS, LUCKSTONE, FLINT },
2388 /* alternate spellings; if the difference is only the presence or
2389 absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
2390 vs "pick-axe") then there is no need for inclusion in this list;
2391 likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */
2392 struct alt_spellings {
2393 const char *sp;
2394 int ob;
2395 } spellings[] = {
2396 { "pickax", PICK_AXE },
2397 { "whip", BULLWHIP },
2398 { "saber", SILVER_SABER },
2399 { "silver sabre", SILVER_SABER },
2400 { "smooth shield", SHIELD_OF_REFLECTION },
2401 { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
2402 { "grey dragon scales", GRAY_DRAGON_SCALES },
2403 { "iron ball", HEAVY_IRON_BALL },
2404 { "lantern", BRASS_LANTERN },
2405 { "mattock", DWARVISH_MATTOCK },
2406 { "amulet of poison resistance", AMULET_VERSUS_POISON },
2407 { "potion of sleep", POT_SLEEPING },
2408 { "stone", ROCK },
2409 { "camera", EXPENSIVE_CAMERA },
2410 { "tee shirt", T_SHIRT },
2411 { "can", TIN },
2412 { "can opener", TIN_OPENER },
2413 { "kelp", KELP_FROND },
2414 { "eucalyptus", EUCALYPTUS_LEAF },
2415 { "royal jelly", LUMP_OF_ROYAL_JELLY },
2416 { "lembas", LEMBAS_WAFER },
2417 { "marker", MAGIC_MARKER },
2418 { "hook", GRAPPLING_HOOK },
2419 { "grappling iron", GRAPPLING_HOOK },
2420 { "grapnel", GRAPPLING_HOOK },
2421 { "grapple", GRAPPLING_HOOK },
2422 { "protection from shape shifters", RIN_PROTECTION_FROM_SHAPE_CHAN },
2423 /* normally we wouldn't have to worry about unnecessary <space>, but
2424 " stone" will get stripped off, preventing a wishymatch; that actually
2425 lets "flint stone" be a match, so we also accept bogus "flintstone" */
2426 { "luck stone", LUCKSTONE },
2427 { "load stone", LOADSTONE },
2428 { "touch stone", TOUCHSTONE },
2429 { "flintstone", FLINT },
2430 { (const char *) 0, 0 },
2433 short
2434 rnd_otyp_by_wpnskill(skill)
2435 schar skill;
2437 int i, n = 0;
2438 short otyp = STRANGE_OBJECT;
2439 for (i = bases[WEAPON_CLASS];
2440 i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++)
2441 if (objects[i].oc_skill == skill) {
2442 n++;
2443 otyp = i;
2445 if (n > 0) {
2446 n = rn2(n);
2447 for (i = bases[WEAPON_CLASS];
2448 i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++)
2449 if (objects[i].oc_skill == skill)
2450 if (--n < 0)
2451 return i;
2453 return otyp;
2456 short
2457 rnd_otyp_by_namedesc(name, oclass)
2458 char *name;
2459 char oclass;
2461 int i = oclass ? bases[(int)oclass] : 1;
2462 int n = 0;
2463 short otyp = STRANGE_OBJECT;
2464 short validobjs[NUM_OBJECTS];
2465 register const char *zn;
2466 long maxprob = 0;
2468 if (!name) return STRANGE_OBJECT;
2470 memset((genericptr_t) validobjs, 0, sizeof(validobjs));
2472 while (i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)) {
2473 if ((zn = OBJ_NAME(objects[i])) != 0 && wishymatch(name, zn, TRUE)) {
2474 otyp = i;
2475 } else if ((zn = OBJ_DESCR(objects[i])) != 0 && wishymatch(name, zn, FALSE) &&
2476 /* don't match extra descriptions (w/o real name) */
2477 OBJ_NAME(objects[i])) {
2478 otyp = i;
2479 } else if ((zn = objects[i].oc_uname) != 0 && wishymatch(name, zn, FALSE)) {
2480 otyp = i;
2482 if (otyp != STRANGE_OBJECT) {
2483 validobjs[n++] = otyp;
2484 maxprob += (objects[otyp].oc_prob + 1);
2485 otyp = STRANGE_OBJECT;
2487 i++;
2490 if (n > 0 && maxprob) {
2491 long prob = rn2(maxprob);
2492 i = 0;
2493 while ((i < (n-1)) && (prob -= (objects[validobjs[i]].oc_prob + 1)) > 0)
2494 i++;
2495 return validobjs[i];
2497 return STRANGE_OBJECT;
2502 * Return something wished for. Specifying a null pointer for
2503 * the user request string results in a random object. Otherwise,
2504 * if asking explicitly for "nothing" (or "nil") return no_wish;
2505 * if not an object return &zeroobj; if an error (no matching object),
2506 * return null.
2508 struct obj *
2509 readobjnam(bp, no_wish)
2510 register char *bp;
2511 struct obj *no_wish;
2513 register char *p;
2514 register int i;
2515 register struct obj *otmp;
2516 int cnt, spe, spesgn, typ, very, rechrg;
2517 int blessed, uncursed, iscursed, ispoisoned, isgreased;
2518 int eroded, eroded2, erodeproof;
2519 int halfeaten, mntmp, contents;
2520 int islit, unlabeled, ishistoric, isdiluted, trapped;
2521 int tmp, tinv, tvariety;
2522 int wetness;
2523 struct fruit *f;
2524 int ftype = context.current_fruit;
2525 char fruitbuf[BUFSZ];
2526 /* Fruits may not mess up the ability to wish for real objects (since
2527 * you can leave a fruit in a bones file and it will be added to
2528 * another person's game), so they must be checked for last, after
2529 * stripping all the possible prefixes and seeing if there's a real
2530 * name in there. So we have to save the full original name. However,
2531 * it's still possible to do things like "uncursed burnt Alaska",
2532 * or worse yet, "2 burned 5 course meals", so we need to loop to
2533 * strip off the prefixes again, this time stripping only the ones
2534 * possible on food.
2535 * We could get even more detailed so as to allow food names with
2536 * prefixes that _are_ possible on food, so you could wish for
2537 * "2 3 alarm chilis". Currently this isn't allowed; options.c
2538 * automatically sticks 'candied' in front of such names.
2540 char oclass;
2541 char *un, *dn, *actualn, *origbp = bp;
2542 const char *name = 0;
2544 cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed =
2545 ispoisoned = isgreased = eroded = eroded2 = erodeproof = halfeaten =
2546 islit = unlabeled = ishistoric = isdiluted = trapped = 0;
2547 tvariety = RANDOM_TIN;
2548 mntmp = NON_PM;
2549 #define UNDEFINED 0
2550 #define EMPTY 1
2551 #define SPINACH 2
2552 contents = UNDEFINED;
2553 oclass = 0;
2554 actualn = dn = un = 0;
2555 wetness = 0;
2557 if (!bp)
2558 goto any;
2559 /* first, remove extra whitespace they may have typed */
2560 (void) mungspaces(bp);
2561 /* allow wishing for "nothing" to preserve wishless conduct...
2562 [now requires "wand of nothing" if that's what was really wanted] */
2563 if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil")
2564 || !strcmpi(bp, "none"))
2565 return no_wish;
2566 /* save the [nearly] unmodified choice string */
2567 Strcpy(fruitbuf, bp);
2569 for (;;) {
2570 register int l;
2572 if (!bp || !*bp)
2573 goto any;
2574 if (!strncmpi(bp, "an ", l = 3) || !strncmpi(bp, "a ", l = 2)) {
2575 cnt = 1;
2576 } else if (!strncmpi(bp, "the ", l = 4)) {
2577 ; /* just increment `bp' by `l' below */
2578 } else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
2579 cnt = atoi(bp);
2580 while (digit(*bp))
2581 bp++;
2582 while (*bp == ' ')
2583 bp++;
2584 l = 0;
2585 } else if (*bp == '+' || *bp == '-') {
2586 spesgn = (*bp++ == '+') ? 1 : -1;
2587 spe = atoi(bp);
2588 while (digit(*bp))
2589 bp++;
2590 while (*bp == ' ')
2591 bp++;
2592 l = 0;
2593 } else if (!strncmpi(bp, "blessed ", l = 8)
2594 || !strncmpi(bp, "holy ", l = 5)) {
2595 blessed = 1;
2596 } else if (!strncmpi(bp, "moist ", l = 6)
2597 || !strncmpi(bp, "wet ", l = 4)) {
2598 if (!strncmpi(bp, "wet ", 4))
2599 wetness = rn2(3) + 3;
2600 else
2601 wetness = rnd(2);
2602 } else if (!strncmpi(bp, "cursed ", l = 7)
2603 || !strncmpi(bp, "unholy ", l = 7)) {
2604 iscursed = 1;
2605 } else if (!strncmpi(bp, "uncursed ", l = 9)) {
2606 uncursed = 1;
2607 } else if (!strncmpi(bp, "rustproof ", l = 10)
2608 || !strncmpi(bp, "erodeproof ", l = 11)
2609 || !strncmpi(bp, "corrodeproof ", l = 13)
2610 || !strncmpi(bp, "fixed ", l = 6)
2611 || !strncmpi(bp, "fireproof ", l = 10)
2612 || !strncmpi(bp, "rotproof ", l = 9)) {
2613 erodeproof = 1;
2614 } else if (!strncmpi(bp, "lit ", l = 4)
2615 || !strncmpi(bp, "burning ", l = 8)) {
2616 islit = 1;
2617 } else if (!strncmpi(bp, "unlit ", l = 6)
2618 || !strncmpi(bp, "extinguished ", l = 13)) {
2619 islit = 0;
2620 /* "unlabeled" and "blank" are synonymous */
2621 } else if (!strncmpi(bp, "unlabeled ", l = 10)
2622 || !strncmpi(bp, "unlabelled ", l = 11)
2623 || !strncmpi(bp, "blank ", l = 6)) {
2624 unlabeled = 1;
2625 } else if (!strncmpi(bp, "poisoned ", l = 9)) {
2626 ispoisoned = 1;
2627 /* "trapped" recognized but not honored outside wizard mode */
2628 } else if (!strncmpi(bp, "trapped ", l = 8)) {
2629 trapped = 0; /* undo any previous "untrapped" */
2630 if (wizard)
2631 trapped = 1;
2632 } else if (!strncmpi(bp, "untrapped ", l = 10)) {
2633 trapped = 2; /* not trapped */
2634 } else if (!strncmpi(bp, "greased ", l = 8)) {
2635 isgreased = 1;
2636 } else if (!strncmpi(bp, "very ", l = 5)) {
2637 /* very rusted very heavy iron ball */
2638 very = 1;
2639 } else if (!strncmpi(bp, "thoroughly ", l = 11)) {
2640 very = 2;
2641 } else if (!strncmpi(bp, "rusty ", l = 6)
2642 || !strncmpi(bp, "rusted ", l = 7)
2643 || !strncmpi(bp, "burnt ", l = 6)
2644 || !strncmpi(bp, "burned ", l = 7)) {
2645 eroded = 1 + very;
2646 very = 0;
2647 } else if (!strncmpi(bp, "corroded ", l = 9)
2648 || !strncmpi(bp, "rotted ", l = 7)) {
2649 eroded2 = 1 + very;
2650 very = 0;
2651 } else if (!strncmpi(bp, "partly eaten ", l = 13)
2652 || !strncmpi(bp, "partially eaten ", l = 16)) {
2653 halfeaten = 1;
2654 } else if (!strncmpi(bp, "historic ", l = 9)) {
2655 ishistoric = 1;
2656 } else if (!strncmpi(bp, "diluted ", l = 8)) {
2657 isdiluted = 1;
2658 } else if (!strncmpi(bp, "empty ", l = 6)) {
2659 contents = EMPTY;
2660 } else
2661 break;
2662 bp += l;
2664 if (!cnt)
2665 cnt = 1; /* %% what with "gems" etc. ? */
2666 if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) {
2667 boolean keeptrailingchars = TRUE;
2669 p[(p > bp && p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */
2670 ++p; /* advance past '(' */
2671 if (!strncmpi(p, "lit)", 4)) {
2672 islit = 1;
2673 p += 4 - 1; /* point at ')' */
2674 } else {
2675 spe = atoi(p);
2676 while (digit(*p))
2677 p++;
2678 if (*p == ':') {
2679 p++;
2680 rechrg = spe;
2681 spe = atoi(p);
2682 while (digit(*p))
2683 p++;
2685 if (*p != ')') {
2686 spe = rechrg = 0;
2687 /* mis-matched parentheses; rest of string will be ignored
2688 * [probably we should restore everything back to '('
2689 * instead since it might be part of "named ..."]
2691 keeptrailingchars = FALSE;
2692 } else {
2693 spesgn = 1;
2696 if (keeptrailingchars) {
2697 char *pp = eos(bp);
2699 /* 'pp' points at 'pb's terminating '\0',
2700 'p' points at ')' and will be incremented past it */
2701 do {
2702 *pp++ = *++p;
2703 } while (*p);
2707 * otmp->spe is type schar, so we don't want spe to be any bigger or
2708 * smaller. Also, spe should always be positive --some cheaters may
2709 * try to confuse atoi().
2711 if (spe < 0) {
2712 spesgn = -1; /* cheaters get what they deserve */
2713 spe = abs(spe);
2715 if (spe > SCHAR_LIM)
2716 spe = SCHAR_LIM;
2717 if (rechrg < 0 || rechrg > 7)
2718 rechrg = 7; /* recharge_limit */
2720 /* now we have the actual name, as delivered by xname, say
2721 * green potions called whisky
2722 * scrolls labeled "QWERTY"
2723 * egg
2724 * fortune cookies
2725 * very heavy iron ball named hoei
2726 * wand of wishing
2727 * elven cloak
2729 if ((p = strstri(bp, " named ")) != 0) {
2730 *p = 0;
2731 name = p + 7;
2733 if ((p = strstri(bp, " called ")) != 0) {
2734 *p = 0;
2735 un = p + 8;
2736 /* "helmet called telepathy" is not "helmet" (a specific type)
2737 * "shield called reflection" is not "shield" (a general type)
2739 for (i = 0; i < SIZE(o_ranges); i++)
2740 if (!strcmpi(bp, o_ranges[i].name)) {
2741 oclass = o_ranges[i].oclass;
2742 goto srch;
2745 if ((p = strstri(bp, " labeled ")) != 0) {
2746 *p = 0;
2747 dn = p + 9;
2748 } else if ((p = strstri(bp, " labelled ")) != 0) {
2749 *p = 0;
2750 dn = p + 10;
2752 if ((p = strstri(bp, " of spinach")) != 0) {
2753 *p = 0;
2754 contents = SPINACH;
2758 Skip over "pair of ", "pairs of", "set of" and "sets of".
2760 Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
2761 English either way. See makeplural() for more on pair/pairs.
2763 We should only double count if the object in question is not
2764 referred to as a "pair of". E.g. We should double if the player
2765 types "pair of spears", but not if the player types "pair of
2766 lenses". Luckily (?) all objects that are referred to as pairs
2767 -- boots, gloves, and lenses -- are also not mergable, so cnt is
2768 ignored anyway.
2770 if (!strncmpi(bp, "pair of ", 8)) {
2771 bp += 8;
2772 cnt *= 2;
2773 } else if (cnt > 1 && !strncmpi(bp, "pairs of ", 9)) {
2774 bp += 9;
2775 cnt *= 2;
2776 } else if (!strncmpi(bp, "set of ", 7)) {
2777 bp += 7;
2778 } else if (!strncmpi(bp, "sets of ", 8)) {
2779 bp += 8;
2782 /* intercept pudding globs here; they're a valid wish target,
2783 * but we need them to not get treated like a corpse.
2785 * also don't let player wish for multiple globs.
2787 if ((p = strstri(bp, "glob of ")) != 0
2788 || (p = strstri(bp, "globs of ")) != 0) {
2789 int globoffset = (*(p + 4) == 's') ? 9 : 8;
2790 if ((mntmp = name_to_mon(p + globoffset)) >= PM_GRAY_OOZE
2791 && mntmp <= PM_BLACK_PUDDING) {
2792 mntmp = NON_PM; /* lie to ourselves */
2793 cnt = 0; /* force only one */
2795 } else {
2797 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
2798 * Don't check if it's a wand or spellbook.
2799 * (avoid "wand/finger of death" confusion).
2801 if (!strstri(bp, "wand ") && !strstri(bp, "spellbook ")
2802 && !strstri(bp, "finger ")) {
2803 if (((p = strstri(bp, "tin of ")) != 0)
2804 && (tmp = tin_variety_txt(p + 7, &tinv))
2805 && (mntmp = name_to_mon(p + 7 + tmp)) >= LOW_PM) {
2806 *(p + 3) = 0;
2807 tvariety = tinv;
2808 } else if ((p = strstri(bp, " of ")) != 0
2809 && (mntmp = name_to_mon(p + 4)) >= LOW_PM)
2810 *p = 0;
2813 /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
2814 if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
2815 if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
2816 if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
2817 if (strncmpi(bp, "master key",
2818 10)) /* not the "master" rank */
2819 if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */
2820 if (mntmp < LOW_PM && strlen(bp) > 2
2821 && (mntmp = name_to_mon(bp)) >= LOW_PM) {
2822 int mntmptoo,
2823 mntmplen; /* double check for rank title */
2824 char *obp = bp;
2825 mntmptoo = title_to_mon(bp, (int *) 0, &mntmplen);
2826 bp += mntmp != mntmptoo
2827 ? (int) strlen(mons[mntmp].mname)
2828 : mntmplen;
2829 if (*bp == ' ')
2830 bp++;
2831 else if (!strncmpi(bp, "s ", 2))
2832 bp += 2;
2833 else if (!strncmpi(bp, "es ", 3))
2834 bp += 3;
2835 else if (!*bp && !actualn && !dn && !un
2836 && !oclass) {
2837 /* no referent; they don't really mean a
2838 * monster type */
2839 bp = obp;
2840 mntmp = NON_PM;
2844 /* first change to singular if necessary */
2845 if (*bp) {
2846 char *sng = makesingular(bp);
2847 if (strcmp(bp, sng)) {
2848 if (cnt == 1)
2849 cnt = 2;
2850 Strcpy(bp, sng);
2854 /* Alternate spellings (pick-ax, silver sabre, &c) */
2856 struct alt_spellings *as = spellings;
2858 while (as->sp) {
2859 if (fuzzymatch(bp, as->sp, " -", TRUE)) {
2860 typ = as->ob;
2861 goto typfnd;
2863 as++;
2865 /* can't use spellings list for this one due to shuffling */
2866 if (!strncmpi(bp, "grey spell", 10))
2867 *(bp + 2) = 'a';
2869 if ((p = strstri(bp, "armour")) != 0) {
2870 /* skip past "armo", then copy remainder beyond "u" */
2871 p += 4;
2872 while ((*p = *(p + 1)) != '\0')
2873 ++p; /* self terminating */
2877 /* dragon scales - assumes order of dragons */
2878 if (!strcmpi(bp, "scales") && mntmp >= PM_GRAY_DRAGON
2879 && mntmp <= PM_YELLOW_DRAGON) {
2880 typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
2881 mntmp = NON_PM; /* no monster */
2882 goto typfnd;
2885 p = eos(bp);
2886 if (!BSTRCMPI(bp, p - 10, "holy water")) {
2887 typ = POT_WATER;
2888 if ((p - bp) >= 12 && *(p - 12) == 'u')
2889 iscursed = 1; /* unholy water */
2890 else
2891 blessed = 1;
2892 goto typfnd;
2894 if (unlabeled && !BSTRCMPI(bp, p - 6, "scroll")) {
2895 typ = SCR_BLANK_PAPER;
2896 goto typfnd;
2898 if (unlabeled && !BSTRCMPI(bp, p - 9, "spellbook")) {
2899 typ = SPE_BLANK_PAPER;
2900 goto typfnd;
2903 * NOTE: Gold pieces are handled as objects nowadays, and therefore
2904 * this section should probably be reconsidered as well as the entire
2905 * gold/money concept. Maybe we want to add other monetary units as
2906 * well in the future. (TH)
2908 if (!BSTRCMPI(bp, p - 10, "gold piece") || !BSTRCMPI(bp, p - 7, "zorkmid")
2909 || !strcmpi(bp, "gold") || !strcmpi(bp, "money")
2910 || !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
2911 if (cnt > 5000 && !wizard)
2912 cnt = 5000;
2913 else if (cnt < 1)
2914 cnt = 1;
2915 otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
2916 otmp->quan = (long) cnt;
2917 otmp->owt = weight(otmp);
2918 context.botl = 1;
2919 return otmp;
2922 /* check for single character object class code ("/" for wand, &c) */
2923 if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES
2924 && i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) {
2925 oclass = i;
2926 goto any;
2929 /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */
2930 /* false hits on, e.g., rings for "ring mail". */
2931 if (strncmpi(bp, "enchant ", 8) && strncmpi(bp, "destroy ", 8)
2932 && strncmpi(bp, "detect food", 11)
2933 && strncmpi(bp, "food detection", 14) && strncmpi(bp, "ring mail", 9)
2934 && strncmpi(bp, "studded leather armor", 21)
2935 && strncmpi(bp, "leather armor", 13)
2936 && strncmpi(bp, "tooled horn", 11) && strncmpi(bp, "food ration", 11)
2937 && strncmpi(bp, "meat ring", 9))
2938 for (i = 0; i < (int) (sizeof wrpsym); i++) {
2939 register int j = strlen(wrp[i]);
2940 if (!strncmpi(bp, wrp[i], j)) {
2941 oclass = wrpsym[i];
2942 if (oclass != AMULET_CLASS) {
2943 bp += j;
2944 if (!strncmpi(bp, " of ", 4))
2945 actualn = bp + 4;
2946 /* else if(*bp) ?? */
2947 } else
2948 actualn = bp;
2949 goto srch;
2951 if (!BSTRCMPI(bp, p - j, wrp[i])) {
2952 oclass = wrpsym[i];
2953 p -= j;
2954 *p = 0;
2955 if (p > bp && p[-1] == ' ')
2956 p[-1] = 0;
2957 actualn = dn = bp;
2958 goto srch;
2962 /* Wishing in wizard mode can create traps and furniture.
2963 * Part I: distinguish between trap and object for the two
2964 * types of traps which have corresponding objects: bear trap
2965 * and land mine. "beartrap" (object) and "bear trap" (trap)
2966 * have a difference in spelling which we used to exploit by
2967 * adding a special case in wishymatch(), but "land mine" is
2968 * spelled the same either way so needs different handing.
2969 * Since we need something else for land mine, we've dropped
2970 * the bear trap hack so that both are handled exactly the
2971 * same. To get an armed trap instead of a disarmed object,
2972 * the player can prefix either the object name or the trap
2973 * name with "trapped " (which ordinarily applies to chests
2974 * and tins), or append something--anything at all except for
2975 * " object", but " trap" is suggested--to either the trap
2976 * name or the object name.
2978 if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) {
2979 boolean beartrap = (lowc(*bp) == 'b');
2980 char *zp = bp + 4; /* skip "bear"/"land" */
2982 if (*zp == ' ')
2983 ++zp; /* embedded space is optional */
2984 if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) {
2985 zp += 4;
2986 if (trapped == 2 || !strcmpi(zp, " object")) {
2987 /* "untrapped <foo>" or "<foo> object" */
2988 typ = beartrap ? BEARTRAP : LAND_MINE;
2989 goto typfnd;
2990 } else if (trapped == 1 || *zp != '\0') {
2991 /* "trapped <foo>" or "<foo> trap" (actually "<foo>*") */
2992 int idx = trap_to_defsym(beartrap ? BEAR_TRAP : LANDMINE);
2994 /* use canonical trap spelling, skip object matching */
2995 Strcpy(bp, defsyms[idx].explanation);
2996 goto wiztrap;
2998 /* [no prefix or suffix; we're going to end up matching
2999 the object name and getting a disarmed trap object] */
3003 retry:
3004 /* "grey stone" check must be before general "stone" */
3005 for (i = 0; i < SIZE(o_ranges); i++)
3006 if (!strcmpi(bp, o_ranges[i].name)) {
3007 typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
3008 goto typfnd;
3011 if (!BSTRCMPI(bp, p - 6, " stone") || !BSTRCMPI(bp, p - 4, " gem")) {
3012 p[!strcmpi(p - 4, " gem") ? -4 : -6] = '\0';
3013 oclass = GEM_CLASS;
3014 dn = actualn = bp;
3015 goto srch;
3016 } else if (!strcmpi(bp, "looking glass")) {
3017 ; /* avoid false hit on "* glass" */
3018 } else if (!BSTRCMPI(bp, p - 6, " glass") || !strcmpi(bp, "glass")) {
3019 register char *g = bp;
3020 if (strstri(g, "broken"))
3021 return (struct obj *) 0;
3022 if (!strncmpi(g, "worthless ", 10))
3023 g += 10;
3024 if (!strncmpi(g, "piece of ", 9))
3025 g += 9;
3026 if (!strncmpi(g, "colored ", 8))
3027 g += 8;
3028 else if (!strncmpi(g, "coloured ", 9))
3029 g += 9;
3030 if (!strcmpi(g, "glass")) { /* choose random color */
3031 /* 9 different kinds */
3032 typ = LAST_GEM + rnd(9);
3033 if (objects[typ].oc_class == GEM_CLASS)
3034 goto typfnd;
3035 else
3036 typ = 0; /* somebody changed objects[]? punt */
3037 } else { /* try to construct canonical form */
3038 char tbuf[BUFSZ];
3040 Strcpy(tbuf, "worthless piece of ");
3041 Strcat(tbuf, g); /* assume it starts with the color */
3042 Strcpy(bp, tbuf);
3046 actualn = bp;
3047 if (!dn)
3048 dn = actualn; /* ex. "skull cap" */
3049 srch:
3050 /* check real names of gems first */
3051 if (!oclass && actualn) {
3052 for (i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
3053 register const char *zn;
3055 if ((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
3056 typ = i;
3057 goto typfnd;
3062 if (((typ = rnd_otyp_by_namedesc(actualn, oclass)) != STRANGE_OBJECT)
3063 || ((typ = rnd_otyp_by_namedesc(dn, oclass)) != STRANGE_OBJECT)
3064 || ((typ = rnd_otyp_by_namedesc(un, oclass)) != STRANGE_OBJECT)
3065 || ((typ = rnd_otyp_by_namedesc(origbp, oclass)) != STRANGE_OBJECT))
3066 goto typfnd;
3067 typ = 0;
3069 if (actualn) {
3070 struct Jitem *j = Japanese_items;
3072 while (j->item) {
3073 if (actualn && !strcmpi(actualn, j->name)) {
3074 typ = j->item;
3075 goto typfnd;
3077 j++;
3080 /* if we've stripped off "armor" and failed to match anything
3081 in objects[], append "mail" and try again to catch misnamed
3082 requests like "plate armor" and "yellow dragon scale armor" */
3083 if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) {
3084 /* modifying bp's string is ok; we're about to resort
3085 to random armor if this also fails to match anything */
3086 Strcat(bp, " mail");
3087 goto retry;
3089 if (!strcmpi(bp, "spinach")) {
3090 contents = SPINACH;
3091 typ = TIN;
3092 goto typfnd;
3094 /* Note: not strcmpi. 2 fruits, one capital, one not, are possible.
3095 Also not strncmp. We used to ignore trailing text with it, but
3096 that resulted in "grapefruit" matching "grape" if the latter came
3097 earlier than the former in the fruit list. */
3099 char *fp;
3100 int l, cntf;
3101 int blessedf, iscursedf, uncursedf, halfeatenf;
3103 blessedf = iscursedf = uncursedf = halfeatenf = 0;
3104 cntf = 0;
3106 fp = fruitbuf;
3107 for (;;) {
3108 if (!fp || !*fp)
3109 break;
3110 if (!strncmpi(fp, "an ", l = 3) || !strncmpi(fp, "a ", l = 2)) {
3111 cntf = 1;
3112 } else if (!cntf && digit(*fp)) {
3113 cntf = atoi(fp);
3114 while (digit(*fp))
3115 fp++;
3116 while (*fp == ' ')
3117 fp++;
3118 l = 0;
3119 } else if (!strncmpi(fp, "blessed ", l = 8)) {
3120 blessedf = 1;
3121 } else if (!strncmpi(fp, "cursed ", l = 7)) {
3122 iscursedf = 1;
3123 } else if (!strncmpi(fp, "uncursed ", l = 9)) {
3124 uncursedf = 1;
3125 } else if (!strncmpi(fp, "partly eaten ", l = 13)
3126 || !strncmpi(fp, "partially eaten ", l = 16)) {
3127 halfeatenf = 1;
3128 } else
3129 break;
3130 fp += l;
3133 for (f = ffruit; f; f = f->nextf) {
3134 /* match type: 0=none, 1=exact, 2=singular, 3=plural */
3135 int ftyp = 0;
3137 if (!strcmp(fp, f->fname))
3138 ftyp = 1;
3139 else if (!strcmp(fp, makesingular(f->fname)))
3140 ftyp = 2;
3141 else if (!strcmp(fp, makeplural(f->fname)))
3142 ftyp = 3;
3143 if (ftyp) {
3144 typ = SLIME_MOLD;
3145 blessed = blessedf;
3146 iscursed = iscursedf;
3147 uncursed = uncursedf;
3148 halfeaten = halfeatenf;
3149 /* adjust count if user explicitly asked for
3150 singular amount (can't happen unless fruit
3151 has been given an already pluralized name)
3152 or for plural amount */
3153 if (ftyp == 2 && !cntf)
3154 cntf = 1;
3155 else if (ftyp == 3 && !cntf)
3156 cntf = 2;
3157 cnt = cntf;
3158 ftype = f->fid;
3159 goto typfnd;
3164 if (!oclass && actualn) {
3165 short objtyp;
3167 /* Perhaps it's an artifact specified by name, not type */
3168 name = artifact_name(actualn, &objtyp);
3169 if (name) {
3170 typ = objtyp;
3171 goto typfnd;
3174 /* Let wizards wish for traps and furniture.
3175 * Must come after objects check so wizards can still wish for
3176 * trap objects like beartraps.
3177 * Disallow such topology tweaks for WIZKIT startup wishes.
3179 wiztrap:
3180 if (wizard && !program_state.wizkit_wishing) {
3181 struct rm *lev;
3182 int trap, x = u.ux, y = u.uy;
3184 for (trap = NO_TRAP + 1; trap < TRAPNUM; trap++) {
3185 struct trap *t;
3186 const char *tname;
3188 tname = defsyms[trap_to_defsym(trap)].explanation;
3189 if (strncmpi(tname, bp, strlen(tname)))
3190 continue;
3191 /* found it; avoid stupid mistakes */
3192 if ((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz))
3193 trap = ROCKTRAP;
3194 if ((t = maketrap(x, y, trap)) != 0) {
3195 trap = t->ttyp;
3196 tname = defsyms[trap_to_defsym(trap)].explanation;
3197 pline("%s%s.", An(tname),
3198 (trap != MAGIC_PORTAL) ? "" : " to nowhere");
3199 } else
3200 pline("Creation of %s failed.", an(tname));
3201 return &zeroobj;
3204 /* furniture and terrain */
3205 lev = &levl[x][y];
3206 p = eos(bp);
3207 if (!BSTRCMPI(bp, p - 8, "fountain")) {
3208 lev->typ = FOUNTAIN;
3209 level.flags.nfountains++;
3210 if (!strncmpi(bp, "magic ", 6))
3211 lev->blessedftn = 1;
3212 pline("A %sfountain.", lev->blessedftn ? "magic " : "");
3213 newsym(x, y);
3214 return &zeroobj;
3216 if (!BSTRCMPI(bp, p - 6, "throne")) {
3217 lev->typ = THRONE;
3218 pline("A throne.");
3219 newsym(x, y);
3220 return &zeroobj;
3222 if (!BSTRCMPI(bp, p - 4, "sink")) {
3223 lev->typ = SINK;
3224 level.flags.nsinks++;
3225 pline("A sink.");
3226 newsym(x, y);
3227 return &zeroobj;
3229 /* ("water" matches "potion of water" rather than terrain) */
3230 if (!BSTRCMPI(bp, p - 4, "pool") || !BSTRCMPI(bp, p - 4, "moat")) {
3231 lev->typ = !BSTRCMPI(bp, p - 4, "pool") ? POOL : MOAT;
3232 del_engr_at(x, y);
3233 pline("A %s.", (lev->typ == POOL) ? "pool" : "moat");
3234 /* Must manually make kelp! */
3235 water_damage_chain(level.objects[x][y], TRUE);
3236 newsym(x, y);
3237 return &zeroobj;
3239 if (!BSTRCMPI(bp, p - 4, "lava")) { /* also matches "molten lava" */
3240 lev->typ = LAVAPOOL;
3241 del_engr_at(x, y);
3242 pline("A pool of molten lava.");
3243 if (!(Levitation || Flying))
3244 (void) lava_effects();
3245 newsym(x, y);
3246 return &zeroobj;
3249 if (!BSTRCMPI(bp, p - 5, "altar")) {
3250 aligntyp al;
3252 lev->typ = ALTAR;
3253 if (!strncmpi(bp, "chaotic ", 8))
3254 al = A_CHAOTIC;
3255 else if (!strncmpi(bp, "neutral ", 8))
3256 al = A_NEUTRAL;
3257 else if (!strncmpi(bp, "lawful ", 7))
3258 al = A_LAWFUL;
3259 else if (!strncmpi(bp, "unaligned ", 10))
3260 al = A_NONE;
3261 else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
3262 al = (!rn2(6)) ? A_NONE : rn2((int) A_LAWFUL + 2) - 1;
3263 lev->altarmask = Align2amask(al);
3264 pline("%s altar.", An(align_str(al)));
3265 newsym(x, y);
3266 return &zeroobj;
3269 if (!BSTRCMPI(bp, p - 5, "grave")
3270 || !BSTRCMPI(bp, p - 9, "headstone")) {
3271 make_grave(x, y, (char *) 0);
3272 pline("%s.", IS_GRAVE(lev->typ) ? "A grave"
3273 : "Can't place a grave here");
3274 newsym(x, y);
3275 return &zeroobj;
3278 if (!BSTRCMPI(bp, p - 4, "tree")) {
3279 lev->typ = TREE;
3280 pline("A tree.");
3281 newsym(x, y);
3282 block_point(x, y);
3283 return &zeroobj;
3286 if (!BSTRCMPI(bp, p - 4, "bars")) {
3287 lev->typ = IRONBARS;
3288 pline("Iron bars.");
3289 newsym(x, y);
3290 return &zeroobj;
3294 if (!oclass && !typ) {
3295 if (!strncmpi(bp, "polearm", 7)) {
3296 typ = rnd_otyp_by_wpnskill(P_POLEARMS);
3297 goto typfnd;
3298 } else if (!strncmpi(bp, "hammer", 6)) {
3299 typ = rnd_otyp_by_wpnskill(P_HAMMER);
3300 goto typfnd;
3304 if (!oclass)
3305 return ((struct obj *) 0);
3306 any:
3307 if (!oclass)
3308 oclass = wrpsym[rn2((int) sizeof(wrpsym))];
3309 typfnd:
3310 if (typ)
3311 oclass = objects[typ].oc_class;
3313 /* handle some objects that are only allowed in wizard mode */
3314 if (typ && !wizard) {
3315 switch (typ) {
3316 case AMULET_OF_YENDOR:
3317 typ = FAKE_AMULET_OF_YENDOR;
3318 break;
3319 case CANDELABRUM_OF_INVOCATION:
3320 typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
3321 break;
3322 case BELL_OF_OPENING:
3323 typ = BELL;
3324 break;
3325 case SPE_BOOK_OF_THE_DEAD:
3326 typ = SPE_BLANK_PAPER;
3327 break;
3328 case MAGIC_LAMP:
3329 typ = OIL_LAMP;
3330 break;
3331 default:
3332 /* catch any other non-wishable objects (venom) */
3333 if (objects[typ].oc_nowish)
3334 return (struct obj *) 0;
3335 break;
3340 * Create the object, then fine-tune it.
3342 otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE);
3343 typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */
3345 if (islit && (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN
3346 || Is_candle(otmp) || typ == POT_OIL)) {
3347 place_object(otmp, u.ux, u.uy); /* make it viable light source */
3348 begin_burn(otmp, FALSE);
3349 obj_extract_self(otmp); /* now release it for caller's use */
3352 /* if player specified a reasonable count, maybe honor it */
3353 if (cnt > 0 && objects[typ].oc_merge
3354 && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp))
3355 || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp))
3356 || typ == ROCK || is_missile(otmp)))))
3357 otmp->quan = (long) cnt;
3359 if (oclass == VENOM_CLASS)
3360 otmp->spe = 1;
3362 if (spesgn == 0) {
3363 spe = otmp->spe;
3364 } else if (wizard) {
3365 ; /* no alteration to spe */
3366 } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS
3367 || is_weptool(otmp)
3368 || (oclass == RING_CLASS && objects[typ].oc_charged)) {
3369 if (spe > rnd(5) && spe > otmp->spe)
3370 spe = 0;
3371 if (spe > 2 && Luck < 0)
3372 spesgn = -1;
3373 } else {
3374 if (oclass == WAND_CLASS) {
3375 if (spe > 1 && spesgn == -1)
3376 spe = 1;
3377 } else {
3378 if (spe > 0 && spesgn == -1)
3379 spe = 0;
3381 if (spe > otmp->spe)
3382 spe = otmp->spe;
3385 if (spesgn == -1)
3386 spe = -spe;
3388 /* set otmp->spe. This may, or may not, use spe... */
3389 switch (typ) {
3390 case TIN:
3391 if (contents == EMPTY) {
3392 otmp->corpsenm = NON_PM;
3393 otmp->spe = 0;
3394 } else if (contents == SPINACH) {
3395 otmp->corpsenm = NON_PM;
3396 otmp->spe = 1;
3398 break;
3399 case TOWEL:
3400 if (wetness)
3401 otmp->spe = wetness;
3402 break;
3403 case SLIME_MOLD:
3404 otmp->spe = ftype;
3405 /* Fall through */
3406 case SKELETON_KEY:
3407 case CHEST:
3408 case LARGE_BOX:
3409 case HEAVY_IRON_BALL:
3410 case IRON_CHAIN:
3411 case STATUE:
3412 /* otmp->cobj already done in mksobj() */
3413 break;
3414 #ifdef MAIL
3415 case SCR_MAIL:
3416 /* 0: delivered in-game via external event (or randomly for fake mail);
3417 1: from bones or wishing; 2: written with marker */
3418 otmp->spe = 1;
3419 break;
3420 #endif
3421 case WAN_WISHING:
3422 if (!wizard) {
3423 otmp->spe = (rn2(10) ? -1 : 0);
3424 break;
3426 /* fall through, if wizard */
3427 default:
3428 otmp->spe = spe;
3431 /* set otmp->corpsenm or dragon scale [mail] */
3432 if (mntmp >= LOW_PM) {
3433 if (mntmp == PM_LONG_WORM_TAIL)
3434 mntmp = PM_LONG_WORM;
3436 switch (typ) {
3437 case TIN:
3438 otmp->spe = 0; /* No spinach */
3439 if (dead_species(mntmp, FALSE)) {
3440 otmp->corpsenm = NON_PM; /* it's empty */
3441 } else if (!(mons[mntmp].geno & G_UNIQ)
3442 && !(mvitals[mntmp].mvflags & G_NOCORPSE)
3443 && mons[mntmp].cnutrit != 0) {
3444 otmp->corpsenm = mntmp;
3446 break;
3447 case CORPSE:
3448 if (!(mons[mntmp].geno & G_UNIQ)
3449 && !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
3450 if (mons[mntmp].msound == MS_GUARDIAN)
3451 mntmp = genus(mntmp, 1);
3452 set_corpsenm(otmp, mntmp);
3454 break;
3455 case FIGURINE:
3456 if (!(mons[mntmp].geno & G_UNIQ) && !is_human(&mons[mntmp])
3457 #ifdef MAIL
3458 && mntmp != PM_MAIL_DAEMON
3459 #endif
3461 otmp->corpsenm = mntmp;
3462 break;
3463 case EGG:
3464 mntmp = can_be_hatched(mntmp);
3465 /* this also sets hatch timer if appropriate */
3466 set_corpsenm(otmp, mntmp);
3467 break;
3468 case STATUE:
3469 otmp->corpsenm = mntmp;
3470 if (Has_contents(otmp) && verysmall(&mons[mntmp]))
3471 delete_contents(otmp); /* no spellbook */
3472 otmp->spe = ishistoric ? STATUE_HISTORIC : 0;
3473 break;
3474 case SCALE_MAIL:
3475 /* Dragon mail - depends on the order of objects & dragons. */
3476 if (mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON)
3477 otmp->otyp = GRAY_DRAGON_SCALE_MAIL + mntmp - PM_GRAY_DRAGON;
3478 break;
3482 /* set blessed/cursed -- setting the fields directly is safe
3483 * since weight() is called below and addinv() will take care
3484 * of luck */
3485 if (iscursed) {
3486 curse(otmp);
3487 } else if (uncursed) {
3488 otmp->blessed = 0;
3489 otmp->cursed = (Luck < 0 && !wizard);
3490 } else if (blessed) {
3491 otmp->blessed = (Luck >= 0 || wizard);
3492 otmp->cursed = (Luck < 0 && !wizard);
3493 } else if (spesgn < 0) {
3494 curse(otmp);
3497 /* set eroded and erodeproof */
3498 if (erosion_matters(otmp)) {
3499 if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
3500 otmp->oeroded = eroded;
3501 if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
3502 otmp->oeroded2 = eroded2;
3504 * 3.6.1: earlier versions included `&& !eroded && !eroded2' here,
3505 * but damageproof combined with damaged is feasible (eroded
3506 * armor modified by confused reading of cursed destroy armor)
3507 * so don't prevent player from wishing for such a combination.
3509 if (erodeproof && (is_damageable(otmp) || otmp->otyp == CRYSKNIFE))
3510 otmp->oerodeproof = (Luck >= 0 || wizard);
3513 /* set otmp->recharged */
3514 if (oclass == WAND_CLASS) {
3515 /* prevent wishing abuse */
3516 if (otmp->otyp == WAN_WISHING && !wizard)
3517 rechrg = 1;
3518 otmp->recharged = (unsigned) rechrg;
3521 /* set poisoned */
3522 if (ispoisoned) {
3523 if (is_poisonable(otmp))
3524 otmp->opoisoned = (Luck >= 0);
3525 else if (oclass == FOOD_CLASS)
3526 /* try to taint by making it as old as possible */
3527 otmp->age = 1L;
3529 /* and [un]trapped */
3530 if (trapped) {
3531 if (Is_box(otmp) || typ == TIN)
3532 otmp->otrapped = (trapped == 1);
3535 if (isgreased)
3536 otmp->greased = 1;
3538 if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER)
3539 otmp->odiluted = 1;
3541 /* set tin variety */
3542 if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard))
3543 set_tin_variety(otmp, tvariety);
3545 if (name) {
3546 const char *aname;
3547 short objtyp;
3549 /* an artifact name might need capitalization fixing */
3550 aname = artifact_name(name, &objtyp);
3551 if (aname && objtyp == otmp->otyp)
3552 name = aname;
3554 /* 3.6 tribute - fix up novel */
3555 if (otmp->otyp == SPE_NOVEL) {
3556 const char *novelname;
3558 novelname = lookup_novel(name, &otmp->novelidx);
3559 if (novelname)
3560 name = novelname;
3563 otmp = oname(otmp, name);
3564 if (otmp->oartifact) {
3565 otmp->quan = 1L;
3566 u.uconduct.wisharti++; /* KMH, conduct */
3570 /* more wishing abuse: don't allow wishing for certain artifacts */
3571 /* and make them pay; charge them for the wish anyway! */
3572 if ((is_quest_artifact(otmp)
3573 || (otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) {
3574 artifact_exists(otmp, safe_oname(otmp), FALSE);
3575 obfree(otmp, (struct obj *) 0);
3576 otmp = &zeroobj;
3577 pline("For a moment, you feel %s in your %s, but it disappears!",
3578 something, makeplural(body_part(HAND)));
3581 if (halfeaten && otmp->oclass == FOOD_CLASS) {
3582 if (otmp->otyp == CORPSE)
3583 otmp->oeaten = mons[otmp->corpsenm].cnutrit;
3584 else
3585 otmp->oeaten = objects[otmp->otyp].oc_nutrition;
3586 /* (do this adjustment before setting up object's weight) */
3587 consume_oeaten(otmp, 1);
3589 otmp->owt = weight(otmp);
3590 if (very && otmp->otyp == HEAVY_IRON_BALL)
3591 otmp->owt += IRON_BALL_W_INCR;
3593 return otmp;
3597 rnd_class(first, last)
3598 int first, last;
3600 int i, x, sum = 0;
3602 if (first == last)
3603 return first;
3604 for (i = first; i <= last; i++)
3605 sum += objects[i].oc_prob;
3606 if (!sum) /* all zero */
3607 return first + rn2(last - first + 1);
3608 x = rnd(sum);
3609 for (i = first; i <= last; i++)
3610 if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
3611 return i;
3612 return 0;
3615 STATIC_OVL const char *
3616 Japanese_item_name(i)
3617 int i;
3619 struct Jitem *j = Japanese_items;
3621 while (j->item) {
3622 if (i == j->item)
3623 return j->name;
3624 j++;
3626 return (const char *) 0;
3629 const char *
3630 suit_simple_name(suit)
3631 struct obj *suit;
3633 const char *suitnm, *esuitp;
3635 if (Is_dragon_mail(suit))
3636 return "dragon mail"; /* <color> dragon scale mail */
3637 else if (Is_dragon_scales(suit))
3638 return "dragon scales";
3639 suitnm = OBJ_NAME(objects[suit->otyp]);
3640 esuitp = eos((char *) suitnm);
3641 if (strlen(suitnm) > 5 && !strcmp(esuitp - 5, " mail"))
3642 return "mail"; /* most suits fall into this category */
3643 else if (strlen(suitnm) > 7 && !strcmp(esuitp - 7, " jacket"))
3644 return "jacket"; /* leather jacket */
3645 /* suit is lame but armor is ambiguous and body armor is absurd */
3646 return "suit";
3649 const char *
3650 cloak_simple_name(cloak)
3651 struct obj *cloak;
3653 if (cloak) {
3654 switch (cloak->otyp) {
3655 case ROBE:
3656 return "robe";
3657 case MUMMY_WRAPPING:
3658 return "wrapping";
3659 case ALCHEMY_SMOCK:
3660 return (objects[cloak->otyp].oc_name_known && cloak->dknown)
3661 ? "smock"
3662 : "apron";
3663 default:
3664 break;
3667 return "cloak";
3670 /* helm vs hat for messages */
3671 const char *
3672 helm_simple_name(helmet)
3673 struct obj *helmet;
3676 * There is some wiggle room here; the result has been chosen
3677 * for consistency with the "protected by hard helmet" messages
3678 * given for various bonks on the head: headgear that provides
3679 * such protection is a "helm", that which doesn't is a "hat".
3681 * elven leather helm / leather hat -> hat
3682 * dwarvish iron helm / hard hat -> helm
3683 * The rest are completely straightforward:
3684 * fedora, cornuthaum, dunce cap -> hat
3685 * all other types of helmets -> helm
3687 return (helmet && !is_metallic(helmet)) ? "hat" : "helm";
3690 const char *
3691 mimic_obj_name(mtmp)
3692 struct monst *mtmp;
3694 if (mtmp->m_ap_type == M_AP_OBJECT) {
3695 if (mtmp->mappearance == GOLD_PIECE)
3696 return "gold";
3697 if (mtmp->mappearance != STRANGE_OBJECT)
3698 return simple_typename(mtmp->mappearance);
3700 return "whatcha-may-callit";
3704 * Construct a query prompt string, based around an object name, which is
3705 * guaranteed to fit within [QBUFSZ]. Takes an optional prefix, three
3706 * choices for filling in the middle (two object formatting functions and a
3707 * last resort literal which should be very short), and an optional suffix.
3709 char *
3710 safe_qbuf(qbuf, qprefix, qsuffix, obj, func, altfunc, lastR)
3711 char *qbuf; /* output buffer */
3712 const char *qprefix, *qsuffix;
3713 struct obj *obj;
3714 char *FDECL((*func), (OBJ_P)), *FDECL((*altfunc), (OBJ_P));
3715 const char *lastR;
3717 char *bufp, *endp;
3718 /* convert size_t (or int for ancient systems) to ordinary unsigned */
3719 unsigned len, lenlimit,
3720 len_qpfx = (unsigned) (qprefix ? strlen(qprefix) : 0),
3721 len_qsfx = (unsigned) (qsuffix ? strlen(qsuffix) : 0),
3722 len_lastR = (unsigned) strlen(lastR);
3724 lenlimit = QBUFSZ - 1;
3725 endp = qbuf + lenlimit;
3726 /* sanity check, aimed mainly at paniclog (it's conceivable for
3727 the result of short_oname() to be shorter than the length of
3728 the last resort string, but we ignore that possibility here) */
3729 if (len_qpfx > lenlimit)
3730 impossible("safe_qbuf: prefix too long (%u characters).", len_qpfx);
3731 else if (len_qpfx + len_qsfx > lenlimit)
3732 impossible("safe_qbuf: suffix too long (%u + %u characters).",
3733 len_qpfx, len_qsfx);
3734 else if (len_qpfx + len_lastR + len_qsfx > lenlimit)
3735 impossible("safe_qbuf: filler too long (%u + %u + %u characters).",
3736 len_qpfx, len_lastR, len_qsfx);
3738 /* the output buffer might be the same as the prefix if caller
3739 has already partially filled it */
3740 if (qbuf == qprefix) {
3741 /* prefix is already in the buffer */
3742 *endp = '\0';
3743 } else if (qprefix) {
3744 /* put prefix into the buffer */
3745 (void) strncpy(qbuf, qprefix, lenlimit);
3746 *endp = '\0';
3747 } else {
3748 /* no prefix; output buffer starts out empty */
3749 qbuf[0] = '\0';
3751 len = (unsigned) strlen(qbuf);
3753 if (len + len_lastR + len_qsfx > lenlimit) {
3754 /* too long; skip formatting, last resort output is truncated */
3755 if (len < lenlimit) {
3756 (void) strncpy(&qbuf[len], lastR, lenlimit - len);
3757 *endp = '\0';
3758 len = (unsigned) strlen(qbuf);
3759 if (qsuffix && len < lenlimit) {
3760 (void) strncpy(&qbuf[len], qsuffix, lenlimit - len);
3761 *endp = '\0';
3762 /* len = (unsigned) strlen(qbuf); */
3765 } else {
3766 /* suffix and last resort are guaranteed to fit */
3767 len += len_qsfx; /* include the pending suffix */
3768 /* format the object */
3769 bufp = short_oname(obj, func, altfunc, lenlimit - len);
3770 if (len + strlen(bufp) <= lenlimit)
3771 Strcat(qbuf, bufp); /* formatted name fits */
3772 else
3773 Strcat(qbuf, lastR); /* use last resort */
3774 releaseobuf(bufp);
3776 if (qsuffix)
3777 Strcat(qbuf, qsuffix);
3779 /* assert( strlen(qbuf) < QBUFSZ ); */
3780 return qbuf;
3783 /*objnam.c*/