use of #terrain while underwater
[aNetHack.git] / src / objnam.c
blob93fdcae83aec242fbf97ed5b9074536ae2c12b00
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_P));
15 STATIC_DCL boolean FDECL(wishymatch, (const char *, const char *, BOOLEAN_P));
16 STATIC_DCL char *NDECL(nextobuf);
17 STATIC_DCL void FDECL(releaseobuf, (char *));
18 STATIC_DCL char *FDECL(minimal_xname, (struct obj *));
19 STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *));
20 STATIC_DCL boolean FDECL(singplur_lookup, (char *, char *, BOOLEAN_P,
21 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 (obj->globby) {
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 STATIC_OVL 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 STATIC_OVL short
2457 rnd_otyp_by_namedesc(name, oclass)
2458 char *name;
2459 char oclass;
2461 int i, n = 0;
2462 short validobjs[NUM_OBJECTS];
2463 register const char *zn;
2464 long maxprob = 0;
2466 if (!name)
2467 return STRANGE_OBJECT;
2469 memset((genericptr_t) validobjs, 0, sizeof(validobjs));
2471 for (i = oclass ? bases[(int)oclass] : STRANGE_OBJECT + 1;
2472 i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass);
2473 ++i) {
2474 /* don't match extra descriptions (w/o real name) */
2475 if ((zn = OBJ_NAME(objects[i])) == 0)
2476 continue;
2477 if (wishymatch(name, zn, TRUE)
2478 || ((zn = OBJ_DESCR(objects[i])) != 0
2479 && wishymatch(name, zn, FALSE))
2480 || ((zn = objects[i].oc_uname) != 0
2481 && wishymatch(name, zn, FALSE))) {
2482 validobjs[n++] = (short) i;
2483 maxprob += (objects[i].oc_prob + 1);
2487 if (n > 0 && maxprob) {
2488 long prob = rn2(maxprob);
2490 i = 0;
2491 while (i < n - 1 && (prob -= (objects[validobjs[i]].oc_prob + 1)) > 0)
2492 i++;
2493 return validobjs[i];
2495 return STRANGE_OBJECT;
2499 * Return something wished for. Specifying a null pointer for
2500 * the user request string results in a random object. Otherwise,
2501 * if asking explicitly for "nothing" (or "nil") return no_wish;
2502 * if not an object return &zeroobj; if an error (no matching object),
2503 * return null.
2505 struct obj *
2506 readobjnam(bp, no_wish)
2507 register char *bp;
2508 struct obj *no_wish;
2510 register char *p;
2511 register int i;
2512 register struct obj *otmp;
2513 int cnt, spe, spesgn, typ, very, rechrg;
2514 int blessed, uncursed, iscursed, ispoisoned, isgreased;
2515 int eroded, eroded2, erodeproof;
2516 int halfeaten, mntmp, contents;
2517 int islit, unlabeled, ishistoric, isdiluted, trapped;
2518 int tmp, tinv, tvariety;
2519 int wetness, gsize;
2520 struct fruit *f;
2521 int ftype = context.current_fruit;
2522 char fruitbuf[BUFSZ];
2523 /* Fruits may not mess up the ability to wish for real objects (since
2524 * you can leave a fruit in a bones file and it will be added to
2525 * another person's game), so they must be checked for last, after
2526 * stripping all the possible prefixes and seeing if there's a real
2527 * name in there. So we have to save the full original name. However,
2528 * it's still possible to do things like "uncursed burnt Alaska",
2529 * or worse yet, "2 burned 5 course meals", so we need to loop to
2530 * strip off the prefixes again, this time stripping only the ones
2531 * possible on food.
2532 * We could get even more detailed so as to allow food names with
2533 * prefixes that _are_ possible on food, so you could wish for
2534 * "2 3 alarm chilis". Currently this isn't allowed; options.c
2535 * automatically sticks 'candied' in front of such names.
2537 char oclass;
2538 char *un, *dn, *actualn, *origbp = bp;
2539 const char *name = 0;
2541 cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed =
2542 ispoisoned = isgreased = eroded = eroded2 = erodeproof = halfeaten =
2543 islit = unlabeled = ishistoric = isdiluted = trapped = 0;
2544 tvariety = RANDOM_TIN;
2545 mntmp = NON_PM;
2546 #define UNDEFINED 0
2547 #define EMPTY 1
2548 #define SPINACH 2
2549 contents = UNDEFINED;
2550 oclass = 0;
2551 actualn = dn = un = 0;
2552 wetness = 0;
2554 if (!bp)
2555 goto any;
2556 /* first, remove extra whitespace they may have typed */
2557 (void) mungspaces(bp);
2558 /* allow wishing for "nothing" to preserve wishless conduct...
2559 [now requires "wand of nothing" if that's what was really wanted] */
2560 if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil")
2561 || !strcmpi(bp, "none"))
2562 return no_wish;
2563 /* save the [nearly] unmodified choice string */
2564 Strcpy(fruitbuf, bp);
2566 for (;;) {
2567 register int l;
2569 if (!bp || !*bp)
2570 goto any;
2571 if (!strncmpi(bp, "an ", l = 3) || !strncmpi(bp, "a ", l = 2)) {
2572 cnt = 1;
2573 } else if (!strncmpi(bp, "the ", l = 4)) {
2574 ; /* just increment `bp' by `l' below */
2575 } else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
2576 cnt = atoi(bp);
2577 while (digit(*bp))
2578 bp++;
2579 while (*bp == ' ')
2580 bp++;
2581 l = 0;
2582 } else if (*bp == '+' || *bp == '-') {
2583 spesgn = (*bp++ == '+') ? 1 : -1;
2584 spe = atoi(bp);
2585 while (digit(*bp))
2586 bp++;
2587 while (*bp == ' ')
2588 bp++;
2589 l = 0;
2590 } else if (!strncmpi(bp, "blessed ", l = 8)
2591 || !strncmpi(bp, "holy ", l = 5)) {
2592 blessed = 1;
2593 } else if (!strncmpi(bp, "moist ", l = 6)
2594 || !strncmpi(bp, "wet ", l = 4)) {
2595 if (!strncmpi(bp, "wet ", 4))
2596 wetness = rn2(3) + 3;
2597 else
2598 wetness = rnd(2);
2599 } else if (!strncmpi(bp, "cursed ", l = 7)
2600 || !strncmpi(bp, "unholy ", l = 7)) {
2601 iscursed = 1;
2602 } else if (!strncmpi(bp, "uncursed ", l = 9)) {
2603 uncursed = 1;
2604 } else if (!strncmpi(bp, "rustproof ", l = 10)
2605 || !strncmpi(bp, "erodeproof ", l = 11)
2606 || !strncmpi(bp, "corrodeproof ", l = 13)
2607 || !strncmpi(bp, "fixed ", l = 6)
2608 || !strncmpi(bp, "fireproof ", l = 10)
2609 || !strncmpi(bp, "rotproof ", l = 9)) {
2610 erodeproof = 1;
2611 } else if (!strncmpi(bp, "lit ", l = 4)
2612 || !strncmpi(bp, "burning ", l = 8)) {
2613 islit = 1;
2614 } else if (!strncmpi(bp, "unlit ", l = 6)
2615 || !strncmpi(bp, "extinguished ", l = 13)) {
2616 islit = 0;
2617 /* "unlabeled" and "blank" are synonymous */
2618 } else if (!strncmpi(bp, "unlabeled ", l = 10)
2619 || !strncmpi(bp, "unlabelled ", l = 11)
2620 || !strncmpi(bp, "blank ", l = 6)) {
2621 unlabeled = 1;
2622 } else if (!strncmpi(bp, "poisoned ", l = 9)) {
2623 ispoisoned = 1;
2624 /* "trapped" recognized but not honored outside wizard mode */
2625 } else if (!strncmpi(bp, "trapped ", l = 8)) {
2626 trapped = 0; /* undo any previous "untrapped" */
2627 if (wizard)
2628 trapped = 1;
2629 } else if (!strncmpi(bp, "untrapped ", l = 10)) {
2630 trapped = 2; /* not trapped */
2631 } else if (!strncmpi(bp, "greased ", l = 8)) {
2632 isgreased = 1;
2633 } else if (!strncmpi(bp, "very ", l = 5)) {
2634 /* very rusted very heavy iron ball */
2635 very = 1;
2636 } else if (!strncmpi(bp, "thoroughly ", l = 11)) {
2637 very = 2;
2638 } else if (!strncmpi(bp, "rusty ", l = 6)
2639 || !strncmpi(bp, "rusted ", l = 7)
2640 || !strncmpi(bp, "burnt ", l = 6)
2641 || !strncmpi(bp, "burned ", l = 7)) {
2642 eroded = 1 + very;
2643 very = 0;
2644 } else if (!strncmpi(bp, "corroded ", l = 9)
2645 || !strncmpi(bp, "rotted ", l = 7)) {
2646 eroded2 = 1 + very;
2647 very = 0;
2648 } else if (!strncmpi(bp, "partly eaten ", l = 13)
2649 || !strncmpi(bp, "partially eaten ", l = 16)) {
2650 halfeaten = 1;
2651 } else if (!strncmpi(bp, "historic ", l = 9)) {
2652 ishistoric = 1;
2653 } else if (!strncmpi(bp, "diluted ", l = 8)) {
2654 isdiluted = 1;
2655 } else if (!strncmpi(bp, "empty ", l = 6)) {
2656 contents = EMPTY;
2657 } else if (!strncmpi(bp, "small ", l = 6)) { /* glob sizes */
2658 gsize = 1;
2659 } else if (!strncmpi(bp, "medium ", l = 7)) {
2660 /* xname() doesn't display "medium" but without this
2661 there'd be no way to ask for the intermediate size */
2662 gsize = 2;
2663 } else if (!strncmpi(bp, "large ", l = 6)) {
2664 /* "very large " had "very " peeled off on previous iteration */
2665 gsize = (very != 1) ? 3 : 4;
2666 } else
2667 break;
2668 bp += l;
2670 if (!cnt)
2671 cnt = 1; /* %% what with "gems" etc. ? */
2672 if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) {
2673 boolean keeptrailingchars = TRUE;
2675 p[(p > bp && p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */
2676 ++p; /* advance past '(' */
2677 if (!strncmpi(p, "lit)", 4)) {
2678 islit = 1;
2679 p += 4 - 1; /* point at ')' */
2680 } else {
2681 spe = atoi(p);
2682 while (digit(*p))
2683 p++;
2684 if (*p == ':') {
2685 p++;
2686 rechrg = spe;
2687 spe = atoi(p);
2688 while (digit(*p))
2689 p++;
2691 if (*p != ')') {
2692 spe = rechrg = 0;
2693 /* mis-matched parentheses; rest of string will be ignored
2694 * [probably we should restore everything back to '('
2695 * instead since it might be part of "named ..."]
2697 keeptrailingchars = FALSE;
2698 } else {
2699 spesgn = 1;
2702 if (keeptrailingchars) {
2703 char *pp = eos(bp);
2705 /* 'pp' points at 'pb's terminating '\0',
2706 'p' points at ')' and will be incremented past it */
2707 do {
2708 *pp++ = *++p;
2709 } while (*p);
2713 * otmp->spe is type schar, so we don't want spe to be any bigger or
2714 * smaller. Also, spe should always be positive --some cheaters may
2715 * try to confuse atoi().
2717 if (spe < 0) {
2718 spesgn = -1; /* cheaters get what they deserve */
2719 spe = abs(spe);
2721 if (spe > SCHAR_LIM)
2722 spe = SCHAR_LIM;
2723 if (rechrg < 0 || rechrg > 7)
2724 rechrg = 7; /* recharge_limit */
2726 /* now we have the actual name, as delivered by xname, say
2727 * green potions called whisky
2728 * scrolls labeled "QWERTY"
2729 * egg
2730 * fortune cookies
2731 * very heavy iron ball named hoei
2732 * wand of wishing
2733 * elven cloak
2735 if ((p = strstri(bp, " named ")) != 0) {
2736 *p = 0;
2737 name = p + 7;
2739 if ((p = strstri(bp, " called ")) != 0) {
2740 *p = 0;
2741 un = p + 8;
2742 /* "helmet called telepathy" is not "helmet" (a specific type)
2743 * "shield called reflection" is not "shield" (a general type)
2745 for (i = 0; i < SIZE(o_ranges); i++)
2746 if (!strcmpi(bp, o_ranges[i].name)) {
2747 oclass = o_ranges[i].oclass;
2748 goto srch;
2751 if ((p = strstri(bp, " labeled ")) != 0) {
2752 *p = 0;
2753 dn = p + 9;
2754 } else if ((p = strstri(bp, " labelled ")) != 0) {
2755 *p = 0;
2756 dn = p + 10;
2758 if ((p = strstri(bp, " of spinach")) != 0) {
2759 *p = 0;
2760 contents = SPINACH;
2764 Skip over "pair of ", "pairs of", "set of" and "sets of".
2766 Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
2767 English either way. See makeplural() for more on pair/pairs.
2769 We should only double count if the object in question is not
2770 referred to as a "pair of". E.g. We should double if the player
2771 types "pair of spears", but not if the player types "pair of
2772 lenses". Luckily (?) all objects that are referred to as pairs
2773 -- boots, gloves, and lenses -- are also not mergable, so cnt is
2774 ignored anyway.
2776 if (!strncmpi(bp, "pair of ", 8)) {
2777 bp += 8;
2778 cnt *= 2;
2779 } else if (cnt > 1 && !strncmpi(bp, "pairs of ", 9)) {
2780 bp += 9;
2781 cnt *= 2;
2782 } else if (!strncmpi(bp, "set of ", 7)) {
2783 bp += 7;
2784 } else if (!strncmpi(bp, "sets of ", 8)) {
2785 bp += 8;
2788 /* intercept pudding globs here; they're a valid wish target,
2789 * but we need them to not get treated like a corpse.
2791 * also don't let player wish for multiple globs.
2793 if ((p = strstri(bp, "glob of ")) != 0
2794 || (p = strstri(bp, "globs of ")) != 0) {
2795 int globoffset = (*(p + 4) == 's') ? 9 : 8;
2797 if ((mntmp = name_to_mon(p + globoffset)) >= PM_GRAY_OOZE
2798 && mntmp <= PM_BLACK_PUDDING) {
2799 mntmp = NON_PM; /* lie to ourselves */
2800 cnt = 0; /* force only one */
2802 } else {
2804 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
2805 * Don't check if it's a wand or spellbook.
2806 * (avoid "wand/finger of death" confusion).
2808 if (!strstri(bp, "wand ") && !strstri(bp, "spellbook ")
2809 && !strstri(bp, "finger ")) {
2810 if (((p = strstri(bp, "tin of ")) != 0)
2811 && (tmp = tin_variety_txt(p + 7, &tinv))
2812 && (mntmp = name_to_mon(p + 7 + tmp)) >= LOW_PM) {
2813 *(p + 3) = 0;
2814 tvariety = tinv;
2815 } else if ((p = strstri(bp, " of ")) != 0
2816 && (mntmp = name_to_mon(p + 4)) >= LOW_PM)
2817 *p = 0;
2820 /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
2821 if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
2822 if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
2823 if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
2824 if (strncmpi(bp, "master key",
2825 10)) /* not the "master" rank */
2826 if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */
2827 if (mntmp < LOW_PM && strlen(bp) > 2
2828 && (mntmp = name_to_mon(bp)) >= LOW_PM) {
2829 int mntmptoo,
2830 mntmplen; /* double check for rank title */
2831 char *obp = bp;
2832 mntmptoo = title_to_mon(bp, (int *) 0, &mntmplen);
2833 bp += mntmp != mntmptoo
2834 ? (int) strlen(mons[mntmp].mname)
2835 : mntmplen;
2836 if (*bp == ' ')
2837 bp++;
2838 else if (!strncmpi(bp, "s ", 2))
2839 bp += 2;
2840 else if (!strncmpi(bp, "es ", 3))
2841 bp += 3;
2842 else if (!*bp && !actualn && !dn && !un
2843 && !oclass) {
2844 /* no referent; they don't really mean a
2845 * monster type */
2846 bp = obp;
2847 mntmp = NON_PM;
2851 /* first change to singular if necessary */
2852 if (*bp) {
2853 char *sng = makesingular(bp);
2854 if (strcmp(bp, sng)) {
2855 if (cnt == 1)
2856 cnt = 2;
2857 Strcpy(bp, sng);
2861 /* Alternate spellings (pick-ax, silver sabre, &c) */
2863 struct alt_spellings *as = spellings;
2865 while (as->sp) {
2866 if (fuzzymatch(bp, as->sp, " -", TRUE)) {
2867 typ = as->ob;
2868 goto typfnd;
2870 as++;
2872 /* can't use spellings list for this one due to shuffling */
2873 if (!strncmpi(bp, "grey spell", 10))
2874 *(bp + 2) = 'a';
2876 if ((p = strstri(bp, "armour")) != 0) {
2877 /* skip past "armo", then copy remainder beyond "u" */
2878 p += 4;
2879 while ((*p = *(p + 1)) != '\0')
2880 ++p; /* self terminating */
2884 /* dragon scales - assumes order of dragons */
2885 if (!strcmpi(bp, "scales") && mntmp >= PM_GRAY_DRAGON
2886 && mntmp <= PM_YELLOW_DRAGON) {
2887 typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
2888 mntmp = NON_PM; /* no monster */
2889 goto typfnd;
2892 p = eos(bp);
2893 if (!BSTRCMPI(bp, p - 10, "holy water")) {
2894 typ = POT_WATER;
2895 if ((p - bp) >= 12 && *(p - 12) == 'u')
2896 iscursed = 1; /* unholy water */
2897 else
2898 blessed = 1;
2899 goto typfnd;
2901 if (unlabeled && !BSTRCMPI(bp, p - 6, "scroll")) {
2902 typ = SCR_BLANK_PAPER;
2903 goto typfnd;
2905 if (unlabeled && !BSTRCMPI(bp, p - 9, "spellbook")) {
2906 typ = SPE_BLANK_PAPER;
2907 goto typfnd;
2910 * NOTE: Gold pieces are handled as objects nowadays, and therefore
2911 * this section should probably be reconsidered as well as the entire
2912 * gold/money concept. Maybe we want to add other monetary units as
2913 * well in the future. (TH)
2915 if (!BSTRCMPI(bp, p - 10, "gold piece") || !BSTRCMPI(bp, p - 7, "zorkmid")
2916 || !strcmpi(bp, "gold") || !strcmpi(bp, "money")
2917 || !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
2918 if (cnt > 5000 && !wizard)
2919 cnt = 5000;
2920 else if (cnt < 1)
2921 cnt = 1;
2922 otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
2923 otmp->quan = (long) cnt;
2924 otmp->owt = weight(otmp);
2925 context.botl = 1;
2926 return otmp;
2929 /* check for single character object class code ("/" for wand, &c) */
2930 if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES
2931 && i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) {
2932 oclass = i;
2933 goto any;
2936 /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */
2937 /* false hits on, e.g., rings for "ring mail". */
2938 if (strncmpi(bp, "enchant ", 8) && strncmpi(bp, "destroy ", 8)
2939 && strncmpi(bp, "detect food", 11)
2940 && strncmpi(bp, "food detection", 14) && strncmpi(bp, "ring mail", 9)
2941 && strncmpi(bp, "studded leather armor", 21)
2942 && strncmpi(bp, "leather armor", 13)
2943 && strncmpi(bp, "tooled horn", 11) && strncmpi(bp, "food ration", 11)
2944 && strncmpi(bp, "meat ring", 9))
2945 for (i = 0; i < (int) (sizeof wrpsym); i++) {
2946 register int j = strlen(wrp[i]);
2947 if (!strncmpi(bp, wrp[i], j)) {
2948 oclass = wrpsym[i];
2949 if (oclass != AMULET_CLASS) {
2950 bp += j;
2951 if (!strncmpi(bp, " of ", 4))
2952 actualn = bp + 4;
2953 /* else if(*bp) ?? */
2954 } else
2955 actualn = bp;
2956 goto srch;
2958 if (!BSTRCMPI(bp, p - j, wrp[i])) {
2959 oclass = wrpsym[i];
2960 p -= j;
2961 *p = 0;
2962 if (p > bp && p[-1] == ' ')
2963 p[-1] = 0;
2964 actualn = dn = bp;
2965 goto srch;
2969 /* Wishing in wizard mode can create traps and furniture.
2970 * Part I: distinguish between trap and object for the two
2971 * types of traps which have corresponding objects: bear trap
2972 * and land mine. "beartrap" (object) and "bear trap" (trap)
2973 * have a difference in spelling which we used to exploit by
2974 * adding a special case in wishymatch(), but "land mine" is
2975 * spelled the same either way so needs different handing.
2976 * Since we need something else for land mine, we've dropped
2977 * the bear trap hack so that both are handled exactly the
2978 * same. To get an armed trap instead of a disarmed object,
2979 * the player can prefix either the object name or the trap
2980 * name with "trapped " (which ordinarily applies to chests
2981 * and tins), or append something--anything at all except for
2982 * " object", but " trap" is suggested--to either the trap
2983 * name or the object name.
2985 if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) {
2986 boolean beartrap = (lowc(*bp) == 'b');
2987 char *zp = bp + 4; /* skip "bear"/"land" */
2989 if (*zp == ' ')
2990 ++zp; /* embedded space is optional */
2991 if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) {
2992 zp += 4;
2993 if (trapped == 2 || !strcmpi(zp, " object")) {
2994 /* "untrapped <foo>" or "<foo> object" */
2995 typ = beartrap ? BEARTRAP : LAND_MINE;
2996 goto typfnd;
2997 } else if (trapped == 1 || *zp != '\0') {
2998 /* "trapped <foo>" or "<foo> trap" (actually "<foo>*") */
2999 int idx = trap_to_defsym(beartrap ? BEAR_TRAP : LANDMINE);
3001 /* use canonical trap spelling, skip object matching */
3002 Strcpy(bp, defsyms[idx].explanation);
3003 goto wiztrap;
3005 /* [no prefix or suffix; we're going to end up matching
3006 the object name and getting a disarmed trap object] */
3010 retry:
3011 /* "grey stone" check must be before general "stone" */
3012 for (i = 0; i < SIZE(o_ranges); i++)
3013 if (!strcmpi(bp, o_ranges[i].name)) {
3014 typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
3015 goto typfnd;
3018 if (!BSTRCMPI(bp, p - 6, " stone") || !BSTRCMPI(bp, p - 4, " gem")) {
3019 p[!strcmpi(p - 4, " gem") ? -4 : -6] = '\0';
3020 oclass = GEM_CLASS;
3021 dn = actualn = bp;
3022 goto srch;
3023 } else if (!strcmpi(bp, "looking glass")) {
3024 ; /* avoid false hit on "* glass" */
3025 } else if (!BSTRCMPI(bp, p - 6, " glass") || !strcmpi(bp, "glass")) {
3026 register char *g = bp;
3027 if (strstri(g, "broken"))
3028 return (struct obj *) 0;
3029 if (!strncmpi(g, "worthless ", 10))
3030 g += 10;
3031 if (!strncmpi(g, "piece of ", 9))
3032 g += 9;
3033 if (!strncmpi(g, "colored ", 8))
3034 g += 8;
3035 else if (!strncmpi(g, "coloured ", 9))
3036 g += 9;
3037 if (!strcmpi(g, "glass")) { /* choose random color */
3038 /* 9 different kinds */
3039 typ = LAST_GEM + rnd(9);
3040 if (objects[typ].oc_class == GEM_CLASS)
3041 goto typfnd;
3042 else
3043 typ = 0; /* somebody changed objects[]? punt */
3044 } else { /* try to construct canonical form */
3045 char tbuf[BUFSZ];
3047 Strcpy(tbuf, "worthless piece of ");
3048 Strcat(tbuf, g); /* assume it starts with the color */
3049 Strcpy(bp, tbuf);
3053 actualn = bp;
3054 if (!dn)
3055 dn = actualn; /* ex. "skull cap" */
3056 srch:
3057 /* check real names of gems first */
3058 if (!oclass && actualn) {
3059 for (i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
3060 register const char *zn;
3062 if ((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
3063 typ = i;
3064 goto typfnd;
3069 if (((typ = rnd_otyp_by_namedesc(actualn, oclass)) != STRANGE_OBJECT)
3070 || ((typ = rnd_otyp_by_namedesc(dn, oclass)) != STRANGE_OBJECT)
3071 || ((typ = rnd_otyp_by_namedesc(un, oclass)) != STRANGE_OBJECT)
3072 || ((typ = rnd_otyp_by_namedesc(origbp, oclass)) != STRANGE_OBJECT))
3073 goto typfnd;
3074 typ = 0;
3076 if (actualn) {
3077 struct Jitem *j = Japanese_items;
3079 while (j->item) {
3080 if (actualn && !strcmpi(actualn, j->name)) {
3081 typ = j->item;
3082 goto typfnd;
3084 j++;
3087 /* if we've stripped off "armor" and failed to match anything
3088 in objects[], append "mail" and try again to catch misnamed
3089 requests like "plate armor" and "yellow dragon scale armor" */
3090 if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) {
3091 /* modifying bp's string is ok; we're about to resort
3092 to random armor if this also fails to match anything */
3093 Strcat(bp, " mail");
3094 goto retry;
3096 if (!strcmpi(bp, "spinach")) {
3097 contents = SPINACH;
3098 typ = TIN;
3099 goto typfnd;
3101 /* Note: not strcmpi. 2 fruits, one capital, one not, are possible.
3102 Also not strncmp. We used to ignore trailing text with it, but
3103 that resulted in "grapefruit" matching "grape" if the latter came
3104 earlier than the former in the fruit list. */
3106 char *fp;
3107 int l, cntf;
3108 int blessedf, iscursedf, uncursedf, halfeatenf;
3110 blessedf = iscursedf = uncursedf = halfeatenf = 0;
3111 cntf = 0;
3113 fp = fruitbuf;
3114 for (;;) {
3115 if (!fp || !*fp)
3116 break;
3117 if (!strncmpi(fp, "an ", l = 3) || !strncmpi(fp, "a ", l = 2)) {
3118 cntf = 1;
3119 } else if (!cntf && digit(*fp)) {
3120 cntf = atoi(fp);
3121 while (digit(*fp))
3122 fp++;
3123 while (*fp == ' ')
3124 fp++;
3125 l = 0;
3126 } else if (!strncmpi(fp, "blessed ", l = 8)) {
3127 blessedf = 1;
3128 } else if (!strncmpi(fp, "cursed ", l = 7)) {
3129 iscursedf = 1;
3130 } else if (!strncmpi(fp, "uncursed ", l = 9)) {
3131 uncursedf = 1;
3132 } else if (!strncmpi(fp, "partly eaten ", l = 13)
3133 || !strncmpi(fp, "partially eaten ", l = 16)) {
3134 halfeatenf = 1;
3135 } else
3136 break;
3137 fp += l;
3140 for (f = ffruit; f; f = f->nextf) {
3141 /* match type: 0=none, 1=exact, 2=singular, 3=plural */
3142 int ftyp = 0;
3144 if (!strcmp(fp, f->fname))
3145 ftyp = 1;
3146 else if (!strcmp(fp, makesingular(f->fname)))
3147 ftyp = 2;
3148 else if (!strcmp(fp, makeplural(f->fname)))
3149 ftyp = 3;
3150 if (ftyp) {
3151 typ = SLIME_MOLD;
3152 blessed = blessedf;
3153 iscursed = iscursedf;
3154 uncursed = uncursedf;
3155 halfeaten = halfeatenf;
3156 /* adjust count if user explicitly asked for
3157 singular amount (can't happen unless fruit
3158 has been given an already pluralized name)
3159 or for plural amount */
3160 if (ftyp == 2 && !cntf)
3161 cntf = 1;
3162 else if (ftyp == 3 && !cntf)
3163 cntf = 2;
3164 cnt = cntf;
3165 ftype = f->fid;
3166 goto typfnd;
3171 if (!oclass && actualn) {
3172 short objtyp;
3174 /* Perhaps it's an artifact specified by name, not type */
3175 name = artifact_name(actualn, &objtyp);
3176 if (name) {
3177 typ = objtyp;
3178 goto typfnd;
3181 /* Let wizards wish for traps and furniture.
3182 * Must come after objects check so wizards can still wish for
3183 * trap objects like beartraps.
3184 * Disallow such topology tweaks for WIZKIT startup wishes.
3186 wiztrap:
3187 if (wizard && !program_state.wizkit_wishing) {
3188 struct rm *lev;
3189 int trap, x = u.ux, y = u.uy;
3191 for (trap = NO_TRAP + 1; trap < TRAPNUM; trap++) {
3192 struct trap *t;
3193 const char *tname;
3195 tname = defsyms[trap_to_defsym(trap)].explanation;
3196 if (strncmpi(tname, bp, strlen(tname)))
3197 continue;
3198 /* found it; avoid stupid mistakes */
3199 if ((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz))
3200 trap = ROCKTRAP;
3201 if ((t = maketrap(x, y, trap)) != 0) {
3202 trap = t->ttyp;
3203 tname = defsyms[trap_to_defsym(trap)].explanation;
3204 pline("%s%s.", An(tname),
3205 (trap != MAGIC_PORTAL) ? "" : " to nowhere");
3206 } else
3207 pline("Creation of %s failed.", an(tname));
3208 return &zeroobj;
3211 /* furniture and terrain */
3212 lev = &levl[x][y];
3213 p = eos(bp);
3214 if (!BSTRCMPI(bp, p - 8, "fountain")) {
3215 lev->typ = FOUNTAIN;
3216 level.flags.nfountains++;
3217 if (!strncmpi(bp, "magic ", 6))
3218 lev->blessedftn = 1;
3219 pline("A %sfountain.", lev->blessedftn ? "magic " : "");
3220 newsym(x, y);
3221 return &zeroobj;
3223 if (!BSTRCMPI(bp, p - 6, "throne")) {
3224 lev->typ = THRONE;
3225 pline("A throne.");
3226 newsym(x, y);
3227 return &zeroobj;
3229 if (!BSTRCMPI(bp, p - 4, "sink")) {
3230 lev->typ = SINK;
3231 level.flags.nsinks++;
3232 pline("A sink.");
3233 newsym(x, y);
3234 return &zeroobj;
3236 /* ("water" matches "potion of water" rather than terrain) */
3237 if (!BSTRCMPI(bp, p - 4, "pool") || !BSTRCMPI(bp, p - 4, "moat")) {
3238 lev->typ = !BSTRCMPI(bp, p - 4, "pool") ? POOL : MOAT;
3239 del_engr_at(x, y);
3240 pline("A %s.", (lev->typ == POOL) ? "pool" : "moat");
3241 /* Must manually make kelp! */
3242 water_damage_chain(level.objects[x][y], TRUE);
3243 newsym(x, y);
3244 return &zeroobj;
3246 if (!BSTRCMPI(bp, p - 4, "lava")) { /* also matches "molten lava" */
3247 lev->typ = LAVAPOOL;
3248 del_engr_at(x, y);
3249 pline("A pool of molten lava.");
3250 if (!(Levitation || Flying))
3251 (void) lava_effects();
3252 newsym(x, y);
3253 return &zeroobj;
3256 if (!BSTRCMPI(bp, p - 5, "altar")) {
3257 aligntyp al;
3259 lev->typ = ALTAR;
3260 if (!strncmpi(bp, "chaotic ", 8))
3261 al = A_CHAOTIC;
3262 else if (!strncmpi(bp, "neutral ", 8))
3263 al = A_NEUTRAL;
3264 else if (!strncmpi(bp, "lawful ", 7))
3265 al = A_LAWFUL;
3266 else if (!strncmpi(bp, "unaligned ", 10))
3267 al = A_NONE;
3268 else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
3269 al = (!rn2(6)) ? A_NONE : rn2((int) A_LAWFUL + 2) - 1;
3270 lev->altarmask = Align2amask(al);
3271 pline("%s altar.", An(align_str(al)));
3272 newsym(x, y);
3273 return &zeroobj;
3276 if (!BSTRCMPI(bp, p - 5, "grave")
3277 || !BSTRCMPI(bp, p - 9, "headstone")) {
3278 make_grave(x, y, (char *) 0);
3279 pline("%s.", IS_GRAVE(lev->typ) ? "A grave"
3280 : "Can't place a grave here");
3281 newsym(x, y);
3282 return &zeroobj;
3285 if (!BSTRCMPI(bp, p - 4, "tree")) {
3286 lev->typ = TREE;
3287 pline("A tree.");
3288 newsym(x, y);
3289 block_point(x, y);
3290 return &zeroobj;
3293 if (!BSTRCMPI(bp, p - 4, "bars")) {
3294 lev->typ = IRONBARS;
3295 pline("Iron bars.");
3296 newsym(x, y);
3297 return &zeroobj;
3301 if (!oclass && !typ) {
3302 if (!strncmpi(bp, "polearm", 7)) {
3303 typ = rnd_otyp_by_wpnskill(P_POLEARMS);
3304 goto typfnd;
3305 } else if (!strncmpi(bp, "hammer", 6)) {
3306 typ = rnd_otyp_by_wpnskill(P_HAMMER);
3307 goto typfnd;
3311 if (!oclass)
3312 return ((struct obj *) 0);
3313 any:
3314 if (!oclass)
3315 oclass = wrpsym[rn2((int) sizeof(wrpsym))];
3316 typfnd:
3317 if (typ)
3318 oclass = objects[typ].oc_class;
3320 /* handle some objects that are only allowed in wizard mode */
3321 if (typ && !wizard) {
3322 switch (typ) {
3323 case AMULET_OF_YENDOR:
3324 typ = FAKE_AMULET_OF_YENDOR;
3325 break;
3326 case CANDELABRUM_OF_INVOCATION:
3327 typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
3328 break;
3329 case BELL_OF_OPENING:
3330 typ = BELL;
3331 break;
3332 case SPE_BOOK_OF_THE_DEAD:
3333 typ = SPE_BLANK_PAPER;
3334 break;
3335 case MAGIC_LAMP:
3336 typ = OIL_LAMP;
3337 break;
3338 default:
3339 /* catch any other non-wishable objects (venom) */
3340 if (objects[typ].oc_nowish)
3341 return (struct obj *) 0;
3342 break;
3347 * Create the object, then fine-tune it.
3349 otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE);
3350 typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */
3352 if (islit && (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN
3353 || Is_candle(otmp) || typ == POT_OIL)) {
3354 place_object(otmp, u.ux, u.uy); /* make it viable light source */
3355 begin_burn(otmp, FALSE);
3356 obj_extract_self(otmp); /* now release it for caller's use */
3359 /* if player specified a reasonable count, maybe honor it */
3360 if (cnt > 0 && objects[typ].oc_merge
3361 && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp))
3362 || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp))
3363 || typ == ROCK || is_missile(otmp)))))
3364 otmp->quan = (long) cnt;
3366 if (oclass == VENOM_CLASS)
3367 otmp->spe = 1;
3369 if (spesgn == 0) {
3370 spe = otmp->spe;
3371 } else if (wizard) {
3372 ; /* no alteration to spe */
3373 } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS
3374 || is_weptool(otmp)
3375 || (oclass == RING_CLASS && objects[typ].oc_charged)) {
3376 if (spe > rnd(5) && spe > otmp->spe)
3377 spe = 0;
3378 if (spe > 2 && Luck < 0)
3379 spesgn = -1;
3380 } else {
3381 if (oclass == WAND_CLASS) {
3382 if (spe > 1 && spesgn == -1)
3383 spe = 1;
3384 } else {
3385 if (spe > 0 && spesgn == -1)
3386 spe = 0;
3388 if (spe > otmp->spe)
3389 spe = otmp->spe;
3392 if (spesgn == -1)
3393 spe = -spe;
3395 /* set otmp->spe. This may, or may not, use spe... */
3396 switch (typ) {
3397 case TIN:
3398 if (contents == EMPTY) {
3399 otmp->corpsenm = NON_PM;
3400 otmp->spe = 0;
3401 } else if (contents == SPINACH) {
3402 otmp->corpsenm = NON_PM;
3403 otmp->spe = 1;
3405 break;
3406 case TOWEL:
3407 if (wetness)
3408 otmp->spe = wetness;
3409 break;
3410 case SLIME_MOLD:
3411 otmp->spe = ftype;
3412 /* Fall through */
3413 case SKELETON_KEY:
3414 case CHEST:
3415 case LARGE_BOX:
3416 case HEAVY_IRON_BALL:
3417 case IRON_CHAIN:
3418 case STATUE:
3419 /* otmp->cobj already done in mksobj() */
3420 break;
3421 #ifdef MAIL
3422 case SCR_MAIL:
3423 /* 0: delivered in-game via external event (or randomly for fake mail);
3424 1: from bones or wishing; 2: written with marker */
3425 otmp->spe = 1;
3426 break;
3427 #endif
3428 case WAN_WISHING:
3429 if (!wizard) {
3430 otmp->spe = (rn2(10) ? -1 : 0);
3431 break;
3433 /* fall through, if wizard */
3434 default:
3435 otmp->spe = spe;
3438 /* set otmp->corpsenm or dragon scale [mail] */
3439 if (mntmp >= LOW_PM) {
3440 if (mntmp == PM_LONG_WORM_TAIL)
3441 mntmp = PM_LONG_WORM;
3443 switch (typ) {
3444 case TIN:
3445 otmp->spe = 0; /* No spinach */
3446 if (dead_species(mntmp, FALSE)) {
3447 otmp->corpsenm = NON_PM; /* it's empty */
3448 } else if (!(mons[mntmp].geno & G_UNIQ)
3449 && !(mvitals[mntmp].mvflags & G_NOCORPSE)
3450 && mons[mntmp].cnutrit != 0) {
3451 otmp->corpsenm = mntmp;
3453 break;
3454 case CORPSE:
3455 if (!(mons[mntmp].geno & G_UNIQ)
3456 && !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
3457 if (mons[mntmp].msound == MS_GUARDIAN)
3458 mntmp = genus(mntmp, 1);
3459 set_corpsenm(otmp, mntmp);
3461 break;
3462 case EGG:
3463 mntmp = can_be_hatched(mntmp);
3464 /* this also sets hatch timer if appropriate */
3465 set_corpsenm(otmp, mntmp);
3466 break;
3467 case FIGURINE:
3468 if (!(mons[mntmp].geno & G_UNIQ) && !is_human(&mons[mntmp])
3469 #ifdef MAIL
3470 && mntmp != PM_MAIL_DAEMON
3471 #endif
3473 otmp->corpsenm = mntmp;
3474 break;
3475 case STATUE:
3476 otmp->corpsenm = mntmp;
3477 if (Has_contents(otmp) && verysmall(&mons[mntmp]))
3478 delete_contents(otmp); /* no spellbook */
3479 otmp->spe = ishistoric ? STATUE_HISTORIC : 0;
3480 break;
3481 case SCALE_MAIL:
3482 /* Dragon mail - depends on the order of objects & dragons. */
3483 if (mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON)
3484 otmp->otyp = GRAY_DRAGON_SCALE_MAIL + mntmp - PM_GRAY_DRAGON;
3485 break;
3489 /* set blessed/cursed -- setting the fields directly is safe
3490 * since weight() is called below and addinv() will take care
3491 * of luck */
3492 if (iscursed) {
3493 curse(otmp);
3494 } else if (uncursed) {
3495 otmp->blessed = 0;
3496 otmp->cursed = (Luck < 0 && !wizard);
3497 } else if (blessed) {
3498 otmp->blessed = (Luck >= 0 || wizard);
3499 otmp->cursed = (Luck < 0 && !wizard);
3500 } else if (spesgn < 0) {
3501 curse(otmp);
3504 /* set eroded and erodeproof */
3505 if (erosion_matters(otmp)) {
3506 if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
3507 otmp->oeroded = eroded;
3508 if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
3509 otmp->oeroded2 = eroded2;
3511 * 3.6.1: earlier versions included `&& !eroded && !eroded2' here,
3512 * but damageproof combined with damaged is feasible (eroded
3513 * armor modified by confused reading of cursed destroy armor)
3514 * so don't prevent player from wishing for such a combination.
3516 if (erodeproof && (is_damageable(otmp) || otmp->otyp == CRYSKNIFE))
3517 otmp->oerodeproof = (Luck >= 0 || wizard);
3520 /* set otmp->recharged */
3521 if (oclass == WAND_CLASS) {
3522 /* prevent wishing abuse */
3523 if (otmp->otyp == WAN_WISHING && !wizard)
3524 rechrg = 1;
3525 otmp->recharged = (unsigned) rechrg;
3528 /* set poisoned */
3529 if (ispoisoned) {
3530 if (is_poisonable(otmp))
3531 otmp->opoisoned = (Luck >= 0);
3532 else if (oclass == FOOD_CLASS)
3533 /* try to taint by making it as old as possible */
3534 otmp->age = 1L;
3536 /* and [un]trapped */
3537 if (trapped) {
3538 if (Is_box(otmp) || typ == TIN)
3539 otmp->otrapped = (trapped == 1);
3542 if (isgreased)
3543 otmp->greased = 1;
3545 if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER)
3546 otmp->odiluted = 1;
3548 /* set tin variety */
3549 if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard))
3550 set_tin_variety(otmp, tvariety);
3552 if (name) {
3553 const char *aname;
3554 short objtyp;
3556 /* an artifact name might need capitalization fixing */
3557 aname = artifact_name(name, &objtyp);
3558 if (aname && objtyp == otmp->otyp)
3559 name = aname;
3561 /* 3.6 tribute - fix up novel */
3562 if (otmp->otyp == SPE_NOVEL) {
3563 const char *novelname;
3565 novelname = lookup_novel(name, &otmp->novelidx);
3566 if (novelname)
3567 name = novelname;
3570 otmp = oname(otmp, name);
3571 if (otmp->oartifact) {
3572 otmp->quan = 1L;
3573 u.uconduct.wisharti++; /* KMH, conduct */
3577 /* more wishing abuse: don't allow wishing for certain artifacts */
3578 /* and make them pay; charge them for the wish anyway! */
3579 if ((is_quest_artifact(otmp)
3580 || (otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) {
3581 artifact_exists(otmp, safe_oname(otmp), FALSE);
3582 obfree(otmp, (struct obj *) 0);
3583 otmp = &zeroobj;
3584 pline("For a moment, you feel %s in your %s, but it disappears!",
3585 something, makeplural(body_part(HAND)));
3588 if (halfeaten && otmp->oclass == FOOD_CLASS) {
3589 if (otmp->otyp == CORPSE)
3590 otmp->oeaten = mons[otmp->corpsenm].cnutrit;
3591 else
3592 otmp->oeaten = objects[otmp->otyp].oc_nutrition;
3593 /* (do this adjustment before setting up object's weight) */
3594 consume_oeaten(otmp, 1);
3596 otmp->owt = weight(otmp);
3597 if (very && otmp->otyp == HEAVY_IRON_BALL)
3598 otmp->owt += IRON_BALL_W_INCR;
3599 else if (gsize > 1 && otmp->globby)
3600 /* 0: unspecified => small; 1: small => keep default owt of 20;
3601 2: medium => 120; 3: large => 320; 4: very large => 520 */
3602 otmp->owt += 100 + (gsize - 2) * 200;
3604 return otmp;
3608 rnd_class(first, last)
3609 int first, last;
3611 int i, x, sum = 0;
3613 if (first == last)
3614 return first;
3615 for (i = first; i <= last; i++)
3616 sum += objects[i].oc_prob;
3617 if (!sum) /* all zero */
3618 return first + rn2(last - first + 1);
3619 x = rnd(sum);
3620 for (i = first; i <= last; i++)
3621 if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
3622 return i;
3623 return 0;
3626 STATIC_OVL const char *
3627 Japanese_item_name(i)
3628 int i;
3630 struct Jitem *j = Japanese_items;
3632 while (j->item) {
3633 if (i == j->item)
3634 return j->name;
3635 j++;
3637 return (const char *) 0;
3640 const char *
3641 suit_simple_name(suit)
3642 struct obj *suit;
3644 const char *suitnm, *esuitp;
3646 if (Is_dragon_mail(suit))
3647 return "dragon mail"; /* <color> dragon scale mail */
3648 else if (Is_dragon_scales(suit))
3649 return "dragon scales";
3650 suitnm = OBJ_NAME(objects[suit->otyp]);
3651 esuitp = eos((char *) suitnm);
3652 if (strlen(suitnm) > 5 && !strcmp(esuitp - 5, " mail"))
3653 return "mail"; /* most suits fall into this category */
3654 else if (strlen(suitnm) > 7 && !strcmp(esuitp - 7, " jacket"))
3655 return "jacket"; /* leather jacket */
3656 /* suit is lame but armor is ambiguous and body armor is absurd */
3657 return "suit";
3660 const char *
3661 cloak_simple_name(cloak)
3662 struct obj *cloak;
3664 if (cloak) {
3665 switch (cloak->otyp) {
3666 case ROBE:
3667 return "robe";
3668 case MUMMY_WRAPPING:
3669 return "wrapping";
3670 case ALCHEMY_SMOCK:
3671 return (objects[cloak->otyp].oc_name_known && cloak->dknown)
3672 ? "smock"
3673 : "apron";
3674 default:
3675 break;
3678 return "cloak";
3681 /* helm vs hat for messages */
3682 const char *
3683 helm_simple_name(helmet)
3684 struct obj *helmet;
3687 * There is some wiggle room here; the result has been chosen
3688 * for consistency with the "protected by hard helmet" messages
3689 * given for various bonks on the head: headgear that provides
3690 * such protection is a "helm", that which doesn't is a "hat".
3692 * elven leather helm / leather hat -> hat
3693 * dwarvish iron helm / hard hat -> helm
3694 * The rest are completely straightforward:
3695 * fedora, cornuthaum, dunce cap -> hat
3696 * all other types of helmets -> helm
3698 return (helmet && !is_metallic(helmet)) ? "hat" : "helm";
3701 const char *
3702 mimic_obj_name(mtmp)
3703 struct monst *mtmp;
3705 if (mtmp->m_ap_type == M_AP_OBJECT) {
3706 if (mtmp->mappearance == GOLD_PIECE)
3707 return "gold";
3708 if (mtmp->mappearance != STRANGE_OBJECT)
3709 return simple_typename(mtmp->mappearance);
3711 return "whatcha-may-callit";
3715 * Construct a query prompt string, based around an object name, which is
3716 * guaranteed to fit within [QBUFSZ]. Takes an optional prefix, three
3717 * choices for filling in the middle (two object formatting functions and a
3718 * last resort literal which should be very short), and an optional suffix.
3720 char *
3721 safe_qbuf(qbuf, qprefix, qsuffix, obj, func, altfunc, lastR)
3722 char *qbuf; /* output buffer */
3723 const char *qprefix, *qsuffix;
3724 struct obj *obj;
3725 char *FDECL((*func), (OBJ_P)), *FDECL((*altfunc), (OBJ_P));
3726 const char *lastR;
3728 char *bufp, *endp;
3729 /* convert size_t (or int for ancient systems) to ordinary unsigned */
3730 unsigned len, lenlimit,
3731 len_qpfx = (unsigned) (qprefix ? strlen(qprefix) : 0),
3732 len_qsfx = (unsigned) (qsuffix ? strlen(qsuffix) : 0),
3733 len_lastR = (unsigned) strlen(lastR);
3735 lenlimit = QBUFSZ - 1;
3736 endp = qbuf + lenlimit;
3737 /* sanity check, aimed mainly at paniclog (it's conceivable for
3738 the result of short_oname() to be shorter than the length of
3739 the last resort string, but we ignore that possibility here) */
3740 if (len_qpfx > lenlimit)
3741 impossible("safe_qbuf: prefix too long (%u characters).", len_qpfx);
3742 else if (len_qpfx + len_qsfx > lenlimit)
3743 impossible("safe_qbuf: suffix too long (%u + %u characters).",
3744 len_qpfx, len_qsfx);
3745 else if (len_qpfx + len_lastR + len_qsfx > lenlimit)
3746 impossible("safe_qbuf: filler too long (%u + %u + %u characters).",
3747 len_qpfx, len_lastR, len_qsfx);
3749 /* the output buffer might be the same as the prefix if caller
3750 has already partially filled it */
3751 if (qbuf == qprefix) {
3752 /* prefix is already in the buffer */
3753 *endp = '\0';
3754 } else if (qprefix) {
3755 /* put prefix into the buffer */
3756 (void) strncpy(qbuf, qprefix, lenlimit);
3757 *endp = '\0';
3758 } else {
3759 /* no prefix; output buffer starts out empty */
3760 qbuf[0] = '\0';
3762 len = (unsigned) strlen(qbuf);
3764 if (len + len_lastR + len_qsfx > lenlimit) {
3765 /* too long; skip formatting, last resort output is truncated */
3766 if (len < lenlimit) {
3767 (void) strncpy(&qbuf[len], lastR, lenlimit - len);
3768 *endp = '\0';
3769 len = (unsigned) strlen(qbuf);
3770 if (qsuffix && len < lenlimit) {
3771 (void) strncpy(&qbuf[len], qsuffix, lenlimit - len);
3772 *endp = '\0';
3773 /* len = (unsigned) strlen(qbuf); */
3776 } else {
3777 /* suffix and last resort are guaranteed to fit */
3778 len += len_qsfx; /* include the pending suffix */
3779 /* format the object */
3780 bufp = short_oname(obj, func, altfunc, lenlimit - len);
3781 if (len + strlen(bufp) <= lenlimit)
3782 Strcat(qbuf, bufp); /* formatted name fits */
3783 else
3784 Strcat(qbuf, lastR); /* use last resort */
3785 releaseobuf(bufp);
3787 if (qsuffix)
3788 Strcat(qbuf, qsuffix);
3790 /* assert( strlen(qbuf) < QBUFSZ ); */
3791 return qbuf;
3794 /*objnam.c*/