Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / rogue / inventory.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Timothy C. Stoehr.
7 *
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.
23 *
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.
35 */
36
37#ifndef lint
38#if 0
39static char sccsid[] = "@(#)inventory.c 8.1 (Berkeley) 5/31/93";
40#endif
41static const char rcsid[] =
42 "$FreeBSD: src/games/rogue/inventory.c,v 1.4 1999/11/30 03:49:23 billf Exp $";
43#endif /* not lint */
44
45/*
46 * inventory.c
47 *
48 * This source herein may be modified and/or distributed by anybody who
49 * so desires, with the following restrictions:
50 * 1.) No portion of this notice shall be removed.
51 * 2.) Credit shall not be taken for the creation of this source.
52 * 3.) This code is not to be traded, sold, or used for personal
53 * gain or profit.
54 *
55 */
56
57#include "rogue.h"
58
59boolean is_wood[WANDS];
60const char *press_space = " --press space to continue--";
61
62const 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
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 "
94};
95
96const 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 "
111};
112
113const 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 "
154};
155
156#define COMS 48
157
158struct id_com_s {
159 short com_char;
160 const char *com_desc;
161};
162
163const 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"
212};
213
214extern boolean wizard;
215extern char *m_names[], *more;
216
217inventory(pack, mask)
218const object *pack;
219unsigned short mask;
220{
221 object *obj;
222 short i = 0, j, maxlen = 0, n;
223 char descs[MAX_PACK_COUNT+1][DCOLS];
224 short row, col;
225
226 obj = pack->next_object;
227
228 if (!obj) {
229 message("your pack is empty", 0);
230 return;
231 }
232 while (obj) {
233 if (obj->what_is & mask) {
234 descs[i][0] = ' ';
235 descs[i][1] = obj->ichar;
236 descs[i][2] = ((obj->what_is & ARMOR) && obj->is_protected)
237 ? '}' : ')';
238 descs[i][3] = ' ';
239 get_desc(obj, descs[i]+4);
240 if ((n = strlen(descs[i])) > maxlen) {
241 maxlen = n;
242 }
243 i++;
244 }
245 obj = obj->next_object;
246 }
247 (void) strcpy(descs[i++], press_space);
248 if (maxlen < 27) maxlen = 27;
249 col = DCOLS - (maxlen + 2);
250
251 for (row = 0; ((row < i) && (row < DROWS)); row++) {
252 if (row > 0) {
253 for (j = col; j < DCOLS; j++) {
254 descs[row-1][j-col] = mvinch(row, j);
255 }
256 descs[row-1][j-col] = 0;
257 }
258 mvaddstr(row, col, descs[row]);
259 clrtoeol();
260 }
261 refresh();
262 wait_for_ack();
263
264 move(0, 0);
265 clrtoeol();
266
267 for (j = 1; ((j < i) && (j < DROWS)); j++) {
268 mvaddstr(j, col, descs[j-1]);
269 }
270}
271
272id_com()
273{
274 int ch = 0;
275 short i, j, k;
276
277 while (ch != CANCEL) {
278 check_message();
279 message("Character you want help for (* for all):", 0);
280
281 refresh();
282 ch = getchar();
283
284 switch(ch) {
285 case LIST:
286 {
287 char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
288 short rows = (((COMS / 2) + (COMS % 2)) + 1);
289 boolean need_two_screens;
290
291 if (rows > LINES) {
292 need_two_screens = 1;
293 rows = LINES;
294 }
295 k = 0;
296
297 for (i = 0; i < rows; i++) {
298 for (j = 0; j < DCOLS; j++) {
299 save[i][j] = mvinch(i, j);
300 }
301 }
302MORE:
303 for (i = 0; i < rows; i++) {
304 move(i, 0);
305 clrtoeol();
306 }
307 for (i = 0; i < (rows-1); i++) {
308 if (i < (LINES-1)) {
309 if (((i + i) < COMS) && ((i+i+k) < COMS)) {
310 mvaddstr(i, 0, com_id_tab[i+i+k].com_desc);
311 }
312 if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) {
313 mvaddstr(i, (DCOLS/2),
314 com_id_tab[i+i+k+1].com_desc);
315 }
316 }
317 }
318 mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
319 refresh();
320 wait_for_ack();
321
322 if (need_two_screens) {
323 k += ((rows-1) * 2);
324 need_two_screens = 0;
325 goto MORE;
326 }
327 for (i = 0; i < rows; i++) {
328 move(i, 0);
329 for (j = 0; j < DCOLS; j++) {
330 addch(save[i][j]);
331 }
332 }
333 }
334 break;
335 default:
336 if (!pr_com_id(ch)) {
337 if (!pr_motion_char(ch)) {
338 check_message();
339 message("unknown character", 0);
340 }
341 }
342 ch = CANCEL;
343 break;
344 }
345 }
346}
347
348pr_com_id(ch)
349int ch;
350{
351 int i;
352
353 if (!get_com_id(&i, ch)) {
354 return(0);
355 }
356 check_message();
357 message(com_id_tab[i].com_desc, 0);
358 return(1);
359}
360
361get_com_id(index, ch)
362int *index;
363short ch;
364{
365 short i;
366
367 for (i = 0; i < COMS; i++) {
368 if (com_id_tab[i].com_char == ch) {
369 *index = i;
370 return(1);
371 }
372 }
373 return(0);
374}
375
376pr_motion_char(ch)
377int ch;
378{
379 if ( (ch == 'J') ||
380 (ch == 'K') ||
381 (ch == 'L') ||
382 (ch == 'H') ||
383 (ch == 'Y') ||
384 (ch == 'U') ||
385 (ch == 'N') ||
386 (ch == 'B') ||
387 (ch == '\012') ||
388 (ch == '\013') ||
389 (ch == '\010') ||
390 (ch == '\014') ||
391 (ch == '\025') ||
392 (ch == '\031') ||
393 (ch == '\016') ||
394 (ch == '\002')) {
395 char until[18], buf[DCOLS];
396 int n;
397
398 if (ch <= '\031') {
399 ch += 96;
400 (void) strcpy(until, "until adjascent");
401 } else {
402 ch += 32;
403 until[0] = '\0';
404 }
405 (void) get_com_id(&n, ch);
406 sprintf(buf, "run %s %s", com_id_tab[n].com_desc + 8, until);
407 check_message();
408 message(buf, 0);
409 return(1);
410 } else {
411 return(0);
412 }
413}
414
415mix_colors()
416{
417 short i, j, k;
418 char *t;
419
420 for (i = 0; i <= 32; i++) {
421 j = get_rand(0, (POTIONS - 1));
422 k = get_rand(0, (POTIONS - 1));
423 t = id_potions[j].title;
424 id_potions[j].title = id_potions[k].title;
425 id_potions[k].title = t;
426 }
427}
428
429make_scroll_titles()
430{
431 short i, j, n;
432 short sylls, s;
433
434 for (i = 0; i < SCROLS; i++) {
435 sylls = get_rand(2, 5);
436 (void) strcpy(id_scrolls[i].title, "'");
437
438 for (j = 0; j < sylls; j++) {
439 s = get_rand(1, (MAXSYLLABLES-1));
440 (void) strcat(id_scrolls[i].title, syllables[s]);
441 }
442 n = strlen(id_scrolls[i].title);
443 (void) strcpy(id_scrolls[i].title+(n-1), "' ");
444 }
445}
446
447get_desc(obj, desc)
448const object *obj;
449char *desc;
450{
451 const char *item_name;
452 struct id *id_table;
453 char more_info[32];
454 short i;
455
456 if (obj->what_is == AMULET) {
457 (void) strcpy(desc, "the amulet of Yendor ");
458 return;
459 }
460 item_name = name_of(obj);
461
462 if (obj->what_is == GOLD) {
463 sprintf(desc, "%d pieces of gold", obj->quantity);
464 return;
465 }
466
467 if (obj->what_is != ARMOR) {
468 if (obj->quantity == 1) {
469 (void) strcpy(desc, "a ");
470 } else {
471 sprintf(desc, "%d ", obj->quantity);
472 }
473 }
474 if (obj->what_is == FOOD) {
475 if (obj->which_kind == RATION) {
476 if (obj->quantity > 1) {
477 sprintf(desc, "%d rations of ", obj->quantity);
478 } else {
479 (void) strcpy(desc, "some ");
480 }
481 } else {
482 (void) strcpy(desc, "a ");
483 }
484 (void) strcat(desc, item_name);
485 goto ANA;
486 }
487 id_table = get_id_table(obj);
488
489 if (wizard) {
490 goto ID;
491 }
492 if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
493 goto CHECK;
494 }
495
496 switch(id_table[obj->which_kind].id_status) {
497 case UNIDENTIFIED:
498CHECK:
499 switch(obj->what_is) {
500 case SCROL:
501 (void) strcat(desc, item_name);
502 (void) strcat(desc, "entitled: ");
503 (void) strcat(desc, id_table[obj->which_kind].title);
504 break;
505 case POTION:
506 (void) strcat(desc, id_table[obj->which_kind].title);
507 (void) strcat(desc, item_name);
508 break;
509 case WAND:
510 case RING:
511 if (obj->identified ||
512 (id_table[obj->which_kind].id_status == IDENTIFIED)) {
513 goto ID;
514 }
515 if (id_table[obj->which_kind].id_status == CALLED) {
516 goto CALL;
517 }
518 (void) strcat(desc, id_table[obj->which_kind].title);
519 (void) strcat(desc, item_name);
520 break;
521 case ARMOR:
522 if (obj->identified) {
523 goto ID;
524 }
525 (void) strcpy(desc, id_table[obj->which_kind].title);
526 break;
527 case WEAPON:
528 if (obj->identified) {
529 goto ID;
530 }
531 (void) strcat(desc, name_of(obj));
532 break;
533 }
534 break;
535 case CALLED:
536CALL: switch(obj->what_is) {
537 case SCROL:
538 case POTION:
539 case WAND:
540 case RING:
541 (void) strcat(desc, item_name);
542 (void) strcat(desc, "called ");
543 (void) strcat(desc, id_table[obj->which_kind].title);
544 break;
545 }
546 break;
547 case IDENTIFIED:
548ID: switch(obj->what_is) {
549 case SCROL:
550 case POTION:
551 (void) strcat(desc, item_name);
552 (void) strcat(desc, id_table[obj->which_kind].real);
553 break;
554 case RING:
555 if (wizard || obj->identified) {
556 if ((obj->which_kind == DEXTERITY) ||
557 (obj->which_kind == ADD_STRENGTH)) {
558 sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
559 obj->class);
560 (void) strcat(desc, more_info);
561 }
562 }
563 (void) strcat(desc, item_name);
564 (void) strcat(desc, id_table[obj->which_kind].real);
565 break;
566 case WAND:
567 (void) strcat(desc, item_name);
568 (void) strcat(desc, id_table[obj->which_kind].real);
569 if (wizard || obj->identified) {
570 sprintf(more_info, "[%d]", obj->class);
571 (void) strcat(desc, more_info);
572 }
573 break;
574 case ARMOR:
575 sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""),
576 obj->d_enchant);
577 (void) strcat(desc, id_table[obj->which_kind].title);
578 sprintf(more_info, "[%d] ", get_armor_class(obj));
579 (void) strcat(desc, more_info);
580 break;
581 case WEAPON:
582 sprintf(desc+strlen(desc), "%s%d,%s%d ",
583 ((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant,
584 ((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant);
585 (void) strcat(desc, name_of(obj));
586 break;
587 }
588 break;
589 }
590ANA:
591 if (!strncmp(desc, "a ", 2)) {
592 if (is_vowel(desc[2])) {
593 for (i = strlen(desc) + 1; i > 1; i--) {
594 desc[i] = desc[i-1];
595 }
596 desc[1] = 'n';
597 }
598 }
599 if (obj->in_use_flags & BEING_WIELDED) {
600 (void) strcat(desc, "in hand");
601 } else if (obj->in_use_flags & BEING_WORN) {
602 (void) strcat(desc, "being worn");
603 } else if (obj->in_use_flags & ON_LEFT_HAND) {
604 (void) strcat(desc, "on left hand");
605 } else if (obj->in_use_flags & ON_RIGHT_HAND) {
606 (void) strcat(desc, "on right hand");
607 }
608}
609
610get_wand_and_ring_materials()
611{
612 short i, j;
613 boolean used[WAND_MATERIALS];
614
615 for (i = 0; i < WAND_MATERIALS; i++) {
616 used[i] = 0;
617 }
618 for (i = 0; i < WANDS; i++) {
619 do {
620 j = get_rand(0, WAND_MATERIALS-1);
621 } while (used[j]);
622 used[j] = 1;
623 (void) strcpy(id_wands[i].title, wand_materials[j]);
624 is_wood[i] = (j > MAX_METAL);
625 }
626 for (i = 0; i < GEMS; i++) {
627 used[i] = 0;
628 }
629 for (i = 0; i < RINGS; i++) {
630 do {
631 j = get_rand(0, GEMS-1);
632 } while (used[j]);
633 used[j] = 1;
634 (void) strcpy(id_rings[i].title, gems[j]);
635 }
636}
637
638single_inv(ichar)
639short ichar;
640{
641 short ch;
642 char desc[DCOLS];
643 object *obj;
644
645 ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
646
647 if (ch == CANCEL) {
648 return;
649 }
650 if (!(obj = get_letter_object(ch))) {
651 message("no such item.", 0);
652 return;
653 }
654 desc[0] = ch;
655 desc[1] = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
656 desc[2] = ' ';
657 desc[3] = 0;
658 get_desc(obj, desc+3);
659 message(desc, 0);
660}
661
662struct id *
663get_id_table(obj)
664const object *obj;
665{
666 switch(obj->what_is) {
667 case SCROL:
668 return(id_scrolls);
669 case POTION:
670 return(id_potions);
671 case WAND:
672 return(id_wands);
673 case RING:
674 return(id_rings);
675 case WEAPON:
676 return(id_weapons);
677 case ARMOR:
678 return(id_armors);
679 }
680 return((struct id *) 0);
681}
682
683inv_armor_weapon(is_weapon)
684boolean is_weapon;
685{
686 if (is_weapon) {
687 if (rogue.weapon) {
688 single_inv(rogue.weapon->ichar);
689 } else {
690 message("not wielding anything", 0);
691 }
692 } else {
693 if (rogue.armor) {
694 single_inv(rogue.armor->ichar);
695 } else {
696 message("not wearing anything", 0);
697 }
698 }
699}
700
701id_type()
702{
703 const char *id;
704 int ch;
705 char buf[DCOLS];
706
707 message("what do you want identified?", 0);
708
709 ch = rgetchar();
710
711 if ((ch >= 'A') && (ch <= 'Z')) {
712 id = m_names[ch-'A'];
713 } else if (ch < 32) {
714 check_message();
715 return;
716 } else {
717 switch(ch) {
718 case '@':
719 id = "you";
720 break;
721 case '%':
722 id = "staircase";
723 break;
724 case '^':
725 id = "trap";
726 break;
727 case '+':
728 id = "door";
729 break;
730 case '-':
731 case '|':
732 id = "wall of a room";
733 break;
734 case '.':
735 id = "floor";
736 break;
737 case '#':
738 id = "passage";
739 break;
740 case ' ':
741 id = "solid rock";
742 break;
743 case '=':
744 id = "ring";
745 break;
746 case '?':
747 id = "scroll";
748 break;
749 case '!':
750 id = "potion";
751 break;
752 case '/':
753 id = "wand or staff";
754 break;
755 case ')':
756 id = "weapon";
757 break;
758 case ']':
759 id = "armor";
760 break;
761 case '*':
762 id = "gold";
763 break;
764 case ':':
765 id = "food";
766 break;
767 case ',':
768 id = "the Amulet of Yendor";
769 break;
770 default:
771 id = "unknown character";
772 break;
773 }
774 }
775 check_message();
776 sprintf(buf, "'%c': %s", ch, id);
777 message(buf, 0);
778}