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