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