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