1 /* $NetBSD: hack.objnam.c,v 1.7 2008/01/28 06:55:42 dholland 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.7 2008/01/28 06:55:42 dholland 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 unsigned ii; 422 int i; 423 int cnt, spe, spesgn, typ, heavy; 424 char let; 425 char *un, *dn, *an; 426 /* int the = 0; char *oname = 0; */ 427 cnt = spe = spesgn = typ = heavy = 0; 428 let = 0; 429 an = dn = un = 0; 430 for (p = bp; *p; p++) 431 if ('A' <= *p && *p <= 'Z') 432 *p += 'a' - 'A'; 433 if (!strncmp(bp, "the ", 4)) { 434 /* the = 1; */ 435 bp += 4; 436 } else if (!strncmp(bp, "an ", 3)) { 437 cnt = 1; 438 bp += 3; 439 } else if (!strncmp(bp, "a ", 2)) { 440 cnt = 1; 441 bp += 2; 442 } 443 if (!cnt && digit(*bp)) { 444 cnt = atoi(bp); 445 while (digit(*bp)) 446 bp++; 447 while (*bp == ' ') 448 bp++; 449 } 450 if (!cnt) 451 cnt = 1; /* %% what with "gems" etc. ? */ 452 453 if (*bp == '+' || *bp == '-') { 454 spesgn = (*bp++ == '+') ? 1 : -1; 455 spe = atoi(bp); 456 while (digit(*bp)) 457 bp++; 458 while (*bp == ' ') 459 bp++; 460 } else { 461 p = strrchr(bp, '('); 462 if (p) { 463 if (p > bp && p[-1] == ' ') 464 p[-1] = 0; 465 else 466 *p = 0; 467 p++; 468 spe = atoi(p); 469 while (digit(*p)) 470 p++; 471 if (strcmp(p, ")")) 472 spe = 0; 473 else 474 spesgn = 1; 475 } 476 } 477 /* 478 * now we have the actual name, as delivered by xname, say green 479 * potions called whisky scrolls labeled "QWERTY" egg dead zruties 480 * fortune cookies very heavy iron ball named hoei wand of wishing 481 * elven cloak 482 */ 483 for (p = bp; *p; p++) 484 if (!strncmp(p, " named ", 7)) { 485 *p = 0; 486 /* oname = p+7; */ 487 } 488 for (p = bp; *p; p++) 489 if (!strncmp(p, " called ", 8)) { 490 *p = 0; 491 un = p + 8; 492 } 493 for (p = bp; *p; p++) 494 if (!strncmp(p, " labeled ", 9)) { 495 *p = 0; 496 dn = p + 9; 497 } 498 /* first change to singular if necessary */ 499 if (cnt != 1) { 500 /* find "cloves of garlic", "worthless pieces of blue glass" */ 501 for (p = bp; *p; p++) 502 if (!strncmp(p, "s of ", 5)) { 503 while ((*p = p[1]) != '\0') 504 p++; 505 goto sing; 506 } 507 /* remove -s or -es (boxes) or -ies (rubies, zruties) */ 508 p = eos(bp); 509 if (p[-1] == 's') { 510 if (p[-2] == 'e') { 511 if (p[-3] == 'i') { 512 if (!strcmp(p - 7, "cookies")) 513 goto mins; 514 Strcpy(p - 3, "y"); 515 goto sing; 516 } 517 /* note: cloves / knives from clove / knife */ 518 if (!strcmp(p - 6, "knives")) { 519 Strcpy(p - 3, "fe"); 520 goto sing; 521 } 522 /* note: nurses, axes but boxes */ 523 if (!strcmp(p - 5, "boxes")) { 524 p[-2] = 0; 525 goto sing; 526 } 527 } 528 mins: 529 p[-1] = 0; 530 } else { 531 if (!strcmp(p - 9, "homunculi")) { 532 Strcpy(p - 1, "us"); /* !! makes string 533 * longer */ 534 goto sing; 535 } 536 if (!strcmp(p - 5, "teeth")) { 537 Strcpy(p - 5, "tooth"); 538 goto sing; 539 } 540 /* here we cannot find the plural suffix */ 541 } 542 } 543 sing: 544 if (!strcmp(bp, "amulet of yendor")) { 545 typ = AMULET_OF_YENDOR; 546 goto typfnd; 547 } 548 p = eos(bp); 549 if (!strcmp(p - 5, " mail")) { /* Note: ring mail is not a ring ! */ 550 let = ARMOR_SYM; 551 an = bp; 552 goto srch; 553 } 554 for (ii = 0; ii < sizeof(wrpsym); ii++) { 555 int j = strlen(wrp[ii]); 556 if (!strncmp(bp, wrp[ii], j)) { 557 let = wrpsym[ii]; 558 bp += j; 559 if (!strncmp(bp, " of ", 4)) 560 an = bp + 4; 561 /* else if(*bp) ?? */ 562 goto srch; 563 } 564 if (!strcmp(p - j, wrp[ii])) { 565 let = wrpsym[ii]; 566 p -= j; 567 *p = 0; 568 if (p[-1] == ' ') 569 p[-1] = 0; 570 dn = bp; 571 goto srch; 572 } 573 } 574 if (!strcmp(p - 6, " stone")) { 575 p[-6] = 0; 576 let = GEM_SYM; 577 an = bp; 578 goto srch; 579 } 580 if (!strcmp(bp, "very heavy iron ball")) { 581 heavy = 1; 582 typ = HEAVY_IRON_BALL; 583 goto typfnd; 584 } 585 an = bp; 586 srch: 587 if (!an && !dn && !un) 588 goto any; 589 i = 1; 590 if (let) 591 i = bases[letindex(let)]; 592 while (i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)) { 593 const char *zn = objects[i].oc_name; 594 595 if (!zn) 596 goto nxti; 597 if (an && strcmp(an, zn)) 598 goto nxti; 599 if (dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn))) 600 goto nxti; 601 if (un && (!(zn = objects[i].oc_uname) || strcmp(un, zn))) 602 goto nxti; 603 typ = i; 604 goto typfnd; 605 nxti: 606 i++; 607 } 608 any: 609 if (!let) 610 let = wrpsym[rn2(sizeof(wrpsym))]; 611 typ = probtype(let); 612 typfnd: 613 { 614 struct obj *otmp; 615 let = objects[typ].oc_olet; 616 otmp = mksobj(typ); 617 if (heavy) 618 otmp->owt += 15; 619 if (cnt > 0 && strchr("%?!*)", let) && 620 (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20))) 621 otmp->quan = cnt; 622 623 if (spe > 3 && spe > otmp->spe) 624 spe = 0; 625 else if (let == WAND_SYM) 626 spe = otmp->spe; 627 if (spe == 3 && u.uluck < 0) 628 spesgn = -1; 629 if (let != WAND_SYM && spesgn == -1) 630 spe = -spe; 631 if (let == BALL_SYM) 632 spe = 0; 633 else if (let == AMULET_SYM) 634 spe = -1; 635 else if (typ == WAN_WISHING && rn2(10)) 636 spe = (rn2(10) ? -1 : 0); 637 otmp->spe = spe; 638 639 if (spesgn == -1) 640 otmp->cursed = 1; 641 642 return (otmp); 643 } 644 } 645