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. */
7 /* "an uncursed greased partly eaten guardian naga hatchling [corpse]" */
8 #define PREFIX 80 /* (56) */
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 *));
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));
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) \
37 || (objects[typ].oc_material == GEMSTONE \
38 && (typ != DILITHIUM_CRYSTAL && typ != RUBY && typ != DIAMOND \
39 && typ != SAPPHIRE && typ != BLACK_OPAL && typ != EMERALD \
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" },
49 { PLATE_MAIL
, "tanko" },
51 { LEATHER_GLOVES
, "yugake" },
52 { FOOD_RATION
, "gunyoki" },
53 { POT_BOOZE
, "sake" },
56 STATIC_DCL
const char *FDECL(Japanese_item_name
, (int i
));
61 register const char *pref
;
63 register int i
= (int) strlen(pref
);
66 impossible("PREFIX too short (for %d).", i
);
70 (void) strncpy(s
, pref
, i
); /* do not copy trailing 0 */
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;
81 obufidx
= (obufidx
+ 1) % NUMOBUF
;
82 return obufs
[obufidx
];
85 /* put the most recently allocated buffer back if possible */
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
;
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
) {
114 Strcpy(buf
, "potion");
117 Strcpy(buf
, "scroll");
123 if (otyp
!= SPE_NOVEL
) {
124 Strcpy(buf
, "spellbook");
126 Strcpy(buf
, !nn
? "book" : "novel");
135 Strcpy(buf
, actualn
);
137 Strcpy(buf
, "amulet");
139 Sprintf(eos(buf
), " called %s", un
);
141 Sprintf(eos(buf
), " (%s)", dn
);
145 Strcpy(buf
, actualn
);
147 Strcat(buf
, " stone");
149 Sprintf(eos(buf
), " called %s", un
);
151 Sprintf(eos(buf
), " (%s)", dn
);
153 Strcpy(buf
, dn
? dn
: actualn
);
154 if (ocl
->oc_class
== GEM_CLASS
)
156 (ocl
->oc_material
== MINERAL
) ? " stone" : " gem");
158 Sprintf(eos(buf
), " called %s", un
);
162 /* here for ring/scroll/potion/wand */
165 Strcpy(buf
, actualn
); /* avoid spellbook of Book of the Dead */
167 Sprintf(eos(buf
), " of %s", actualn
);
170 Sprintf(eos(buf
), " called %s", un
);
172 Sprintf(eos(buf
), " (%s)", dn
);
176 /* less verbose result than obj_typename(); either the actual name
177 or the description (but not both); user-assigned name is ignored */
179 simple_typename(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 */
196 if (!obj
->oartifact
|| !has_oname(obj
))
198 if (!program_state
.gameover
&& !iflags
.override_ID
) {
199 if (not_fully_identified(obj
))
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.
214 distant_name(obj
, func
)
216 char *FDECL((*func
), (OBJ_P
));
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.
234 /* convert player specified fruit name into corresponding fruit juice name
235 ("slice of pizza" -> "pizza juice" rather than "slice of pizza 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 ");
244 fruit_nam
+= 4; /* skip past " of " */
246 fruit_nam
= pl_fruit
; /* use it as is */
248 Sprintf(buf
, "%s%s", makesingular(fruit_nam
), juice
? " juice" : "");
256 return xname_flags(obj
, CXN_NORMAL
);
260 xname_flags(obj
, cxn_flags
)
261 register struct obj
*obj
;
262 unsigned cxn_flags
; /* bitmask of CXN_xxx values */
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
);
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
)
287 if (!Blind
&& !distantname
)
289 if (Role_if(PM_PRIEST
))
292 if (iflags
.override_ID
) {
293 known
= dknown
= bknown
= TRUE
;
297 dknown
= obj
->dknown
;
298 bknown
= obj
->bknown
;
301 if (obj_is_pname(obj
))
303 switch (obj
->oclass
) {
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
);
311 Strcpy(buf
, actualn
);
313 Sprintf(buf
, "amulet called %s", un
);
315 Sprintf(buf
, "%s amulet", dn
);
318 if (is_poisonable(obj
) && obj
->opoisoned
)
319 Strcpy(buf
, "poisoned ");
323 Strcpy(buf
, "pair of ");
324 else if (is_wet_towel(obj
))
325 Strcpy(buf
, (obj
->spe
< 3) ? "moist " : "wet ");
328 Strcat(buf
, dn
? dn
: actualn
);
330 Strcat(buf
, actualn
);
332 Strcat(buf
, dn
? dn
: actualn
);
333 Strcat(buf
, " called ");
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" : "",
343 } else if (is_wet_towel(obj
)) {
345 Sprintf(eos(buf
), " (%d)", obj
->spe
);
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
);
354 if (is_boots(obj
) || is_gloves(obj
))
355 Strcpy(buf
, "pair of ");
357 if (obj
->otyp
>= ELVEN_SHIELD
&& obj
->otyp
<= ORCISH_SHIELD
359 Strcpy(buf
, "shield");
362 if (obj
->otyp
== SHIELD_OF_REFLECTION
&& !dknown
) {
363 Strcpy(buf
, "smooth shield");
368 Strcat(buf
, actualn
);
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");
381 Strcpy(buf
, "armor");
382 Strcat(buf
, " called ");
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
);
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
)));
409 if (Is_pudding(obj
)) {
422 Strcpy(buf
, actualn
);
423 if (typ
== TIN
&& known
)
424 tin_details(obj
, omndx
, buf
);
428 Strcpy(buf
, actualn
);
431 if (typ
== STATUE
&& omndx
!= NON_PM
)
432 Sprintf(buf
, "%s%s of %s%s",
433 (Role_if(PM_ARCHEOLOGIST
) && (obj
->spe
& STATUE_HISTORIC
))
437 type_is_pname(&mons
[omndx
])
439 : the_unique_pm(&mons
[omndx
])
441 : index(vowels
, *mons
[omndx
].mname
)
446 Strcpy(buf
, actualn
);
449 Sprintf(buf
, "%sheavy iron ball",
450 (obj
->owt
> ocl
->oc_weight
) ? "very " : "");
453 if (dknown
&& obj
->odiluted
)
454 Strcpy(buf
, "diluted ");
455 if (nn
|| un
|| !dknown
) {
456 Strcat(buf
, "potion");
461 if (typ
== POT_WATER
&& bknown
462 && (obj
->blessed
|| obj
->cursed
)) {
463 Strcat(buf
, obj
->blessed
? "holy " : "unholy ");
465 Strcat(buf
, actualn
);
467 Strcat(buf
, " called ");
472 Strcat(buf
, " potion");
476 Strcpy(buf
, "scroll");
481 Strcat(buf
, actualn
);
483 Strcat(buf
, " called ");
485 } else if (ocl
->oc_magic
) {
486 Strcat(buf
, " labeled ");
490 Strcat(buf
, " scroll");
497 Sprintf(buf
, "wand of %s", actualn
);
499 Sprintf(buf
, "wand called %s", un
);
501 Sprintf(buf
, "%s wand", dn
);
504 if (typ
== SPE_NOVEL
) { /* 3.6 tribute */
508 Strcpy(buf
, actualn
);
510 Sprintf(buf
, "novel called %s", un
);
512 Sprintf(buf
, "%s book", dn
);
515 } else if (!dknown
) {
516 Strcpy(buf
, "spellbook");
518 if (typ
!= SPE_BOOK_OF_THE_DEAD
)
519 Strcpy(buf
, "spellbook of ");
520 Strcat(buf
, actualn
);
522 Sprintf(buf
, "spellbook called %s", un
);
524 Sprintf(buf
, "%s spellbook", dn
);
530 Sprintf(buf
, "ring of %s", actualn
);
532 Sprintf(buf
, "ring called %s", un
);
534 Sprintf(buf
, "%s ring", dn
);
537 const char *rock
= (ocl
->oc_material
== MINERAL
) ? "stone" : "gem";
543 Sprintf(buf
, "%s called %s", rock
, un
);
545 Sprintf(buf
, "%s %s", dn
, rock
);
547 Strcpy(buf
, actualn
);
549 Strcat(buf
, " stone");
554 Sprintf(buf
, "glorkum %d %d %d", obj
->oclass
, typ
, obj
->spe
);
557 Strcpy(buf
, makeplural(buf
));
559 if (obj
->otyp
== T_SHIRT
&& program_state
.gameover
) {
562 Sprintf(eos(buf
), " with text \"%s\"", tshirt_text(obj
, tmpbuf
));
565 if (has_oname(obj
) && dknown
) {
566 Strcat(buf
, " named ");
568 Strcat(buf
, ONAME(obj
));
571 if (!strncmpi(buf
, "the ", 4))
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
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
;
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 */
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
)
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
;
626 /* xname() output augmented for multishot missile feedback */
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
);
643 /* used for naming "the unique_item" instead of "a unique_item" */
648 boolean known
= (obj
->known
|| iflags
.override_ID
);
650 if (!obj
->dknown
&& !iflags
.override_ID
)
652 else if (obj
->otyp
== FAKE_AMULET_OF_YENDOR
&& !known
)
653 return TRUE
; /* lie */
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) */
662 struct permonst
*ptr
;
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
))
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
])
677 /* Wizard no longer needs this; he's flagged as unique these days */
678 if (ptr
== &mons
[PM_WIZARD_OF_YENDOR
])
684 add_erosion_words(obj
, prefix
)
688 boolean iscrys
= (obj
->otyp
== CRYSKNIFE
);
691 rknown
= (iflags
.override_ID
== 0) ? obj
->rknown
: TRUE
;
693 if (!is_damageable(obj
) && !iscrys
)
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
) {
702 Strcat(prefix
, "very ");
705 Strcat(prefix
, "thoroughly ");
708 Strcat(prefix
, is_rustprone(obj
) ? "rusty " : "burnt ");
710 if (obj
->oeroded2
&& !iscrys
) {
711 switch (obj
->oeroded2
) {
713 Strcat(prefix
, "very ");
716 Strcat(prefix
, "thoroughly ");
719 Strcat(prefix
, is_corrodeable(obj
) ? "corroded " : "rotted ");
721 if (rknown
&& obj
->oerodeproof
)
722 Strcat(prefix
, iscrys
726 : is_corrodeable(obj
)
727 ? "corrodeproof " /* "stainless"? */
734 doname_base(obj
, with_price
)
735 register struct obj
*obj
;
738 boolean ispoisoned
= FALSE
;
739 boolean known
, cknown
, bknown
, lknown
;
740 int omndx
= obj
->corpsenm
;
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
;
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
) {
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] */
773 } else if (obj_is_pname(obj
) || the_unique_obj(obj
)) {
774 if (!strncmpi(bp
, "the ", 4))
776 Strcpy(prefix
, "the ");
778 Strcpy(prefix
, "a ");
781 /* "empty" goes at the beginning, but item count goes at the end */
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"
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
)
821 && obj
->otyp
!= SCR_MAIL
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
)) {
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 ");
838 Strcat(prefix
, "unlocked ");
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
,
856 switch (obj
->oclass
) {
858 if (obj
->owornmask
& W_AMUL
)
859 Strcat(bp
, " (being worn)");
863 Strcat(prefix
, "poisoned ");
865 add_erosion_words(obj
, prefix
);
867 Strcat(prefix
, sitoa(obj
->spe
));
872 if (obj
->owornmask
& W_ARMOR
)
873 Strcat(bp
, (obj
== uskin
) ? " (embedded in your skin)"
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)");
884 if (obj
->otyp
== LEASH
&& obj
->leashmon
!= 0) {
885 Strcat(bp
, " (in use)");
890 if (obj
->otyp
== CANDELABRUM_OF_INVOCATION
) {
892 Strcpy(tmpbuf
, "no");
894 Sprintf(tmpbuf
, "%d", obj
->spe
);
895 Sprintf(eos(bp
), " (%s candle%s%s)", tmpbuf
, plur(obj
->spe
),
896 !obj
->lamplit
? " attached" : ", lit");
898 } else if (obj
->otyp
== OIL_LAMP
|| obj
->otyp
== MAGIC_LAMP
899 || obj
->otyp
== BRASS_LANTERN
|| Is_candle(obj
)) {
901 && obj
->age
< 20L * (long) objects
[obj
->otyp
].oc_cost
)
902 Strcat(prefix
, "partly used ");
904 Strcat(bp
, " (lit)");
907 if (objects
[obj
->otyp
].oc_charged
)
911 add_erosion_words(obj
, prefix
);
914 Sprintf(eos(bp
), " (%d:%d)", (int) obj
->recharged
, obj
->spe
);
917 if (obj
->otyp
== POT_OIL
&& obj
->lamplit
)
918 Strcat(bp
, " (lit)");
921 add_erosion_words(obj
, prefix
);
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
));
931 if (known
&& objects
[obj
->otyp
].oc_charged
) {
932 Strcat(prefix
, sitoa(obj
->spe
));
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 ");
948 && (known
|| (mvitals
[omndx
].mvflags
& MV_KNOWS_EGG
))) {
949 Strcat(prefix
, mons
[omndx
].mname
);
952 Strcat(bp
, " (laid by you)");
955 if (obj
->otyp
== MEAT_RING
)
960 add_erosion_words(obj
, prefix
);
961 if (obj
->owornmask
& W_BALL
)
962 Strcat(bp
, " (chained to you)");
966 if ((obj
->owornmask
& W_WEP
) && !mrg_to_wielded
) {
967 if (obj
->quan
!= 1L) {
968 Strcat(bp
, " (wielded)");
970 const char *hand_s
= body_part(HAND
);
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");
980 Sprintf(eos(bp
), " %s", glow_color(obj
->oartifact
));
985 if (obj
->owornmask
& W_SWAPWEP
) {
987 Sprintf(eos(bp
), " (wielded in other %s)", body_part(HAND
));
989 Strcat(bp
, " (alternate weapon; not wielded)");
991 if (obj
->owornmask
& W_QUIVER
) {
992 switch (obj
->oclass
) {
995 if (objects
[obj
->otyp
].oc_skill
== -P_BOW
) {
997 Strcat(bp
, " (in quiver)");
1000 /* Ammo not for a bow */
1001 Strcat(bp
, " (in quiver pouch)");
1005 /* Weapons not considered ammo */
1006 Strcat(bp
, " (at the ready)");
1009 /* Small things and ammo not for a bow */
1015 Strcat(bp
, " (in quiver pouch)");
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
);
1031 Sprintf(eos(bp
), " (%ld %s)", price
, currency(price
));
1033 if (!strncmp(prefix
, "a ", 2)
1034 && index(vowels
, *(prefix
+ 2) ? *(prefix
+ 2) : *bp
)
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
);
1054 register struct obj
*obj
;
1056 return doname_base(obj
, FALSE
);
1059 /* Name of object including price. */
1061 doname_with_price(obj
)
1062 register struct obj
*obj
;
1064 return doname_base(obj
, TRUE
);
1067 /* used from invent.c */
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
1078 || (!otmp
->bknown
&& otmp
->otyp
!= SCR_MAIL
)
1082 || !objects
[otmp
->otyp
].oc_name_known
)
1084 if ((!otmp
->cknown
&& (Is_container(otmp
) || otmp
->otyp
== STATUE
))
1085 || (!otmp
->lknown
&& Is_box(otmp
)))
1087 if (otmp
->oartifact
&& undiscovered_artifact(otmp
->oartifact
))
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.
1096 || (otmp
->oclass
!= ARMOR_CLASS
&& otmp
->oclass
!= WEAPON_CLASS
1097 && !is_weptool(otmp
) /* (redundant) */
1098 && otmp
->oclass
!= BALL_CLASS
)) /* (useless) */
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 */
1108 corpse_xname(otmp
, adjective
, cxn_flags
)
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,
1125 glob
= (otmp
->otyp
!= CORPSE
&& otmp
->globby
);
1129 mname
= OBJ_NAME(objects
[otmp
->otyp
]); /* "glob of <monster>" */
1130 } else if (omndx
== NON_PM
) { /* paranoia */
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 */
1138 mname
= mons
[omndx
].mname
;
1139 if (the_unique_pm(&mons
[omndx
]) || type_is_pname(&mons
[omndx
])) {
1140 mname
= s_suffix(mname
);
1142 /* don't precede personal name like "Medusa" with an article */
1143 if (type_is_pname(&mons
[omndx
]))
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
)
1152 the_prefix
= any_prefix
= FALSE
;
1153 else if (the_prefix
)
1154 any_prefix
= FALSE
; /* mutually exclusive */
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) */
1162 Strcat(nambuf
, "the ");
1164 if (!adjective
|| !*adjective
) {
1165 /* normal case: newt corpse */
1166 Strcat(nambuf
, mname
);
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 */
1175 /* doname() might include a count in the adjective argument;
1176 if so, don't prepend an article */
1177 if (digit(*adjective
))
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 */
1195 Strcpy(nambuf
, an(nambuf
));
1200 /* xname doesn't include monster type for "corpse"; cxname does */
1205 if (obj
->otyp
== CORPSE
)
1206 return corpse_xname(obj
, (const char *) 0, CXN_NORMAL
);
1210 /* like cxname, but ignores quantity */
1212 cxname_singular(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 */
1225 struct obj save_obj
;
1226 unsigned save_ocknown
;
1227 char *buf
, *save_ocuname
, *save_oname
= (char *) 0;
1229 /* bypass object twiddling for artifacts */
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 */
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;
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 */
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
) {
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 */
1271 Sprintf(buf
, "deadly slime mold%s", plur(obj
->quan
));
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
;
1288 /* xname,doname,&c with long results reformatted to omit some stuff */
1290 short_oname(obj
, func
, altfunc
, lenlimit
)
1292 char *FDECL((*func
), (OBJ_P
)), /* main formatting routine */
1293 *FDECL((*altfunc
), (OBJ_P
)); /* alternate for shortest result */
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
)
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
)
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
)
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
;
1344 /* still long; strip several name-lengthening attributes;
1345 called and named strings are still in truncated form */
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 */
1360 ONAME(obj
) = save_oname
;
1362 objects
[obj
->otyp
].oc_uname
= save_uname
;
1364 /* use whatever we've got, whether it's too long or not */
1369 * Used if only one of a collection of objects is named (e.g. in eat.c).
1372 singular(otmp
, func
)
1373 register struct obj
*otmp
;
1374 char *FDECL((*func
), (OBJ_P
));
1379 /* using xname for corpses does not give the monster type */
1380 if (otmp
->otyp
== CORPSE
&& func
== xname
)
1383 savequan
= otmp
->quan
;
1385 nam
= (*func
)(otmp
);
1386 otmp
->quan
= savequan
;
1392 register const char *str
;
1394 char *buf
= nextobuf();
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))
1416 char *tmp
= an(str
);
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.
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);
1437 } else if (*str
< 'A' || *str
> 'Z') {
1438 /* not a proper name, needs an article */
1441 /* Probably a proper name, might not need an article */
1442 register char *tmp
, *named
, *called
;
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')) {
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
))
1457 if (tmp
&& (!named
|| tmp
< named
)) /* found an "of" */
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"))
1467 Strcpy(buf
, "the ");
1479 char *tmp
= the(str
);
1485 /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
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
);
1500 Strcat(bp
, otense(otmp
, verb
));
1505 /* combine yname and aobjnam eg "your count cxname(otmp)" */
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
);
1525 /* combine Yname2 and aobjnam eg "Your count cxname(otmp)" */
1531 register char *s
= yobjnam(obj
, verb
);
1537 /* like aobjnam, but prepend "The", not count, and use xname */
1543 char *bp
= The(xname(otmp
));
1547 Strcat(bp
, otense(otmp
, verb
));
1552 /* capitalized variant of doname() */
1557 char *s
= doname(obj
);
1563 /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(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
);
1583 /* capitalized variant of yname() */
1588 char *s
= yname(obj
);
1594 /* returns "your minimal_xname(obj)"
1595 * or "Foobar's minimal_xname(obj)"
1596 * or "the minimal_xname(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() */
1614 char *s
= ysimple_name(obj
);
1620 /* "scroll" or "scrolls" */
1625 char *simpleoname
= minimal_xname(obj
);
1627 if (obj
->quan
!= 1L)
1628 simpleoname
= makeplural(simpleoname
);
1632 /* "a scroll" or "scrolls"; "a silver bell" or "the Bell of Opening" */
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
);
1655 /* "the scroll" or "the scrolls" */
1660 char *simpleoname
= simpleonames(obj
);
1662 return the(simpleoname
);
1665 /* artifact's name without any object type or known/dknown/&c feedback */
1667 bare_artifactname(obj
)
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]);
1678 outbuf
= xname(obj
);
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
,
1695 /* return form of the verb (input plural) if xname(otmp) were the subject */
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
);
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",
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 */
1732 register const char *subj
;
1733 register const char *verb
;
1735 char *buf
= nextobuf(), *bspot
;
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.
1751 if (!strncmpi(subj
, "a ", 2) || !strncmpi(subj
, "an ", 3))
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)) {
1763 len
= (int) strlen(subj
);
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
))
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
))
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
);
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");
1819 Strcasecpy(bspot
+ 1, "s");
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
[] = {
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" },
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" },
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
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
;
1880 for (as
= as_is
; *as
; ++as
) {
1881 al
= (int) strlen(*as
);
1882 if (!BSTRCMPI(basestr
, endstring
- al
, *as
))
1886 for (as
= alt_as_is
; *as
; ++as
) {
1887 al
= (int) strlen(*as
);
1888 if (!BSTRCMPI(basestr
, endstring
- al
, *as
))
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")) {
1899 (void) strkitten(basestr
, 's');
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 */
1919 /* searches for common compounds, ex. lump of royal jelly */
1921 singplur_compound(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 ",
1933 }, /* list of first characters for all compounds[] entries */
1934 compound_start
[] = " -";
1936 const char *const *cmpd
;
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
))
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
)))
1950 /* wasn't recognized as a compound phrase */
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.
1973 register char *spot
;
1974 char lo_c
, *str
= nextobuf();
1975 const char *excess
= (char *) 0;
1979 while (*oldstr
== ' ')
1981 if (!oldstr
|| !*oldstr
) {
1982 impossible("plural of null?");
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))
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
);
2005 while (spot
> str
&& *spot
== ' ')
2006 spot
--; /* Strip blanks from end */
2008 /* Now spot is the last character of the string */
2012 /* Single letters */
2013 if (len
== 1 || !letter(*spot
)) {
2014 Strcpy(spot
+ 1, "'s");
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 */
2026 /* spot+1: synch up with makesingular's usage */
2027 if (singplur_lookup(str
, spot
+ 1, TRUE
, already_plural
))
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")))
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");
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");
2055 /* ium/ia (mycelia, baluchitheria) */
2056 if (len
>= 3 && !strcmpi(spot
- 2, "ium")) {
2057 Strcasecpy(spot
- 2, "ia");
2060 /* algae, larvae, hyphae (another fungus part) */
2061 if ((len
>= 4 && !strcmpi(spot
- 3, "alga"))
2063 && (!strcmpi(spot
- 4, "hypha") || !strcmpi(spot
- 4, "larva")))
2064 || (len
>= 6 && !strcmpi(spot
- 5, "amoeba"))
2065 || (len
>= 8 && (!strcmpi(spot
- 7, "vertebra")))) {
2067 Strcasecpy(spot
+ 1, "e");
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");
2077 /* sis/ses (nemesis) */
2078 if (len
>= 3 && !strcmpi(spot
- 2, "sis")) {
2079 Strcasecpy(spot
- 1, "es");
2082 /* matzoh/matzot, possible food name */
2084 && (!strcmpi(spot
- 5, "matzoh") || !strcmpi(spot
- 5, "matzah"))) {
2085 Strcasecpy(spot
- 1, "ot"); /* oh/ah -> ot */
2089 && (!strcmpi(spot
- 4, "matzo") || !strcmpi(spot
- 4, "matza"))) {
2090 Strcasecpy(spot
, "ot"); /* o/a -> ot */
2094 /* note: -eau/-eaux (gateau, bordeau...) */
2095 /* note: ox/oxen, VAX/VAXen, goose/geese */
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 */
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 */
2113 /* Default: append an 's' */
2114 Strcasecpy(spot
+ 1, "s");
2118 Strcat(str
, excess
);
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.
2135 makesingular(oldstr
)
2138 register char *p
, *bp
;
2139 const char *excess
= 0;
2140 char *str
= nextobuf();
2143 while (*oldstr
== ' ')
2145 if (!oldstr
|| !*oldstr
) {
2146 impossible("singular of null?");
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
);
2160 /* dispense with some words which don't need singularization */
2161 if (singplur_lookup(bp
, p
, FALSE
, special_subjs
))
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 */
2173 Strcasecpy(p
- 3, "y"); /* ies -> y */
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"))
2183 Strcasecpy(p
- 3, "f"); /* ves -> f */
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 */
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"))
2205 } else if (!BSTRCMPI(bp
, p
- 2, "ss")
2206 || !BSTRCMPI(bp
, p
- 5, " lens")
2207 || (p
- 4 == bp
&& !strcmpi(p
- 4, "lens"))) {
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");
2219 /* matzot -> matzo, algae -> alga */
2220 if (!BSTRCMPI(bp
, p
- 6, "matzot") || !BSTRCMPI(bp
, p
- 2, "ae")) {
2221 *(p
- 1) = '\0'; /* drop t/e */
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 */
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...] */
2242 /* compare user string against object name string using fuzzy matching */
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
))
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
)
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
)
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>" */
2298 Strcat(strcpy(buf
, detect_SP
), u_str
);
2299 /* "detect monster" -> "detect monsters" */
2300 if (!strcmpi(u_str
, "monster"))
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 */
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
);
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
{
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
},
2387 { "camera", EXPENSIVE_CAMERA
},
2388 { "tee shirt", T_SHIRT
},
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 },
2412 rnd_otyp_by_wpnskill(skill
)
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
) {
2425 for (i
= bases
[WEAPON_CLASS
];
2426 i
< NUM_OBJECTS
&& objects
[i
].oc_class
== WEAPON_CLASS
; i
++)
2427 if (objects
[i
].oc_skill
== skill
)
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),
2442 readobjnam(bp
, no_wish
)
2444 struct obj
*no_wish
;
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
;
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
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.
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
;
2485 contents
= UNDEFINED
;
2487 actualn
= dn
= un
= 0;
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"))
2499 /* save the [nearly] unmodified choice string */
2500 Strcpy(fruitbuf
, bp
);
2507 if (!strncmpi(bp
, "an ", l
= 3) || !strncmpi(bp
, "a ", l
= 2)) {
2509 } else if (!strncmpi(bp
, "the ", l
= 4)) {
2510 ; /* just increment `bp' by `l' below */
2511 } else if (!cnt
&& digit(*bp
) && strcmp(bp
, "0")) {
2518 } else if (*bp
== '+' || *bp
== '-') {
2519 spesgn
= (*bp
++ == '+') ? 1 : -1;
2526 } else if (!strncmpi(bp
, "blessed ", l
= 8)
2527 || !strncmpi(bp
, "holy ", l
= 5)) {
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;
2535 } else if (!strncmpi(bp
, "cursed ", l
= 7)
2536 || !strncmpi(bp
, "unholy ", l
= 7)) {
2538 } else if (!strncmpi(bp
, "uncursed ", l
= 9)) {
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)) {
2547 } else if (!strncmpi(bp
, "lit ", l
= 4)
2548 || !strncmpi(bp
, "burning ", l
= 8)) {
2550 } else if (!strncmpi(bp
, "unlit ", l
= 6)
2551 || !strncmpi(bp
, "extinguished ", l
= 13)) {
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)) {
2558 } else if (!strncmpi(bp
, "poisoned ", l
= 9)) {
2560 /* "trapped" recognized but not honored outside wizard mode */
2561 } else if (!strncmpi(bp
, "trapped ", l
= 8)) {
2562 trapped
= 0; /* undo any previous "untrapped" */
2565 } else if (!strncmpi(bp
, "untrapped ", l
= 10)) {
2566 trapped
= 2; /* not trapped */
2567 } else if (!strncmpi(bp
, "greased ", l
= 8)) {
2569 } else if (!strncmpi(bp
, "very ", l
= 5)) {
2570 /* very rusted very heavy iron ball */
2572 } else if (!strncmpi(bp
, "thoroughly ", l
= 11)) {
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)) {
2580 } else if (!strncmpi(bp
, "corroded ", l
= 9)
2581 || !strncmpi(bp
, "rotted ", l
= 7)) {
2584 } else if (!strncmpi(bp
, "partly eaten ", l
= 13)
2585 || !strncmpi(bp
, "partially eaten ", l
= 16)) {
2587 } else if (!strncmpi(bp
, "historic ", l
= 9)) {
2589 } else if (!strncmpi(bp
, "diluted ", l
= 8)) {
2591 } else if (!strncmpi(bp
, "empty ", l
= 6)) {
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)) {
2606 p
+= 4 - 1; /* point at ')' */
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
;
2629 if (keeptrailingchars
) {
2632 /* 'pp' points at 'pb's terminating '\0',
2633 'p' points at ')' and will be incremented past it */
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().
2645 spesgn
= -1; /* cheaters get what they deserve */
2648 if (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"
2658 * very heavy iron ball named hoei
2662 if ((p
= strstri(bp
, " named ")) != 0) {
2666 if ((p
= strstri(bp
, " called ")) != 0) {
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
;
2678 if ((p
= strstri(bp
, " labeled ")) != 0) {
2681 } else if ((p
= strstri(bp
, " labelled ")) != 0) {
2685 if ((p
= strstri(bp
, " of spinach")) != 0) {
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
2703 if (!strncmpi(bp
, "pair of ", 8)) {
2706 } else if (cnt
> 1 && !strncmpi(bp
, "pairs of ", 9)) {
2709 } else if (!strncmpi(bp
, "set of ", 7)) {
2711 } else if (!strncmpi(bp
, "sets of ", 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 */
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
) {
2741 } else if ((p
= strstri(bp
, " of ")) != 0
2742 && (mntmp
= name_to_mon(p
+ 4)) >= LOW_PM
)
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
) {
2756 mntmplen
; /* double check for rank title */
2758 mntmptoo
= title_to_mon(bp
, (int *) 0, &mntmplen
);
2759 bp
+= mntmp
!= mntmptoo
2760 ? (int) strlen(mons
[mntmp
].mname
)
2764 else if (!strncmpi(bp
, "s ", 2))
2766 else if (!strncmpi(bp
, "es ", 3))
2768 else if (!*bp
&& !actualn
&& !dn
&& !un
2770 /* no referent; they don't really mean a
2777 /* first change to singular if necessary */
2779 char *sng
= makesingular(bp
);
2780 if (strcmp(bp
, sng
)) {
2787 /* Alternate spellings (pick-ax, silver sabre, &c) */
2789 struct alt_spellings
*as
= spellings
;
2792 if (fuzzymatch(bp
, as
->sp
, " -", TRUE
)) {
2798 /* can't use spellings list for this one due to shuffling */
2799 if (!strncmpi(bp
, "grey spell", 10))
2802 if ((p
= strstri(bp
, "armour")) != 0) {
2803 /* skip past "armo", then copy remainder beyond "u" */
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 */
2819 if (!BSTRCMPI(bp
, p
- 10, "holy water")) {
2821 if ((p
- bp
) >= 12 && *(p
- 12) == 'u')
2822 iscursed
= 1; /* unholy water */
2827 if (unlabeled
&& !BSTRCMPI(bp
, p
- 6, "scroll")) {
2828 typ
= SCR_BLANK_PAPER
;
2831 if (unlabeled
&& !BSTRCMPI(bp
, p
- 9, "spellbook")) {
2832 typ
= SPE_BLANK_PAPER
;
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
)
2848 otmp
= mksobj(GOLD_PIECE
, FALSE
, FALSE
);
2849 otmp
->quan
= (long) cnt
;
2850 otmp
->owt
= weight(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
)) {
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
)) {
2875 if (oclass
!= AMULET_CLASS
) {
2877 if (!strncmpi(bp
, " of ", 4))
2879 /* else if(*bp) ?? */
2884 if (!BSTRCMPI(bp
, p
- j
, wrp
[i
])) {
2888 if (p
> bp
&& p
[-1] == ' ')
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" */
2916 ++zp
; /* embedded space is optional */
2917 if (!strncmpi(zp
, beartrap
? "trap" : "mine", 4)) {
2919 if (trapped
== 2 || !strcmpi(zp
, " object")) {
2920 /* "untrapped <foo>" or "<foo> object" */
2921 typ
= beartrap
? BEARTRAP
: LAND_MINE
;
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
);
2931 /* [no prefix or suffix; we're going to end up matching
2932 the object name and getting a disarmed trap object] */
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
);
2944 if (!BSTRCMPI(bp
, p
- 6, " stone") || !BSTRCMPI(bp
, p
- 4, " gem")) {
2945 p
[!strcmpi(p
- 4, " gem") ? -4 : -6] = '\0';
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))
2957 if (!strncmpi(g
, "piece of ", 9))
2959 if (!strncmpi(g
, "colored ", 8))
2961 else if (!strncmpi(g
, "coloured ", 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
)
2969 typ
= 0; /* somebody changed objects[]? punt */
2970 } else { /* try to construct canonical form */
2973 Strcpy(tbuf
, "worthless piece of ");
2974 Strcat(tbuf
, g
); /* assume it starts with the color */
2981 dn
= actualn
; /* ex. "skull cap" */
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
)) {
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
)) {
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;
3011 if (un
&& (zn
= objects
[i
].oc_uname
) != 0
3012 && wishymatch(un
, zn
, FALSE
)) {
3019 struct Jitem
*j
= Japanese_items
;
3022 if (actualn
&& !strcmpi(actualn
, j
->name
)) {
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");
3038 if (!strcmpi(bp
, "spinach")) {
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. */
3050 int blessedf
, iscursedf
, uncursedf
, halfeatenf
;
3052 blessedf
= iscursedf
= uncursedf
= halfeatenf
= 0;
3059 if (!strncmpi(fp
, "an ", l
= 3) || !strncmpi(fp
, "a ", l
= 2)) {
3061 } else if (!cntf
&& digit(*fp
)) {
3068 } else if (!strncmpi(fp
, "blessed ", l
= 8)) {
3070 } else if (!strncmpi(fp
, "cursed ", l
= 7)) {
3072 } else if (!strncmpi(fp
, "uncursed ", l
= 9)) {
3074 } else if (!strncmpi(fp
, "partly eaten ", l
= 13)
3075 || !strncmpi(fp
, "partially eaten ", l
= 16)) {
3082 for (f
= ffruit
; f
; f
= f
->nextf
) {
3083 /* match type: 0=none, 1=exact, 2=singular, 3=plural */
3086 if (!strcmp(fp
, f
->fname
))
3088 else if (!strcmp(fp
, makesingular(f
->fname
)))
3090 else if (!strcmp(fp
, makeplural(f
->fname
)))
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
)
3104 else if (ftyp
== 3 && !cntf
)
3113 if (!oclass
&& actualn
) {
3116 /* Perhaps it's an artifact specified by name, not type */
3117 name
= artifact_name(actualn
, &objtyp
);
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.
3129 if (wizard
&& !program_state
.wizkit_wishing
) {
3131 int trap
, x
= u
.ux
, y
= u
.uy
;
3133 for (trap
= NO_TRAP
+ 1; trap
< TRAPNUM
; trap
++) {
3137 tname
= defsyms
[trap_to_defsym(trap
)].explanation
;
3138 if (strncmpi(tname
, bp
, strlen(tname
)))
3140 /* found it; avoid stupid mistakes */
3141 if ((trap
== TRAPDOOR
|| trap
== HOLE
) && !Can_fall_thru(&u
.uz
))
3143 if ((t
= maketrap(x
, y
, trap
)) != 0) {
3145 tname
= defsyms
[trap_to_defsym(trap
)].explanation
;
3146 pline("%s%s.", An(tname
),
3147 (trap
!= MAGIC_PORTAL
) ? "" : " to nowhere");
3149 pline("Creation of %s failed.", an(tname
));
3153 /* furniture and terrain */
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 " : "");
3165 if (!BSTRCMPI(bp
, p
- 6, "throne")) {
3171 if (!BSTRCMPI(bp
, p
- 4, "sink")) {
3173 level
.flags
.nsinks
++;
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
;
3182 pline("A %s.", (lev
->typ
== POOL
) ? "pool" : "moat");
3183 /* Must manually make kelp! */
3184 water_damage_chain(level
.objects
[x
][y
], TRUE
);
3188 if (!BSTRCMPI(bp
, p
- 4, "lava")) { /* also matches "molten lava" */
3189 lev
->typ
= LAVAPOOL
;
3191 pline("A pool of molten lava.");
3192 if (!(Levitation
|| Flying
))
3193 (void) lava_effects();
3198 if (!BSTRCMPI(bp
, p
- 5, "altar")) {
3202 if (!strncmpi(bp
, "chaotic ", 8))
3204 else if (!strncmpi(bp
, "neutral ", 8))
3206 else if (!strncmpi(bp
, "lawful ", 7))
3208 else if (!strncmpi(bp
, "unaligned ", 10))
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
)));
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");
3227 if (!BSTRCMPI(bp
, p
- 4, "tree")) {
3235 if (!BSTRCMPI(bp
, p
- 4, "bars")) {
3236 lev
->typ
= IRONBARS
;
3237 pline("Iron bars.");
3243 if (!oclass
&& !typ
) {
3244 if (!strncmpi(bp
, "polearm", 7)) {
3245 typ
= rnd_otyp_by_wpnskill(P_POLEARMS
);
3247 } else if (!strncmpi(bp
, "hammer", 6)) {
3248 typ
= rnd_otyp_by_wpnskill(P_HAMMER
);
3254 return ((struct obj
*) 0);
3257 oclass
= wrpsym
[rn2((int) sizeof(wrpsym
))];
3260 oclass
= objects
[typ
].oc_class
;
3262 /* handle some objects that are only allowed in wizard mode */
3263 if (typ
&& !wizard
) {
3265 case AMULET_OF_YENDOR
:
3266 typ
= FAKE_AMULET_OF_YENDOR
;
3268 case CANDELABRUM_OF_INVOCATION
:
3269 typ
= rnd_class(TALLOW_CANDLE
, WAX_CANDLE
);
3271 case BELL_OF_OPENING
:
3274 case SPE_BOOK_OF_THE_DEAD
:
3275 typ
= SPE_BLANK_PAPER
;
3281 /* catch any other non-wishable objects (venom) */
3282 if (objects
[typ
].oc_nowish
)
3283 return (struct obj
*) 0;
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
)
3313 } else if (wizard
) {
3314 ; /* no alteration to spe */
3315 } else if (oclass
== ARMOR_CLASS
|| oclass
== WEAPON_CLASS
3317 || (oclass
== RING_CLASS
&& objects
[typ
].oc_charged
)) {
3318 if (spe
> rnd(5) && spe
> otmp
->spe
)
3320 if (spe
> 2 && Luck
< 0)
3323 if (oclass
== WAND_CLASS
) {
3324 if (spe
> 1 && spesgn
== -1)
3327 if (spe
> 0 && spesgn
== -1)
3330 if (spe
> otmp
->spe
)
3337 /* set otmp->spe. This may, or may not, use spe... */
3340 if (contents
== EMPTY
) {
3341 otmp
->corpsenm
= NON_PM
;
3343 } else if (contents
== SPINACH
) {
3344 otmp
->corpsenm
= NON_PM
;
3350 otmp
->spe
= wetness
;
3358 case HEAVY_IRON_BALL
:
3361 /* otmp->cobj already done in mksobj() */
3365 /* 0: delivered in-game via external event (or randomly for fake mail);
3366 1: from bones or wishing; 2: written with marker */
3372 otmp
->spe
= (rn2(10) ? -1 : 0);
3375 /* fall through, if wizard */
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
;
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
;
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
);
3405 if (!(mons
[mntmp
].geno
& G_UNIQ
) && !is_human(&mons
[mntmp
])
3407 && mntmp
!= PM_MAIL_DAEMON
3410 otmp
->corpsenm
= mntmp
;
3413 mntmp
= can_be_hatched(mntmp
);
3414 /* this also sets hatch timer if appropriate */
3415 set_corpsenm(otmp
, mntmp
);
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;
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
;
3431 /* set blessed/cursed -- setting the fields directly is safe
3432 * since weight() is called below and addinv() will take care
3436 } else if (uncursed
) {
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) {
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
)
3463 otmp
->recharged
= (unsigned) rechrg
;
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 */
3474 /* and [un]trapped */
3476 if (Is_box(otmp
) || typ
== TIN
)
3477 otmp
->otrapped
= (trapped
== 1);
3483 if (isdiluted
&& otmp
->oclass
== POTION_CLASS
&& otmp
->otyp
!= POT_WATER
)
3486 /* set tin variety */
3487 if (otmp
->otyp
== TIN
&& tvariety
>= 0 && (rn2(4) || wizard
))
3488 set_tin_variety(otmp
, tvariety
);
3494 /* an artifact name might need capitalization fixing */
3495 aname
= artifact_name(name
, &objtyp
);
3496 if (aname
&& objtyp
== otmp
->otyp
)
3499 /* 3.6 tribute - fix up novel */
3500 if (otmp
->otyp
== SPE_NOVEL
) {
3501 const char *novelname
;
3503 novelname
= lookup_novel(name
, &otmp
->novelidx
);
3508 otmp
= oname(otmp
, name
);
3509 if (otmp
->oartifact
) {
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);
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
;
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
;
3542 rnd_class(first
, last
)
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);
3554 for (i
= first
; i
<= last
; i
++)
3555 if (objects
[i
].oc_prob
&& (x
-= objects
[i
].oc_prob
) <= 0)
3560 STATIC_OVL
const char *
3561 Japanese_item_name(i
)
3564 struct Jitem
*j
= Japanese_items
;
3571 return (const char *) 0;
3575 suit_simple_name(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 */
3595 cloak_simple_name(cloak
)
3599 switch (cloak
->otyp
) {
3602 case MUMMY_WRAPPING
:
3605 return (objects
[cloak
->otyp
].oc_name_known
&& cloak
->dknown
)
3615 /* helm vs hat for messages */
3617 helm_simple_name(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";
3636 mimic_obj_name(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
)
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.
3656 safe_qbuf(qbuf
, qprefix
, qsuffix
, obj
, func
, altfunc
, lastR
)
3657 char *qbuf
; /* output buffer */
3658 const char *qprefix
, *qsuffix
;
3660 char *FDECL((*func
), (OBJ_P
)), *FDECL((*altfunc
), (OBJ_P
));
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 */
3689 } else if (qprefix
) {
3690 /* put prefix into the buffer */
3691 (void) strncpy(qbuf
, qprefix
, lenlimit
);
3694 /* no prefix; output buffer starts out empty */
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
);
3704 len
= (unsigned) strlen(qbuf
);
3705 if (qsuffix
&& len
< lenlimit
) {
3706 (void) strncpy(&qbuf
[len
], qsuffix
, lenlimit
- len
);
3708 /* len = (unsigned) strlen(qbuf); */
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 */
3719 Strcat(qbuf
, lastR
); /* use last resort */
3723 Strcat(qbuf
, qsuffix
);
3725 /* assert( strlen(qbuf) < QBUFSZ ); */