Home | History | Annotate | Line # | Download | only in rogue
      1 /*	$NetBSD: inventory.c,v 1.15 2011/08/26 06:18:17 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.15 2011/08/26 06:18:17 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 static int get_com_id(int *, short);
    215 static int pr_com_id(int);
    216 static int pr_motion_char(int);
    217 
    218 void
    219 inventory(const object *pack, unsigned short mask)
    220 {
    221 	object *obj;
    222 	short i = 0, j;
    223 	size_t maxlen = 0, n;
    224 	short row, col;
    225 
    226 	struct {
    227 		short letter;
    228 		short sepchar;
    229 		char desc[DCOLS];
    230 		char savebuf[DCOLS+8];
    231 	} descs[MAX_PACK_COUNT+1];
    232 
    233 
    234 	obj = pack->next_object;
    235 
    236 	if (!obj) {
    237 		messagef(0, "your pack is empty");
    238 		return;
    239 	}
    240 	while (obj) {
    241 		if (obj->what_is & mask) {
    242 			descs[i].letter = obj->ichar;
    243 			descs[i].sepchar = ((obj->what_is & ARMOR) && obj->is_protected)
    244 				? '}' : ')';
    245 			get_desc(obj, descs[i].desc, sizeof(descs[i].desc));
    246 			n = strlen(descs[i].desc) + 4;
    247 			if (n > maxlen) {
    248 				maxlen = n;
    249 			}
    250 			i++;
    251 			/*assert(i<=MAX_PACK_COUNT);*/
    252 		}
    253 		obj = obj->next_object;
    254 	}
    255 	if (maxlen < 27) maxlen = 27;
    256 	if (maxlen > DCOLS-2) maxlen = DCOLS-2;
    257 	col = DCOLS - (maxlen + 2);
    258 
    259 	for (row = 0; ((row <= i) && (row < DROWS)); row++) {
    260 		for (j = col; j < DCOLS; j++) {
    261 			descs[row].savebuf[j-col] = mvinch(row, j);
    262 		}
    263 		descs[row].savebuf[j-col] = 0;
    264 		if (row < i) {
    265 			mvprintw(row, col, " %c%c %s",
    266 				descs[row].letter, descs[row].sepchar,
    267 				descs[row].desc);
    268 		}
    269 		else {
    270 			mvaddstr(row, col, press_space);
    271 		}
    272 		clrtoeol();
    273 	}
    274 	refresh();
    275 	wait_for_ack();
    276 
    277 	move(0, 0);
    278 	clrtoeol();
    279 
    280 	for (j = 1; ((j <= i) && (j < DROWS)); j++) {
    281 		mvaddstr(j, col, descs[j].savebuf);
    282 	}
    283 }
    284 
    285 void
    286 id_com(void)
    287 {
    288 	int ch = 0;
    289 	short i, j, k;
    290 
    291 	while (ch != CANCEL) {
    292 		check_message();
    293 		messagef(0, "Character you want help for (* for all):");
    294 
    295 		refresh();
    296 		ch = getchar();
    297 
    298 		switch(ch) {
    299 		case LIST:
    300 			{
    301 				char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
    302 				short rows = (((COMS / 2) + (COMS % 2)) + 1);
    303 				boolean need_two_screens = FALSE;
    304 
    305 				if (rows > LINES) {
    306 					need_two_screens = 1;
    307 					rows = LINES;
    308 				}
    309 				k = 0;
    310 
    311 				for (i = 0; i < rows; i++) {
    312 					for (j = 0; j < DCOLS; j++) {
    313 						save[i][j] = mvinch(i, j);
    314 					}
    315 				}
    316 MORE:
    317 				for (i = 0; i < rows; i++) {
    318 					move(i, 0);
    319 					clrtoeol();
    320 				}
    321 				for (i = 0; i < (rows-1); i++) {
    322 					if (i < (LINES-1)) {
    323 						if (((i + i) < COMS) && ((i+i+k) < COMS)) {
    324 							mvaddstr(i, 0, com_id_tab[i+i+k].com_desc);
    325 						}
    326 						if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) {
    327 							mvaddstr(i, (DCOLS/2),
    328 										com_id_tab[i+i+k+1].com_desc);
    329 						}
    330 					}
    331 				}
    332 				mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
    333 				refresh();
    334 				wait_for_ack();
    335 
    336 				if (need_two_screens) {
    337 					k += ((rows-1) * 2);
    338 					need_two_screens = 0;
    339 					goto MORE;
    340 				}
    341 				for (i = 0; i < rows; i++) {
    342 					move(i, 0);
    343 					for (j = 0; j < DCOLS; j++) {
    344 						addch(save[i][j]);
    345 					}
    346 				}
    347 			}
    348 			break;
    349 		default:
    350 			if (!pr_com_id(ch)) {
    351 				if (!pr_motion_char(ch)) {
    352 					check_message();
    353 					messagef(0, "unknown character");
    354 				}
    355 			}
    356 			ch = CANCEL;
    357 			break;
    358 		}
    359 	}
    360 }
    361 
    362 static int
    363 pr_com_id(int ch)
    364 {
    365 	int i;
    366 
    367 	if (!get_com_id(&i, ch)) {
    368 		return(0);
    369 	}
    370 	check_message();
    371 	messagef(0, "%s", com_id_tab[i].com_desc);
    372 	return(1);
    373 }
    374 
    375 static int
    376 get_com_id(int *indexp, short ch)
    377 {
    378 	short i;
    379 
    380 	for (i = 0; i < COMS; i++) {
    381 		if (com_id_tab[i].com_char == ch) {
    382 			*indexp = i;
    383 			return(1);
    384 		}
    385 	}
    386 	return(0);
    387 }
    388 
    389 static int
    390 pr_motion_char(int ch)
    391 {
    392 	if (	(ch == 'J') ||
    393 			(ch == 'K') ||
    394 			(ch == 'L') ||
    395 			(ch == 'H') ||
    396 			(ch == 'Y') ||
    397 			(ch == 'U') ||
    398 			(ch == 'N') ||
    399 			(ch == 'B') ||
    400 			(ch == '\012') ||
    401 			(ch == '\013') ||
    402 			(ch == '\010') ||
    403 			(ch == '\014') ||
    404 			(ch == '\025') ||
    405 			(ch == '\031') ||
    406 			(ch == '\016') ||
    407 			(ch == '\002')) {
    408 		const char *until;
    409 		int n = 0;	/* XXX: GCC */
    410 		if (ch <= '\031') {
    411 			ch += 96;
    412 			until = " until adjacent";
    413 		} else {
    414 			ch += 32;
    415 			until = "";
    416 		}
    417 		(void)get_com_id(&n, ch);
    418 		check_message();
    419 		messagef(0, "run %s%s", com_id_tab[n].com_desc + 8, until);
    420 		return(1);
    421 	} else {
    422 		return(0);
    423 	}
    424 }
    425 
    426 void
    427 mix_colors(void)
    428 {
    429 	short i, j, k;
    430 	char t[MAX_ID_TITLE_LEN];
    431 
    432 	for (i = 0; i <= 32; i++) {
    433 		j = get_rand(0, (POTIONS - 1));
    434 		k = get_rand(0, (POTIONS - 1));
    435 		strlcpy(t, id_potions[j].title, sizeof(t));
    436 		strlcpy(id_potions[j].title, id_potions[k].title,
    437 			sizeof(id_potions[j].title));
    438 		strlcpy(id_potions[k].title, t, sizeof(id_potions[k].title));
    439 	}
    440 }
    441 
    442 void
    443 make_scroll_titles(void)
    444 {
    445 	short i, j, n;
    446 	short sylls, s;
    447 	size_t maxlen = sizeof(id_scrolls[0].title);
    448 
    449 	for (i = 0; i < SCROLS; i++) {
    450 		sylls = get_rand(2, 5);
    451 		(void)strlcpy(id_scrolls[i].title, "'", maxlen);
    452 
    453 		for (j = 0; j < sylls; j++) {
    454 			s = get_rand(1, (MAXSYLLABLES-1));
    455 			(void)strlcat(id_scrolls[i].title, syllables[s],
    456 					maxlen);
    457 		}
    458 		/* trim trailing space */
    459 		n = strlen(id_scrolls[i].title);
    460 		id_scrolls[i].title[n-1] = 0;
    461 
    462 		(void)strlcat(id_scrolls[i].title, "' ", maxlen);
    463 	}
    464 }
    465 
    466 struct sbuf {
    467 	char *buf;
    468 	size_t maxlen;
    469 };
    470 
    471 static void sbuf_init(struct sbuf *s, char *buf, size_t maxlen);
    472 static void sbuf_addstr(struct sbuf *s, const char *str);
    473 static void sbuf_addf(struct sbuf *s, const char *fmt, ...) __printflike(2,3);
    474 static void desc_count(struct sbuf *s, int n);
    475 static void desc_called(struct sbuf *s, const object *);
    476 
    477 static
    478 void
    479 sbuf_init(struct sbuf *s, char *buf, size_t maxlen)
    480 {
    481 	s->buf = buf;
    482 	s->maxlen = maxlen;
    483 	/*assert(maxlen>0);*/
    484 	s->buf[0] = 0;
    485 }
    486 
    487 static
    488 void
    489 sbuf_addstr(struct sbuf *s, const char *str)
    490 {
    491 	strlcat(s->buf, str, s->maxlen);
    492 }
    493 
    494 static
    495 void
    496 sbuf_addf(struct sbuf *s, const char *fmt, ...)
    497 {
    498 	va_list ap;
    499 	size_t initlen;
    500 
    501 	initlen = strlen(s->buf);
    502 	va_start(ap, fmt);
    503 	vsnprintf(s->buf+initlen, s->maxlen-initlen, fmt, ap);
    504 	va_end(ap);
    505 }
    506 
    507 static
    508 void
    509 desc_count(struct sbuf *s, int n)
    510 {
    511 	if (n == 1) {
    512 		sbuf_addstr(s, "an ");
    513 	} else {
    514 		sbuf_addf(s, "%d ", n);
    515 	}
    516 }
    517 
    518 static
    519 void
    520 desc_called(struct sbuf *s, const object *obj)
    521 {
    522 	struct id *id_table;
    523 
    524 	id_table = get_id_table(obj);
    525 	sbuf_addstr(s, name_of(obj));
    526 	sbuf_addstr(s, "called ");
    527 	sbuf_addstr(s, id_table[obj->which_kind].title);
    528 }
    529 
    530 void
    531 get_desc(const object *obj, char *desc, size_t desclen)
    532 {
    533 	const char *item_name;
    534 	struct id *id_table;
    535 	struct sbuf db;
    536 	unsigned short objtype_id_status;
    537 
    538 	if (obj->what_is == AMULET) {
    539 		(void)strlcpy(desc, "the amulet of Yendor ", desclen);
    540 		return;
    541 	}
    542 
    543 	if (obj->what_is == GOLD) {
    544 		snprintf(desc, desclen, "%d pieces of gold", obj->quantity);
    545 		return;
    546 	}
    547 
    548 	item_name = name_of(obj);
    549 	id_table = get_id_table(obj);
    550 	if (wizard || id_table == NULL) {
    551 		objtype_id_status = IDENTIFIED;
    552 	}
    553 	else {
    554 		objtype_id_status = id_table[obj->which_kind].id_status;
    555 	}
    556 	if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
    557 		if (obj->identified) {
    558 			objtype_id_status = IDENTIFIED;
    559 		}
    560 	}
    561 
    562 	sbuf_init(&db, desc, desclen);
    563 
    564 	switch (obj->what_is) {
    565 	case FOOD:
    566 		if (obj->which_kind == RATION) {
    567 			if (obj->quantity > 1) {
    568 				sbuf_addf(&db,
    569 					 "%d rations of %s", obj->quantity,
    570 					 item_name);
    571 			} else {
    572 				sbuf_addf(&db, "some %s", item_name);
    573 			}
    574 		} else {
    575 			sbuf_addf(&db, "an %s", item_name);
    576 		}
    577 		break;
    578 	case SCROL:
    579 		desc_count(&db, obj->quantity);
    580 		if (objtype_id_status==UNIDENTIFIED) {
    581 			sbuf_addstr(&db, item_name);
    582 			sbuf_addstr(&db, "entitled: ");
    583 			sbuf_addstr(&db, id_table[obj->which_kind].title);
    584 		} else if (objtype_id_status==CALLED) {
    585 			desc_called(&db, obj);
    586 		} else {
    587 			sbuf_addstr(&db, item_name);
    588 			sbuf_addstr(&db, id_table[obj->which_kind].real);
    589 		}
    590 		break;
    591 	case POTION:
    592 		desc_count(&db, obj->quantity);
    593 		if (objtype_id_status==UNIDENTIFIED) {
    594 			sbuf_addstr(&db, id_table[obj->which_kind].title);
    595 			sbuf_addstr(&db, item_name);
    596 		} else if (objtype_id_status==CALLED) {
    597 			desc_called(&db, obj);
    598 		} else {
    599 			sbuf_addstr(&db, item_name);
    600 			sbuf_addstr(&db, id_table[obj->which_kind].real);
    601 		}
    602 		break;
    603 	case WAND:
    604 		desc_count(&db, obj->quantity);
    605 		if (objtype_id_status==UNIDENTIFIED) {
    606 			sbuf_addstr(&db, id_table[obj->which_kind].title);
    607 			sbuf_addstr(&db, item_name);
    608 		} else if (objtype_id_status==CALLED) {
    609 			desc_called(&db, obj);
    610 		} else {
    611 			sbuf_addstr(&db, item_name);
    612 			sbuf_addstr(&db, id_table[obj->which_kind].real);
    613 			if (wizard || obj->identified) {
    614 				sbuf_addf(&db, "[%d]", obj->class);
    615 			}
    616 		}
    617 		break;
    618 	case RING:
    619 		desc_count(&db, obj->quantity);
    620 		if (objtype_id_status==UNIDENTIFIED) {
    621 			sbuf_addstr(&db, id_table[obj->which_kind].title);
    622 			sbuf_addstr(&db, item_name);
    623 		} else if (objtype_id_status==CALLED) {
    624 			desc_called(&db, obj);
    625 		} else {
    626 			if ((wizard || obj->identified) &&
    627 			    (obj->which_kind == DEXTERITY ||
    628 			     obj->which_kind == ADD_STRENGTH)) {
    629 				sbuf_addf(&db, "%+d ", obj->class);
    630 			}
    631 			sbuf_addstr(&db, item_name);
    632 			sbuf_addstr(&db, id_table[obj->which_kind].real);
    633 		}
    634 		break;
    635 	case ARMOR:
    636 		/* no desc_count() */
    637 		if (objtype_id_status==UNIDENTIFIED) {
    638 			sbuf_addstr(&db, id_table[obj->which_kind].title);
    639 		} else {
    640 			sbuf_addf(&db, "%+d %s[%d] ", obj->d_enchant,
    641 				id_table[obj->which_kind].title,
    642 				get_armor_class(obj));
    643     		}
    644 		break;
    645 	case WEAPON:
    646 		desc_count(&db, obj->quantity);
    647 		if (objtype_id_status==UNIDENTIFIED) {
    648 			sbuf_addstr(&db, name_of(obj));
    649 		} else {
    650 			sbuf_addf(&db, "%+d,%+d %s",
    651 				obj->hit_enchant, obj->d_enchant,
    652 				name_of(obj));
    653 		}
    654 		break;
    655 	}
    656 
    657 	if (obj->in_use_flags & BEING_WIELDED) {
    658 		sbuf_addstr(&db, "in hand");
    659 	} else if (obj->in_use_flags & BEING_WORN) {
    660 		sbuf_addstr(&db, "being worn");
    661 	} else if (obj->in_use_flags & ON_LEFT_HAND) {
    662 		sbuf_addstr(&db, "on left hand");
    663 	} else if (obj->in_use_flags & ON_RIGHT_HAND) {
    664 		sbuf_addstr(&db, "on right hand");
    665 	}
    666 
    667 	if (!strncmp(db.buf, "an ", 3)) {
    668 		if (!is_vowel(db.buf[3])) {
    669 			memmove(db.buf+2, db.buf+3, strlen(db.buf+3)+1);
    670 			db.buf[1] = ' ';
    671 		}
    672 	}
    673 }
    674 
    675 void
    676 get_wand_and_ring_materials(void)
    677 {
    678 	short i, j;
    679 	boolean used[WAND_MATERIALS];
    680 
    681 	for (i = 0; i < WAND_MATERIALS; i++) {
    682 		used[i] = 0;
    683 	}
    684 	for (i = 0; i < WANDS; i++) {
    685 		do {
    686 			j = get_rand(0, WAND_MATERIALS-1);
    687 		} while (used[j]);
    688 		used[j] = 1;
    689 		(void)strlcpy(id_wands[i].title, wand_materials[j],
    690 			       sizeof(id_wands[i].title));
    691 		is_wood[i] = (j > MAX_METAL);
    692 	}
    693 	for (i = 0; i < GEMS; i++) {
    694 		used[i] = 0;
    695 	}
    696 	for (i = 0; i < RINGS; i++) {
    697 		do {
    698 			j = get_rand(0, GEMS-1);
    699 		} while (used[j]);
    700 		used[j] = 1;
    701 		(void)strlcpy(id_rings[i].title, gems[j],
    702 			       sizeof(id_rings[i].title));
    703 	}
    704 }
    705 
    706 void
    707 single_inv(short ichar)
    708 {
    709 	short ch, ch2;
    710 	char desc[DCOLS];
    711 	object *obj;
    712 
    713 	ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
    714 
    715 	if (ch == CANCEL) {
    716 		return;
    717 	}
    718 	if (!(obj = get_letter_object(ch))) {
    719 		messagef(0, "no such item.");
    720 		return;
    721 	}
    722 	ch2 = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
    723 	get_desc(obj, desc, sizeof(desc));
    724 	messagef(0, "%c%c %s", ch, ch2, desc);
    725 }
    726 
    727 struct id *
    728 get_id_table(const object *obj)
    729 {
    730 	switch(obj->what_is) {
    731 	case SCROL:
    732 		return(id_scrolls);
    733 	case POTION:
    734 		return(id_potions);
    735 	case WAND:
    736 		return(id_wands);
    737 	case RING:
    738 		return(id_rings);
    739 	case WEAPON:
    740 		return(id_weapons);
    741 	case ARMOR:
    742 		return(id_armors);
    743 	}
    744 	return((struct id *)0);
    745 }
    746 
    747 void
    748 inv_armor_weapon(boolean is_weapon)
    749 {
    750 	if (is_weapon) {
    751 		if (rogue.weapon) {
    752 			single_inv(rogue.weapon->ichar);
    753 		} else {
    754 			messagef(0, "not wielding anything");
    755 		}
    756 	} else {
    757 		if (rogue.armor) {
    758 			single_inv(rogue.armor->ichar);
    759 		} else {
    760 			messagef(0, "not wearing anything");
    761 		}
    762 	}
    763 }
    764 
    765 void
    766 id_type(void)
    767 {
    768 	const char *id;
    769 	int ch;
    770 
    771 	messagef(0, "what do you want identified?");
    772 
    773 	ch = rgetchar();
    774 
    775 	if ((ch >= 'A') && (ch <= 'Z')) {
    776 		id = m_names[ch-'A'];
    777 	} else if (ch < 32) {
    778 		check_message();
    779 		return;
    780 	} else {
    781 		switch(ch) {
    782 		case '@':
    783 			id = "you";
    784 			break;
    785 		case '%':
    786 			id = "staircase";
    787 			break;
    788 		case '^':
    789 			id = "trap";
    790 			break;
    791 		case '+':
    792 			id = "door";
    793 			break;
    794 		case '-':
    795 		case '|':
    796 			id = "wall of a room";
    797 			break;
    798 		case '.':
    799 			id = "floor";
    800 			break;
    801 		case '#':
    802 			id = "passage";
    803 			break;
    804 		case ' ':
    805 			id = "solid rock";
    806 			break;
    807 		case '=':
    808 			id = "ring";
    809 			break;
    810 		case '?':
    811 			id = "scroll";
    812 			break;
    813 		case '!':
    814 			id = "potion";
    815 			break;
    816 		case '/':
    817 			id = "wand or staff";
    818 			break;
    819 		case ')':
    820 			id = "weapon";
    821 			break;
    822 		case ']':
    823 			id = "armor";
    824 			break;
    825 		case '*':
    826 			id = "gold";
    827 			break;
    828 		case ':':
    829 			id = "food";
    830 			break;
    831 		case ',':
    832 			id = "the Amulet of Yendor";
    833 			break;
    834 		default:
    835 			id = "unknown character";
    836 			break;
    837 		}
    838 	}
    839 	check_message();
    840 	messagef(0, "'%c': %s", ch, id);
    841 }
    842