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