1 /* NetHack 3.6 objnam.c $NHDT-Date: 1462067746 2016/05/01 01:55:46 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.169 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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
short FDECL(rnd_otyp_by_namedesc
, (char *, char));
15 STATIC_DCL boolean
FDECL(wishymatch
, (const char *, const char *, BOOLEAN_P
));
16 STATIC_DCL
char *NDECL(nextobuf
);
17 STATIC_DCL
void FDECL(releaseobuf
, (char *));
18 STATIC_DCL
char *FDECL(minimal_xname
, (struct obj
*));
19 STATIC_DCL
void FDECL(add_erosion_words
, (struct obj
*, char *));
21 FDECL(singplur_lookup
, (char *, char *, BOOLEAN_P
, const char *const *));
22 STATIC_DCL
char *FDECL(singplur_compound
, (char *));
23 STATIC_DCL
char *FDECL(xname_flags
, (struct obj
*, unsigned));
30 #define BSTRCMPI(base, ptr, str) ((ptr) < base || strcmpi((ptr), str))
31 #define BSTRNCMPI(base, ptr, str, num) \
32 ((ptr) < base || strncmpi((ptr), str, num))
33 #define Strcasecpy(dst, src) (void) strcasecpy(dst, src)
35 /* true for gems/rocks that should have " stone" appended to their names */
36 #define GemStone(typ) \
38 || (objects[typ].oc_material == GEMSTONE \
39 && (typ != DILITHIUM_CRYSTAL && typ != RUBY && typ != DIAMOND \
40 && typ != SAPPHIRE && typ != BLACK_OPAL && typ != EMERALD \
43 STATIC_OVL
struct Jitem Japanese_items
[] = { { SHORT_SWORD
, "wakizashi" },
44 { BROADSWORD
, "ninja-to" },
45 { FLAIL
, "nunchaku" },
46 { GLAIVE
, "naginata" },
47 { LOCK_PICK
, "osaku" },
48 { WOODEN_HARP
, "koto" },
50 { PLATE_MAIL
, "tanko" },
52 { LEATHER_GLOVES
, "yugake" },
53 { FOOD_RATION
, "gunyoki" },
54 { POT_BOOZE
, "sake" },
57 STATIC_DCL
const char *FDECL(Japanese_item_name
, (int i
));
62 register const char *pref
;
64 register int i
= (int) strlen(pref
);
67 impossible("PREFIX too short (for %d).", i
);
71 (void) strncpy(s
, pref
, i
); /* do not copy trailing 0 */
75 /* manage a pool of BUFSZ buffers, so callers don't have to */
76 static char NEARDATA obufs
[NUMOBUF
][BUFSZ
];
77 static int obufidx
= 0;
82 obufidx
= (obufidx
+ 1) % NUMOBUF
;
83 return obufs
[obufidx
];
86 /* put the most recently allocated buffer back if possible */
91 /* caller may not know whether bufp is the most recently allocated
92 buffer; if it isn't, do nothing */
93 if (bufp
== obufs
[obufidx
])
94 obufidx
= (obufidx
- 1 + NUMOBUF
) % NUMOBUF
;
101 char *buf
= nextobuf();
102 register struct objclass
*ocl
= &objects
[otyp
];
103 register const char *actualn
= OBJ_NAME(*ocl
);
104 register const char *dn
= OBJ_DESCR(*ocl
);
105 register const char *un
= ocl
->oc_uname
;
106 register int nn
= ocl
->oc_name_known
;
108 if (Role_if(PM_SAMURAI
) && Japanese_item_name(otyp
))
109 actualn
= Japanese_item_name(otyp
);
110 switch (ocl
->oc_class
) {
115 Strcpy(buf
, "potion");
118 Strcpy(buf
, "scroll");
124 if (otyp
!= SPE_NOVEL
) {
125 Strcpy(buf
, "spellbook");
127 Strcpy(buf
, !nn
? "book" : "novel");
136 Strcpy(buf
, actualn
);
138 Strcpy(buf
, "amulet");
140 Sprintf(eos(buf
), " called %s", un
);
142 Sprintf(eos(buf
), " (%s)", dn
);
146 Strcpy(buf
, actualn
);
148 Strcat(buf
, " stone");
150 Sprintf(eos(buf
), " called %s", un
);
152 Sprintf(eos(buf
), " (%s)", dn
);
154 Strcpy(buf
, dn
? dn
: actualn
);
155 if (ocl
->oc_class
== GEM_CLASS
)
157 (ocl
->oc_material
== MINERAL
) ? " stone" : " gem");
159 Sprintf(eos(buf
), " called %s", un
);
163 /* here for ring/scroll/potion/wand */
166 Strcpy(buf
, actualn
); /* avoid spellbook of Book of the Dead */
168 Sprintf(eos(buf
), " of %s", actualn
);
171 Sprintf(eos(buf
), " called %s", un
);
173 Sprintf(eos(buf
), " (%s)", dn
);
177 /* less verbose result than obj_typename(); either the actual name
178 or the description (but not both); user-assigned name is ignored */
180 simple_typename(otyp
)
183 char *bufp
, *pp
, *save_uname
= objects
[otyp
].oc_uname
;
185 objects
[otyp
].oc_uname
= 0; /* suppress any name given by user */
186 bufp
= obj_typename(otyp
);
187 objects
[otyp
].oc_uname
= save_uname
;
188 if ((pp
= strstri(bufp
, " (")) != 0)
189 *pp
= '\0'; /* strip the appended description */
197 if (!obj
->oartifact
|| !has_oname(obj
))
199 if (!program_state
.gameover
&& !iflags
.override_ID
) {
200 if (not_fully_identified(obj
))
206 /* used by distant_name() to pass extra information to xname_flags();
207 it would be much cleaner if this were a parameter, but that would
208 require all of the xname() and doname() calls to be modified */
209 static int distantname
= 0;
211 /* Give the name of an object seen at a distance. Unlike xname/doname,
212 * we don't want to set dknown if it's not set already.
215 distant_name(obj
, func
)
217 char *FDECL((*func
), (OBJ_P
));
221 /* 3.6.1: this used to save Blind, set it, make the call, then restore
222 * the saved value; but the Eyes of the Overworld override blindness
223 * and let characters wearing them get dknown set for distant items.
225 * TODO? if the hero is wearing those Eyes, figure out whether the
226 * object is within X-ray radius and only treat it as distant when
227 * beyond that radius. Logic is iffy but result might be interesting.
235 /* convert player specified fruit name into corresponding fruit juice name
236 ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */
239 boolean juice
; /* whether or not to append " juice" to the name */
241 char *buf
= nextobuf();
242 const char *fruit_nam
= strstri(pl_fruit
, " of ");
245 fruit_nam
+= 4; /* skip past " of " */
247 fruit_nam
= pl_fruit
; /* use it as is */
249 Sprintf(buf
, "%s%s", makesingular(fruit_nam
), juice
? " juice" : "");
257 return xname_flags(obj
, CXN_NORMAL
);
261 xname_flags(obj
, cxn_flags
)
262 register struct obj
*obj
;
263 unsigned cxn_flags
; /* bitmask of CXN_xxx values */
266 register int typ
= obj
->otyp
;
267 register struct objclass
*ocl
= &objects
[typ
];
268 int nn
= ocl
->oc_name_known
, omndx
= obj
->corpsenm
;
269 const char *actualn
= OBJ_NAME(*ocl
);
270 const char *dn
= OBJ_DESCR(*ocl
);
271 const char *un
= ocl
->oc_uname
;
272 boolean pluralize
= (obj
->quan
!= 1L) && !(cxn_flags
& CXN_SINGULAR
);
273 boolean known
, dknown
, bknown
;
275 buf
= nextobuf() + PREFIX
; /* leave room for "17 -3 " */
276 if (Role_if(PM_SAMURAI
) && Japanese_item_name(typ
))
277 actualn
= Japanese_item_name(typ
);
281 * clean up known when it's tied to oc_name_known, eg after AD_DRIN
282 * This is only required for unique objects since the article
283 * printed for the object is tied to the combination of the two
284 * and printing the wrong article gives away information.
286 if (!nn
&& ocl
->oc_uses_known
&& ocl
->oc_unique
)
288 if (!Blind
&& !distantname
)
290 if (Role_if(PM_PRIEST
))
293 if (iflags
.override_ID
) {
294 known
= dknown
= bknown
= TRUE
;
298 dknown
= obj
->dknown
;
299 bknown
= obj
->bknown
;
302 if (obj_is_pname(obj
))
304 switch (obj
->oclass
) {
307 Strcpy(buf
, "amulet");
308 else if (typ
== AMULET_OF_YENDOR
|| typ
== FAKE_AMULET_OF_YENDOR
)
309 /* each must be identified individually */
310 Strcpy(buf
, known
? actualn
: dn
);
312 Strcpy(buf
, actualn
);
314 Sprintf(buf
, "amulet called %s", un
);
316 Sprintf(buf
, "%s amulet", dn
);
319 if (is_poisonable(obj
) && obj
->opoisoned
)
320 Strcpy(buf
, "poisoned ");
324 Strcpy(buf
, "pair of ");
325 else if (is_wet_towel(obj
))
326 Strcpy(buf
, (obj
->spe
< 3) ? "moist " : "wet ");
329 Strcat(buf
, dn
? dn
: actualn
);
331 Strcat(buf
, actualn
);
333 Strcat(buf
, dn
? dn
: actualn
);
334 Strcat(buf
, " called ");
337 Strcat(buf
, dn
? dn
: actualn
);
338 /* If we use an() here we'd have to remember never to use */
339 /* it whenever calling doname() or xname(). */
340 if (typ
== FIGURINE
&& omndx
!= NON_PM
) {
341 Sprintf(eos(buf
), " of a%s %s",
342 index(vowels
, *mons
[omndx
].mname
) ? "n" : "",
344 } else if (is_wet_towel(obj
)) {
346 Sprintf(eos(buf
), " (%d)", obj
->spe
);
350 /* depends on order of the dragon scales objects */
351 if (typ
>= GRAY_DRAGON_SCALES
&& typ
<= YELLOW_DRAGON_SCALES
) {
352 Sprintf(buf
, "set of %s", actualn
);
355 if (is_boots(obj
) || is_gloves(obj
))
356 Strcpy(buf
, "pair of ");
358 if (obj
->otyp
>= ELVEN_SHIELD
&& obj
->otyp
<= ORCISH_SHIELD
360 Strcpy(buf
, "shield");
363 if (obj
->otyp
== SHIELD_OF_REFLECTION
&& !dknown
) {
364 Strcpy(buf
, "smooth shield");
369 Strcat(buf
, actualn
);
372 Strcat(buf
, "boots");
373 else if (is_gloves(obj
))
374 Strcat(buf
, "gloves");
375 else if (is_cloak(obj
))
376 Strcpy(buf
, "cloak");
377 else if (is_helmet(obj
))
378 Strcpy(buf
, "helmet");
379 else if (is_shield(obj
))
380 Strcpy(buf
, "shield");
382 Strcpy(buf
, "armor");
383 Strcat(buf
, " called ");
389 if (typ
== SLIME_MOLD
) {
390 register struct fruit
*f
;
392 for (f
= ffruit
; f
; f
= f
->nextf
) {
393 if (f
->fid
== obj
->spe
) {
394 Strcpy(buf
, f
->fname
);
399 impossible("Bad fruit #%d?", obj
->spe
);
400 Strcpy(buf
, "fruit");
401 } else if (pluralize
) {
402 /* ick; already pluralized fruit names
403 are allowed--we want to try to avoid
404 adding a redundant plural suffix */
405 Strcpy(buf
, makeplural(makesingular(buf
)));
410 if (Is_pudding(obj
)) {
423 Strcpy(buf
, actualn
);
424 if (typ
== TIN
&& known
)
425 tin_details(obj
, omndx
, buf
);
429 Strcpy(buf
, actualn
);
432 if (typ
== STATUE
&& omndx
!= NON_PM
)
433 Sprintf(buf
, "%s%s of %s%s",
434 (Role_if(PM_ARCHEOLOGIST
) && (obj
->spe
& STATUE_HISTORIC
))
438 type_is_pname(&mons
[omndx
])
440 : the_unique_pm(&mons
[omndx
])
442 : index(vowels
, *mons
[omndx
].mname
)
447 Strcpy(buf
, actualn
);
450 Sprintf(buf
, "%sheavy iron ball",
451 (obj
->owt
> ocl
->oc_weight
) ? "very " : "");
454 if (dknown
&& obj
->odiluted
)
455 Strcpy(buf
, "diluted ");
456 if (nn
|| un
|| !dknown
) {
457 Strcat(buf
, "potion");
462 if (typ
== POT_WATER
&& bknown
463 && (obj
->blessed
|| obj
->cursed
)) {
464 Strcat(buf
, obj
->blessed
? "holy " : "unholy ");
466 Strcat(buf
, actualn
);
468 Strcat(buf
, " called ");
473 Strcat(buf
, " potion");
477 Strcpy(buf
, "scroll");
482 Strcat(buf
, actualn
);
484 Strcat(buf
, " called ");
486 } else if (ocl
->oc_magic
) {
487 Strcat(buf
, " labeled ");
491 Strcat(buf
, " scroll");
498 Sprintf(buf
, "wand of %s", actualn
);
500 Sprintf(buf
, "wand called %s", un
);
502 Sprintf(buf
, "%s wand", dn
);
505 if (typ
== SPE_NOVEL
) { /* 3.6 tribute */
509 Strcpy(buf
, actualn
);
511 Sprintf(buf
, "novel called %s", un
);
513 Sprintf(buf
, "%s book", dn
);
516 } else if (!dknown
) {
517 Strcpy(buf
, "spellbook");
519 if (typ
!= SPE_BOOK_OF_THE_DEAD
)
520 Strcpy(buf
, "spellbook of ");
521 Strcat(buf
, actualn
);
523 Sprintf(buf
, "spellbook called %s", un
);
525 Sprintf(buf
, "%s spellbook", dn
);
531 Sprintf(buf
, "ring of %s", actualn
);
533 Sprintf(buf
, "ring called %s", un
);
535 Sprintf(buf
, "%s ring", dn
);
538 const char *rock
= (ocl
->oc_material
== MINERAL
) ? "stone" : "gem";
544 Sprintf(buf
, "%s called %s", rock
, un
);
546 Sprintf(buf
, "%s %s", dn
, rock
);
548 Strcpy(buf
, actualn
);
550 Strcat(buf
, " stone");
555 Sprintf(buf
, "glorkum %d %d %d", obj
->oclass
, typ
, obj
->spe
);
558 Strcpy(buf
, makeplural(buf
));
560 if (obj
->otyp
== T_SHIRT
&& program_state
.gameover
) {
563 Sprintf(eos(buf
), " with text \"%s\"", tshirt_text(obj
, tmpbuf
));
566 if (has_oname(obj
) && dknown
) {
567 Strcat(buf
, " named ");
569 Strcat(buf
, ONAME(obj
));
572 if (!strncmpi(buf
, "the ", 4))
577 /* similar to simple_typename but minimal_xname operates on a particular
578 object rather than its general type; it formats the most basic info:
579 potion -- if description not known
580 brown potion -- if oc_name_known not set
581 potion of object detection -- if discovered
589 struct objclass saveobcls
;
590 int otyp
= obj
->otyp
;
592 /* suppress user-supplied name */
593 saveobcls
.oc_uname
= objects
[otyp
].oc_uname
;
594 objects
[otyp
].oc_uname
= 0;
595 /* suppress actual name if object's description is unknown */
596 saveobcls
.oc_name_known
= objects
[otyp
].oc_name_known
;
598 objects
[otyp
].oc_name_known
= 0;
600 /* caveat: this makes a lot of assumptions about which fields
601 are required in order for xname() to yield a sensible result */
604 bareobj
.oclass
= obj
->oclass
;
605 bareobj
.dknown
= obj
->dknown
;
606 /* suppress known except for amulets (needed for fakes and real A-of-Y) */
607 bareobj
.known
= (obj
->oclass
== AMULET_CLASS
)
609 /* default is "on" for types which don't use it */
610 : !objects
[otyp
].oc_uses_known
;
611 bareobj
.quan
= 1L; /* don't want plural */
612 bareobj
.corpsenm
= NON_PM
; /* suppress statue and figurine details */
613 /* but suppressing fruit details leads to "bad fruit #0"
614 [perhaps we should force "slime mold" rather than use xname?] */
615 if (obj
->otyp
== SLIME_MOLD
)
616 bareobj
.spe
= obj
->spe
;
618 bufp
= distant_name(&bareobj
, xname
); /* xname(&bareobj) */
619 if (!strncmp(bufp
, "uncursed ", 9))
620 bufp
+= 9; /* Role_if(PM_PRIEST) */
622 objects
[otyp
].oc_uname
= saveobcls
.oc_uname
;
623 objects
[otyp
].oc_name_known
= saveobcls
.oc_name_known
;
627 /* xname() output augmented for multishot missile feedback */
633 char *onm
= xname(obj
);
635 if (m_shot
.n
> 1 && m_shot
.o
== obj
->otyp
) {
636 /* "the Nth arrow"; value will eventually be passed to an() or
637 The(), both of which correctly handle this "the " prefix */
638 Sprintf(tmpbuf
, "the %d%s ", m_shot
.i
, ordin(m_shot
.i
));
639 onm
= strprepend(onm
, tmpbuf
);
644 /* used for naming "the unique_item" instead of "a unique_item" */
649 boolean known
= (obj
->known
|| iflags
.override_ID
);
651 if (!obj
->dknown
&& !iflags
.override_ID
)
653 else if (obj
->otyp
== FAKE_AMULET_OF_YENDOR
&& !known
)
654 return TRUE
; /* lie */
656 return (boolean
) (objects
[obj
->otyp
].oc_unique
657 && (known
|| obj
->otyp
== AMULET_OF_YENDOR
));
660 /* should monster type be prefixed with "the"? (mostly used for corpses) */
663 struct permonst
*ptr
;
667 /* even though monsters with personal names are unique, we want to
668 describe them as "Name" rather than "the Name" */
669 if (type_is_pname(ptr
))
672 uniq
= (ptr
->geno
& G_UNIQ
) ? TRUE
: FALSE
;
673 /* high priest is unique if it includes "of <deity>", otherwise not
674 (caller needs to handle the 1st possibility; we assume the 2nd);
675 worm tail should be irrelevant but is included for completeness */
676 if (ptr
== &mons
[PM_HIGH_PRIEST
] || ptr
== &mons
[PM_LONG_WORM_TAIL
])
678 /* Wizard no longer needs this; he's flagged as unique these days */
679 if (ptr
== &mons
[PM_WIZARD_OF_YENDOR
])
685 add_erosion_words(obj
, prefix
)
689 boolean iscrys
= (obj
->otyp
== CRYSKNIFE
);
692 rknown
= (iflags
.override_ID
== 0) ? obj
->rknown
: TRUE
;
694 if (!is_damageable(obj
) && !iscrys
)
697 /* The only cases where any of these bits do double duty are for
698 * rotted food and diluted potions, which are all not is_damageable().
700 if (obj
->oeroded
&& !iscrys
) {
701 switch (obj
->oeroded
) {
703 Strcat(prefix
, "very ");
706 Strcat(prefix
, "thoroughly ");
709 Strcat(prefix
, is_rustprone(obj
) ? "rusty " : "burnt ");
711 if (obj
->oeroded2
&& !iscrys
) {
712 switch (obj
->oeroded2
) {
714 Strcat(prefix
, "very ");
717 Strcat(prefix
, "thoroughly ");
720 Strcat(prefix
, is_corrodeable(obj
) ? "corroded " : "rotted ");
722 if (rknown
&& obj
->oerodeproof
)
723 Strcat(prefix
, iscrys
727 : is_corrodeable(obj
)
728 ? "corrodeproof " /* "stainless"? */
734 /* used to prevent rust on items where rust makes no difference */
739 switch (obj
->oclass
) {
741 /* it's possible for a rusty weptool to be polymorphed into some
742 non-weptool iron tool, in which case the rust implicitly goes
743 away, but it's also possible for it to be polymorphed into a
744 non-iron tool, in which case rust also implicitly goes away,
745 so there's no particular reason to try to handle the first
746 instance differently [this comment belongs in poly_obj()...] */
747 return is_weptool(obj
) ? TRUE
: FALSE
;
760 doname_base(obj
, with_price
)
761 register struct obj
*obj
;
764 boolean ispoisoned
= FALSE
;
765 boolean known
, dknown
, cknown
, bknown
, lknown
;
766 int omndx
= obj
->corpsenm
;
768 char tmpbuf
[PREFIX
+ 1]; /* for when we have to add something at
769 the start of prefix instead of the
770 end (Strcat is used on the end) */
771 register char *bp
= xname(obj
);
773 if (iflags
.override_ID
) {
774 known
= dknown
= cknown
= bknown
= lknown
= TRUE
;
777 dknown
= obj
->dknown
;
778 cknown
= obj
->cknown
;
779 bknown
= obj
->bknown
;
780 lknown
= obj
->lknown
;
783 /* When using xname, we want "poisoned arrow", and when using
784 * doname, we want "poisoned +0 arrow". This kludge is about the only
785 * way to do it, at least until someone overhauls xname() and doname(),
786 * combining both into one function taking a parameter.
788 /* must check opoisoned--someone can have a weirdly-named fruit */
789 if (!strncmp(bp
, "poisoned ", 9) && obj
->opoisoned
) {
794 if (obj
->quan
!= 1L) {
796 Sprintf(prefix
, "%ld ", obj
->quan
);
798 Strcpy(prefix
, "some ");
799 } else if (obj
->otyp
== CORPSE
) {
800 /* skip article prefix for corpses [else corpse_xname()
801 would have to be taught how to strip it off again] */
803 } else if (obj_is_pname(obj
) || the_unique_obj(obj
)) {
804 if (!strncmpi(bp
, "the ", 4))
806 Strcpy(prefix
, "the ");
808 Strcpy(prefix
, "a ");
811 /* "empty" goes at the beginning, but item count goes at the end */
813 /* bag of tricks: include "empty" prefix if it's known to
814 be empty but its precise number of charges isn't known
815 (when that is known, suffix of "(n:0)" will be appended,
816 making the prefix be redundant; note that 'known' flag
817 isn't set when emptiness gets discovered because then
818 charging magic would yield known number of new charges) */
819 && (obj
->otyp
== BAG_OF_TRICKS
820 ? (obj
->spe
== 0 && !obj
->known
)
821 /* not bag of tricks: empty if container which has no contents */
822 : (Is_container(obj
) || obj
->otyp
== STATUE
)
823 && !Has_contents(obj
)))
824 Strcat(prefix
, "empty ");
826 if (bknown
&& obj
->oclass
!= COIN_CLASS
827 && (obj
->otyp
!= POT_WATER
|| !objects
[POT_WATER
].oc_name_known
828 || (!obj
->cursed
&& !obj
->blessed
))) {
829 /* allow 'blessed clear potion' if we don't know it's holy water;
830 * always allow "uncursed potion of water"
833 Strcat(prefix
, "cursed ");
834 else if (obj
->blessed
)
835 Strcat(prefix
, "blessed ");
836 else if (!iflags
.implicit_uncursed
837 /* For most items with charges or +/-, if you know how many
838 * charges are left or what the +/- is, then you must have
839 * totally identified the item, so "uncursed" is unnecessary,
840 * because an identified object not described as "blessed" or
841 * "cursed" must be uncursed.
843 * If the charges or +/- is not known, "uncursed" must be
844 * printed to avoid ambiguity between an item whose curse
845 * status is unknown, and an item known to be uncursed.
847 || ((!known
|| !objects
[obj
->otyp
].oc_charged
848 || obj
->oclass
== ARMOR_CLASS
849 || obj
->oclass
== RING_CLASS
)
851 && obj
->otyp
!= SCR_MAIL
853 && obj
->otyp
!= FAKE_AMULET_OF_YENDOR
854 && obj
->otyp
!= AMULET_OF_YENDOR
855 && !Role_if(PM_PRIEST
)))
856 Strcat(prefix
, "uncursed ");
859 if (lknown
&& Is_box(obj
)) {
861 /* 3.6.0 used "unlockable" here but that could be misunderstood
862 to mean "capable of being unlocked" rather than the intended
863 "not capable of being locked" */
864 Strcat(prefix
, "broken ");
865 else if (obj
->olocked
)
866 Strcat(prefix
, "locked ");
868 Strcat(prefix
, "unlocked ");
872 Strcat(prefix
, "greased ");
874 if (cknown
&& Has_contents(obj
)) {
875 /* we count all objects (obj->quantity); perhaps we should
876 count separate stacks instead (or even introduce a user
877 preference option to choose between the two alternatives)
878 since it's somewhat odd so see "containing 1002 items"
879 when there are 2 scrolls plus 1000 gold pieces */
880 long itemcount
= count_contents(obj
, FALSE
, FALSE
, TRUE
);
882 Sprintf(eos(bp
), " containing %ld item%s", itemcount
,
886 switch (is_weptool(obj
) ? WEAPON_CLASS
: obj
->oclass
) {
888 if (obj
->owornmask
& W_AMUL
)
889 Strcat(bp
, " (being worn)");
892 if (obj
->owornmask
& W_ARMOR
)
893 Strcat(bp
, (obj
== uskin
) ? " (embedded in your skin)"
898 Strcat(prefix
, "poisoned ");
899 add_erosion_words(obj
, prefix
);
901 Strcat(prefix
, sitoa(obj
->spe
));
906 if (obj
->owornmask
& (W_TOOL
| W_SADDLE
)) { /* blindfold */
907 Strcat(bp
, " (being worn)");
910 if (obj
->otyp
== LEASH
&& obj
->leashmon
!= 0) {
911 Strcat(bp
, " (in use)");
914 if (obj
->otyp
== CANDELABRUM_OF_INVOCATION
) {
916 Strcpy(tmpbuf
, "no");
918 Sprintf(tmpbuf
, "%d", obj
->spe
);
919 Sprintf(eos(bp
), " (%s candle%s%s)", tmpbuf
, plur(obj
->spe
),
920 !obj
->lamplit
? " attached" : ", lit");
922 } else if (obj
->otyp
== OIL_LAMP
|| obj
->otyp
== MAGIC_LAMP
923 || obj
->otyp
== BRASS_LANTERN
|| Is_candle(obj
)) {
925 && obj
->age
< 20L * (long) objects
[obj
->otyp
].oc_cost
)
926 Strcat(prefix
, "partly used ");
928 Strcat(bp
, " (lit)");
931 if (objects
[obj
->otyp
].oc_charged
)
937 Sprintf(eos(bp
), " (%d:%d)", (int) obj
->recharged
, obj
->spe
);
940 if (obj
->otyp
== POT_OIL
&& obj
->lamplit
)
941 Strcat(bp
, " (lit)");
945 if (obj
->owornmask
& W_RINGR
)
946 Strcat(bp
, " (on right ");
947 if (obj
->owornmask
& W_RINGL
)
948 Strcat(bp
, " (on left ");
949 if (obj
->owornmask
& W_RING
) {
950 Strcat(bp
, body_part(HAND
));
953 if (known
&& objects
[obj
->otyp
].oc_charged
) {
954 Strcat(prefix
, sitoa(obj
->spe
));
960 Strcat(prefix
, "partly eaten ");
961 if (obj
->otyp
== CORPSE
) {
962 Sprintf(prefix
, "%s ",
963 corpse_xname(obj
, prefix
, CXN_ARTICLE
| CXN_NOCORPSE
));
964 } else if (obj
->otyp
== EGG
) {
965 #if 0 /* corpses don't tell if they're stale either */
966 if (known
&& stale_egg(obj
))
967 Strcat(prefix
, "stale ");
970 && (known
|| (mvitals
[omndx
].mvflags
& MV_KNOWS_EGG
))) {
971 Strcat(prefix
, mons
[omndx
].mname
);
974 Strcat(bp
, " (laid by you)");
977 if (obj
->otyp
== MEAT_RING
)
982 add_erosion_words(obj
, prefix
);
983 if (obj
->owornmask
& W_BALL
)
984 Strcat(bp
, " (chained to you)");
988 if ((obj
->owornmask
& W_WEP
) && !mrg_to_wielded
) {
989 if (obj
->quan
!= 1L) {
990 Strcat(bp
, " (wielded)");
992 const char *hand_s
= body_part(HAND
);
995 hand_s
= makeplural(hand_s
);
996 Sprintf(eos(bp
), " (weapon in %s)", hand_s
);
998 if (warn_obj_cnt
&& obj
== uwep
&& (EWarn_of_mon
& W_WEP
) != 0L) {
999 /* presumably can be felt when blind */
1000 Strcat(bp
, " (glowing");
1002 Sprintf(eos(bp
), " %s", glow_color(obj
->oartifact
));
1007 if (obj
->owornmask
& W_SWAPWEP
) {
1009 Sprintf(eos(bp
), " (wielded in other %s)", body_part(HAND
));
1011 Strcat(bp
, " (alternate weapon; not wielded)");
1013 if (obj
->owornmask
& W_QUIVER
) {
1014 switch (obj
->oclass
) {
1017 if (objects
[obj
->otyp
].oc_skill
== -P_BOW
) {
1018 /* Ammo for a bow */
1019 Strcat(bp
, " (in quiver)");
1022 /* Ammo not for a bow */
1023 Strcat(bp
, " (in quiver pouch)");
1027 /* Weapons not considered ammo */
1028 Strcat(bp
, " (at the ready)");
1031 /* Small things and ammo not for a bow */
1037 Strcat(bp
, " (in quiver pouch)");
1039 default: /* odd things */
1040 Strcat(bp
, " (at the ready)");
1043 if (!iflags
.suppress_price
&& is_unpaid(obj
)) {
1044 long quotedprice
= unpaid_cost(obj
, TRUE
);
1046 Sprintf(eos(bp
), " (%s, %ld %s)",
1047 obj
->unpaid
? "unpaid" : "contents",
1048 quotedprice
, currency(quotedprice
));
1049 } else if (with_price
) {
1050 long price
= get_cost_of_shop_item(obj
);
1053 Sprintf(eos(bp
), " (%ld %s)", price
, currency(price
));
1055 if (!strncmp(prefix
, "a ", 2)
1056 && index(vowels
, *(prefix
+ 2) ? *(prefix
+ 2) : *bp
)
1058 || (strncmp(bp
, "uranium", 7) && strncmp(bp
, "unicorn", 7)
1059 && strncmp(bp
, "eucalyptus", 10)))) {
1060 Strcpy(tmpbuf
, prefix
);
1061 Strcpy(prefix
, "an ");
1062 Strcpy(prefix
+ 3, tmpbuf
+ 2);
1065 /* show weight for items (debug tourist info)
1066 * aum is stolen from Crawl's "Arbitrary Unit of Measure" */
1067 if (wizard
&& iflags
.wizweight
) {
1068 Sprintf(eos(bp
), " (%d aum)", obj
->owt
);
1070 bp
= strprepend(bp
, prefix
);
1076 register struct obj
*obj
;
1078 return doname_base(obj
, FALSE
);
1081 /* Name of object including price. */
1083 doname_with_price(obj
)
1084 register struct obj
*obj
;
1086 return doname_base(obj
, TRUE
);
1089 /* used from invent.c */
1091 not_fully_identified(otmp
)
1092 register struct obj
*otmp
;
1094 /* gold doesn't have any interesting attributes [yet?] */
1095 if (otmp
->oclass
== COIN_CLASS
)
1096 return FALSE
; /* always fully ID'd */
1097 /* check fundamental ID hallmarks first */
1098 if (!otmp
->known
|| !otmp
->dknown
1100 || (!otmp
->bknown
&& otmp
->otyp
!= SCR_MAIL
)
1104 || !objects
[otmp
->otyp
].oc_name_known
)
1106 if ((!otmp
->cknown
&& (Is_container(otmp
) || otmp
->otyp
== STATUE
))
1107 || (!otmp
->lknown
&& Is_box(otmp
)))
1109 if (otmp
->oartifact
&& undiscovered_artifact(otmp
->oartifact
))
1111 /* otmp->rknown is the only item of interest if we reach here */
1113 * Note: if a revision ever allows scrolls to become fireproof or
1114 * rings to become shockproof, this checking will need to be revised.
1115 * `rknown' ID only matters if xname() will provide the info about it.
1118 || (otmp
->oclass
!= ARMOR_CLASS
&& otmp
->oclass
!= WEAPON_CLASS
1119 && !is_weptool(otmp
) /* (redundant) */
1120 && otmp
->oclass
!= BALL_CLASS
)) /* (useless) */
1122 else /* lack of `rknown' only matters for vulnerable objects */
1123 return (boolean
) (is_rustprone(otmp
) || is_corrodeable(otmp
)
1124 || is_flammable(otmp
));
1127 /* format a corpse name (xname() omits monster type; doname() calls us);
1128 eatcorpse() also uses us for death reason when eating tainted glob */
1130 corpse_xname(otmp
, adjective
, cxn_flags
)
1132 const char *adjective
;
1133 unsigned cxn_flags
; /* bitmask of CXN_xxx values */
1135 char *nambuf
= nextobuf();
1136 int omndx
= otmp
->corpsenm
;
1137 boolean ignore_quan
= (cxn_flags
& CXN_SINGULAR
) != 0,
1138 /* suppress "the" from "the unique monster corpse" */
1139 no_prefix
= (cxn_flags
& CXN_NO_PFX
) != 0,
1140 /* include "the" for "the woodchuck corpse */
1141 the_prefix
= (cxn_flags
& CXN_PFX_THE
) != 0,
1142 /* include "an" for "an ogre corpse */
1143 any_prefix
= (cxn_flags
& CXN_ARTICLE
) != 0,
1144 /* leave off suffix (do_name() appends "corpse" itself) */
1145 omit_corpse
= (cxn_flags
& CXN_NOCORPSE
) != 0,
1147 glob
= (otmp
->otyp
!= CORPSE
&& otmp
->globby
);
1151 mname
= OBJ_NAME(objects
[otmp
->otyp
]); /* "glob of <monster>" */
1152 } else if (omndx
== NON_PM
) { /* paranoia */
1154 /* [Possible enhancement: check whether corpse has monster traits
1155 attached in order to use priestname() for priests and minions.] */
1156 } else if (omndx
== PM_ALIGNED_PRIEST
) {
1157 /* avoid "aligned priest"; it just exposes internal details */
1160 mname
= mons
[omndx
].mname
;
1161 if (the_unique_pm(&mons
[omndx
]) || type_is_pname(&mons
[omndx
])) {
1162 mname
= s_suffix(mname
);
1164 /* don't precede personal name like "Medusa" with an article */
1165 if (type_is_pname(&mons
[omndx
]))
1167 /* always precede non-personal unique monster name like
1168 "Oracle" with "the" unless explicitly overridden */
1169 else if (the_unique_pm(&mons
[omndx
]) && !no_prefix
)
1174 the_prefix
= any_prefix
= FALSE
;
1175 else if (the_prefix
)
1176 any_prefix
= FALSE
; /* mutually exclusive */
1179 /* can't use the() the way we use an() below because any capitalized
1180 Name causes it to assume a personal name and return Name as-is;
1181 that's usually the behavior wanted, but here we need to force "the"
1182 to precede capitalized unique monsters (pnames are handled above) */
1184 Strcat(nambuf
, "the ");
1186 if (!adjective
|| !*adjective
) {
1187 /* normal case: newt corpse */
1188 Strcat(nambuf
, mname
);
1190 /* adjective positioning depends upon format of monster name */
1191 if (possessive
) /* Medusa's cursed partly eaten corpse */
1192 Sprintf(eos(nambuf
), "%s %s", mname
, adjective
);
1193 else /* cursed partly eaten troll corpse */
1194 Sprintf(eos(nambuf
), "%s %s", adjective
, mname
);
1195 /* in case adjective has a trailing space, squeeze it out */
1197 /* doname() might include a count in the adjective argument;
1198 if so, don't prepend an article */
1199 if (digit(*adjective
))
1204 ; /* omit_corpse doesn't apply; quantity is always 1 */
1205 } else if (!omit_corpse
) {
1206 Strcat(nambuf
, " corpse");
1207 /* makeplural(nambuf) => append "s" to "corpse" */
1208 if (otmp
->quan
> 1L && !ignore_quan
) {
1209 Strcat(nambuf
, "s");
1210 any_prefix
= FALSE
; /* avoid "a newt corpses" */
1214 /* it's safe to overwrite our nambuf after an() has copied
1215 its old value into another buffer */
1217 Strcpy(nambuf
, an(nambuf
));
1222 /* xname doesn't include monster type for "corpse"; cxname does */
1227 if (obj
->otyp
== CORPSE
)
1228 return corpse_xname(obj
, (const char *) 0, CXN_NORMAL
);
1232 /* like cxname, but ignores quantity */
1234 cxname_singular(obj
)
1237 if (obj
->otyp
== CORPSE
)
1238 return corpse_xname(obj
, (const char *) 0, CXN_SINGULAR
);
1239 return xname_flags(obj
, CXN_SINGULAR
);
1242 /* treat an object as fully ID'd when it might be used as reason for death */
1247 struct obj save_obj
;
1248 unsigned save_ocknown
;
1249 char *buf
, *save_ocuname
, *save_oname
= (char *) 0;
1251 /* bypass object twiddling for artifacts */
1253 return bare_artifactname(obj
);
1255 /* remember original settings for core of the object;
1256 oextra structs other than oname don't matter here--since they
1257 aren't modified they don't need to be saved and restored */
1260 save_oname
= ONAME(obj
);
1262 /* killer name should be more specific than general xname; however, exact
1263 info like blessed/cursed and rustproof makes things be too verbose */
1264 obj
->known
= obj
->dknown
= 1;
1265 obj
->bknown
= obj
->rknown
= obj
->greased
= 0;
1266 /* if character is a priest[ess], bknown will get toggled back on */
1267 if (obj
->otyp
!= POT_WATER
)
1268 obj
->blessed
= obj
->cursed
= 0;
1270 obj
->bknown
= 1; /* describe holy/unholy water as such */
1271 /* "killed by poisoned <obj>" would be misleading when poison is
1272 not the cause of death and "poisoned by poisoned <obj>" would
1273 be redundant when it is, so suppress "poisoned" prefix */
1275 /* strip user-supplied name; artifacts keep theirs */
1276 if (!obj
->oartifact
&& save_oname
)
1277 ONAME(obj
) = (char *) 0;
1278 /* temporarily identify the type of object */
1279 save_ocknown
= objects
[obj
->otyp
].oc_name_known
;
1280 objects
[obj
->otyp
].oc_name_known
= 1;
1281 save_ocuname
= objects
[obj
->otyp
].oc_uname
;
1282 objects
[obj
->otyp
].oc_uname
= 0; /* avoid "foo called bar" */
1284 /* format the object */
1285 if (obj
->otyp
== CORPSE
) {
1287 Strcpy(buf
, corpse_xname(obj
, (const char *) 0, CXN_NORMAL
));
1288 } else if (obj
->otyp
== SLIME_MOLD
) {
1289 /* concession to "most unique deaths competition" in the annual
1290 devnull tournament, suppress player supplied fruit names because
1291 those can be used to fake other objects and dungeon features */
1293 Sprintf(buf
, "deadly slime mold%s", plur(obj
->quan
));
1297 /* apply an article if appropriate; caller should always use KILLED_BY */
1298 if (obj
->quan
== 1L && !strstri(buf
, "'s ") && !strstri(buf
, "s' "))
1299 buf
= (obj_is_pname(obj
) || the_unique_obj(obj
)) ? the(buf
) : an(buf
);
1301 objects
[obj
->otyp
].oc_name_known
= save_ocknown
;
1302 objects
[obj
->otyp
].oc_uname
= save_ocuname
;
1303 *obj
= save_obj
; /* restore object's core settings */
1304 if (!obj
->oartifact
&& save_oname
)
1305 ONAME(obj
) = save_oname
;
1310 /* xname,doname,&c with long results reformatted to omit some stuff */
1312 short_oname(obj
, func
, altfunc
, lenlimit
)
1314 char *FDECL((*func
), (OBJ_P
)), /* main formatting routine */
1315 *FDECL((*altfunc
), (OBJ_P
)); /* alternate for shortest result */
1318 struct obj save_obj
;
1319 char unamebuf
[12], onamebuf
[12], *save_oname
, *save_uname
, *outbuf
;
1321 outbuf
= (*func
)(obj
);
1322 if ((unsigned) strlen(outbuf
) <= lenlimit
)
1325 /* shorten called string to fairly small amount */
1326 save_uname
= objects
[obj
->otyp
].oc_uname
;
1327 if (save_uname
&& strlen(save_uname
) >= sizeof unamebuf
) {
1328 (void) strncpy(unamebuf
, save_uname
, sizeof unamebuf
- 4);
1329 Strcpy(unamebuf
+ sizeof unamebuf
- 4, "...");
1330 objects
[obj
->otyp
].oc_uname
= unamebuf
;
1331 releaseobuf(outbuf
);
1332 outbuf
= (*func
)(obj
);
1333 objects
[obj
->otyp
].oc_uname
= save_uname
; /* restore called string */
1334 if ((unsigned) strlen(outbuf
) <= lenlimit
)
1338 /* shorten named string to fairly small amount */
1339 save_oname
= has_oname(obj
) ? ONAME(obj
) : 0;
1340 if (save_oname
&& strlen(save_oname
) >= sizeof onamebuf
) {
1341 (void) strncpy(onamebuf
, save_oname
, sizeof onamebuf
- 4);
1342 Strcpy(onamebuf
+ sizeof onamebuf
- 4, "...");
1343 ONAME(obj
) = onamebuf
;
1344 releaseobuf(outbuf
);
1345 outbuf
= (*func
)(obj
);
1346 ONAME(obj
) = save_oname
; /* restore named string */
1347 if ((unsigned) strlen(outbuf
) <= lenlimit
)
1351 /* shorten both called and named strings;
1352 unamebuf and onamebuf have both already been populated */
1353 if (save_uname
&& strlen(save_uname
) >= sizeof unamebuf
&& save_oname
1354 && strlen(save_oname
) >= sizeof onamebuf
) {
1355 objects
[obj
->otyp
].oc_uname
= unamebuf
;
1356 ONAME(obj
) = onamebuf
;
1357 releaseobuf(outbuf
);
1358 outbuf
= (*func
)(obj
);
1359 if ((unsigned) strlen(outbuf
) <= lenlimit
) {
1360 objects
[obj
->otyp
].oc_uname
= save_uname
;
1361 ONAME(obj
) = save_oname
;
1366 /* still long; strip several name-lengthening attributes;
1367 called and named strings are still in truncated form */
1369 obj
->bknown
= obj
->rknown
= obj
->greased
= 0;
1370 obj
->oeroded
= obj
->oeroded2
= 0;
1371 releaseobuf(outbuf
);
1372 outbuf
= (*func
)(obj
);
1373 if (altfunc
&& (unsigned) strlen(outbuf
) > lenlimit
) {
1374 /* still long; use the alternate function (usually one of
1375 the jackets around minimal_xname()) */
1376 releaseobuf(outbuf
);
1377 outbuf
= (*altfunc
)(obj
);
1379 /* restore the object */
1382 ONAME(obj
) = save_oname
;
1384 objects
[obj
->otyp
].oc_uname
= save_uname
;
1386 /* use whatever we've got, whether it's too long or not */
1391 * Used if only one of a collection of objects is named (e.g. in eat.c).
1394 singular(otmp
, func
)
1395 register struct obj
*otmp
;
1396 char *FDECL((*func
), (OBJ_P
));
1401 /* using xname for corpses does not give the monster type */
1402 if (otmp
->otyp
== CORPSE
&& func
== xname
)
1405 savequan
= otmp
->quan
;
1407 nam
= (*func
)(otmp
);
1408 otmp
->quan
= savequan
;
1414 register const char *str
;
1416 char *buf
= nextobuf();
1420 if (strncmpi(str
, "the ", 4) && strcmp(str
, "molten lava")
1421 && strcmp(str
, "iron bars") && strcmp(str
, "ice")) {
1422 if (index(vowels
, *str
) && strncmp(str
, "one-", 4)
1423 && strncmp(str
, "useful", 6) && strncmp(str
, "unicorn", 7)
1424 && strncmp(str
, "uranium", 7) && strncmp(str
, "eucalyptus", 10))
1438 char *tmp
= an(str
);
1445 * Prepend "the" if necessary; assumes str is a subject derived from xname.
1446 * Use type_is_pname() for monster names, not the(). the() is idempotent.
1452 char *buf
= nextobuf();
1453 boolean insert_the
= FALSE
;
1455 if (!strncmpi(str
, "the ", 4)) {
1456 buf
[0] = lowc(*str
);
1457 Strcpy(&buf
[1], str
+ 1);
1459 } else if (*str
< 'A' || *str
> 'Z') {
1460 /* not a proper name, needs an article */
1463 /* Probably a proper name, might not need an article */
1464 register char *tmp
, *named
, *called
;
1467 /* some objects have capitalized adjectives in their names */
1468 if (((tmp
= rindex(str
, ' ')) != 0 || (tmp
= rindex(str
, '-')) != 0)
1469 && (tmp
[1] < 'A' || tmp
[1] > 'Z')) {
1471 } else if (tmp
&& index(str
, ' ') < tmp
) { /* has spaces */
1472 /* it needs an article if the name contains "of" */
1473 tmp
= strstri(str
, " of ");
1474 named
= strstri(str
, " named ");
1475 called
= strstri(str
, " called ");
1476 if (called
&& (!named
|| called
< named
))
1479 if (tmp
&& (!named
|| tmp
< named
)) /* found an "of" */
1481 /* stupid special case: lacks "of" but needs "the" */
1482 else if (!named
&& (l
= strlen(str
)) >= 31
1483 && !strcmp(&str
[l
- 31],
1484 "Platinum Yendorian Express Card"))
1489 Strcpy(buf
, "the ");
1501 char *tmp
= the(str
);
1507 /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */
1513 char prefix
[PREFIX
];
1514 char *bp
= cxname(otmp
);
1516 if (otmp
->quan
!= 1L) {
1517 Sprintf(prefix
, "%ld ", otmp
->quan
);
1518 bp
= strprepend(bp
, prefix
);
1522 Strcat(bp
, otense(otmp
, verb
));
1527 /* combine yname and aobjnam eg "your count cxname(otmp)" */
1533 char *s
= aobjnam(obj
, verb
);
1535 /* leave off "your" for most of your artifacts, but prepend
1536 * "your" for unique objects and "foo of bar" quest artifacts */
1537 if (!carried(obj
) || !obj_is_pname(obj
)
1538 || obj
->oartifact
>= ART_ORB_OF_DETECTION
) {
1539 char *outbuf
= shk_your(nextobuf(), obj
);
1540 int space_left
= BUFSZ
- 1 - strlen(outbuf
);
1542 s
= strncat(outbuf
, s
, space_left
);
1547 /* combine Yname2 and aobjnam eg "Your count cxname(otmp)" */
1553 register char *s
= yobjnam(obj
, verb
);
1559 /* like aobjnam, but prepend "The", not count, and use xname */
1565 char *bp
= The(xname(otmp
));
1569 Strcat(bp
, otense(otmp
, verb
));
1574 /* capitalized variant of doname() */
1579 char *s
= doname(obj
);
1585 /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
1590 char *s
= cxname(obj
);
1592 /* leave off "your" for most of your artifacts, but prepend
1593 * "your" for unique objects and "foo of bar" quest artifacts */
1594 if (!carried(obj
) || !obj_is_pname(obj
)
1595 || obj
->oartifact
>= ART_ORB_OF_DETECTION
) {
1596 char *outbuf
= shk_your(nextobuf(), obj
);
1597 int space_left
= BUFSZ
- 1 - strlen(outbuf
);
1599 s
= strncat(outbuf
, s
, space_left
);
1605 /* capitalized variant of yname() */
1610 char *s
= yname(obj
);
1616 /* returns "your minimal_xname(obj)"
1617 * or "Foobar's minimal_xname(obj)"
1618 * or "the minimal_xname(obj)"
1624 char *outbuf
= nextobuf();
1625 char *s
= shk_your(outbuf
, obj
); /* assert( s == outbuf ); */
1626 int space_left
= BUFSZ
- 1 - strlen(s
);
1628 return strncat(s
, minimal_xname(obj
), space_left
);
1631 /* capitalized variant of ysimple_name() */
1636 char *s
= ysimple_name(obj
);
1642 /* "scroll" or "scrolls" */
1647 char *simpleoname
= minimal_xname(obj
);
1649 if (obj
->quan
!= 1L)
1650 simpleoname
= makeplural(simpleoname
);
1654 /* "a scroll" or "scrolls"; "a silver bell" or "the Bell of Opening" */
1659 char *simpleoname
= simpleonames(obj
);
1660 int otyp
= obj
->otyp
;
1662 /* prefix with "the" if a unique item, or a fake one imitating same,
1663 has been formatted with its actual name (we let typename() handle
1664 any `known' and `dknown' checking necessary) */
1665 if (otyp
== FAKE_AMULET_OF_YENDOR
)
1666 otyp
= AMULET_OF_YENDOR
;
1667 if (objects
[otyp
].oc_unique
1668 && !strcmp(simpleoname
, OBJ_NAME(objects
[otyp
])))
1669 return the(simpleoname
);
1671 /* simpleoname is singular if quan==1, plural otherwise */
1672 if (obj
->quan
== 1L)
1673 simpleoname
= an(simpleoname
);
1677 /* "the scroll" or "the scrolls" */
1682 char *simpleoname
= simpleonames(obj
);
1684 return the(simpleoname
);
1687 /* artifact's name without any object type or known/dknown/&c feedback */
1689 bare_artifactname(obj
)
1694 if (obj
->oartifact
) {
1695 outbuf
= nextobuf();
1696 Strcpy(outbuf
, artiname(obj
->oartifact
));
1697 if (!strncmp(outbuf
, "The ", 4))
1698 outbuf
[0] = lowc(outbuf
[0]);
1700 outbuf
= xname(obj
);
1705 static const char *wrp
[] = {
1706 "wand", "ring", "potion", "scroll", "gem",
1707 "amulet", "spellbook", "spell book",
1708 /* for non-specific wishes */
1709 "weapon", "armor", "tool", "food", "comestible",
1711 static const char wrpsym
[] = { WAND_CLASS
, RING_CLASS
, POTION_CLASS
,
1712 SCROLL_CLASS
, GEM_CLASS
, AMULET_CLASS
,
1713 SPBOOK_CLASS
, SPBOOK_CLASS
, WEAPON_CLASS
,
1714 ARMOR_CLASS
, TOOL_CLASS
, FOOD_CLASS
,
1717 /* return form of the verb (input plural) if xname(otmp) were the subject */
1726 * verb is given in plural (without trailing s). Return as input
1727 * if the result of xname(otmp) would be plural. Don't bother
1728 * recomputing xname(otmp) at this time.
1730 if (!is_plural(otmp
))
1731 return vtense((char *) 0, verb
);
1738 /* various singular words that vtense would otherwise categorize as plural;
1739 also used by makesingular() to catch some special cases */
1740 static const char *const special_subjs
[] = {
1741 "erinys", "manes", /* this one is ambiguous */
1742 "Cyclops", "Hippocrates", "Pelias", "aklys",
1743 "amnesia", "detect monsters", "paralysis", "shape changers",
1745 /* note: "detect monsters" and "shape changers" are normally
1746 caught via "<something>(s) of <whatever>", but they can be
1747 wished for using the shorter form, so we include them here
1748 to accommodate usage by makesingular during wishing */
1751 /* return form of the verb (input plural) for present tense 3rd person subj */
1754 register const char *subj
;
1755 register const char *verb
;
1757 char *buf
= nextobuf(), *bspot
;
1759 const char *sp
, *spot
;
1760 const char *const *spec
;
1763 * verb is given in plural (without trailing s). Return as input
1764 * if subj appears to be plural. Add special cases as necessary.
1765 * Many hard cases can already be handled by using otense() instead.
1766 * If this gets much bigger, consider decomposing makeplural.
1767 * Note: monster names are not expected here (except before corpse).
1769 * Special case: allow null sobj to get the singular 3rd person
1770 * present tense form so we don't duplicate this code elsewhere.
1773 if (!strncmpi(subj
, "a ", 2) || !strncmpi(subj
, "an ", 3))
1775 spot
= (const char *) 0;
1776 for (sp
= subj
; (sp
= index(sp
, ' ')) != 0; ++sp
) {
1777 if (!strncmpi(sp
, " of ", 4) || !strncmpi(sp
, " from ", 6)
1778 || !strncmpi(sp
, " called ", 8) || !strncmpi(sp
, " named ", 7)
1779 || !strncmpi(sp
, " labeled ", 9)) {
1785 len
= (int) strlen(subj
);
1787 spot
= subj
+ len
- 1;
1790 * plural: anything that ends in 's', but not '*us' or '*ss'.
1791 * Guess at a few other special cases that makeplural creates.
1793 if ((lowc(*spot
) == 's' && spot
!= subj
1794 && !index("us", lowc(*(spot
- 1))))
1795 || !BSTRNCMPI(subj
, spot
- 3, "eeth", 4)
1796 || !BSTRNCMPI(subj
, spot
- 3, "feet", 4)
1797 || !BSTRNCMPI(subj
, spot
- 1, "ia", 2)
1798 || !BSTRNCMPI(subj
, spot
- 1, "ae", 2)) {
1799 /* check for special cases to avoid false matches */
1800 len
= (int) (spot
- subj
) + 1;
1801 for (spec
= special_subjs
; *spec
; spec
++) {
1802 ltmp
= strlen(*spec
);
1803 if (len
== ltmp
&& !strncmpi(*spec
, subj
, len
))
1805 /* also check for <prefix><space><special_subj>
1806 to catch things like "the invisible erinys" */
1807 if (len
> ltmp
&& *(spot
- ltmp
) == ' '
1808 && !strncmpi(*spec
, spot
- ltmp
+ 1, ltmp
))
1812 return strcpy(buf
, verb
);
1815 * 3rd person plural doesn't end in telltale 's';
1816 * 2nd person singular behaves as if plural.
1818 if (!strcmpi(subj
, "they") || !strcmpi(subj
, "you"))
1819 return strcpy(buf
, verb
);
1824 len
= (int) strlen(buf
);
1825 bspot
= buf
+ len
- 1;
1827 if (!strcmpi(buf
, "are")) {
1828 Strcasecpy(buf
, "is");
1829 } else if (!strcmpi(buf
, "have")) {
1830 Strcasecpy(bspot
- 1, "s");
1831 } else if (index("zxs", lowc(*bspot
))
1832 || (len
>= 2 && lowc(*bspot
) == 'h'
1833 && index("cs", lowc(*(bspot
- 1))))
1834 || (len
== 2 && lowc(*bspot
) == 'o')) {
1835 /* Ends in z, x, s, ch, sh; add an "es" */
1836 Strcasecpy(bspot
+ 1, "es");
1837 } else if (lowc(*bspot
) == 'y' && !index(vowels
, lowc(*(bspot
- 1)))) {
1838 /* like "y" case in makeplural */
1839 Strcasecpy(bspot
, "ies");
1841 Strcasecpy(bspot
+ 1, "s");
1848 const char *sing
, *plur
;
1851 /* word pairs that don't fit into formula-based transformations;
1852 also some suffices which have very few--often one--matches or
1853 which aren't systematically reversible (knives, staves) */
1854 static struct sing_plur one_off
[] = {
1856 "children" }, /* (for wise guys who give their food funny names) */
1857 { "cubus", "cubi" }, /* in-/suc-cubus */
1858 { "culus", "culi" }, /* homunculus */
1859 { "djinni", "djinn" },
1860 { "erinys", "erinyes" },
1862 { "fungus", "fungi" },
1863 { "knife", "knives" },
1864 { "labrum", "labra" }, /* candelabrum */
1865 { "louse", "lice" },
1866 { "mouse", "mice" },
1867 { "mumak", "mumakil" },
1868 { "nemesis", "nemeses" },
1869 { "rtex", "rtices" }, /* vortex */
1870 { "tooth", "teeth" },
1871 { "staff", "staves" },
1875 static const char *const as_is
[] = {
1876 /* makesingular() leaves these plural due to how they're used */
1877 "boots", "shoes", "gloves", "lenses", "scales",
1878 "eyes", "gauntlets", "iron bars",
1879 /* both singular and plural are spelled the same */
1880 "deer", "fish", "tuna", "yaki", "-hai",
1881 "krill", "manes", "ninja", "sheep", "ronin",
1882 "roshi", "shito", "tengu", "ki-rin", "Nazgul",
1883 "gunyoki", "piranha", "samurai", "shuriken", 0,
1884 /* Note: "fish" and "piranha" are collective plurals, suitable
1885 for "wiped out all <foo>". For "3 <foo>", they should be
1886 "fishes" and "piranhas" instead. We settle for collective
1887 variant instead of attempting to support both. */
1890 /* singularize/pluralize decisions common to both makesingular & makeplural
1893 singplur_lookup(basestr
, endstring
, to_plural
, alt_as_is
)
1894 char *basestr
, *endstring
; /* base string, pointer to eos(string) */
1895 boolean to_plural
; /* true => makeplural, false => makesingular */
1896 const char *const *alt_as_is
; /* another set like as_is[] */
1898 const struct sing_plur
*sp
;
1899 const char *same
, *other
, *const *as
;
1902 for (as
= as_is
; *as
; ++as
) {
1903 al
= (int) strlen(*as
);
1904 if (!BSTRCMPI(basestr
, endstring
- al
, *as
))
1908 for (as
= alt_as_is
; *as
; ++as
) {
1909 al
= (int) strlen(*as
);
1910 if (!BSTRCMPI(basestr
, endstring
- al
, *as
))
1915 /* avoid false hit on one_off[].plur == "lice";
1916 if more of these turn up, one_off[] entries will need to flagged
1917 as to which are whole words and which are matchable as suffices
1918 then matching in the loop below will end up becoming more complex */
1919 if (!strcmpi(basestr
, "slice")) {
1921 (void) strkitten(basestr
, 's');
1924 for (sp
= one_off
; sp
->sing
; sp
++) {
1925 /* check whether endstring already matches */
1926 same
= to_plural
? sp
->plur
: sp
->sing
;
1927 al
= (int) strlen(same
);
1928 if (!BSTRCMPI(basestr
, endstring
- al
, same
))
1929 return TRUE
; /* use as-is */
1930 /* check whether it matches the inverse; if so, transform it */
1931 other
= to_plural
? sp
->sing
: sp
->plur
;
1932 al
= (int) strlen(other
);
1933 if (!BSTRCMPI(basestr
, endstring
- al
, other
)) {
1934 Strcasecpy(endstring
- al
, same
);
1935 return TRUE
; /* one_off[] transformation */
1941 /* searches for common compounds, ex. lump of royal jelly */
1943 singplur_compound(str
)
1946 /* if new entries are added, be sure to keep compound_start[] in sync */
1947 static const char *const compounds
[] =
1949 " of ", " labeled ", " called ",
1950 " named ", " above", /* lurkers above */
1951 " versus ", " from ", " in ",
1952 " on ", " a la ", " with", /* " with "? */
1953 " de ", " d'", " du ",
1955 }, /* list of first characters for all compounds[] entries */
1956 compound_start
[] = " -";
1958 const char *const *cmpd
;
1961 for (p
= str
; *p
; ++p
) {
1962 /* substring starting at p can only match if *p is found
1963 within compound_start[] */
1964 if (!index(compound_start
, *p
))
1967 /* check current substring against all words in the compound[] list */
1968 for (cmpd
= compounds
; *cmpd
; ++cmpd
)
1969 if (!strncmpi(p
, *cmpd
, (int) strlen(*cmpd
)))
1972 /* wasn't recognized as a compound phrase */
1976 /* Plural routine; chiefly used for user-defined fruits. We have to try to
1977 * account for everything reasonable the player has; something unreasonable
1978 * can still break the code. However, it's still a lot more accurate than
1979 * "just add an s at the end", which Rogue uses...
1981 * Also used for plural monster names ("Wiped out all homunculi." or the
1982 * vanquished monsters list) and body parts. A lot of unique monsters have
1983 * names which get mangled by makeplural and/or makesingular. They're not
1984 * genocidable, and vanquished-mon handling does its own special casing
1985 * (for uniques who've been revived and re-killed), so we don't bother
1986 * trying to get those right here.
1988 * Also misused by muse.c to convert 1st person present verbs to 2nd person.
1989 * 3.6.0: made case-insensitive.
1995 register char *spot
;
1996 char lo_c
, *str
= nextobuf();
1997 const char *excess
= (char *) 0;
2001 while (*oldstr
== ' ')
2003 if (!oldstr
|| !*oldstr
) {
2004 impossible("plural of null?");
2008 Strcpy(str
, oldstr
);
2011 * Skip changing "pair of" to "pairs of". According to Webster, usual
2012 * English usage is use pairs for humans, e.g. 3 pairs of dancers,
2013 * and pair for objects and non-humans, e.g. 3 pair of boots. We don't
2014 * refer to pairs of humans in this game so just skip to the bottom.
2016 if (!strncmpi(str
, "pair of ", 8))
2019 /* look for "foo of bar" so that we can focus on "foo" */
2020 if ((spot
= singplur_compound(str
)) != 0) {
2021 excess
= oldstr
+ (int) (spot
- str
);
2027 while (spot
> str
&& *spot
== ' ')
2028 spot
--; /* Strip blanks from end */
2030 /* Now spot is the last character of the string */
2034 /* Single letters */
2035 if (len
== 1 || !letter(*spot
)) {
2036 Strcpy(spot
+ 1, "'s");
2040 /* dispense with some words which don't need pluralization */
2042 static const char *const already_plural
[] = {
2043 "ae", /* algae, larvae, &c */
2044 "men", /* also catches women, watchmen */
2048 /* spot+1: synch up with makesingular's usage */
2049 if (singplur_lookup(str
, spot
+ 1, TRUE
, already_plural
))
2052 /* more of same, but not suitable for blanket loop checking */
2053 if ((len
== 2 && !strcmpi(str
, "ya"))
2054 || (len
>= 3 && !strcmpi(spot
- 2, " ya")))
2058 /* man/men ("Wiped out all cavemen.") */
2059 if (len
>= 3 && !strcmpi(spot
- 2, "man")
2060 /* exclude shamans and humans */
2061 && (len
< 6 || strcmpi(spot
- 5, "shaman"))
2062 && (len
< 5 || strcmpi(spot
- 4, "human"))) {
2063 Strcasecpy(spot
- 1, "en");
2066 if (lowc(*spot
) == 'f') { /* (staff handled via one_off[]) */
2067 lo_c
= lowc(*(spot
- 1));
2068 if (len
>= 3 && !strcmpi(spot
- 2, "erf")) {
2069 /* avoid "nerf" -> "nerves", "serf" -> "serves" */
2070 ; /* fall through to default (append 's') */
2071 } else if (index("lr", lo_c
) || index(vowels
, lo_c
)) {
2072 /* [aeioulr]f to [aeioulr]ves */
2073 Strcasecpy(spot
, "ves");
2077 /* ium/ia (mycelia, baluchitheria) */
2078 if (len
>= 3 && !strcmpi(spot
- 2, "ium")) {
2079 Strcasecpy(spot
- 2, "ia");
2082 /* algae, larvae, hyphae (another fungus part) */
2083 if ((len
>= 4 && !strcmpi(spot
- 3, "alga"))
2085 && (!strcmpi(spot
- 4, "hypha") || !strcmpi(spot
- 4, "larva")))
2086 || (len
>= 6 && !strcmpi(spot
- 5, "amoeba"))
2087 || (len
>= 8 && (!strcmpi(spot
- 7, "vertebra")))) {
2089 Strcasecpy(spot
+ 1, "e");
2092 /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */
2093 if (len
> 3 && !strcmpi(spot
- 1, "us")
2094 && !((len
>= 5 && !strcmpi(spot
- 4, "lotus"))
2095 || (len
>= 6 && !strcmpi(spot
- 5, "wumpus")))) {
2096 Strcasecpy(spot
- 1, "i");
2099 /* sis/ses (nemesis) */
2100 if (len
>= 3 && !strcmpi(spot
- 2, "sis")) {
2101 Strcasecpy(spot
- 1, "es");
2104 /* matzoh/matzot, possible food name */
2106 && (!strcmpi(spot
- 5, "matzoh") || !strcmpi(spot
- 5, "matzah"))) {
2107 Strcasecpy(spot
- 1, "ot"); /* oh/ah -> ot */
2111 && (!strcmpi(spot
- 4, "matzo") || !strcmpi(spot
- 4, "matza"))) {
2112 Strcasecpy(spot
, "ot"); /* o/a -> ot */
2116 /* note: -eau/-eaux (gateau, bordeau...) */
2117 /* note: ox/oxen, VAX/VAXen, goose/geese */
2121 /* Ends in z, x, s, ch, sh; add an "es" */
2122 if (index("zxs", lo_c
)
2123 || (len
>= 2 && lo_c
== 'h' && index("cs", lowc(*(spot
- 1))))
2124 /* Kludge to get "tomatoes" and "potatoes" right */
2125 || (len
>= 4 && !strcmpi(spot
- 2, "ato"))
2126 || (len
>= 5 && !strcmpi(spot
- 4, "dingo"))) {
2127 Strcasecpy(spot
+ 1, "es"); /* append es */
2130 /* Ends in y preceded by consonant (note: also "qu") change to "ies" */
2131 if (lo_c
== 'y' && !index(vowels
, lowc(*(spot
- 1)))) {
2132 Strcasecpy(spot
, "ies"); /* y -> ies */
2135 /* Default: append an 's' */
2136 Strcasecpy(spot
+ 1, "s");
2140 Strcat(str
, excess
);
2145 * Singularize a string the user typed in; this helps reduce the complexity
2146 * of readobjnam, and is also used in pager.c to singularize the string
2147 * for which help is sought.
2149 * "Manes" is ambiguous: monster type (keep s), or horse body part (drop s)?
2150 * Its inclusion in as_is[]/special_subj[] makes it get treated as the former.
2152 * A lot of unique monsters have names ending in s; plural, or singular
2153 * from plural, doesn't make much sense for them so we don't bother trying.
2154 * 3.6.0: made case-insensitive.
2157 makesingular(oldstr
)
2160 register char *p
, *bp
;
2161 const char *excess
= 0;
2162 char *str
= nextobuf();
2165 while (*oldstr
== ' ')
2167 if (!oldstr
|| !*oldstr
) {
2168 impossible("singular of null?");
2173 bp
= strcpy(str
, oldstr
);
2175 /* check for "foo of bar" so that we can focus on "foo" */
2176 if ((p
= singplur_compound(bp
)) != 0) {
2177 excess
= oldstr
+ (int) (p
- bp
);
2182 /* dispense with some words which don't need singularization */
2183 if (singplur_lookup(bp
, p
, FALSE
, special_subjs
))
2186 /* remove -s or -es (boxes) or -ies (rubies) */
2187 if (p
>= bp
+ 1 && lowc(p
[-1]) == 's') {
2188 if (p
>= bp
+ 2 && lowc(p
[-2]) == 'e') {
2189 if (p
>= bp
+ 3 && lowc(p
[-3]) == 'i') { /* "ies" */
2190 if (!BSTRCMPI(bp
, p
- 7, "cookies")
2191 || !BSTRCMPI(bp
, p
- 4, "pies")
2192 || !BSTRCMPI(bp
, p
- 5, "mbies") /* zombie */
2193 || !BSTRCMPI(bp
, p
- 5, "yries")) /* valkyrie */
2195 Strcasecpy(p
- 3, "y"); /* ies -> y */
2198 /* wolves, but f to ves isn't fully reversible */
2199 if (p
- 4 >= bp
&& (index("lr", lowc(*(p
- 4)))
2200 || index(vowels
, lowc(*(p
- 4))))
2201 && !BSTRCMPI(bp
, p
- 3, "ves")) {
2202 if (!BSTRCMPI(bp
, p
- 6, "cloves")
2203 || !BSTRCMPI(bp
, p
- 6, "nerves"))
2205 Strcasecpy(p
- 3, "f"); /* ves -> f */
2208 /* note: nurses, axes but boxes, wumpuses */
2209 if (!BSTRCMPI(bp
, p
- 4, "eses")
2210 || !BSTRCMPI(bp
, p
- 4, "oxes") /* boxes, foxes */
2211 || !BSTRCMPI(bp
, p
- 4, "nxes") /* lynxes */
2212 || !BSTRCMPI(bp
, p
- 4, "ches")
2213 || !BSTRCMPI(bp
, p
- 4, "uses") /* lotuses */
2214 || !BSTRCMPI(bp
, p
- 4, "sses") /* priestesses */
2215 || !BSTRCMPI(bp
, p
- 5, "atoes") /* tomatoes */
2216 || !BSTRCMPI(bp
, p
- 7, "dingoes")
2217 || !BSTRCMPI(bp
, p
- 7, "Aleaxes")) {
2218 *(p
- 2) = '\0'; /* drop es */
2220 } /* else fall through to mins */
2222 /* ends in 's' but not 'es' */
2223 } else if (!BSTRCMPI(bp
, p
- 2, "us")) { /* lotus, fungus... */
2224 if (BSTRCMPI(bp
, p
- 6, "tengus") /* but not these... */
2225 && BSTRCMPI(bp
, p
- 7, "hezrous"))
2227 } else if (!BSTRCMPI(bp
, p
- 2, "ss")
2228 || !BSTRCMPI(bp
, p
- 5, " lens")
2229 || (p
- 4 == bp
&& !strcmpi(p
- 4, "lens"))) {
2233 *(p
- 1) = '\0'; /* drop s */
2235 } else { /* input doesn't end in 's' */
2237 if (!BSTRCMPI(bp
, p
- 3, "men")) {
2238 Strcasecpy(p
- 2, "an");
2241 /* matzot -> matzo, algae -> alga */
2242 if (!BSTRCMPI(bp
, p
- 6, "matzot") || !BSTRCMPI(bp
, p
- 2, "ae")) {
2243 *(p
- 1) = '\0'; /* drop t/e */
2246 /* balactheria -> balactherium */
2247 if (p
- 4 >= bp
&& !strcmpi(p
- 2, "ia")
2248 && index("lr", lowc(*(p
- 3))) && lowc(*(p
- 4)) == 'e') {
2249 Strcasecpy(p
- 1, "um"); /* a -> um */
2252 /* here we cannot find the plural suffix */
2256 /* if we stripped off a suffix (" of bar" from "foo of bar"),
2257 put it back now [strcat() isn't actually 100% safe here...] */
2264 /* compare user string against object name string using fuzzy matching */
2266 wishymatch(u_str
, o_str
, retry_inverted
)
2267 const char *u_str
; /* from user, so might be variant spelling */
2268 const char *o_str
; /* from objects[], so is in canonical form */
2269 boolean retry_inverted
; /* optional extra "of" handling */
2271 static NEARDATA
const char detect_SP
[] = "detect ",
2272 SP_detection
[] = " detection";
2273 char *p
, buf
[BUFSZ
];
2275 /* ignore spaces & hyphens and upper/lower case when comparing */
2276 if (fuzzymatch(u_str
, o_str
, " -", TRUE
))
2279 if (retry_inverted
) {
2280 const char *u_of
, *o_of
;
2282 /* when just one of the strings is in the form "foo of bar",
2283 convert it into "bar foo" and perform another comparison */
2284 u_of
= strstri(u_str
, " of ");
2285 o_of
= strstri(o_str
, " of ");
2286 if (u_of
&& !o_of
) {
2287 Strcpy(buf
, u_of
+ 4);
2288 p
= eos(strcat(buf
, " "));
2289 while (u_str
< u_of
)
2292 return fuzzymatch(buf
, o_str
, " -", TRUE
);
2293 } else if (o_of
&& !u_of
) {
2294 Strcpy(buf
, o_of
+ 4);
2295 p
= eos(strcat(buf
, " "));
2296 while (o_str
< o_of
)
2299 return fuzzymatch(u_str
, buf
, " -", TRUE
);
2303 /* [note: if something like "elven speed boots" ever gets added, these
2304 special cases should be changed to call wishymatch() recursively in
2305 order to get the "of" inversion handling] */
2306 if (!strncmp(o_str
, "dwarvish ", 9)) {
2307 if (!strncmpi(u_str
, "dwarven ", 8))
2308 return fuzzymatch(u_str
+ 8, o_str
+ 9, " -", TRUE
);
2309 } else if (!strncmp(o_str
, "elven ", 6)) {
2310 if (!strncmpi(u_str
, "elvish ", 7))
2311 return fuzzymatch(u_str
+ 7, o_str
+ 6, " -", TRUE
);
2312 else if (!strncmpi(u_str
, "elfin ", 6))
2313 return fuzzymatch(u_str
+ 6, o_str
+ 6, " -", TRUE
);
2314 } else if (!strncmp(o_str
, detect_SP
, sizeof detect_SP
- 1)) {
2315 /* check for "detect <foo>" vs "<foo> detection" */
2316 if ((p
= strstri(u_str
, SP_detection
)) != 0
2317 && !*(p
+ sizeof SP_detection
- 1)) {
2318 /* convert "<foo> detection" into "detect <foo>" */
2320 Strcat(strcpy(buf
, detect_SP
), u_str
);
2321 /* "detect monster" -> "detect monsters" */
2322 if (!strcmpi(u_str
, "monster"))
2325 return fuzzymatch(buf
, o_str
, " -", TRUE
);
2327 } else if (strstri(o_str
, SP_detection
)) {
2328 /* and the inverse, "<foo> detection" vs "detect <foo>" */
2329 if (!strncmpi(u_str
, detect_SP
, sizeof detect_SP
- 1)) {
2330 /* convert "detect <foo>s" into "<foo> detection" */
2331 p
= makesingular(u_str
+ sizeof detect_SP
- 1);
2332 Strcat(strcpy(buf
, p
), SP_detection
);
2333 /* caller may be looping through objects[], so avoid
2334 churning through all the obufs */
2336 return fuzzymatch(buf
, o_str
, " -", TRUE
);
2338 } else if (strstri(o_str
, "ability")) {
2339 /* when presented with "foo of bar", makesingular() used to
2340 singularize both foo & bar, but now only does so for foo */
2341 /* catch "{potion(s),ring} of {gain,restore,sustain} abilities" */
2342 if ((p
= strstri(u_str
, "abilities")) != 0
2343 && !*(p
+ sizeof "abilities" - 1)) {
2344 (void) strncpy(buf
, u_str
, (unsigned) (p
- u_str
));
2345 Strcpy(buf
+ (p
- u_str
), "ability");
2346 return fuzzymatch(buf
, o_str
, " -", TRUE
);
2348 } else if (!strcmp(o_str
, "aluminum")) {
2349 /* this special case doesn't really fit anywhere else... */
2350 /* (note that " wand" will have been stripped off by now) */
2351 if (!strcmpi(u_str
, "aluminium"))
2352 return fuzzymatch(u_str
+ 9, o_str
+ 8, " -", TRUE
);
2359 const char *name
, oclass
;
2360 int f_o_range
, l_o_range
;
2363 /* wishable subranges of objects */
2364 STATIC_OVL NEARDATA
const struct o_range o_ranges
[] = {
2365 { "bag", TOOL_CLASS
, SACK
, BAG_OF_TRICKS
},
2366 { "lamp", TOOL_CLASS
, OIL_LAMP
, MAGIC_LAMP
},
2367 { "candle", TOOL_CLASS
, TALLOW_CANDLE
, WAX_CANDLE
},
2368 { "horn", TOOL_CLASS
, TOOLED_HORN
, HORN_OF_PLENTY
},
2369 { "shield", ARMOR_CLASS
, SMALL_SHIELD
, SHIELD_OF_REFLECTION
},
2370 { "hat", ARMOR_CLASS
, FEDORA
, DUNCE_CAP
},
2371 { "helm", ARMOR_CLASS
, ELVEN_LEATHER_HELM
, HELM_OF_TELEPATHY
},
2372 { "gloves", ARMOR_CLASS
, LEATHER_GLOVES
, GAUNTLETS_OF_DEXTERITY
},
2373 { "gauntlets", ARMOR_CLASS
, LEATHER_GLOVES
, GAUNTLETS_OF_DEXTERITY
},
2374 { "boots", ARMOR_CLASS
, LOW_BOOTS
, LEVITATION_BOOTS
},
2375 { "shoes", ARMOR_CLASS
, LOW_BOOTS
, IRON_SHOES
},
2376 { "cloak", ARMOR_CLASS
, MUMMY_WRAPPING
, CLOAK_OF_DISPLACEMENT
},
2377 { "shirt", ARMOR_CLASS
, HAWAIIAN_SHIRT
, T_SHIRT
},
2378 { "dragon scales", ARMOR_CLASS
, GRAY_DRAGON_SCALES
,
2379 YELLOW_DRAGON_SCALES
},
2380 { "dragon scale mail", ARMOR_CLASS
, GRAY_DRAGON_SCALE_MAIL
,
2381 YELLOW_DRAGON_SCALE_MAIL
},
2382 { "sword", WEAPON_CLASS
, SHORT_SWORD
, KATANA
},
2383 { "venom", VENOM_CLASS
, BLINDING_VENOM
, ACID_VENOM
},
2384 { "gray stone", GEM_CLASS
, LUCKSTONE
, FLINT
},
2385 { "grey stone", GEM_CLASS
, LUCKSTONE
, FLINT
},
2388 /* alternate spellings; if the difference is only the presence or
2389 absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
2390 vs "pick-axe") then there is no need for inclusion in this list;
2391 likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */
2392 struct alt_spellings
{
2396 { "pickax", PICK_AXE
},
2397 { "whip", BULLWHIP
},
2398 { "saber", SILVER_SABER
},
2399 { "silver sabre", SILVER_SABER
},
2400 { "smooth shield", SHIELD_OF_REFLECTION
},
2401 { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL
},
2402 { "grey dragon scales", GRAY_DRAGON_SCALES
},
2403 { "iron ball", HEAVY_IRON_BALL
},
2404 { "lantern", BRASS_LANTERN
},
2405 { "mattock", DWARVISH_MATTOCK
},
2406 { "amulet of poison resistance", AMULET_VERSUS_POISON
},
2407 { "potion of sleep", POT_SLEEPING
},
2409 { "camera", EXPENSIVE_CAMERA
},
2410 { "tee shirt", T_SHIRT
},
2412 { "can opener", TIN_OPENER
},
2413 { "kelp", KELP_FROND
},
2414 { "eucalyptus", EUCALYPTUS_LEAF
},
2415 { "royal jelly", LUMP_OF_ROYAL_JELLY
},
2416 { "lembas", LEMBAS_WAFER
},
2417 { "marker", MAGIC_MARKER
},
2418 { "hook", GRAPPLING_HOOK
},
2419 { "grappling iron", GRAPPLING_HOOK
},
2420 { "grapnel", GRAPPLING_HOOK
},
2421 { "grapple", GRAPPLING_HOOK
},
2422 { "protection from shape shifters", RIN_PROTECTION_FROM_SHAPE_CHAN
},
2423 /* normally we wouldn't have to worry about unnecessary <space>, but
2424 " stone" will get stripped off, preventing a wishymatch; that actually
2425 lets "flint stone" be a match, so we also accept bogus "flintstone" */
2426 { "luck stone", LUCKSTONE
},
2427 { "load stone", LOADSTONE
},
2428 { "touch stone", TOUCHSTONE
},
2429 { "flintstone", FLINT
},
2430 { (const char *) 0, 0 },
2434 rnd_otyp_by_wpnskill(skill
)
2438 short otyp
= STRANGE_OBJECT
;
2439 for (i
= bases
[WEAPON_CLASS
];
2440 i
< NUM_OBJECTS
&& objects
[i
].oc_class
== WEAPON_CLASS
; i
++)
2441 if (objects
[i
].oc_skill
== skill
) {
2447 for (i
= bases
[WEAPON_CLASS
];
2448 i
< NUM_OBJECTS
&& objects
[i
].oc_class
== WEAPON_CLASS
; i
++)
2449 if (objects
[i
].oc_skill
== skill
)
2457 rnd_otyp_by_namedesc(name
, oclass
)
2461 int i
= oclass
? bases
[(int)oclass
] : 1;
2463 short otyp
= STRANGE_OBJECT
;
2464 short validobjs
[NUM_OBJECTS
];
2465 register const char *zn
;
2468 if (!name
) return STRANGE_OBJECT
;
2470 memset((genericptr_t
) validobjs
, 0, sizeof(validobjs
));
2472 while (i
< NUM_OBJECTS
&& (!oclass
|| objects
[i
].oc_class
== oclass
)) {
2473 if ((zn
= OBJ_NAME(objects
[i
])) != 0 && wishymatch(name
, zn
, TRUE
)) {
2475 } else if ((zn
= OBJ_DESCR(objects
[i
])) != 0 && wishymatch(name
, zn
, FALSE
) &&
2476 /* don't match extra descriptions (w/o real name) */
2477 OBJ_NAME(objects
[i
])) {
2479 } else if ((zn
= objects
[i
].oc_uname
) != 0 && wishymatch(name
, zn
, FALSE
)) {
2482 if (otyp
!= STRANGE_OBJECT
) {
2483 validobjs
[n
++] = otyp
;
2484 maxprob
+= (objects
[otyp
].oc_prob
+ 1);
2485 otyp
= STRANGE_OBJECT
;
2490 if (n
> 0 && maxprob
) {
2491 long prob
= rn2(maxprob
);
2493 while ((i
< (n
-1)) && (prob
-= (objects
[validobjs
[i
]].oc_prob
+ 1)) > 0)
2495 return validobjs
[i
];
2497 return STRANGE_OBJECT
;
2502 * Return something wished for. Specifying a null pointer for
2503 * the user request string results in a random object. Otherwise,
2504 * if asking explicitly for "nothing" (or "nil") return no_wish;
2505 * if not an object return &zeroobj; if an error (no matching object),
2509 readobjnam(bp
, no_wish
)
2511 struct obj
*no_wish
;
2515 register struct obj
*otmp
;
2516 int cnt
, spe
, spesgn
, typ
, very
, rechrg
;
2517 int blessed
, uncursed
, iscursed
, ispoisoned
, isgreased
;
2518 int eroded
, eroded2
, erodeproof
;
2519 int halfeaten
, mntmp
, contents
;
2520 int islit
, unlabeled
, ishistoric
, isdiluted
, trapped
;
2521 int tmp
, tinv
, tvariety
;
2524 int ftype
= context
.current_fruit
;
2525 char fruitbuf
[BUFSZ
];
2526 /* Fruits may not mess up the ability to wish for real objects (since
2527 * you can leave a fruit in a bones file and it will be added to
2528 * another person's game), so they must be checked for last, after
2529 * stripping all the possible prefixes and seeing if there's a real
2530 * name in there. So we have to save the full original name. However,
2531 * it's still possible to do things like "uncursed burnt Alaska",
2532 * or worse yet, "2 burned 5 course meals", so we need to loop to
2533 * strip off the prefixes again, this time stripping only the ones
2535 * We could get even more detailed so as to allow food names with
2536 * prefixes that _are_ possible on food, so you could wish for
2537 * "2 3 alarm chilis". Currently this isn't allowed; options.c
2538 * automatically sticks 'candied' in front of such names.
2541 char *un
, *dn
, *actualn
, *origbp
= bp
;
2542 const char *name
= 0;
2544 cnt
= spe
= spesgn
= typ
= very
= rechrg
= blessed
= uncursed
= iscursed
=
2545 ispoisoned
= isgreased
= eroded
= eroded2
= erodeproof
= halfeaten
=
2546 islit
= unlabeled
= ishistoric
= isdiluted
= trapped
= 0;
2547 tvariety
= RANDOM_TIN
;
2552 contents
= UNDEFINED
;
2554 actualn
= dn
= un
= 0;
2559 /* first, remove extra whitespace they may have typed */
2560 (void) mungspaces(bp
);
2561 /* allow wishing for "nothing" to preserve wishless conduct...
2562 [now requires "wand of nothing" if that's what was really wanted] */
2563 if (!strcmpi(bp
, "nothing") || !strcmpi(bp
, "nil")
2564 || !strcmpi(bp
, "none"))
2566 /* save the [nearly] unmodified choice string */
2567 Strcpy(fruitbuf
, bp
);
2574 if (!strncmpi(bp
, "an ", l
= 3) || !strncmpi(bp
, "a ", l
= 2)) {
2576 } else if (!strncmpi(bp
, "the ", l
= 4)) {
2577 ; /* just increment `bp' by `l' below */
2578 } else if (!cnt
&& digit(*bp
) && strcmp(bp
, "0")) {
2585 } else if (*bp
== '+' || *bp
== '-') {
2586 spesgn
= (*bp
++ == '+') ? 1 : -1;
2593 } else if (!strncmpi(bp
, "blessed ", l
= 8)
2594 || !strncmpi(bp
, "holy ", l
= 5)) {
2596 } else if (!strncmpi(bp
, "moist ", l
= 6)
2597 || !strncmpi(bp
, "wet ", l
= 4)) {
2598 if (!strncmpi(bp
, "wet ", 4))
2599 wetness
= rn2(3) + 3;
2602 } else if (!strncmpi(bp
, "cursed ", l
= 7)
2603 || !strncmpi(bp
, "unholy ", l
= 7)) {
2605 } else if (!strncmpi(bp
, "uncursed ", l
= 9)) {
2607 } else if (!strncmpi(bp
, "rustproof ", l
= 10)
2608 || !strncmpi(bp
, "erodeproof ", l
= 11)
2609 || !strncmpi(bp
, "corrodeproof ", l
= 13)
2610 || !strncmpi(bp
, "fixed ", l
= 6)
2611 || !strncmpi(bp
, "fireproof ", l
= 10)
2612 || !strncmpi(bp
, "rotproof ", l
= 9)) {
2614 } else if (!strncmpi(bp
, "lit ", l
= 4)
2615 || !strncmpi(bp
, "burning ", l
= 8)) {
2617 } else if (!strncmpi(bp
, "unlit ", l
= 6)
2618 || !strncmpi(bp
, "extinguished ", l
= 13)) {
2620 /* "unlabeled" and "blank" are synonymous */
2621 } else if (!strncmpi(bp
, "unlabeled ", l
= 10)
2622 || !strncmpi(bp
, "unlabelled ", l
= 11)
2623 || !strncmpi(bp
, "blank ", l
= 6)) {
2625 } else if (!strncmpi(bp
, "poisoned ", l
= 9)) {
2627 /* "trapped" recognized but not honored outside wizard mode */
2628 } else if (!strncmpi(bp
, "trapped ", l
= 8)) {
2629 trapped
= 0; /* undo any previous "untrapped" */
2632 } else if (!strncmpi(bp
, "untrapped ", l
= 10)) {
2633 trapped
= 2; /* not trapped */
2634 } else if (!strncmpi(bp
, "greased ", l
= 8)) {
2636 } else if (!strncmpi(bp
, "very ", l
= 5)) {
2637 /* very rusted very heavy iron ball */
2639 } else if (!strncmpi(bp
, "thoroughly ", l
= 11)) {
2641 } else if (!strncmpi(bp
, "rusty ", l
= 6)
2642 || !strncmpi(bp
, "rusted ", l
= 7)
2643 || !strncmpi(bp
, "burnt ", l
= 6)
2644 || !strncmpi(bp
, "burned ", l
= 7)) {
2647 } else if (!strncmpi(bp
, "corroded ", l
= 9)
2648 || !strncmpi(bp
, "rotted ", l
= 7)) {
2651 } else if (!strncmpi(bp
, "partly eaten ", l
= 13)
2652 || !strncmpi(bp
, "partially eaten ", l
= 16)) {
2654 } else if (!strncmpi(bp
, "historic ", l
= 9)) {
2656 } else if (!strncmpi(bp
, "diluted ", l
= 8)) {
2658 } else if (!strncmpi(bp
, "empty ", l
= 6)) {
2665 cnt
= 1; /* %% what with "gems" etc. ? */
2666 if (strlen(bp
) > 1 && (p
= rindex(bp
, '(')) != 0) {
2667 boolean keeptrailingchars
= TRUE
;
2669 p
[(p
> bp
&& p
[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */
2670 ++p
; /* advance past '(' */
2671 if (!strncmpi(p
, "lit)", 4)) {
2673 p
+= 4 - 1; /* point at ')' */
2687 /* mis-matched parentheses; rest of string will be ignored
2688 * [probably we should restore everything back to '('
2689 * instead since it might be part of "named ..."]
2691 keeptrailingchars
= FALSE
;
2696 if (keeptrailingchars
) {
2699 /* 'pp' points at 'pb's terminating '\0',
2700 'p' points at ')' and will be incremented past it */
2707 * otmp->spe is type schar, so we don't want spe to be any bigger or
2708 * smaller. Also, spe should always be positive --some cheaters may
2709 * try to confuse atoi().
2712 spesgn
= -1; /* cheaters get what they deserve */
2715 if (spe
> SCHAR_LIM
)
2717 if (rechrg
< 0 || rechrg
> 7)
2718 rechrg
= 7; /* recharge_limit */
2720 /* now we have the actual name, as delivered by xname, say
2721 * green potions called whisky
2722 * scrolls labeled "QWERTY"
2725 * very heavy iron ball named hoei
2729 if ((p
= strstri(bp
, " named ")) != 0) {
2733 if ((p
= strstri(bp
, " called ")) != 0) {
2736 /* "helmet called telepathy" is not "helmet" (a specific type)
2737 * "shield called reflection" is not "shield" (a general type)
2739 for (i
= 0; i
< SIZE(o_ranges
); i
++)
2740 if (!strcmpi(bp
, o_ranges
[i
].name
)) {
2741 oclass
= o_ranges
[i
].oclass
;
2745 if ((p
= strstri(bp
, " labeled ")) != 0) {
2748 } else if ((p
= strstri(bp
, " labelled ")) != 0) {
2752 if ((p
= strstri(bp
, " of spinach")) != 0) {
2758 Skip over "pair of ", "pairs of", "set of" and "sets of".
2760 Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
2761 English either way. See makeplural() for more on pair/pairs.
2763 We should only double count if the object in question is not
2764 referred to as a "pair of". E.g. We should double if the player
2765 types "pair of spears", but not if the player types "pair of
2766 lenses". Luckily (?) all objects that are referred to as pairs
2767 -- boots, gloves, and lenses -- are also not mergable, so cnt is
2770 if (!strncmpi(bp
, "pair of ", 8)) {
2773 } else if (cnt
> 1 && !strncmpi(bp
, "pairs of ", 9)) {
2776 } else if (!strncmpi(bp
, "set of ", 7)) {
2778 } else if (!strncmpi(bp
, "sets of ", 8)) {
2782 /* intercept pudding globs here; they're a valid wish target,
2783 * but we need them to not get treated like a corpse.
2785 * also don't let player wish for multiple globs.
2787 if ((p
= strstri(bp
, "glob of ")) != 0
2788 || (p
= strstri(bp
, "globs of ")) != 0) {
2789 int globoffset
= (*(p
+ 4) == 's') ? 9 : 8;
2790 if ((mntmp
= name_to_mon(p
+ globoffset
)) >= PM_GRAY_OOZE
2791 && mntmp
<= PM_BLACK_PUDDING
) {
2792 mntmp
= NON_PM
; /* lie to ourselves */
2793 cnt
= 0; /* force only one */
2797 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
2798 * Don't check if it's a wand or spellbook.
2799 * (avoid "wand/finger of death" confusion).
2801 if (!strstri(bp
, "wand ") && !strstri(bp
, "spellbook ")
2802 && !strstri(bp
, "finger ")) {
2803 if (((p
= strstri(bp
, "tin of ")) != 0)
2804 && (tmp
= tin_variety_txt(p
+ 7, &tinv
))
2805 && (mntmp
= name_to_mon(p
+ 7 + tmp
)) >= LOW_PM
) {
2808 } else if ((p
= strstri(bp
, " of ")) != 0
2809 && (mntmp
= name_to_mon(p
+ 4)) >= LOW_PM
)
2813 /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
2814 if (strncmpi(bp
, "samurai sword", 13)) /* not the "samurai" monster! */
2815 if (strncmpi(bp
, "wizard lock", 11)) /* not the "wizard" monster! */
2816 if (strncmpi(bp
, "ninja-to", 8)) /* not the "ninja" rank */
2817 if (strncmpi(bp
, "master key",
2818 10)) /* not the "master" rank */
2819 if (strncmpi(bp
, "magenta", 7)) /* not the "mage" rank */
2820 if (mntmp
< LOW_PM
&& strlen(bp
) > 2
2821 && (mntmp
= name_to_mon(bp
)) >= LOW_PM
) {
2823 mntmplen
; /* double check for rank title */
2825 mntmptoo
= title_to_mon(bp
, (int *) 0, &mntmplen
);
2826 bp
+= mntmp
!= mntmptoo
2827 ? (int) strlen(mons
[mntmp
].mname
)
2831 else if (!strncmpi(bp
, "s ", 2))
2833 else if (!strncmpi(bp
, "es ", 3))
2835 else if (!*bp
&& !actualn
&& !dn
&& !un
2837 /* no referent; they don't really mean a
2844 /* first change to singular if necessary */
2846 char *sng
= makesingular(bp
);
2847 if (strcmp(bp
, sng
)) {
2854 /* Alternate spellings (pick-ax, silver sabre, &c) */
2856 struct alt_spellings
*as
= spellings
;
2859 if (fuzzymatch(bp
, as
->sp
, " -", TRUE
)) {
2865 /* can't use spellings list for this one due to shuffling */
2866 if (!strncmpi(bp
, "grey spell", 10))
2869 if ((p
= strstri(bp
, "armour")) != 0) {
2870 /* skip past "armo", then copy remainder beyond "u" */
2872 while ((*p
= *(p
+ 1)) != '\0')
2873 ++p
; /* self terminating */
2877 /* dragon scales - assumes order of dragons */
2878 if (!strcmpi(bp
, "scales") && mntmp
>= PM_GRAY_DRAGON
2879 && mntmp
<= PM_YELLOW_DRAGON
) {
2880 typ
= GRAY_DRAGON_SCALES
+ mntmp
- PM_GRAY_DRAGON
;
2881 mntmp
= NON_PM
; /* no monster */
2886 if (!BSTRCMPI(bp
, p
- 10, "holy water")) {
2888 if ((p
- bp
) >= 12 && *(p
- 12) == 'u')
2889 iscursed
= 1; /* unholy water */
2894 if (unlabeled
&& !BSTRCMPI(bp
, p
- 6, "scroll")) {
2895 typ
= SCR_BLANK_PAPER
;
2898 if (unlabeled
&& !BSTRCMPI(bp
, p
- 9, "spellbook")) {
2899 typ
= SPE_BLANK_PAPER
;
2903 * NOTE: Gold pieces are handled as objects nowadays, and therefore
2904 * this section should probably be reconsidered as well as the entire
2905 * gold/money concept. Maybe we want to add other monetary units as
2906 * well in the future. (TH)
2908 if (!BSTRCMPI(bp
, p
- 10, "gold piece") || !BSTRCMPI(bp
, p
- 7, "zorkmid")
2909 || !strcmpi(bp
, "gold") || !strcmpi(bp
, "money")
2910 || !strcmpi(bp
, "coin") || *bp
== GOLD_SYM
) {
2911 if (cnt
> 5000 && !wizard
)
2915 otmp
= mksobj(GOLD_PIECE
, FALSE
, FALSE
);
2916 otmp
->quan
= (long) cnt
;
2917 otmp
->owt
= weight(otmp
);
2922 /* check for single character object class code ("/" for wand, &c) */
2923 if (strlen(bp
) == 1 && (i
= def_char_to_objclass(*bp
)) < MAXOCLASSES
2924 && i
> ILLOBJ_CLASS
&& (i
!= VENOM_CLASS
|| wizard
)) {
2929 /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */
2930 /* false hits on, e.g., rings for "ring mail". */
2931 if (strncmpi(bp
, "enchant ", 8) && strncmpi(bp
, "destroy ", 8)
2932 && strncmpi(bp
, "detect food", 11)
2933 && strncmpi(bp
, "food detection", 14) && strncmpi(bp
, "ring mail", 9)
2934 && strncmpi(bp
, "studded leather armor", 21)
2935 && strncmpi(bp
, "leather armor", 13)
2936 && strncmpi(bp
, "tooled horn", 11) && strncmpi(bp
, "food ration", 11)
2937 && strncmpi(bp
, "meat ring", 9))
2938 for (i
= 0; i
< (int) (sizeof wrpsym
); i
++) {
2939 register int j
= strlen(wrp
[i
]);
2940 if (!strncmpi(bp
, wrp
[i
], j
)) {
2942 if (oclass
!= AMULET_CLASS
) {
2944 if (!strncmpi(bp
, " of ", 4))
2946 /* else if(*bp) ?? */
2951 if (!BSTRCMPI(bp
, p
- j
, wrp
[i
])) {
2955 if (p
> bp
&& p
[-1] == ' ')
2962 /* Wishing in wizard mode can create traps and furniture.
2963 * Part I: distinguish between trap and object for the two
2964 * types of traps which have corresponding objects: bear trap
2965 * and land mine. "beartrap" (object) and "bear trap" (trap)
2966 * have a difference in spelling which we used to exploit by
2967 * adding a special case in wishymatch(), but "land mine" is
2968 * spelled the same either way so needs different handing.
2969 * Since we need something else for land mine, we've dropped
2970 * the bear trap hack so that both are handled exactly the
2971 * same. To get an armed trap instead of a disarmed object,
2972 * the player can prefix either the object name or the trap
2973 * name with "trapped " (which ordinarily applies to chests
2974 * and tins), or append something--anything at all except for
2975 * " object", but " trap" is suggested--to either the trap
2976 * name or the object name.
2978 if (wizard
&& (!strncmpi(bp
, "bear", 4) || !strncmpi(bp
, "land", 4))) {
2979 boolean beartrap
= (lowc(*bp
) == 'b');
2980 char *zp
= bp
+ 4; /* skip "bear"/"land" */
2983 ++zp
; /* embedded space is optional */
2984 if (!strncmpi(zp
, beartrap
? "trap" : "mine", 4)) {
2986 if (trapped
== 2 || !strcmpi(zp
, " object")) {
2987 /* "untrapped <foo>" or "<foo> object" */
2988 typ
= beartrap
? BEARTRAP
: LAND_MINE
;
2990 } else if (trapped
== 1 || *zp
!= '\0') {
2991 /* "trapped <foo>" or "<foo> trap" (actually "<foo>*") */
2992 int idx
= trap_to_defsym(beartrap
? BEAR_TRAP
: LANDMINE
);
2994 /* use canonical trap spelling, skip object matching */
2995 Strcpy(bp
, defsyms
[idx
].explanation
);
2998 /* [no prefix or suffix; we're going to end up matching
2999 the object name and getting a disarmed trap object] */
3004 /* "grey stone" check must be before general "stone" */
3005 for (i
= 0; i
< SIZE(o_ranges
); i
++)
3006 if (!strcmpi(bp
, o_ranges
[i
].name
)) {
3007 typ
= rnd_class(o_ranges
[i
].f_o_range
, o_ranges
[i
].l_o_range
);
3011 if (!BSTRCMPI(bp
, p
- 6, " stone") || !BSTRCMPI(bp
, p
- 4, " gem")) {
3012 p
[!strcmpi(p
- 4, " gem") ? -4 : -6] = '\0';
3016 } else if (!strcmpi(bp
, "looking glass")) {
3017 ; /* avoid false hit on "* glass" */
3018 } else if (!BSTRCMPI(bp
, p
- 6, " glass") || !strcmpi(bp
, "glass")) {
3019 register char *g
= bp
;
3020 if (strstri(g
, "broken"))
3021 return (struct obj
*) 0;
3022 if (!strncmpi(g
, "worthless ", 10))
3024 if (!strncmpi(g
, "piece of ", 9))
3026 if (!strncmpi(g
, "colored ", 8))
3028 else if (!strncmpi(g
, "coloured ", 9))
3030 if (!strcmpi(g
, "glass")) { /* choose random color */
3031 /* 9 different kinds */
3032 typ
= LAST_GEM
+ rnd(9);
3033 if (objects
[typ
].oc_class
== GEM_CLASS
)
3036 typ
= 0; /* somebody changed objects[]? punt */
3037 } else { /* try to construct canonical form */
3040 Strcpy(tbuf
, "worthless piece of ");
3041 Strcat(tbuf
, g
); /* assume it starts with the color */
3048 dn
= actualn
; /* ex. "skull cap" */
3050 /* check real names of gems first */
3051 if (!oclass
&& actualn
) {
3052 for (i
= bases
[GEM_CLASS
]; i
<= LAST_GEM
; i
++) {
3053 register const char *zn
;
3055 if ((zn
= OBJ_NAME(objects
[i
])) && !strcmpi(actualn
, zn
)) {
3062 if (((typ
= rnd_otyp_by_namedesc(actualn
, oclass
)) != STRANGE_OBJECT
)
3063 || ((typ
= rnd_otyp_by_namedesc(dn
, oclass
)) != STRANGE_OBJECT
)
3064 || ((typ
= rnd_otyp_by_namedesc(un
, oclass
)) != STRANGE_OBJECT
)
3065 || ((typ
= rnd_otyp_by_namedesc(origbp
, oclass
)) != STRANGE_OBJECT
))
3070 struct Jitem
*j
= Japanese_items
;
3073 if (actualn
&& !strcmpi(actualn
, j
->name
)) {
3080 /* if we've stripped off "armor" and failed to match anything
3081 in objects[], append "mail" and try again to catch misnamed
3082 requests like "plate armor" and "yellow dragon scale armor" */
3083 if (oclass
== ARMOR_CLASS
&& !strstri(bp
, "mail")) {
3084 /* modifying bp's string is ok; we're about to resort
3085 to random armor if this also fails to match anything */
3086 Strcat(bp
, " mail");
3089 if (!strcmpi(bp
, "spinach")) {
3094 /* Note: not strcmpi. 2 fruits, one capital, one not, are possible.
3095 Also not strncmp. We used to ignore trailing text with it, but
3096 that resulted in "grapefruit" matching "grape" if the latter came
3097 earlier than the former in the fruit list. */
3101 int blessedf
, iscursedf
, uncursedf
, halfeatenf
;
3103 blessedf
= iscursedf
= uncursedf
= halfeatenf
= 0;
3110 if (!strncmpi(fp
, "an ", l
= 3) || !strncmpi(fp
, "a ", l
= 2)) {
3112 } else if (!cntf
&& digit(*fp
)) {
3119 } else if (!strncmpi(fp
, "blessed ", l
= 8)) {
3121 } else if (!strncmpi(fp
, "cursed ", l
= 7)) {
3123 } else if (!strncmpi(fp
, "uncursed ", l
= 9)) {
3125 } else if (!strncmpi(fp
, "partly eaten ", l
= 13)
3126 || !strncmpi(fp
, "partially eaten ", l
= 16)) {
3133 for (f
= ffruit
; f
; f
= f
->nextf
) {
3134 /* match type: 0=none, 1=exact, 2=singular, 3=plural */
3137 if (!strcmp(fp
, f
->fname
))
3139 else if (!strcmp(fp
, makesingular(f
->fname
)))
3141 else if (!strcmp(fp
, makeplural(f
->fname
)))
3146 iscursed
= iscursedf
;
3147 uncursed
= uncursedf
;
3148 halfeaten
= halfeatenf
;
3149 /* adjust count if user explicitly asked for
3150 singular amount (can't happen unless fruit
3151 has been given an already pluralized name)
3152 or for plural amount */
3153 if (ftyp
== 2 && !cntf
)
3155 else if (ftyp
== 3 && !cntf
)
3164 if (!oclass
&& actualn
) {
3167 /* Perhaps it's an artifact specified by name, not type */
3168 name
= artifact_name(actualn
, &objtyp
);
3174 /* Let wizards wish for traps and furniture.
3175 * Must come after objects check so wizards can still wish for
3176 * trap objects like beartraps.
3177 * Disallow such topology tweaks for WIZKIT startup wishes.
3180 if (wizard
&& !program_state
.wizkit_wishing
) {
3182 int trap
, x
= u
.ux
, y
= u
.uy
;
3184 for (trap
= NO_TRAP
+ 1; trap
< TRAPNUM
; trap
++) {
3188 tname
= defsyms
[trap_to_defsym(trap
)].explanation
;
3189 if (strncmpi(tname
, bp
, strlen(tname
)))
3191 /* found it; avoid stupid mistakes */
3192 if ((trap
== TRAPDOOR
|| trap
== HOLE
) && !Can_fall_thru(&u
.uz
))
3194 if ((t
= maketrap(x
, y
, trap
)) != 0) {
3196 tname
= defsyms
[trap_to_defsym(trap
)].explanation
;
3197 pline("%s%s.", An(tname
),
3198 (trap
!= MAGIC_PORTAL
) ? "" : " to nowhere");
3200 pline("Creation of %s failed.", an(tname
));
3204 /* furniture and terrain */
3207 if (!BSTRCMPI(bp
, p
- 8, "fountain")) {
3208 lev
->typ
= FOUNTAIN
;
3209 level
.flags
.nfountains
++;
3210 if (!strncmpi(bp
, "magic ", 6))
3211 lev
->blessedftn
= 1;
3212 pline("A %sfountain.", lev
->blessedftn
? "magic " : "");
3216 if (!BSTRCMPI(bp
, p
- 6, "throne")) {
3222 if (!BSTRCMPI(bp
, p
- 4, "sink")) {
3224 level
.flags
.nsinks
++;
3229 /* ("water" matches "potion of water" rather than terrain) */
3230 if (!BSTRCMPI(bp
, p
- 4, "pool") || !BSTRCMPI(bp
, p
- 4, "moat")) {
3231 lev
->typ
= !BSTRCMPI(bp
, p
- 4, "pool") ? POOL
: MOAT
;
3233 pline("A %s.", (lev
->typ
== POOL
) ? "pool" : "moat");
3234 /* Must manually make kelp! */
3235 water_damage_chain(level
.objects
[x
][y
], TRUE
);
3239 if (!BSTRCMPI(bp
, p
- 4, "lava")) { /* also matches "molten lava" */
3240 lev
->typ
= LAVAPOOL
;
3242 pline("A pool of molten lava.");
3243 if (!(Levitation
|| Flying
))
3244 (void) lava_effects();
3249 if (!BSTRCMPI(bp
, p
- 5, "altar")) {
3253 if (!strncmpi(bp
, "chaotic ", 8))
3255 else if (!strncmpi(bp
, "neutral ", 8))
3257 else if (!strncmpi(bp
, "lawful ", 7))
3259 else if (!strncmpi(bp
, "unaligned ", 10))
3261 else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
3262 al
= (!rn2(6)) ? A_NONE
: rn2((int) A_LAWFUL
+ 2) - 1;
3263 lev
->altarmask
= Align2amask(al
);
3264 pline("%s altar.", An(align_str(al
)));
3269 if (!BSTRCMPI(bp
, p
- 5, "grave")
3270 || !BSTRCMPI(bp
, p
- 9, "headstone")) {
3271 make_grave(x
, y
, (char *) 0);
3272 pline("%s.", IS_GRAVE(lev
->typ
) ? "A grave"
3273 : "Can't place a grave here");
3278 if (!BSTRCMPI(bp
, p
- 4, "tree")) {
3286 if (!BSTRCMPI(bp
, p
- 4, "bars")) {
3287 lev
->typ
= IRONBARS
;
3288 pline("Iron bars.");
3294 if (!oclass
&& !typ
) {
3295 if (!strncmpi(bp
, "polearm", 7)) {
3296 typ
= rnd_otyp_by_wpnskill(P_POLEARMS
);
3298 } else if (!strncmpi(bp
, "hammer", 6)) {
3299 typ
= rnd_otyp_by_wpnskill(P_HAMMER
);
3305 return ((struct obj
*) 0);
3308 oclass
= wrpsym
[rn2((int) sizeof(wrpsym
))];
3311 oclass
= objects
[typ
].oc_class
;
3313 /* handle some objects that are only allowed in wizard mode */
3314 if (typ
&& !wizard
) {
3316 case AMULET_OF_YENDOR
:
3317 typ
= FAKE_AMULET_OF_YENDOR
;
3319 case CANDELABRUM_OF_INVOCATION
:
3320 typ
= rnd_class(TALLOW_CANDLE
, WAX_CANDLE
);
3322 case BELL_OF_OPENING
:
3325 case SPE_BOOK_OF_THE_DEAD
:
3326 typ
= SPE_BLANK_PAPER
;
3332 /* catch any other non-wishable objects (venom) */
3333 if (objects
[typ
].oc_nowish
)
3334 return (struct obj
*) 0;
3340 * Create the object, then fine-tune it.
3342 otmp
= typ
? mksobj(typ
, TRUE
, FALSE
) : mkobj(oclass
, FALSE
);
3343 typ
= otmp
->otyp
, oclass
= otmp
->oclass
; /* what we actually got */
3345 if (islit
&& (typ
== OIL_LAMP
|| typ
== MAGIC_LAMP
|| typ
== BRASS_LANTERN
3346 || Is_candle(otmp
) || typ
== POT_OIL
)) {
3347 place_object(otmp
, u
.ux
, u
.uy
); /* make it viable light source */
3348 begin_burn(otmp
, FALSE
);
3349 obj_extract_self(otmp
); /* now release it for caller's use */
3352 /* if player specified a reasonable count, maybe honor it */
3353 if (cnt
> 0 && objects
[typ
].oc_merge
3354 && (wizard
|| cnt
< rnd(6) || (cnt
<= 7 && Is_candle(otmp
))
3355 || (cnt
<= 20 && ((oclass
== WEAPON_CLASS
&& is_ammo(otmp
))
3356 || typ
== ROCK
|| is_missile(otmp
)))))
3357 otmp
->quan
= (long) cnt
;
3359 if (oclass
== VENOM_CLASS
)
3364 } else if (wizard
) {
3365 ; /* no alteration to spe */
3366 } else if (oclass
== ARMOR_CLASS
|| oclass
== WEAPON_CLASS
3368 || (oclass
== RING_CLASS
&& objects
[typ
].oc_charged
)) {
3369 if (spe
> rnd(5) && spe
> otmp
->spe
)
3371 if (spe
> 2 && Luck
< 0)
3374 if (oclass
== WAND_CLASS
) {
3375 if (spe
> 1 && spesgn
== -1)
3378 if (spe
> 0 && spesgn
== -1)
3381 if (spe
> otmp
->spe
)
3388 /* set otmp->spe. This may, or may not, use spe... */
3391 if (contents
== EMPTY
) {
3392 otmp
->corpsenm
= NON_PM
;
3394 } else if (contents
== SPINACH
) {
3395 otmp
->corpsenm
= NON_PM
;
3401 otmp
->spe
= wetness
;
3409 case HEAVY_IRON_BALL
:
3412 /* otmp->cobj already done in mksobj() */
3416 /* 0: delivered in-game via external event (or randomly for fake mail);
3417 1: from bones or wishing; 2: written with marker */
3423 otmp
->spe
= (rn2(10) ? -1 : 0);
3426 /* fall through, if wizard */
3431 /* set otmp->corpsenm or dragon scale [mail] */
3432 if (mntmp
>= LOW_PM
) {
3433 if (mntmp
== PM_LONG_WORM_TAIL
)
3434 mntmp
= PM_LONG_WORM
;
3438 otmp
->spe
= 0; /* No spinach */
3439 if (dead_species(mntmp
, FALSE
)) {
3440 otmp
->corpsenm
= NON_PM
; /* it's empty */
3441 } else if (!(mons
[mntmp
].geno
& G_UNIQ
)
3442 && !(mvitals
[mntmp
].mvflags
& G_NOCORPSE
)
3443 && mons
[mntmp
].cnutrit
!= 0) {
3444 otmp
->corpsenm
= mntmp
;
3448 if (!(mons
[mntmp
].geno
& G_UNIQ
)
3449 && !(mvitals
[mntmp
].mvflags
& G_NOCORPSE
)) {
3450 if (mons
[mntmp
].msound
== MS_GUARDIAN
)
3451 mntmp
= genus(mntmp
, 1);
3452 set_corpsenm(otmp
, mntmp
);
3456 if (!(mons
[mntmp
].geno
& G_UNIQ
) && !is_human(&mons
[mntmp
])
3458 && mntmp
!= PM_MAIL_DAEMON
3461 otmp
->corpsenm
= mntmp
;
3464 mntmp
= can_be_hatched(mntmp
);
3465 /* this also sets hatch timer if appropriate */
3466 set_corpsenm(otmp
, mntmp
);
3469 otmp
->corpsenm
= mntmp
;
3470 if (Has_contents(otmp
) && verysmall(&mons
[mntmp
]))
3471 delete_contents(otmp
); /* no spellbook */
3472 otmp
->spe
= ishistoric
? STATUE_HISTORIC
: 0;
3475 /* Dragon mail - depends on the order of objects & dragons. */
3476 if (mntmp
>= PM_GRAY_DRAGON
&& mntmp
<= PM_YELLOW_DRAGON
)
3477 otmp
->otyp
= GRAY_DRAGON_SCALE_MAIL
+ mntmp
- PM_GRAY_DRAGON
;
3482 /* set blessed/cursed -- setting the fields directly is safe
3483 * since weight() is called below and addinv() will take care
3487 } else if (uncursed
) {
3489 otmp
->cursed
= (Luck
< 0 && !wizard
);
3490 } else if (blessed
) {
3491 otmp
->blessed
= (Luck
>= 0 || wizard
);
3492 otmp
->cursed
= (Luck
< 0 && !wizard
);
3493 } else if (spesgn
< 0) {
3497 /* set eroded and erodeproof */
3498 if (erosion_matters(otmp
)) {
3499 if (eroded
&& (is_flammable(otmp
) || is_rustprone(otmp
)))
3500 otmp
->oeroded
= eroded
;
3501 if (eroded2
&& (is_corrodeable(otmp
) || is_rottable(otmp
)))
3502 otmp
->oeroded2
= eroded2
;
3504 * 3.6.1: earlier versions included `&& !eroded && !eroded2' here,
3505 * but damageproof combined with damaged is feasible (eroded
3506 * armor modified by confused reading of cursed destroy armor)
3507 * so don't prevent player from wishing for such a combination.
3509 if (erodeproof
&& (is_damageable(otmp
) || otmp
->otyp
== CRYSKNIFE
))
3510 otmp
->oerodeproof
= (Luck
>= 0 || wizard
);
3513 /* set otmp->recharged */
3514 if (oclass
== WAND_CLASS
) {
3515 /* prevent wishing abuse */
3516 if (otmp
->otyp
== WAN_WISHING
&& !wizard
)
3518 otmp
->recharged
= (unsigned) rechrg
;
3523 if (is_poisonable(otmp
))
3524 otmp
->opoisoned
= (Luck
>= 0);
3525 else if (oclass
== FOOD_CLASS
)
3526 /* try to taint by making it as old as possible */
3529 /* and [un]trapped */
3531 if (Is_box(otmp
) || typ
== TIN
)
3532 otmp
->otrapped
= (trapped
== 1);
3538 if (isdiluted
&& otmp
->oclass
== POTION_CLASS
&& otmp
->otyp
!= POT_WATER
)
3541 /* set tin variety */
3542 if (otmp
->otyp
== TIN
&& tvariety
>= 0 && (rn2(4) || wizard
))
3543 set_tin_variety(otmp
, tvariety
);
3549 /* an artifact name might need capitalization fixing */
3550 aname
= artifact_name(name
, &objtyp
);
3551 if (aname
&& objtyp
== otmp
->otyp
)
3554 /* 3.6 tribute - fix up novel */
3555 if (otmp
->otyp
== SPE_NOVEL
) {
3556 const char *novelname
;
3558 novelname
= lookup_novel(name
, &otmp
->novelidx
);
3563 otmp
= oname(otmp
, name
);
3564 if (otmp
->oartifact
) {
3566 u
.uconduct
.wisharti
++; /* KMH, conduct */
3570 /* more wishing abuse: don't allow wishing for certain artifacts */
3571 /* and make them pay; charge them for the wish anyway! */
3572 if ((is_quest_artifact(otmp
)
3573 || (otmp
->oartifact
&& rn2(nartifact_exist()) > 1)) && !wizard
) {
3574 artifact_exists(otmp
, safe_oname(otmp
), FALSE
);
3575 obfree(otmp
, (struct obj
*) 0);
3577 pline("For a moment, you feel %s in your %s, but it disappears!",
3578 something
, makeplural(body_part(HAND
)));
3581 if (halfeaten
&& otmp
->oclass
== FOOD_CLASS
) {
3582 if (otmp
->otyp
== CORPSE
)
3583 otmp
->oeaten
= mons
[otmp
->corpsenm
].cnutrit
;
3585 otmp
->oeaten
= objects
[otmp
->otyp
].oc_nutrition
;
3586 /* (do this adjustment before setting up object's weight) */
3587 consume_oeaten(otmp
, 1);
3589 otmp
->owt
= weight(otmp
);
3590 if (very
&& otmp
->otyp
== HEAVY_IRON_BALL
)
3591 otmp
->owt
+= IRON_BALL_W_INCR
;
3597 rnd_class(first
, last
)
3604 for (i
= first
; i
<= last
; i
++)
3605 sum
+= objects
[i
].oc_prob
;
3606 if (!sum
) /* all zero */
3607 return first
+ rn2(last
- first
+ 1);
3609 for (i
= first
; i
<= last
; i
++)
3610 if (objects
[i
].oc_prob
&& (x
-= objects
[i
].oc_prob
) <= 0)
3615 STATIC_OVL
const char *
3616 Japanese_item_name(i
)
3619 struct Jitem
*j
= Japanese_items
;
3626 return (const char *) 0;
3630 suit_simple_name(suit
)
3633 const char *suitnm
, *esuitp
;
3635 if (Is_dragon_mail(suit
))
3636 return "dragon mail"; /* <color> dragon scale mail */
3637 else if (Is_dragon_scales(suit
))
3638 return "dragon scales";
3639 suitnm
= OBJ_NAME(objects
[suit
->otyp
]);
3640 esuitp
= eos((char *) suitnm
);
3641 if (strlen(suitnm
) > 5 && !strcmp(esuitp
- 5, " mail"))
3642 return "mail"; /* most suits fall into this category */
3643 else if (strlen(suitnm
) > 7 && !strcmp(esuitp
- 7, " jacket"))
3644 return "jacket"; /* leather jacket */
3645 /* suit is lame but armor is ambiguous and body armor is absurd */
3650 cloak_simple_name(cloak
)
3654 switch (cloak
->otyp
) {
3657 case MUMMY_WRAPPING
:
3660 return (objects
[cloak
->otyp
].oc_name_known
&& cloak
->dknown
)
3670 /* helm vs hat for messages */
3672 helm_simple_name(helmet
)
3676 * There is some wiggle room here; the result has been chosen
3677 * for consistency with the "protected by hard helmet" messages
3678 * given for various bonks on the head: headgear that provides
3679 * such protection is a "helm", that which doesn't is a "hat".
3681 * elven leather helm / leather hat -> hat
3682 * dwarvish iron helm / hard hat -> helm
3683 * The rest are completely straightforward:
3684 * fedora, cornuthaum, dunce cap -> hat
3685 * all other types of helmets -> helm
3687 return (helmet
&& !is_metallic(helmet
)) ? "hat" : "helm";
3691 mimic_obj_name(mtmp
)
3694 if (mtmp
->m_ap_type
== M_AP_OBJECT
) {
3695 if (mtmp
->mappearance
== GOLD_PIECE
)
3697 if (mtmp
->mappearance
!= STRANGE_OBJECT
)
3698 return simple_typename(mtmp
->mappearance
);
3700 return "whatcha-may-callit";
3704 * Construct a query prompt string, based around an object name, which is
3705 * guaranteed to fit within [QBUFSZ]. Takes an optional prefix, three
3706 * choices for filling in the middle (two object formatting functions and a
3707 * last resort literal which should be very short), and an optional suffix.
3710 safe_qbuf(qbuf
, qprefix
, qsuffix
, obj
, func
, altfunc
, lastR
)
3711 char *qbuf
; /* output buffer */
3712 const char *qprefix
, *qsuffix
;
3714 char *FDECL((*func
), (OBJ_P
)), *FDECL((*altfunc
), (OBJ_P
));
3718 /* convert size_t (or int for ancient systems) to ordinary unsigned */
3719 unsigned len
, lenlimit
,
3720 len_qpfx
= (unsigned) (qprefix
? strlen(qprefix
) : 0),
3721 len_qsfx
= (unsigned) (qsuffix
? strlen(qsuffix
) : 0),
3722 len_lastR
= (unsigned) strlen(lastR
);
3724 lenlimit
= QBUFSZ
- 1;
3725 endp
= qbuf
+ lenlimit
;
3726 /* sanity check, aimed mainly at paniclog (it's conceivable for
3727 the result of short_oname() to be shorter than the length of
3728 the last resort string, but we ignore that possibility here) */
3729 if (len_qpfx
> lenlimit
)
3730 impossible("safe_qbuf: prefix too long (%u characters).", len_qpfx
);
3731 else if (len_qpfx
+ len_qsfx
> lenlimit
)
3732 impossible("safe_qbuf: suffix too long (%u + %u characters).",
3733 len_qpfx
, len_qsfx
);
3734 else if (len_qpfx
+ len_lastR
+ len_qsfx
> lenlimit
)
3735 impossible("safe_qbuf: filler too long (%u + %u + %u characters).",
3736 len_qpfx
, len_lastR
, len_qsfx
);
3738 /* the output buffer might be the same as the prefix if caller
3739 has already partially filled it */
3740 if (qbuf
== qprefix
) {
3741 /* prefix is already in the buffer */
3743 } else if (qprefix
) {
3744 /* put prefix into the buffer */
3745 (void) strncpy(qbuf
, qprefix
, lenlimit
);
3748 /* no prefix; output buffer starts out empty */
3751 len
= (unsigned) strlen(qbuf
);
3753 if (len
+ len_lastR
+ len_qsfx
> lenlimit
) {
3754 /* too long; skip formatting, last resort output is truncated */
3755 if (len
< lenlimit
) {
3756 (void) strncpy(&qbuf
[len
], lastR
, lenlimit
- len
);
3758 len
= (unsigned) strlen(qbuf
);
3759 if (qsuffix
&& len
< lenlimit
) {
3760 (void) strncpy(&qbuf
[len
], qsuffix
, lenlimit
- len
);
3762 /* len = (unsigned) strlen(qbuf); */
3766 /* suffix and last resort are guaranteed to fit */
3767 len
+= len_qsfx
; /* include the pending suffix */
3768 /* format the object */
3769 bufp
= short_oname(obj
, func
, altfunc
, lenlimit
- len
);
3770 if (len
+ strlen(bufp
) <= lenlimit
)
3771 Strcat(qbuf
, bufp
); /* formatted name fits */
3773 Strcat(qbuf
, lastR
); /* use last resort */
3777 Strcat(qbuf
, qsuffix
);
3779 /* assert( strlen(qbuf) < QBUFSZ ); */