kernel - Fix /dev/mem access for memory >=4GB
[dragonfly.git] / games / rogue / inventory.c
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. 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.
19  *
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.
31  *
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 $
35  */
36
37 /*
38  * inventory.c
39  *
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.
46  *
47  */
48
49 #include "rogue.h"
50
51 static boolean  pr_com_id(int);
52 static boolean  get_com_id(int *, short);
53 static boolean  pr_motion_char(int);
54
55 boolean is_wood[WANDS];
56 const char *press_space = " --press space to continue--";
57
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 "
89 };
90
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 "
106 };
107
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 "
149 };
150
151 #define COMS 48
152
153 struct id_com_s {
154         short com_char;
155         const char *com_desc;
156 };
157
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" }
207 };
208
209 extern boolean wizard;
210 extern char *m_names[], *more;
211
212 void
213 inventory(const object *pack, unsigned short mask)
214 {
215         object *obj;
216         short i = 0, j, maxlen = 0, n;
217         char descs[MAX_PACK_COUNT+1][DCOLS];
218         short row, col;
219
220         obj = pack->next_object;
221
222         if (!obj) {
223                 message("your pack is empty", 0);
224                 return;
225         }
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;
236                         }
237                 i++;
238                 }
239                 obj = obj->next_object;
240         }
241         strcpy(descs[i++], press_space);
242         if (maxlen < 27) maxlen = 27;
243         col = DCOLS - (maxlen + 2);
244
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);
249                         }
250                         descs[row-1][j-col] = 0;
251                 }
252                 mvaddstr(row, col, descs[row]);
253                 clrtoeol();
254         }
255         refresh();
256         wait_for_ack();
257
258         move(0, 0);
259         clrtoeol();
260
261         for (j = 1; ((j < i) && (j < DROWS)); j++) {
262                 mvaddstr(j, col, descs[j-1]);
263         }
264 }
265
266 void
267 id_com(void)
268 {
269         int ch = 0;
270         short i, j, k;
271
272         while (ch != CANCEL) {
273                 check_message();
274                 message("Character you want help for (* for all):", 0);
275
276                 refresh();
277                 ch = getchar();
278
279                 switch(ch) {
280                 case LIST:
281                         {
282                                 char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
283                                 short rows = (((COMS / 2) + (COMS % 2)) + 1);
284                                 boolean need_two_screens = FALSE;
285
286                                 if (rows > LINES) {
287                                         need_two_screens = 1;
288                                         rows = LINES;
289                                 }
290                                 k = 0;
291
292                                 for (i = 0; i < rows; i++) {
293                                         for (j = 0; j < DCOLS; j++) {
294                                                 save[i][j] = mvinch(i, j);
295                                         }
296                                 }
297 MORE:
298                                 for (i = 0; i < rows; i++) {
299                                         move(i, 0);
300                                         clrtoeol();
301                                 }
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);
306                                                 }
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);
310                                                 }
311                                         }
312                                 }
313                                 mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
314                                 refresh();
315                                 wait_for_ack();
316
317                                 if (need_two_screens) {
318                                         k += ((rows-1) * 2);
319                                         need_two_screens = 0;
320                                         goto MORE;
321                                 }
322                                 for (i = 0; i < rows; i++) {
323                                         move(i, 0);
324                                         for (j = 0; j < DCOLS; j++) {
325                                                 addch(save[i][j]);
326                                         }
327                                 }
328                         }
329                         break;
330                 default:
331                         if (!pr_com_id(ch)) {
332                                 if (!pr_motion_char(ch)) {
333                                         check_message();
334                                         message("unknown character", 0);
335                                 }
336                         }
337                         ch = CANCEL;
338                         break;
339                 }
340         }
341 }
342
343 static boolean
344 pr_com_id(int ch)
345 {
346         int i;
347
348         if (!get_com_id(&i, ch)) {
349                 return(0);
350         }
351         check_message();
352         message(com_id_tab[i].com_desc, 0);
353         return(1);
354 }
355
356 static boolean
357 get_com_id(int *idx, short ch)
358 {
359         short i;
360
361         for (i = 0; i < COMS; i++) {
362                 if (com_id_tab[i].com_char == ch) {
363                         *idx = i;
364                         return(1);
365                 }
366         }
367         return(0);
368 }
369
370 static boolean
371 pr_motion_char(int ch)
372 {
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;
391
392                 if (ch <= '\031') {
393                         ch += 96;
394                         strcpy(until, "until adjascent");
395                 } else {
396                         ch += 32;
397                         until[0] = '\0';
398                 }
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);
406         }
407 }
408
409 void
410 mix_colors(void)
411 {
412         short i, j, k;
413         char *t[MAX_ID_TITLE_LEN];
414
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);
420         }
421 }
422
423 void
424 make_scroll_titles(void)
425 {
426         short i, j, n;
427         short sylls, s;
428
429         for (i = 0; i < SCROLS; i++) {
430                 sylls = get_rand(2, 5);
431                 strcpy(id_scrolls[i].title, "'");
432
433                 for (j = 0; j < sylls; j++) {
434                         s = get_rand(1, (MAXSYLLABLES-1));
435                         strcat(id_scrolls[i].title, syllables[s]);
436                 }
437                 n = strlen(id_scrolls[i].title);
438                 strcpy(id_scrolls[i].title+(n-1), "' ");
439         }
440 }
441
442 void
443 get_desc(const object *obj, char *desc)
444 {
445         const char *item_name;
446         struct id *id_table;
447         char more_info[32];
448         short i;
449
450         if (obj->what_is == AMULET) {
451                 strcpy(desc, "the amulet of Yendor ");
452                 return;
453         }
454         item_name = name_of(obj);
455
456         if (obj->what_is == GOLD) {
457                 sprintf(desc, "%d pieces of gold", obj->quantity);
458                 return;
459         }
460
461         if (obj->what_is != ARMOR) {
462                 if (obj->quantity == 1) {
463                         strcpy(desc, "a ");
464                 } else {
465                         sprintf(desc, "%d ", obj->quantity);
466                 }
467         }
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 ");
474                         }
475                 } else {
476                         strcpy(desc, "a ");
477                 }
478                 strcat(desc, item_name);
479                 goto ANA;
480         }
481         id_table = get_id_table(obj);
482
483         if (wizard) {
484                 goto ID;
485         }
486         if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
487                 goto CHECK;
488         }
489
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;
508                         }
509                         if (id_table[obj->which_kind].id_status == CALLED) {
510                                 goto CALL;
511                         }
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;
518                         }
519                         strcpy(desc, id_table[obj->which_kind].title);
520                         break;
521                 case WEAPON:
522                         if (obj->identified) {
523                                 goto ID;
524                         }
525                         strcat(desc, name_of(obj));
526                         break;
527                 }
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;
539                 }
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);
555                                 }
556                         }
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);
566                         }
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;
581                 }
582                 break;
583         }
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];
589                         }
590                         desc[1] = 'n';
591                 }
592         }
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");
601         }
602 }
603
604 void
605 get_wand_and_ring_materials(void)
606 {
607         short i, j;
608         boolean used[WAND_MATERIALS];
609
610         for (i = 0; i < WAND_MATERIALS; i++) {
611                 used[i] = 0;
612         }
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);
620         }
621         for (i = 0; i < GEMS; i++) {
622                 used[i] = 0;
623         }
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]);
630         }
631 }
632
633 void
634 single_inv(short ichar)
635 {
636         short ch;
637         char desc[DCOLS];
638         object *obj;
639
640         ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
641
642         if (ch == CANCEL) {
643                 return;
644         }
645         if (!(obj = get_letter_object(ch))) {
646                 message("no such item.", 0);
647                 return;
648         }
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);
655 }
656
657 struct id *
658 get_id_table(const object *obj)
659 {
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);
673         }
674         return(NULL);
675 }
676
677 void
678 inv_armor_weapon(boolean is_weapon)
679 {
680         if (is_weapon) {
681                 if (rogue.weapon) {
682                         single_inv(rogue.weapon->ichar);
683                 } else {
684                         message("not wielding anything", 0);
685                 }
686         } else {
687                 if (rogue.armor) {
688                         single_inv(rogue.armor->ichar);
689                 } else {
690                         message("not wearing anything", 0);
691                 }
692         }
693 }
694
695 void
696 id_type(void)
697 {
698         const char *id;
699         int ch;
700         char buf[DCOLS];
701
702         message("what do you want identified?", 0);
703
704         ch = rgetchar();
705
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;
768                 }
769         }
770         check_message();
771         sprintf(buf, "'%c': %s", ch, id);
772         message(buf, 0);
773 }