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