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