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 *
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 *
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 *
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
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 *
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 *
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
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
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 *
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
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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
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 *
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
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 *
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*/