Drop main() prototype. Syncs with NetBSD-8
[minix.git] / games / rogue / inventory.c
blob934e8aa3f5fd4fa011af791686121336d4c744fb
1 /* $NetBSD: inventory.c,v 1.15 2011/08/26 06:18:17 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.15 2011/08/26 06:18:17 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, ...) __printflike(2,3);
474 static void desc_count(struct sbuf *s, int n);
475 static void desc_called(struct sbuf *s, const object *);
477 static
478 void
479 sbuf_init(struct sbuf *s, char *buf, size_t maxlen)
481 s->buf = buf;
482 s->maxlen = maxlen;
483 /*assert(maxlen>0);*/
484 s->buf[0] = 0;
487 static
488 void
489 sbuf_addstr(struct sbuf *s, const char *str)
491 strlcat(s->buf, str, s->maxlen);
494 static
495 void
496 sbuf_addf(struct sbuf *s, const char *fmt, ...)
498 va_list ap;
499 size_t initlen;
501 initlen = strlen(s->buf);
502 va_start(ap, fmt);
503 vsnprintf(s->buf+initlen, s->maxlen-initlen, fmt, ap);
504 va_end(ap);
507 static
508 void
509 desc_count(struct sbuf *s, int n)
511 if (n == 1) {
512 sbuf_addstr(s, "an ");
513 } else {
514 sbuf_addf(s, "%d ", n);
518 static
519 void
520 desc_called(struct sbuf *s, const object *obj)
522 struct id *id_table;
524 id_table = get_id_table(obj);
525 sbuf_addstr(s, name_of(obj));
526 sbuf_addstr(s, "called ");
527 sbuf_addstr(s, id_table[obj->which_kind].title);
530 void
531 get_desc(const object *obj, char *desc, size_t desclen)
533 const char *item_name;
534 struct id *id_table;
535 struct sbuf db;
536 unsigned short objtype_id_status;
538 if (obj->what_is == AMULET) {
539 (void)strlcpy(desc, "the amulet of Yendor ", desclen);
540 return;
543 if (obj->what_is == GOLD) {
544 snprintf(desc, desclen, "%d pieces of gold", obj->quantity);
545 return;
548 item_name = name_of(obj);
549 id_table = get_id_table(obj);
550 if (wizard || id_table == NULL) {
551 objtype_id_status = IDENTIFIED;
553 else {
554 objtype_id_status = id_table[obj->which_kind].id_status;
556 if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
557 if (obj->identified) {
558 objtype_id_status = IDENTIFIED;
562 sbuf_init(&db, desc, desclen);
564 switch (obj->what_is) {
565 case FOOD:
566 if (obj->which_kind == RATION) {
567 if (obj->quantity > 1) {
568 sbuf_addf(&db,
569 "%d rations of %s", obj->quantity,
570 item_name);
571 } else {
572 sbuf_addf(&db, "some %s", item_name);
574 } else {
575 sbuf_addf(&db, "an %s", item_name);
577 break;
578 case SCROL:
579 desc_count(&db, obj->quantity);
580 if (objtype_id_status==UNIDENTIFIED) {
581 sbuf_addstr(&db, item_name);
582 sbuf_addstr(&db, "entitled: ");
583 sbuf_addstr(&db, id_table[obj->which_kind].title);
584 } else if (objtype_id_status==CALLED) {
585 desc_called(&db, obj);
586 } else {
587 sbuf_addstr(&db, item_name);
588 sbuf_addstr(&db, id_table[obj->which_kind].real);
590 break;
591 case POTION:
592 desc_count(&db, obj->quantity);
593 if (objtype_id_status==UNIDENTIFIED) {
594 sbuf_addstr(&db, id_table[obj->which_kind].title);
595 sbuf_addstr(&db, item_name);
596 } else if (objtype_id_status==CALLED) {
597 desc_called(&db, obj);
598 } else {
599 sbuf_addstr(&db, item_name);
600 sbuf_addstr(&db, id_table[obj->which_kind].real);
602 break;
603 case WAND:
604 desc_count(&db, obj->quantity);
605 if (objtype_id_status==UNIDENTIFIED) {
606 sbuf_addstr(&db, id_table[obj->which_kind].title);
607 sbuf_addstr(&db, item_name);
608 } else if (objtype_id_status==CALLED) {
609 desc_called(&db, obj);
610 } else {
611 sbuf_addstr(&db, item_name);
612 sbuf_addstr(&db, id_table[obj->which_kind].real);
613 if (wizard || obj->identified) {
614 sbuf_addf(&db, "[%d]", obj->class);
617 break;
618 case RING:
619 desc_count(&db, obj->quantity);
620 if (objtype_id_status==UNIDENTIFIED) {
621 sbuf_addstr(&db, id_table[obj->which_kind].title);
622 sbuf_addstr(&db, item_name);
623 } else if (objtype_id_status==CALLED) {
624 desc_called(&db, obj);
625 } else {
626 if ((wizard || obj->identified) &&
627 (obj->which_kind == DEXTERITY ||
628 obj->which_kind == ADD_STRENGTH)) {
629 sbuf_addf(&db, "%+d ", obj->class);
631 sbuf_addstr(&db, item_name);
632 sbuf_addstr(&db, id_table[obj->which_kind].real);
634 break;
635 case ARMOR:
636 /* no desc_count() */
637 if (objtype_id_status==UNIDENTIFIED) {
638 sbuf_addstr(&db, id_table[obj->which_kind].title);
639 } else {
640 sbuf_addf(&db, "%+d %s[%d] ", obj->d_enchant,
641 id_table[obj->which_kind].title,
642 get_armor_class(obj));
644 break;
645 case WEAPON:
646 desc_count(&db, obj->quantity);
647 if (objtype_id_status==UNIDENTIFIED) {
648 sbuf_addstr(&db, name_of(obj));
649 } else {
650 sbuf_addf(&db, "%+d,%+d %s",
651 obj->hit_enchant, obj->d_enchant,
652 name_of(obj));
654 break;
657 if (obj->in_use_flags & BEING_WIELDED) {
658 sbuf_addstr(&db, "in hand");
659 } else if (obj->in_use_flags & BEING_WORN) {
660 sbuf_addstr(&db, "being worn");
661 } else if (obj->in_use_flags & ON_LEFT_HAND) {
662 sbuf_addstr(&db, "on left hand");
663 } else if (obj->in_use_flags & ON_RIGHT_HAND) {
664 sbuf_addstr(&db, "on right hand");
667 if (!strncmp(db.buf, "an ", 3)) {
668 if (!is_vowel(db.buf[3])) {
669 memmove(db.buf+2, db.buf+3, strlen(db.buf+3)+1);
670 db.buf[1] = ' ';
675 void
676 get_wand_and_ring_materials(void)
678 short i, j;
679 boolean used[WAND_MATERIALS];
681 for (i = 0; i < WAND_MATERIALS; i++) {
682 used[i] = 0;
684 for (i = 0; i < WANDS; i++) {
685 do {
686 j = get_rand(0, WAND_MATERIALS-1);
687 } while (used[j]);
688 used[j] = 1;
689 (void)strlcpy(id_wands[i].title, wand_materials[j],
690 sizeof(id_wands[i].title));
691 is_wood[i] = (j > MAX_METAL);
693 for (i = 0; i < GEMS; i++) {
694 used[i] = 0;
696 for (i = 0; i < RINGS; i++) {
697 do {
698 j = get_rand(0, GEMS-1);
699 } while (used[j]);
700 used[j] = 1;
701 (void)strlcpy(id_rings[i].title, gems[j],
702 sizeof(id_rings[i].title));
706 void
707 single_inv(short ichar)
709 short ch, ch2;
710 char desc[DCOLS];
711 object *obj;
713 ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
715 if (ch == CANCEL) {
716 return;
718 if (!(obj = get_letter_object(ch))) {
719 messagef(0, "no such item.");
720 return;
722 ch2 = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
723 get_desc(obj, desc, sizeof(desc));
724 messagef(0, "%c%c %s", ch, ch2, desc);
727 struct id *
728 get_id_table(const object *obj)
730 switch(obj->what_is) {
731 case SCROL:
732 return(id_scrolls);
733 case POTION:
734 return(id_potions);
735 case WAND:
736 return(id_wands);
737 case RING:
738 return(id_rings);
739 case WEAPON:
740 return(id_weapons);
741 case ARMOR:
742 return(id_armors);
744 return((struct id *)0);
747 void
748 inv_armor_weapon(boolean is_weapon)
750 if (is_weapon) {
751 if (rogue.weapon) {
752 single_inv(rogue.weapon->ichar);
753 } else {
754 messagef(0, "not wielding anything");
756 } else {
757 if (rogue.armor) {
758 single_inv(rogue.armor->ichar);
759 } else {
760 messagef(0, "not wearing anything");
765 void
766 id_type(void)
768 const char *id;
769 int ch;
771 messagef(0, "what do you want identified?");
773 ch = rgetchar();
775 if ((ch >= 'A') && (ch <= 'Z')) {
776 id = m_names[ch-'A'];
777 } else if (ch < 32) {
778 check_message();
779 return;
780 } else {
781 switch(ch) {
782 case '@':
783 id = "you";
784 break;
785 case '%':
786 id = "staircase";
787 break;
788 case '^':
789 id = "trap";
790 break;
791 case '+':
792 id = "door";
793 break;
794 case '-':
795 case '|':
796 id = "wall of a room";
797 break;
798 case '.':
799 id = "floor";
800 break;
801 case '#':
802 id = "passage";
803 break;
804 case ' ':
805 id = "solid rock";
806 break;
807 case '=':
808 id = "ring";
809 break;
810 case '?':
811 id = "scroll";
812 break;
813 case '!':
814 id = "potion";
815 break;
816 case '/':
817 id = "wand or staff";
818 break;
819 case ')':
820 id = "weapon";
821 break;
822 case ']':
823 id = "armor";
824 break;
825 case '*':
826 id = "gold";
827 break;
828 case ':':
829 id = "food";
830 break;
831 case ',':
832 id = "the Amulet of Yendor";
833 break;
834 default:
835 id = "unknown character";
836 break;
839 check_message();
840 messagef(0, "'%c': %s", ch, id);