Use define for iron ball weight increment
[aNetHack.git] / src / objnam.c
blob8e98e07b88c8d6389db22a31457c694c14e97d1d
1 /* NetHack 3.6 objnam.c $NHDT-Date: 1452043772 2016/01/06 01:29:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.163 $ */
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 boolean FDECL(wishymatch, (const char *, const char *, BOOLEAN_P));
15 STATIC_DCL char *NDECL(nextobuf);
16 STATIC_DCL void FDECL(releaseobuf, (char *));
17 STATIC_DCL char *FDECL(minimal_xname, (struct obj *));
18 STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *));
19 STATIC_DCL boolean
20 FDECL(singplur_lookup, (char *, char *, BOOLEAN_P, const char *const *));
21 STATIC_DCL char *FDECL(singplur_compound, (char *));
22 STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
24 struct Jitem {
25 int item;
26 const char *name;
29 #define BSTRCMPI(base, ptr, str) ((ptr) < base || strcmpi((ptr), str))
30 #define BSTRNCMPI(base, ptr, str, num) \
31 ((ptr) < base || strncmpi((ptr), str, num))
32 #define Strcasecpy(dst, src) (void) strcasecpy(dst, src)
34 /* true for gems/rocks that should have " stone" appended to their names */
35 #define GemStone(typ) \
36 (typ == FLINT \
37 || (objects[typ].oc_material == GEMSTONE \
38 && (typ != DILITHIUM_CRYSTAL && typ != RUBY && typ != DIAMOND \
39 && typ != SAPPHIRE && typ != BLACK_OPAL && typ != EMERALD \
40 && typ != OPAL)))
42 STATIC_OVL struct Jitem Japanese_items[] = { { SHORT_SWORD, "wakizashi" },
43 { BROADSWORD, "ninja-to" },
44 { FLAIL, "nunchaku" },
45 { GLAIVE, "naginata" },
46 { LOCK_PICK, "osaku" },
47 { WOODEN_HARP, "koto" },
48 { KNIFE, "shito" },
49 { PLATE_MAIL, "tanko" },
50 { HELMET, "kabuto" },
51 { LEATHER_GLOVES, "yugake" },
52 { FOOD_RATION, "gunyoki" },
53 { POT_BOOZE, "sake" },
54 { 0, "" } };
56 STATIC_DCL const char *FDECL(Japanese_item_name, (int i));
58 STATIC_OVL char *
59 strprepend(s, pref)
60 register char *s;
61 register const char *pref;
63 register int i = (int) strlen(pref);
65 if (i > PREFIX) {
66 impossible("PREFIX too short (for %d).", i);
67 return s;
69 s -= i;
70 (void) strncpy(s, pref, i); /* do not copy trailing 0 */
71 return s;
74 /* manage a pool of BUFSZ buffers, so callers don't have to */
75 static char NEARDATA obufs[NUMOBUF][BUFSZ];
76 static int obufidx = 0;
78 STATIC_OVL char *
79 nextobuf()
81 obufidx = (obufidx + 1) % NUMOBUF;
82 return obufs[obufidx];
85 /* put the most recently allocated buffer back if possible */
86 STATIC_OVL void
87 releaseobuf(bufp)
88 char *bufp;
90 /* caller may not know whether bufp is the most recently allocated
91 buffer; if it isn't, do nothing */
92 if (bufp == obufs[obufidx])
93 obufidx = (obufidx - 1 + NUMOBUF) % NUMOBUF;
96 char *
97 obj_typename(otyp)
98 register int otyp;
100 char *buf = nextobuf();
101 register struct objclass *ocl = &objects[otyp];
102 register const char *actualn = OBJ_NAME(*ocl);
103 register const char *dn = OBJ_DESCR(*ocl);
104 register const char *un = ocl->oc_uname;
105 register int nn = ocl->oc_name_known;
107 if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
108 actualn = Japanese_item_name(otyp);
109 switch (ocl->oc_class) {
110 case COIN_CLASS:
111 Strcpy(buf, "coin");
112 break;
113 case POTION_CLASS:
114 Strcpy(buf, "potion");
115 break;
116 case SCROLL_CLASS:
117 Strcpy(buf, "scroll");
118 break;
119 case WAND_CLASS:
120 Strcpy(buf, "wand");
121 break;
122 case SPBOOK_CLASS:
123 if (otyp != SPE_NOVEL) {
124 Strcpy(buf, "spellbook");
125 } else {
126 Strcpy(buf, !nn ? "book" : "novel");
127 nn = 0;
129 break;
130 case RING_CLASS:
131 Strcpy(buf, "ring");
132 break;
133 case AMULET_CLASS:
134 if (nn)
135 Strcpy(buf, actualn);
136 else
137 Strcpy(buf, "amulet");
138 if (un)
139 Sprintf(eos(buf), " called %s", un);
140 if (dn)
141 Sprintf(eos(buf), " (%s)", dn);
142 return buf;
143 default:
144 if (nn) {
145 Strcpy(buf, actualn);
146 if (GemStone(otyp))
147 Strcat(buf, " stone");
148 if (un)
149 Sprintf(eos(buf), " called %s", un);
150 if (dn)
151 Sprintf(eos(buf), " (%s)", dn);
152 } else {
153 Strcpy(buf, dn ? dn : actualn);
154 if (ocl->oc_class == GEM_CLASS)
155 Strcat(buf,
156 (ocl->oc_material == MINERAL) ? " stone" : " gem");
157 if (un)
158 Sprintf(eos(buf), " called %s", un);
160 return buf;
162 /* here for ring/scroll/potion/wand */
163 if (nn) {
164 if (ocl->oc_unique)
165 Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */
166 else
167 Sprintf(eos(buf), " of %s", actualn);
169 if (un)
170 Sprintf(eos(buf), " called %s", un);
171 if (dn)
172 Sprintf(eos(buf), " (%s)", dn);
173 return buf;
176 /* less verbose result than obj_typename(); either the actual name
177 or the description (but not both); user-assigned name is ignored */
178 char *
179 simple_typename(otyp)
180 int otyp;
182 char *bufp, *pp, *save_uname = objects[otyp].oc_uname;
184 objects[otyp].oc_uname = 0; /* suppress any name given by user */
185 bufp = obj_typename(otyp);
186 objects[otyp].oc_uname = save_uname;
187 if ((pp = strstri(bufp, " (")) != 0)
188 *pp = '\0'; /* strip the appended description */
189 return bufp;
192 boolean
193 obj_is_pname(obj)
194 struct obj *obj;
196 if (!obj->oartifact || !has_oname(obj))
197 return FALSE;
198 if (!program_state.gameover && !iflags.override_ID) {
199 if (not_fully_identified(obj))
200 return FALSE;
202 return TRUE;
205 /* used by distant_name() to pass extra information to xname_flags();
206 it would be much cleaner if this were a parameter, but that would
207 require all of the xname() and doname() calls to be modified */
208 static int distantname = 0;
210 /* Give the name of an object seen at a distance. Unlike xname/doname,
211 * we don't want to set dknown if it's not set already.
213 char *
214 distant_name(obj, func)
215 struct obj *obj;
216 char *FDECL((*func), (OBJ_P));
218 char *str;
220 /* 3.6.1: this used to save Blind, set it, make the call, then restore
221 * the saved value; but the Eyes of the Overworld override blindness
222 * and let characters wearing them get dknown set for distant items.
224 * TODO? if the hero is wearing those Eyes, figure out whether the
225 * object is within X-ray radius and only treat it as distant when
226 * beyond that radius. Logic is iffy but result might be interesting.
228 ++distantname;
229 str = (*func)(obj);
230 --distantname;
231 return str;
234 /* convert player specified fruit name into corresponding fruit juice name
235 ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
236 char *
237 fruitname(juice)
238 boolean juice; /* whether or not to append " juice" to the name */
240 char *buf = nextobuf();
241 const char *fruit_nam = strstri(pl_fruit, " of ");
243 if (fruit_nam)
244 fruit_nam += 4; /* skip past " of " */
245 else
246 fruit_nam = pl_fruit; /* use it as is */
248 Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : "");
249 return buf;
252 char *
253 xname(obj)
254 struct obj *obj;
256 return xname_flags(obj, CXN_NORMAL);
259 char *
260 xname_flags(obj, cxn_flags)
261 register struct obj *obj;
262 unsigned cxn_flags; /* bitmask of CXN_xxx values */
264 register char *buf;
265 register int typ = obj->otyp;
266 register struct objclass *ocl = &objects[typ];
267 int nn = ocl->oc_name_known, omndx = obj->corpsenm;
268 const char *actualn = OBJ_NAME(*ocl);
269 const char *dn = OBJ_DESCR(*ocl);
270 const char *un = ocl->oc_uname;
271 boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR);
272 boolean known, dknown, bknown;
274 buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */
275 if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
276 actualn = Japanese_item_name(typ);
278 buf[0] = '\0';
280 * clean up known when it's tied to oc_name_known, eg after AD_DRIN
281 * This is only required for unique objects since the article
282 * printed for the object is tied to the combination of the two
283 * and printing the wrong article gives away information.
285 if (!nn && ocl->oc_uses_known && ocl->oc_unique)
286 obj->known = 0;
287 if (!Blind && !distantname)
288 obj->dknown = TRUE;
289 if (Role_if(PM_PRIEST))
290 obj->bknown = TRUE;
292 if (iflags.override_ID) {
293 known = dknown = bknown = TRUE;
294 nn = 1;
295 } else {
296 known = obj->known;
297 dknown = obj->dknown;
298 bknown = obj->bknown;
301 if (obj_is_pname(obj))
302 goto nameit;
303 switch (obj->oclass) {
304 case AMULET_CLASS:
305 if (!dknown)
306 Strcpy(buf, "amulet");
307 else if (typ == AMULET_OF_YENDOR || typ == FAKE_AMULET_OF_YENDOR)
308 /* each must be identified individually */
309 Strcpy(buf, known ? actualn : dn);
310 else if (nn)
311 Strcpy(buf, actualn);
312 else if (un)
313 Sprintf(buf, "amulet called %s", un);
314 else
315 Sprintf(buf, "%s amulet", dn);
316 break;
317 case WEAPON_CLASS:
318 if (is_poisonable(obj) && obj->opoisoned)
319 Strcpy(buf, "poisoned ");
320 case VENOM_CLASS:
321 case TOOL_CLASS:
322 if (typ == LENSES)
323 Strcpy(buf, "pair of ");
324 else if (is_wet_towel(obj))
325 Strcpy(buf, (obj->spe < 3) ? "moist " : "wet ");
327 if (!dknown)
328 Strcat(buf, dn ? dn : actualn);
329 else if (nn)
330 Strcat(buf, actualn);
331 else if (un) {
332 Strcat(buf, dn ? dn : actualn);
333 Strcat(buf, " called ");
334 Strcat(buf, un);
335 } else
336 Strcat(buf, dn ? dn : actualn);
337 /* If we use an() here we'd have to remember never to use */
338 /* it whenever calling doname() or xname(). */
339 if (typ == FIGURINE && omndx != NON_PM) {
340 Sprintf(eos(buf), " of a%s %s",
341 index(vowels, *mons[omndx].mname) ? "n" : "",
342 mons[omndx].mname);
343 } else if (is_wet_towel(obj)) {
344 if (wizard)
345 Sprintf(eos(buf), " (%d)", obj->spe);
347 break;
348 case ARMOR_CLASS:
349 /* depends on order of the dragon scales objects */
350 if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
351 Sprintf(buf, "set of %s", actualn);
352 break;
354 if (is_boots(obj) || is_gloves(obj))
355 Strcpy(buf, "pair of ");
357 if (obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
358 && !dknown) {
359 Strcpy(buf, "shield");
360 break;
362 if (obj->otyp == SHIELD_OF_REFLECTION && !dknown) {
363 Strcpy(buf, "smooth shield");
364 break;
367 if (nn)
368 Strcat(buf, actualn);
369 else if (un) {
370 if (is_boots(obj))
371 Strcat(buf, "boots");
372 else if (is_gloves(obj))
373 Strcat(buf, "gloves");
374 else if (is_cloak(obj))
375 Strcpy(buf, "cloak");
376 else if (is_helmet(obj))
377 Strcpy(buf, "helmet");
378 else if (is_shield(obj))
379 Strcpy(buf, "shield");
380 else
381 Strcpy(buf, "armor");
382 Strcat(buf, " called ");
383 Strcat(buf, un);
384 } else
385 Strcat(buf, dn);
386 break;
387 case FOOD_CLASS:
388 if (typ == SLIME_MOLD) {
389 register struct fruit *f;
391 for (f = ffruit; f; f = f->nextf) {
392 if (f->fid == obj->spe) {
393 Strcpy(buf, f->fname);
394 break;
397 if (!f) {
398 impossible("Bad fruit #%d?", obj->spe);
399 Strcpy(buf, "fruit");
400 } else if (pluralize) {
401 /* ick; already pluralized fruit names
402 are allowed--we want to try to avoid
403 adding a redundant plural suffix */
404 Strcpy(buf, makeplural(makesingular(buf)));
405 pluralize = FALSE;
407 break;
409 if (Is_pudding(obj)) {
410 Sprintf(buf, "%s%s",
411 (obj->owt < 100)
412 ? "small "
413 : (obj->owt > 500)
414 ? "very large "
415 : (obj->owt > 300)
416 ? "large "
417 : "",
418 actualn);
419 break;
422 Strcpy(buf, actualn);
423 if (typ == TIN && known)
424 tin_details(obj, omndx, buf);
425 break;
426 case COIN_CLASS:
427 case CHAIN_CLASS:
428 Strcpy(buf, actualn);
429 break;
430 case ROCK_CLASS:
431 if (typ == STATUE && omndx != NON_PM)
432 Sprintf(buf, "%s%s of %s%s",
433 (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC))
434 ? "historic "
435 : "",
436 actualn,
437 type_is_pname(&mons[omndx])
438 ? ""
439 : the_unique_pm(&mons[omndx])
440 ? "the "
441 : index(vowels, *mons[omndx].mname)
442 ? "an "
443 : "a ",
444 mons[omndx].mname);
445 else
446 Strcpy(buf, actualn);
447 break;
448 case BALL_CLASS:
449 Sprintf(buf, "%sheavy iron ball",
450 (obj->owt > ocl->oc_weight) ? "very " : "");
451 break;
452 case POTION_CLASS:
453 if (dknown && obj->odiluted)
454 Strcpy(buf, "diluted ");
455 if (nn || un || !dknown) {
456 Strcat(buf, "potion");
457 if (!dknown)
458 break;
459 if (nn) {
460 Strcat(buf, " of ");
461 if (typ == POT_WATER && bknown
462 && (obj->blessed || obj->cursed)) {
463 Strcat(buf, obj->blessed ? "holy " : "unholy ");
465 Strcat(buf, actualn);
466 } else {
467 Strcat(buf, " called ");
468 Strcat(buf, un);
470 } else {
471 Strcat(buf, dn);
472 Strcat(buf, " potion");
474 break;
475 case SCROLL_CLASS:
476 Strcpy(buf, "scroll");
477 if (!dknown)
478 break;
479 if (nn) {
480 Strcat(buf, " of ");
481 Strcat(buf, actualn);
482 } else if (un) {
483 Strcat(buf, " called ");
484 Strcat(buf, un);
485 } else if (ocl->oc_magic) {
486 Strcat(buf, " labeled ");
487 Strcat(buf, dn);
488 } else {
489 Strcpy(buf, dn);
490 Strcat(buf, " scroll");
492 break;
493 case WAND_CLASS:
494 if (!dknown)
495 Strcpy(buf, "wand");
496 else if (nn)
497 Sprintf(buf, "wand of %s", actualn);
498 else if (un)
499 Sprintf(buf, "wand called %s", un);
500 else
501 Sprintf(buf, "%s wand", dn);
502 break;
503 case SPBOOK_CLASS:
504 if (typ == SPE_NOVEL) { /* 3.6 tribute */
505 if (!dknown)
506 Strcpy(buf, "book");
507 else if (nn)
508 Strcpy(buf, actualn);
509 else if (un)
510 Sprintf(buf, "novel called %s", un);
511 else
512 Sprintf(buf, "%s book", dn);
513 break;
514 /* end of tribute */
515 } else if (!dknown) {
516 Strcpy(buf, "spellbook");
517 } else if (nn) {
518 if (typ != SPE_BOOK_OF_THE_DEAD)
519 Strcpy(buf, "spellbook of ");
520 Strcat(buf, actualn);
521 } else if (un) {
522 Sprintf(buf, "spellbook called %s", un);
523 } else
524 Sprintf(buf, "%s spellbook", dn);
525 break;
526 case RING_CLASS:
527 if (!dknown)
528 Strcpy(buf, "ring");
529 else if (nn)
530 Sprintf(buf, "ring of %s", actualn);
531 else if (un)
532 Sprintf(buf, "ring called %s", un);
533 else
534 Sprintf(buf, "%s ring", dn);
535 break;
536 case GEM_CLASS: {
537 const char *rock = (ocl->oc_material == MINERAL) ? "stone" : "gem";
539 if (!dknown) {
540 Strcpy(buf, rock);
541 } else if (!nn) {
542 if (un)
543 Sprintf(buf, "%s called %s", rock, un);
544 else
545 Sprintf(buf, "%s %s", dn, rock);
546 } else {
547 Strcpy(buf, actualn);
548 if (GemStone(typ))
549 Strcat(buf, " stone");
551 break;
553 default:
554 Sprintf(buf, "glorkum %d %d %d", obj->oclass, typ, obj->spe);
556 if (pluralize)
557 Strcpy(buf, makeplural(buf));
559 if (obj->otyp == T_SHIRT && program_state.gameover) {
560 char tmpbuf[BUFSZ];
562 Sprintf(eos(buf), " with text \"%s\"", tshirt_text(obj, tmpbuf));
565 if (has_oname(obj) && dknown) {
566 Strcat(buf, " named ");
567 nameit:
568 Strcat(buf, ONAME(obj));
571 if (!strncmpi(buf, "the ", 4))
572 buf += 4;
573 return buf;
576 /* similar to simple_typename but minimal_xname operates on a particular
577 object rather than its general type; it formats the most basic info:
578 potion -- if description not known
579 brown potion -- if oc_name_known not set
580 potion of object detection -- if discovered
582 static char *
583 minimal_xname(obj)
584 struct obj *obj;
586 char *bufp;
587 struct obj bareobj;
588 struct objclass saveobcls;
589 int otyp = obj->otyp;
591 /* suppress user-supplied name */
592 saveobcls.oc_uname = objects[otyp].oc_uname;
593 objects[otyp].oc_uname = 0;
594 /* suppress actual name if object's description is unknown */
595 saveobcls.oc_name_known = objects[otyp].oc_name_known;
596 if (!obj->dknown)
597 objects[otyp].oc_name_known = 0;
599 /* caveat: this makes a lot of assumptions about which fields
600 are required in order for xname() to yield a sensible result */
601 bareobj = zeroobj;
602 bareobj.otyp = otyp;
603 bareobj.oclass = obj->oclass;
604 bareobj.dknown = obj->dknown;
605 /* suppress known except for amulets (needed for fakes and real A-of-Y) */
606 bareobj.known = (obj->oclass == AMULET_CLASS)
607 ? obj->known
608 /* default is "on" for types which don't use it */
609 : !objects[otyp].oc_uses_known;
610 bareobj.quan = 1L; /* don't want plural */
611 bareobj.corpsenm = NON_PM; /* suppress statue and figurine details */
612 /* but suppressing fruit details leads to "bad fruit #0"
613 [perhaps we should force "slime mold" rather than use xname?] */
614 if (obj->otyp == SLIME_MOLD)
615 bareobj.spe = obj->spe;
617 bufp = distant_name(&bareobj, xname); /* xname(&bareobj) */
618 if (!strncmp(bufp, "uncursed ", 9))
619 bufp += 9; /* Role_if(PM_PRIEST) */
621 objects[otyp].oc_uname = saveobcls.oc_uname;
622 objects[otyp].oc_name_known = saveobcls.oc_name_known;
623 return bufp;
626 /* xname() output augmented for multishot missile feedback */
627 char *
628 mshot_xname(obj)
629 struct obj *obj;
631 char tmpbuf[BUFSZ];
632 char *onm = xname(obj);
634 if (m_shot.n > 1 && m_shot.o == obj->otyp) {
635 /* "the Nth arrow"; value will eventually be passed to an() or
636 The(), both of which correctly handle this "the " prefix */
637 Sprintf(tmpbuf, "the %d%s ", m_shot.i, ordin(m_shot.i));
638 onm = strprepend(onm, tmpbuf);
640 return onm;
643 /* used for naming "the unique_item" instead of "a unique_item" */
644 boolean
645 the_unique_obj(obj)
646 struct obj *obj;
648 boolean known = (obj->known || iflags.override_ID);
650 if (!obj->dknown && !iflags.override_ID)
651 return FALSE;
652 else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !known)
653 return TRUE; /* lie */
654 else
655 return (boolean) (objects[obj->otyp].oc_unique
656 && (known || obj->otyp == AMULET_OF_YENDOR));
659 /* should monster type be prefixed with "the"? (mostly used for corpses) */
660 boolean
661 the_unique_pm(ptr)
662 struct permonst *ptr;
664 boolean uniq;
666 /* even though monsters with personal names are unique, we want to
667 describe them as "Name" rather than "the Name" */
668 if (type_is_pname(ptr))
669 return FALSE;
671 uniq = (ptr->geno & G_UNIQ) ? TRUE : FALSE;
672 /* high priest is unique if it includes "of <deity>", otherwise not
673 (caller needs to handle the 1st possibility; we assume the 2nd);
674 worm tail should be irrelevant but is included for completeness */
675 if (ptr == &mons[PM_HIGH_PRIEST] || ptr == &mons[PM_LONG_WORM_TAIL])
676 uniq = FALSE;
677 /* Wizard no longer needs this; he's flagged as unique these days */
678 if (ptr == &mons[PM_WIZARD_OF_YENDOR])
679 uniq = TRUE;
680 return uniq;
683 STATIC_OVL void
684 add_erosion_words(obj, prefix)
685 struct obj *obj;
686 char *prefix;
688 boolean iscrys = (obj->otyp == CRYSKNIFE);
689 boolean rknown;
691 rknown = (iflags.override_ID == 0) ? obj->rknown : TRUE;
693 if (!is_damageable(obj) && !iscrys)
694 return;
696 /* The only cases where any of these bits do double duty are for
697 * rotted food and diluted potions, which are all not is_damageable().
699 if (obj->oeroded && !iscrys) {
700 switch (obj->oeroded) {
701 case 2:
702 Strcat(prefix, "very ");
703 break;
704 case 3:
705 Strcat(prefix, "thoroughly ");
706 break;
708 Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt ");
710 if (obj->oeroded2 && !iscrys) {
711 switch (obj->oeroded2) {
712 case 2:
713 Strcat(prefix, "very ");
714 break;
715 case 3:
716 Strcat(prefix, "thoroughly ");
717 break;
719 Strcat(prefix, is_corrodeable(obj) ? "corroded " : "rotted ");
721 if (rknown && obj->oerodeproof)
722 Strcat(prefix, iscrys
723 ? "fixed "
724 : is_rustprone(obj)
725 ? "rustproof "
726 : is_corrodeable(obj)
727 ? "corrodeproof " /* "stainless"? */
728 : is_flammable(obj)
729 ? "fireproof "
730 : "");
733 static char *
734 doname_base(obj, with_price)
735 register struct obj *obj;
736 boolean with_price;
738 boolean ispoisoned = FALSE;
739 boolean known, cknown, bknown, lknown;
740 int omndx = obj->corpsenm;
741 char prefix[PREFIX];
742 char tmpbuf[PREFIX + 1]; /* for when we have to add something at
743 the start of prefix instead of the
744 end (Strcat is used on the end) */
745 register char *bp = xname(obj);
747 if (iflags.override_ID) {
748 known = cknown = bknown = lknown = TRUE;
749 } else {
750 known = obj->known;
751 cknown = obj->cknown;
752 bknown = obj->bknown;
753 lknown = obj->lknown;
756 /* When using xname, we want "poisoned arrow", and when using
757 * doname, we want "poisoned +0 arrow". This kludge is about the only
758 * way to do it, at least until someone overhauls xname() and doname(),
759 * combining both into one function taking a parameter.
761 /* must check opoisoned--someone can have a weirdly-named fruit */
762 if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
763 bp += 9;
764 ispoisoned = TRUE;
767 if (obj->quan != 1L) {
768 Sprintf(prefix, "%ld ", obj->quan);
769 } else if (obj->otyp == CORPSE) {
770 /* skip article prefix for corpses [else corpse_xname()
771 would have to be taught how to strip it off again] */
772 *prefix = '\0';
773 } else if (obj_is_pname(obj) || the_unique_obj(obj)) {
774 if (!strncmpi(bp, "the ", 4))
775 bp += 4;
776 Strcpy(prefix, "the ");
777 } else {
778 Strcpy(prefix, "a ");
781 /* "empty" goes at the beginning, but item count goes at the end */
782 if (cknown
783 /* bag of tricks: include "empty" prefix if it's known to
784 be empty but its precise number of charges isn't known
785 (when that is known, suffix of "(n:0)" will be appended,
786 making the prefix be redundant; note that 'known' flag
787 isn't set when emptiness gets discovered because then
788 charging magic would yield known number of new charges) */
789 && (obj->otyp == BAG_OF_TRICKS
790 ? (obj->spe == 0 && !obj->known)
791 /* not bag of tricks: empty if container which has no contents */
792 : (Is_container(obj) || obj->otyp == STATUE)
793 && !Has_contents(obj)))
794 Strcat(prefix, "empty ");
796 if (bknown && obj->oclass != COIN_CLASS
797 && (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
798 || (!obj->cursed && !obj->blessed))) {
799 /* allow 'blessed clear potion' if we don't know it's holy water;
800 * always allow "uncursed potion of water"
802 if (obj->cursed)
803 Strcat(prefix, "cursed ");
804 else if (obj->blessed)
805 Strcat(prefix, "blessed ");
806 else if (!iflags.implicit_uncursed
807 /* For most items with charges or +/-, if you know how many
808 * charges are left or what the +/- is, then you must have
809 * totally identified the item, so "uncursed" is unnecessary,
810 * because an identified object not described as "blessed" or
811 * "cursed" must be uncursed.
813 * If the charges or +/- is not known, "uncursed" must be
814 * printed to avoid ambiguity between an item whose curse
815 * status is unknown, and an item known to be uncursed.
817 || ((!known || !objects[obj->otyp].oc_charged
818 || obj->oclass == ARMOR_CLASS
819 || obj->oclass == RING_CLASS)
820 #ifdef MAIL
821 && obj->otyp != SCR_MAIL
822 #endif
823 && obj->otyp != FAKE_AMULET_OF_YENDOR
824 && obj->otyp != AMULET_OF_YENDOR
825 && !Role_if(PM_PRIEST)))
826 Strcat(prefix, "uncursed ");
829 if (lknown && Is_box(obj)) {
830 if (obj->obroken)
831 /* 3.6.0 used "unlockable" here but that could be misunderstood
832 to mean "capable of being unlocked" rather than the intended
833 "not capable of being locked" */
834 Strcat(prefix, "broken ");
835 else if (obj->olocked)
836 Strcat(prefix, "locked ");
837 else
838 Strcat(prefix, "unlocked ");
841 if (obj->greased)
842 Strcat(prefix, "greased ");
844 if (cknown && Has_contents(obj)) {
845 /* we count all objects (obj->quantity); perhaps we should
846 count separate stacks instead (or even introduce a user
847 preference option to choose between the two alternatives)
848 since it's somewhat odd so see "containing 1002 items"
849 when there are 2 scrolls plus 1000 gold pieces */
850 long itemcount = count_contents(obj, FALSE, FALSE, TRUE);
852 Sprintf(eos(bp), " containing %ld item%s", itemcount,
853 plur(itemcount));
856 switch (obj->oclass) {
857 case AMULET_CLASS:
858 if (obj->owornmask & W_AMUL)
859 Strcat(bp, " (being worn)");
860 break;
861 case WEAPON_CLASS:
862 if (ispoisoned)
863 Strcat(prefix, "poisoned ");
864 plus:
865 add_erosion_words(obj, prefix);
866 if (known) {
867 Strcat(prefix, sitoa(obj->spe));
868 Strcat(prefix, " ");
870 break;
871 case ARMOR_CLASS:
872 if (obj->owornmask & W_ARMOR)
873 Strcat(bp, (obj == uskin) ? " (embedded in your skin)"
874 : " (being worn)");
875 goto plus;
876 case TOOL_CLASS:
877 /* weptools already get this done when we go to the +n code */
878 if (!is_weptool(obj))
879 add_erosion_words(obj, prefix);
880 if (obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) {
881 Strcat(bp, " (being worn)");
882 break;
884 if (obj->otyp == LEASH && obj->leashmon != 0) {
885 Strcat(bp, " (in use)");
886 break;
888 if (is_weptool(obj))
889 goto plus;
890 if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
891 if (!obj->spe)
892 Strcpy(tmpbuf, "no");
893 else
894 Sprintf(tmpbuf, "%d", obj->spe);
895 Sprintf(eos(bp), " (%s candle%s%s)", tmpbuf, plur(obj->spe),
896 !obj->lamplit ? " attached" : ", lit");
897 break;
898 } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
899 || obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
900 if (Is_candle(obj)
901 && obj->age < 20L * (long) objects[obj->otyp].oc_cost)
902 Strcat(prefix, "partly used ");
903 if (obj->lamplit)
904 Strcat(bp, " (lit)");
905 break;
907 if (objects[obj->otyp].oc_charged)
908 goto charges;
909 break;
910 case WAND_CLASS:
911 add_erosion_words(obj, prefix);
912 charges:
913 if (known)
914 Sprintf(eos(bp), " (%d:%d)", (int) obj->recharged, obj->spe);
915 break;
916 case POTION_CLASS:
917 if (obj->otyp == POT_OIL && obj->lamplit)
918 Strcat(bp, " (lit)");
919 break;
920 case RING_CLASS:
921 add_erosion_words(obj, prefix);
922 ring:
923 if (obj->owornmask & W_RINGR)
924 Strcat(bp, " (on right ");
925 if (obj->owornmask & W_RINGL)
926 Strcat(bp, " (on left ");
927 if (obj->owornmask & W_RING) {
928 Strcat(bp, body_part(HAND));
929 Strcat(bp, ")");
931 if (known && objects[obj->otyp].oc_charged) {
932 Strcat(prefix, sitoa(obj->spe));
933 Strcat(prefix, " ");
935 break;
936 case FOOD_CLASS:
937 if (obj->oeaten)
938 Strcat(prefix, "partly eaten ");
939 if (obj->otyp == CORPSE) {
940 Sprintf(prefix, "%s ",
941 corpse_xname(obj, prefix, CXN_ARTICLE | CXN_NOCORPSE));
942 } else if (obj->otyp == EGG) {
943 #if 0 /* corpses don't tell if they're stale either */
944 if (known && stale_egg(obj))
945 Strcat(prefix, "stale ");
946 #endif
947 if (omndx >= LOW_PM
948 && (known || (mvitals[omndx].mvflags & MV_KNOWS_EGG))) {
949 Strcat(prefix, mons[omndx].mname);
950 Strcat(prefix, " ");
951 if (obj->spe)
952 Strcat(bp, " (laid by you)");
955 if (obj->otyp == MEAT_RING)
956 goto ring;
957 break;
958 case BALL_CLASS:
959 case CHAIN_CLASS:
960 add_erosion_words(obj, prefix);
961 if (obj->owornmask & W_BALL)
962 Strcat(bp, " (chained to you)");
963 break;
966 if ((obj->owornmask & W_WEP) && !mrg_to_wielded) {
967 if (obj->quan != 1L) {
968 Strcat(bp, " (wielded)");
969 } else {
970 const char *hand_s = body_part(HAND);
972 if (bimanual(obj))
973 hand_s = makeplural(hand_s);
974 Sprintf(eos(bp), " (weapon in %s)", hand_s);
976 if (warn_obj_cnt && obj == uwep && (EWarn_of_mon & W_WEP) != 0L) {
977 /* presumably can be felt when blind */
978 Strcat(bp, " (glowing");
979 if (!Blind)
980 Sprintf(eos(bp), " %s", glow_color(obj->oartifact));
981 Strcat(bp, ")");
985 if (obj->owornmask & W_SWAPWEP) {
986 if (u.twoweap)
987 Sprintf(eos(bp), " (wielded in other %s)", body_part(HAND));
988 else
989 Strcat(bp, " (alternate weapon; not wielded)");
991 if (obj->owornmask & W_QUIVER) {
992 switch (obj->oclass) {
993 case WEAPON_CLASS:
994 if (is_ammo(obj)) {
995 if (objects[obj->otyp].oc_skill == -P_BOW) {
996 /* Ammo for a bow */
997 Strcat(bp, " (in quiver)");
998 break;
999 } else {
1000 /* Ammo not for a bow */
1001 Strcat(bp, " (in quiver pouch)");
1002 break;
1004 } else {
1005 /* Weapons not considered ammo */
1006 Strcat(bp, " (at the ready)");
1007 break;
1009 /* Small things and ammo not for a bow */
1010 case RING_CLASS:
1011 case AMULET_CLASS:
1012 case WAND_CLASS:
1013 case COIN_CLASS:
1014 case GEM_CLASS:
1015 Strcat(bp, " (in quiver pouch)");
1016 break;
1017 default: /* odd things */
1018 Strcat(bp, " (at the ready)");
1021 if (!iflags.suppress_price && is_unpaid(obj)) {
1022 long quotedprice = unpaid_cost(obj, TRUE);
1024 Sprintf(eos(bp), " (%s, %ld %s)",
1025 obj->unpaid ? "unpaid" : "contents",
1026 quotedprice, currency(quotedprice));
1027 } else if (with_price) {
1028 long price = get_cost_of_shop_item(obj);
1030 if (price > 0)
1031 Sprintf(eos(bp), " (%ld %s)", price, currency(price));
1033 if (!strncmp(prefix, "a ", 2)
1034 && index(vowels, *(prefix + 2) ? *(prefix + 2) : *bp)
1035 && (*(prefix + 2)
1036 || (strncmp(bp, "uranium", 7) && strncmp(bp, "unicorn", 7)
1037 && strncmp(bp, "eucalyptus", 10)))) {
1038 Strcpy(tmpbuf, prefix);
1039 Strcpy(prefix, "an ");
1040 Strcpy(prefix + 3, tmpbuf + 2);
1043 /* show weight for items (debug tourist info)
1044 * aum is stolen from Crawl's "Arbitrary Unit of Measure" */
1045 if (wizard && iflags.wizweight) {
1046 Sprintf(eos(bp), " (%d aum)", obj->owt);
1048 bp = strprepend(bp, prefix);
1049 return bp;
1052 char *
1053 doname(obj)
1054 register struct obj *obj;
1056 return doname_base(obj, FALSE);
1059 /* Name of object including price. */
1060 char *
1061 doname_with_price(obj)
1062 register struct obj *obj;
1064 return doname_base(obj, TRUE);
1067 /* used from invent.c */
1068 boolean
1069 not_fully_identified(otmp)
1070 register struct obj *otmp;
1072 /* gold doesn't have any interesting attributes [yet?] */
1073 if (otmp->oclass == COIN_CLASS)
1074 return FALSE; /* always fully ID'd */
1075 /* check fundamental ID hallmarks first */
1076 if (!otmp->known || !otmp->dknown
1077 #ifdef MAIL
1078 || (!otmp->bknown && otmp->otyp != SCR_MAIL)
1079 #else
1080 || !otmp->bknown
1081 #endif
1082 || !objects[otmp->otyp].oc_name_known)
1083 return TRUE;
1084 if ((!otmp->cknown && (Is_container(otmp) || otmp->otyp == STATUE))
1085 || (!otmp->lknown && Is_box(otmp)))
1086 return TRUE;
1087 if (otmp->oartifact && undiscovered_artifact(otmp->oartifact))
1088 return TRUE;
1089 /* otmp->rknown is the only item of interest if we reach here */
1091 * Note: if a revision ever allows scrolls to become fireproof or
1092 * rings to become shockproof, this checking will need to be revised.
1093 * `rknown' ID only matters if xname() will provide the info about it.
1095 if (otmp->rknown
1096 || (otmp->oclass != ARMOR_CLASS && otmp->oclass != WEAPON_CLASS
1097 && !is_weptool(otmp) /* (redundant) */
1098 && otmp->oclass != BALL_CLASS)) /* (useless) */
1099 return FALSE;
1100 else /* lack of `rknown' only matters for vulnerable objects */
1101 return (boolean) (is_rustprone(otmp) || is_corrodeable(otmp)
1102 || is_flammable(otmp));
1105 /* format a corpse name (xname() omits monster type; doname() calls us);
1106 eatcorpse() also uses us for death reason when eating tainted glob */
1107 char *
1108 corpse_xname(otmp, adjective, cxn_flags)
1109 struct obj *otmp;
1110 const char *adjective;
1111 unsigned cxn_flags; /* bitmask of CXN_xxx values */
1113 char *nambuf = nextobuf();
1114 int omndx = otmp->corpsenm;
1115 boolean ignore_quan = (cxn_flags & CXN_SINGULAR) != 0,
1116 /* suppress "the" from "the unique monster corpse" */
1117 no_prefix = (cxn_flags & CXN_NO_PFX) != 0,
1118 /* include "the" for "the woodchuck corpse */
1119 the_prefix = (cxn_flags & CXN_PFX_THE) != 0,
1120 /* include "an" for "an ogre corpse */
1121 any_prefix = (cxn_flags & CXN_ARTICLE) != 0,
1122 /* leave off suffix (do_name() appends "corpse" itself) */
1123 omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0,
1124 possessive = FALSE,
1125 glob = (otmp->otyp != CORPSE && otmp->globby);
1126 const char *mname;
1128 if (glob) {
1129 mname = OBJ_NAME(objects[otmp->otyp]); /* "glob of <monster>" */
1130 } else if (omndx == NON_PM) { /* paranoia */
1131 mname = "thing";
1132 /* [Possible enhancement: check whether corpse has monster traits
1133 attached in order to use priestname() for priests and minions.] */
1134 } else if (omndx == PM_ALIGNED_PRIEST) {
1135 /* avoid "aligned priest"; it just exposes internal details */
1136 mname = "priest";
1137 } else {
1138 mname = mons[omndx].mname;
1139 if (the_unique_pm(&mons[omndx]) || type_is_pname(&mons[omndx])) {
1140 mname = s_suffix(mname);
1141 possessive = TRUE;
1142 /* don't precede personal name like "Medusa" with an article */
1143 if (type_is_pname(&mons[omndx]))
1144 no_prefix = TRUE;
1145 /* always precede non-personal unique monster name like
1146 "Oracle" with "the" unless explicitly overridden */
1147 else if (the_unique_pm(&mons[omndx]) && !no_prefix)
1148 the_prefix = TRUE;
1151 if (no_prefix)
1152 the_prefix = any_prefix = FALSE;
1153 else if (the_prefix)
1154 any_prefix = FALSE; /* mutually exclusive */
1156 *nambuf = '\0';
1157 /* can't use the() the way we use an() below because any capitalized
1158 Name causes it to assume a personal name and return Name as-is;
1159 that's usually the behavior wanted, but here we need to force "the"
1160 to precede capitalized unique monsters (pnames are handled above) */
1161 if (the_prefix)
1162 Strcat(nambuf, "the ");
1164 if (!adjective || !*adjective) {
1165 /* normal case: newt corpse */
1166 Strcat(nambuf, mname);
1167 } else {
1168 /* adjective positioning depends upon format of monster name */
1169 if (possessive) /* Medusa's cursed partly eaten corpse */
1170 Sprintf(eos(nambuf), "%s %s", mname, adjective);
1171 else /* cursed partly eaten troll corpse */
1172 Sprintf(eos(nambuf), "%s %s", adjective, mname);
1173 /* in case adjective has a trailing space, squeeze it out */
1174 mungspaces(nambuf);
1175 /* doname() might include a count in the adjective argument;
1176 if so, don't prepend an article */
1177 if (digit(*adjective))
1178 any_prefix = FALSE;
1181 if (glob) {
1182 ; /* omit_corpse doesn't apply; quantity is always 1 */
1183 } else if (!omit_corpse) {
1184 Strcat(nambuf, " corpse");
1185 /* makeplural(nambuf) => append "s" to "corpse" */
1186 if (otmp->quan > 1L && !ignore_quan) {
1187 Strcat(nambuf, "s");
1188 any_prefix = FALSE; /* avoid "a newt corpses" */
1192 /* it's safe to overwrite our nambuf after an() has copied
1193 its old value into another buffer */
1194 if (any_prefix)
1195 Strcpy(nambuf, an(nambuf));
1197 return nambuf;
1200 /* xname doesn't include monster type for "corpse"; cxname does */
1201 char *
1202 cxname(obj)
1203 struct obj *obj;
1205 if (obj->otyp == CORPSE)
1206 return corpse_xname(obj, (const char *) 0, CXN_NORMAL);
1207 return xname(obj);
1210 /* like cxname, but ignores quantity */
1211 char *
1212 cxname_singular(obj)
1213 struct obj *obj;
1215 if (obj->otyp == CORPSE)
1216 return corpse_xname(obj, (const char *) 0, CXN_SINGULAR);
1217 return xname_flags(obj, CXN_SINGULAR);
1220 /* treat an object as fully ID'd when it might be used as reason for death */
1221 char *
1222 killer_xname(obj)
1223 struct obj *obj;
1225 struct obj save_obj;
1226 unsigned save_ocknown;
1227 char *buf, *save_ocuname, *save_oname = (char *) 0;
1229 /* bypass object twiddling for artifacts */
1230 if (obj->oartifact)
1231 return bare_artifactname(obj);
1233 /* remember original settings for core of the object;
1234 oextra structs other than oname don't matter here--since they
1235 aren't modified they don't need to be saved and restored */
1236 save_obj = *obj;
1237 if (has_oname(obj))
1238 save_oname = ONAME(obj);
1240 /* killer name should be more specific than general xname; however, exact
1241 info like blessed/cursed and rustproof makes things be too verbose */
1242 obj->known = obj->dknown = 1;
1243 obj->bknown = obj->rknown = obj->greased = 0;
1244 /* if character is a priest[ess], bknown will get toggled back on */
1245 if (obj->otyp != POT_WATER)
1246 obj->blessed = obj->cursed = 0;
1247 else
1248 obj->bknown = 1; /* describe holy/unholy water as such */
1249 /* "killed by poisoned <obj>" would be misleading when poison is
1250 not the cause of death and "poisoned by poisoned <obj>" would
1251 be redundant when it is, so suppress "poisoned" prefix */
1252 obj->opoisoned = 0;
1253 /* strip user-supplied name; artifacts keep theirs */
1254 if (!obj->oartifact && save_oname)
1255 ONAME(obj) = (char *) 0;
1256 /* temporarily identify the type of object */
1257 save_ocknown = objects[obj->otyp].oc_name_known;
1258 objects[obj->otyp].oc_name_known = 1;
1259 save_ocuname = objects[obj->otyp].oc_uname;
1260 objects[obj->otyp].oc_uname = 0; /* avoid "foo called bar" */
1262 /* format the object */
1263 if (obj->otyp == CORPSE) {
1264 buf = nextobuf();
1265 Strcpy(buf, corpse_xname(obj, (const char *) 0, CXN_NORMAL));
1266 } else if (obj->otyp == SLIME_MOLD) {
1267 /* concession to "most unique deaths competition" in the annual
1268 devnull tournament, suppress player supplied fruit names because
1269 those can be used to fake other objects and dungeon features */
1270 buf = nextobuf();
1271 Sprintf(buf, "deadly slime mold%s", plur(obj->quan));
1272 } else {
1273 buf = xname(obj);
1275 /* apply an article if appropriate; caller should always use KILLED_BY */
1276 if (obj->quan == 1L && !strstri(buf, "'s ") && !strstri(buf, "s' "))
1277 buf = (obj_is_pname(obj) || the_unique_obj(obj)) ? the(buf) : an(buf);
1279 objects[obj->otyp].oc_name_known = save_ocknown;
1280 objects[obj->otyp].oc_uname = save_ocuname;
1281 *obj = save_obj; /* restore object's core settings */
1282 if (!obj->oartifact && save_oname)
1283 ONAME(obj) = save_oname;
1285 return buf;
1288 /* xname,doname,&c with long results reformatted to omit some stuff */
1289 char *
1290 short_oname(obj, func, altfunc, lenlimit)
1291 struct obj *obj;
1292 char *FDECL((*func), (OBJ_P)), /* main formatting routine */
1293 *FDECL((*altfunc), (OBJ_P)); /* alternate for shortest result */
1294 unsigned lenlimit;
1296 struct obj save_obj;
1297 char unamebuf[12], onamebuf[12], *save_oname, *save_uname, *outbuf;
1299 outbuf = (*func)(obj);
1300 if ((unsigned) strlen(outbuf) <= lenlimit)
1301 return outbuf;
1303 /* shorten called string to fairly small amount */
1304 save_uname = objects[obj->otyp].oc_uname;
1305 if (save_uname && strlen(save_uname) >= sizeof unamebuf) {
1306 (void) strncpy(unamebuf, save_uname, sizeof unamebuf - 4);
1307 Strcpy(unamebuf + sizeof unamebuf - 4, "...");
1308 objects[obj->otyp].oc_uname = unamebuf;
1309 releaseobuf(outbuf);
1310 outbuf = (*func)(obj);
1311 objects[obj->otyp].oc_uname = save_uname; /* restore called string */
1312 if ((unsigned) strlen(outbuf) <= lenlimit)
1313 return outbuf;
1316 /* shorten named string to fairly small amount */
1317 save_oname = has_oname(obj) ? ONAME(obj) : 0;
1318 if (save_oname && strlen(save_oname) >= sizeof onamebuf) {
1319 (void) strncpy(onamebuf, save_oname, sizeof onamebuf - 4);
1320 Strcpy(onamebuf + sizeof onamebuf - 4, "...");
1321 ONAME(obj) = onamebuf;
1322 releaseobuf(outbuf);
1323 outbuf = (*func)(obj);
1324 ONAME(obj) = save_oname; /* restore named string */
1325 if ((unsigned) strlen(outbuf) <= lenlimit)
1326 return outbuf;
1329 /* shorten both called and named strings;
1330 unamebuf and onamebuf have both already been populated */
1331 if (save_uname && strlen(save_uname) >= sizeof unamebuf && save_oname
1332 && strlen(save_oname) >= sizeof onamebuf) {
1333 objects[obj->otyp].oc_uname = unamebuf;
1334 ONAME(obj) = onamebuf;
1335 releaseobuf(outbuf);
1336 outbuf = (*func)(obj);
1337 if ((unsigned) strlen(outbuf) <= lenlimit) {
1338 objects[obj->otyp].oc_uname = save_uname;
1339 ONAME(obj) = save_oname;
1340 return outbuf;
1344 /* still long; strip several name-lengthening attributes;
1345 called and named strings are still in truncated form */
1346 save_obj = *obj;
1347 obj->bknown = obj->rknown = obj->greased = 0;
1348 obj->oeroded = obj->oeroded2 = 0;
1349 releaseobuf(outbuf);
1350 outbuf = (*func)(obj);
1351 if (altfunc && (unsigned) strlen(outbuf) > lenlimit) {
1352 /* still long; use the alternate function (usually one of
1353 the jackets around minimal_xname()) */
1354 releaseobuf(outbuf);
1355 outbuf = (*altfunc)(obj);
1357 /* restore the object */
1358 *obj = save_obj;
1359 if (save_oname)
1360 ONAME(obj) = save_oname;
1361 if (save_uname)
1362 objects[obj->otyp].oc_uname = save_uname;
1364 /* use whatever we've got, whether it's too long or not */
1365 return outbuf;
1369 * Used if only one of a collection of objects is named (e.g. in eat.c).
1371 const char *
1372 singular(otmp, func)
1373 register struct obj *otmp;
1374 char *FDECL((*func), (OBJ_P));
1376 long savequan;
1377 char *nam;
1379 /* using xname for corpses does not give the monster type */
1380 if (otmp->otyp == CORPSE && func == xname)
1381 func = cxname;
1383 savequan = otmp->quan;
1384 otmp->quan = 1L;
1385 nam = (*func)(otmp);
1386 otmp->quan = savequan;
1387 return nam;
1390 char *
1391 an(str)
1392 register const char *str;
1394 char *buf = nextobuf();
1396 buf[0] = '\0';
1398 if (strncmpi(str, "the ", 4) && strcmp(str, "molten lava")
1399 && strcmp(str, "iron bars") && strcmp(str, "ice")) {
1400 if (index(vowels, *str) && strncmp(str, "one-", 4)
1401 && strncmp(str, "useful", 6) && strncmp(str, "unicorn", 7)
1402 && strncmp(str, "uranium", 7) && strncmp(str, "eucalyptus", 10))
1403 Strcpy(buf, "an ");
1404 else
1405 Strcpy(buf, "a ");
1408 Strcat(buf, str);
1409 return buf;
1412 char *
1413 An(str)
1414 const char *str;
1416 char *tmp = an(str);
1418 *tmp = highc(*tmp);
1419 return tmp;
1423 * Prepend "the" if necessary; assumes str is a subject derived from xname.
1424 * Use type_is_pname() for monster names, not the(). the() is idempotent.
1426 char *
1427 the(str)
1428 const char *str;
1430 char *buf = nextobuf();
1431 boolean insert_the = FALSE;
1433 if (!strncmpi(str, "the ", 4)) {
1434 buf[0] = lowc(*str);
1435 Strcpy(&buf[1], str + 1);
1436 return buf;
1437 } else if (*str < 'A' || *str > 'Z') {
1438 /* not a proper name, needs an article */
1439 insert_the = TRUE;
1440 } else {
1441 /* Probably a proper name, might not need an article */
1442 register char *tmp, *named, *called;
1443 int l;
1445 /* some objects have capitalized adjectives in their names */
1446 if (((tmp = rindex(str, ' ')) != 0 || (tmp = rindex(str, '-')) != 0)
1447 && (tmp[1] < 'A' || tmp[1] > 'Z')) {
1448 insert_the = TRUE;
1449 } else if (tmp && index(str, ' ') < tmp) { /* has spaces */
1450 /* it needs an article if the name contains "of" */
1451 tmp = strstri(str, " of ");
1452 named = strstri(str, " named ");
1453 called = strstri(str, " called ");
1454 if (called && (!named || called < named))
1455 named = called;
1457 if (tmp && (!named || tmp < named)) /* found an "of" */
1458 insert_the = TRUE;
1459 /* stupid special case: lacks "of" but needs "the" */
1460 else if (!named && (l = strlen(str)) >= 31
1461 && !strcmp(&str[l - 31],
1462 "Platinum Yendorian Express Card"))
1463 insert_the = TRUE;
1466 if (insert_the)
1467 Strcpy(buf, "the ");
1468 else
1469 buf[0] = '\0';
1470 Strcat(buf, str);
1472 return buf;
1475 char *
1476 The(str)
1477 const char *str;
1479 char *tmp = the(str);
1481 *tmp = highc(*tmp);
1482 return tmp;
1485 /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
1486 char *
1487 aobjnam(otmp, verb)
1488 struct obj *otmp;
1489 const char *verb;
1491 char prefix[PREFIX];
1492 char *bp = cxname(otmp);
1494 if (otmp->quan != 1L) {
1495 Sprintf(prefix, "%ld ", otmp->quan);
1496 bp = strprepend(bp, prefix);
1498 if (verb) {
1499 Strcat(bp, " ");
1500 Strcat(bp, otense(otmp, verb));
1502 return bp;
1505 /* combine yname and aobjnam eg "your count cxname(otmp)" */
1506 char *
1507 yobjnam(obj, verb)
1508 struct obj *obj;
1509 const char *verb;
1511 char *s = aobjnam(obj, verb);
1513 /* leave off "your" for most of your artifacts, but prepend
1514 * "your" for unique objects and "foo of bar" quest artifacts */
1515 if (!carried(obj) || !obj_is_pname(obj)
1516 || obj->oartifact >= ART_ORB_OF_DETECTION) {
1517 char *outbuf = shk_your(nextobuf(), obj);
1518 int space_left = BUFSZ - 1 - strlen(outbuf);
1520 s = strncat(outbuf, s, space_left);
1522 return s;
1525 /* combine Yname2 and aobjnam eg "Your count cxname(otmp)" */
1526 char *
1527 Yobjnam2(obj, verb)
1528 struct obj *obj;
1529 const char *verb;
1531 register char *s = yobjnam(obj, verb);
1533 *s = highc(*s);
1534 return s;
1537 /* like aobjnam, but prepend "The", not count, and use xname */
1538 char *
1539 Tobjnam(otmp, verb)
1540 struct obj *otmp;
1541 const char *verb;
1543 char *bp = The(xname(otmp));
1545 if (verb) {
1546 Strcat(bp, " ");
1547 Strcat(bp, otense(otmp, verb));
1549 return bp;
1552 /* capitalized variant of doname() */
1553 char *
1554 Doname2(obj)
1555 struct obj *obj;
1557 char *s = doname(obj);
1559 *s = highc(*s);
1560 return s;
1563 /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
1564 char *
1565 yname(obj)
1566 struct obj *obj;
1568 char *s = cxname(obj);
1570 /* leave off "your" for most of your artifacts, but prepend
1571 * "your" for unique objects and "foo of bar" quest artifacts */
1572 if (!carried(obj) || !obj_is_pname(obj)
1573 || obj->oartifact >= ART_ORB_OF_DETECTION) {
1574 char *outbuf = shk_your(nextobuf(), obj);
1575 int space_left = BUFSZ - 1 - strlen(outbuf);
1577 s = strncat(outbuf, s, space_left);
1580 return s;
1583 /* capitalized variant of yname() */
1584 char *
1585 Yname2(obj)
1586 struct obj *obj;
1588 char *s = yname(obj);
1590 *s = highc(*s);
1591 return s;
1594 /* returns "your minimal_xname(obj)"
1595 * or "Foobar's minimal_xname(obj)"
1596 * or "the minimal_xname(obj)"
1598 char *
1599 ysimple_name(obj)
1600 struct obj *obj;
1602 char *outbuf = nextobuf();
1603 char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */
1604 int space_left = BUFSZ - 1 - strlen(s);
1606 return strncat(s, minimal_xname(obj), space_left);
1609 /* capitalized variant of ysimple_name() */
1610 char *
1611 Ysimple_name2(obj)
1612 struct obj *obj;
1614 char *s = ysimple_name(obj);
1616 *s = highc(*s);
1617 return s;
1620 /* "scroll" or "scrolls" */
1621 char *
1622 simpleonames(obj)
1623 struct obj *obj;
1625 char *simpleoname = minimal_xname(obj);
1627 if (obj->quan != 1L)
1628 simpleoname = makeplural(simpleoname);
1629 return simpleoname;
1632 /* "a scroll" or "scrolls"; "a silver bell" or "the Bell of Opening" */
1633 char *
1634 ansimpleoname(obj)
1635 struct obj *obj;
1637 char *simpleoname = simpleonames(obj);
1638 int otyp = obj->otyp;
1640 /* prefix with "the" if a unique item, or a fake one imitating same,
1641 has been formatted with its actual name (we let typename() handle
1642 any `known' and `dknown' checking necessary) */
1643 if (otyp == FAKE_AMULET_OF_YENDOR)
1644 otyp = AMULET_OF_YENDOR;
1645 if (objects[otyp].oc_unique
1646 && !strcmp(simpleoname, OBJ_NAME(objects[otyp])))
1647 return the(simpleoname);
1649 /* simpleoname is singular if quan==1, plural otherwise */
1650 if (obj->quan == 1L)
1651 simpleoname = an(simpleoname);
1652 return simpleoname;
1655 /* "the scroll" or "the scrolls" */
1656 char *
1657 thesimpleoname(obj)
1658 struct obj *obj;
1660 char *simpleoname = simpleonames(obj);
1662 return the(simpleoname);
1665 /* artifact's name without any object type or known/dknown/&c feedback */
1666 char *
1667 bare_artifactname(obj)
1668 struct obj *obj;
1670 char *outbuf;
1672 if (obj->oartifact) {
1673 outbuf = nextobuf();
1674 Strcpy(outbuf, artiname(obj->oartifact));
1675 if (!strncmp(outbuf, "The ", 4))
1676 outbuf[0] = lowc(outbuf[0]);
1677 } else {
1678 outbuf = xname(obj);
1680 return outbuf;
1683 static const char *wrp[] = {
1684 "wand", "ring", "potion", "scroll", "gem",
1685 "amulet", "spellbook", "spell book",
1686 /* for non-specific wishes */
1687 "weapon", "armor", "tool", "food", "comestible",
1689 static const char wrpsym[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
1690 SCROLL_CLASS, GEM_CLASS, AMULET_CLASS,
1691 SPBOOK_CLASS, SPBOOK_CLASS, WEAPON_CLASS,
1692 ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
1693 FOOD_CLASS };
1695 /* return form of the verb (input plural) if xname(otmp) were the subject */
1696 char *
1697 otense(otmp, verb)
1698 struct obj *otmp;
1699 const char *verb;
1701 char *buf;
1704 * verb is given in plural (without trailing s). Return as input
1705 * if the result of xname(otmp) would be plural. Don't bother
1706 * recomputing xname(otmp) at this time.
1708 if (!is_plural(otmp))
1709 return vtense((char *) 0, verb);
1711 buf = nextobuf();
1712 Strcpy(buf, verb);
1713 return buf;
1716 /* various singular words that vtense would otherwise categorize as plural;
1717 also used by makesingular() to catch some special cases */
1718 static const char *const special_subjs[] = {
1719 "erinys", "manes", /* this one is ambiguous */
1720 "Cyclops", "Hippocrates", "Pelias", "aklys",
1721 "amnesia", "detect monsters", "paralysis", "shape changers",
1722 "nemesis", 0
1723 /* note: "detect monsters" and "shape changers" are normally
1724 caught via "<something>(s) of <whatever>", but they can be
1725 wished for using the shorter form, so we include them here
1726 to accommodate usage by makesingular during wishing */
1729 /* return form of the verb (input plural) for present tense 3rd person subj */
1730 char *
1731 vtense(subj, verb)
1732 register const char *subj;
1733 register const char *verb;
1735 char *buf = nextobuf(), *bspot;
1736 int len, ltmp;
1737 const char *sp, *spot;
1738 const char *const *spec;
1741 * verb is given in plural (without trailing s). Return as input
1742 * if subj appears to be plural. Add special cases as necessary.
1743 * Many hard cases can already be handled by using otense() instead.
1744 * If this gets much bigger, consider decomposing makeplural.
1745 * Note: monster names are not expected here (except before corpse).
1747 * Special case: allow null sobj to get the singular 3rd person
1748 * present tense form so we don't duplicate this code elsewhere.
1750 if (subj) {
1751 if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3))
1752 goto sing;
1753 spot = (const char *) 0;
1754 for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) {
1755 if (!strncmpi(sp, " of ", 4) || !strncmpi(sp, " from ", 6)
1756 || !strncmpi(sp, " called ", 8) || !strncmpi(sp, " named ", 7)
1757 || !strncmpi(sp, " labeled ", 9)) {
1758 if (sp != subj)
1759 spot = sp - 1;
1760 break;
1763 len = (int) strlen(subj);
1764 if (!spot)
1765 spot = subj + len - 1;
1768 * plural: anything that ends in 's', but not '*us' or '*ss'.
1769 * Guess at a few other special cases that makeplural creates.
1771 if ((lowc(*spot) == 's' && spot != subj
1772 && !index("us", lowc(*(spot - 1))))
1773 || !BSTRNCMPI(subj, spot - 3, "eeth", 4)
1774 || !BSTRNCMPI(subj, spot - 3, "feet", 4)
1775 || !BSTRNCMPI(subj, spot - 1, "ia", 2)
1776 || !BSTRNCMPI(subj, spot - 1, "ae", 2)) {
1777 /* check for special cases to avoid false matches */
1778 len = (int) (spot - subj) + 1;
1779 for (spec = special_subjs; *spec; spec++) {
1780 ltmp = strlen(*spec);
1781 if (len == ltmp && !strncmpi(*spec, subj, len))
1782 goto sing;
1783 /* also check for <prefix><space><special_subj>
1784 to catch things like "the invisible erinys" */
1785 if (len > ltmp && *(spot - ltmp) == ' '
1786 && !strncmpi(*spec, spot - ltmp + 1, ltmp))
1787 goto sing;
1790 return strcpy(buf, verb);
1793 * 3rd person plural doesn't end in telltale 's';
1794 * 2nd person singular behaves as if plural.
1796 if (!strcmpi(subj, "they") || !strcmpi(subj, "you"))
1797 return strcpy(buf, verb);
1800 sing:
1801 Strcpy(buf, verb);
1802 len = (int) strlen(buf);
1803 bspot = buf + len - 1;
1805 if (!strcmpi(buf, "are")) {
1806 Strcasecpy(buf, "is");
1807 } else if (!strcmpi(buf, "have")) {
1808 Strcasecpy(bspot - 1, "s");
1809 } else if (index("zxs", lowc(*bspot))
1810 || (len >= 2 && lowc(*bspot) == 'h'
1811 && index("cs", lowc(*(bspot - 1))))
1812 || (len == 2 && lowc(*bspot) == 'o')) {
1813 /* Ends in z, x, s, ch, sh; add an "es" */
1814 Strcasecpy(bspot + 1, "es");
1815 } else if (lowc(*bspot) == 'y' && !index(vowels, lowc(*(bspot - 1)))) {
1816 /* like "y" case in makeplural */
1817 Strcasecpy(bspot, "ies");
1818 } else {
1819 Strcasecpy(bspot + 1, "s");
1822 return buf;
1825 struct sing_plur {
1826 const char *sing, *plur;
1829 /* word pairs that don't fit into formula-based transformations;
1830 also some suffices which have very few--often one--matches or
1831 which aren't systematically reversible (knives, staves) */
1832 static struct sing_plur one_off[] = {
1833 { "child",
1834 "children" }, /* (for wise guys who give their food funny names) */
1835 { "cubus", "cubi" }, /* in-/suc-cubus */
1836 { "culus", "culi" }, /* homunculus */
1837 { "djinni", "djinn" },
1838 { "erinys", "erinyes" },
1839 { "foot", "feet" },
1840 { "fungus", "fungi" },
1841 { "knife", "knives" },
1842 { "labrum", "labra" }, /* candelabrum */
1843 { "louse", "lice" },
1844 { "mouse", "mice" },
1845 { "mumak", "mumakil" },
1846 { "nemesis", "nemeses" },
1847 { "rtex", "rtices" }, /* vortex */
1848 { "tooth", "teeth" },
1849 { "staff", "staves" },
1850 { 0, 0 }
1853 static const char *const as_is[] = {
1854 /* makesingular() leaves these plural due to how they're used */
1855 "boots", "shoes", "gloves", "lenses", "scales",
1856 "eyes", "gauntlets", "iron bars",
1857 /* both singular and plural are spelled the same */
1858 "deer", "fish", "tuna", "yaki", "-hai",
1859 "krill", "manes", "ninja", "sheep", "ronin",
1860 "roshi", "shito", "tengu", "ki-rin", "Nazgul",
1861 "gunyoki", "piranha", "samurai", "shuriken", 0,
1862 /* Note: "fish" and "piranha" are collective plurals, suitable
1863 for "wiped out all <foo>". For "3 <foo>", they should be
1864 "fishes" and "piranhas" instead. We settle for collective
1865 variant instead of attempting to support both. */
1868 /* singularize/pluralize decisions common to both makesingular & makeplural
1870 STATIC_OVL boolean
1871 singplur_lookup(basestr, endstring, to_plural, alt_as_is)
1872 char *basestr, *endstring; /* base string, pointer to eos(string) */
1873 boolean to_plural; /* true => makeplural, false => makesingular */
1874 const char *const *alt_as_is; /* another set like as_is[] */
1876 const struct sing_plur *sp;
1877 const char *same, *other, *const *as;
1878 int al;
1880 for (as = as_is; *as; ++as) {
1881 al = (int) strlen(*as);
1882 if (!BSTRCMPI(basestr, endstring - al, *as))
1883 return TRUE;
1885 if (alt_as_is) {
1886 for (as = alt_as_is; *as; ++as) {
1887 al = (int) strlen(*as);
1888 if (!BSTRCMPI(basestr, endstring - al, *as))
1889 return TRUE;
1893 /* avoid false hit on one_off[].plur == "lice";
1894 if more of these turn up, one_off[] entries will need to flagged
1895 as to which are whole words and which are matchable as suffices
1896 then matching in the loop below will end up becoming more complex */
1897 if (!strcmpi(basestr, "slice")) {
1898 if (to_plural)
1899 (void) strkitten(basestr, 's');
1900 return TRUE;
1902 for (sp = one_off; sp->sing; sp++) {
1903 /* check whether endstring already matches */
1904 same = to_plural ? sp->plur : sp->sing;
1905 al = (int) strlen(same);
1906 if (!BSTRCMPI(basestr, endstring - al, same))
1907 return TRUE; /* use as-is */
1908 /* check whether it matches the inverse; if so, transform it */
1909 other = to_plural ? sp->sing : sp->plur;
1910 al = (int) strlen(other);
1911 if (!BSTRCMPI(basestr, endstring - al, other)) {
1912 Strcasecpy(endstring - al, same);
1913 return TRUE; /* one_off[] transformation */
1916 return FALSE;
1919 /* searches for common compounds, ex. lump of royal jelly */
1920 STATIC_OVL char *
1921 singplur_compound(str)
1922 char *str;
1924 /* if new entries are added, be sure to keep compound_start[] in sync */
1925 static const char *const compounds[] =
1927 " of ", " labeled ", " called ",
1928 " named ", " above", /* lurkers above */
1929 " versus ", " from ", " in ",
1930 " on ", " a la ", " with", /* " with "? */
1931 " de ", " d'", " du ",
1932 "-in-", "-at-", 0
1933 }, /* list of first characters for all compounds[] entries */
1934 compound_start[] = " -";
1936 const char *const *cmpd;
1937 char *p;
1939 for (p = str; *p; ++p) {
1940 /* substring starting at p can only match if *p is found
1941 within compound_start[] */
1942 if (!index(compound_start, *p))
1943 continue;
1945 /* check current substring against all words in the compound[] list */
1946 for (cmpd = compounds; *cmpd; ++cmpd)
1947 if (!strncmpi(p, *cmpd, (int) strlen(*cmpd)))
1948 return p;
1950 /* wasn't recognized as a compound phrase */
1951 return 0;
1954 /* Plural routine; chiefly used for user-defined fruits. We have to try to
1955 * account for everything reasonable the player has; something unreasonable
1956 * can still break the code. However, it's still a lot more accurate than
1957 * "just add an s at the end", which Rogue uses...
1959 * Also used for plural monster names ("Wiped out all homunculi." or the
1960 * vanquished monsters list) and body parts. A lot of unique monsters have
1961 * names which get mangled by makeplural and/or makesingular. They're not
1962 * genocidable, and vanquished-mon handling does its own special casing
1963 * (for uniques who've been revived and re-killed), so we don't bother
1964 * trying to get those right here.
1966 * Also misused by muse.c to convert 1st person present verbs to 2nd person.
1967 * 3.6.0: made case-insensitive.
1969 char *
1970 makeplural(oldstr)
1971 const char *oldstr;
1973 register char *spot;
1974 char lo_c, *str = nextobuf();
1975 const char *excess = (char *) 0;
1976 int len;
1978 if (oldstr)
1979 while (*oldstr == ' ')
1980 oldstr++;
1981 if (!oldstr || !*oldstr) {
1982 impossible("plural of null?");
1983 Strcpy(str, "s");
1984 return str;
1986 Strcpy(str, oldstr);
1989 * Skip changing "pair of" to "pairs of". According to Webster, usual
1990 * English usage is use pairs for humans, e.g. 3 pairs of dancers,
1991 * and pair for objects and non-humans, e.g. 3 pair of boots. We don't
1992 * refer to pairs of humans in this game so just skip to the bottom.
1994 if (!strncmpi(str, "pair of ", 8))
1995 goto bottom;
1997 /* look for "foo of bar" so that we can focus on "foo" */
1998 if ((spot = singplur_compound(str)) != 0) {
1999 excess = oldstr + (int) (spot - str);
2000 *spot = '\0';
2001 } else
2002 spot = eos(str);
2004 spot--;
2005 while (spot > str && *spot == ' ')
2006 spot--; /* Strip blanks from end */
2007 *(spot + 1) = 0;
2008 /* Now spot is the last character of the string */
2010 len = strlen(str);
2012 /* Single letters */
2013 if (len == 1 || !letter(*spot)) {
2014 Strcpy(spot + 1, "'s");
2015 goto bottom;
2018 /* dispense with some words which don't need pluralization */
2020 static const char *const already_plural[] = {
2021 "ae", /* algae, larvae, &c */
2022 "men", /* also catches women, watchmen */
2023 "matzot", 0,
2026 /* spot+1: synch up with makesingular's usage */
2027 if (singplur_lookup(str, spot + 1, TRUE, already_plural))
2028 goto bottom;
2030 /* more of same, but not suitable for blanket loop checking */
2031 if ((len == 2 && !strcmpi(str, "ya"))
2032 || (len >= 3 && !strcmpi(spot - 2, " ya")))
2033 goto bottom;
2036 /* man/men ("Wiped out all cavemen.") */
2037 if (len >= 3 && !strcmpi(spot - 2, "man")
2038 /* exclude shamans and humans */
2039 && (len < 6 || strcmpi(spot - 5, "shaman"))
2040 && (len < 5 || strcmpi(spot - 4, "human"))) {
2041 Strcasecpy(spot - 1, "en");
2042 goto bottom;
2044 if (lowc(*spot) == 'f') { /* (staff handled via one_off[]) */
2045 lo_c = lowc(*(spot - 1));
2046 if (len >= 3 && !strcmpi(spot - 2, "erf")) {
2047 /* avoid "nerf" -> "nerves", "serf" -> "serves" */
2048 ; /* fall through to default (append 's') */
2049 } else if (index("lr", lo_c) || index(vowels, lo_c)) {
2050 /* [aeioulr]f to [aeioulr]ves */
2051 Strcasecpy(spot, "ves");
2052 goto bottom;
2055 /* ium/ia (mycelia, baluchitheria) */
2056 if (len >= 3 && !strcmpi(spot - 2, "ium")) {
2057 Strcasecpy(spot - 2, "ia");
2058 goto bottom;
2060 /* algae, larvae, hyphae (another fungus part) */
2061 if ((len >= 4 && !strcmpi(spot - 3, "alga"))
2062 || (len >= 5
2063 && (!strcmpi(spot - 4, "hypha") || !strcmpi(spot - 4, "larva")))
2064 || (len >= 6 && !strcmpi(spot - 5, "amoeba"))
2065 || (len >= 8 && (!strcmpi(spot - 7, "vertebra")))) {
2066 /* a to ae */
2067 Strcasecpy(spot + 1, "e");
2068 goto bottom;
2070 /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */
2071 if (len > 3 && !strcmpi(spot - 1, "us")
2072 && !((len >= 5 && !strcmpi(spot - 4, "lotus"))
2073 || (len >= 6 && !strcmpi(spot - 5, "wumpus")))) {
2074 Strcasecpy(spot - 1, "i");
2075 goto bottom;
2077 /* sis/ses (nemesis) */
2078 if (len >= 3 && !strcmpi(spot - 2, "sis")) {
2079 Strcasecpy(spot - 1, "es");
2080 goto bottom;
2082 /* matzoh/matzot, possible food name */
2083 if (len >= 6
2084 && (!strcmpi(spot - 5, "matzoh") || !strcmpi(spot - 5, "matzah"))) {
2085 Strcasecpy(spot - 1, "ot"); /* oh/ah -> ot */
2086 goto bottom;
2088 if (len >= 5
2089 && (!strcmpi(spot - 4, "matzo") || !strcmpi(spot - 4, "matza"))) {
2090 Strcasecpy(spot, "ot"); /* o/a -> ot */
2091 goto bottom;
2094 /* note: -eau/-eaux (gateau, bordeau...) */
2095 /* note: ox/oxen, VAX/VAXen, goose/geese */
2097 lo_c = lowc(*spot);
2099 /* Ends in z, x, s, ch, sh; add an "es" */
2100 if (index("zxs", lo_c)
2101 || (len >= 2 && lo_c == 'h' && index("cs", lowc(*(spot - 1))))
2102 /* Kludge to get "tomatoes" and "potatoes" right */
2103 || (len >= 4 && !strcmpi(spot - 2, "ato"))
2104 || (len >= 5 && !strcmpi(spot - 4, "dingo"))) {
2105 Strcasecpy(spot + 1, "es"); /* append es */
2106 goto bottom;
2108 /* Ends in y preceded by consonant (note: also "qu") change to "ies" */
2109 if (lo_c == 'y' && !index(vowels, lowc(*(spot - 1)))) {
2110 Strcasecpy(spot, "ies"); /* y -> ies */
2111 goto bottom;
2113 /* Default: append an 's' */
2114 Strcasecpy(spot + 1, "s");
2116 bottom:
2117 if (excess)
2118 Strcat(str, excess);
2119 return str;
2123 * Singularize a string the user typed in; this helps reduce the complexity
2124 * of readobjnam, and is also used in pager.c to singularize the string
2125 * for which help is sought.
2127 * "Manes" is ambiguous: monster type (keep s), or horse body part (drop s)?
2128 * Its inclusion in as_is[]/special_subj[] makes it get treated as the former.
2130 * A lot of unique monsters have names ending in s; plural, or singular
2131 * from plural, doesn't make much sense for them so we don't bother trying.
2132 * 3.6.0: made case-insensitive.
2134 char *
2135 makesingular(oldstr)
2136 const char *oldstr;
2138 register char *p, *bp;
2139 const char *excess = 0;
2140 char *str = nextobuf();
2142 if (oldstr)
2143 while (*oldstr == ' ')
2144 oldstr++;
2145 if (!oldstr || !*oldstr) {
2146 impossible("singular of null?");
2147 str[0] = '\0';
2148 return str;
2151 bp = strcpy(str, oldstr);
2153 /* check for "foo of bar" so that we can focus on "foo" */
2154 if ((p = singplur_compound(bp)) != 0) {
2155 excess = oldstr + (int) (p - bp);
2156 *p = '\0';
2157 } else
2158 p = eos(bp);
2160 /* dispense with some words which don't need singularization */
2161 if (singplur_lookup(bp, p, FALSE, special_subjs))
2162 goto bottom;
2164 /* remove -s or -es (boxes) or -ies (rubies) */
2165 if (p >= bp + 1 && lowc(p[-1]) == 's') {
2166 if (p >= bp + 2 && lowc(p[-2]) == 'e') {
2167 if (p >= bp + 3 && lowc(p[-3]) == 'i') { /* "ies" */
2168 if (!BSTRCMPI(bp, p - 7, "cookies")
2169 || !BSTRCMPI(bp, p - 4, "pies")
2170 || !BSTRCMPI(bp, p - 5, "mbies") /* zombie */
2171 || !BSTRCMPI(bp, p - 5, "yries")) /* valkyrie */
2172 goto mins;
2173 Strcasecpy(p - 3, "y"); /* ies -> y */
2174 goto bottom;
2176 /* wolves, but f to ves isn't fully reversible */
2177 if (p - 4 >= bp && (index("lr", lowc(*(p - 4)))
2178 || index(vowels, lowc(*(p - 4))))
2179 && !BSTRCMPI(bp, p - 3, "ves")) {
2180 if (!BSTRCMPI(bp, p - 6, "cloves")
2181 || !BSTRCMPI(bp, p - 6, "nerves"))
2182 goto mins;
2183 Strcasecpy(p - 3, "f"); /* ves -> f */
2184 goto bottom;
2186 /* note: nurses, axes but boxes, wumpuses */
2187 if (!BSTRCMPI(bp, p - 4, "eses")
2188 || !BSTRCMPI(bp, p - 4, "oxes") /* boxes, foxes */
2189 || !BSTRCMPI(bp, p - 4, "nxes") /* lynxes */
2190 || !BSTRCMPI(bp, p - 4, "ches")
2191 || !BSTRCMPI(bp, p - 4, "uses") /* lotuses */
2192 || !BSTRCMPI(bp, p - 4, "sses") /* priestesses */
2193 || !BSTRCMPI(bp, p - 5, "atoes") /* tomatoes */
2194 || !BSTRCMPI(bp, p - 7, "dingoes")
2195 || !BSTRCMPI(bp, p - 7, "Aleaxes")) {
2196 *(p - 2) = '\0'; /* drop es */
2197 goto bottom;
2198 } /* else fall through to mins */
2200 /* ends in 's' but not 'es' */
2201 } else if (!BSTRCMPI(bp, p - 2, "us")) { /* lotus, fungus... */
2202 if (BSTRCMPI(bp, p - 6, "tengus") /* but not these... */
2203 && BSTRCMPI(bp, p - 7, "hezrous"))
2204 goto bottom;
2205 } else if (!BSTRCMPI(bp, p - 2, "ss")
2206 || !BSTRCMPI(bp, p - 5, " lens")
2207 || (p - 4 == bp && !strcmpi(p - 4, "lens"))) {
2208 goto bottom;
2210 mins:
2211 *(p - 1) = '\0'; /* drop s */
2213 } else { /* input doesn't end in 's' */
2215 if (!BSTRCMPI(bp, p - 3, "men")) {
2216 Strcasecpy(p - 2, "an");
2217 goto bottom;
2219 /* matzot -> matzo, algae -> alga */
2220 if (!BSTRCMPI(bp, p - 6, "matzot") || !BSTRCMPI(bp, p - 2, "ae")) {
2221 *(p - 1) = '\0'; /* drop t/e */
2222 goto bottom;
2224 /* balactheria -> balactherium */
2225 if (p - 4 >= bp && !strcmpi(p - 2, "ia")
2226 && index("lr", lowc(*(p - 3))) && lowc(*(p - 4)) == 'e') {
2227 Strcasecpy(p - 1, "um"); /* a -> um */
2230 /* here we cannot find the plural suffix */
2233 bottom:
2234 /* if we stripped off a suffix (" of bar" from "foo of bar"),
2235 put it back now [strcat() isn't actually 100% safe here...] */
2236 if (excess)
2237 Strcat(bp, excess);
2239 return bp;
2242 /* compare user string against object name string using fuzzy matching */
2243 STATIC_OVL boolean
2244 wishymatch(u_str, o_str, retry_inverted)
2245 const char *u_str; /* from user, so might be variant spelling */
2246 const char *o_str; /* from objects[], so is in canonical form */
2247 boolean retry_inverted; /* optional extra "of" handling */
2249 static NEARDATA const char detect_SP[] = "detect ",
2250 SP_detection[] = " detection";
2251 char *p, buf[BUFSZ];
2253 /* ignore spaces & hyphens and upper/lower case when comparing */
2254 if (fuzzymatch(u_str, o_str, " -", TRUE))
2255 return TRUE;
2257 if (retry_inverted) {
2258 const char *u_of, *o_of;
2260 /* when just one of the strings is in the form "foo of bar",
2261 convert it into "bar foo" and perform another comparison */
2262 u_of = strstri(u_str, " of ");
2263 o_of = strstri(o_str, " of ");
2264 if (u_of && !o_of) {
2265 Strcpy(buf, u_of + 4);
2266 p = eos(strcat(buf, " "));
2267 while (u_str < u_of)
2268 *p++ = *u_str++;
2269 *p = '\0';
2270 return fuzzymatch(buf, o_str, " -", TRUE);
2271 } else if (o_of && !u_of) {
2272 Strcpy(buf, o_of + 4);
2273 p = eos(strcat(buf, " "));
2274 while (o_str < o_of)
2275 *p++ = *o_str++;
2276 *p = '\0';
2277 return fuzzymatch(u_str, buf, " -", TRUE);
2281 /* [note: if something like "elven speed boots" ever gets added, these
2282 special cases should be changed to call wishymatch() recursively in
2283 order to get the "of" inversion handling] */
2284 if (!strncmp(o_str, "dwarvish ", 9)) {
2285 if (!strncmpi(u_str, "dwarven ", 8))
2286 return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE);
2287 } else if (!strncmp(o_str, "elven ", 6)) {
2288 if (!strncmpi(u_str, "elvish ", 7))
2289 return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE);
2290 else if (!strncmpi(u_str, "elfin ", 6))
2291 return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE);
2292 } else if (!strncmp(o_str, detect_SP, sizeof detect_SP - 1)) {
2293 /* check for "detect <foo>" vs "<foo> detection" */
2294 if ((p = strstri(u_str, SP_detection)) != 0
2295 && !*(p + sizeof SP_detection - 1)) {
2296 /* convert "<foo> detection" into "detect <foo>" */
2297 *p = '\0';
2298 Strcat(strcpy(buf, detect_SP), u_str);
2299 /* "detect monster" -> "detect monsters" */
2300 if (!strcmpi(u_str, "monster"))
2301 Strcat(buf, "s");
2302 *p = ' ';
2303 return fuzzymatch(buf, o_str, " -", TRUE);
2305 } else if (strstri(o_str, SP_detection)) {
2306 /* and the inverse, "<foo> detection" vs "detect <foo>" */
2307 if (!strncmpi(u_str, detect_SP, sizeof detect_SP - 1)) {
2308 /* convert "detect <foo>s" into "<foo> detection" */
2309 p = makesingular(u_str + sizeof detect_SP - 1);
2310 Strcat(strcpy(buf, p), SP_detection);
2311 /* caller may be looping through objects[], so avoid
2312 churning through all the obufs */
2313 releaseobuf(p);
2314 return fuzzymatch(buf, o_str, " -", TRUE);
2316 } else if (strstri(o_str, "ability")) {
2317 /* when presented with "foo of bar", makesingular() used to
2318 singularize both foo & bar, but now only does so for foo */
2319 /* catch "{potion(s),ring} of {gain,restore,sustain} abilities" */
2320 if ((p = strstri(u_str, "abilities")) != 0
2321 && !*(p + sizeof "abilities" - 1)) {
2322 (void) strncpy(buf, u_str, (unsigned) (p - u_str));
2323 Strcpy(buf + (p - u_str), "ability");
2324 return fuzzymatch(buf, o_str, " -", TRUE);
2326 } else if (!strcmp(o_str, "aluminum")) {
2327 /* this special case doesn't really fit anywhere else... */
2328 /* (note that " wand" will have been stripped off by now) */
2329 if (!strcmpi(u_str, "aluminium"))
2330 return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE);
2333 return FALSE;
2336 struct o_range {
2337 const char *name, oclass;
2338 int f_o_range, l_o_range;
2341 /* wishable subranges of objects */
2342 STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
2343 { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS },
2344 { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP },
2345 { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE },
2346 { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY },
2347 { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION },
2348 { "hat", ARMOR_CLASS, FEDORA, DUNCE_CAP },
2349 { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
2350 { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
2351 { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
2352 { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS },
2353 { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES },
2354 { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
2355 { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT },
2356 { "dragon scales", ARMOR_CLASS, GRAY_DRAGON_SCALES,
2357 YELLOW_DRAGON_SCALES },
2358 { "dragon scale mail", ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL,
2359 YELLOW_DRAGON_SCALE_MAIL },
2360 { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA },
2361 { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM },
2362 { "gray stone", GEM_CLASS, LUCKSTONE, FLINT },
2363 { "grey stone", GEM_CLASS, LUCKSTONE, FLINT },
2366 /* alternate spellings; if the difference is only the presence or
2367 absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
2368 vs "pick-axe") then there is no need for inclusion in this list;
2369 likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */
2370 struct alt_spellings {
2371 const char *sp;
2372 int ob;
2373 } spellings[] = {
2374 { "pickax", PICK_AXE },
2375 { "whip", BULLWHIP },
2376 { "saber", SILVER_SABER },
2377 { "silver sabre", SILVER_SABER },
2378 { "smooth shield", SHIELD_OF_REFLECTION },
2379 { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
2380 { "grey dragon scales", GRAY_DRAGON_SCALES },
2381 { "iron ball", HEAVY_IRON_BALL },
2382 { "lantern", BRASS_LANTERN },
2383 { "mattock", DWARVISH_MATTOCK },
2384 { "amulet of poison resistance", AMULET_VERSUS_POISON },
2385 { "potion of sleep", POT_SLEEPING },
2386 { "stone", ROCK },
2387 { "camera", EXPENSIVE_CAMERA },
2388 { "tee shirt", T_SHIRT },
2389 { "can", TIN },
2390 { "can opener", TIN_OPENER },
2391 { "kelp", KELP_FROND },
2392 { "eucalyptus", EUCALYPTUS_LEAF },
2393 { "royal jelly", LUMP_OF_ROYAL_JELLY },
2394 { "lembas", LEMBAS_WAFER },
2395 { "marker", MAGIC_MARKER },
2396 { "hook", GRAPPLING_HOOK },
2397 { "grappling iron", GRAPPLING_HOOK },
2398 { "grapnel", GRAPPLING_HOOK },
2399 { "grapple", GRAPPLING_HOOK },
2400 { "protection from shape shifters", RIN_PROTECTION_FROM_SHAPE_CHAN },
2401 /* normally we wouldn't have to worry about unnecessary <space>, but
2402 " stone" will get stripped off, preventing a wishymatch; that actually
2403 lets "flint stone" be a match, so we also accept bogus "flintstone" */
2404 { "luck stone", LUCKSTONE },
2405 { "load stone", LOADSTONE },
2406 { "touch stone", TOUCHSTONE },
2407 { "flintstone", FLINT },
2408 { (const char *) 0, 0 },
2411 short
2412 rnd_otyp_by_wpnskill(skill)
2413 schar skill;
2415 int i, n = 0;
2416 short otyp = STRANGE_OBJECT;
2417 for (i = bases[WEAPON_CLASS];
2418 i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++)
2419 if (objects[i].oc_skill == skill) {
2420 n++;
2421 otyp = i;
2423 if (n > 0) {
2424 n = rn2(n);
2425 for (i = bases[WEAPON_CLASS];
2426 i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++)
2427 if (objects[i].oc_skill == skill)
2428 if (--n < 0)
2429 return i;
2431 return otyp;
2435 * Return something wished for. Specifying a null pointer for
2436 * the user request string results in a random object. Otherwise,
2437 * if asking explicitly for "nothing" (or "nil") return no_wish;
2438 * if not an object return &zeroobj; if an error (no matching object),
2439 * return null.
2441 struct obj *
2442 readobjnam(bp, no_wish)
2443 register char *bp;
2444 struct obj *no_wish;
2446 register char *p;
2447 register int i;
2448 register struct obj *otmp;
2449 int cnt, spe, spesgn, typ, very, rechrg;
2450 int blessed, uncursed, iscursed, ispoisoned, isgreased;
2451 int eroded, eroded2, erodeproof;
2452 int halfeaten, mntmp, contents;
2453 int islit, unlabeled, ishistoric, isdiluted, trapped;
2454 int tmp, tinv, tvariety;
2455 int wetness;
2456 struct fruit *f;
2457 int ftype = context.current_fruit;
2458 char fruitbuf[BUFSZ];
2459 /* Fruits may not mess up the ability to wish for real objects (since
2460 * you can leave a fruit in a bones file and it will be added to
2461 * another person's game), so they must be checked for last, after
2462 * stripping all the possible prefixes and seeing if there's a real
2463 * name in there. So we have to save the full original name. However,
2464 * it's still possible to do things like "uncursed burnt Alaska",
2465 * or worse yet, "2 burned 5 course meals", so we need to loop to
2466 * strip off the prefixes again, this time stripping only the ones
2467 * possible on food.
2468 * We could get even more detailed so as to allow food names with
2469 * prefixes that _are_ possible on food, so you could wish for
2470 * "2 3 alarm chilis". Currently this isn't allowed; options.c
2471 * automatically sticks 'candied' in front of such names.
2473 char oclass;
2474 char *un, *dn, *actualn;
2475 const char *name = 0;
2477 cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed =
2478 ispoisoned = isgreased = eroded = eroded2 = erodeproof = halfeaten =
2479 islit = unlabeled = ishistoric = isdiluted = trapped = 0;
2480 tvariety = RANDOM_TIN;
2481 mntmp = NON_PM;
2482 #define UNDEFINED 0
2483 #define EMPTY 1
2484 #define SPINACH 2
2485 contents = UNDEFINED;
2486 oclass = 0;
2487 actualn = dn = un = 0;
2488 wetness = 0;
2490 if (!bp)
2491 goto any;
2492 /* first, remove extra whitespace they may have typed */
2493 (void) mungspaces(bp);
2494 /* allow wishing for "nothing" to preserve wishless conduct...
2495 [now requires "wand of nothing" if that's what was really wanted] */
2496 if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil")
2497 || !strcmpi(bp, "none"))
2498 return no_wish;
2499 /* save the [nearly] unmodified choice string */
2500 Strcpy(fruitbuf, bp);
2502 for (;;) {
2503 register int l;
2505 if (!bp || !*bp)
2506 goto any;
2507 if (!strncmpi(bp, "an ", l = 3) || !strncmpi(bp, "a ", l = 2)) {
2508 cnt = 1;
2509 } else if (!strncmpi(bp, "the ", l = 4)) {
2510 ; /* just increment `bp' by `l' below */
2511 } else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
2512 cnt = atoi(bp);
2513 while (digit(*bp))
2514 bp++;
2515 while (*bp == ' ')
2516 bp++;
2517 l = 0;
2518 } else if (*bp == '+' || *bp == '-') {
2519 spesgn = (*bp++ == '+') ? 1 : -1;
2520 spe = atoi(bp);
2521 while (digit(*bp))
2522 bp++;
2523 while (*bp == ' ')
2524 bp++;
2525 l = 0;
2526 } else if (!strncmpi(bp, "blessed ", l = 8)
2527 || !strncmpi(bp, "holy ", l = 5)) {
2528 blessed = 1;
2529 } else if (!strncmpi(bp, "moist ", l = 6)
2530 || !strncmpi(bp, "wet ", l = 4)) {
2531 if (!strncmpi(bp, "wet ", 4))
2532 wetness = rn2(3) + 3;
2533 else
2534 wetness = rnd(2);
2535 } else if (!strncmpi(bp, "cursed ", l = 7)
2536 || !strncmpi(bp, "unholy ", l = 7)) {
2537 iscursed = 1;
2538 } else if (!strncmpi(bp, "uncursed ", l = 9)) {
2539 uncursed = 1;
2540 } else if (!strncmpi(bp, "rustproof ", l = 10)
2541 || !strncmpi(bp, "erodeproof ", l = 11)
2542 || !strncmpi(bp, "corrodeproof ", l = 13)
2543 || !strncmpi(bp, "fixed ", l = 6)
2544 || !strncmpi(bp, "fireproof ", l = 10)
2545 || !strncmpi(bp, "rotproof ", l = 9)) {
2546 erodeproof = 1;
2547 } else if (!strncmpi(bp, "lit ", l = 4)
2548 || !strncmpi(bp, "burning ", l = 8)) {
2549 islit = 1;
2550 } else if (!strncmpi(bp, "unlit ", l = 6)
2551 || !strncmpi(bp, "extinguished ", l = 13)) {
2552 islit = 0;
2553 /* "unlabeled" and "blank" are synonymous */
2554 } else if (!strncmpi(bp, "unlabeled ", l = 10)
2555 || !strncmpi(bp, "unlabelled ", l = 11)
2556 || !strncmpi(bp, "blank ", l = 6)) {
2557 unlabeled = 1;
2558 } else if (!strncmpi(bp, "poisoned ", l = 9)) {
2559 ispoisoned = 1;
2560 /* "trapped" recognized but not honored outside wizard mode */
2561 } else if (!strncmpi(bp, "trapped ", l = 8)) {
2562 trapped = 0; /* undo any previous "untrapped" */
2563 if (wizard)
2564 trapped = 1;
2565 } else if (!strncmpi(bp, "untrapped ", l = 10)) {
2566 trapped = 2; /* not trapped */
2567 } else if (!strncmpi(bp, "greased ", l = 8)) {
2568 isgreased = 1;
2569 } else if (!strncmpi(bp, "very ", l = 5)) {
2570 /* very rusted very heavy iron ball */
2571 very = 1;
2572 } else if (!strncmpi(bp, "thoroughly ", l = 11)) {
2573 very = 2;
2574 } else if (!strncmpi(bp, "rusty ", l = 6)
2575 || !strncmpi(bp, "rusted ", l = 7)
2576 || !strncmpi(bp, "burnt ", l = 6)
2577 || !strncmpi(bp, "burned ", l = 7)) {
2578 eroded = 1 + very;
2579 very = 0;
2580 } else if (!strncmpi(bp, "corroded ", l = 9)
2581 || !strncmpi(bp, "rotted ", l = 7)) {
2582 eroded2 = 1 + very;
2583 very = 0;
2584 } else if (!strncmpi(bp, "partly eaten ", l = 13)
2585 || !strncmpi(bp, "partially eaten ", l = 16)) {
2586 halfeaten = 1;
2587 } else if (!strncmpi(bp, "historic ", l = 9)) {
2588 ishistoric = 1;
2589 } else if (!strncmpi(bp, "diluted ", l = 8)) {
2590 isdiluted = 1;
2591 } else if (!strncmpi(bp, "empty ", l = 6)) {
2592 contents = EMPTY;
2593 } else
2594 break;
2595 bp += l;
2597 if (!cnt)
2598 cnt = 1; /* %% what with "gems" etc. ? */
2599 if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) {
2600 boolean keeptrailingchars = TRUE;
2602 p[(p > bp && p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */
2603 ++p; /* advance past '(' */
2604 if (!strncmpi(p, "lit)", 4)) {
2605 islit = 1;
2606 p += 4 - 1; /* point at ')' */
2607 } else {
2608 spe = atoi(p);
2609 while (digit(*p))
2610 p++;
2611 if (*p == ':') {
2612 p++;
2613 rechrg = spe;
2614 spe = atoi(p);
2615 while (digit(*p))
2616 p++;
2618 if (*p != ')') {
2619 spe = rechrg = 0;
2620 /* mis-matched parentheses; rest of string will be ignored
2621 * [probably we should restore everything back to '('
2622 * instead since it might be part of "named ..."]
2624 keeptrailingchars = FALSE;
2625 } else {
2626 spesgn = 1;
2629 if (keeptrailingchars) {
2630 char *pp = eos(bp);
2632 /* 'pp' points at 'pb's terminating '\0',
2633 'p' points at ')' and will be incremented past it */
2634 do {
2635 *pp++ = *++p;
2636 } while (*p);
2640 * otmp->spe is type schar, so we don't want spe to be any bigger or
2641 * smaller. Also, spe should always be positive --some cheaters may
2642 * try to confuse atoi().
2644 if (spe < 0) {
2645 spesgn = -1; /* cheaters get what they deserve */
2646 spe = abs(spe);
2648 if (spe > SCHAR_LIM)
2649 spe = SCHAR_LIM;
2650 if (rechrg < 0 || rechrg > 7)
2651 rechrg = 7; /* recharge_limit */
2653 /* now we have the actual name, as delivered by xname, say
2654 * green potions called whisky
2655 * scrolls labeled "QWERTY"
2656 * egg
2657 * fortune cookies
2658 * very heavy iron ball named hoei
2659 * wand of wishing
2660 * elven cloak
2662 if ((p = strstri(bp, " named ")) != 0) {
2663 *p = 0;
2664 name = p + 7;
2666 if ((p = strstri(bp, " called ")) != 0) {
2667 *p = 0;
2668 un = p + 8;
2669 /* "helmet called telepathy" is not "helmet" (a specific type)
2670 * "shield called reflection" is not "shield" (a general type)
2672 for (i = 0; i < SIZE(o_ranges); i++)
2673 if (!strcmpi(bp, o_ranges[i].name)) {
2674 oclass = o_ranges[i].oclass;
2675 goto srch;
2678 if ((p = strstri(bp, " labeled ")) != 0) {
2679 *p = 0;
2680 dn = p + 9;
2681 } else if ((p = strstri(bp, " labelled ")) != 0) {
2682 *p = 0;
2683 dn = p + 10;
2685 if ((p = strstri(bp, " of spinach")) != 0) {
2686 *p = 0;
2687 contents = SPINACH;
2691 Skip over "pair of ", "pairs of", "set of" and "sets of".
2693 Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
2694 English either way. See makeplural() for more on pair/pairs.
2696 We should only double count if the object in question is not
2697 referred to as a "pair of". E.g. We should double if the player
2698 types "pair of spears", but not if the player types "pair of
2699 lenses". Luckily (?) all objects that are referred to as pairs
2700 -- boots, gloves, and lenses -- are also not mergable, so cnt is
2701 ignored anyway.
2703 if (!strncmpi(bp, "pair of ", 8)) {
2704 bp += 8;
2705 cnt *= 2;
2706 } else if (cnt > 1 && !strncmpi(bp, "pairs of ", 9)) {
2707 bp += 9;
2708 cnt *= 2;
2709 } else if (!strncmpi(bp, "set of ", 7)) {
2710 bp += 7;
2711 } else if (!strncmpi(bp, "sets of ", 8)) {
2712 bp += 8;
2715 /* intercept pudding globs here; they're a valid wish target,
2716 * but we need them to not get treated like a corpse.
2718 * also don't let player wish for multiple globs.
2720 if ((p = strstri(bp, "glob of ")) != 0
2721 || (p = strstri(bp, "globs of ")) != 0) {
2722 int globoffset = (*(p + 4) == 's') ? 9 : 8;
2723 if ((mntmp = name_to_mon(p + globoffset)) >= PM_GRAY_OOZE
2724 && mntmp <= PM_BLACK_PUDDING) {
2725 mntmp = NON_PM; /* lie to ourselves */
2726 cnt = 0; /* force only one */
2728 } else {
2730 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
2731 * Don't check if it's a wand or spellbook.
2732 * (avoid "wand/finger of death" confusion).
2734 if (!strstri(bp, "wand ") && !strstri(bp, "spellbook ")
2735 && !strstri(bp, "finger ")) {
2736 if (((p = strstri(bp, "tin of ")) != 0)
2737 && (tmp = tin_variety_txt(p + 7, &tinv))
2738 && (mntmp = name_to_mon(p + 7 + tmp)) >= LOW_PM) {
2739 *(p + 3) = 0;
2740 tvariety = tinv;
2741 } else if ((p = strstri(bp, " of ")) != 0
2742 && (mntmp = name_to_mon(p + 4)) >= LOW_PM)
2743 *p = 0;
2746 /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
2747 if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
2748 if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
2749 if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
2750 if (strncmpi(bp, "master key",
2751 10)) /* not the "master" rank */
2752 if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */
2753 if (mntmp < LOW_PM && strlen(bp) > 2
2754 && (mntmp = name_to_mon(bp)) >= LOW_PM) {
2755 int mntmptoo,
2756 mntmplen; /* double check for rank title */
2757 char *obp = bp;
2758 mntmptoo = title_to_mon(bp, (int *) 0, &mntmplen);
2759 bp += mntmp != mntmptoo
2760 ? (int) strlen(mons[mntmp].mname)
2761 : mntmplen;
2762 if (*bp == ' ')
2763 bp++;
2764 else if (!strncmpi(bp, "s ", 2))
2765 bp += 2;
2766 else if (!strncmpi(bp, "es ", 3))
2767 bp += 3;
2768 else if (!*bp && !actualn && !dn && !un
2769 && !oclass) {
2770 /* no referent; they don't really mean a
2771 * monster type */
2772 bp = obp;
2773 mntmp = NON_PM;
2777 /* first change to singular if necessary */
2778 if (*bp) {
2779 char *sng = makesingular(bp);
2780 if (strcmp(bp, sng)) {
2781 if (cnt == 1)
2782 cnt = 2;
2783 Strcpy(bp, sng);
2787 /* Alternate spellings (pick-ax, silver sabre, &c) */
2789 struct alt_spellings *as = spellings;
2791 while (as->sp) {
2792 if (fuzzymatch(bp, as->sp, " -", TRUE)) {
2793 typ = as->ob;
2794 goto typfnd;
2796 as++;
2798 /* can't use spellings list for this one due to shuffling */
2799 if (!strncmpi(bp, "grey spell", 10))
2800 *(bp + 2) = 'a';
2802 if ((p = strstri(bp, "armour")) != 0) {
2803 /* skip past "armo", then copy remainder beyond "u" */
2804 p += 4;
2805 while ((*p = *(p + 1)) != '\0')
2806 ++p; /* self terminating */
2810 /* dragon scales - assumes order of dragons */
2811 if (!strcmpi(bp, "scales") && mntmp >= PM_GRAY_DRAGON
2812 && mntmp <= PM_YELLOW_DRAGON) {
2813 typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
2814 mntmp = NON_PM; /* no monster */
2815 goto typfnd;
2818 p = eos(bp);
2819 if (!BSTRCMPI(bp, p - 10, "holy water")) {
2820 typ = POT_WATER;
2821 if ((p - bp) >= 12 && *(p - 12) == 'u')
2822 iscursed = 1; /* unholy water */
2823 else
2824 blessed = 1;
2825 goto typfnd;
2827 if (unlabeled && !BSTRCMPI(bp, p - 6, "scroll")) {
2828 typ = SCR_BLANK_PAPER;
2829 goto typfnd;
2831 if (unlabeled && !BSTRCMPI(bp, p - 9, "spellbook")) {
2832 typ = SPE_BLANK_PAPER;
2833 goto typfnd;
2836 * NOTE: Gold pieces are handled as objects nowadays, and therefore
2837 * this section should probably be reconsidered as well as the entire
2838 * gold/money concept. Maybe we want to add other monetary units as
2839 * well in the future. (TH)
2841 if (!BSTRCMPI(bp, p - 10, "gold piece") || !BSTRCMPI(bp, p - 7, "zorkmid")
2842 || !strcmpi(bp, "gold") || !strcmpi(bp, "money")
2843 || !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
2844 if (cnt > 5000 && !wizard)
2845 cnt = 5000;
2846 else if (cnt < 1)
2847 cnt = 1;
2848 otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
2849 otmp->quan = (long) cnt;
2850 otmp->owt = weight(otmp);
2851 context.botl = 1;
2852 return otmp;
2855 /* check for single character object class code ("/" for wand, &c) */
2856 if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES
2857 && i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) {
2858 oclass = i;
2859 goto any;
2862 /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */
2863 /* false hits on, e.g., rings for "ring mail". */
2864 if (strncmpi(bp, "enchant ", 8) && strncmpi(bp, "destroy ", 8)
2865 && strncmpi(bp, "detect food", 11)
2866 && strncmpi(bp, "food detection", 14) && strncmpi(bp, "ring mail", 9)
2867 && strncmpi(bp, "studded leather armor", 21)
2868 && strncmpi(bp, "leather armor", 13)
2869 && strncmpi(bp, "tooled horn", 11) && strncmpi(bp, "food ration", 11)
2870 && strncmpi(bp, "meat ring", 9))
2871 for (i = 0; i < (int) (sizeof wrpsym); i++) {
2872 register int j = strlen(wrp[i]);
2873 if (!strncmpi(bp, wrp[i], j)) {
2874 oclass = wrpsym[i];
2875 if (oclass != AMULET_CLASS) {
2876 bp += j;
2877 if (!strncmpi(bp, " of ", 4))
2878 actualn = bp + 4;
2879 /* else if(*bp) ?? */
2880 } else
2881 actualn = bp;
2882 goto srch;
2884 if (!BSTRCMPI(bp, p - j, wrp[i])) {
2885 oclass = wrpsym[i];
2886 p -= j;
2887 *p = 0;
2888 if (p > bp && p[-1] == ' ')
2889 p[-1] = 0;
2890 actualn = dn = bp;
2891 goto srch;
2895 /* Wishing in wizard mode can create traps and furniture.
2896 * Part I: distinguish between trap and object for the two
2897 * types of traps which have corresponding objects: bear trap
2898 * and land mine. "beartrap" (object) and "bear trap" (trap)
2899 * have a difference in spelling which we used to exploit by
2900 * adding a special case in wishymatch(), but "land mine" is
2901 * spelled the same either way so needs different handing.
2902 * Since we need something else for land mine, we've dropped
2903 * the bear trap hack so that both are handled exactly the
2904 * same. To get an armed trap instead of a disarmed object,
2905 * the player can prefix either the object name or the trap
2906 * name with "trapped " (which ordinarily applies to chests
2907 * and tins), or append something--anything at all except for
2908 * " object", but " trap" is suggested--to either the trap
2909 * name or the object name.
2911 if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) {
2912 boolean beartrap = (lowc(*bp) == 'b');
2913 char *zp = bp + 4; /* skip "bear"/"land" */
2915 if (*zp == ' ')
2916 ++zp; /* embedded space is optional */
2917 if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) {
2918 zp += 4;
2919 if (trapped == 2 || !strcmpi(zp, " object")) {
2920 /* "untrapped <foo>" or "<foo> object" */
2921 typ = beartrap ? BEARTRAP : LAND_MINE;
2922 goto typfnd;
2923 } else if (trapped == 1 || *zp != '\0') {
2924 /* "trapped <foo>" or "<foo> trap" (actually "<foo>*") */
2925 int idx = trap_to_defsym(beartrap ? BEAR_TRAP : LANDMINE);
2927 /* use canonical trap spelling, skip object matching */
2928 Strcpy(bp, defsyms[idx].explanation);
2929 goto wiztrap;
2931 /* [no prefix or suffix; we're going to end up matching
2932 the object name and getting a disarmed trap object] */
2936 retry:
2937 /* "grey stone" check must be before general "stone" */
2938 for (i = 0; i < SIZE(o_ranges); i++)
2939 if (!strcmpi(bp, o_ranges[i].name)) {
2940 typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
2941 goto typfnd;
2944 if (!BSTRCMPI(bp, p - 6, " stone") || !BSTRCMPI(bp, p - 4, " gem")) {
2945 p[!strcmpi(p - 4, " gem") ? -4 : -6] = '\0';
2946 oclass = GEM_CLASS;
2947 dn = actualn = bp;
2948 goto srch;
2949 } else if (!strcmpi(bp, "looking glass")) {
2950 ; /* avoid false hit on "* glass" */
2951 } else if (!BSTRCMPI(bp, p - 6, " glass") || !strcmpi(bp, "glass")) {
2952 register char *g = bp;
2953 if (strstri(g, "broken"))
2954 return (struct obj *) 0;
2955 if (!strncmpi(g, "worthless ", 10))
2956 g += 10;
2957 if (!strncmpi(g, "piece of ", 9))
2958 g += 9;
2959 if (!strncmpi(g, "colored ", 8))
2960 g += 8;
2961 else if (!strncmpi(g, "coloured ", 9))
2962 g += 9;
2963 if (!strcmpi(g, "glass")) { /* choose random color */
2964 /* 9 different kinds */
2965 typ = LAST_GEM + rnd(9);
2966 if (objects[typ].oc_class == GEM_CLASS)
2967 goto typfnd;
2968 else
2969 typ = 0; /* somebody changed objects[]? punt */
2970 } else { /* try to construct canonical form */
2971 char tbuf[BUFSZ];
2973 Strcpy(tbuf, "worthless piece of ");
2974 Strcat(tbuf, g); /* assume it starts with the color */
2975 Strcpy(bp, tbuf);
2979 actualn = bp;
2980 if (!dn)
2981 dn = actualn; /* ex. "skull cap" */
2982 srch:
2983 /* check real names of gems first */
2984 if (!oclass && actualn) {
2985 for (i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
2986 register const char *zn;
2988 if ((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
2989 typ = i;
2990 goto typfnd;
2994 i = oclass ? bases[(int) oclass] : 1;
2995 while (i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)) {
2996 register const char *zn;
2998 if (actualn && (zn = OBJ_NAME(objects[i])) != 0
2999 && wishymatch(actualn, zn, TRUE)) {
3000 typ = i;
3001 goto typfnd;
3003 if (dn && (zn = OBJ_DESCR(objects[i])) != 0
3004 && wishymatch(dn, zn, FALSE)) {
3005 /* don't match extra descriptions (w/o real name) */
3006 if (!OBJ_NAME(objects[i]))
3007 return (struct obj *) 0;
3008 typ = i;
3009 goto typfnd;
3011 if (un && (zn = objects[i].oc_uname) != 0
3012 && wishymatch(un, zn, FALSE)) {
3013 typ = i;
3014 goto typfnd;
3016 i++;
3018 if (actualn) {
3019 struct Jitem *j = Japanese_items;
3021 while (j->item) {
3022 if (actualn && !strcmpi(actualn, j->name)) {
3023 typ = j->item;
3024 goto typfnd;
3026 j++;
3029 /* if we've stripped off "armor" and failed to match anything
3030 in objects[], append "mail" and try again to catch misnamed
3031 requests like "plate armor" and "yellow dragon scale armor" */
3032 if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) {
3033 /* modifying bp's string is ok; we're about to resort
3034 to random armor if this also fails to match anything */
3035 Strcat(bp, " mail");
3036 goto retry;
3038 if (!strcmpi(bp, "spinach")) {
3039 contents = SPINACH;
3040 typ = TIN;
3041 goto typfnd;
3043 /* Note: not strcmpi. 2 fruits, one capital, one not, are possible.
3044 Also not strncmp. We used to ignore trailing text with it, but
3045 that resulted in "grapefruit" matching "grape" if the latter came
3046 earlier than the former in the fruit list. */
3048 char *fp;
3049 int l, cntf;
3050 int blessedf, iscursedf, uncursedf, halfeatenf;
3052 blessedf = iscursedf = uncursedf = halfeatenf = 0;
3053 cntf = 0;
3055 fp = fruitbuf;
3056 for (;;) {
3057 if (!fp || !*fp)
3058 break;
3059 if (!strncmpi(fp, "an ", l = 3) || !strncmpi(fp, "a ", l = 2)) {
3060 cntf = 1;
3061 } else if (!cntf && digit(*fp)) {
3062 cntf = atoi(fp);
3063 while (digit(*fp))
3064 fp++;
3065 while (*fp == ' ')
3066 fp++;
3067 l = 0;
3068 } else if (!strncmpi(fp, "blessed ", l = 8)) {
3069 blessedf = 1;
3070 } else if (!strncmpi(fp, "cursed ", l = 7)) {
3071 iscursedf = 1;
3072 } else if (!strncmpi(fp, "uncursed ", l = 9)) {
3073 uncursedf = 1;
3074 } else if (!strncmpi(fp, "partly eaten ", l = 13)
3075 || !strncmpi(fp, "partially eaten ", l = 16)) {
3076 halfeatenf = 1;
3077 } else
3078 break;
3079 fp += l;
3082 for (f = ffruit; f; f = f->nextf) {
3083 /* match type: 0=none, 1=exact, 2=singular, 3=plural */
3084 int ftyp = 0;
3086 if (!strcmp(fp, f->fname))
3087 ftyp = 1;
3088 else if (!strcmp(fp, makesingular(f->fname)))
3089 ftyp = 2;
3090 else if (!strcmp(fp, makeplural(f->fname)))
3091 ftyp = 3;
3092 if (ftyp) {
3093 typ = SLIME_MOLD;
3094 blessed = blessedf;
3095 iscursed = iscursedf;
3096 uncursed = uncursedf;
3097 halfeaten = halfeatenf;
3098 /* adjust count if user explicitly asked for
3099 singular amount (can't happen unless fruit
3100 has been given an already pluralized name)
3101 or for plural amount */
3102 if (ftyp == 2 && !cntf)
3103 cntf = 1;
3104 else if (ftyp == 3 && !cntf)
3105 cntf = 2;
3106 cnt = cntf;
3107 ftype = f->fid;
3108 goto typfnd;
3113 if (!oclass && actualn) {
3114 short objtyp;
3116 /* Perhaps it's an artifact specified by name, not type */
3117 name = artifact_name(actualn, &objtyp);
3118 if (name) {
3119 typ = objtyp;
3120 goto typfnd;
3123 /* Let wizards wish for traps and furniture.
3124 * Must come after objects check so wizards can still wish for
3125 * trap objects like beartraps.
3126 * Disallow such topology tweaks for WIZKIT startup wishes.
3128 wiztrap:
3129 if (wizard && !program_state.wizkit_wishing) {
3130 struct rm *lev;
3131 int trap, x = u.ux, y = u.uy;
3133 for (trap = NO_TRAP + 1; trap < TRAPNUM; trap++) {
3134 struct trap *t;
3135 const char *tname;
3137 tname = defsyms[trap_to_defsym(trap)].explanation;
3138 if (strncmpi(tname, bp, strlen(tname)))
3139 continue;
3140 /* found it; avoid stupid mistakes */
3141 if ((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz))
3142 trap = ROCKTRAP;
3143 if ((t = maketrap(x, y, trap)) != 0) {
3144 trap = t->ttyp;
3145 tname = defsyms[trap_to_defsym(trap)].explanation;
3146 pline("%s%s.", An(tname),
3147 (trap != MAGIC_PORTAL) ? "" : " to nowhere");
3148 } else
3149 pline("Creation of %s failed.", an(tname));
3150 return &zeroobj;
3153 /* furniture and terrain */
3154 lev = &levl[x][y];
3155 p = eos(bp);
3156 if (!BSTRCMPI(bp, p - 8, "fountain")) {
3157 lev->typ = FOUNTAIN;
3158 level.flags.nfountains++;
3159 if (!strncmpi(bp, "magic ", 6))
3160 lev->blessedftn = 1;
3161 pline("A %sfountain.", lev->blessedftn ? "magic " : "");
3162 newsym(x, y);
3163 return &zeroobj;
3165 if (!BSTRCMPI(bp, p - 6, "throne")) {
3166 lev->typ = THRONE;
3167 pline("A throne.");
3168 newsym(x, y);
3169 return &zeroobj;
3171 if (!BSTRCMPI(bp, p - 4, "sink")) {
3172 lev->typ = SINK;
3173 level.flags.nsinks++;
3174 pline("A sink.");
3175 newsym(x, y);
3176 return &zeroobj;
3178 /* ("water" matches "potion of water" rather than terrain) */
3179 if (!BSTRCMPI(bp, p - 4, "pool") || !BSTRCMPI(bp, p - 4, "moat")) {
3180 lev->typ = !BSTRCMPI(bp, p - 4, "pool") ? POOL : MOAT;
3181 del_engr_at(x, y);
3182 pline("A %s.", (lev->typ == POOL) ? "pool" : "moat");
3183 /* Must manually make kelp! */
3184 water_damage_chain(level.objects[x][y], TRUE);
3185 newsym(x, y);
3186 return &zeroobj;
3188 if (!BSTRCMPI(bp, p - 4, "lava")) { /* also matches "molten lava" */
3189 lev->typ = LAVAPOOL;
3190 del_engr_at(x, y);
3191 pline("A pool of molten lava.");
3192 if (!(Levitation || Flying))
3193 (void) lava_effects();
3194 newsym(x, y);
3195 return &zeroobj;
3198 if (!BSTRCMPI(bp, p - 5, "altar")) {
3199 aligntyp al;
3201 lev->typ = ALTAR;
3202 if (!strncmpi(bp, "chaotic ", 8))
3203 al = A_CHAOTIC;
3204 else if (!strncmpi(bp, "neutral ", 8))
3205 al = A_NEUTRAL;
3206 else if (!strncmpi(bp, "lawful ", 7))
3207 al = A_LAWFUL;
3208 else if (!strncmpi(bp, "unaligned ", 10))
3209 al = A_NONE;
3210 else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
3211 al = (!rn2(6)) ? A_NONE : rn2((int) A_LAWFUL + 2) - 1;
3212 lev->altarmask = Align2amask(al);
3213 pline("%s altar.", An(align_str(al)));
3214 newsym(x, y);
3215 return &zeroobj;
3218 if (!BSTRCMPI(bp, p - 5, "grave")
3219 || !BSTRCMPI(bp, p - 9, "headstone")) {
3220 make_grave(x, y, (char *) 0);
3221 pline("%s.", IS_GRAVE(lev->typ) ? "A grave"
3222 : "Can't place a grave here");
3223 newsym(x, y);
3224 return &zeroobj;
3227 if (!BSTRCMPI(bp, p - 4, "tree")) {
3228 lev->typ = TREE;
3229 pline("A tree.");
3230 newsym(x, y);
3231 block_point(x, y);
3232 return &zeroobj;
3235 if (!BSTRCMPI(bp, p - 4, "bars")) {
3236 lev->typ = IRONBARS;
3237 pline("Iron bars.");
3238 newsym(x, y);
3239 return &zeroobj;
3243 if (!oclass && !typ) {
3244 if (!strncmpi(bp, "polearm", 7)) {
3245 typ = rnd_otyp_by_wpnskill(P_POLEARMS);
3246 goto typfnd;
3247 } else if (!strncmpi(bp, "hammer", 6)) {
3248 typ = rnd_otyp_by_wpnskill(P_HAMMER);
3249 goto typfnd;
3253 if (!oclass)
3254 return ((struct obj *) 0);
3255 any:
3256 if (!oclass)
3257 oclass = wrpsym[rn2((int) sizeof(wrpsym))];
3258 typfnd:
3259 if (typ)
3260 oclass = objects[typ].oc_class;
3262 /* handle some objects that are only allowed in wizard mode */
3263 if (typ && !wizard) {
3264 switch (typ) {
3265 case AMULET_OF_YENDOR:
3266 typ = FAKE_AMULET_OF_YENDOR;
3267 break;
3268 case CANDELABRUM_OF_INVOCATION:
3269 typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
3270 break;
3271 case BELL_OF_OPENING:
3272 typ = BELL;
3273 break;
3274 case SPE_BOOK_OF_THE_DEAD:
3275 typ = SPE_BLANK_PAPER;
3276 break;
3277 case MAGIC_LAMP:
3278 typ = OIL_LAMP;
3279 break;
3280 default:
3281 /* catch any other non-wishable objects (venom) */
3282 if (objects[typ].oc_nowish)
3283 return (struct obj *) 0;
3284 break;
3289 * Create the object, then fine-tune it.
3291 otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE);
3292 typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */
3294 if (islit && (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN
3295 || Is_candle(otmp) || typ == POT_OIL)) {
3296 place_object(otmp, u.ux, u.uy); /* make it viable light source */
3297 begin_burn(otmp, FALSE);
3298 obj_extract_self(otmp); /* now release it for caller's use */
3301 /* if player specified a reasonable count, maybe honor it */
3302 if (cnt > 0 && objects[typ].oc_merge
3303 && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp))
3304 || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp))
3305 || typ == ROCK || is_missile(otmp)))))
3306 otmp->quan = (long) cnt;
3308 if (oclass == VENOM_CLASS)
3309 otmp->spe = 1;
3311 if (spesgn == 0) {
3312 spe = otmp->spe;
3313 } else if (wizard) {
3314 ; /* no alteration to spe */
3315 } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS
3316 || is_weptool(otmp)
3317 || (oclass == RING_CLASS && objects[typ].oc_charged)) {
3318 if (spe > rnd(5) && spe > otmp->spe)
3319 spe = 0;
3320 if (spe > 2 && Luck < 0)
3321 spesgn = -1;
3322 } else {
3323 if (oclass == WAND_CLASS) {
3324 if (spe > 1 && spesgn == -1)
3325 spe = 1;
3326 } else {
3327 if (spe > 0 && spesgn == -1)
3328 spe = 0;
3330 if (spe > otmp->spe)
3331 spe = otmp->spe;
3334 if (spesgn == -1)
3335 spe = -spe;
3337 /* set otmp->spe. This may, or may not, use spe... */
3338 switch (typ) {
3339 case TIN:
3340 if (contents == EMPTY) {
3341 otmp->corpsenm = NON_PM;
3342 otmp->spe = 0;
3343 } else if (contents == SPINACH) {
3344 otmp->corpsenm = NON_PM;
3345 otmp->spe = 1;
3347 break;
3348 case TOWEL:
3349 if (wetness)
3350 otmp->spe = wetness;
3351 break;
3352 case SLIME_MOLD:
3353 otmp->spe = ftype;
3354 /* Fall through */
3355 case SKELETON_KEY:
3356 case CHEST:
3357 case LARGE_BOX:
3358 case HEAVY_IRON_BALL:
3359 case IRON_CHAIN:
3360 case STATUE:
3361 /* otmp->cobj already done in mksobj() */
3362 break;
3363 #ifdef MAIL
3364 case SCR_MAIL:
3365 /* 0: delivered in-game via external event (or randomly for fake mail);
3366 1: from bones or wishing; 2: written with marker */
3367 otmp->spe = 1;
3368 break;
3369 #endif
3370 case WAN_WISHING:
3371 if (!wizard) {
3372 otmp->spe = (rn2(10) ? -1 : 0);
3373 break;
3375 /* fall through, if wizard */
3376 default:
3377 otmp->spe = spe;
3380 /* set otmp->corpsenm or dragon scale [mail] */
3381 if (mntmp >= LOW_PM) {
3382 if (mntmp == PM_LONG_WORM_TAIL)
3383 mntmp = PM_LONG_WORM;
3385 switch (typ) {
3386 case TIN:
3387 otmp->spe = 0; /* No spinach */
3388 if (dead_species(mntmp, FALSE)) {
3389 otmp->corpsenm = NON_PM; /* it's empty */
3390 } else if (!(mons[mntmp].geno & G_UNIQ)
3391 && !(mvitals[mntmp].mvflags & G_NOCORPSE)
3392 && mons[mntmp].cnutrit != 0) {
3393 otmp->corpsenm = mntmp;
3395 break;
3396 case CORPSE:
3397 if (!(mons[mntmp].geno & G_UNIQ)
3398 && !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
3399 if (mons[mntmp].msound == MS_GUARDIAN)
3400 mntmp = genus(mntmp, 1);
3401 set_corpsenm(otmp, mntmp);
3403 break;
3404 case FIGURINE:
3405 if (!(mons[mntmp].geno & G_UNIQ) && !is_human(&mons[mntmp])
3406 #ifdef MAIL
3407 && mntmp != PM_MAIL_DAEMON
3408 #endif
3410 otmp->corpsenm = mntmp;
3411 break;
3412 case EGG:
3413 mntmp = can_be_hatched(mntmp);
3414 /* this also sets hatch timer if appropriate */
3415 set_corpsenm(otmp, mntmp);
3416 break;
3417 case STATUE:
3418 otmp->corpsenm = mntmp;
3419 if (Has_contents(otmp) && verysmall(&mons[mntmp]))
3420 delete_contents(otmp); /* no spellbook */
3421 otmp->spe = ishistoric ? STATUE_HISTORIC : 0;
3422 break;
3423 case SCALE_MAIL:
3424 /* Dragon mail - depends on the order of objects & dragons. */
3425 if (mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON)
3426 otmp->otyp = GRAY_DRAGON_SCALE_MAIL + mntmp - PM_GRAY_DRAGON;
3427 break;
3431 /* set blessed/cursed -- setting the fields directly is safe
3432 * since weight() is called below and addinv() will take care
3433 * of luck */
3434 if (iscursed) {
3435 curse(otmp);
3436 } else if (uncursed) {
3437 otmp->blessed = 0;
3438 otmp->cursed = (Luck < 0 && !wizard);
3439 } else if (blessed) {
3440 otmp->blessed = (Luck >= 0 || wizard);
3441 otmp->cursed = (Luck < 0 && !wizard);
3442 } else if (spesgn < 0) {
3443 curse(otmp);
3446 /* set eroded */
3447 if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) {
3448 if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
3449 otmp->oeroded = eroded;
3450 if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
3451 otmp->oeroded2 = eroded2;
3453 /* set erodeproof */
3454 if (erodeproof && !eroded && !eroded2)
3455 otmp->oerodeproof = (Luck >= 0 || wizard);
3458 /* set otmp->recharged */
3459 if (oclass == WAND_CLASS) {
3460 /* prevent wishing abuse */
3461 if (otmp->otyp == WAN_WISHING && !wizard)
3462 rechrg = 1;
3463 otmp->recharged = (unsigned) rechrg;
3466 /* set poisoned */
3467 if (ispoisoned) {
3468 if (is_poisonable(otmp))
3469 otmp->opoisoned = (Luck >= 0);
3470 else if (oclass == FOOD_CLASS)
3471 /* try to taint by making it as old as possible */
3472 otmp->age = 1L;
3474 /* and [un]trapped */
3475 if (trapped) {
3476 if (Is_box(otmp) || typ == TIN)
3477 otmp->otrapped = (trapped == 1);
3480 if (isgreased)
3481 otmp->greased = 1;
3483 if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER)
3484 otmp->odiluted = 1;
3486 /* set tin variety */
3487 if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard))
3488 set_tin_variety(otmp, tvariety);
3490 if (name) {
3491 const char *aname;
3492 short objtyp;
3494 /* an artifact name might need capitalization fixing */
3495 aname = artifact_name(name, &objtyp);
3496 if (aname && objtyp == otmp->otyp)
3497 name = aname;
3499 /* 3.6 tribute - fix up novel */
3500 if (otmp->otyp == SPE_NOVEL) {
3501 const char *novelname;
3503 novelname = lookup_novel(name, &otmp->novelidx);
3504 if (novelname)
3505 name = novelname;
3508 otmp = oname(otmp, name);
3509 if (otmp->oartifact) {
3510 otmp->quan = 1L;
3511 u.uconduct.wisharti++; /* KMH, conduct */
3515 /* more wishing abuse: don't allow wishing for certain artifacts */
3516 /* and make them pay; charge them for the wish anyway! */
3517 if ((is_quest_artifact(otmp)
3518 || (otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) {
3519 artifact_exists(otmp, safe_oname(otmp), FALSE);
3520 obfree(otmp, (struct obj *) 0);
3521 otmp = &zeroobj;
3522 pline("For a moment, you feel %s in your %s, but it disappears!",
3523 something, makeplural(body_part(HAND)));
3526 if (halfeaten && otmp->oclass == FOOD_CLASS) {
3527 if (otmp->otyp == CORPSE)
3528 otmp->oeaten = mons[otmp->corpsenm].cnutrit;
3529 else
3530 otmp->oeaten = objects[otmp->otyp].oc_nutrition;
3531 /* (do this adjustment before setting up object's weight) */
3532 consume_oeaten(otmp, 1);
3534 otmp->owt = weight(otmp);
3535 if (very && otmp->otyp == HEAVY_IRON_BALL)
3536 otmp->owt += IRON_BALL_W_INCR;
3538 return otmp;
3542 rnd_class(first, last)
3543 int first, last;
3545 int i, x, sum = 0;
3547 if (first == last)
3548 return first;
3549 for (i = first; i <= last; i++)
3550 sum += objects[i].oc_prob;
3551 if (!sum) /* all zero */
3552 return first + rn2(last - first + 1);
3553 x = rnd(sum);
3554 for (i = first; i <= last; i++)
3555 if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
3556 return i;
3557 return 0;
3560 STATIC_OVL const char *
3561 Japanese_item_name(i)
3562 int i;
3564 struct Jitem *j = Japanese_items;
3566 while (j->item) {
3567 if (i == j->item)
3568 return j->name;
3569 j++;
3571 return (const char *) 0;
3574 const char *
3575 suit_simple_name(suit)
3576 struct obj *suit;
3578 const char *suitnm, *esuitp;
3580 if (Is_dragon_mail(suit))
3581 return "dragon mail"; /* <color> dragon scale mail */
3582 else if (Is_dragon_scales(suit))
3583 return "dragon scales";
3584 suitnm = OBJ_NAME(objects[suit->otyp]);
3585 esuitp = eos((char *) suitnm);
3586 if (strlen(suitnm) > 5 && !strcmp(esuitp - 5, " mail"))
3587 return "mail"; /* most suits fall into this category */
3588 else if (strlen(suitnm) > 7 && !strcmp(esuitp - 7, " jacket"))
3589 return "jacket"; /* leather jacket */
3590 /* suit is lame but armor is ambiguous and body armor is absurd */
3591 return "suit";
3594 const char *
3595 cloak_simple_name(cloak)
3596 struct obj *cloak;
3598 if (cloak) {
3599 switch (cloak->otyp) {
3600 case ROBE:
3601 return "robe";
3602 case MUMMY_WRAPPING:
3603 return "wrapping";
3604 case ALCHEMY_SMOCK:
3605 return (objects[cloak->otyp].oc_name_known && cloak->dknown)
3606 ? "smock"
3607 : "apron";
3608 default:
3609 break;
3612 return "cloak";
3615 /* helm vs hat for messages */
3616 const char *
3617 helm_simple_name(helmet)
3618 struct obj *helmet;
3621 * There is some wiggle room here; the result has been chosen
3622 * for consistency with the "protected by hard helmet" messages
3623 * given for various bonks on the head: headgear that provides
3624 * such protection is a "helm", that which doesn't is a "hat".
3626 * elven leather helm / leather hat -> hat
3627 * dwarvish iron helm / hard hat -> helm
3628 * The rest are completely straightforward:
3629 * fedora, cornuthaum, dunce cap -> hat
3630 * all other types of helmets -> helm
3632 return (helmet && !is_metallic(helmet)) ? "hat" : "helm";
3635 const char *
3636 mimic_obj_name(mtmp)
3637 struct monst *mtmp;
3639 if (mtmp->m_ap_type == M_AP_OBJECT
3640 && mtmp->mappearance != STRANGE_OBJECT) {
3641 int idx = objects[mtmp->mappearance].oc_descr_idx;
3642 if (mtmp->mappearance == GOLD_PIECE)
3643 return "gold";
3644 return obj_descr[idx].oc_name;
3646 return "whatcha-may-callit";
3650 * Construct a query prompt string, based around an object name, which is
3651 * guaranteed to fit within [QBUFSZ]. Takes an optional prefix, three
3652 * choices for filling in the middle (two object formatting functions and a
3653 * last resort literal which should be very short), and an optional suffix.
3655 char *
3656 safe_qbuf(qbuf, qprefix, qsuffix, obj, func, altfunc, lastR)
3657 char *qbuf; /* output buffer */
3658 const char *qprefix, *qsuffix;
3659 struct obj *obj;
3660 char *FDECL((*func), (OBJ_P)), *FDECL((*altfunc), (OBJ_P));
3661 const char *lastR;
3663 char *bufp, *endp;
3664 /* convert size_t (or int for ancient systems) to ordinary unsigned */
3665 unsigned len, lenlimit,
3666 len_qpfx = (unsigned) (qprefix ? strlen(qprefix) : 0),
3667 len_qsfx = (unsigned) (qsuffix ? strlen(qsuffix) : 0),
3668 len_lastR = (unsigned) strlen(lastR);
3670 lenlimit = QBUFSZ - 1;
3671 endp = qbuf + lenlimit;
3672 /* sanity check, aimed mainly at paniclog (it's conceivable for
3673 the result of short_oname() to be shorter than the length of
3674 the last resort string, but we ignore that possibility here) */
3675 if (len_qpfx > lenlimit)
3676 impossible("safe_qbuf: prefix too long (%u characters).", len_qpfx);
3677 else if (len_qpfx + len_qsfx > lenlimit)
3678 impossible("safe_qbuf: suffix too long (%u + %u characters).",
3679 len_qpfx, len_qsfx);
3680 else if (len_qpfx + len_lastR + len_qsfx > lenlimit)
3681 impossible("safe_qbuf: filler too long (%u + %u + %u characters).",
3682 len_qpfx, len_lastR, len_qsfx);
3684 /* the output buffer might be the same as the prefix if caller
3685 has already partially filled it */
3686 if (qbuf == qprefix) {
3687 /* prefix is already in the buffer */
3688 *endp = '\0';
3689 } else if (qprefix) {
3690 /* put prefix into the buffer */
3691 (void) strncpy(qbuf, qprefix, lenlimit);
3692 *endp = '\0';
3693 } else {
3694 /* no prefix; output buffer starts out empty */
3695 qbuf[0] = '\0';
3697 len = (unsigned) strlen(qbuf);
3699 if (len + len_lastR + len_qsfx > lenlimit) {
3700 /* too long; skip formatting, last resort output is truncated */
3701 if (len < lenlimit) {
3702 (void) strncpy(&qbuf[len], lastR, lenlimit - len);
3703 *endp = '\0';
3704 len = (unsigned) strlen(qbuf);
3705 if (qsuffix && len < lenlimit) {
3706 (void) strncpy(&qbuf[len], qsuffix, lenlimit - len);
3707 *endp = '\0';
3708 /* len = (unsigned) strlen(qbuf); */
3711 } else {
3712 /* suffix and last resort are guaranteed to fit */
3713 len += len_qsfx; /* include the pending suffix */
3714 /* format the object */
3715 bufp = short_oname(obj, func, altfunc, lenlimit - len);
3716 if (len + strlen(bufp) <= lenlimit)
3717 Strcat(qbuf, bufp); /* formatted name fits */
3718 else
3719 Strcat(qbuf, lastR); /* use last resort */
3720 releaseobuf(bufp);
3722 if (qsuffix)
3723 Strcat(qbuf, qsuffix);
3725 /* assert( strlen(qbuf) < QBUFSZ ); */
3726 return qbuf;
3729 /*objnam.c*/