1 /* $NetBSD: hack.objnam.c,v 1.6 2003/04/02 18:36:39 jsm Exp $ */ 2 3 /* 4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 * Amsterdam 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are 10 * met: 11 * 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * - Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * - Neither the name of the Stichting Centrum voor Wiskunde en 20 * Informatica, nor the names of its contributors may be used to endorse or 21 * promote products derived from this software without specific prior 22 * written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. The name of the author may not be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 #include <sys/cdefs.h> 65 #ifndef lint 66 __RCSID("$NetBSD: hack.objnam.c,v 1.6 2003/04/02 18:36:39 jsm Exp $"); 67 #endif /* not lint */ 68 69 #include <stdlib.h> 70 #include "hack.h" 71 #include "extern.h" 72 #define Sprintf (void) sprintf 73 #define Strcat (void) strcat 74 #define Strcpy (void) strcpy 75 #define PREFIX 15 76 77 char * 78 strprepend(s, pref) 79 char *s, *pref; 80 { 81 int i = strlen(pref); 82 if (i > PREFIX) { 83 pline("WARNING: prefix too short."); 84 return (s); 85 } 86 s -= i; 87 (void) strncpy(s, pref, i); /* do not copy trailing 0 */ 88 return (s); 89 } 90 91 char * 92 sitoa(a) 93 int a; 94 { 95 static char buf[13]; 96 Sprintf(buf, (a < 0) ? "%d" : "+%d", a); 97 return (buf); 98 } 99 100 char * 101 typename(otyp) 102 int otyp; 103 { 104 static char buf[BUFSZ]; 105 struct objclass *ocl = &objects[otyp]; 106 const char *an = ocl->oc_name; 107 const char *dn = ocl->oc_descr; 108 char *un = ocl->oc_uname; 109 int nn = ocl->oc_name_known; 110 switch (ocl->oc_olet) { 111 case POTION_SYM: 112 Strcpy(buf, "potion"); 113 break; 114 case SCROLL_SYM: 115 Strcpy(buf, "scroll"); 116 break; 117 case WAND_SYM: 118 Strcpy(buf, "wand"); 119 break; 120 case RING_SYM: 121 Strcpy(buf, "ring"); 122 break; 123 default: 124 if (nn) { 125 Strcpy(buf, an); 126 if (otyp >= TURQUOISE && otyp <= JADE) 127 Strcat(buf, " stone"); 128 if (un) 129 Sprintf(eos(buf), " called %s", un); 130 if (dn) 131 Sprintf(eos(buf), " (%s)", dn); 132 } else { 133 Strcpy(buf, dn ? dn : an); 134 if (ocl->oc_olet == GEM_SYM) 135 Strcat(buf, " gem"); 136 if (un) 137 Sprintf(eos(buf), " called %s", un); 138 } 139 return (buf); 140 } 141 /* here for ring/scroll/potion/wand */ 142 if (nn) 143 Sprintf(eos(buf), " of %s", an); 144 if (un) 145 Sprintf(eos(buf), " called %s", un); 146 if (dn) 147 Sprintf(eos(buf), " (%s)", dn); 148 return (buf); 149 } 150 151 char * 152 xname(obj) 153 struct obj *obj; 154 { 155 static char bufr[BUFSZ]; 156 char *buf = &(bufr[PREFIX]); /* leave room for "17 -3 " */ 157 int nn = objects[obj->otyp].oc_name_known; 158 const char *an = objects[obj->otyp].oc_name; 159 const char *dn = objects[obj->otyp].oc_descr; 160 char *un = objects[obj->otyp].oc_uname; 161 int pl = (obj->quan != 1); 162 if (!obj->dknown && !Blind) 163 obj->dknown = 1;/* %% doesnt belong here */ 164 switch (obj->olet) { 165 case AMULET_SYM: 166 Strcpy(buf, (obj->spe < 0 && obj->known) 167 ? "cheap plastic imitation of the " : ""); 168 Strcat(buf, "Amulet of Yendor"); 169 break; 170 case TOOL_SYM: 171 if (!nn) { 172 Strcpy(buf, dn); 173 break; 174 } 175 Strcpy(buf, an); 176 break; 177 case FOOD_SYM: 178 if (obj->otyp == DEAD_HOMUNCULUS && pl) { 179 pl = 0; 180 Strcpy(buf, "dead homunculi"); 181 break; 182 } 183 /* fungis ? */ 184 /* fall into next case */ 185 case WEAPON_SYM: 186 if (obj->otyp == WORM_TOOTH && pl) { 187 pl = 0; 188 Strcpy(buf, "worm teeth"); 189 break; 190 } 191 if (obj->otyp == CRYSKNIFE && pl) { 192 pl = 0; 193 Strcpy(buf, "crysknives"); 194 break; 195 } 196 /* fall into next case */ 197 case ARMOR_SYM: 198 case CHAIN_SYM: 199 case ROCK_SYM: 200 Strcpy(buf, an); 201 break; 202 case BALL_SYM: 203 Sprintf(buf, "%sheavy iron ball", 204 (obj->owt > objects[obj->otyp].oc_weight) ? "very " : ""); 205 break; 206 case POTION_SYM: 207 if (nn || un || !obj->dknown) { 208 Strcpy(buf, "potion"); 209 if (pl) { 210 pl = 0; 211 Strcat(buf, "s"); 212 } 213 if (!obj->dknown) 214 break; 215 if (un) { 216 Strcat(buf, " called "); 217 Strcat(buf, un); 218 } else { 219 Strcat(buf, " of "); 220 Strcat(buf, an); 221 } 222 } else { 223 Strcpy(buf, dn); 224 Strcat(buf, " potion"); 225 } 226 break; 227 case SCROLL_SYM: 228 Strcpy(buf, "scroll"); 229 if (pl) { 230 pl = 0; 231 Strcat(buf, "s"); 232 } 233 if (!obj->dknown) 234 break; 235 if (nn) { 236 Strcat(buf, " of "); 237 Strcat(buf, an); 238 } else if (un) { 239 Strcat(buf, " called "); 240 Strcat(buf, un); 241 } else { 242 Strcat(buf, " labeled "); 243 Strcat(buf, dn); 244 } 245 break; 246 case WAND_SYM: 247 if (!obj->dknown) 248 Sprintf(buf, "wand"); 249 else if (nn) 250 Sprintf(buf, "wand of %s", an); 251 else if (un) 252 Sprintf(buf, "wand called %s", un); 253 else 254 Sprintf(buf, "%s wand", dn); 255 break; 256 case RING_SYM: 257 if (!obj->dknown) 258 Sprintf(buf, "ring"); 259 else if (nn) 260 Sprintf(buf, "ring of %s", an); 261 else if (un) 262 Sprintf(buf, "ring called %s", un); 263 else 264 Sprintf(buf, "%s ring", dn); 265 break; 266 case GEM_SYM: 267 if (!obj->dknown) { 268 Strcpy(buf, "gem"); 269 break; 270 } 271 if (!nn) { 272 Sprintf(buf, "%s gem", dn); 273 break; 274 } 275 Strcpy(buf, an); 276 if (obj->otyp >= TURQUOISE && obj->otyp <= JADE) 277 Strcat(buf, " stone"); 278 break; 279 default: 280 Sprintf(buf, "glorkum %c (0%o) %u %d", 281 obj->olet, obj->olet, obj->otyp, obj->spe); 282 } 283 if (pl) { 284 char *p; 285 286 for (p = buf; *p; p++) { 287 if (!strncmp(" of ", p, 4)) { 288 /* pieces of, cloves of, lumps of */ 289 int c1, c2 = 's'; 290 291 do { 292 c1 = c2; 293 c2 = *p; 294 *p++ = c1; 295 } while (c1); 296 goto nopl; 297 } 298 } 299 p = eos(buf) - 1; 300 if (*p == 's' || *p == 'z' || *p == 'x' || 301 (*p == 'h' && p[-1] == 's')) 302 Strcat(buf, "es"); /* boxes */ 303 else if (*p == 'y' && !strchr(vowels, p[-1])) 304 Strcpy(p, "ies"); /* rubies, zruties */ 305 else 306 Strcat(buf, "s"); 307 } 308 nopl: 309 if (obj->onamelth) { 310 Strcat(buf, " named "); 311 Strcat(buf, ONAME(obj)); 312 } 313 return (buf); 314 } 315 316 char * 317 doname(obj) 318 struct obj *obj; 319 { 320 char prefix[PREFIX]; 321 char *bp = xname(obj); 322 if (obj->quan != 1) 323 Sprintf(prefix, "%u ", obj->quan); 324 else 325 Strcpy(prefix, "a "); 326 switch (obj->olet) { 327 case AMULET_SYM: 328 if (strncmp(bp, "cheap ", 6)) 329 Strcpy(prefix, "the "); 330 break; 331 case ARMOR_SYM: 332 if (obj->owornmask & W_ARMOR) 333 Strcat(bp, " (being worn)"); 334 /* fall into next case */ 335 case WEAPON_SYM: 336 if (obj->known) { 337 Strcat(prefix, sitoa(obj->spe)); 338 Strcat(prefix, " "); 339 } 340 break; 341 case WAND_SYM: 342 if (obj->known) 343 Sprintf(eos(bp), " (%d)", obj->spe); 344 break; 345 case RING_SYM: 346 if (obj->owornmask & W_RINGR) 347 Strcat(bp, " (on right hand)"); 348 if (obj->owornmask & W_RINGL) 349 Strcat(bp, " (on left hand)"); 350 if (obj->known && (objects[obj->otyp].bits & SPEC)) { 351 Strcat(prefix, sitoa(obj->spe)); 352 Strcat(prefix, " "); 353 } 354 break; 355 } 356 if (obj->owornmask & W_WEP) 357 Strcat(bp, " (weapon in hand)"); 358 if (obj->unpaid) 359 Strcat(bp, " (unpaid)"); 360 if (!strcmp(prefix, "a ") && strchr(vowels, *bp)) 361 Strcpy(prefix, "an "); 362 bp = strprepend(bp, prefix); 363 return (bp); 364 } 365 366 /* used only in hack.fight.c (thitu) */ 367 void 368 setan(const char *str, char *buf) 369 { 370 if (strchr(vowels, *str)) 371 Sprintf(buf, "an %s", str); 372 else 373 Sprintf(buf, "a %s", str); 374 } 375 376 char * 377 aobjnam(otmp, verb) 378 struct obj *otmp; 379 const char *verb; 380 { 381 char *bp = xname(otmp); 382 char prefix[PREFIX]; 383 if (otmp->quan != 1) { 384 Sprintf(prefix, "%u ", otmp->quan); 385 bp = strprepend(bp, prefix); 386 } 387 if (verb) { 388 /* verb is given in plural (i.e., without trailing s) */ 389 Strcat(bp, " "); 390 if (otmp->quan != 1) 391 Strcat(bp, verb); 392 else if (!strcmp(verb, "are")) 393 Strcat(bp, "is"); 394 else { 395 Strcat(bp, verb); 396 Strcat(bp, "s"); 397 } 398 } 399 return (bp); 400 } 401 402 char * 403 Doname(obj) 404 struct obj *obj; 405 { 406 char *s = doname(obj); 407 408 if ('a' <= *s && *s <= 'z') 409 *s -= ('a' - 'A'); 410 return (s); 411 } 412 413 const char *const wrp[] = {"wand", "ring", "potion", "scroll", "gem"}; 414 const char wrpsym[] = {WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM}; 415 416 struct obj * 417 readobjnam(bp) 418 char *bp; 419 { 420 char *p; 421 int i; 422 int cnt, spe, spesgn, typ, heavy; 423 char let; 424 char *un, *dn, *an; 425 /* int the = 0; char *oname = 0; */ 426 cnt = spe = spesgn = typ = heavy = 0; 427 let = 0; 428 an = dn = un = 0; 429 for (p = bp; *p; p++) 430 if ('A' <= *p && *p <= 'Z') 431 *p += 'a' - 'A'; 432 if (!strncmp(bp, "the ", 4)) { 433 /* the = 1; */ 434 bp += 4; 435 } else if (!strncmp(bp, "an ", 3)) { 436 cnt = 1; 437 bp += 3; 438 } else if (!strncmp(bp, "a ", 2)) { 439 cnt = 1; 440 bp += 2; 441 } 442 if (!cnt && digit(*bp)) { 443 cnt = atoi(bp); 444 while (digit(*bp)) 445 bp++; 446 while (*bp == ' ') 447 bp++; 448 } 449 if (!cnt) 450 cnt = 1; /* %% what with "gems" etc. ? */ 451 452 if (*bp == '+' || *bp == '-') { 453 spesgn = (*bp++ == '+') ? 1 : -1; 454 spe = atoi(bp); 455 while (digit(*bp)) 456 bp++; 457 while (*bp == ' ') 458 bp++; 459 } else { 460 p = strrchr(bp, '('); 461 if (p) { 462 if (p > bp && p[-1] == ' ') 463 p[-1] = 0; 464 else 465 *p = 0; 466 p++; 467 spe = atoi(p); 468 while (digit(*p)) 469 p++; 470 if (strcmp(p, ")")) 471 spe = 0; 472 else 473 spesgn = 1; 474 } 475 } 476 /* 477 * now we have the actual name, as delivered by xname, say green 478 * potions called whisky scrolls labeled "QWERTY" egg dead zruties 479 * fortune cookies very heavy iron ball named hoei wand of wishing 480 * elven cloak 481 */ 482 for (p = bp; *p; p++) 483 if (!strncmp(p, " named ", 7)) { 484 *p = 0; 485 /* oname = p+7; */ 486 } 487 for (p = bp; *p; p++) 488 if (!strncmp(p, " called ", 8)) { 489 *p = 0; 490 un = p + 8; 491 } 492 for (p = bp; *p; p++) 493 if (!strncmp(p, " labeled ", 9)) { 494 *p = 0; 495 dn = p + 9; 496 } 497 /* first change to singular if necessary */ 498 if (cnt != 1) { 499 /* find "cloves of garlic", "worthless pieces of blue glass" */ 500 for (p = bp; *p; p++) 501 if (!strncmp(p, "s of ", 5)) { 502 while ((*p = p[1]) != '\0') 503 p++; 504 goto sing; 505 } 506 /* remove -s or -es (boxes) or -ies (rubies, zruties) */ 507 p = eos(bp); 508 if (p[-1] == 's') { 509 if (p[-2] == 'e') { 510 if (p[-3] == 'i') { 511 if (!strcmp(p - 7, "cookies")) 512 goto mins; 513 Strcpy(p - 3, "y"); 514 goto sing; 515 } 516 /* note: cloves / knives from clove / knife */ 517 if (!strcmp(p - 6, "knives")) { 518 Strcpy(p - 3, "fe"); 519 goto sing; 520 } 521 /* note: nurses, axes but boxes */ 522 if (!strcmp(p - 5, "boxes")) { 523 p[-2] = 0; 524 goto sing; 525 } 526 } 527 mins: 528 p[-1] = 0; 529 } else { 530 if (!strcmp(p - 9, "homunculi")) { 531 Strcpy(p - 1, "us"); /* !! makes string 532 * longer */ 533 goto sing; 534 } 535 if (!strcmp(p - 5, "teeth")) { 536 Strcpy(p - 5, "tooth"); 537 goto sing; 538 } 539 /* here we cannot find the plural suffix */ 540 } 541 } 542 sing: 543 if (!strcmp(bp, "amulet of yendor")) { 544 typ = AMULET_OF_YENDOR; 545 goto typfnd; 546 } 547 p = eos(bp); 548 if (!strcmp(p - 5, " mail")) { /* Note: ring mail is not a ring ! */ 549 let = ARMOR_SYM; 550 an = bp; 551 goto srch; 552 } 553 for (i = 0; i < sizeof(wrpsym); i++) { 554 int j = strlen(wrp[i]); 555 if (!strncmp(bp, wrp[i], j)) { 556 let = wrpsym[i]; 557 bp += j; 558 if (!strncmp(bp, " of ", 4)) 559 an = bp + 4; 560 /* else if(*bp) ?? */ 561 goto srch; 562 } 563 if (!strcmp(p - j, wrp[i])) { 564 let = wrpsym[i]; 565 p -= j; 566 *p = 0; 567 if (p[-1] == ' ') 568 p[-1] = 0; 569 dn = bp; 570 goto srch; 571 } 572 } 573 if (!strcmp(p - 6, " stone")) { 574 p[-6] = 0; 575 let = GEM_SYM; 576 an = bp; 577 goto srch; 578 } 579 if (!strcmp(bp, "very heavy iron ball")) { 580 heavy = 1; 581 typ = HEAVY_IRON_BALL; 582 goto typfnd; 583 } 584 an = bp; 585 srch: 586 if (!an && !dn && !un) 587 goto any; 588 i = 1; 589 if (let) 590 i = bases[letindex(let)]; 591 while (i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)) { 592 const char *zn = objects[i].oc_name; 593 594 if (!zn) 595 goto nxti; 596 if (an && strcmp(an, zn)) 597 goto nxti; 598 if (dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn))) 599 goto nxti; 600 if (un && (!(zn = objects[i].oc_uname) || strcmp(un, zn))) 601 goto nxti; 602 typ = i; 603 goto typfnd; 604 nxti: 605 i++; 606 } 607 any: 608 if (!let) 609 let = wrpsym[rn2(sizeof(wrpsym))]; 610 typ = probtype(let); 611 typfnd: 612 { 613 struct obj *otmp; 614 let = objects[typ].oc_olet; 615 otmp = mksobj(typ); 616 if (heavy) 617 otmp->owt += 15; 618 if (cnt > 0 && strchr("%?!*)", let) && 619 (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20))) 620 otmp->quan = cnt; 621 622 if (spe > 3 && spe > otmp->spe) 623 spe = 0; 624 else if (let == WAND_SYM) 625 spe = otmp->spe; 626 if (spe == 3 && u.uluck < 0) 627 spesgn = -1; 628 if (let != WAND_SYM && spesgn == -1) 629 spe = -spe; 630 if (let == BALL_SYM) 631 spe = 0; 632 else if (let == AMULET_SYM) 633 spe = -1; 634 else if (typ == WAN_WISHING && rn2(10)) 635 spe = (rn2(10) ? -1 : 0); 636 otmp->spe = spe; 637 638 if (spesgn == -1) 639 otmp->cursed = 1; 640 641 return (otmp); 642 } 643 } 644