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