Fix a case where a spinlock was not being released.
[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.
1de703da
MD
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 $
0a2f18be 38 * $DragonFly: src/games/rogue/inventory.c,v 1.3 2003/08/26 23:52:50 drhodus Exp $
984263bc
MD
39 */
40
984263bc
MD
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
55boolean is_wood[WANDS];
56const char *press_space = " --press space to continue--";
57
58const 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
92const 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
109const 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
154struct id_com_s {
155 short com_char;
156 const char *com_desc;
157};
158
159const 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
210extern boolean wizard;
211extern char *m_names[], *more;
212
213inventory(pack, mask)
214const object *pack;
215unsigned 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
268id_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 }
298MORE:
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
344pr_com_id(ch)
345int 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
357get_com_id(index, ch)
358int *index;
359short 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
372pr_motion_char(ch)
373int 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
411mix_colors()
412{
413 short i, j, k;
0a2f18be 414 char *t[MAX_ID_TITLE_LEN];
984263bc
MD
415
416 for (i = 0; i <= 32; i++) {
417 j = get_rand(0, (POTIONS - 1));
418 k = get_rand(0, (POTIONS - 1));
0a2f18be
DR
419 memcpy(t, id_potions[j].title, MAX_ID_TITLE_LEN);
420 memcpy(id_potions[j].title, id_potions[k].title, MAX_ID_TITLE_LEN);
984263bc
MD
421 }
422}
423
424make_scroll_titles()
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 (void) strcpy(id_scrolls[i].title, "'");
432
433 for (j = 0; j < sylls; j++) {
434 s = get_rand(1, (MAXSYLLABLES-1));
435 (void) strcat(id_scrolls[i].title, syllables[s]);
436 }
437 n = strlen(id_scrolls[i].title);
438 (void) strcpy(id_scrolls[i].title+(n-1), "' ");
439 }
440}
441
442get_desc(obj, desc)
443const object *obj;
444char *desc;
445{
446 const char *item_name;
447 struct id *id_table;
448 char more_info[32];
449 short i;
450
451 if (obj->what_is == AMULET) {
452 (void) strcpy(desc, "the amulet of Yendor ");
453 return;
454 }
455 item_name = name_of(obj);
456
457 if (obj->what_is == GOLD) {
458 sprintf(desc, "%d pieces of gold", obj->quantity);
459 return;
460 }
461
462 if (obj->what_is != ARMOR) {
463 if (obj->quantity == 1) {
464 (void) strcpy(desc, "a ");
465 } else {
466 sprintf(desc, "%d ", obj->quantity);
467 }
468 }
469 if (obj->what_is == FOOD) {
470 if (obj->which_kind == RATION) {
471 if (obj->quantity > 1) {
472 sprintf(desc, "%d rations of ", obj->quantity);
473 } else {
474 (void) strcpy(desc, "some ");
475 }
476 } else {
477 (void) strcpy(desc, "a ");
478 }
479 (void) strcat(desc, item_name);
480 goto ANA;
481 }
482 id_table = get_id_table(obj);
483
484 if (wizard) {
485 goto ID;
486 }
487 if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
488 goto CHECK;
489 }
490
491 switch(id_table[obj->which_kind].id_status) {
492 case UNIDENTIFIED:
493CHECK:
494 switch(obj->what_is) {
495 case SCROL:
496 (void) strcat(desc, item_name);
497 (void) strcat(desc, "entitled: ");
498 (void) strcat(desc, id_table[obj->which_kind].title);
499 break;
500 case POTION:
501 (void) strcat(desc, id_table[obj->which_kind].title);
502 (void) strcat(desc, item_name);
503 break;
504 case WAND:
505 case RING:
506 if (obj->identified ||
507 (id_table[obj->which_kind].id_status == IDENTIFIED)) {
508 goto ID;
509 }
510 if (id_table[obj->which_kind].id_status == CALLED) {
511 goto CALL;
512 }
513 (void) strcat(desc, id_table[obj->which_kind].title);
514 (void) strcat(desc, item_name);
515 break;
516 case ARMOR:
517 if (obj->identified) {
518 goto ID;
519 }
520 (void) strcpy(desc, id_table[obj->which_kind].title);
521 break;
522 case WEAPON:
523 if (obj->identified) {
524 goto ID;
525 }
526 (void) strcat(desc, name_of(obj));
527 break;
528 }
529 break;
530 case CALLED:
531CALL: switch(obj->what_is) {
532 case SCROL:
533 case POTION:
534 case WAND:
535 case RING:
536 (void) strcat(desc, item_name);
537 (void) strcat(desc, "called ");
538 (void) strcat(desc, id_table[obj->which_kind].title);
539 break;
540 }
541 break;
542 case IDENTIFIED:
543ID: switch(obj->what_is) {
544 case SCROL:
545 case POTION:
546 (void) strcat(desc, item_name);
547 (void) strcat(desc, id_table[obj->which_kind].real);
548 break;
549 case RING:
550 if (wizard || obj->identified) {
551 if ((obj->which_kind == DEXTERITY) ||
552 (obj->which_kind == ADD_STRENGTH)) {
553 sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
554 obj->class);
555 (void) strcat(desc, more_info);
556 }
557 }
558 (void) strcat(desc, item_name);
559 (void) strcat(desc, id_table[obj->which_kind].real);
560 break;
561 case WAND:
562 (void) strcat(desc, item_name);
563 (void) strcat(desc, id_table[obj->which_kind].real);
564 if (wizard || obj->identified) {
565 sprintf(more_info, "[%d]", obj->class);
566 (void) strcat(desc, more_info);
567 }
568 break;
569 case ARMOR:
570 sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""),
571 obj->d_enchant);
572 (void) strcat(desc, id_table[obj->which_kind].title);
573 sprintf(more_info, "[%d] ", get_armor_class(obj));
574 (void) strcat(desc, more_info);
575 break;
576 case WEAPON:
577 sprintf(desc+strlen(desc), "%s%d,%s%d ",
578 ((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant,
579 ((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant);
580 (void) strcat(desc, name_of(obj));
581 break;
582 }
583 break;
584 }
585ANA:
586 if (!strncmp(desc, "a ", 2)) {
587 if (is_vowel(desc[2])) {
588 for (i = strlen(desc) + 1; i > 1; i--) {
589 desc[i] = desc[i-1];
590 }
591 desc[1] = 'n';
592 }
593 }
594 if (obj->in_use_flags & BEING_WIELDED) {
595 (void) strcat(desc, "in hand");
596 } else if (obj->in_use_flags & BEING_WORN) {
597 (void) strcat(desc, "being worn");
598 } else if (obj->in_use_flags & ON_LEFT_HAND) {
599 (void) strcat(desc, "on left hand");
600 } else if (obj->in_use_flags & ON_RIGHT_HAND) {
601 (void) strcat(desc, "on right hand");
602 }
603}
604
605get_wand_and_ring_materials()
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 (void) 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 (void) strcpy(id_rings[i].title, gems[j]);
630 }
631}
632
633single_inv(ichar)
634short 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
657struct id *
658get_id_table(obj)
659const object *obj;
660{
661 switch(obj->what_is) {
662 case SCROL:
663 return(id_scrolls);
664 case POTION:
665 return(id_potions);
666 case WAND:
667 return(id_wands);
668 case RING:
669 return(id_rings);
670 case WEAPON:
671 return(id_weapons);
672 case ARMOR:
673 return(id_armors);
674 }
675 return((struct id *) 0);
676}
677
678inv_armor_weapon(is_weapon)
679boolean is_weapon;
680{
681 if (is_weapon) {
682 if (rogue.weapon) {
683 single_inv(rogue.weapon->ichar);
684 } else {
685 message("not wielding anything", 0);
686 }
687 } else {
688 if (rogue.armor) {
689 single_inv(rogue.armor->ichar);
690 } else {
691 message("not wearing anything", 0);
692 }
693 }
694}
695
696id_type()
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}