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