Sync usage with man page.
[netbsd-mini2440.git] / games / rogue / inventory.c
blobc6bfca93bdabe33f9cd0c4122a0d91d257f9cd5e
1 /* $NetBSD: inventory.c,v 1.13 2008/01/14 03:50:01 dholland Exp $ */
3 /*
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Timothy C. Stoehr.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)inventory.c 8.1 (Berkeley) 5/31/93";
39 #else
40 __RCSID("$NetBSD: inventory.c,v 1.13 2008/01/14 03:50:01 dholland Exp $");
41 #endif
42 #endif /* not lint */
45 * inventory.c
47 * This source herein may be modified and/or distributed by anybody who
48 * so desires, with the following restrictions:
49 * 1.) No portion of this notice shall be removed.
50 * 2.) Credit shall not be taken for the creation of this source.
51 * 3.) This code is not to be traded, sold, or used for personal
52 * gain or profit.
56 #include <stdarg.h>
57 #include "rogue.h"
59 boolean is_wood[WANDS];
60 const char *press_space = " --press space to continue--";
62 static 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 ",
79 "teak ",
80 "oak ",
81 "cherry ",
82 "birch ",
83 "pine ",
84 "cedar ",
85 "redwood ",
86 "balsa ",
87 "ivory ",
88 "walnut ",
89 "maple ",
90 "mahogany ",
91 "elm ",
92 "palm ",
93 "wooden "
96 static const char *const gems[GEMS] = {
97 "diamond ",
98 "stibotantalite ",
99 "lapi-lazuli ",
100 "ruby ",
101 "emerald ",
102 "sapphire ",
103 "amethyst ",
104 "quartz ",
105 "tiger-eye ",
106 "opal ",
107 "agate ",
108 "turquoise ",
109 "pearl ",
110 "garnet "
113 static const char *const syllables[MAXSYLLABLES] = {
114 "blech ",
115 "foo ",
116 "barf ",
117 "rech ",
118 "bar ",
119 "blech ",
120 "quo ",
121 "bloto ",
122 "oh ",
123 "caca ",
124 "blorp ",
125 "erp ",
126 "festr ",
127 "rot ",
128 "slie ",
129 "snorf ",
130 "iky ",
131 "yuky ",
132 "ooze ",
133 "ah ",
134 "bahl ",
135 "zep ",
136 "druhl ",
137 "flem ",
138 "behil ",
139 "arek ",
140 "mep ",
141 "zihr ",
142 "grit ",
143 "kona ",
144 "kini ",
145 "ichi ",
146 "tims ",
147 "ogr ",
148 "oo ",
149 "ighr ",
150 "coph ",
151 "swerr ",
152 "mihln ",
153 "poxi "
156 #define COMS 48
158 struct id_com_s {
159 short com_char;
160 const char *com_desc;
163 static const struct id_com_s com_id_tab[COMS] = {
164 {'?', "? prints help"},
165 {'r', "r read scroll"},
166 {'/', "/ identify object"},
167 {'e', "e eat food"},
168 {'h', "h left "},
169 {'w', "w wield a weapon"},
170 {'j', "j down"},
171 {'W', "W wear armor"},
172 {'k', "k up"},
173 {'T', "T take armor off"},
174 {'l', "l right"},
175 {'P', "P put on ring"},
176 {'y', "y up & left"},
177 {'R', "R remove ring"},
178 {'u', "u up & right"},
179 {'d', "d drop object"},
180 {'b', "b down & left"},
181 {'c', "c call object"},
182 {'n', "n down & right"},
183 {'\0', "<SHIFT><dir>: run that way"},
184 {')', ") print current weapon"},
185 {'\0', "<CTRL><dir>: run till adjacent"},
186 {']', "] print current armor"},
187 {'f', "f<dir> fight till death or near death"},
188 {'=', "= print current rings"},
189 {'t', "t<dir> throw something"},
190 {'\001', "^A print Hp-raise average"},
191 {'m', "m<dir> move onto without picking up"},
192 {'z', "z<dir> zap a wand in a direction"},
193 {'o', "o examine/set options"},
194 {'^', "^<dir> identify trap type"},
195 {'\022', "^R redraw screen"},
196 {'&', "& save screen into 'rogue.screen'"},
197 {'s', "s search for trap/secret door"},
198 {'\020', "^P repeat last message"},
199 {'>', "> go down a staircase"},
200 {'\033', "^[ cancel command"},
201 {'<', "< go up a staircase"},
202 {'S', "S save game"},
203 {'.', ". rest for a turn"},
204 {'Q', "Q quit"},
205 {',', ", pick something up"},
206 {'!', "! shell escape"},
207 {'i', "i inventory"},
208 {'F', "F<dir> fight till either of you dies"},
209 {'I', "I inventory single item"},
210 {'v', "v print version number"},
211 {'q', "q quaff potion" }
214 static int get_com_id(int *, short);
215 static int pr_com_id(int);
216 static int pr_motion_char(int);
218 void
219 inventory(const object *pack, unsigned short mask)
221 object *obj;
222 short i = 0, j;
223 size_t maxlen = 0, n;
224 short row, col;
226 struct {
227 short letter;
228 short sepchar;
229 char desc[DCOLS];
230 char savebuf[DCOLS+8];
231 } descs[MAX_PACK_COUNT+1];
234 obj = pack->next_object;
236 if (!obj) {
237 messagef(0, "your pack is empty");
238 return;
240 while (obj) {
241 if (obj->what_is & mask) {
242 descs[i].letter = obj->ichar;
243 descs[i].sepchar = ((obj->what_is & ARMOR) && obj->is_protected)
244 ? '}' : ')';
245 get_desc(obj, descs[i].desc, sizeof(descs[i].desc));
246 n = strlen(descs[i].desc) + 4;
247 if (n > maxlen) {
248 maxlen = n;
250 i++;
251 /*assert(i<=MAX_PACK_COUNT);*/
253 obj = obj->next_object;
255 if (maxlen < 27) maxlen = 27;
256 if (maxlen > DCOLS-2) maxlen = DCOLS-2;
257 col = DCOLS - (maxlen + 2);
259 for (row = 0; ((row <= i) && (row < DROWS)); row++) {
260 for (j = col; j < DCOLS; j++) {
261 descs[row].savebuf[j-col] = mvinch(row, j);
263 descs[row].savebuf[j-col] = 0;
264 if (row < i) {
265 mvprintw(row, col, " %c%c %s",
266 descs[row].letter, descs[row].sepchar,
267 descs[row].desc);
269 else {
270 mvaddstr(row, col, press_space);
272 clrtoeol();
274 refresh();
275 wait_for_ack();
277 move(0, 0);
278 clrtoeol();
280 for (j = 1; ((j <= i) && (j < DROWS)); j++) {
281 mvaddstr(j, col, descs[j].savebuf);
285 void
286 id_com(void)
288 int ch = 0;
289 short i, j, k;
291 while (ch != CANCEL) {
292 check_message();
293 messagef(0, "Character you want help for (* for all):");
295 refresh();
296 ch = getchar();
298 switch(ch) {
299 case LIST:
301 char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
302 short rows = (((COMS / 2) + (COMS % 2)) + 1);
303 boolean need_two_screens = FALSE;
305 if (rows > LINES) {
306 need_two_screens = 1;
307 rows = LINES;
309 k = 0;
311 for (i = 0; i < rows; i++) {
312 for (j = 0; j < DCOLS; j++) {
313 save[i][j] = mvinch(i, j);
316 MORE:
317 for (i = 0; i < rows; i++) {
318 move(i, 0);
319 clrtoeol();
321 for (i = 0; i < (rows-1); i++) {
322 if (i < (LINES-1)) {
323 if (((i + i) < COMS) && ((i+i+k) < COMS)) {
324 mvaddstr(i, 0, com_id_tab[i+i+k].com_desc);
326 if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) {
327 mvaddstr(i, (DCOLS/2),
328 com_id_tab[i+i+k+1].com_desc);
332 mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
333 refresh();
334 wait_for_ack();
336 if (need_two_screens) {
337 k += ((rows-1) * 2);
338 need_two_screens = 0;
339 goto MORE;
341 for (i = 0; i < rows; i++) {
342 move(i, 0);
343 for (j = 0; j < DCOLS; j++) {
344 addch(save[i][j]);
348 break;
349 default:
350 if (!pr_com_id(ch)) {
351 if (!pr_motion_char(ch)) {
352 check_message();
353 messagef(0, "unknown character");
356 ch = CANCEL;
357 break;
362 static int
363 pr_com_id(int ch)
365 int i;
367 if (!get_com_id(&i, ch)) {
368 return(0);
370 check_message();
371 messagef(0, "%s", com_id_tab[i].com_desc);
372 return(1);
375 static int
376 get_com_id(int *indexp, short ch)
378 short i;
380 for (i = 0; i < COMS; i++) {
381 if (com_id_tab[i].com_char == ch) {
382 *indexp = i;
383 return(1);
386 return(0);
389 static int
390 pr_motion_char(int ch)
392 if ( (ch == 'J') ||
393 (ch == 'K') ||
394 (ch == 'L') ||
395 (ch == 'H') ||
396 (ch == 'Y') ||
397 (ch == 'U') ||
398 (ch == 'N') ||
399 (ch == 'B') ||
400 (ch == '\012') ||
401 (ch == '\013') ||
402 (ch == '\010') ||
403 (ch == '\014') ||
404 (ch == '\025') ||
405 (ch == '\031') ||
406 (ch == '\016') ||
407 (ch == '\002')) {
408 const char *until;
409 int n = 0; /* XXX: GCC */
410 if (ch <= '\031') {
411 ch += 96;
412 until = " until adjacent";
413 } else {
414 ch += 32;
415 until = "";
417 (void)get_com_id(&n, ch);
418 check_message();
419 messagef(0, "run %s%s", com_id_tab[n].com_desc + 8, until);
420 return(1);
421 } else {
422 return(0);
426 void
427 mix_colors(void)
429 short i, j, k;
430 char t[MAX_ID_TITLE_LEN];
432 for (i = 0; i <= 32; i++) {
433 j = get_rand(0, (POTIONS - 1));
434 k = get_rand(0, (POTIONS - 1));
435 strlcpy(t, id_potions[j].title, sizeof(t));
436 strlcpy(id_potions[j].title, id_potions[k].title,
437 sizeof(id_potions[j].title));
438 strlcpy(id_potions[k].title, t, sizeof(id_potions[k].title));
442 void
443 make_scroll_titles(void)
445 short i, j, n;
446 short sylls, s;
447 size_t maxlen = sizeof(id_scrolls[0].title);
449 for (i = 0; i < SCROLS; i++) {
450 sylls = get_rand(2, 5);
451 (void)strlcpy(id_scrolls[i].title, "'", maxlen);
453 for (j = 0; j < sylls; j++) {
454 s = get_rand(1, (MAXSYLLABLES-1));
455 (void)strlcat(id_scrolls[i].title, syllables[s],
456 maxlen);
458 /* trim trailing space */
459 n = strlen(id_scrolls[i].title);
460 id_scrolls[i].title[n-1] = 0;
462 (void)strlcat(id_scrolls[i].title, "' ", maxlen);
466 struct sbuf {
467 char *buf;
468 size_t maxlen;
471 static void sbuf_init(struct sbuf *s, char *buf, size_t maxlen);
472 static void sbuf_addstr(struct sbuf *s, const char *str);
473 static void sbuf_addf(struct sbuf *s, const char *fmt, ...)
474 __attribute__((__format__(__printf__, 2, 3)));
475 static void desc_count(struct sbuf *s, int n);
476 static void desc_called(struct sbuf *s, const object *);
478 static
479 void
480 sbuf_init(struct sbuf *s, char *buf, size_t maxlen)
482 s->buf = buf;
483 s->maxlen = maxlen;
484 /*assert(maxlen>0);*/
485 s->buf[0] = 0;
488 static
489 void
490 sbuf_addstr(struct sbuf *s, const char *str)
492 strlcat(s->buf, str, s->maxlen);
495 static
496 void
497 sbuf_addf(struct sbuf *s, const char *fmt, ...)
499 va_list ap;
500 size_t initlen;
502 initlen = strlen(s->buf);
503 va_start(ap, fmt);
504 vsnprintf(s->buf+initlen, s->maxlen-initlen, fmt, ap);
505 va_end(ap);
508 static
509 void
510 desc_count(struct sbuf *s, int n)
512 if (n == 1) {
513 sbuf_addstr(s, "an ");
514 } else {
515 sbuf_addf(s, "%d ", n);
519 static
520 void
521 desc_called(struct sbuf *s, const object *obj)
523 struct id *id_table;
525 id_table = get_id_table(obj);
526 sbuf_addstr(s, name_of(obj));
527 sbuf_addstr(s, "called ");
528 sbuf_addstr(s, id_table[obj->which_kind].title);
531 void
532 get_desc(const object *obj, char *desc, size_t desclen)
534 const char *item_name;
535 struct id *id_table;
536 struct sbuf db;
537 unsigned short objtype_id_status;
539 if (obj->what_is == AMULET) {
540 (void)strlcpy(desc, "the amulet of Yendor ", desclen);
541 return;
544 if (obj->what_is == GOLD) {
545 snprintf(desc, desclen, "%d pieces of gold", obj->quantity);
546 return;
549 item_name = name_of(obj);
550 id_table = get_id_table(obj);
551 if (wizard || id_table == NULL) {
552 objtype_id_status = IDENTIFIED;
554 else {
555 objtype_id_status = id_table[obj->which_kind].id_status;
557 if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
558 if (obj->identified) {
559 objtype_id_status = IDENTIFIED;
563 sbuf_init(&db, desc, desclen);
565 switch (obj->what_is) {
566 case FOOD:
567 if (obj->which_kind == RATION) {
568 if (obj->quantity > 1) {
569 sbuf_addf(&db,
570 "%d rations of %s", obj->quantity,
571 item_name);
572 } else {
573 sbuf_addf(&db, "some %s", item_name);
575 } else {
576 sbuf_addf(&db, "an %s", item_name);
578 break;
579 case SCROL:
580 desc_count(&db, obj->quantity);
581 if (objtype_id_status==UNIDENTIFIED) {
582 sbuf_addstr(&db, item_name);
583 sbuf_addstr(&db, "entitled: ");
584 sbuf_addstr(&db, id_table[obj->which_kind].title);
585 } else if (objtype_id_status==CALLED) {
586 desc_called(&db, obj);
587 } else {
588 sbuf_addstr(&db, item_name);
589 sbuf_addstr(&db, id_table[obj->which_kind].real);
591 break;
592 case POTION:
593 desc_count(&db, obj->quantity);
594 if (objtype_id_status==UNIDENTIFIED) {
595 sbuf_addstr(&db, id_table[obj->which_kind].title);
596 sbuf_addstr(&db, item_name);
597 } else if (objtype_id_status==CALLED) {
598 desc_called(&db, obj);
599 } else {
600 sbuf_addstr(&db, item_name);
601 sbuf_addstr(&db, id_table[obj->which_kind].real);
603 break;
604 case WAND:
605 desc_count(&db, obj->quantity);
606 if (objtype_id_status==UNIDENTIFIED) {
607 sbuf_addstr(&db, id_table[obj->which_kind].title);
608 sbuf_addstr(&db, item_name);
609 } else if (objtype_id_status==CALLED) {
610 desc_called(&db, obj);
611 } else {
612 sbuf_addstr(&db, item_name);
613 sbuf_addstr(&db, id_table[obj->which_kind].real);
614 if (wizard || obj->identified) {
615 sbuf_addf(&db, "[%d]", obj->class);
618 break;
619 case RING:
620 desc_count(&db, obj->quantity);
621 if (objtype_id_status==UNIDENTIFIED) {
622 sbuf_addstr(&db, id_table[obj->which_kind].title);
623 sbuf_addstr(&db, item_name);
624 } else if (objtype_id_status==CALLED) {
625 desc_called(&db, obj);
626 } else {
627 if ((wizard || obj->identified) &&
628 (obj->which_kind == DEXTERITY ||
629 obj->which_kind == ADD_STRENGTH)) {
630 sbuf_addf(&db, "%+d ", obj->class);
632 sbuf_addstr(&db, item_name);
633 sbuf_addstr(&db, id_table[obj->which_kind].real);
635 break;
636 case ARMOR:
637 /* no desc_count() */
638 if (objtype_id_status==UNIDENTIFIED) {
639 sbuf_addstr(&db, id_table[obj->which_kind].title);
640 } else {
641 sbuf_addf(&db, "%+d %s[%d] ", obj->d_enchant,
642 id_table[obj->which_kind].title,
643 get_armor_class(obj));
645 break;
646 case WEAPON:
647 desc_count(&db, obj->quantity);
648 if (objtype_id_status==UNIDENTIFIED) {
649 sbuf_addstr(&db, name_of(obj));
650 } else {
651 sbuf_addf(&db, "%+d,%+d %s",
652 obj->hit_enchant, obj->d_enchant,
653 name_of(obj));
655 break;
658 if (obj->in_use_flags & BEING_WIELDED) {
659 sbuf_addstr(&db, "in hand");
660 } else if (obj->in_use_flags & BEING_WORN) {
661 sbuf_addstr(&db, "being worn");
662 } else if (obj->in_use_flags & ON_LEFT_HAND) {
663 sbuf_addstr(&db, "on left hand");
664 } else if (obj->in_use_flags & ON_RIGHT_HAND) {
665 sbuf_addstr(&db, "on right hand");
668 if (!strncmp(db.buf, "an ", 3)) {
669 if (!is_vowel(db.buf[3])) {
670 memmove(db.buf+2, db.buf+3, strlen(db.buf+3)+1);
671 db.buf[1] = ' ';
676 void
677 get_wand_and_ring_materials(void)
679 short i, j;
680 boolean used[WAND_MATERIALS];
682 for (i = 0; i < WAND_MATERIALS; i++) {
683 used[i] = 0;
685 for (i = 0; i < WANDS; i++) {
686 do {
687 j = get_rand(0, WAND_MATERIALS-1);
688 } while (used[j]);
689 used[j] = 1;
690 (void)strlcpy(id_wands[i].title, wand_materials[j],
691 sizeof(id_wands[i].title));
692 is_wood[i] = (j > MAX_METAL);
694 for (i = 0; i < GEMS; i++) {
695 used[i] = 0;
697 for (i = 0; i < RINGS; i++) {
698 do {
699 j = get_rand(0, GEMS-1);
700 } while (used[j]);
701 used[j] = 1;
702 (void)strlcpy(id_rings[i].title, gems[j],
703 sizeof(id_rings[i].title));
707 void
708 single_inv(short ichar)
710 short ch, ch2;
711 char desc[DCOLS];
712 object *obj;
714 ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
716 if (ch == CANCEL) {
717 return;
719 if (!(obj = get_letter_object(ch))) {
720 messagef(0, "no such item.");
721 return;
723 ch2 = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
724 get_desc(obj, desc, sizeof(desc));
725 messagef(0, "%c%c %s", ch, ch2, desc);
728 struct id *
729 get_id_table(const object *obj)
731 switch(obj->what_is) {
732 case SCROL:
733 return(id_scrolls);
734 case POTION:
735 return(id_potions);
736 case WAND:
737 return(id_wands);
738 case RING:
739 return(id_rings);
740 case WEAPON:
741 return(id_weapons);
742 case ARMOR:
743 return(id_armors);
745 return((struct id *)0);
748 void
749 inv_armor_weapon(boolean is_weapon)
751 if (is_weapon) {
752 if (rogue.weapon) {
753 single_inv(rogue.weapon->ichar);
754 } else {
755 messagef(0, "not wielding anything");
757 } else {
758 if (rogue.armor) {
759 single_inv(rogue.armor->ichar);
760 } else {
761 messagef(0, "not wearing anything");
766 void
767 id_type(void)
769 const char *id;
770 int ch;
772 messagef(0, "what do you want identified?");
774 ch = rgetchar();
776 if ((ch >= 'A') && (ch <= 'Z')) {
777 id = m_names[ch-'A'];
778 } else if (ch < 32) {
779 check_message();
780 return;
781 } else {
782 switch(ch) {
783 case '@':
784 id = "you";
785 break;
786 case '%':
787 id = "staircase";
788 break;
789 case '^':
790 id = "trap";
791 break;
792 case '+':
793 id = "door";
794 break;
795 case '-':
796 case '|':
797 id = "wall of a room";
798 break;
799 case '.':
800 id = "floor";
801 break;
802 case '#':
803 id = "passage";
804 break;
805 case ' ':
806 id = "solid rock";
807 break;
808 case '=':
809 id = "ring";
810 break;
811 case '?':
812 id = "scroll";
813 break;
814 case '!':
815 id = "potion";
816 break;
817 case '/':
818 id = "wand or staff";
819 break;
820 case ')':
821 id = "weapon";
822 break;
823 case ']':
824 id = "armor";
825 break;
826 case '*':
827 id = "gold";
828 break;
829 case ':':
830 id = "food";
831 break;
832 case ',':
833 id = "the Amulet of Yendor";
834 break;
835 default:
836 id = "unknown character";
837 break;
840 check_message();
841 messagef(0, "'%c': %s", ch, id);