1 /* SCCS Id: @(#)objnam.c 3.3 2000/07/23 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "hack.h"
6
7 /* "an uncursed greased partly eaten guardian naga hatchling [corpse]" */
8 #define PREFIX 80 /* (56) */
9 #define SCHAR_LIM 127
10
11 STATIC_DCL char *FDECL(strprepend,(char *,const char *));
12 #ifdef OVL0
13 static boolean FDECL(the_unique_obj, (struct obj *obj));
14 #endif
15 #ifdef OVLB
16 static boolean FDECL(wishymatch, (const char *,const char *,BOOLEAN_P));
17 #endif
18
19 struct Jitem {
20 int item;
21 const char *name;
22 };
23
24 /* true for gems/rocks that should have " stone" appended to their names */
25 #define GemStone(typ) (typ == FLINT || \
26 (objects[typ].oc_material == GEMSTONE && \
27 (typ != DILITHIUM_CRYSTAL && typ != RUBY && \
28 typ != DIAMOND && typ != SAPPHIRE && \
29 typ != BLACK_OPAL && \
30 typ != EMERALD && typ != OPAL)))
31
32 #ifndef OVLB
33
34 STATIC_DCL struct Jitem Japanese_items[];
35
36 #else /* OVLB */
37
38 STATIC_OVL struct Jitem Japanese_items[] = {
39 { SHORT_SWORD, "wakizashi" },
40 { BROADSWORD, "ninja-to" },
41 { FLAIL, "nunchaku" },
42 { GLAIVE, "naginata" },
43 { LOCK_PICK, "osaku" },
44 { WOODEN_HARP, "koto" },
45 { KNIFE, "shito" },
46 { PLATE_MAIL, "tanko" },
47 { HELMET, "kabuto" },
48 { LEATHER_GLOVES, "yugake" },
49 { FOOD_RATION, "gunyoki" },
50 { KELP_FROND, "nori" },
51 { POT_BOOZE, "sake" },
52 {0, "" }
53 };
54
55 #endif /* OVLB */
56
57 STATIC_DCL const char *FDECL(Japanese_item_name,(int i));
58
59 #ifdef OVL1
60
61 STATIC_OVL char *
strprepend(s,pref)62 strprepend(s,pref)
63 register char *s;
64 register const char *pref;
65 {
66 register int i = (int)strlen(pref);
67
68 if(i > PREFIX) {
69 impossible("PREFIX too short (for %d).", i);
70 return(s);
71 }
72 s -= i;
73 (void) strncpy(s, pref, i); /* do not copy trailing 0 */
74 return(s);
75 }
76
77 #endif /* OVL1 */
78 #ifdef OVLB
79
80 char *
obj_typename(otyp)81 obj_typename(otyp)
82 register int otyp;
83 {
84 #ifdef LINT /* static char buf[BUFSZ]; */
85 char buf[BUFSZ];
86 #else
87 static char NEARDATA buf[BUFSZ];
88 #endif
89 register struct objclass *ocl = &objects[otyp];
90 register const char *actualn = OBJ_NAME(*ocl);
91 register const char *dn = OBJ_DESCR(*ocl);
92 register const char *un = ocl->oc_uname;
93 register int nn = ocl->oc_name_known;
94
95
96 if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
97 actualn = Japanese_item_name(otyp);
98 switch(ocl->oc_class) {
99 case GOLD_CLASS:
100 Strcpy(buf, "coin");
101 break;
102 case POTION_CLASS:
103 Strcpy(buf, "potion");
104 break;
105 case SCROLL_CLASS:
106 Strcpy(buf, "scroll");
107 break;
108 case WAND_CLASS:
109 Strcpy(buf, "wand");
110 break;
111 case SPBOOK_CLASS:
112 Strcpy(buf, "spellbook");
113 break;
114 case RING_CLASS:
115 Strcpy(buf, "ring");
116 break;
117 case AMULET_CLASS:
118 if(nn)
119 Strcpy(buf,actualn);
120 else
121 Strcpy(buf,"amulet");
122 if(un)
123 Sprintf(eos(buf)," called %s",un);
124 if(dn)
125 Sprintf(eos(buf)," (%s)",dn);
126 return(buf);
127 default:
128 if(nn) {
129 Strcpy(buf, actualn);
130 if (GemStone(otyp))
131 Strcat(buf, " stone");
132 if(un)
133 Sprintf(eos(buf), " called %s", un);
134 if(dn)
135 Sprintf(eos(buf), " (%s)", dn);
136 } else {
137 Strcpy(buf, dn ? dn : actualn);
138 if(ocl->oc_class == GEM_CLASS)
139 Strcat(buf, (ocl->oc_material == MINERAL) ?
140 " stone" : " gem");
141 if(un)
142 Sprintf(eos(buf), " called %s", un);
143 }
144 return(buf);
145 }
146 /* here for ring/scroll/potion/wand */
147 if(nn)
148 Sprintf(eos(buf), " of %s", actualn);
149 if(un)
150 Sprintf(eos(buf), " called %s", un);
151 if(dn)
152 Sprintf(eos(buf), " (%s)", dn);
153 return(buf);
154 }
155
156 /* less verbose result than obj_typename(); either the actual name
157 or the description (but not both); user-assigned name is ignored */
158 char *
simple_typename(otyp)159 simple_typename(otyp)
160 int otyp;
161 {
162 char *bufp, *pp, *save_uname = objects[otyp].oc_uname;
163
164 objects[otyp].oc_uname = 0; /* suppress any name given by user */
165 bufp = obj_typename(otyp);
166 objects[otyp].oc_uname = save_uname;
167 if ((pp = strstri(bufp, " (")) != 0)
168 *pp = '\0'; /* strip the appended description */
169 return bufp;
170 }
171
172 boolean
obj_is_pname(obj)173 obj_is_pname(obj)
174 register struct obj *obj;
175 {
176 return((boolean)(obj->dknown && obj->known && obj->onamelth &&
177 /* Since there aren't any objects which are both
178 artifacts and unique, the last check is redundant. */
179 obj->oartifact && !objects[obj->otyp].oc_unique));
180 }
181
182 /* Give the name of an object seen at a distance. Unlike xname/doname,
183 * we don't want to set dknown if it's not set already. The kludge used is
184 * to temporarily set Blind so that xname() skips the dknown setting. This
185 * assumes that we don't want to do this too often; if this function becomes
186 * frequently used, it'd probably be better to pass a parameter to xname()
187 * or doname() instead.
188 */
189 char *
distant_name(obj,func)190 distant_name(obj, func)
191 register struct obj *obj;
192 char *FDECL((*func), (OBJ_P));
193 {
194 char *str;
195
196 long save_Blinded = Blinded;
197 Blinded = 1;
198 str = (*func)(obj);
199 Blinded = save_Blinded;
200 return str;
201 }
202
203 #endif /* OVLB */
204 #ifdef OVL1
205
206 char *
xname(obj)207 xname(obj)
208 register struct obj *obj;
209 {
210 #ifdef LINT /* lint may handle static decl poorly -- static char bufr[]; */
211 char bufr[BUFSZ];
212 #else
213 static char bufr[BUFSZ];
214 #endif
215 register char *buf = &(bufr[PREFIX]); /* leave room for "17 -3 " */
216 register int typ = obj->otyp;
217 register struct objclass *ocl = &objects[typ];
218 register int nn = ocl->oc_name_known;
219 register const char *actualn = OBJ_NAME(*ocl);
220 register const char *dn = OBJ_DESCR(*ocl);
221 register const char *un = ocl->oc_uname;
222
223 if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
224 actualn = Japanese_item_name(typ);
225
226 buf[0] = '\0';
227 if (!Blind) obj->dknown = TRUE;
228 if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
229 if (obj_is_pname(obj))
230 goto nameit;
231 switch (obj->oclass) {
232 case AMULET_CLASS:
233 if (!obj->dknown)
234 Strcpy(buf, "amulet");
235 else if (typ == AMULET_OF_YENDOR ||
236 typ == FAKE_AMULET_OF_YENDOR)
237 /* each must be identified individually */
238 Strcpy(buf, obj->known ? actualn : dn);
239 else if (nn)
240 Strcpy(buf, actualn);
241 else if (un)
242 Sprintf(buf,"amulet called %s", un);
243 else
244 Sprintf(buf,"%s amulet", dn);
245 break;
246 case WEAPON_CLASS:
247 if (is_poisonable(obj) && obj->opoisoned)
248 Strcpy(buf, "poisoned ");
249 case VENOM_CLASS:
250 case TOOL_CLASS:
251 if (typ == LENSES)
252 Strcpy(buf, "pair of ");
253
254 if (!obj->dknown)
255 Strcat(buf, dn ? dn : actualn);
256 else if (nn)
257 Strcat(buf, actualn);
258 else if (un) {
259 Strcat(buf, dn ? dn : actualn);
260 Strcat(buf, " called ");
261 Strcat(buf, un);
262 } else
263 Strcat(buf, dn ? dn : actualn);
264 /* If we use an() here we'd have to remember never to use */
265 /* it whenever calling doname() or xname(). */
266 if (typ == FIGURINE)
267 Sprintf(eos(buf), " of a%s %s",
268 index(vowels,*(mons[obj->corpsenm].mname)) ? "n" : "",
269 mons[obj->corpsenm].mname);
270 break;
271 case ARMOR_CLASS:
272 /* depends on order of the dragon scales objects */
273 if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
274 Sprintf(buf, "set of %s", actualn);
275 break;
276 }
277 if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
278
279 if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
280 && !obj->dknown) {
281 Strcpy(buf, "shield");
282 break;
283 }
284 if(obj->otyp == SHIELD_OF_REFLECTION && !obj->dknown) {
285 Strcpy(buf, "smooth shield");
286 break;
287 }
288
289 if(nn) Strcat(buf, actualn);
290 else if(un) {
291 if(is_boots(obj))
292 Strcat(buf,"boots");
293 else if(is_gloves(obj))
294 Strcat(buf,"gloves");
295 else if(is_cloak(obj))
296 Strcpy(buf,"cloak");
297 else if(is_helmet(obj))
298 Strcpy(buf,"helmet");
299 else if(is_shield(obj))
300 Strcpy(buf,"shield");
301 else
302 Strcpy(buf,"armor");
303 Strcat(buf, " called ");
304 Strcat(buf, un);
305 } else Strcat(buf, dn);
306 break;
307 case FOOD_CLASS:
308 if (typ == SLIME_MOLD) {
309 register struct fruit *f;
310
311 for(f=ffruit; f; f = f->nextf) {
312 if(f->fid == obj->spe) {
313 Strcpy(buf, f->fname);
314 break;
315 }
316 }
317 if (!f) impossible("Bad fruit #%d?", obj->spe);
318 break;
319 }
320
321 Strcpy(buf, actualn);
322 if (typ == TIN && obj->known) {
323 if(obj->spe > 0)
324 Strcat(buf, " of spinach");
325 else if (obj->corpsenm == NON_PM)
326 Strcpy(buf, "empty tin");
327 else if (vegetarian(&mons[obj->corpsenm]))
328 Sprintf(eos(buf), " of %s", mons[obj->corpsenm].mname);
329 else
330 Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname);
331 }
332 break;
333 case GOLD_CLASS:
334 case CHAIN_CLASS:
335 Strcpy(buf, actualn);
336 break;
337 case ROCK_CLASS:
338 if (typ == STATUE)
339 Sprintf(buf, "%s%s of %s%s",
340 (Role_if(PM_ARCHEOLOGIST) && obj->spe) ? "historic " : "" ,
341 actualn,
342 type_is_pname(&mons[obj->corpsenm]) ? "" :
343 (mons[obj->corpsenm].geno & G_UNIQ) ? "the " :
344 (index(vowels,*(mons[obj->corpsenm].mname)) ?
345 "an " : "a "),
346 mons[obj->corpsenm].mname);
347 else Strcpy(buf, actualn);
348 break;
349 case BALL_CLASS:
350 Sprintf(buf, "%sheavy iron ball",
351 (obj->owt > ocl->oc_weight) ? "very " : "");
352 break;
353 case POTION_CLASS:
354 if (obj->dknown && obj->odiluted)
355 Strcpy(buf, "diluted ");
356 if(nn || un || !obj->dknown) {
357 Strcat(buf, "potion");
358 if(!obj->dknown) break;
359 if(nn) {
360 Strcat(buf, " of ");
361 if (typ == POT_WATER &&
362 obj->bknown && (obj->blessed || obj->cursed)) {
363 Strcat(buf, obj->blessed ? "holy " : "unholy ");
364 }
365 Strcat(buf, actualn);
366 } else {
367 Strcat(buf, " called ");
368 Strcat(buf, un);
369 }
370 } else {
371 Strcat(buf, dn);
372 Strcat(buf, " potion");
373 }
374 break;
375 case SCROLL_CLASS:
376 Strcpy(buf, "scroll");
377 if(!obj->dknown) break;
378 if(nn) {
379 Strcat(buf, " of ");
380 Strcat(buf, actualn);
381 } else if(un) {
382 Strcat(buf, " called ");
383 Strcat(buf, un);
384 } else if (ocl->oc_magic) {
385 Strcat(buf, " labeled ");
386 Strcat(buf, dn);
387 } else {
388 Strcpy(buf, dn);
389 Strcat(buf, " scroll");
390 }
391 break;
392 case WAND_CLASS:
393 if(!obj->dknown)
394 Strcpy(buf, "wand");
395 else if(nn)
396 Sprintf(buf, "wand of %s", actualn);
397 else if(un)
398 Sprintf(buf, "wand called %s", un);
399 else
400 Sprintf(buf, "%s wand", dn);
401 break;
402 case SPBOOK_CLASS:
403 if (!obj->dknown) {
404 Strcpy(buf, "spellbook");
405 } else if (nn) {
406 if (typ != SPE_BOOK_OF_THE_DEAD)
407 Strcpy(buf, "spellbook of ");
408 Strcat(buf, actualn);
409 } else if (un) {
410 Sprintf(buf, "spellbook called %s", un);
411 } else
412 Sprintf(buf, "%s spellbook", dn);
413 break;
414 case RING_CLASS:
415 if(!obj->dknown)
416 Strcpy(buf, "ring");
417 else if(nn)
418 Sprintf(buf, "ring of %s", actualn);
419 else if(un)
420 Sprintf(buf, "ring called %s", un);
421 else
422 Sprintf(buf, "%s ring", dn);
423 break;
424 case GEM_CLASS:
425 {
426 const char *rock =
427 (ocl->oc_material == MINERAL) ? "stone" : "gem";
428 if (!obj->dknown) {
429 Strcpy(buf, rock);
430 } else if (!nn) {
431 if (un) Sprintf(buf,"%s called %s", rock, un);
432 else Sprintf(buf, "%s %s", dn, rock);
433 } else {
434 Strcpy(buf, actualn);
435 if (GemStone(typ)) Strcat(buf, " stone");
436 }
437 break;
438 }
439 default:
440 Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe);
441 }
442 if (obj->quan != 1L) Strcpy(buf, makeplural(buf));
443
444 if (obj->onamelth && obj->dknown) {
445 Strcat(buf, " named ");
446 nameit:
447 Strcat(buf, ONAME(obj));
448 }
449
450 if (!strncmpi(buf, "the ", 4)) buf += 4;
451 return(buf);
452 }
453
454 #endif /* OVL1 */
455 #ifdef OVL0
456
457 /* used for naming "the unique_item" instead of "a unique_item" */
458 static boolean
the_unique_obj(obj)459 the_unique_obj(obj)
460 register struct obj *obj;
461 {
462 if (!obj->dknown)
463 return FALSE;
464 else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known)
465 return TRUE; /* lie */
466 else
467 return (boolean)(objects[obj->otyp].oc_unique &&
468 (obj->known || obj->otyp == AMULET_OF_YENDOR));
469 }
470
471 static void
add_erosion_words(obj,prefix)472 add_erosion_words(obj,prefix)
473 struct obj *obj;
474 char *prefix;
475 {
476 boolean iscrys = (obj->otyp == CRYSKNIFE);
477
478
479 if (!is_damageable(obj) && !iscrys) return;
480
481 /* The only cases where any of these bits do double duty are for
482 * rotted food and diluted potions, which are all not is_damageable().
483 */
484 if (obj->oeroded && !iscrys) {
485 switch (obj->oeroded) {
486 case 2: Strcat(prefix, "very "); break;
487 case 3: Strcat(prefix, "thoroughly "); break;
488 }
489 Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt ");
490 }
491 if (obj->oeroded2 && !iscrys) {
492 switch (obj->oeroded2) {
493 case 2: Strcat(prefix, "very "); break;
494 case 3: Strcat(prefix, "thoroughly "); break;
495 }
496 Strcat(prefix, is_corrodeable(obj) ? "corroded " :
497 "rotted ");
498 }
499 if (obj->rknown && obj->oerodeproof)
500 Strcat(prefix,
501 iscrys ? "fixed " :
502 is_rustprone(obj) ? "rustproof " :
503 is_corrodeable(obj) ? "corrodeproof " : /* "stainless"? */
504 is_flammable(obj) ? "fireproof " : "");
505 }
506
507 char *
doname(obj)508 doname(obj)
509 register struct obj *obj;
510 {
511 boolean ispoisoned = FALSE;
512 char prefix[PREFIX];
513 char tmpbuf[PREFIX+1];
514 /* when we have to add something at the start of prefix instead of the
515 * end (Strcat is used on the end)
516 */
517 register char *bp = xname(obj);
518
519 /* When using xname, we want "poisoned arrow", and when using
520 * doname, we want "poisoned +0 arrow". This kludge is about the only
521 * way to do it, at least until someone overhauls xname() and doname(),
522 * combining both into one function taking a parameter.
523 */
524 /* must check opoisoned--someone can have a weirdly-named fruit */
525 if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
526 bp += 9;
527 ispoisoned = TRUE;
528 }
529
530 if(obj->quan != 1L)
531 Sprintf(prefix, "%ld ", obj->quan);
532 else if (obj_is_pname(obj) || the_unique_obj(obj)) {
533 if (!strncmpi(bp, "the ", 4))
534 bp += 4;
535 Strcpy(prefix, "the ");
536 } else
537 Strcpy(prefix, "a ");
538
539 #ifdef INVISIBLE_OBJECTS
540 if (obj->oinvis) Strcat(prefix,"invisible ");
541 #endif
542
543 if (obj->bknown &&
544 obj->oclass != GOLD_CLASS &&
545 (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
546 || (!obj->cursed && !obj->blessed))) {
547 /* allow 'blessed clear potion' if we don't know it's holy water;
548 * always allow "uncursed potion of water"
549 */
550 if (obj->cursed)
551 Strcat(prefix, "cursed ");
552 else if (obj->blessed)
553 Strcat(prefix, "blessed ");
554 else if ((!obj->known || !objects[obj->otyp].oc_charged ||
555 (obj->oclass == ARMOR_CLASS ||
556 obj->oclass == RING_CLASS))
557 /* For most items with charges or +/-, if you know how many
558 * charges are left or what the +/- is, then you must have
559 * totally identified the item, so "uncursed" is unneccesary,
560 * because an identified object not described as "blessed" or
561 * "cursed" must be uncursed.
562 *
563 * If the charges or +/- is not known, "uncursed" must be
564 * printed to avoid ambiguity between an item whose curse
565 * status is unknown, and an item known to be uncursed.
566 */
567 #ifdef MAIL
568 && obj->otyp != SCR_MAIL
569 #endif
570 && obj->otyp != FAKE_AMULET_OF_YENDOR
571 && obj->otyp != AMULET_OF_YENDOR
572 && !Role_if(PM_PRIEST))
573 Strcat(prefix, "uncursed ");
574 }
575
576 if (obj->greased) Strcat(prefix, "greased ");
577
578 switch(obj->oclass) {
579 case AMULET_CLASS:
580 if(obj->owornmask & W_AMUL)
581 Strcat(bp, " (being worn)");
582 break;
583 case WEAPON_CLASS:
584 if(ispoisoned)
585 Strcat(prefix, "poisoned ");
586 plus:
587 add_erosion_words(obj, prefix);
588 if(obj->known) {
589 Strcat(prefix, sitoa(obj->spe));
590 Strcat(prefix, " ");
591 }
592 break;
593 case ARMOR_CLASS:
594 if(obj->owornmask & W_ARMOR)
595 Strcat(bp, (obj == uskin) ? " (embedded in your skin)" :
596 " (being worn)");
597 goto plus;
598 case TOOL_CLASS:
599 /* weptools already get this done when we go to the +n code */
600 if (!is_weptool(obj))
601 add_erosion_words(obj, prefix);
602 if(obj->owornmask & (W_TOOL /* blindfold */
603 #ifdef STEED
604 | W_SADDLE
605 #endif
606 )) {
607 Strcat(bp, " (being worn)");
608 break;
609 }
610 if (obj->otyp == LEASH && obj->leashmon != 0) {
611 Strcat(bp, " (in use)");
612 break;
613 }
614 if (is_weptool(obj))
615 goto plus;
616 if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
617 if (!obj->spe)
618 Strcpy(tmpbuf, "no");
619 else
620 Sprintf(tmpbuf, "%d", obj->spe);
621 Sprintf(eos(bp), " (%s candle%s%s)",
622 tmpbuf, plur(obj->spe),
623 !obj->lamplit ? " attached" : ", lit");
624 break;
625 } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
626 obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
627 if (Is_candle(obj) &&
628 obj->age < 20L * (long)objects[obj->otyp].oc_cost)
629 Strcat(prefix, "partly used ");
630 if(obj->lamplit)
631 Strcat(bp, " (lit)");
632 break;
633 }
634 if(objects[obj->otyp].oc_charged)
635 goto charges;
636 break;
637 case WAND_CLASS:
638 add_erosion_words(obj, prefix);
639 charges:
640 if(obj->known)
641 Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe);
642 break;
643 case POTION_CLASS:
644 if (obj->otyp == POT_OIL && obj->lamplit)
645 Strcat(bp, " (lit)");
646 break;
647 case RING_CLASS:
648 add_erosion_words(obj, prefix);
649 ring:
650 if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
651 if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
652 if(obj->owornmask & W_RING) {
653 Strcat(bp, body_part(HAND));
654 Strcat(bp, ")");
655 }
656 if(obj->known && objects[obj->otyp].oc_charged) {
657 Strcat(prefix, sitoa(obj->spe));
658 Strcat(prefix, " ");
659 }
660 break;
661 case FOOD_CLASS:
662 if (obj->oeaten)
663 Strcat(prefix, "partly eaten ");
664 if (obj->otyp == CORPSE) {
665 if (mons[obj->corpsenm].geno & G_UNIQ) {
666 Sprintf(prefix, "%s%s ",
667 (type_is_pname(&mons[obj->corpsenm]) ?
668 "" : "the "),
669 s_suffix(mons[obj->corpsenm].mname));
670 if (obj->oeaten) Strcat(prefix, "partly eaten ");
671 } else {
672 Strcat(prefix, mons[obj->corpsenm].mname);
673 Strcat(prefix, " ");
674 }
675 } else if (obj->otyp == EGG) {
676 #if 0 /* corpses don't tell if they're stale either */
677 if (obj->known && stale_egg(obj))
678 Strcat(prefix, "stale ");
679 #endif
680 if (obj->corpsenm >= LOW_PM &&
681 (obj->known ||
682 mvitals[obj->corpsenm].mvflags & MV_KNOWS_EGG)) {
683 Strcat(prefix, mons[obj->corpsenm].mname);
684 Strcat(prefix, " ");
685 if (obj->spe)
686 Strcat(bp, " (laid by you)");
687 }
688 }
689 if (obj->otyp == MEAT_RING) goto ring;
690 break;
691 case BALL_CLASS:
692 case CHAIN_CLASS:
693 add_erosion_words(obj, prefix);
694 if(obj->owornmask & W_BALL)
695 Strcat(bp, " (chained to you)");
696 break;
697 }
698
699 if((obj->owornmask & W_WEP) && !mrg_to_wielded) {
700 if (obj->quan != 1L) {
701 Strcat(bp, " (wielded)");
702 } else {
703 const char *hand_s = body_part(HAND);
704
705 if (bimanual(obj)) hand_s = makeplural(hand_s);
706 Sprintf(eos(bp), " (weapon in %s)", hand_s);
707 }
708 }
709 if(obj->owornmask & W_SWAPWEP) {
710 if (u.twoweap)
711 Sprintf(eos(bp), " (wielded in other %s)",
712 body_part(HAND));
713 else
714 Strcat(bp, " (alternate weapon; not wielded)");
715 }
716 if(obj->owornmask & W_QUIVER) Strcat(bp, " (in quiver)");
717 if(obj->unpaid)
718 Strcat(bp, " (unpaid)");
719 if (!strncmp(prefix, "a ", 2) &&
720 index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
721 && (*(prefix+2) || (strncmp(bp, "uranium", 7)
722 && strncmp(bp, "unicorn", 7)
723 && strncmp(bp, "eucalyptus", 10)))) {
724 Strcpy(tmpbuf, prefix);
725 Strcpy(prefix, "an ");
726 Strcpy(prefix+3, tmpbuf+2);
727 }
728 bp = strprepend(bp, prefix);
729 return(bp);
730 }
731
732 #endif /* OVL0 */
733 #ifdef OVLB
734
735 /* used from invent.c */
736 boolean
not_fully_identified(otmp)737 not_fully_identified(otmp)
738 register struct obj *otmp;
739 {
740 /* check fundamental ID hallmarks first */
741 if (!otmp->known || !otmp->dknown ||
742 #ifdef MAIL
743 (!otmp->bknown && otmp->otyp != SCR_MAIL) ||
744 #else
745 !otmp->bknown ||
746 #endif
747 !objects[otmp->otyp].oc_name_known) /* ?redundant? */
748 return TRUE;
749 if (otmp->oartifact && undiscovered_artifact(otmp->oartifact))
750 return TRUE;
751 /* otmp->rknown is the only item of interest if we reach here */
752 /*
753 * Note: if a revision ever allows scrolls to become fireproof or
754 * rings to become shockproof, this checking will need to be revised.
755 * `rknown' ID only matters if xname() will provide the info about it.
756 */
757 if (otmp->rknown || (otmp->oclass != ARMOR_CLASS &&
758 otmp->oclass != WEAPON_CLASS &&
759 !is_weptool(otmp) && /* (redunant) */
760 otmp->oclass != BALL_CLASS)) /* (useless) */
761 return FALSE;
762 else /* lack of `rknown' only matters for vulnerable objects */
763 return (boolean)(is_rustprone(otmp) ||
764 is_corrodeable(otmp) ||
765 is_flammable(otmp));
766 }
767
768 /* The result is actually modifiable, but caller shouldn't rely on that
769 * due to the small buffer size.
770 */
771 const char *
corpse_xname(otmp,ignore_oquan)772 corpse_xname(otmp, ignore_oquan)
773 struct obj *otmp;
774 boolean ignore_oquan; /* to force singular */
775 {
776 static char NEARDATA nambuf[40];
777
778 /* assert( strlen(mons[otmp->corpsenm].mname) <= 32 ); */
779 Sprintf(nambuf, "%s corpse", mons[otmp->corpsenm].mname);
780
781 if (ignore_oquan || otmp->quan < 2)
782 return nambuf;
783 else
784 return makeplural(nambuf);
785 }
786
787 /*
788 * Used if only one of a collection of objects is named (e.g. in eat.c).
789 */
790 const char *
singular(otmp,func)791 singular(otmp, func)
792 register struct obj *otmp;
793 char *FDECL((*func), (OBJ_P));
794 {
795 long savequan;
796 char *nam;
797
798 /* Note: using xname for corpses will not give the monster type */
799 if (otmp->otyp == CORPSE && func == xname)
800 return corpse_xname(otmp, TRUE);
801
802 savequan = otmp->quan;
803 otmp->quan = 1L;
804 nam = (*func)(otmp);
805 otmp->quan = savequan;
806 return nam;
807 }
808
809 char *
an(str)810 an(str)
811 register const char *str;
812 {
813 static char NEARDATA buf[BUFSZ];
814
815 buf[0] = '\0';
816
817 if (strncmpi(str, "the ", 4) &&
818 strcmp(str, "molten lava") &&
819 strcmp(str, "iron bars") &&
820 strcmp(str, "ice")) {
821 if (index(vowels, *str) &&
822 strncmp(str, "useful", 6) &&
823 strncmp(str, "unicorn", 7) &&
824 strncmp(str, "uranium", 7) &&
825 strncmp(str, "eucalyptus", 10))
826 Strcpy(buf, "an ");
827 else
828 Strcpy(buf, "a ");
829 }
830
831 Strcat(buf, str);
832 return buf;
833 }
834
835 char *
An(str)836 An(str)
837 const char *str;
838 {
839 register char *tmp = an(str);
840 *tmp = highc(*tmp);
841 return tmp;
842 }
843
844 /*
845 * Prepend "the" if necessary; assumes str is a subject derived from xname.
846 * Use type_is_pname() for monster names, not the(). the() is idempotent.
847 */
848 char *
the(str)849 the(str)
850 const char *str;
851 {
852 static char NEARDATA buf[BUFSZ];
853 boolean insert_the = FALSE;
854
855 if (!strncmpi(str, "the ", 4)) {
856 buf[0] = lowc(*str);
857 Strcpy(&buf[1], str+1);
858 return buf;
859 } else if (*str < 'A' || *str > 'Z') {
860 /* not a proper name, needs an article */
861 insert_the = TRUE;
862 } else {
863 /* Probably a proper name, might not need an article */
864 register char *tmp, *named, *called;
865 int l;
866
867 /* some objects have capitalized adjectives in their names */
868 if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) &&
869 (tmp[1] < 'A' || tmp[1] > 'Z'))
870 insert_the = TRUE;
871 else if (tmp && index(str, ' ') < tmp) { /* has spaces */
872 /* it needs an article if the name contains "of" */
873 tmp = strstri(str, " of ");
874 named = strstri(str, " named ");
875 called = strstri(str, " called ");
876 if (called && (!named || called < named)) named = called;
877
878 if (tmp && (!named || tmp < named)) /* found an "of" */
879 insert_the = TRUE;
880 /* stupid special case: lacks "of" but needs "the" */
881 else if (!named && (l = strlen(str)) >= 31 &&
882 !strcmp(&str[l - 31], "Platinum Yendorian Express Card"))
883 insert_the = TRUE;
884 }
885 }
886 if (insert_the)
887 Strcpy(buf, "the ");
888 else
889 buf[0] = '\0';
890 Strcat(buf, str);
891
892 return buf;
893 }
894
895 char *
The(str)896 The(str)
897 const char *str;
898 {
899 register char *tmp = the(str);
900 *tmp = highc(*tmp);
901 return tmp;
902 }
903
904 char *
aobjnam(otmp,verb)905 aobjnam(otmp,verb)
906 register struct obj *otmp;
907 register const char *verb;
908 {
909 register char *bp = xname(otmp);
910 char prefix[PREFIX];
911
912 if(otmp->quan != 1L) {
913 Sprintf(prefix, "%ld ", otmp->quan);
914 bp = strprepend(bp, prefix);
915 }
916
917 if(verb) {
918 /* verb is given in plural (without trailing s) */
919 Strcat(bp, " ");
920 if(otmp->quan != 1L)
921 Strcat(bp, verb);
922 else if(!strcmp(verb, "are"))
923 Strcat(bp, "is");
924 else {
925 Strcat(bp, verb);
926 Strcat(bp, "s");
927 }
928 }
929 return(bp);
930 }
931
932 /* capitalized variant of doname() */
933 char *
Doname2(obj)934 Doname2(obj)
935 register struct obj *obj;
936 {
937 register char *s = doname(obj);
938
939 *s = highc(*s);
940 return(s);
941 }
942
943 /* returns "your xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */
944 char *
yname(obj)945 yname(obj)
946 struct obj *obj;
947 {
948 static char outbuf[BUFSZ];
949 char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */
950 int space_left = sizeof outbuf - strlen(s) - sizeof " ";
951
952 return strncat(strcat(s, " "), xname(obj), space_left);
953 }
954
955 /* capitalized variant of yname() */
956 char *
Yname2(obj)957 Yname2(obj)
958 struct obj *obj;
959 {
960 char *s = yname(obj);
961
962 *s = highc(*s);
963 return s;
964 }
965
966 static const char *wrp[] = {
967 "wand", "ring", "potion", "scroll", "gem", "amulet",
968 "spellbook", "spell book",
969 /* for non-specific wishes */
970 "weapon", "armor", "armour", "tool", "food", "comestible",
971 };
972 static const char wrpsym[] = {
973 WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS,
974 AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS,
975 WEAPON_CLASS, ARMOR_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS,
976 FOOD_CLASS
977 };
978
979 #endif /* OVLB */
980 #ifdef OVL0
981
982 /* Plural routine; chiefly used for user-defined fruits. We have to try to
983 * account for everything reasonable the player has; something unreasonable
984 * can still break the code. However, it's still a lot more accurate than
985 * "just add an s at the end", which Rogue uses...
986 *
987 * Also used for plural monster names ("Wiped out all homunculi.")
988 * and body parts.
989 *
990 * Also misused by muse.c to convert 1st person present verbs to 2nd person.
991 */
992 char *
makeplural(oldstr)993 makeplural(oldstr)
994 const char *oldstr;
995 {
996 /* Note: cannot use strcmpi here -- it'd give MATZot, CAVEMeN,... */
997 register char *spot;
998 static char NEARDATA str[BUFSZ];
999 const char *excess = (char *)0;
1000 int len;
1001
1002 while (*oldstr==' ') oldstr++;
1003 if (!oldstr || !*oldstr) {
1004 impossible("plural of null?");
1005 Strcpy(str, "s");
1006 return str;
1007 }
1008 Strcpy(str, oldstr);
1009
1010 /*
1011 Skip changing "pair of" to "pairs of". According to Webster, usual
1012 English usage is use pairs for humans, e.g. 3 pairs of dancers,
1013 and pair for objects and non-humans, e.g. 3 pair of boots. We don't
1014 refer to pairs of humans in this game so just skip to the bottom.
1015
1016 Actually, none of the "pair" objects -- gloves, boots, and lenses --
1017 currently merge, so this isn't used.
1018 */
1019 if (!strncmp(str, "pair of ", 8))
1020 goto bottom;
1021
1022 /* Search for common compounds, ex. lump of royal jelly */
1023 for(spot=str; *spot; spot++) {
1024 if (!strncmp(spot, " of ", 4)
1025 || !strncmp(spot, " labeled ", 9)
1026 || !strncmp(spot, " called ", 8)
1027 || !strncmp(spot, " named ", 7)
1028 || !strcmp(spot, " above") /* lurkers above */
1029 || !strncmp(spot, " versus ", 8)
1030 || !strncmp(spot, " from ", 6)
1031 || !strncmp(spot, " in ", 4)
1032 || !strncmp(spot, " on ", 4)
1033 || !strncmp(spot, " a la ", 6)
1034 || !strncmp(spot, " with", 5) /* " with "? */
1035 || !strncmp(spot, " de ", 4)
1036 || !strncmp(spot, " d'", 3)
1037 || !strncmp(spot, " du ", 4)) {
1038 excess = oldstr + (int) (spot - str);
1039 *spot = 0;
1040 break;
1041 }
1042 }
1043 spot--;
1044 while (*spot==' ') spot--; /* Strip blanks from end */
1045 *(spot+1) = 0;
1046 /* Now spot is the last character of the string */
1047
1048 len = strlen(str);
1049
1050 /* Single letters */
1051 if (len==1 || !letter(*spot)) {
1052 Strcpy(spot+1, "'s");
1053 goto bottom;
1054 }
1055
1056 /* Same singular and plural; mostly Japanese words except for "manes" */
1057 if ((len == 2 && !strcmp(str, "ya")) ||
1058 (len >= 2 && !strcmp(spot-1, "ai")) || /* samurai, Uruk-hai */
1059 (len >= 3 && !strcmp(spot-2, " ya")) ||
1060 (len >= 4 &&
1061 (!strcmp(spot-3, "fish") || !strcmp(spot-3, "tuna") ||
1062 !strcmp(spot-3, "deer") || !strcmp(spot-3, "yaki") ||
1063 !strcmp(spot-3, "nori"))) ||
1064 (len >= 5 && (!strcmp(spot-4, "sheep") ||
1065 !strcmp(spot-4, "ninja") ||
1066 !strcmp(spot-4, "ronin") ||
1067 !strcmp(spot-4, "shito") ||
1068 !strcmp(spot-4, "tengu") ||
1069 !strcmp(spot-4, "manes"))) ||
1070 (len >= 6 && !strcmp(spot-5, "ki-rin")) ||
1071 (len >= 7 && !strcmp(spot-6, "gunyoki")))
1072 goto bottom;
1073
1074 /* man/men ("Wiped out all cavemen.") */
1075 if (len >= 3 && !strcmp(spot-2, "man") &&
1076 (len<6 || strcmp(spot-5, "shaman")) &&
1077 (len<5 || strcmp(spot-4, "human"))) {
1078 *(spot-1) = 'e';
1079 goto bottom;
1080 }
1081
1082 /* tooth/teeth */
1083 if (len >= 5 && !strcmp(spot-4, "tooth")) {
1084 Strcpy(spot-3, "eeth");
1085 goto bottom;
1086 }
1087
1088 /* knife/knives, etc... */
1089 if (!strcmp(spot-1, "fe")) {
1090 Strcpy(spot-1, "ves");
1091 goto bottom;
1092 } else if (*spot == 'f') {
1093 if (index("lr", *(spot-1)) || index(vowels, *(spot-1))) {
1094 Strcpy(spot, "ves");
1095 goto bottom;
1096 } else if (len >= 5 && !strncmp(spot-4, "staf", 4)) {
1097 Strcpy(spot-1, "ves");
1098 goto bottom;
1099 }
1100 }
1101
1102 /* foot/feet (body part) */
1103 if (len >= 4 && !strcmp(spot-3, "foot")) {
1104 Strcpy(spot-2, "eet");
1105 goto bottom;
1106 }
1107
1108 /* ium/ia (mycelia, baluchitheria) */
1109 if (len >= 3 && !strcmp(spot-2, "ium")) {
1110 *(spot--) = (char)0;
1111 *spot = 'a';
1112 goto bottom;
1113 }
1114
1115 /* algae, larvae, hyphae (another fungus part) */
1116 if ((len >= 4 && !strcmp(spot-3, "alga")) ||
1117 (len >= 5 &&
1118 (!strcmp(spot-4, "hypha") || !strcmp(spot-4, "larva")))) {
1119 Strcpy(spot, "ae");
1120 goto bottom;
1121 }
1122
1123 /* fungus/fungi, homunculus/homunculi, but wumpuses */
1124 if (!strcmp(spot-1, "us") && (len < 6 || strcmp(spot-5, "wumpus"))) {
1125 *(spot--) = (char)0;
1126 *spot = 'i';
1127 goto bottom;
1128 }
1129
1130 /* vortex/vortices */
1131 if (len >= 6 && !strcmp(spot-3, "rtex")) {
1132 Strcpy(spot-1, "ices");
1133 goto bottom;
1134 }
1135
1136 /* djinni/djinn (note: also efreeti/efreet) */
1137 if (len >= 6 && !strcmp(spot-5, "djinni")) {
1138 *spot = (char)0;
1139 goto bottom;
1140 }
1141
1142 /* mumak/mumakil */
1143 if (len >= 5 && !strcmp(spot-4, "mumak")) {
1144 Strcpy(spot+1, "il");
1145 goto bottom;
1146 }
1147
1148 /* sis/ses (nemesis) */
1149 if (len >= 3 && !strcmp(spot-2, "sis")) {
1150 *(spot-1) = 'e';
1151 goto bottom;
1152 }
1153
1154 /* erinys/erinyes */
1155 if (len >= 6 && !strcmp(spot-5, "erinys")) {
1156 Strcpy(spot, "es");
1157 goto bottom;
1158 }
1159
1160 /* mouse/mice,louse/lice (not a monster, but possible in food names) */
1161 if (len >= 5 && !strcmp(spot-3, "ouse") && index("MmLl", *(spot-4))) {
1162 Strcpy(spot-3, "ice");
1163 goto bottom;
1164 }
1165
1166 /* matzoh/matzot, possible food name */
1167 if (len >= 6 && (!strcmp(spot-5, "matzoh")
1168 || !strcmp(spot-5, "matzah"))) {
1169 Strcpy(spot-1, "ot");
1170 goto bottom;
1171 }
1172 if (len >= 5 && (!strcmp(spot-4, "matzo")
1173 || !strcmp(spot-5, "matza"))) {
1174 Strcpy(spot, "ot");
1175 goto bottom;
1176 }
1177
1178 /* child/children (for wise guys who give their food funny names) */
1179 if (len >= 5 && !strcmp(spot-4, "child")) {
1180 Strcpy(spot, "dren");
1181 goto bottom;
1182 }
1183
1184 /* note: -eau/-eaux (gateau, bordeau...) */
1185 /* note: ox/oxen, VAX/VAXen, goose/geese */
1186
1187 /* Ends in z, x, s, ch, sh; add an "es" */
1188 if (index("zxs", *spot)
1189 || (len >= 2 && *spot=='h' && index("cs", *(spot-1)))
1190 /* Kludge to get "tomatoes" and "potatoes" right */
1191 || (len >= 4 && !strcmp(spot-2, "ato"))) {
1192 Strcpy(spot+1, "es");
1193 goto bottom;
1194 }
1195
1196 /* Ends in y preceded by consonant (note: also "qu") change to "ies" */
1197 if (*spot == 'y' &&
1198 (!index(vowels, *(spot-1)))) {
1199 Strcpy(spot, "ies");
1200 goto bottom;
1201 }
1202
1203 /* Default: append an 's' */
1204 Strcpy(spot+1, "s");
1205
1206 bottom: if (excess) Strcpy(eos(str), excess);
1207 return str;
1208 }
1209
1210 #endif /* OVL0 */
1211
1212 struct o_range {
1213 const char *name, oclass;
1214 int f_o_range, l_o_range;
1215 };
1216
1217 #ifndef OVLB
1218
1219 STATIC_DCL const struct o_range o_ranges[];
1220
1221 #else /* OVLB */
1222
1223 /* wishable subranges of objects */
1224 STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
1225 { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS },
1226 { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP },
1227 { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE },
1228 { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY },
1229 { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION },
1230 { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY },
1231 { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1232 { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY },
1233 { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS },
1234 { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES },
1235 { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT },
1236 #ifdef TOURIST
1237 { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT },
1238 #endif
1239 { "dragon scales",
1240 ARMOR_CLASS, GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES },
1241 { "dragon scale mail",
1242 ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL },
1243 { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA },
1244 #ifdef WIZARD
1245 { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM },
1246 #endif
1247 { "gray stone", GEM_CLASS, LUCKSTONE, FLINT },
1248 { "grey stone", GEM_CLASS, LUCKSTONE, FLINT },
1249 };
1250
1251 #define BSTRCMP(base,ptr,string) ((ptr) < base || strcmp((ptr),string))
1252 #define BSTRCMPI(base,ptr,string) ((ptr) < base || strcmpi((ptr),string))
1253 #define BSTRNCMP(base,ptr,string,num) ((ptr)<base || strncmp((ptr),string,num))
1254 #define BSTRNCMPI(base,ptr,string,num) ((ptr)<base||strncmpi((ptr),string,num))
1255
1256 /*
1257 * Singularize a string the user typed in; this helps reduce the complexity
1258 * of readobjnam, and is also used in pager.c to singularize the string
1259 * for which help is sought.
1260 */
1261
1262 char *
makesingular(oldstr)1263 makesingular(oldstr)
1264 const char *oldstr;
1265 {
1266 register char *p, *bp;
1267 static char NEARDATA str[BUFSZ];
1268
1269 if (!oldstr || !*oldstr) {
1270 impossible("singular of null?");
1271 str[0] = 0;
1272 return str;
1273 }
1274 Strcpy(str, oldstr);
1275 bp = str;
1276
1277 while (*bp == ' ') bp++;
1278 /* find "cloves of garlic", "worthless pieces of blue glass" */
1279 if ((p = strstri(bp, "s of ")) != 0) {
1280 /* but don't singularize "gauntlets", "boots", "Eyes of the.." */
1281 if (BSTRNCMPI(bp, p-3, "Eye", 3) &&
1282 BSTRNCMP(bp, p-4, "boot", 4) &&
1283 BSTRNCMP(bp, p-8, "gauntlet", 8))
1284 while ((*p = *(p+1)) != 0) p++;
1285 return bp;
1286 }
1287
1288 /* remove -s or -es (boxes) or -ies (rubies) */
1289 p = eos(bp);
1290 if (p >= bp+1 && p[-1] == 's') {
1291 if (p >= bp+2 && p[-2] == 'e') {
1292 if (p >= bp+3 && p[-3] == 'i') {
1293 if(!BSTRCMP(bp, p-7, "cookies") ||
1294 !BSTRCMP(bp, p-4, "pies"))
1295 goto mins;
1296 Strcpy(p-3, "y");
1297 return bp;
1298 }
1299
1300 /* note: cloves / knives from clove / knife */
1301 if(!BSTRCMP(bp, p-6, "knives")) {
1302 Strcpy(p-3, "fe");
1303 return bp;
1304 }
1305
1306 if(!BSTRCMP(bp, p-6, "staves")) {
1307 Strcpy(p-3, "ff");
1308 return bp;
1309 }
1310
1311 if (!BSTRCMPI(bp, p-6, "leaves")) {
1312 Strcpy(p-3, "f");
1313 return bp;
1314 }
1315
1316 /* note: nurses, axes but boxes */
1317 if(!BSTRCMP(bp, p-5, "boxes")) {
1318 p[-2] = 0;
1319 return bp;
1320 }
1321 if (!BSTRCMP(bp, p-6, "gloves") ||
1322 !BSTRCMP(bp, p-6, "lenses") ||
1323 !BSTRCMP(bp, p-5, "shoes") ||
1324 !BSTRCMP(bp, p-6, "scales"))
1325 return bp;
1326 } else if (!BSTRCMP(bp, p-5, "boots") ||
1327 !BSTRCMP(bp, p-9, "gauntlets") ||
1328 !BSTRCMP(bp, p-6, "tricks") ||
1329 !BSTRCMP(bp, p-9, "paralysis") ||
1330 !BSTRCMP(bp, p-5, "glass") ||
1331 !BSTRCMP(bp, p-4, "ness") ||
1332 !BSTRCMP(bp, p-14, "shape changers") ||
1333 !BSTRCMP(bp, p-15, "detect monsters") ||
1334 !BSTRCMPI(bp, p-11, "Aesculapius") || /* staff */
1335 !BSTRCMP(bp, p-10, "eucalyptus") ||
1336 #ifdef WIZARD
1337 !BSTRCMP(bp, p-9, "iron bars") ||
1338 #endif
1339 !BSTRCMP(bp, p-5, "aklys"))
1340 return bp;
1341 mins:
1342 p[-1] = 0;
1343 } else {
1344 if(!BSTRCMP(bp, p-5, "teeth")) {
1345 Strcpy(p-5, "tooth");
1346 return bp;
1347 }
1348 /* here we cannot find the plural suffix */
1349 }
1350 return bp;
1351 }
1352
1353 /* compare user string against object name string using fuzzy matching */
1354 static boolean
wishymatch(u_str,o_str,retry_inverted)1355 wishymatch(u_str, o_str, retry_inverted)
1356 const char *u_str; /* from user, so might be variant spelling */
1357 const char *o_str; /* from objects[], so is in canonical form */
1358 boolean retry_inverted; /* optional extra "of" handling */
1359 {
1360 /* ignore spaces & hyphens and upper/lower case when comparing */
1361 if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE;
1362
1363 if (retry_inverted) {
1364 const char *u_of, *o_of;
1365 char *p, buf[BUFSZ];
1366
1367 /* when just one of the strings is in the form "foo of bar",
1368 convert it into "bar foo" and perform another comparison */
1369 u_of = strstri(u_str, " of ");
1370 o_of = strstri(o_str, " of ");
1371 if (u_of && !o_of) {
1372 Strcpy(buf, u_of + 4);
1373 p = eos(strcat(buf, " "));
1374 while (u_str < u_of) *p++ = *u_str++;
1375 *p = '\0';
1376 return fuzzymatch(buf, o_str, " -", TRUE);
1377 } else if (o_of && !u_of) {
1378 Strcpy(buf, o_of + 4);
1379 p = eos(strcat(buf, " "));
1380 while (o_str < o_of) *p++ = *o_str++;
1381 *p = '\0';
1382 return fuzzymatch(u_str, buf, " -", TRUE);
1383 }
1384 }
1385
1386 /* [note: if something like "elven speed boots" ever gets added, these
1387 special cases should be changed to call wishymatch() recursively in
1388 order to get the "of" inversion handling] */
1389 if (!strncmp(o_str, "dwarvish ", 9)) {
1390 if (!strncmpi(u_str, "dwarven ", 8))
1391 return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE);
1392 } else if (!strncmp(o_str, "elven ", 6)) {
1393 if (!strncmpi(u_str, "elvish ", 7))
1394 return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE);
1395 else if (!strncmpi(u_str, "elfin ", 6))
1396 return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE);
1397 } else if (!strcmp(o_str, "aluminum")) {
1398 /* this special case doesn't really fit anywhere else... */
1399 /* (note that " wand" will have been stripped off by now) */
1400 if (!strcmpi(u_str, "aluminium"))
1401 return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE);
1402 }
1403
1404 return FALSE;
1405 }
1406
1407 /* alternate spellings; if the difference is only the presence or
1408 absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe"
1409 vs "pick-axe") then there is no need for inclusion in this list;
1410 likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */
1411 struct alt_spellings {
1412 const char *sp;
1413 int ob;
1414 } spellings[] = {
1415 { "pickax", PICK_AXE },
1416 { "whip", BULLWHIP },
1417 { "saber", SILVER_SABER },
1418 { "silver sabre", SILVER_SABER },
1419 { "smooth shield", SHIELD_OF_REFLECTION },
1420 { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL },
1421 { "grey dragon scales", GRAY_DRAGON_SCALES },
1422 { "enchant armour", SCR_ENCHANT_ARMOR },
1423 { "destroy armour", SCR_DESTROY_ARMOR },
1424 { "scroll of enchant armour", SCR_ENCHANT_ARMOR },
1425 { "scroll of destroy armour", SCR_DESTROY_ARMOR },
1426 { "leather armour", LEATHER_ARMOR },
1427 { "studded leather armour", STUDDED_LEATHER_ARMOR },
1428 { "iron ball", HEAVY_IRON_BALL },
1429 { "lantern", BRASS_LANTERN },
1430 { "mattock", DWARVISH_MATTOCK },
1431 { "amulet of poison resistance", AMULET_VERSUS_POISON },
1432 { "stone", ROCK },
1433 #ifdef TOURIST
1434 { "camera", EXPENSIVE_CAMERA },
1435 { "tee shirt", T_SHIRT },
1436 #endif
1437 { "can", TIN },
1438 { "can opener", TIN_OPENER },
1439 { "kelp", KELP_FROND },
1440 { "eucalyptus", EUCALYPTUS_LEAF },
1441 { "grapple", GRAPPLING_HOOK },
1442 { (const char *)0, 0 },
1443 };
1444
1445 /* Return something wished for. If not an object, return &zeroobj; if an error
1446 * (no matching object), return (struct obj *)0. Giving readobjnam() a null
1447 * pointer skips the error return and creates a random object instead.
1448 */
1449 struct obj *
readobjnam(bp)1450 readobjnam(bp)
1451 register char *bp;
1452 {
1453 register char *p;
1454 register int i;
1455 register struct obj *otmp;
1456 int cnt, spe, spesgn, typ, very, rechrg;
1457 int blessed, uncursed, iscursed, ispoisoned, isgreased;
1458 int eroded, eroded2, erodeproof;
1459 #ifdef INVISIBLE_OBJECTS
1460 int isinvisible;
1461 #endif
1462 int halfeaten, mntmp, contents;
1463 int islit, unlabeled, ishistoric, isdiluted;
1464 struct fruit *f;
1465 int ftype = current_fruit;
1466 char fruitbuf[BUFSZ];
1467 /* Fruits may not mess up the ability to wish for real objects (since
1468 * you can leave a fruit in a bones file and it will be added to
1469 * another person's game), so they must be checked for last, after
1470 * stripping all the possible prefixes and seeing if there's a real
1471 * name in there. So we have to save the full original name. However,
1472 * it's still possible to do things like "uncursed burnt Alaska",
1473 * or worse yet, "2 burned 5 course meals", so we need to loop to
1474 * strip off the prefixes again, this time stripping only the ones
1475 * possible on food.
1476 * We could get even more detailed so as to allow food names with
1477 * prefixes that _are_ possible on food, so you could wish for
1478 * "2 3 alarm chilis". Currently this isn't allowed; options.c
1479 * automatically sticks 'candied' in front of such names.
1480 */
1481
1482 char oclass;
1483 char *un, *dn, *actualn;
1484 const char *name=0;
1485
1486 cnt = spe = spesgn = typ = very = rechrg =
1487 blessed = uncursed = iscursed =
1488 #ifdef INVISIBLE_OBJECTS
1489 isinvisible =
1490 #endif
1491 ispoisoned = isgreased = eroded = eroded2 = erodeproof =
1492 halfeaten = islit = unlabeled = ishistoric = isdiluted = 0;
1493 mntmp = NON_PM;
1494 #define UNDEFINED 0
1495 #define EMPTY 1
1496 #define SPINACH 2
1497 contents = UNDEFINED;
1498 oclass = 0;
1499 actualn = dn = un = 0;
1500
1501 if (!bp) goto any;
1502 /* first, remove extra whitespace they may have typed */
1503 (void)mungspaces(bp);
1504 Strcpy(fruitbuf, bp);
1505
1506 for(;;) {
1507 register int l;
1508
1509 if (!bp || !*bp) goto any;
1510 if (!strncmpi(bp, "an ", l=3) ||
1511 !strncmpi(bp, "a ", l=2)) {
1512 cnt = 1;
1513 } else if (!strncmpi(bp, "the ", l=4)) {
1514 ; /* just increment `bp' by `l' below */
1515 } else if (!cnt && digit(*bp) && strcmp(bp, "0")) {
1516 cnt = atoi(bp);
1517 while(digit(*bp)) bp++;
1518 while(*bp == ' ') bp++;
1519 l = 0;
1520 } else if (!strncmpi(bp, "blessed ", l=8) ||
1521 !strncmpi(bp, "holy ", l=5)) {
1522 blessed = 1;
1523 } else if (!strncmpi(bp, "cursed ", l=7) ||
1524 !strncmpi(bp, "unholy ", l=7)) {
1525 iscursed = 1;
1526 } else if (!strncmpi(bp, "uncursed ", l=9)) {
1527 uncursed = 1;
1528 #ifdef INVISIBLE_OBJECTS
1529 } else if (!strncmpi(bp, "invisible ", l=10)) {
1530 isinvisible = 1;
1531 #endif
1532 } else if (!strncmpi(bp, "rustproof ", l=10) ||
1533 !strncmpi(bp, "erodeproof ", l=11) ||
1534 !strncmpi(bp, "corrodeproof ", l=13) ||
1535 !strncmpi(bp, "fixed ", l=6) ||
1536 !strncmpi(bp, "fireproof ", l=10) ||
1537 !strncmpi(bp, "rotproof ", l=9)) {
1538 erodeproof = 1;
1539 } else if (!strncmpi(bp,"lit ", l=4) ||
1540 !strncmpi(bp,"burning ", l=8)) {
1541 islit = 1;
1542 } else if (!strncmpi(bp,"unlit ", l=6) ||
1543 !strncmpi(bp,"extinguished ", l=13)) {
1544 islit = 0;
1545 /* "unlabeled" and "blank" are synonymous */
1546 } else if (!strncmpi(bp,"unlabeled ", l=10) ||
1547 !strncmpi(bp,"unlabelled ", l=11) ||
1548 !strncmpi(bp,"blank ", l=6)) {
1549 unlabeled = 1;
1550 } else if(!strncmpi(bp, "poisoned ",l=9)
1551 #ifdef WIZARD
1552 || (wizard && !strncmpi(bp, "trapped ",l=8))
1553 #endif
1554 ) {
1555 ispoisoned=1;
1556 } else if(!strncmpi(bp, "greased ",l=8)) {
1557 isgreased=1;
1558 } else if (!strncmpi(bp, "very ", l=5)) {
1559 /* very rusted very heavy iron ball */
1560 very = 1;
1561 } else if (!strncmpi(bp, "thoroughly ", l=11)) {
1562 very = 2;
1563 } else if (!strncmpi(bp, "rusty ", l=6) ||
1564 !strncmpi(bp, "rusted ", l=7) ||
1565 !strncmpi(bp, "burnt ", l=6) ||
1566 !strncmpi(bp, "burned ", l=7)) {
1567 eroded = 1 + very;
1568 very = 0;
1569 } else if (!strncmpi(bp, "corroded ", l=9) ||
1570 !strncmpi(bp, "rotted ", l=7)) {
1571 eroded2 = 1 + very;
1572 very = 0;
1573 } else if (!strncmpi(bp, "partly eaten ", l=13)) {
1574 halfeaten = 1;
1575 } else if (!strncmpi(bp, "historic ", l=9)) {
1576 ishistoric = 1;
1577 } else if (!strncmpi(bp, "diluted ", l=8)) {
1578 isdiluted = 1;
1579 } else break;
1580 bp += l;
1581 }
1582 if(!cnt) cnt = 1; /* %% what with "gems" etc. ? */
1583 if(!strncmpi(bp, "empty ", 6)) {
1584 contents = EMPTY;
1585 bp += 6;
1586 }
1587 if (strlen(bp) > 1) {
1588 if (*bp == '+' || *bp == '-') {
1589 spesgn = (*bp++ == '+') ? 1 : -1;
1590 spe = atoi(bp);
1591 while(digit(*bp)) bp++;
1592 while(*bp == ' ') bp++;
1593 } else if ((p = rindex(bp, '(')) != 0) {
1594 if (p > bp && p[-1] == ' ') p[-1] = 0;
1595 else *p = 0;
1596 p++;
1597 if (!strcmpi(p, "lit)")) {
1598 islit = 1;
1599 } else {
1600 spe = atoi(p);
1601 while (digit(*p)) p++;
1602 if (*p == ':') {
1603 p++;
1604 rechrg = spe;
1605 spe = atoi(p);
1606 while (digit(*p)) p++;
1607 }
1608 if (*p != ')') {
1609 spe = rechrg = 0;
1610 } else {
1611 spesgn = 1;
1612 p++;
1613 if (*p) Strcat(bp, p);
1614 }
1615 }
1616 }
1617 }
1618 /*
1619 otmp->spe is type schar; so we don't want spe to be any bigger or smaller.
1620 also, spe should always be positive -- some cheaters may try to confuse
1621 atoi()
1622 */
1623 if (spe < 0) {
1624 spesgn = -1; /* cheaters get what they deserve */
1625 spe = abs(spe);
1626 }
1627 if (spe > SCHAR_LIM)
1628 spe = SCHAR_LIM;
1629 if (rechrg < 0 || rechrg > 7) rechrg = 7; /* recharge_limit */
1630
1631 /* now we have the actual name, as delivered by xname, say
1632 green potions called whisky
1633 scrolls labeled "QWERTY"
1634 egg
1635 fortune cookies
1636 very heavy iron ball named hoei
1637 wand of wishing
1638 elven cloak
1639 */
1640 if ((p = strstri(bp, " named ")) != 0) {
1641 *p = 0;
1642 name = p+7;
1643 }
1644 if ((p = strstri(bp, " called ")) != 0) {
1645 *p = 0;
1646 un = p+8;
1647 /* "helmet called telepathy" is not "helmet" (a specific type)
1648 * "shield called reflection" is not "shield" (a general type)
1649 */
1650 for(i = 0; i < SIZE(o_ranges); i++)
1651 if(!strcmpi(bp, o_ranges[i].name)) {
1652 oclass = o_ranges[i].oclass;
1653 goto srch;
1654 }
1655 }
1656 if ((p = strstri(bp, " labeled ")) != 0) {
1657 *p = 0;
1658 dn = p+9;
1659 } else if ((p = strstri(bp, " labelled ")) != 0) {
1660 *p = 0;
1661 dn = p+10;
1662 }
1663 if ((p = strstri(bp, " of spinach")) != 0) {
1664 *p = 0;
1665 contents = SPINACH;
1666 }
1667
1668 /*
1669 Skip over "pair of ", "pairs of", "set of" and "sets of".
1670
1671 Accept "3 pair of boots" as well as "3 pairs of boots". It is valid
1672 English either way. See makeplural() for more on pair/pairs.
1673
1674 We should only double count if the object in question is not
1675 refered to as a "pair of". E.g. We should double if the player
1676 types "pair of spears", but not if the player types "pair of
1677 lenses". Luckily (?) all objects that are refered to as pairs
1678 -- boots, gloves, and lenses -- are also not mergable, so cnt is
1679 ignored anyway.
1680 */
1681 if(!strncmpi(bp, "pair of ",8)) {
1682 bp += 8;
1683 cnt *= 2;
1684 } else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) {
1685 bp += 9;
1686 cnt *= 2;
1687 } else if (!strncmpi(bp, "set of ",7)) {
1688 bp += 7;
1689 } else if (!strncmpi(bp, "sets of ",8)) {
1690 bp += 8;
1691 }
1692
1693 /*
1694 * Find corpse type using "of" (figurine of an orc, tin of orc meat)
1695 * Don't check if it's a wand or spellbook.
1696 * (avoid "wand/finger of death" confusion).
1697 */
1698 if (!strstri(bp, "wand ")
1699 && !strstri(bp, "spellbook ")
1700 && !strstri(bp, "finger ")) {
1701 if ((p = strstri(bp, " of ")) != 0
1702 && (mntmp = name_to_mon(p+4)) >= LOW_PM)
1703 *p = 0;
1704 }
1705 /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */
1706 if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */
1707 if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */
1708 if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */
1709 if (strncmpi(bp, "master key", 10)) /* not the "master" rank */
1710 if (mntmp < LOW_PM && strlen(bp) > 2 &&
1711 (mntmp = name_to_mon(bp)) >= LOW_PM) {
1712 int mntmptoo, mntmplen; /* double check for rank title */
1713 char *obp = bp;
1714 mntmptoo = title_to_mon(bp, (int *)0, &mntmplen);
1715 bp += mntmp != mntmptoo ? strlen(mons[mntmp].mname) : mntmplen;
1716 if (*bp == ' ') bp++;
1717 else if (!strncmpi(bp, "s ", 2)) bp += 2;
1718 else if (!strncmpi(bp, "es ", 3)) bp += 3;
1719 else if (!*bp && !actualn && !dn && !un && !oclass) {
1720 /* no referent; they don't really mean a monster type */
1721 bp = obp;
1722 mntmp = NON_PM;
1723 }
1724 }
1725
1726 /* first change to singular if necessary */
1727 if (*bp) {
1728 char *sng = makesingular(bp);
1729 if (strcmp(bp, sng)) {
1730 if (cnt == 1) cnt = 2;
1731 Strcpy(bp, sng);
1732 }
1733 }
1734
1735 /* Alternate spellings (pick-ax, silver sabre, &c) */
1736 {
1737 struct alt_spellings *as = spellings;
1738
1739 while (as->sp) {
1740 if (fuzzymatch(bp, as->sp, " -", TRUE)) {
1741 typ = as->ob;
1742 goto typfnd;
1743 }
1744 as++;
1745 }
1746 }
1747
1748 /* dragon scales - assumes order of dragons */
1749 if(!strcmpi(bp, "scales") &&
1750 mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) {
1751 typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON;
1752 mntmp = NON_PM; /* no monster */
1753 goto typfnd;
1754 }
1755
1756 p = eos(bp);
1757 if(!BSTRCMPI(bp, p-10, "holy water")) {
1758 typ = POT_WATER;
1759 if ((p-bp) >= 12 && *(p-12) == 'u')
1760 iscursed = 1; /* unholy water */
1761 else blessed = 1;
1762 goto typfnd;
1763 }
1764 if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) {
1765 typ = SCR_BLANK_PAPER;
1766 goto typfnd;
1767 }
1768 if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) {
1769 typ = SPE_BLANK_PAPER;
1770 goto typfnd;
1771 }
1772 /*
1773 * NOTE: Gold pieces are handled as objects nowadays, and therefore
1774 * this section should probably be reconsidered as well as the entire
1775 * gold/money concept. Maybe we want to add other monetary units as
1776 * well in the future. (TH)
1777 */
1778 if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") ||
1779 !strcmpi(bp, "gold") || !strcmpi(bp, "money") ||
1780 !strcmpi(bp, "coin") || *bp == GOLD_SYM) {
1781 if (cnt > 5000
1782 #ifdef WIZARD
1783 && !wizard
1784 #endif
1785 ) cnt=5000;
1786 if (cnt < 1) cnt=1;
1787 pline("%d gold piece%s.", cnt, plur(cnt));
1788 u.ugold += cnt;
1789 flags.botl=1;
1790 return (&zeroobj);
1791 }
1792 if (strlen(bp) == 1 &&
1793 (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS
1794 #ifdef WIZARD
1795 && (wizard || i != VENOM_CLASS)
1796 #else
1797 && i != VENOM_CLASS
1798 #endif
1799 ) {
1800 oclass = i;
1801 goto any;
1802 }
1803
1804 /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */
1805 /* false hits on, e.g., rings for "ring mail". */
1806 if(strncmpi(bp, "enchant ", 8) &&
1807 strncmpi(bp, "destroy ", 8) &&
1808 strncmpi(bp, "food detection", 14) &&
1809 strncmpi(bp, "ring mail", 9) &&
1810 strncmpi(bp, "studded leather arm", 19) &&
1811 strncmpi(bp, "leather arm", 11) &&
1812 strncmpi(bp, "tooled horn", 11) &&
1813 strncmpi(bp, "food ration", 11) &&
1814 strncmpi(bp, "meat ring", 9)
1815 )
1816 for (i = 0; i < (int)(sizeof wrpsym); i++) {
1817 register int j = strlen(wrp[i]);
1818 if(!strncmpi(bp, wrp[i], j)){
1819 oclass = wrpsym[i];
1820 if(oclass != AMULET_CLASS) {
1821 bp += j;
1822 if(!strncmpi(bp, " of ", 4)) actualn = bp+4;
1823 /* else if(*bp) ?? */
1824 } else
1825 actualn = bp;
1826 goto srch;
1827 }
1828 if(!BSTRCMPI(bp, p-j, wrp[i])){
1829 oclass = wrpsym[i];
1830 p -= j;
1831 *p = 0;
1832 if(p > bp && p[-1] == ' ') p[-1] = 0;
1833 actualn = dn = bp;
1834 goto srch;
1835 }
1836 }
1837
1838 /* "grey stone" check must be before general "stone" */
1839 for (i = 0; i < SIZE(o_ranges); i++)
1840 if(!strcmpi(bp, o_ranges[i].name)) {
1841 typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range);
1842 goto typfnd;
1843 }
1844
1845 if (!BSTRCMPI(bp, p-6, " stone")) {
1846 p[-6] = 0;
1847 oclass = GEM_CLASS;
1848 dn = actualn = bp;
1849 goto srch;
1850 } else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) {
1851 register char *g = bp;
1852 if (strstri(g, "broken")) return (struct obj *)0;
1853 if (!strncmpi(g, "worthless ", 10)) g += 10;
1854 if (!strncmpi(g, "piece of ", 9)) g += 9;
1855 if (!strncmpi(g, "colored ", 8)) g += 8;
1856 else if (!strncmpi(g, "coloured ", 9)) g += 9;
1857 if (!strcmpi(g, "glass")) { /* choose random color */
1858 /* 9 different kinds */
1859 typ = LAST_GEM + rnd(9);
1860 if (objects[typ].oc_class == GEM_CLASS) goto typfnd;
1861 else typ = 0; /* somebody changed objects[]? punt */
1862 } else if (g > bp) { /* try to construct canonical form */
1863 char tbuf[BUFSZ];
1864 Strcpy(tbuf, "worthless piece of ");
1865 Strcat(tbuf, g); /* assume it starts with the color */
1866 Strcpy(bp, tbuf);
1867 }
1868 }
1869
1870 actualn = bp;
1871 if (!dn) dn = actualn; /* ex. "skull cap" */
1872 srch:
1873 /* check real names of gems first */
1874 if(!oclass && actualn) {
1875 for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) {
1876 register const char *zn;
1877
1878 if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) {
1879 typ = i;
1880 goto typfnd;
1881 }
1882 }
1883 }
1884 i = oclass ? bases[(int)oclass] : 1;
1885 while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){
1886 register const char *zn;
1887
1888 if (actualn && (zn = OBJ_NAME(objects[i])) != 0 &&
1889 wishymatch(actualn, zn, TRUE)) {
1890 typ = i;
1891 goto typfnd;
1892 }
1893 if (dn && (zn = OBJ_DESCR(objects[i])) != 0 &&
1894 wishymatch(dn, zn, FALSE)) {
1895 /* don't match extra descriptions (w/o real name) */
1896 if (!OBJ_NAME(objects[i])) return (struct obj *)0;
1897 typ = i;
1898 goto typfnd;
1899 }
1900 if (un && (zn = objects[i].oc_uname) != 0 &&
1901 wishymatch(un, zn, FALSE)) {
1902 typ = i;
1903 goto typfnd;
1904 }
1905 i++;
1906 }
1907 if (actualn) {
1908 struct Jitem *j = Japanese_items;
1909 while(j->item) {
1910 if (actualn && !strcmpi(actualn, j->name)) {
1911 typ = j->item;
1912 goto typfnd;
1913 }
1914 j++;
1915 }
1916 }
1917 if (!strcmpi(bp, "spinach")) {
1918 contents = SPINACH;
1919 typ = TIN;
1920 goto typfnd;
1921 }
1922 /* Note: not strncmpi. 2 fruits, one capital, one not, are possible. */
1923 {
1924 char *fp;
1925 int l, cntf;
1926 int blessedf, iscursedf, uncursedf, halfeatenf;
1927
1928 blessedf = iscursedf = uncursedf = halfeatenf = 0;
1929 cntf = 0;
1930
1931 fp = fruitbuf;
1932 for(;;) {
1933 if (!fp || !*fp) break;
1934 if (!strncmpi(fp, "an ", l=3) ||
1935 !strncmpi(fp, "a ", l=2)) {
1936 cntf = 1;
1937 } else if (!cntf && digit(*fp)) {
1938 cntf = atoi(fp);
1939 while(digit(*fp)) fp++;
1940 while(*fp == ' ') fp++;
1941 l = 0;
1942 } else if (!strncmpi(fp, "blessed ", l=8)) {
1943 blessedf = 1;
1944 } else if (!strncmpi(fp, "cursed ", l=7)) {
1945 iscursedf = 1;
1946 } else if (!strncmpi(fp, "uncursed ", l=9)) {
1947 uncursedf = 1;
1948 } else if (!strncmpi(fp, "partly eaten ", l=13)) {
1949 halfeatenf = 1;
1950 } else break;
1951 fp += l;
1952 }
1953
1954 for(f=ffruit; f; f = f->nextf) {
1955 char *f1 = f->fname, *f2 = makeplural(f->fname);
1956
1957 if(!strncmp(fp, f1, strlen(f1)) ||
1958 !strncmp(fp, f2, strlen(f2))) {
1959 typ = SLIME_MOLD;
1960 blessed = blessedf;
1961 iscursed = iscursedf;
1962 uncursed = uncursedf;
1963 halfeaten = halfeatenf;
1964 cnt = cntf;
1965 ftype = f->fid;
1966 goto typfnd;
1967 }
1968 }
1969 }
1970
1971 if(!oclass && actualn) {
1972 short objtyp;
1973
1974 /* Perhaps it's an artifact specified by name, not type */
1975 name = artifact_name(actualn, &objtyp);
1976 if(name) {
1977 typ = objtyp;
1978 goto typfnd;
1979 }
1980 }
1981 #ifdef WIZARD
1982 /* Let wizards wish for traps --KAA */
1983 /* must come after objects check so wizards can still wish for
1984 * trap objects like beartraps
1985 */
1986 if (wizard) {
1987 int trap;
1988
1989 for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) {
1990 const char *tname;
1991
1992 tname = defsyms[trap_to_defsym(trap)].explanation;
1993 if (!strncmpi(tname, bp, strlen(tname))) {
1994 /* avoid stupid mistakes */
1995 if((trap == TRAPDOOR || trap == HOLE)
1996 && !Can_fall_thru(&u.uz)) trap = ROCKTRAP;
1997 (void) maketrap(u.ux, u.uy, trap);
1998 pline("%s.", An(tname));
1999 return(&zeroobj);
2000 }
2001 }
2002 /* or some other dungeon features -dlc */
2003 p = eos(bp);
2004 if(!BSTRCMP(bp, p-8, "fountain")) {
2005 levl[u.ux][u.uy].typ = FOUNTAIN;
2006 level.flags.nfountains++;
2007 if(!strncmpi(bp, "magic ", 6))
2008 levl[u.ux][u.uy].blessedftn = 1;
2009 pline("A %sfountain.",
2010 levl[u.ux][u.uy].blessedftn ? "magic " : "");
2011 newsym(u.ux, u.uy);
2012 return(&zeroobj);
2013 }
2014 if(!BSTRCMP(bp, p-6, "throne")) {
2015 levl[u.ux][u.uy].typ = THRONE;
2016 pline("A throne.");
2017 newsym(u.ux, u.uy);
2018 return(&zeroobj);
2019 }
2020 # ifdef SINKS
2021 if(!BSTRCMP(bp, p-4, "sink")) {
2022 levl[u.ux][u.uy].typ = SINK;
2023 level.flags.nsinks++;
2024 pline("A sink.");
2025 newsym(u.ux, u.uy);
2026 return &zeroobj;
2027 }
2028 # endif
2029 if(!BSTRCMP(bp, p-4, "pool")) {
2030 levl[u.ux][u.uy].typ = POOL;
2031 del_engr_at(u.ux, u.uy);
2032 pline("A pool.");
2033 /* Must manually make kelp! */
2034 water_damage(level.objects[u.ux][u.uy], FALSE, TRUE);
2035 newsym(u.ux, u.uy);
2036 return &zeroobj;
2037 }
2038 if (!BSTRCMP(bp, p-4, "lava")) { /* also matches "molten lava" */
2039 levl[u.ux][u.uy].typ = LAVAPOOL;
2040 del_engr_at(u.ux, u.uy);
2041 pline("A pool of molten lava.");
2042 if (!(Levitation || Flying)) (void) lava_effects();
2043 newsym(u.ux, u.uy);
2044 return &zeroobj;
2045 }
2046
2047 if(!BSTRCMP(bp, p-5, "altar")) {
2048 aligntyp al;
2049
2050 levl[u.ux][u.uy].typ = ALTAR;
2051 if(!strncmpi(bp, "chaotic ", 8))
2052 al = A_CHAOTIC;
2053 else if(!strncmpi(bp, "neutral ", 8))
2054 al = A_NEUTRAL;
2055 else if(!strncmpi(bp, "lawful ", 7))
2056 al = A_LAWFUL;
2057 else if(!strncmpi(bp, "unaligned ", 10))
2058 al = A_NONE;
2059 else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
2060 al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1;
2061 levl[u.ux][u.uy].altarmask = Align2amask( al );
2062 pline("%s altar.", An(align_str(al)));
2063 newsym(u.ux, u.uy);
2064 return(&zeroobj);
2065 }
2066
2067 if(!BSTRCMP(bp, p-5, "grave") || !BSTRCMP(bp, p-9, "headstone")) {
2068 make_grave(u.ux, u.uy, (char *) 0);
2069 pline("A grave.");
2070 newsym(u.ux, u.uy);
2071 return(&zeroobj);
2072 }
2073
2074 if(!BSTRCMP(bp, p-4, "tree")) {
2075 levl[u.ux][u.uy].typ = TREE;
2076 pline("A tree.");
2077 newsym(u.ux, u.uy);
2078 return &zeroobj;
2079 }
2080
2081 if(!BSTRCMP(bp, p-4, "bars")) {
2082 levl[u.ux][u.uy].typ = IRONBARS;
2083 pline("Iron bars.");
2084 newsym(u.ux, u.uy);
2085 return &zeroobj;
2086 }
2087 }
2088 #endif
2089 if(!oclass) return((struct obj *)0);
2090 any:
2091 if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))];
2092 typfnd:
2093 if (typ) oclass = objects[typ].oc_class;
2094
2095 /* check for some objects that are not allowed */
2096 if (typ && objects[typ].oc_unique) {
2097 #ifdef WIZARD
2098 if (wizard)
2099 ; /* allow unique objects */
2100 else
2101 #endif
2102 switch (typ) {
2103 case AMULET_OF_YENDOR:
2104 typ = FAKE_AMULET_OF_YENDOR;
2105 break;
2106 case CANDELABRUM_OF_INVOCATION:
2107 typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE);
2108 break;
2109 case BELL_OF_OPENING:
2110 typ = BELL;
2111 break;
2112 case SPE_BOOK_OF_THE_DEAD:
2113 typ = SPE_BLANK_PAPER;
2114 break;
2115 }
2116 }
2117
2118 /* catch any other non-wishable objects */
2119 if (objects[typ].oc_nowish
2120 #ifdef WIZARD
2121 && !wizard
2122 #endif
2123 )
2124 return((struct obj *)0);
2125
2126 /* convert magic lamps to regular lamps before lighting them or setting
2127 the charges */
2128 if (typ == MAGIC_LAMP
2129 #ifdef WIZARD
2130 && !wizard
2131 #endif
2132 )
2133 typ = OIL_LAMP;
2134
2135 if(typ) {
2136 otmp = mksobj(typ, TRUE, FALSE);
2137 } else {
2138 otmp = mkobj(oclass, FALSE);
2139 if (otmp) typ = otmp->otyp;
2140 }
2141
2142 if (islit &&
2143 (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN ||
2144 Is_candle(otmp) || typ == POT_OIL)) {
2145 place_object(otmp, u.ux, u.uy); /* make it viable light source */
2146 begin_burn(otmp, FALSE);
2147 obj_extract_self(otmp); /* now release it for caller's use */
2148 }
2149
2150 if(cnt > 0 && objects[typ].oc_merge && oclass != SPBOOK_CLASS &&
2151 (cnt < rnd(6) ||
2152 #ifdef WIZARD
2153 wizard ||
2154 #endif
2155 (cnt <= 7 && Is_candle(otmp)) ||
2156 (cnt <= 20 &&
2157 ((oclass == WEAPON_CLASS && is_ammo(otmp))
2158 || typ == ROCK || is_missile(otmp)))))
2159 otmp->quan = (long) cnt;
2160
2161 #ifdef WIZARD
2162 if (oclass == VENOM_CLASS) otmp->spe = 1;
2163 #endif
2164
2165 if (spesgn == 0) spe = otmp->spe;
2166 #ifdef WIZARD
2167 else if (wizard) /* no alteration to spe */ ;
2168 #endif
2169 else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS ||
2170 is_weptool(otmp) ||
2171 (oclass==RING_CLASS && objects[typ].oc_charged)) {
2172 if(spe > rnd(5) && spe > otmp->spe) spe = 0;
2173 if(spe > 2 && Luck < 0) spesgn = -1;
2174 } else {
2175 if (oclass == WAND_CLASS) {
2176 if (spe > 1 && spesgn == -1) spe = 1;
2177 } else {
2178 if (spe > 0 && spesgn == -1) spe = 0;
2179 }
2180 if (spe > otmp->spe) spe = otmp->spe;
2181 }
2182
2183 if (spesgn == -1) spe = -spe;
2184
2185 /* set otmp->spe. This may, or may not, use spe... */
2186 switch (typ) {
2187 case TIN: if (contents==EMPTY) {
2188 otmp->corpsenm = NON_PM;
2189 otmp->spe = 0;
2190 } else if (contents==SPINACH) {
2191 otmp->corpsenm = NON_PM;
2192 otmp->spe = 1;
2193 }
2194 break;
2195 case SLIME_MOLD: otmp->spe = ftype;
2196 /* Fall through */
2197 case SKELETON_KEY: case CHEST: case LARGE_BOX:
2198 case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE:
2199 /* otmp->cobj already done in mksobj() */
2200 break;
2201 #ifdef MAIL
2202 case SCR_MAIL: otmp->spe = 1; break;
2203 #endif
2204 case WAN_WISHING:
2205 #ifdef WIZARD
2206 if (!wizard) {
2207 #endif
2208 otmp->spe = (rn2(10) ? -1 : 0);
2209 break;
2210 #ifdef WIZARD
2211 }
2212 /* fall through, if wizard */
2213 #endif
2214 default: otmp->spe = spe;
2215 }
2216
2217 /* set otmp->corpsenm or dragon scale [mail] */
2218 if (mntmp >= LOW_PM) switch(typ) {
2219 case TIN:
2220 otmp->spe = 0; /* No spinach */
2221 if (dead_species(mntmp, FALSE)) {
2222 otmp->corpsenm = NON_PM; /* it's empty */
2223 } else if (!(mons[mntmp].geno & G_UNIQ) &&
2224 !(mvitals[mntmp].mvflags & G_NOCORPSE) &&
2225 mons[mntmp].cnutrit != 0) {
2226 otmp->corpsenm = mntmp;
2227 }
2228 break;
2229 case CORPSE:
2230 if (!(mons[mntmp].geno & G_UNIQ) &&
2231 !(mvitals[mntmp].mvflags & G_NOCORPSE)) {
2232 /* beware of random troll or lizard corpse,
2233 or of ordinary one being forced to such */
2234 if (otmp->timed) obj_stop_timers(otmp);
2235 otmp->corpsenm = mntmp;
2236 start_corpse_timeout(otmp);
2237 }
2238 break;
2239 case FIGURINE:
2240 if (!(mons[mntmp].geno & G_UNIQ)
2241 && !is_human(&mons[mntmp])
2242 #ifdef MAIL
2243 && mntmp != PM_MAIL_DAEMON
2244 #endif
2245 )
2246 otmp->corpsenm = mntmp;
2247 break;
2248 case EGG:
2249 mntmp = can_be_hatched(mntmp);
2250 if (mntmp != NON_PM) {
2251 otmp->corpsenm = mntmp;
2252 if (!dead_species(mntmp, TRUE))
2253 attach_egg_hatch_timeout(otmp);
2254 else
2255 kill_egg(otmp);
2256 }
2257 break;
2258 case STATUE: otmp->corpsenm = mntmp;
2259 if (Has_contents(otmp) && verysmall(&mons[mntmp]))
2260 delete_contents(otmp); /* no spellbook */
2261 otmp->spe = ishistoric;
2262 break;
2263 case SCALE_MAIL:
2264 /* Dragon mail - depends on the order of objects */
2265 /* & dragons. */
2266 if (mntmp >= PM_GRAY_DRAGON &&
2267 mntmp <= PM_YELLOW_DRAGON)
2268 otmp->otyp = GRAY_DRAGON_SCALE_MAIL +
2269 mntmp - PM_GRAY_DRAGON;
2270 break;
2271 }
2272
2273 /* set blessed/cursed -- setting the fields directly is safe
2274 * since weight() is called below and addinv() will take care
2275 * of luck */
2276 if (iscursed) {
2277 curse(otmp);
2278 } else if (uncursed) {
2279 otmp->blessed = 0;
2280 otmp->cursed = (Luck < 0
2281 #ifdef WIZARD
2282 && !wizard
2283 #endif
2284 );
2285 } else if (blessed) {
2286 otmp->blessed = (Luck >= 0
2287 #ifdef WIZARD
2288 || wizard
2289 #endif
2290 );
2291 otmp->cursed = (Luck < 0
2292 #ifdef WIZARD
2293 && !wizard
2294 #endif
2295 );
2296 } else if (spesgn < 0) {
2297 curse(otmp);
2298 }
2299
2300 #ifdef INVISIBLE_OBJECTS
2301 if (isinvisible) otmp->oinvis = 1;
2302 #endif
2303
2304 /* set eroded */
2305 if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) {
2306 if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
2307 otmp->oeroded = eroded;
2308 if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
2309 otmp->oeroded2 = eroded2;
2310
2311 /* set erodeproof */
2312 if (erodeproof && !eroded && !eroded2)
2313 otmp->oerodeproof = (Luck >= 0
2314 #ifdef WIZARD
2315 || wizard
2316 #endif
2317 );
2318 }
2319
2320 /* set otmp->recharged */
2321 if (oclass == WAND_CLASS) {
2322 /* prevent wishing abuse */
2323 if (otmp->otyp == WAN_WISHING
2324 #ifdef WIZARD
2325 && !wizard
2326 #endif
2327 ) rechrg = 1;
2328 otmp->recharged = (unsigned)rechrg;
2329 }
2330
2331 /* set poisoned */
2332 if (ispoisoned) {
2333 if (is_poisonable(otmp))
2334 otmp->opoisoned = (Luck >= 0);
2335 else if (Is_box(otmp) || typ == TIN)
2336 otmp->otrapped = 1;
2337 else if (oclass == FOOD_CLASS)
2338 /* try to taint by making it as old as possible */
2339 otmp->age = 1L;
2340 }
2341
2342 if (isgreased) otmp->greased = 1;
2343
2344 if (isdiluted && otmp->oclass == POTION_CLASS &&
2345 otmp->otyp != POT_WATER)
2346 otmp->odiluted = 1;
2347
2348 if (name) {
2349 const char *aname;
2350 short objtyp;
2351
2352 /* an artifact name might need capitalization fixing */
2353 aname = artifact_name(name, &objtyp);
2354 if (aname && objtyp == otmp->otyp) name = aname;
2355
2356 otmp = oname(otmp, name);
2357 if (otmp->oartifact) {
2358 otmp->quan = 1L;
2359 u.uconduct.wisharti++; /* KMH, conduct */
2360 }
2361 }
2362
2363 /* more wishing abuse: don't allow wishing for certain artifacts */
2364 /* and make them pay; charge them for the wish anyway! */
2365 if ((is_quest_artifact(otmp) ||
2366 (otmp->oartifact && rn2(nartifact_exist()) > 1))
2367 #ifdef WIZARD
2368 && !wizard
2369 #endif
2370 ) {
2371 artifact_exists(otmp, ONAME(otmp), FALSE);
2372 obfree(otmp, (struct obj *) 0);
2373 otmp = &zeroobj;
2374 pline(
2375 "For a moment, you feel %s in your %s, but it disappears!",
2376 something,
2377 makeplural(body_part(HAND)));
2378 }
2379
2380 otmp->owt = weight(otmp);
2381 if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160;
2382 if (halfeaten && otmp->oclass == FOOD_CLASS) {
2383 if (otmp->otyp == CORPSE)
2384 otmp->oeaten = mons[otmp->corpsenm].cnutrit;
2385 else otmp->oeaten = objects[otmp->otyp].oc_nutrition;
2386 otmp->owt /= 2;
2387 otmp->oeaten /= 2;
2388 if (!otmp->owt) otmp->owt = 1;
2389 if (!otmp->oeaten) otmp->oeaten = 1;
2390 }
2391 return(otmp);
2392 }
2393
2394 int
rnd_class(first,last)2395 rnd_class(first,last)
2396 int first,last;
2397 {
2398 int i, x, sum=0;
2399
2400 if (first == last)
2401 return (first);
2402 for(i=first; i<=last; i++)
2403 sum += objects[i].oc_prob;
2404 if (!sum) /* all zero */
2405 return first + rn2(last-first+1);
2406 x = rnd(sum);
2407 for(i=first; i<=last; i++)
2408 if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0)
2409 return i;
2410 return 0;
2411 }
2412
2413 STATIC_OVL const char *
Japanese_item_name(i)2414 Japanese_item_name(i)
2415 int i;
2416 {
2417 struct Jitem *j = Japanese_items;
2418
2419 while(j->item) {
2420 if (i == j->item)
2421 return j->name;
2422 j++;
2423 }
2424 return (const char *)0;
2425 }
2426 #endif /* OVLB */
2427
2428 /*objnam.c*/
2429