1 /*- 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Timothy C. Stoehr. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)inventory.c 8.1 (Berkeley) 5/31/93 33 * $FreeBSD: src/games/rogue/inventory.c,v 1.4 1999/11/30 03:49:23 billf Exp $ 34 */ 35 36 /* 37 * inventory.c 38 * 39 * This source herein may be modified and/or distributed by anybody who 40 * so desires, with the following restrictions: 41 * 1.) No portion of this notice shall be removed. 42 * 2.) Credit shall not be taken for the creation of this source. 43 * 3.) This code is not to be traded, sold, or used for personal 44 * gain or profit. 45 * 46 */ 47 48 #include "rogue.h" 49 50 boolean is_wood[WANDS]; 51 const char *press_space = " --press space to continue--"; 52 53 static const char *const wand_materials[WAND_MATERIALS] = { 54 "steel ", 55 "bronze ", 56 "gold ", 57 "silver ", 58 "copper ", 59 "nickel ", 60 "cobalt ", 61 "tin ", 62 "iron ", 63 "magnesium ", 64 "chrome ", 65 "carbon ", 66 "platinum ", 67 "silicon ", 68 "titanium ", 69 "teak ", 70 "oak ", 71 "cherry ", 72 "birch ", 73 "pine ", 74 "cedar ", 75 "redwood ", 76 "balsa ", 77 "ivory ", 78 "walnut ", 79 "maple ", 80 "mahogany ", 81 "elm ", 82 "palm ", 83 "wooden " 84 }; 85 86 static const char *const gems[GEMS] = { 87 "diamond ", 88 "stibotantalite ", 89 "lapi-lazuli ", 90 "ruby ", 91 "emerald ", 92 "sapphire ", 93 "amethyst ", 94 "quartz ", 95 "tiger-eye ", 96 "opal ", 97 "agate ", 98 "turquoise ", 99 "pearl ", 100 "garnet " 101 }; 102 103 static const char *const syllables[MAXSYLLABLES] = { 104 "blech ", 105 "foo ", 106 "barf ", 107 "rech ", 108 "bar ", 109 "blech ", 110 "quo ", 111 "bloto ", 112 "oh ", 113 "caca ", 114 "blorp ", 115 "erp ", 116 "festr ", 117 "rot ", 118 "slie ", 119 "snorf ", 120 "iky ", 121 "yuky ", 122 "ooze ", 123 "ah ", 124 "bahl ", 125 "zep ", 126 "druhl ", 127 "flem ", 128 "behil ", 129 "arek ", 130 "mep ", 131 "zihr ", 132 "grit ", 133 "kona ", 134 "kini ", 135 "ichi ", 136 "tims ", 137 "ogr ", 138 "oo ", 139 "ighr ", 140 "coph ", 141 "swerr ", 142 "mihln ", 143 "poxi " 144 }; 145 146 #define COMS 48 147 148 struct id_com_s { 149 short com_char; 150 const char *com_desc; 151 }; 152 153 static const struct id_com_s com_id_tab[COMS] = { 154 { '?', "? prints help" }, 155 { 'r', "r read scroll" }, 156 { '/', "/ identify object" }, 157 { 'e', "e eat food" }, 158 { 'h', "h left " }, 159 { 'w', "w wield a weapon" }, 160 { 'j', "j down" }, 161 { 'W', "W wear armor" }, 162 { 'k', "k up" }, 163 { 'T', "T take armor off" }, 164 { 'l', "l right" }, 165 { 'P', "P put on ring" }, 166 { 'y', "y up & left" }, 167 { 'R', "R remove ring" }, 168 { 'u', "u up & right" }, 169 { 'd', "d drop object" }, 170 { 'b', "b down & left" }, 171 { 'c', "c call object" }, 172 { 'n', "n down & right" }, 173 { '\0', "<SHIFT><dir>: run that way" }, 174 { ')', ") print current weapon" }, 175 { '\0', "<CTRL><dir>: run till adjacent" }, 176 { ']', "] print current armor" }, 177 { 'f', "f<dir> fight till death or near death" }, 178 { '=', "= print current rings" }, 179 { 't', "t<dir> throw something" }, 180 { '\001', "^A print Hp-raise average" }, 181 { 'm', "m<dir> move onto without picking up" }, 182 { 'z', "z<dir> zap a wand in a direction" }, 183 { 'o', "o examine/set options" }, 184 { '^', "^<dir> identify trap type" }, 185 { '\022', "^R redraw screen" }, 186 { '&', "& save screen into 'rogue.screen'" }, 187 { 's', "s search for trap/secret door" }, 188 { '\020', "^P repeat last message" }, 189 { '>', "> go down a staircase" }, 190 { '\033', "^[ cancel command" }, 191 { '<', "< go up a staircase" }, 192 { 'S', "S save game" }, 193 { '.', ". rest for a turn" }, 194 { 'Q', "Q quit" }, 195 { ',', ", pick something up" }, 196 { '!', "! shell escape" }, 197 { 'i', "i inventory" }, 198 { 'F', "F<dir> fight till either of you dies" }, 199 { 'I', "I inventory single item" }, 200 { 'v', "v print version number" }, 201 { 'q', "q quaff potion" } 202 }; 203 204 static boolean get_com_id(int *, short); 205 static boolean pr_com_id(int); 206 static boolean pr_motion_char(int); 207 208 void 209 inventory(const object *pack, unsigned short mask) 210 { 211 object *obj; 212 short i = 0, j, maxlen = 0, n; 213 char descs[MAX_PACK_COUNT+1][DCOLS]; 214 short row, col; 215 216 obj = pack->next_object; 217 218 if (!obj) { 219 message("your pack is empty", 0); 220 return; 221 } 222 while (obj) { 223 if (obj->what_is & mask) { 224 descs[i][0] = ' '; 225 descs[i][1] = obj->ichar; 226 descs[i][2] = ((obj->what_is & ARMOR) && obj->is_protected) 227 ? '}' : ')'; 228 descs[i][3] = ' '; 229 get_desc(obj, descs[i]+4); 230 if ((n = strlen(descs[i])) > maxlen) { 231 maxlen = n; 232 } 233 i++; 234 } 235 obj = obj->next_object; 236 } 237 strcpy(descs[i++], press_space); 238 if (maxlen < 27) maxlen = 27; 239 col = DCOLS - (maxlen + 2); 240 241 for (row = 0; ((row < i) && (row < DROWS)); row++) { 242 if (row > 0) { 243 for (j = col; j < DCOLS; j++) { 244 descs[row-1][j-col] = mvinch(row, j); 245 } 246 descs[row-1][j-col] = 0; 247 } 248 mvaddstr(row, col, descs[row]); 249 clrtoeol(); 250 } 251 refresh(); 252 wait_for_ack(); 253 254 move(0, 0); 255 clrtoeol(); 256 257 for (j = 1; ((j < i) && (j < DROWS)); j++) { 258 mvaddstr(j, col, descs[j-1]); 259 } 260 } 261 262 void 263 id_com(void) 264 { 265 int ch = 0; 266 short i, j, k; 267 268 while (ch != CANCEL) { 269 check_message(); 270 message("Character you want help for (* for all):", 0); 271 272 refresh(); 273 ch = getchar(); 274 275 switch(ch) { 276 case LIST: 277 { 278 char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS]; 279 short rows = (((COMS / 2) + (COMS % 2)) + 1); 280 boolean need_two_screens = FALSE; 281 282 if (rows > LINES) { 283 need_two_screens = 1; 284 rows = LINES; 285 } 286 k = 0; 287 288 for (i = 0; i < rows; i++) { 289 for (j = 0; j < DCOLS; j++) { 290 save[i][j] = mvinch(i, j); 291 } 292 } 293 MORE: 294 for (i = 0; i < rows; i++) { 295 move(i, 0); 296 clrtoeol(); 297 } 298 for (i = 0; i < (rows-1); i++) { 299 if (i < (LINES-1)) { 300 if (((i + i) < COMS) && ((i+i+k) < COMS)) { 301 mvaddstr(i, 0, com_id_tab[i+i+k].com_desc); 302 } 303 if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) { 304 mvaddstr(i, (DCOLS/2), 305 com_id_tab[i+i+k+1].com_desc); 306 } 307 } 308 } 309 mvaddstr(rows - 1, 0, need_two_screens ? more : press_space); 310 refresh(); 311 wait_for_ack(); 312 313 if (need_two_screens) { 314 k += ((rows-1) * 2); 315 need_two_screens = 0; 316 goto MORE; 317 } 318 for (i = 0; i < rows; i++) { 319 move(i, 0); 320 for (j = 0; j < DCOLS; j++) { 321 addch(save[i][j]); 322 } 323 } 324 } 325 break; 326 default: 327 if (!pr_com_id(ch)) { 328 if (!pr_motion_char(ch)) { 329 check_message(); 330 message("unknown character", 0); 331 } 332 } 333 ch = CANCEL; 334 break; 335 } 336 } 337 } 338 339 static boolean 340 pr_com_id(int ch) 341 { 342 int i; 343 344 if (!get_com_id(&i, ch)) { 345 return(0); 346 } 347 check_message(); 348 message(com_id_tab[i].com_desc, 0); 349 return(1); 350 } 351 352 static boolean 353 get_com_id(int *idx, short ch) 354 { 355 short i; 356 357 for (i = 0; i < COMS; i++) { 358 if (com_id_tab[i].com_char == ch) { 359 *idx = i; 360 return(1); 361 } 362 } 363 return(0); 364 } 365 366 static boolean 367 pr_motion_char(int ch) 368 { 369 if ( (ch == 'J') || 370 (ch == 'K') || 371 (ch == 'L') || 372 (ch == 'H') || 373 (ch == 'Y') || 374 (ch == 'U') || 375 (ch == 'N') || 376 (ch == 'B') || 377 (ch == '\012') || 378 (ch == '\013') || 379 (ch == '\010') || 380 (ch == '\014') || 381 (ch == '\025') || 382 (ch == '\031') || 383 (ch == '\016') || 384 (ch == '\002')) { 385 char until[18], buf[DCOLS]; 386 int n; 387 388 n = 0; 389 if (ch <= '\031') { 390 ch += 96; 391 strcpy(until, "until adjascent"); 392 } else { 393 ch += 32; 394 until[0] = '\0'; 395 } 396 get_com_id(&n, ch); 397 sprintf(buf, "run %s %s", com_id_tab[n].com_desc + 8, until); 398 check_message(); 399 message(buf, 0); 400 return(1); 401 } else { 402 return(0); 403 } 404 } 405 406 void 407 mix_colors(void) 408 { 409 short i, j, k; 410 char *t[MAX_ID_TITLE_LEN]; 411 412 for (i = 0; i <= 32; i++) { 413 j = get_rand(0, (POTIONS - 1)); 414 k = get_rand(0, (POTIONS - 1)); 415 memcpy(t, id_potions[j].title, MAX_ID_TITLE_LEN); 416 memcpy(id_potions[j].title, id_potions[k].title, MAX_ID_TITLE_LEN); 417 memcpy(id_potions[k].title, t, MAX_ID_TITLE_LEN); 418 } 419 } 420 421 void 422 make_scroll_titles(void) 423 { 424 short i, j, n; 425 short sylls, s; 426 427 for (i = 0; i < SCROLS; i++) { 428 sylls = get_rand(2, 5); 429 strcpy(id_scrolls[i].title, "'"); 430 431 for (j = 0; j < sylls; j++) { 432 s = get_rand(1, (MAXSYLLABLES-1)); 433 strcat(id_scrolls[i].title, syllables[s]); 434 } 435 n = strlen(id_scrolls[i].title); 436 strcpy(id_scrolls[i].title+(n-1), "' "); 437 } 438 } 439 440 void 441 get_desc(const object *obj, char *desc) 442 { 443 const char *item_name; 444 struct id *id_table; 445 char more_info[32]; 446 short i; 447 448 if (obj->what_is == AMULET) { 449 strcpy(desc, "the amulet of Yendor "); 450 return; 451 } 452 item_name = name_of(obj); 453 454 if (obj->what_is == GOLD) { 455 sprintf(desc, "%d pieces of gold", obj->quantity); 456 return; 457 } 458 459 if (obj->what_is != ARMOR) { 460 if (obj->quantity == 1) { 461 strcpy(desc, "a "); 462 } else { 463 sprintf(desc, "%d ", obj->quantity); 464 } 465 } 466 if (obj->what_is == FOOD) { 467 if (obj->which_kind == RATION) { 468 if (obj->quantity > 1) { 469 sprintf(desc, "%d rations of ", obj->quantity); 470 } else { 471 strcpy(desc, "some "); 472 } 473 } else { 474 strcpy(desc, "a "); 475 } 476 strcat(desc, item_name); 477 goto ANA; 478 } 479 id_table = get_id_table(obj); 480 481 if (wizard) { 482 goto ID; 483 } 484 if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) { 485 goto CHECK; 486 } 487 488 switch(id_table[obj->which_kind].id_status) { 489 case UNIDENTIFIED: 490 CHECK: 491 switch(obj->what_is) { 492 case SCROL: 493 strcat(desc, item_name); 494 strcat(desc, "entitled: "); 495 strcat(desc, id_table[obj->which_kind].title); 496 break; 497 case POTION: 498 strcat(desc, id_table[obj->which_kind].title); 499 strcat(desc, item_name); 500 break; 501 case WAND: 502 case RING: 503 if (obj->identified || 504 (id_table[obj->which_kind].id_status == IDENTIFIED)) { 505 goto ID; 506 } 507 if (id_table[obj->which_kind].id_status == CALLED) { 508 goto CALL; 509 } 510 strcat(desc, id_table[obj->which_kind].title); 511 strcat(desc, item_name); 512 break; 513 case ARMOR: 514 if (obj->identified) { 515 goto ID; 516 } 517 strcpy(desc, id_table[obj->which_kind].title); 518 break; 519 case WEAPON: 520 if (obj->identified) { 521 goto ID; 522 } 523 strcat(desc, name_of(obj)); 524 break; 525 } 526 break; 527 case CALLED: 528 CALL: switch(obj->what_is) { 529 case SCROL: 530 case POTION: 531 case WAND: 532 case RING: 533 strcat(desc, item_name); 534 strcat(desc, "called "); 535 strcat(desc, id_table[obj->which_kind].title); 536 break; 537 } 538 break; 539 case IDENTIFIED: 540 ID: switch(obj->what_is) { 541 case SCROL: 542 case POTION: 543 strcat(desc, item_name); 544 strcat(desc, id_table[obj->which_kind].real); 545 break; 546 case RING: 547 if (wizard || obj->identified) { 548 if ((obj->which_kind == DEXTERITY) || 549 (obj->which_kind == ADD_STRENGTH)) { 550 sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""), 551 obj->class); 552 strcat(desc, more_info); 553 } 554 } 555 strcat(desc, item_name); 556 strcat(desc, id_table[obj->which_kind].real); 557 break; 558 case WAND: 559 strcat(desc, item_name); 560 strcat(desc, id_table[obj->which_kind].real); 561 if (wizard || obj->identified) { 562 sprintf(more_info, "[%d]", obj->class); 563 strcat(desc, more_info); 564 } 565 break; 566 case ARMOR: 567 sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""), 568 obj->d_enchant); 569 strcat(desc, id_table[obj->which_kind].title); 570 sprintf(more_info, "[%d] ", get_armor_class(obj)); 571 strcat(desc, more_info); 572 break; 573 case WEAPON: 574 sprintf(desc+strlen(desc), "%s%d,%s%d ", 575 ((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant, 576 ((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant); 577 strcat(desc, name_of(obj)); 578 break; 579 } 580 break; 581 } 582 ANA: 583 if (!strncmp(desc, "a ", 2)) { 584 if (is_vowel(desc[2])) { 585 for (i = strlen(desc) + 1; i > 1; i--) { 586 desc[i] = desc[i-1]; 587 } 588 desc[1] = 'n'; 589 } 590 } 591 if (obj->in_use_flags & BEING_WIELDED) { 592 strcat(desc, "in hand"); 593 } else if (obj->in_use_flags & BEING_WORN) { 594 strcat(desc, "being worn"); 595 } else if (obj->in_use_flags & ON_LEFT_HAND) { 596 strcat(desc, "on left hand"); 597 } else if (obj->in_use_flags & ON_RIGHT_HAND) { 598 strcat(desc, "on right hand"); 599 } 600 } 601 602 void 603 get_wand_and_ring_materials(void) 604 { 605 short i, j; 606 boolean used[WAND_MATERIALS]; 607 608 for (i = 0; i < WAND_MATERIALS; i++) { 609 used[i] = 0; 610 } 611 for (i = 0; i < WANDS; i++) { 612 do { 613 j = get_rand(0, WAND_MATERIALS-1); 614 } while (used[j]); 615 used[j] = 1; 616 strcpy(id_wands[i].title, wand_materials[j]); 617 is_wood[i] = (j > MAX_METAL); 618 } 619 for (i = 0; i < GEMS; i++) { 620 used[i] = 0; 621 } 622 for (i = 0; i < RINGS; i++) { 623 do { 624 j = get_rand(0, GEMS-1); 625 } while (used[j]); 626 used[j] = 1; 627 strcpy(id_rings[i].title, gems[j]); 628 } 629 } 630 631 void 632 single_inv(short ichar) 633 { 634 short ch; 635 char desc[DCOLS]; 636 object *obj; 637 638 ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS); 639 640 if (ch == CANCEL) { 641 return; 642 } 643 if (!(obj = get_letter_object(ch))) { 644 message("no such item.", 0); 645 return; 646 } 647 desc[0] = ch; 648 desc[1] = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')'; 649 desc[2] = ' '; 650 desc[3] = 0; 651 get_desc(obj, desc+3); 652 message(desc, 0); 653 } 654 655 struct id * 656 get_id_table(const object *obj) 657 { 658 switch(obj->what_is) { 659 case SCROL: 660 return(id_scrolls); 661 case POTION: 662 return(id_potions); 663 case WAND: 664 return(id_wands); 665 case RING: 666 return(id_rings); 667 case WEAPON: 668 return(id_weapons); 669 case ARMOR: 670 return(id_armors); 671 } 672 return(NULL); 673 } 674 675 void 676 inv_armor_weapon(boolean is_weapon) 677 { 678 if (is_weapon) { 679 if (rogue.weapon) { 680 single_inv(rogue.weapon->ichar); 681 } else { 682 message("not wielding anything", 0); 683 } 684 } else { 685 if (rogue.armor) { 686 single_inv(rogue.armor->ichar); 687 } else { 688 message("not wearing anything", 0); 689 } 690 } 691 } 692 693 void 694 id_type(void) 695 { 696 const char *id; 697 int ch; 698 char buf[DCOLS]; 699 700 message("what do you want identified?", 0); 701 702 ch = rgetchar(); 703 704 if ((ch >= 'A') && (ch <= 'Z')) { 705 id = m_names[ch-'A']; 706 } else if (ch < 32) { 707 check_message(); 708 return; 709 } else { 710 switch(ch) { 711 case '@': 712 id = "you"; 713 break; 714 case '%': 715 id = "staircase"; 716 break; 717 case '^': 718 id = "trap"; 719 break; 720 case '+': 721 id = "door"; 722 break; 723 case '-': 724 case '|': 725 id = "wall of a room"; 726 break; 727 case '.': 728 id = "floor"; 729 break; 730 case '#': 731 id = "passage"; 732 break; 733 case ' ': 734 id = "solid rock"; 735 break; 736 case '=': 737 id = "ring"; 738 break; 739 case '?': 740 id = "scroll"; 741 break; 742 case '!': 743 id = "potion"; 744 break; 745 case '/': 746 id = "wand or staff"; 747 break; 748 case ')': 749 id = "weapon"; 750 break; 751 case ']': 752 id = "armor"; 753 break; 754 case '*': 755 id = "gold"; 756 break; 757 case ':': 758 id = "food"; 759 break; 760 case ',': 761 id = "the Amulet of Yendor"; 762 break; 763 default: 764 id = "unknown character"; 765 break; 766 } 767 } 768 check_message(); 769 sprintf(buf, "'%c': %s", ch, id); 770 message(buf, 0); 771 } 772