1 /* $NetBSD: hack.objnam.c,v 1.4 1997/10/19 16:58:39 christos 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.4 1997/10/19 16:58:39 christos 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 char *an = ocl->oc_name; 50 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 char *an = objects[obj->otyp].oc_name; 102 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(str, buf) 312 char *str, *buf; 313 { 314 if (strchr(vowels, *str)) 315 Sprintf(buf, "an %s", str); 316 else 317 Sprintf(buf, "a %s", str); 318 } 319 320 char * 321 aobjnam(otmp, verb) 322 struct obj *otmp; 323 char *verb; 324 { 325 char *bp = xname(otmp); 326 char prefix[PREFIX]; 327 if (otmp->quan != 1) { 328 Sprintf(prefix, "%u ", otmp->quan); 329 bp = strprepend(bp, prefix); 330 } 331 if (verb) { 332 /* verb is given in plural (i.e., without trailing s) */ 333 Strcat(bp, " "); 334 if (otmp->quan != 1) 335 Strcat(bp, verb); 336 else if (!strcmp(verb, "are")) 337 Strcat(bp, "is"); 338 else { 339 Strcat(bp, verb); 340 Strcat(bp, "s"); 341 } 342 } 343 return (bp); 344 } 345 346 char * 347 Doname(obj) 348 struct obj *obj; 349 { 350 char *s = doname(obj); 351 352 if ('a' <= *s && *s <= 'z') 353 *s -= ('a' - 'A'); 354 return (s); 355 } 356 357 char *wrp[] = {"wand", "ring", "potion", "scroll", "gem"}; 358 char wrpsym[] = {WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM}; 359 360 struct obj * 361 readobjnam(bp) 362 char *bp; 363 { 364 char *p; 365 int i; 366 int cnt, spe, spesgn, typ, heavy; 367 char let; 368 char *un, *dn, *an; 369 /* int the = 0; char *oname = 0; */ 370 cnt = spe = spesgn = typ = heavy = 0; 371 let = 0; 372 an = dn = un = 0; 373 for (p = bp; *p; p++) 374 if ('A' <= *p && *p <= 'Z') 375 *p += 'a' - 'A'; 376 if (!strncmp(bp, "the ", 4)) { 377 /* the = 1; */ 378 bp += 4; 379 } else if (!strncmp(bp, "an ", 3)) { 380 cnt = 1; 381 bp += 3; 382 } else if (!strncmp(bp, "a ", 2)) { 383 cnt = 1; 384 bp += 2; 385 } 386 if (!cnt && digit(*bp)) { 387 cnt = atoi(bp); 388 while (digit(*bp)) 389 bp++; 390 while (*bp == ' ') 391 bp++; 392 } 393 if (!cnt) 394 cnt = 1; /* %% what with "gems" etc. ? */ 395 396 if (*bp == '+' || *bp == '-') { 397 spesgn = (*bp++ == '+') ? 1 : -1; 398 spe = atoi(bp); 399 while (digit(*bp)) 400 bp++; 401 while (*bp == ' ') 402 bp++; 403 } else { 404 p = strrchr(bp, '('); 405 if (p) { 406 if (p > bp && p[-1] == ' ') 407 p[-1] = 0; 408 else 409 *p = 0; 410 p++; 411 spe = atoi(p); 412 while (digit(*p)) 413 p++; 414 if (strcmp(p, ")")) 415 spe = 0; 416 else 417 spesgn = 1; 418 } 419 } 420 /* 421 * now we have the actual name, as delivered by xname, say green 422 * potions called whisky scrolls labeled "QWERTY" egg dead zruties 423 * fortune cookies very heavy iron ball named hoei wand of wishing 424 * elven cloak 425 */ 426 for (p = bp; *p; p++) 427 if (!strncmp(p, " named ", 7)) { 428 *p = 0; 429 /* oname = p+7; */ 430 } 431 for (p = bp; *p; p++) 432 if (!strncmp(p, " called ", 8)) { 433 *p = 0; 434 un = p + 8; 435 } 436 for (p = bp; *p; p++) 437 if (!strncmp(p, " labeled ", 9)) { 438 *p = 0; 439 dn = p + 9; 440 } 441 /* first change to singular if necessary */ 442 if (cnt != 1) { 443 /* find "cloves of garlic", "worthless pieces of blue glass" */ 444 for (p = bp; *p; p++) 445 if (!strncmp(p, "s of ", 5)) { 446 while ((*p = p[1]) != '\0') 447 p++; 448 goto sing; 449 } 450 /* remove -s or -es (boxes) or -ies (rubies, zruties) */ 451 p = eos(bp); 452 if (p[-1] == 's') { 453 if (p[-2] == 'e') { 454 if (p[-3] == 'i') { 455 if (!strcmp(p - 7, "cookies")) 456 goto mins; 457 Strcpy(p - 3, "y"); 458 goto sing; 459 } 460 /* note: cloves / knives from clove / knife */ 461 if (!strcmp(p - 6, "knives")) { 462 Strcpy(p - 3, "fe"); 463 goto sing; 464 } 465 /* note: nurses, axes but boxes */ 466 if (!strcmp(p - 5, "boxes")) { 467 p[-2] = 0; 468 goto sing; 469 } 470 } 471 mins: 472 p[-1] = 0; 473 } else { 474 if (!strcmp(p - 9, "homunculi")) { 475 Strcpy(p - 1, "us"); /* !! makes string 476 * longer */ 477 goto sing; 478 } 479 if (!strcmp(p - 5, "teeth")) { 480 Strcpy(p - 5, "tooth"); 481 goto sing; 482 } 483 /* here we cannot find the plural suffix */ 484 } 485 } 486 sing: 487 if (!strcmp(bp, "amulet of yendor")) { 488 typ = AMULET_OF_YENDOR; 489 goto typfnd; 490 } 491 p = eos(bp); 492 if (!strcmp(p - 5, " mail")) { /* Note: ring mail is not a ring ! */ 493 let = ARMOR_SYM; 494 an = bp; 495 goto srch; 496 } 497 for (i = 0; i < sizeof(wrpsym); i++) { 498 int j = strlen(wrp[i]); 499 if (!strncmp(bp, wrp[i], j)) { 500 let = wrpsym[i]; 501 bp += j; 502 if (!strncmp(bp, " of ", 4)) 503 an = bp + 4; 504 /* else if(*bp) ?? */ 505 goto srch; 506 } 507 if (!strcmp(p - j, wrp[i])) { 508 let = wrpsym[i]; 509 p -= j; 510 *p = 0; 511 if (p[-1] == ' ') 512 p[-1] = 0; 513 dn = bp; 514 goto srch; 515 } 516 } 517 if (!strcmp(p - 6, " stone")) { 518 p[-6] = 0; 519 let = GEM_SYM; 520 an = bp; 521 goto srch; 522 } 523 if (!strcmp(bp, "very heavy iron ball")) { 524 heavy = 1; 525 typ = HEAVY_IRON_BALL; 526 goto typfnd; 527 } 528 an = bp; 529 srch: 530 if (!an && !dn && !un) 531 goto any; 532 i = 1; 533 if (let) 534 i = bases[letindex(let)]; 535 while (i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)) { 536 char *zn = objects[i].oc_name; 537 538 if (!zn) 539 goto nxti; 540 if (an && strcmp(an, zn)) 541 goto nxti; 542 if (dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn))) 543 goto nxti; 544 if (un && (!(zn = objects[i].oc_uname) || strcmp(un, zn))) 545 goto nxti; 546 typ = i; 547 goto typfnd; 548 nxti: 549 i++; 550 } 551 any: 552 if (!let) 553 let = wrpsym[rn2(sizeof(wrpsym))]; 554 typ = probtype(let); 555 typfnd: 556 { 557 struct obj *otmp; 558 let = objects[typ].oc_olet; 559 otmp = mksobj(typ); 560 if (heavy) 561 otmp->owt += 15; 562 if (cnt > 0 && strchr("%?!*)", let) && 563 (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20))) 564 otmp->quan = cnt; 565 566 if (spe > 3 && spe > otmp->spe) 567 spe = 0; 568 else if (let == WAND_SYM) 569 spe = otmp->spe; 570 if (spe == 3 && u.uluck < 0) 571 spesgn = -1; 572 if (let != WAND_SYM && spesgn == -1) 573 spe = -spe; 574 if (let == BALL_SYM) 575 spe = 0; 576 else if (let == AMULET_SYM) 577 spe = -1; 578 else if (typ == WAN_WISHING && rn2(10)) 579 spe = (rn2(10) ? -1 : 0); 580 otmp->spe = spe; 581 582 if (spesgn == -1) 583 otmp->cursed = 1; 584 585 return (otmp); 586 } 587 } 588