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