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