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