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