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