wbsio(4): convert to Newbus and DragonFly -- welcome wbsio(4)!
[dragonfly.git] / games / rogue / inventory.c
blobe2c02c956c9a8fdf4870317df46cd0cc93ad36cc
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. 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.
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.
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 * $DragonFly: src/games/rogue/inventory.c,v 1.4 2006/09/02 19:31:07 pavalos Exp $
38 * inventory.c
40 * This source herein may be modified and/or distributed by anybody who
41 * so desires, with the following restrictions:
42 * 1.) No portion of this notice shall be removed.
43 * 2.) Credit shall not be taken for the creation of this source.
44 * 3.) This code is not to be traded, sold, or used for personal
45 * gain or profit.
49 #include "rogue.h"
51 static boolean pr_com_id(int);
52 static boolean get_com_id(int *, short);
53 static boolean pr_motion_char(int);
55 boolean is_wood[WANDS];
56 const char *press_space = " --press space to continue--";
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 "teak ",
75 "oak ",
76 "cherry ",
77 "birch ",
78 "pine ",
79 "cedar ",
80 "redwood ",
81 "balsa ",
82 "ivory ",
83 "walnut ",
84 "maple ",
85 "mahogany ",
86 "elm ",
87 "palm ",
88 "wooden "
91 const char *const gems[GEMS] = {
92 "diamond ",
93 "stibotantalite ",
94 "lapi-lazuli ",
95 "ruby ",
96 "emerald ",
97 "sapphire ",
98 "amethyst ",
99 "quartz ",
100 "tiger-eye ",
101 "opal ",
102 "agate ",
103 "turquoise ",
104 "pearl ",
105 "garnet "
108 const char *const syllables[MAXSYLLABLES] = {
109 "blech ",
110 "foo ",
111 "barf ",
112 "rech ",
113 "bar ",
114 "blech ",
115 "quo ",
116 "bloto ",
117 "oh ",
118 "caca ",
119 "blorp ",
120 "erp ",
121 "festr ",
122 "rot ",
123 "slie ",
124 "snorf ",
125 "iky ",
126 "yuky ",
127 "ooze ",
128 "ah ",
129 "bahl ",
130 "zep ",
131 "druhl ",
132 "flem ",
133 "behil ",
134 "arek ",
135 "mep ",
136 "zihr ",
137 "grit ",
138 "kona ",
139 "kini ",
140 "ichi ",
141 "tims ",
142 "ogr ",
143 "oo ",
144 "ighr ",
145 "coph ",
146 "swerr ",
147 "mihln ",
148 "poxi "
151 #define COMS 48
153 struct id_com_s {
154 short com_char;
155 const char *com_desc;
158 const struct id_com_s com_id_tab[COMS] = {
159 { '?', "? prints help" },
160 { 'r', "r read scroll" },
161 { '/', "/ identify object" },
162 { 'e', "e eat food" },
163 { 'h', "h left " },
164 { 'w', "w wield a weapon" },
165 { 'j', "j down" },
166 { 'W', "W wear armor" },
167 { 'k', "k up" },
168 { 'T', "T take armor off" },
169 { 'l', "l right" },
170 { 'P', "P put on ring" },
171 { 'y', "y up & left" },
172 { 'R', "R remove ring" },
173 { 'u', "u up & right" },
174 { 'd', "d drop object" },
175 { 'b', "b down & left" },
176 { 'c', "c call object" },
177 { 'n', "n down & right" },
178 { '\0', "<SHIFT><dir>: run that way" },
179 { ')', ") print current weapon" },
180 { '\0', "<CTRL><dir>: run till adjacent" },
181 { ']', "] print current armor" },
182 { 'f', "f<dir> fight till death or near death" },
183 { '=', "= print current rings" },
184 { 't', "t<dir> throw something" },
185 { '\001', "^A print Hp-raise average" },
186 { 'm', "m<dir> move onto without picking up" },
187 { 'z', "z<dir> zap a wand in a direction" },
188 { 'o', "o examine/set options" },
189 { '^', "^<dir> identify trap type" },
190 { '\022', "^R redraw screen" },
191 { '&', "& save screen into 'rogue.screen'" },
192 { 's', "s search for trap/secret door" },
193 { '\020', "^P repeat last message" },
194 { '>', "> go down a staircase" },
195 { '\033', "^[ cancel command" },
196 { '<', "< go up a staircase" },
197 { 'S', "S save game" },
198 { '.', ". rest for a turn" },
199 { 'Q', "Q quit" },
200 { ',', ", pick something up" },
201 { '!', "! shell escape" },
202 { 'i', "i inventory" },
203 { 'F', "F<dir> fight till either of you dies" },
204 { 'I', "I inventory single item" },
205 { 'v', "v print version number" },
206 { 'q', "q quaff potion" }
209 extern boolean wizard;
210 extern char *m_names[], *more;
212 void
213 inventory(const object *pack, unsigned short mask)
215 object *obj;
216 short i = 0, j, maxlen = 0, n;
217 char descs[MAX_PACK_COUNT+1][DCOLS];
218 short row, col;
220 obj = pack->next_object;
222 if (!obj) {
223 message("your pack is empty", 0);
224 return;
226 while (obj) {
227 if (obj->what_is & mask) {
228 descs[i][0] = ' ';
229 descs[i][1] = obj->ichar;
230 descs[i][2] = ((obj->what_is & ARMOR) && obj->is_protected)
231 ? '}' : ')';
232 descs[i][3] = ' ';
233 get_desc(obj, descs[i]+4);
234 if ((n = strlen(descs[i])) > maxlen) {
235 maxlen = n;
237 i++;
239 obj = obj->next_object;
241 strcpy(descs[i++], press_space);
242 if (maxlen < 27) maxlen = 27;
243 col = DCOLS - (maxlen + 2);
245 for (row = 0; ((row < i) && (row < DROWS)); row++) {
246 if (row > 0) {
247 for (j = col; j < DCOLS; j++) {
248 descs[row-1][j-col] = mvinch(row, j);
250 descs[row-1][j-col] = 0;
252 mvaddstr(row, col, descs[row]);
253 clrtoeol();
255 refresh();
256 wait_for_ack();
258 move(0, 0);
259 clrtoeol();
261 for (j = 1; ((j < i) && (j < DROWS)); j++) {
262 mvaddstr(j, col, descs[j-1]);
266 void
267 id_com(void)
269 int ch = 0;
270 short i, j, k;
272 while (ch != CANCEL) {
273 check_message();
274 message("Character you want help for (* for all):", 0);
276 refresh();
277 ch = getchar();
279 switch(ch) {
280 case LIST:
282 char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
283 short rows = (((COMS / 2) + (COMS % 2)) + 1);
284 boolean need_two_screens = FALSE;
286 if (rows > LINES) {
287 need_two_screens = 1;
288 rows = LINES;
290 k = 0;
292 for (i = 0; i < rows; i++) {
293 for (j = 0; j < DCOLS; j++) {
294 save[i][j] = mvinch(i, j);
297 MORE:
298 for (i = 0; i < rows; i++) {
299 move(i, 0);
300 clrtoeol();
302 for (i = 0; i < (rows-1); i++) {
303 if (i < (LINES-1)) {
304 if (((i + i) < COMS) && ((i+i+k) < COMS)) {
305 mvaddstr(i, 0, com_id_tab[i+i+k].com_desc);
307 if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) {
308 mvaddstr(i, (DCOLS/2),
309 com_id_tab[i+i+k+1].com_desc);
313 mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
314 refresh();
315 wait_for_ack();
317 if (need_two_screens) {
318 k += ((rows-1) * 2);
319 need_two_screens = 0;
320 goto MORE;
322 for (i = 0; i < rows; i++) {
323 move(i, 0);
324 for (j = 0; j < DCOLS; j++) {
325 addch(save[i][j]);
329 break;
330 default:
331 if (!pr_com_id(ch)) {
332 if (!pr_motion_char(ch)) {
333 check_message();
334 message("unknown character", 0);
337 ch = CANCEL;
338 break;
343 static boolean
344 pr_com_id(int ch)
346 int i;
348 if (!get_com_id(&i, ch)) {
349 return(0);
351 check_message();
352 message(com_id_tab[i].com_desc, 0);
353 return(1);
356 static boolean
357 get_com_id(int *idx, short ch)
359 short i;
361 for (i = 0; i < COMS; i++) {
362 if (com_id_tab[i].com_char == ch) {
363 *idx = i;
364 return(1);
367 return(0);
370 static boolean
371 pr_motion_char(int ch)
373 if ( (ch == 'J') ||
374 (ch == 'K') ||
375 (ch == 'L') ||
376 (ch == 'H') ||
377 (ch == 'Y') ||
378 (ch == 'U') ||
379 (ch == 'N') ||
380 (ch == 'B') ||
381 (ch == '\012') ||
382 (ch == '\013') ||
383 (ch == '\010') ||
384 (ch == '\014') ||
385 (ch == '\025') ||
386 (ch == '\031') ||
387 (ch == '\016') ||
388 (ch == '\002')) {
389 char until[18], buf[DCOLS];
390 int n;
392 if (ch <= '\031') {
393 ch += 96;
394 strcpy(until, "until adjascent");
395 } else {
396 ch += 32;
397 until[0] = '\0';
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);
409 void
410 mix_colors(void)
412 short i, j, k;
413 char *t[MAX_ID_TITLE_LEN];
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);
423 void
424 make_scroll_titles(void)
426 short i, j, n;
427 short sylls, s;
429 for (i = 0; i < SCROLS; i++) {
430 sylls = get_rand(2, 5);
431 strcpy(id_scrolls[i].title, "'");
433 for (j = 0; j < sylls; j++) {
434 s = get_rand(1, (MAXSYLLABLES-1));
435 strcat(id_scrolls[i].title, syllables[s]);
437 n = strlen(id_scrolls[i].title);
438 strcpy(id_scrolls[i].title+(n-1), "' ");
442 void
443 get_desc(const object *obj, char *desc)
445 const char *item_name;
446 struct id *id_table;
447 char more_info[32];
448 short i;
450 if (obj->what_is == AMULET) {
451 strcpy(desc, "the amulet of Yendor ");
452 return;
454 item_name = name_of(obj);
456 if (obj->what_is == GOLD) {
457 sprintf(desc, "%d pieces of gold", obj->quantity);
458 return;
461 if (obj->what_is != ARMOR) {
462 if (obj->quantity == 1) {
463 strcpy(desc, "a ");
464 } else {
465 sprintf(desc, "%d ", obj->quantity);
468 if (obj->what_is == FOOD) {
469 if (obj->which_kind == RATION) {
470 if (obj->quantity > 1) {
471 sprintf(desc, "%d rations of ", obj->quantity);
472 } else {
473 strcpy(desc, "some ");
475 } else {
476 strcpy(desc, "a ");
478 strcat(desc, item_name);
479 goto ANA;
481 id_table = get_id_table(obj);
483 if (wizard) {
484 goto ID;
486 if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
487 goto CHECK;
490 switch(id_table[obj->which_kind].id_status) {
491 case UNIDENTIFIED:
492 CHECK:
493 switch(obj->what_is) {
494 case SCROL:
495 strcat(desc, item_name);
496 strcat(desc, "entitled: ");
497 strcat(desc, id_table[obj->which_kind].title);
498 break;
499 case POTION:
500 strcat(desc, id_table[obj->which_kind].title);
501 strcat(desc, item_name);
502 break;
503 case WAND:
504 case RING:
505 if (obj->identified ||
506 (id_table[obj->which_kind].id_status == IDENTIFIED)) {
507 goto ID;
509 if (id_table[obj->which_kind].id_status == CALLED) {
510 goto CALL;
512 strcat(desc, id_table[obj->which_kind].title);
513 strcat(desc, item_name);
514 break;
515 case ARMOR:
516 if (obj->identified) {
517 goto ID;
519 strcpy(desc, id_table[obj->which_kind].title);
520 break;
521 case WEAPON:
522 if (obj->identified) {
523 goto ID;
525 strcat(desc, name_of(obj));
526 break;
528 break;
529 case CALLED:
530 CALL: switch(obj->what_is) {
531 case SCROL:
532 case POTION:
533 case WAND:
534 case RING:
535 strcat(desc, item_name);
536 strcat(desc, "called ");
537 strcat(desc, id_table[obj->which_kind].title);
538 break;
540 break;
541 case IDENTIFIED:
542 ID: switch(obj->what_is) {
543 case SCROL:
544 case POTION:
545 strcat(desc, item_name);
546 strcat(desc, id_table[obj->which_kind].real);
547 break;
548 case RING:
549 if (wizard || obj->identified) {
550 if ((obj->which_kind == DEXTERITY) ||
551 (obj->which_kind == ADD_STRENGTH)) {
552 sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
553 obj->class);
554 strcat(desc, more_info);
557 strcat(desc, item_name);
558 strcat(desc, id_table[obj->which_kind].real);
559 break;
560 case WAND:
561 strcat(desc, item_name);
562 strcat(desc, id_table[obj->which_kind].real);
563 if (wizard || obj->identified) {
564 sprintf(more_info, "[%d]", obj->class);
565 strcat(desc, more_info);
567 break;
568 case ARMOR:
569 sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""),
570 obj->d_enchant);
571 strcat(desc, id_table[obj->which_kind].title);
572 sprintf(more_info, "[%d] ", get_armor_class(obj));
573 strcat(desc, more_info);
574 break;
575 case WEAPON:
576 sprintf(desc+strlen(desc), "%s%d,%s%d ",
577 ((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant,
578 ((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant);
579 strcat(desc, name_of(obj));
580 break;
582 break;
584 ANA:
585 if (!strncmp(desc, "a ", 2)) {
586 if (is_vowel(desc[2])) {
587 for (i = strlen(desc) + 1; i > 1; i--) {
588 desc[i] = desc[i-1];
590 desc[1] = 'n';
593 if (obj->in_use_flags & BEING_WIELDED) {
594 strcat(desc, "in hand");
595 } else if (obj->in_use_flags & BEING_WORN) {
596 strcat(desc, "being worn");
597 } else if (obj->in_use_flags & ON_LEFT_HAND) {
598 strcat(desc, "on left hand");
599 } else if (obj->in_use_flags & ON_RIGHT_HAND) {
600 strcat(desc, "on right hand");
604 void
605 get_wand_and_ring_materials(void)
607 short i, j;
608 boolean used[WAND_MATERIALS];
610 for (i = 0; i < WAND_MATERIALS; i++) {
611 used[i] = 0;
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 strcpy(id_wands[i].title, wand_materials[j]);
619 is_wood[i] = (j > MAX_METAL);
621 for (i = 0; i < GEMS; i++) {
622 used[i] = 0;
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 strcpy(id_rings[i].title, gems[j]);
633 void
634 single_inv(short ichar)
636 short ch;
637 char desc[DCOLS];
638 object *obj;
640 ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
642 if (ch == CANCEL) {
643 return;
645 if (!(obj = get_letter_object(ch))) {
646 message("no such item.", 0);
647 return;
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);
657 struct id *
658 get_id_table(const object *obj)
660 switch(obj->what_is) {
661 case SCROL:
662 return(id_scrolls);
663 case POTION:
664 return(id_potions);
665 case WAND:
666 return(id_wands);
667 case RING:
668 return(id_rings);
669 case WEAPON:
670 return(id_weapons);
671 case ARMOR:
672 return(id_armors);
674 return(NULL);
677 void
678 inv_armor_weapon(boolean is_weapon)
680 if (is_weapon) {
681 if (rogue.weapon) {
682 single_inv(rogue.weapon->ichar);
683 } else {
684 message("not wielding anything", 0);
686 } else {
687 if (rogue.armor) {
688 single_inv(rogue.armor->ichar);
689 } else {
690 message("not wearing anything", 0);
695 void
696 id_type(void)
698 const char *id;
699 int ch;
700 char buf[DCOLS];
702 message("what do you want identified?", 0);
704 ch = rgetchar();
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;
770 check_message();
771 sprintf(buf, "'%c': %s", ch, id);
772 message(buf, 0);