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