1 /* File: describe.c */
2 
3 /* Purpose: object recall */
4 
5 /*
6  * Copyright (c) 1997-2001 Tim Baker
7  *
8  * This software may be copied and distributed for educational, research, and
9  * not for profit purposes provided that this copyright and statement are
10  * included in all such copies.
11  */
12 
13 #include "tnb.h"
14 
15 /*
16  * Like strcpy() but returns the length of the string copied
17  */
strcpy_len(char * s1,const char * s2)18 int strcpy_len(char *s1, const char *s2)
19 {
20 	int len = 0;
21 	while ((*s1++ = *s2++)) ++len;
22 	return len;
23 }
24 
25 /* Global pointer into output buffer */
26 static char *s_buffer;
27 
28 /*
29  * Write a string to the output buffer, plus optional padding
30  */
roll_off(cptr str,bool pad)31 static void roll_off(cptr str, bool pad)
32 {
33 	if (pad) s_buffer += strcpy_len(s_buffer, "  ");
34 	s_buffer += strcpy_len(s_buffer, str);
35 }
36 
37 /*
38  * Remove characters from the output buffer
39  */
roll_back(int count)40 static void roll_back(int count)
41 {
42 	s_buffer -= count;
43 }
44 
45 /*
46  * Write array of strings to output buffer
47  */
roll_em(cptr * vp,int vn,cptr joiner,cptr finish)48 static void roll_em(cptr *vp, int vn, cptr joiner, cptr finish)
49 {
50 	int		i;
51 
52 	for (i = 0; i < vn; ++i)
53 	{
54 		roll_off(vp[i], FALSE);
55 
56 		if (i < vn - 2)
57 			roll_off(", ", FALSE);
58 		else if (i == vn - 2)
59 			roll_off(joiner ? joiner : " and ", FALSE);
60 		else
61 			roll_off(finish ? finish : ".", FALSE);
62 	}
63 }
64 
65 #define TR0_STAT_MASK	\
66         (TR0_STR | TR0_INT | TR0_WIS | TR0_DEX | \
67          TR0_CON | TR0_CHR)
68 
69 #define TR1_SUST_MASK	\
70         (TR1_SUST_STR | TR1_SUST_INT | TR1_SUST_WIS | TR1_SUST_DEX | \
71          TR1_SUST_CON | TR1_SUST_CHR)
72 
73 #define TR_STAT_MASK	0, TR0_STAT_MASK
74 #define TR_SUST_MASK	1, TR1_SUST_MASK
75 
76 /*
77  * Write object memory to a buffer
78  */
angtk_describe_object(object_type * o_ptr,char * buf,bool in_store)79 long angtk_describe_object(object_type *o_ptr, char *buf, bool in_store)
80 {
81 	cptr vp[128];
82 	int vn;
83 
84 	bool known = FALSE;
85 	bool k = FALSE;
86 	bool hack;
87 
88 	/* Set the global. See roll_off(). */
89 	s_buffer = buf;
90 
91 	/* Null-terminate it anyhow */
92 	s_buffer[0] = '\0';
93 
94 	/* See if the object is "known" */
95 	if (object_known_p(o_ptr)) known = TRUE;
96 
97 	/* Mega-Hack -- describe activation */
98 	if (FLAG(o_ptr, TR_ACTIVATE))
99 	{
100 		roll_off("It can be activated for ", k);
101 		roll_off(item_activation(o_ptr), FALSE);
102 		roll_off(" if it is being worn.", FALSE);
103 
104 		k = TRUE;
105 	}
106 
107 	/* Figurines, a hack */
108 	if (o_ptr->tval == TV_FIGURINE)
109 	{
110 		roll_off("It will transform into a pet when thrown.", k);
111 		k = TRUE;
112 	}
113 
114 	/* Bad things */
115 	vn = 0;
116 
117 	hack = FALSE;
118 
119 	if (FLAG(o_ptr, TR_TY_CURSE)) vp[vn++] = "carries an ancient foul curse";
120 
121 	if (cursed_p(o_ptr))
122 	{
123 		if (FLAG(o_ptr, TR_PERMA_CURSE))		vp[vn++] = "is permanently cursed";
124 		else if (FLAG(o_ptr, TR_HEAVY_CURSE)) 	vp[vn++] = "is heavily cursed";
125 		else if (known || (o_ptr->info & OB_SENSE)) vp[vn++] = "is cursed";
126 	}
127 
128 	if (FLAG(o_ptr, TR_DRAIN_EXP))			vp[vn++] = "drains experience";
129 	if (FLAG(o_ptr, TR_TELEPORT)) 			vp[vn++] = "teleports randomly";
130 	if (FLAG(o_ptr, TR_AGGRAVATE))			vp[vn++] = "aggravates monsters";
131 	if (FLAG(o_ptr, TR_NO_MAGIC))    vp[vn++] = "disrupts magic";
132 	if (FLAG(o_ptr, TR_NO_TELE))     vp[vn++] = "inhibits teleportation";
133 
134 	if (vn)
135 	{
136 		roll_off("Unfortunately it ", k);
137 		roll_em(vp, vn, NULL, NULL);
138 
139 		k = TRUE;
140 		hack = TRUE;
141 	}
142 
143 	if ((FLAG(o_ptr, TR_STAT_MASK)) && o_ptr->pval)
144 	{
145 		if (hack && (o_ptr->pval < 0))
146 		{
147 			roll_back(1);
148 			roll_off(",", FALSE);
149 		}
150 		else
151 		{
152 			if (k) roll_off("  ", FALSE);
153 			k = TRUE;
154 		}
155 
156 		roll_off((o_ptr->pval > 0) ? "Increases " : (hack ? " and it decreases " : "Decreases "), FALSE);
157 
158 		vn = 0;
159 
160 		if (FLAG(o_ptr, TR_STR)) vp[vn++] = "Strength";
161 		if (FLAG(o_ptr, TR_INT)) vp[vn++] = "Intelligence";
162 		if (FLAG(o_ptr, TR_WIS)) vp[vn++] = "Wisdom";
163 		if (FLAG(o_ptr, TR_DEX)) vp[vn++] = "Dexterity";
164 		if (FLAG(o_ptr, TR_CON)) vp[vn++] = "Constitution";
165 		if (FLAG(o_ptr, TR_CHR)) vp[vn++] = "Charisma";
166 
167 		if (vn == 6)
168 		{
169 			roll_off("all stats.", FALSE);
170 		}
171 		else
172 		{
173 			roll_em(vp, vn, NULL, NULL);
174 		}
175 	}
176 
177 	/* Effects on skills */
178 	if (o_ptr->pval)
179 	{
180 		vn = 0;
181 
182 		if (FLAG(o_ptr, TR_STEALTH))	vp[vn++] = "Stealth";
183 		if (FLAG(o_ptr, TR_SEARCH)) 	vp[vn++] = "Searching";
184 		if (FLAG(o_ptr, TR_INFRA)) 	vp[vn++] = "Infra-vision";
185 		if (FLAG(o_ptr, TR_BLOWS)) 	vp[vn++] = "number of attacks";
186 		if (FLAG(o_ptr, TR_SPEED)) 	vp[vn++] = "speed";
187 
188 		if (vn)
189 		{
190 			roll_off(o_ptr->pval > 0 ? "Improves " : "Hinders ", k);
191 			roll_em(vp, vn, NULL, NULL);
192 			k = TRUE;
193 		}
194 	}
195 
196 	/* Criticals */
197 	vn = 0;
198 
199 	hack = FALSE;
200 
201 	if (FLAG(o_ptr, TR_BRAND_ACID)) 	vp[vn++] = "acid";
202 	if (FLAG(o_ptr, TR_BRAND_ELEC))	vp[vn++] = "electricity";
203 	if (FLAG(o_ptr, TR_BRAND_FIRE)) 	vp[vn++] = "fire";
204 	if (FLAG(o_ptr, TR_BRAND_COLD))	vp[vn++] = "frost";
205 	if (FLAG(o_ptr, TR_BRAND_POIS))	vp[vn++] = "poison";
206 
207 	if (vn)
208 	{
209 		roll_off("Does extra damage from ", k);
210 		roll_em(vp, vn, NULL, NULL);
211 
212 		k = TRUE;
213 		hack = TRUE;
214 	}
215 
216 	if (FLAG(o_ptr, TR_THROW))
217 	{
218 		if (k) roll_off("  ", FALSE);
219 		roll_off("It is perfectly balanced for throwing.", FALSE);
220 
221 		k = TRUE;
222 		hack = TRUE;
223 	}
224 
225 	/* Misc nastiness */
226 	vn = 0;
227 
228 	if (FLAG(o_ptr, TR_CHAOTIC)) vp[vn++] = "produces chaotic effects";
229 	if (FLAG(o_ptr, TR_VAMPIRIC)) vp[vn++] = "drains life from your foes";
230 	if (FLAG(o_ptr, TR_IMPACT)) vp[vn++] = "causes earthquakes";
231 	if (FLAG(o_ptr, TR_VORPAL)) vp[vn++] = "cuts with supernatural sharpness";
232 
233 	if (vn)
234 	{
235 		roll_off("It ", k);
236 		roll_em(vp, vn, NULL, NULL);
237 
238 		k = TRUE;
239 		hack = TRUE;
240 	}
241 
242 	/* What does it slay? */
243 	vn = 0;
244 
245 	if (FLAG(o_ptr, TR_KILL_DRAGON) || FLAG(o_ptr, TR_SLAY_DRAGON)) 	vp[vn++] = "dragons";
246 	if (FLAG(o_ptr, TR_SLAY_ORC))   	vp[vn++] = "orcs";
247 	if (FLAG(o_ptr, TR_SLAY_TROLL)) 	vp[vn++] = "trolls";
248 	if (FLAG(o_ptr, TR_SLAY_GIANT)) 	vp[vn++] = "giants";
249 	if (FLAG(o_ptr, TR_SLAY_DEMON)) 	vp[vn++] = "demons";
250 	if (FLAG(o_ptr, TR_SLAY_UNDEAD)) 	vp[vn++] = "undead";
251 	if (FLAG(o_ptr, TR_SLAY_ANIMAL)) 	vp[vn++] = "animals";
252 	if (FLAG(o_ptr, TR_SLAY_EVIL)) 	vp[vn++] = "evil";
253 
254 	if (vn)
255 	{
256 		roll_off("Especially deadly against ", k);
257 		roll_em(vp, vn, NULL, NULL);
258 		k = TRUE;
259 	}
260 
261 	/* Sustain stats? */
262 	if (FLAG(o_ptr, TR_SUST_MASK))
263 	{
264 		roll_off("Sustains ", k);
265 
266 		vn = 0;
267 
268 		if (FLAG(o_ptr, TR_SUST_STR)) vp[vn++] = "Strength";
269 		if (FLAG(o_ptr, TR_SUST_INT)) vp[vn++] = "Intelligence";
270 		if (FLAG(o_ptr, TR_SUST_WIS)) vp[vn++] = "Wisdom";
271 		if (FLAG(o_ptr, TR_SUST_DEX)) vp[vn++] = "Dexterity";
272 		if (FLAG(o_ptr, TR_SUST_CON)) vp[vn++] = "Constitution";
273 		if (FLAG(o_ptr, TR_SUST_CHR)) vp[vn++] = "Charisma";
274 
275 		if (vn == 6)
276 		{
277 			roll_off("all stats.", FALSE);
278 		}
279 		else
280 		{
281 			roll_em(vp, vn, NULL, NULL);
282 		}
283 
284 		k = TRUE;
285 	}
286 
287 	/* Immunities */
288 	vn = 0;
289 
290 	if (FLAG(o_ptr, TR_IM_ACID)) 		vp[vn++] = "acid";
291 	if (FLAG(o_ptr, TR_IM_ELEC)) 		vp[vn++] = "electricity";
292 	if (FLAG(o_ptr, TR_IM_FIRE)) 		vp[vn++] = "fire";
293 	if (FLAG(o_ptr, TR_IM_COLD)) 		vp[vn++] = "cold";
294 	if (FLAG(o_ptr, TR_RES_BLIND)) 	vp[vn++] = "blindness";
295 	if (FLAG(o_ptr, TR_FREE_ACT))		vp[vn++] = "paralysis";
296 	if (FLAG(o_ptr, TR_RES_FEAR))		vp[vn++] = "fear";
297 
298 	if (vn)
299 	{
300 		roll_off("Provides immunity to ", k);
301 		k = TRUE;
302 
303 		roll_em(vp, vn, NULL, NULL);
304 	}
305 
306 	/* Resistances */
307 	vn = 0;
308 
309 	if (FLAG(o_ptr, TR_RES_ACID)) 		vp[vn++] = "acid";
310 	if (FLAG(o_ptr, TR_RES_ELEC)) 		vp[vn++] = "electricity";
311 	if (FLAG(o_ptr, TR_RES_FIRE)) 		vp[vn++] = "fire";
312 	if (FLAG(o_ptr, TR_RES_COLD)) 		vp[vn++] = "cold";
313 	if (FLAG(o_ptr, TR_RES_POIS)) 		vp[vn++] = "poison";
314 
315 	if (FLAG(o_ptr, TR_RES_LITE)) 		vp[vn++] = "light";
316 	if (FLAG(o_ptr, TR_RES_DARK))		vp[vn++] = "dark";
317 
318 	if (FLAG(o_ptr, TR_RES_CONF)) 		vp[vn++] = "confusion";
319 	if (FLAG(o_ptr, TR_RES_SOUND)) 	vp[vn++] = "sound";
320 	if (FLAG(o_ptr, TR_RES_SHARDS)) 	vp[vn++] = "shards";
321 
322 	if (FLAG(o_ptr, TR_RES_NETHER)) 	vp[vn++] = "nether";
323 	if (FLAG(o_ptr, TR_RES_NEXUS)) 	vp[vn++] = "nexus";
324 	if (FLAG(o_ptr, TR_RES_CHAOS)) 	vp[vn++] = "chaos";
325 	if (FLAG(o_ptr, TR_RES_DISEN))		vp[vn++] = "disenchantment";
326 	if (FLAG(o_ptr, TR_HOLD_LIFE))		vp[vn++] = "life draining";
327 
328 	if (vn)
329 	{
330 		roll_off("Provides resistance to ", k);
331 		roll_em(vp, vn, NULL, NULL);
332 		k = TRUE;
333 	}
334 
335 	/* What's cool? */
336 	vn = 0;
337 
338 	if (FLAG(o_ptr, TR_FEATHER)) 		vp[vn++] = "feather falling";
339 	if (FLAG(o_ptr, TR_SEE_INVIS)) 	vp[vn++] = "see invisible";
340 	if (FLAG(o_ptr, TR_TELEPATHY)) 	vp[vn++] = "telepathy";
341 	if (FLAG(o_ptr, TR_SLOW_DIGEST)) 	vp[vn++] = "slow digestion";
342 	if (FLAG(o_ptr, TR_REGEN)) 		vp[vn++] = "regeneration";
343 
344 	if (vn)
345 	{
346 		roll_off("Enables ", k);
347 		roll_em(vp, vn, NULL, NULL);
348 		k = TRUE;
349 	}
350 
351 	/* Cool too */
352 	vn = 0;
353 
354 	if (FLAG(o_ptr, TR_REFLECT)) vp[vn++] = "reflects missiles";
355 	if (FLAG(o_ptr, TR_SH_FIRE)) vp[vn++] = "radiates fire";
356 	if (FLAG(o_ptr, TR_SH_ELEC)) vp[vn++] = "radiates electricity";
357 
358 	if (vn)
359 	{
360 		roll_off("It ", k);
361 		roll_em(vp, vn, NULL, NULL);
362 		k = TRUE;
363 	}
364 
365 	/* Powerful bows */
366 	vn = 0;
367 
368 	if (FLAG(o_ptr, TR_XTRA_MIGHT)) 	vp[vn++] = "with extra might";
369 	if (FLAG(o_ptr, TR_XTRA_SHOTS)) 	vp[vn++] = "excessively fast";
370 
371 	if (vn)
372 	{
373 		roll_off("Fires missiles ", k);
374 		roll_em(vp, vn, NULL, NULL);
375 		k = TRUE;
376 	}
377 
378 	/* Misc */
379 	if (FLAG(o_ptr, TR_BLESSED))
380 	{
381 		roll_off("It has been blessed by the gods.", k);
382 		k = TRUE;
383 	}
384 
385 	/* Hack -- describe lite's */
386 	if (o_ptr->tval == TV_LITE)
387 	{
388 		if (FLAG(o_ptr, TR_INSTA_ART))
389 		{
390 			roll_off("It provides light (radius 3) forever.", k);
391 		}
392 		else if (o_ptr->sval == SV_LITE_LANTERN)
393 		{
394 			roll_off("It provides light (radius 2) when fueled.", k);
395 		}
396 		else
397 		{
398 			roll_off("It provides light (radius 1) when fueled.", k);
399 		}
400 
401 		k = TRUE;
402 	}
403 
404 	/* Permanent light source */
405 	if (FLAG(o_ptr, TR_LITE))
406 	{
407 		roll_off("It provides light (radius 1) forever.", k);
408 		k = TRUE;
409 	}
410 
411 	if (FLAG(o_ptr, TR_TUNNEL))
412 	{
413 		roll_off("It is ", k);
414 		roll_off((o_ptr->pval >= 0) ? "an effective" : "a useless", FALSE);
415 		roll_off(" digging tool.", FALSE);
416 		k = TRUE;
417 	}
418 
419 	/* What does the object resist? */
420 	vn = 0;
421 
422 	if (FLAG(o_ptr, TR_IGNORE_ACID)) 	vp[vn++] = "acid";
423 	if (FLAG(o_ptr, TR_IGNORE_ELEC)) 	vp[vn++] = "electricity";
424 	if (FLAG(o_ptr, TR_IGNORE_FIRE)) 	vp[vn++] = "fire";
425 	if (FLAG(o_ptr, TR_IGNORE_COLD)) 	vp[vn++] = "cold";
426 
427 	if (vn)
428 	{
429 		roll_off("It cannot be harmed by ", k);
430 		roll_em(vp, vn, " or ", NULL);
431 		k = TRUE;
432 	}
433 
434 	/* Permanently identified? */
435 	if (o_ptr->info & OB_MENTAL)
436 	{
437 		roll_off("It is permanently identified.", k);
438 		k = TRUE;
439 	}
440 
441 	/* Store bought */
442 	if (!in_store && (o_ptr->info & OB_NO_EXP))
443 	{
444 		roll_off("It was purchased.", k);
445 		k = TRUE;
446 	}
447 
448 	return s_buffer - buf;
449 }
450 
451 
452 /*
453  * Set a field of a Tcl array variable
454  */
SetArrayValueChar(cptr varName,cptr field,char value)455 int SetArrayValueChar(cptr varName, cptr field, char value)
456 {
457 	char string[20];
458 
459 	strnfmt(string, 20, "%c", value);
460 	if (Tcl_SetVar2(g_interp, varName, field, string, TCL_LEAVE_ERR_MSG)
461 		== NULL)
462 	{
463 		return TCL_ERROR;
464 	}
465 	return TCL_OK;
466 }
467 
468 /*
469  * Set a field of a Tcl array variable
470  */
SetArrayValueLong(cptr varName,cptr field,long value)471 int SetArrayValueLong(cptr varName, cptr field, long value)
472 {
473 	char string[20];
474 
475 	strnfmt(string, 20, "%ld", value);
476 	if (Tcl_SetVar2(g_interp, varName, field, string, TCL_LEAVE_ERR_MSG)
477 		== NULL)
478 	{
479 		return TCL_ERROR;
480 	}
481 	return TCL_OK;
482 }
483 
484 /*
485  * Set a field of a Tcl array variable
486  */
SetArrayValueString(cptr varName,cptr field,cptr value)487 int SetArrayValueString(cptr varName, cptr field, cptr value)
488 {
489 	if (Tcl_SetVar2(g_interp, varName, field, value, TCL_LEAVE_ERR_MSG)
490 		== NULL)
491 	{
492 		return TCL_ERROR;
493 	}
494 	return TCL_OK;
495 }
496 
497 /*
498  * Dump object info into a Tcl array variable
499  */
DumpObjectInfo(object_type * o_ptr,char * varName)500 static int DumpObjectInfo(object_type *o_ptr, char *varName)
501 {
502 	int known;
503 	cptr note;
504 
505 	/* Known? */
506 	known = object_known_p(o_ptr) ? 1 : 0;
507 
508 	if (SetArrayValueLong(varName, "known", known) != TCL_OK)
509 	{
510 		return TCL_ERROR;
511 	}
512 
513 	/* Some fields are returned only if the object is "known" */
514 	if (known)
515 	{
516 		if (SetArrayValueLong(varName, "activate",
517 			(FLAG(o_ptr, TR_ACTIVATE)) != 0) != TCL_OK)
518 		{
519 			return TCL_ERROR;
520 		}
521 		if (SetArrayValueLong(varName, "artifact", FLAG(o_ptr, TR_INSTA_ART))
522 			!= TCL_OK)
523 		{
524 			return TCL_ERROR;
525 		}
526 		if (SetArrayValueLong(varName, "pval", o_ptr->pval) != TCL_OK)
527 		{
528 			return TCL_ERROR;
529 		}
530 		if (SetArrayValueLong(varName, "to_a", o_ptr->to_a) != TCL_OK)
531 		{
532 			return TCL_ERROR;
533 		}
534 		if (SetArrayValueLong(varName, "to_d", o_ptr->to_d) != TCL_OK)
535 		{
536 			return TCL_ERROR;
537 		}
538 		if (SetArrayValueLong(varName, "to_h", o_ptr->to_h) != TCL_OK)
539 		{
540 			return TCL_ERROR;
541 		}
542 		if (SetArrayValueLong(varName, "timeout", o_ptr->timeout) != TCL_OK)
543 		{
544 			return TCL_ERROR;
545 		}
546 	}
547 
548 	if (SetArrayValueLong(varName, "ac", o_ptr->ac) != TCL_OK)
549 	{
550 		return TCL_ERROR;
551 	}
552 	if (SetArrayValueLong(varName, "dd", o_ptr->dd) != TCL_OK)
553 	{
554 		return TCL_ERROR;
555 	}
556 	if (SetArrayValueLong(varName, "ds", o_ptr->ds) != TCL_OK)
557 	{
558 		return TCL_ERROR;
559 	}
560 	if (SetArrayValueLong(varName, "k_idx", o_ptr->k_idx) != TCL_OK)
561 	{
562 		return TCL_ERROR;
563 	}
564 	if (SetArrayValueLong(varName, "number", o_ptr->number) != TCL_OK)
565 	{
566 		return TCL_ERROR;
567 	}
568 	if (SetArrayValueLong(varName, "sval", o_ptr->sval) != TCL_OK)
569 	{
570 		return TCL_ERROR;
571 	}
572 	if (SetArrayValueLong(varName, "tval", o_ptr->tval) != TCL_OK)
573 	{
574 		return TCL_ERROR;
575 	}
576 	if (SetArrayValueLong(varName, "weight", o_ptr->weight) != TCL_OK)
577 	{
578 		return TCL_ERROR;
579 	}
580 
581 	note = "";
582 	if (o_ptr->inscription)
583 	{
584 		note = quark_str(o_ptr->inscription);
585 	}
586 	if (ExtToUtf_SetArrayValueString(varName, "note", note) != TCL_OK)
587 	{
588 		return TCL_ERROR;
589 	}
590 
591 	return TCL_OK;
592 }
593 
594 /*
595  * Get verbose info for an inventory item. This should be combined
596  * with the "angband inventory" command. The main difference is it
597  * returns more info.
598  */
objcmd_inveninfo(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])599 int objcmd_inveninfo(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
600 {
601 	CommandInfo *infoCmd = (CommandInfo *) clientData;
602 /*	int objC = objc - infoCmd->depth; */
603 	Tcl_Obj *CONST *objV = objv + infoCmd->depth;
604 
605 	int i_idx;
606 	char *varName;
607 	object_type *o_ptr;
608 
609 	/* Hack - ignore parameter */
610 	(void) objc;
611 
612     if (Tcl_GetIntFromObj(interp, objV[1], &i_idx) != TCL_OK)
613     {
614 		return TCL_ERROR;
615     }
616 
617 	/*** Verify index, existing object ***/
618 
619 	/* Get the array variable name to dump results in */
620 	varName = Tcl_GetStringFromObj(objV[2], NULL);
621 
622 	/* Grab the item */
623 	o_ptr = get_list_item(p_ptr->inventory, i_idx);
624 
625 	return DumpObjectInfo(o_ptr, varName);
626 }
627 
628 /* Textual name of each equipment slot */
629 cptr keyword_slot[] = {
630 	"INVEN_WIELD", "INVEN_BOW", "INVEN_LEFT", "INVEN_RIGHT", "INVEN_NECK",
631 	"INVEN_LITE", "INVEN_BODY", "INVEN_OUTER", "INVEN_ARM", "INVEN_HEAD",
632 	"INVEN_HANDS", "INVEN_FEET",
633 	NULL
634 };
635 
636 /*
637  * Get verbose info for an equipment item. This should be combined
638  * with the "angband equipment" command. The main difference is it
639  * returns more info.
640  */
641 int
objcmd_equipinfo(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])642 objcmd_equipinfo(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
643 {
644 	CommandInfo *infoCmd = (CommandInfo *) clientData;
645 /*	int objC = objc - infoCmd->depth; */
646 	Tcl_Obj *CONST *objV = objv + infoCmd->depth;
647 
648 	int i_idx;
649 	char *varName;
650 	object_type *o_ptr;
651 
652 	/* Hack - ignore parameter */
653 	(void) objc;
654 
655 	/* Get a numerical index or slot name */
656     if (Tcl_GetIntFromObj(interp, objV[1], &i_idx) != TCL_OK)
657     {
658 		Tcl_ResetResult(interp);
659 		if (Tcl_GetIndexFromObj(interp, objV[1], keyword_slot,
660 			"slot", 0, &i_idx) != TCL_OK)
661 		{
662 			return TCL_ERROR;
663 		}
664     }
665 
666 	/*** Verify index, existing object ***/
667 
668 	/* Get the array variable name to dump results in */
669 	varName = Tcl_GetStringFromObj(objV[2], NULL);
670 
671 	/* Grab the item */
672 	o_ptr = &p_ptr->equipment[i_idx];
673 
674 	return DumpObjectInfo(o_ptr, varName);
675 }
676