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