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