Angband 3.0.9b.
[angband.git] / src / object1.c
blobd824258be96085c3cb71647e1071190e0191c3fe
1 /* File: object1.c */
3 /*
4 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
9 */
11 #include "angband.h"
12 #include "randname.h"
16 * Max sizes of the following arrays.
18 #define MAX_TITLES 50 /* Used with scrolls (min 48) */
22 * Hold the titles of scrolls, 6 to 14 characters each.
24 * Also keep an array of scroll colors (always WHITE for now).
27 static char scroll_adj[MAX_TITLES][16];
30 static void flavor_assign_fixed(void)
32 int i, j;
34 for (i = 0; i < z_info->flavor_max; i++)
36 flavor_type *flavor_ptr = &flavor_info[i];
38 /* Skip random flavors */
39 if (flavor_ptr->sval == SV_UNKNOWN) continue;
41 for (j = 0; j < z_info->k_max; j++)
43 /* Skip other objects */
44 if ((k_info[j].tval == flavor_ptr->tval) &&
45 (k_info[j].sval == flavor_ptr->sval))
47 /* Store the flavor index */
48 k_info[j].flavor = i;
55 static void flavor_assign_random(byte tval)
57 int i, j;
58 int flavor_count = 0;
59 int choice;
61 /* Count the random flavors for the given tval */
62 for (i = 0; i < z_info->flavor_max; i++)
64 if ((flavor_info[i].tval == tval) &&
65 (flavor_info[i].sval == SV_UNKNOWN))
67 flavor_count++;
71 for (i = 0; i < z_info->k_max; i++)
73 /* Skip other object types */
74 if (k_info[i].tval != tval) continue;
76 /* Skip objects that already are flavored */
77 if (k_info[i].flavor != 0) continue;
79 /* HACK - Ordinary food is "boring" */
80 if ((tval == TV_FOOD) && (k_info[i].sval >= SV_FOOD_MIN_FOOD))
81 continue;
83 if (!flavor_count) quit_fmt("Not enough flavors for tval %d.", tval);
85 /* Select a flavor */
86 choice = rand_int(flavor_count);
88 /* Find and store the flavor */
89 for (j = 0; j < z_info->flavor_max; j++)
91 /* Skip other tvals */
92 if (flavor_info[j].tval != tval) continue;
94 /* Skip assigned svals */
95 if (flavor_info[j].sval != SV_UNKNOWN) continue;
97 if (choice == 0)
99 /* Store the flavor index */
100 k_info[i].flavor = j;
102 /* Mark the flavor as used */
103 flavor_info[j].sval = k_info[i].sval;
105 /* One less flavor to choose from */
106 flavor_count--;
108 break;
111 choice--;
118 * Prepare the "variable" part of the "k_info" array.
120 * The "color"/"metal"/"type" of an item is its "flavor".
121 * For the most part, flavors are assigned randomly each game.
123 * Initialize descriptions for the "colored" objects, including:
124 * Rings, Amulets, Staffs, Wands, Rods, Food, Potions, Scrolls.
126 * The first 4 entries for potions are fixed (Water, Apple Juice,
127 * Slime Mold Juice, Unused Potion).
129 * Scroll titles are always between 6 and 14 letters long. This is
130 * ensured because every title is composed of whole words, where every
131 * word is from 2 to 8 letters long, and that no scroll is finished
132 * until it attempts to grow beyond 15 letters. The first time this
133 * can happen is when the current title has 6 letters and the new word
134 * has 8 letters, which would result in a 6 letter scroll title.
136 * Hack -- make sure everything stays the same for each saved game
137 * This is accomplished by the use of a saved "random seed", as in
138 * "town_gen()". Since no other functions are called while the special
139 * seed is in effect, so this function is pretty "safe".
141 void flavor_init(void)
143 int i, j;
145 /* Hack -- Use the "simple" RNG */
146 Rand_quick = TRUE;
148 /* Hack -- Induce consistant flavors */
149 Rand_value = seed_flavor;
151 flavor_assign_fixed();
153 flavor_assign_random(TV_RING);
154 flavor_assign_random(TV_AMULET);
155 flavor_assign_random(TV_STAFF);
156 flavor_assign_random(TV_WAND);
157 flavor_assign_random(TV_ROD);
158 flavor_assign_random(TV_FOOD);
159 flavor_assign_random(TV_POTION);
160 flavor_assign_random(TV_SCROLL);
162 /* Scrolls (random titles, always white) */
163 for (i = 0; i < MAX_TITLES; i++)
165 char buf[24];
166 char *end = buf;
167 int titlelen = 0;
168 int wordlen;
169 bool okay = TRUE;
171 wordlen = randname_make(RANDNAME_SCROLL, 2, 8, end, 24);
172 while (titlelen + wordlen < (int)(sizeof(scroll_adj[0]) - 1))
174 end[wordlen] = ' ';
175 titlelen += wordlen + 1;
176 end += wordlen + 1;
177 wordlen = randname_make(RANDNAME_SCROLL, 2, 8, end, 24 - titlelen);
179 buf[titlelen - 1] = '\0';
181 /* Check the scroll name hasn't already been generated */
182 for (j = 0; j < i; j++)
184 if (streq(buf, scroll_adj[j]))
186 okay = FALSE;
187 break;
191 if (okay)
193 my_strcpy(scroll_adj[i], buf, sizeof(scroll_adj[0]));
195 else
197 /* Have another go at making a name */
198 i--;
202 /* Hack -- Use the "complex" RNG */
203 Rand_quick = FALSE;
205 /* Analyze every object */
206 for (i = 1; i < z_info->k_max; i++)
208 object_kind *k_ptr = &k_info[i];
210 /* Skip "empty" objects */
211 if (!k_ptr->name) continue;
213 /* No flavor yields aware */
214 if (!k_ptr->flavor) k_ptr->aware = TRUE;
220 #ifdef ALLOW_BORG_GRAPHICS
221 extern void init_translate_visuals(void);
222 #endif /* ALLOW_BORG_GRAPHICS */
226 * Reset the "visual" lists
228 * This involves resetting various things to their "default" state.
230 * If the "prefs" flag is TRUE, then we will also load the appropriate
231 * "user pref file" based on the current setting of the "use_graphics"
232 * flag. This is useful for switching "graphics" on/off.
234 * The features, objects, and monsters, should all be encoded in the
235 * relevant "font.pref" and/or "graf.prf" files. XXX XXX XXX
237 * The "prefs" parameter is no longer meaningful. XXX XXX XXX
239 void reset_visuals(bool unused)
241 int i;
244 /* Unused parameter */
245 (void)unused;
247 /* Extract default attr/char code for features */
248 for (i = 0; i < z_info->f_max; i++)
250 feature_type *f_ptr = &f_info[i];
252 /* Assume we will use the underlying values */
253 f_ptr->x_attr = f_ptr->d_attr;
254 f_ptr->x_char = f_ptr->d_char;
257 /* Extract default attr/char code for objects */
258 for (i = 0; i < z_info->k_max; i++)
260 object_kind *k_ptr = &k_info[i];
262 /* Default attr/char */
263 k_ptr->x_attr = k_ptr->d_attr;
264 k_ptr->x_char = k_ptr->d_char;
267 /* Extract default attr/char code for monsters */
268 for (i = 0; i < z_info->r_max; i++)
270 monster_race *r_ptr = &r_info[i];
272 /* Default attr/char */
273 r_ptr->x_attr = r_ptr->d_attr;
274 r_ptr->x_char = r_ptr->d_char;
277 /* Extract default attr/char code for flavors */
278 for (i = 0; i < z_info->flavor_max; i++)
280 flavor_type *flavor_ptr = &flavor_info[i];
282 /* Default attr/char */
283 flavor_ptr->x_attr = flavor_ptr->d_attr;
284 flavor_ptr->x_char = flavor_ptr->d_char;
287 /* Extract attr/chars for inventory objects (by tval) */
288 for (i = 0; i < (int)N_ELEMENTS(tval_to_attr); i++)
290 /* Default to white */
291 tval_to_attr[i] = TERM_WHITE;
295 /* Graphic symbols */
296 if (use_graphics)
298 /* Process "graf.prf" */
299 process_pref_file("graf.prf");
302 /* Normal symbols */
303 else
305 /* Process "font.prf" */
306 process_pref_file("font.prf");
309 #ifdef ALLOW_BORG_GRAPHICS
310 /* Initialize the translation table for the borg */
311 init_translate_visuals();
312 #endif /* ALLOW_BORG_GRAPHICS */
317 * Modes of object_flags_aux()
319 #define OBJECT_FLAGS_FULL 1 /* Full info */
320 #define OBJECT_FLAGS_KNOWN 2 /* Only flags known to the player */
321 #define OBJECT_FLAGS_RANDOM 3 /* Only known random flags */
325 * Obtain the "flags" for an item
327 static void object_flags_aux(int mode, const object_type *o_ptr, u32b *f1, u32b *f2, u32b *f3)
329 object_kind *k_ptr;
331 if (mode != OBJECT_FLAGS_FULL)
333 /* Clear */
334 (*f1) = (*f2) = (*f3) = 0L;
336 /* Must be identified */
337 if (!object_known_p(o_ptr)) return;
340 if (mode != OBJECT_FLAGS_RANDOM)
342 k_ptr = &k_info[o_ptr->k_idx];
344 /* Base object */
345 (*f1) = k_ptr->flags1;
346 (*f2) = k_ptr->flags2;
347 (*f3) = k_ptr->flags3;
349 if (mode == OBJECT_FLAGS_FULL)
351 /* Artifact */
352 if (o_ptr->name1)
354 artifact_type *a_ptr = &a_info[o_ptr->name1];
356 (*f1) = a_ptr->flags1;
357 (*f2) = a_ptr->flags2;
358 (*f3) = a_ptr->flags3;
362 /* Ego-item */
363 if (o_ptr->name2)
365 ego_item_type *e_ptr = &e_info[o_ptr->name2];
367 (*f1) |= e_ptr->flags1;
368 (*f2) |= e_ptr->flags2;
369 (*f3) |= e_ptr->flags3;
372 if (mode == OBJECT_FLAGS_KNOWN)
374 /* Obvious artifact flags */
375 if (o_ptr->name1)
377 artifact_type *a_ptr = &a_info[o_ptr->name1];
379 /* Obvious flags (pval) */
380 (*f1) = (a_ptr->flags1 & (TR1_PVAL_MASK));
382 (*f3) = (a_ptr->flags3 & (TR3_IGNORE_MASK));
387 if (mode != OBJECT_FLAGS_FULL)
389 bool spoil = FALSE;
391 #ifdef SPOIL_ARTIFACTS
392 /* Full knowledge for some artifacts */
393 if (artifact_p(o_ptr)) spoil = TRUE;
394 #endif /* SPOIL_ARTIFACTS */
396 #ifdef SPOIL_EGO_ITEMS
397 /* Full knowledge for some ego-items */
398 if (ego_item_p(o_ptr)) spoil = TRUE;
399 #endif /* SPOIL_ARTIFACTS */
401 /* Need full knowledge or spoilers */
402 if (!spoil && !(o_ptr->ident & IDENT_MENTAL)) return;
404 /* Artifact */
405 if (o_ptr->name1)
407 artifact_type *a_ptr = &a_info[o_ptr->name1];
409 (*f1) = a_ptr->flags1;
410 (*f2) = a_ptr->flags2;
411 (*f3) = a_ptr->flags3;
413 if (mode == OBJECT_FLAGS_RANDOM)
415 /* Hack - remove 'ignore' flags */
416 (*f3) &= ~(TR3_IGNORE_MASK);
420 /* Full knowledge for *identified* objects */
421 if (!(o_ptr->ident & IDENT_MENTAL)) return;
424 /* Extra powers */
425 switch (o_ptr->xtra1)
427 case OBJECT_XTRA_TYPE_SUSTAIN:
429 /* OBJECT_XTRA_WHAT_SUSTAIN == 2 */
430 (*f2) |= (OBJECT_XTRA_BASE_SUSTAIN << o_ptr->xtra2);
431 break;
434 case OBJECT_XTRA_TYPE_RESIST:
436 /* OBJECT_XTRA_WHAT_RESIST == 2 */
437 (*f2) |= (OBJECT_XTRA_BASE_RESIST << o_ptr->xtra2);
438 break;
441 case OBJECT_XTRA_TYPE_POWER:
443 /* OBJECT_XTRA_WHAT_POWER == 3 */
444 (*f3) |= (OBJECT_XTRA_BASE_POWER << o_ptr->xtra2);
445 break;
453 * Puts a very stripped-down version of an object's name into buf.
454 * If easy_know is TRUE, then the IDed names are used, otherwise
455 * flavours, scroll names, etc will be used.
457 * Just truncates if the buffer isn't big enough.
459 void object_kind_name(char *buf, size_t max, int k_idx, bool easy_know)
461 char *t;
463 object_kind *k_ptr = &k_info[k_idx];
465 /* If not aware, use flavor */
466 if (!easy_know && !k_ptr->aware && k_ptr->flavor)
468 if (k_ptr->tval == TV_SCROLL)
470 strnfmt(buf, max, "\"%s\"", scroll_adj[k_ptr->sval]);
472 else if (k_ptr->tval == TV_FOOD && k_ptr->sval < SV_FOOD_MIN_FOOD)
474 strnfmt(buf, max, "%s Mushroom", flavor_text + flavor_info[k_ptr->flavor].text);
476 else
478 /* Plain flavour (e.g. Copper) will do. */
479 my_strcpy(buf, flavor_text + flavor_info[k_ptr->flavor].text, max);
483 /* Use proper name (Healing, or whatever) */
484 else
486 cptr str = (k_name + k_ptr->name);
488 if (k_ptr->tval == TV_FOOD && k_ptr->sval < SV_FOOD_MIN_FOOD)
490 my_strcpy(buf, "Mushroom of ", max);
491 max -= strlen(buf);
492 t = buf + strlen(buf);
494 else
496 t = buf;
499 /* Skip past leading characters */
500 while ((*str == ' ') || (*str == '&')) str++;
502 /* Copy useful chars */
503 for (; *str && max > 1; str++)
505 /* Pluralizer for irregular plurals */
506 /* Useful for languages where adjective changes for plural */
507 if (*str == '|')
509 /* Process singular part */
510 for (str++; *str != '|' && max > 1; str++)
512 *t++ = *str;
513 max--;
516 /* Process plural part */
517 for (str++; *str != '|'; str++) ;
520 /* English plural indicator can simply be skipped */
521 else if (*str != '~')
523 *t++ = *str;
524 max--;
528 /* Terminate the new name */
529 *t = '\0';
536 * Obtain the "flags" for an item
538 void object_flags(const object_type *o_ptr, u32b *f1, u32b *f2, u32b *f3)
540 object_flags_aux(OBJECT_FLAGS_FULL, o_ptr, f1, f2, f3);
546 * Obtain the "flags" for an item which are known to the player
548 void object_flags_known(const object_type *o_ptr, u32b *f1, u32b *f2, u32b *f3)
550 object_flags_aux(OBJECT_FLAGS_KNOWN, o_ptr, f1, f2, f3);
555 * Efficient version of '(T) += sprintf((T), "%c", (C))'
557 #define object_desc_chr_macro(T,C) do { \
559 /* Copy the char */ \
560 *(T)++ = (C); \
562 } while (0)
567 * Efficient version of '(T) += sprintf((T), "%s", (S))'
569 #define object_desc_str_macro(T,S) do { \
571 cptr s = (S); \
573 /* Copy the string */ \
574 while (*s) *(T)++ = *s++; \
576 } while (0)
581 * Efficient version of '(T) += sprintf((T), "%u", (N))'
583 #define object_desc_num_macro(T,N) do { \
585 int n = (N); \
587 int p; \
589 /* Find "size" of "n" */ \
590 for (p = 1; n >= p * 10; p = p * 10) /* loop */; \
592 /* Dump each digit */ \
593 while (p >= 1) \
595 /* Dump the digit */ \
596 *(T)++ = I2D(n / p); \
598 /* Remove the digit */ \
599 n = n % p; \
601 /* Process next digit */ \
602 p = p / 10; \
605 } while (0)
610 * Efficient version of '(T) += sprintf((T), "%+d", (I))'
612 #define object_desc_int_macro(T,I) do { \
614 int i = (I); \
616 /* Negative */ \
617 if (i < 0) \
619 /* Take the absolute value */ \
620 i = 0 - i; \
622 /* Use a "minus" sign */ \
623 *(T)++ = '-'; \
626 /* Positive (or zero) */ \
627 else \
629 /* Use a "plus" sign */ \
630 *(T)++ = '+'; \
633 /* Dump the number itself */ \
634 object_desc_num_macro(T, i); \
636 } while (0)
642 * Creates a description of the item "o_ptr", and stores it in "buf".
644 * One can choose the "verbosity" of the description, including whether
645 * or not the "number" of items should be described, and how much detail
646 * should be used when describing the item.
648 * The given "buf" should be at least 80 chars long to hold the longest
649 * possible description, which can get pretty long, including inscriptions,
650 * such as:
651 * "no more Maces of Disruption (Defender) (+10,+10) [+5] (+3 to stealth)".
653 * Note that the object description will be clipped to fit into the given
654 * buffer size.
656 * Note the use of "object_desc_int_macro()" and "object_desc_num_macro()"
657 * and "object_desc_str_macro()" and "object_desc_chr_macro()" as extremely
658 * efficient, portable, versions of some common "sprintf()" commands (without
659 * the bounds checking or termination writing), which allow a pointer to
660 * efficiently move through a buffer while modifying it in various ways.
662 * Various improper uses and/or placements of "&" or "~" characters can
663 * easily induce out-of-bounds memory accesses. Some of these could be
664 * easily checked for, if efficiency was not a concern.
666 * Note that all ego-items (when known) append an "Ego-Item Name", unless
667 * the item is also an artifact, which should never happen.
669 * Note that all artifacts (when known) append an "Artifact Name", so we
670 * have special processing for "Specials" (artifact Lites, Rings, Amulets).
671 * The "Specials" never use "modifiers" if they are "known", since they
672 * have special "descriptions", such as "The Necklace of the Dwarves".
674 * Special Lite's use the "k_info" base-name (Phial, Star, or Arkenstone),
675 * plus the artifact name, just like any other artifact, if known.
677 * Special Ring's and Amulet's, if not "aware", use the same code as normal
678 * rings and amulets, and if "aware", use the "k_info" base-name (Ring or
679 * Amulet or Necklace). They will NEVER "append" the "k_info" name. But,
680 * they will append the artifact name, just like any artifact, if known.
682 * None of the Special Rings/Amulets are "EASY_KNOW", though they could be,
683 * at least, those which have no "pluses", such as the three artifact lites.
685 * The "pluralization" rules are extremely hackish, in fact, for efficiency,
686 * we only handle things like "torch"/"torches" and "cutlass"/"cutlasses",
687 * and we would not handle "box"/"boxes", or "knife"/"knives", correctly.
688 * Of course, it would be easy to add rules for these forms.
690 * If "pref" is true then a "numeric" prefix will be pre-pended, else is is
691 * assumed that a string such as "The" or "Your" will be pre-pended later.
693 * Modes ("pref" is TRUE):
694 * 0 -- Chain Mail of Death
695 * 1 -- A Cloak of Death [1,+3]
696 * 2 -- An Amulet of Death [1,+3] (+2 to Stealth)
697 * 3 -- 5 Rings of Death [1,+3] (+2 to Stealth) {nifty} (squelch)
698 * 4 -- 5 Rings of Death [1,+3] (+2 to Stealth) {nifty}
700 * Modes ("pref" is FALSE):
701 * 0 -- Chain Mail of Death
702 * 1 -- Cloak of Death [1,+3]
703 * 2 -- Amulet of Death [1,+3] (+2 to Stealth)
704 * 3 -- Rings of Death [1,+3] (+2 to Stealth) {nifty} (squelch)
705 * 4 -- Rings of Death [1,+3] (+2 to Stealth) {nifty}
707 void object_desc(char *buf, size_t max, const object_type *o_ptr, int pref, int mode)
709 cptr basenm;
710 cptr modstr;
712 int power;
714 bool aware;
715 bool known;
717 bool flavor;
719 bool append_name;
721 bool show_weapon;
722 bool show_armour;
724 char *b;
726 char *t;
728 cptr s;
730 cptr u;
731 cptr v;
733 char p1 = '(', p2 = ')';
734 char b1 = '[', b2 = ']';
735 char c1 = '{', c2 = '}';
737 char tmp_buf[128];
739 u32b f1, f2, f3;
741 object_kind *k_ptr = &k_info[o_ptr->k_idx];
744 /* Extract some flags */
745 object_flags(o_ptr, &f1, &f2, &f3);
748 /* See if the object is "aware" */
749 aware = (object_aware_p(o_ptr) ? TRUE : FALSE);
751 /* See if the object is "known" */
752 known = (object_known_p(o_ptr) ? TRUE : FALSE);
754 /* See if the object is "flavored" */
755 flavor = (k_ptr->flavor ? TRUE : FALSE);
757 /* Allow flavors to be hidden when aware */
758 if (aware && !show_flavors) flavor = FALSE;
760 /* Hack -- mark-to-squelch worthless items XXX */
761 if (!k_ptr->everseen && aware && OPTION(squelch_worthless))
763 if (object_value(o_ptr) == 0)
765 k_ptr->squelch = TRUE;
766 p_ptr->notice |= PN_SQUELCH;
770 /* We've seen it at least once now we're aware of it */
771 if (aware) k_ptr->everseen = TRUE;
773 /* Object is in the inventory of a store */
774 if (o_ptr->ident & IDENT_STORE)
776 /* Don't show flavors */
777 flavor = FALSE;
779 /* Pretend known and aware */
780 aware = TRUE;
781 known = TRUE;
785 /* XXX anything object_desc'd can be squelched */
786 if (aware) k_ptr->everseen = TRUE;
788 /* Assume no name appending */
789 append_name = FALSE;
791 /* Assume no need to show "weapon" bonuses */
792 show_weapon = FALSE;
794 /* Assume no need to show "armour" bonuses */
795 show_armour = FALSE;
797 /* Extract default "base" string */
798 basenm = (k_name + k_ptr->name);
800 /* Assume no "modifier" string */
801 modstr = "";
804 /* Analyze the object */
805 switch (o_ptr->tval)
807 /* Some objects are easy to describe */
808 case TV_SKELETON:
809 case TV_BOTTLE:
810 case TV_JUNK:
811 case TV_SPIKE:
812 case TV_FLASK:
813 case TV_CHEST:
815 break;
818 /* Missiles/Bows/Weapons */
819 case TV_SHOT:
820 case TV_BOLT:
821 case TV_ARROW:
822 case TV_BOW:
823 case TV_HAFTED:
824 case TV_POLEARM:
825 case TV_SWORD:
826 case TV_DIGGING:
828 show_weapon = TRUE;
829 break;
832 /* Armour */
833 case TV_BOOTS:
834 case TV_GLOVES:
835 case TV_CLOAK:
836 case TV_CROWN:
837 case TV_HELM:
838 case TV_SHIELD:
839 case TV_SOFT_ARMOR:
840 case TV_HARD_ARMOR:
841 case TV_DRAG_ARMOR:
843 show_armour = TRUE;
844 break;
847 /* Lites (including a few "Specials") */
848 case TV_LITE:
850 break;
853 /* Amulets (including a few "Specials") */
854 case TV_AMULET:
856 /* Hack -- Known artifacts */
857 if (artifact_p(o_ptr) && aware) break;
859 /* Color the object */
860 modstr = flavor_text + flavor_info[k_ptr->flavor].text;
861 if (aware) append_name = TRUE;
862 basenm = (flavor ? "& # Amulet~" : "& Amulet~");
864 break;
867 /* Rings (including a few "Specials") */
868 case TV_RING:
870 /* Hack -- Known artifacts */
871 if (artifact_p(o_ptr) && aware) break;
873 /* Color the object */
874 modstr = flavor_text + flavor_info[k_ptr->flavor].text;
875 if (aware) append_name = TRUE;
876 basenm = (flavor ? "& # Ring~" : "& Ring~");
878 break;
881 /* Staffs */
882 case TV_STAFF:
884 /* Color the object */
885 modstr = flavor_text + flavor_info[k_ptr->flavor].text;
886 if (aware) append_name = TRUE;
887 basenm = (flavor ? "& # Staff~" : "& Staff~");
889 break;
892 /* Wands */
893 case TV_WAND:
895 /* Color the object */
896 modstr = flavor_text + flavor_info[k_ptr->flavor].text;
897 if (aware) append_name = TRUE;
898 basenm = (flavor ? "& # Wand~" : "& Wand~");
900 break;
903 /* Rods */
904 case TV_ROD:
906 /* Color the object */
907 modstr = flavor_text + flavor_info[k_ptr->flavor].text;
908 if (aware) append_name = TRUE;
909 basenm = (flavor ? "& # Rod~" : "& Rod~");
911 break;
914 /* Scrolls */
915 case TV_SCROLL:
917 /* Color the object */
918 modstr = scroll_adj[o_ptr->sval];
919 if (aware) append_name = TRUE;
920 basenm = (flavor ? "& Scroll~ titled \"#\"" : "& Scroll~");
922 break;
925 /* Potions */
926 case TV_POTION:
928 /* Color the object */
929 modstr = flavor_text + flavor_info[k_ptr->flavor].text;
930 if (aware) append_name = TRUE;
931 basenm = (flavor ? "& # Potion~" : "& Potion~");
933 break;
936 /* Food */
937 case TV_FOOD:
939 /* Ordinary food is "boring" */
940 if (o_ptr->sval >= SV_FOOD_MIN_FOOD) break;
942 /* Color the object */
943 modstr = flavor_text + flavor_info[k_ptr->flavor].text;
944 if (aware) append_name = TRUE;
945 basenm = (flavor ? "& # Mushroom~" : "& Mushroom~");
947 break;
950 /* Magic Books */
951 case TV_MAGIC_BOOK:
953 modstr = basenm;
954 basenm = "& Book~ of Magic Spells #";
955 break;
958 /* Prayer Books */
959 case TV_PRAYER_BOOK:
961 modstr = basenm;
962 basenm = "& Holy Book~ of Prayers #";
963 break;
966 /* Hack -- Gold/Gems */
967 case TV_GOLD:
969 my_strcpy(buf, basenm, max);
970 return;
973 /* Hack -- Default -- Used in the "inventory" routine */
974 default:
976 my_strcpy(buf, "(nothing)", max);
977 return;
982 /* Start dumping the result */
983 t = b = tmp_buf;
985 /* Begin */
986 s = basenm;
988 /* Handle objects which sometimes use "a" or "an" */
989 if (*s == '&')
991 /* Paranoia XXX XXX XXX */
992 /* ASSERT(s[1] == ' '); */
994 /* Skip the ampersand and the following space */
995 s += 2;
997 /* No prefix */
998 if (!pref)
1000 /* Nothing */
1003 /* Hack -- None left */
1004 else if (o_ptr->number <= 0)
1006 object_desc_str_macro(t, "no more ");
1009 /* Extract the number */
1010 else if (o_ptr->number > 1)
1012 object_desc_num_macro(t, o_ptr->number);
1013 object_desc_chr_macro(t, ' ');
1016 /* Hack -- The only one of its kind */
1017 else if (known && artifact_p(o_ptr))
1019 object_desc_str_macro(t, "The ");
1022 /* Hack -- A single one, and next character will be a vowel */
1023 else if ((*s == '#') ? is_a_vowel(modstr[0]) : is_a_vowel(*s))
1025 object_desc_str_macro(t, "an ");
1028 /* A single one, and next character will be a non-vowel */
1029 else
1031 object_desc_str_macro(t, "a ");
1035 /* Handle objects which never use "a" or "an" */
1036 else
1038 /* No pref */
1039 if (!pref)
1041 /* Nothing */
1044 /* Hack -- all gone */
1045 else if (o_ptr->number <= 0)
1047 object_desc_str_macro(t, "no more ");
1050 /* Prefix a number if required */
1051 else if (o_ptr->number > 1)
1053 object_desc_num_macro(t, o_ptr->number);
1054 object_desc_chr_macro(t, ' ');
1057 /* Hack -- The only one of its kind */
1058 else if (known && artifact_p(o_ptr))
1060 object_desc_str_macro(t, "The ");
1063 /* Hack -- A single item, so no prefix needed */
1064 else
1066 /* Nothing */
1071 /* Paranoia XXX XXX XXX */
1072 /* ASSERT(*s != '~'); */
1074 /* Copy the string */
1075 for (; *s; s++)
1077 /* Pluralizer (regular English plurals) */
1078 if (*s == '~')
1080 /* Add a plural if needed */
1081 if ((o_ptr->number != 1) && !(known && artifact_p(o_ptr)))
1083 char k = t[-1];
1085 /* Hack -- "Cutlass-es" and "Torch-es" */
1086 if ((k == 's') || (k == 'h')) *t++ = 'e';
1088 /* Add an 's' */
1089 *t++ = 's';
1093 /* Pluralizer for irregular plurals */
1094 else if (*s == '|')
1096 bool singular = (o_ptr->number == 1);
1098 /* Process singular part */
1099 for (s++; *s != '|'; s++)
1101 if (singular) *t++ = *s;
1104 /* Process plural part */
1105 for (s++; *s != '|'; s++)
1107 if (!singular) *t++ = *s;
1111 /* Modifier */
1112 else if (*s == '#')
1114 /* Append the modifier */
1115 cptr m = (modstr);
1117 for (; *m; m++)
1119 /* Handle pluralization in the modifier */
1120 if (*m != '|')
1122 /* Normal character - copy */
1123 *t++ = *m;
1125 else
1127 /* Pluralizer */
1128 bool singular = (o_ptr->number == 1);
1130 /* Process singular part */
1131 for (m++; *m != '|'; m++)
1133 if (singular) *t++ = *m;
1136 /* Process plural part */
1137 for (m++; *m != '|'; m++)
1139 if (!singular) *t++ = *m;
1145 /* Normal */
1146 else
1148 /* Copy */
1149 *t++ = *s;
1154 /* Append the "kind name" to the "base name" */
1155 if (append_name)
1157 object_desc_str_macro(t, " of ");
1158 object_desc_str_macro(t, (k_name + k_ptr->name));
1162 /* Hack -- Append "Artifact" or "Special" names */
1163 if (known)
1165 /* Grab any artifact name */
1166 if (o_ptr->name1)
1168 artifact_type *a_ptr = &a_info[o_ptr->name1];
1170 object_desc_chr_macro(t, ' ');
1171 object_desc_str_macro(t, (a_name + a_ptr->name));
1174 /* Grab any ego-item name */
1175 else if (o_ptr->name2)
1177 ego_item_type *e_ptr = &e_info[o_ptr->name2];
1179 object_desc_chr_macro(t, ' ');
1180 object_desc_str_macro(t, (e_name + e_ptr->name));
1182 /* Hack - Now we know about the ego-item type */
1183 e_info[o_ptr->name2].everseen = TRUE;
1189 /* No more details wanted */
1190 if (mode < 1) goto object_desc_done;
1193 /* Hack -- Chests must be described in detail */
1194 if (o_ptr->tval == TV_CHEST)
1196 cptr tail = "";
1198 /* Not searched yet */
1199 if (!known)
1201 /* Nothing */
1204 /* May be "empty" */
1205 else if (!o_ptr->pval)
1207 tail = " (empty)";
1210 /* May be "disarmed" */
1211 else if (o_ptr->pval < 0)
1213 if (chest_traps[0 - o_ptr->pval])
1215 tail = " (disarmed)";
1217 else
1219 tail = " (unlocked)";
1223 /* Describe the traps, if any */
1224 else
1226 /* Describe the traps */
1227 switch (chest_traps[o_ptr->pval])
1229 case 0:
1231 tail = " (Locked)";
1232 break;
1234 case CHEST_LOSE_STR:
1236 tail = " (Poison Needle)";
1237 break;
1239 case CHEST_LOSE_CON:
1241 tail = " (Poison Needle)";
1242 break;
1244 case CHEST_POISON:
1246 tail = " (Gas Trap)";
1247 break;
1249 case CHEST_PARALYZE:
1251 tail = " (Gas Trap)";
1252 break;
1254 case CHEST_EXPLODE:
1256 tail = " (Explosion Device)";
1257 break;
1259 case CHEST_SUMMON:
1261 tail = " (Summoning Runes)";
1262 break;
1264 default:
1266 tail = " (Multiple Traps)";
1267 break;
1272 /* Append the tail */
1273 object_desc_str_macro(t, tail);
1277 /* Display the item like a weapon */
1278 if (f3 & (TR3_SHOW_MODS)) show_weapon = TRUE;
1280 /* Display the item like a weapon */
1281 if (o_ptr->to_h && o_ptr->to_d) show_weapon = TRUE;
1283 /* Display the item like armour */
1284 if (o_ptr->ac) show_armour = TRUE;
1287 /* Dump base weapon info */
1288 switch (o_ptr->tval)
1290 /* Missiles */
1291 case TV_SHOT:
1292 case TV_BOLT:
1293 case TV_ARROW:
1295 /* Fall through */
1298 /* Weapons */
1299 case TV_HAFTED:
1300 case TV_POLEARM:
1301 case TV_SWORD:
1302 case TV_DIGGING:
1304 /* Append a "damage" string */
1305 object_desc_chr_macro(t, ' ');
1306 object_desc_chr_macro(t, p1);
1307 object_desc_num_macro(t, o_ptr->dd);
1308 object_desc_chr_macro(t, 'd');
1309 object_desc_num_macro(t, o_ptr->ds);
1310 object_desc_chr_macro(t, p2);
1312 /* All done */
1313 break;
1316 /* Bows */
1317 case TV_BOW:
1319 /* Hack -- Extract the "base power" */
1320 power = (o_ptr->sval % 10);
1322 /* Append a "power" string */
1323 object_desc_chr_macro(t, ' ');
1324 object_desc_chr_macro(t, p1);
1325 object_desc_chr_macro(t, 'x');
1326 object_desc_num_macro(t, power);
1327 object_desc_chr_macro(t, p2);
1329 /* All done */
1330 break;
1335 /* Add the weapon bonuses */
1336 if (known)
1338 /* Show the tohit/todam on request */
1339 if (show_weapon)
1341 object_desc_chr_macro(t, ' ');
1342 object_desc_chr_macro(t, p1);
1343 object_desc_int_macro(t, o_ptr->to_h);
1344 object_desc_chr_macro(t, ',');
1345 object_desc_int_macro(t, o_ptr->to_d);
1346 object_desc_chr_macro(t, p2);
1349 /* Show the tohit if needed */
1350 else if (o_ptr->to_h)
1352 object_desc_chr_macro(t, ' ');
1353 object_desc_chr_macro(t, p1);
1354 object_desc_int_macro(t, o_ptr->to_h);
1355 object_desc_chr_macro(t, p2);
1358 /* Show the todam if needed */
1359 else if (o_ptr->to_d)
1361 object_desc_chr_macro(t, ' ');
1362 object_desc_chr_macro(t, p1);
1363 object_desc_int_macro(t, o_ptr->to_d);
1364 object_desc_chr_macro(t, p2);
1369 /* Add the armor bonuses */
1370 if (known)
1372 /* Show the armor class info */
1373 if (show_armour)
1375 object_desc_chr_macro(t, ' ');
1376 object_desc_chr_macro(t, b1);
1377 object_desc_num_macro(t, o_ptr->ac);
1378 object_desc_chr_macro(t, ',');
1379 object_desc_int_macro(t, o_ptr->to_a);
1380 object_desc_chr_macro(t, b2);
1383 /* No base armor, but does increase armor */
1384 else if (o_ptr->to_a)
1386 object_desc_chr_macro(t, ' ');
1387 object_desc_chr_macro(t, b1);
1388 object_desc_int_macro(t, o_ptr->to_a);
1389 object_desc_chr_macro(t, b2);
1393 /* Hack -- always show base armor */
1394 else if (show_armour)
1396 object_desc_chr_macro(t, ' ');
1397 object_desc_chr_macro(t, b1);
1398 object_desc_num_macro(t, o_ptr->ac);
1399 object_desc_chr_macro(t, b2);
1403 /* No more details wanted */
1404 if (mode < 2) goto object_desc_done;
1406 /* Fuelled light sources get number of remaining turns appended */
1407 if ((o_ptr->tval == TV_LITE) && !(f3 & TR3_NO_FUEL))
1409 /* Turns of light for normal lites */
1410 object_desc_str_macro(t, " (");
1411 object_desc_num_macro(t, o_ptr->timeout);
1412 object_desc_str_macro(t, " turns)");
1416 /* Dump "pval" flags for wearable items */
1417 if (known && (f1 & (TR1_PVAL_MASK)))
1419 cptr tail = "";
1420 cptr tail2 = "";
1422 /* Start the display */
1423 object_desc_chr_macro(t, ' ');
1424 object_desc_chr_macro(t, p1);
1426 /* Dump the "pval" itself */
1427 object_desc_int_macro(t, o_ptr->pval);
1429 /* Do not display the "pval" flags */
1430 if (f3 & (TR3_HIDE_TYPE))
1432 /* Nothing */
1435 /* Stealth */
1436 else if (f1 & (TR1_STEALTH))
1438 /* Dump " to stealth" */
1439 tail = " to stealth";
1442 /* Searching */
1443 else if (f1 & (TR1_SEARCH))
1445 /* Dump " to searching" */
1446 tail = " to searching";
1449 /* Infravision */
1450 else if (f1 & (TR1_INFRA))
1452 /* Dump " to infravision" */
1453 tail = " to infravision";
1456 #if 0
1458 /* Tunneling */
1459 else if (f1 & (TR1_TUNNEL))
1461 /* Dump " to digging" */
1462 tail = " to digging";
1465 #endif
1467 /* Speed */
1468 else if (f1 & (TR1_SPEED))
1470 /* Dump " to speed" */
1471 tail = " to speed";
1474 /* Blows */
1475 else if (f1 & (TR1_BLOWS))
1477 /* Add " attack" */
1478 tail = " attack";
1480 /* Add "attacks" */
1481 if (ABS(o_ptr->pval) != 1) tail2 = "s";
1484 #if 0
1486 /* Shots */
1487 else if (f1 & (TR1_SHOTS))
1489 /* Nothing */
1492 /* Might */
1493 else if (f1 & (TR1_MIGHT))
1495 /* Nothing */
1498 #endif
1500 /* Add the descriptor */
1501 object_desc_str_macro(t, tail);
1502 object_desc_str_macro(t, tail2);
1504 /* Finish the display */
1505 object_desc_chr_macro(t, p2);
1508 /* Hack -- Wands and Staffs have charges */
1509 if (known &&
1510 ((o_ptr->tval == TV_STAFF) ||
1511 (o_ptr->tval == TV_WAND)))
1513 /* Dump " (N charges)" */
1514 object_desc_chr_macro(t, ' ');
1515 object_desc_chr_macro(t, p1);
1516 object_desc_num_macro(t, o_ptr->pval);
1517 object_desc_str_macro(t, " charge");
1518 if (o_ptr->pval != 1)
1520 object_desc_chr_macro(t, 's');
1522 object_desc_chr_macro(t, p2);
1525 /* Hack -- Rods have a "charging" indicator */
1526 else if (known && (o_ptr->tval == TV_ROD))
1528 /* Hack -- Dump " (# charging)" if relevant */
1529 if (o_ptr->timeout > 0)
1531 /* Stacks of rods display an exact count of charging rods. */
1532 if (o_ptr->number > 1)
1534 /* Paranoia */
1535 if (k_ptr->pval == 0) k_ptr->pval = 1;
1537 /* Find out how many rods are charging, by dividing
1538 * current timeout by each rod's maximum timeout.
1539 * Ensure that any remainder is rounded up. Display
1540 * very discharged stacks as merely fully discharged.
1542 power = (o_ptr->timeout + (k_ptr->pval - 1)) / k_ptr->pval;
1544 if (power > o_ptr->number) power = o_ptr->number;
1546 /* Display prettily */
1547 object_desc_str_macro(t, " (");
1548 object_desc_num_macro(t, power);
1549 object_desc_str_macro(t, " charging)");
1551 else
1553 /* Single rod */
1554 object_desc_str_macro(t, " (charging)");
1559 /* Indicate "charging" artifacts */
1560 else if (known && o_ptr->timeout && !(o_ptr->tval == TV_LITE && !artifact_p(o_ptr)))
1562 /* Hack -- Dump " (charging)" if relevant */
1563 object_desc_str_macro(t, " (charging)");
1567 /* No more details wanted */
1568 if (mode < 3) goto object_desc_done;
1571 /* Use standard inscription */
1572 if (o_ptr->note)
1574 u = quark_str(o_ptr->note);
1577 /* Use nothing */
1578 else
1580 u = NULL;
1585 /* Use special inscription, if any */
1586 if (o_ptr->pseudo)
1588 v = inscrip_text[o_ptr->pseudo];
1591 /* Use "cursed" if the item is known to be cursed */
1592 else if (cursed_p(o_ptr) && known)
1594 v = "cursed";
1597 /* Hack -- Use "empty" for empty wands/staffs */
1598 else if (!known && (o_ptr->ident & (IDENT_EMPTY)))
1600 v = "empty";
1603 /* Use "tried" if the object has been tested unsuccessfully */
1604 else if (!aware && object_tried_p(o_ptr))
1606 v = "tried";
1609 /* Nothing */
1610 else
1612 v = NULL;
1616 /* Inscription */
1617 if (u || v)
1619 /* Begin the inscription */
1620 *t++ = ' ';
1621 *t++ = c1;
1623 /* Standard inscription */
1624 if (u)
1626 /* Append the inscription */
1627 while ((t < b + 75) && *u) *t++ = *u++;
1630 /* Special inscription too */
1631 if (u && v && (t < b + 75))
1633 /* Separator */
1634 *t++ = ',';
1635 *t++ = ' ';
1638 /* Special inscription */
1639 if (v)
1641 /* Append the inscription */
1642 while ((t < b + 75) && *v) *t++ = *v++;
1645 /* Terminate the inscription */
1646 *t++ = c2;
1650 /* Add squelch marker unless mode == 4 (in-store) */
1651 if (mode != 4 && !hide_squelchable && squelch_item_ok(o_ptr))
1652 object_desc_str_macro(t, " (squelch)");
1655 object_desc_done:
1657 /* Terminate */
1658 *t = '\0';
1660 /* Copy the string over */
1661 my_strcpy(buf, tmp_buf, max);
1666 * Describe an item and pretend the item is fully known and has no flavor.
1668 void object_desc_spoil(char *buf, size_t max, const object_type *o_ptr, int pref, int mode)
1670 object_type object_type_body;
1671 object_type *i_ptr = &object_type_body;
1673 /* Make a backup */
1674 object_copy(i_ptr, o_ptr);
1676 /* HACK - Pretend the object is in a store inventory */
1677 i_ptr->ident |= IDENT_STORE;
1679 /* Describe */
1680 object_desc(buf, max, i_ptr, pref, mode);
1685 * Describe an item's random attributes for "character dumps"
1687 void identify_random_gen(const object_type *o_ptr)
1689 /* Set hooks for character dump */
1690 object_info_out_flags = object_flags_known;
1692 /* Set the indent/wrap */
1693 text_out_indent = 3;
1694 text_out_wrap = 72;
1696 /* Dump the info */
1697 if (object_info_out(o_ptr))
1698 text_out("\n");
1700 /* Reset indent/wrap */
1701 text_out_indent = 0;
1702 text_out_wrap = 0;
1707 * Convert an inventory index into a one character label.
1709 * Note that the label does NOT distinguish inven/equip.
1711 char index_to_label(int i)
1713 /* Indexes for "inven" are easy */
1714 if (i < INVEN_WIELD) return (I2A(i));
1716 /* Indexes for "equip" are offset */
1717 return (I2A(i - INVEN_WIELD));
1722 * Convert a label into the index of an item in the "inven".
1724 * Return "-1" if the label does not indicate a real item.
1726 s16b label_to_inven(int c)
1728 int i;
1730 /* Convert */
1731 i = (islower((unsigned char)c) ? A2I(c) : -1);
1733 /* Verify the index */
1734 if ((i < 0) || (i > INVEN_PACK)) return (-1);
1736 /* Empty slots can never be chosen */
1737 if (!inventory[i].k_idx) return (-1);
1739 /* Return the index */
1740 return (i);
1745 * Convert a label into the index of a item in the "equip".
1747 * Return "-1" if the label does not indicate a real item.
1749 s16b label_to_equip(int c)
1751 int i;
1753 /* Convert */
1754 i = (islower((unsigned char)c) ? A2I(c) : -1) + INVEN_WIELD;
1756 /* Verify the index */
1757 if ((i < INVEN_WIELD) || (i >= INVEN_TOTAL)) return (-1);
1759 /* Empty slots can never be chosen */
1760 if (!inventory[i].k_idx) return (-1);
1762 /* Return the index */
1763 return (i);
1769 * Determine which equipment slot (if any) an item likes
1771 s16b wield_slot(const object_type *o_ptr)
1773 /* Slot for equipment */
1774 switch (o_ptr->tval)
1776 case TV_DIGGING:
1777 case TV_HAFTED:
1778 case TV_POLEARM:
1779 case TV_SWORD:
1781 return (INVEN_WIELD);
1784 case TV_BOW:
1786 return (INVEN_BOW);
1789 case TV_RING:
1791 /* Use the right hand first */
1792 if (!inventory[INVEN_RIGHT].k_idx) return (INVEN_RIGHT);
1794 /* Use the left hand for swapping (by default) */
1795 return (INVEN_LEFT);
1798 case TV_AMULET:
1800 return (INVEN_NECK);
1803 case TV_LITE:
1805 return (INVEN_LITE);
1808 case TV_DRAG_ARMOR:
1809 case TV_HARD_ARMOR:
1810 case TV_SOFT_ARMOR:
1812 return (INVEN_BODY);
1815 case TV_CLOAK:
1817 return (INVEN_OUTER);
1820 case TV_SHIELD:
1822 return (INVEN_ARM);
1825 case TV_CROWN:
1826 case TV_HELM:
1828 return (INVEN_HEAD);
1831 case TV_GLOVES:
1833 return (INVEN_HANDS);
1836 case TV_BOOTS:
1838 return (INVEN_FEET);
1842 /* No slot available */
1843 return (-1);
1848 * Return a string mentioning how a given item is carried
1850 cptr mention_use(int i)
1852 cptr p;
1854 /* Examine the location */
1855 switch (i)
1857 case INVEN_WIELD: p = "Wielding"; break;
1858 case INVEN_BOW: p = "Shooting"; break;
1859 case INVEN_LEFT: p = "On left hand"; break;
1860 case INVEN_RIGHT: p = "On right hand"; break;
1861 case INVEN_NECK: p = "Around neck"; break;
1862 case INVEN_LITE: p = "Light source"; break;
1863 case INVEN_BODY: p = "On body"; break;
1864 case INVEN_OUTER: p = "About body"; break;
1865 case INVEN_ARM: p = "On arm"; break;
1866 case INVEN_HEAD: p = "On head"; break;
1867 case INVEN_HANDS: p = "On hands"; break;
1868 case INVEN_FEET: p = "On feet"; break;
1869 default: p = "In pack"; break;
1872 /* Hack -- Heavy weapon */
1873 if (i == INVEN_WIELD)
1875 object_type *o_ptr;
1876 o_ptr = &inventory[i];
1877 if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
1879 p = "Just lifting";
1883 /* Hack -- Heavy bow */
1884 if (i == INVEN_BOW)
1886 object_type *o_ptr;
1887 o_ptr = &inventory[i];
1888 if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
1890 p = "Just holding";
1894 /* Return the result */
1895 return (p);
1900 * Return a string describing how a given item is being worn.
1901 * Currently, only used for items in the equipment, not inventory.
1903 cptr describe_use(int i)
1905 cptr p;
1907 switch (i)
1909 case INVEN_WIELD: p = "attacking monsters with"; break;
1910 case INVEN_BOW: p = "shooting missiles with"; break;
1911 case INVEN_LEFT: p = "wearing on your left hand"; break;
1912 case INVEN_RIGHT: p = "wearing on your right hand"; break;
1913 case INVEN_NECK: p = "wearing around your neck"; break;
1914 case INVEN_LITE: p = "using to light the way"; break;
1915 case INVEN_BODY: p = "wearing on your body"; break;
1916 case INVEN_OUTER: p = "wearing on your back"; break;
1917 case INVEN_ARM: p = "wearing on your arm"; break;
1918 case INVEN_HEAD: p = "wearing on your head"; break;
1919 case INVEN_HANDS: p = "wearing on your hands"; break;
1920 case INVEN_FEET: p = "wearing on your feet"; break;
1921 default: p = "carrying in your pack"; break;
1924 /* Hack -- Heavy weapon */
1925 if (i == INVEN_WIELD)
1927 object_type *o_ptr;
1928 o_ptr = &inventory[i];
1929 if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
1931 p = "just lifting";
1935 /* Hack -- Heavy bow */
1936 if (i == INVEN_BOW)
1938 object_type *o_ptr;
1939 o_ptr = &inventory[i];
1940 if (adj_str_hold[p_ptr->stat_ind[A_STR]] < o_ptr->weight / 10)
1942 p = "just holding";
1946 /* Return the result */
1947 return p;
1955 * Check an item against the item tester info
1957 bool item_tester_okay(const object_type *o_ptr)
1959 /* Hack -- allow listing empty slots */
1960 if (item_tester_full) return (TRUE);
1962 /* Require an item */
1963 if (!o_ptr->k_idx) return (FALSE);
1965 /* Hack -- ignore "gold" */
1966 if (o_ptr->tval == TV_GOLD) return (FALSE);
1968 /* Check the tval */
1969 if (item_tester_tval)
1971 if (!(item_tester_tval == o_ptr->tval)) return (FALSE);
1974 /* Check the hook */
1975 if (item_tester_hook)
1977 if (!(*item_tester_hook)(o_ptr)) return (FALSE);
1980 /* Assume okay */
1981 return (TRUE);
1987 * Get the indexes of objects at a given floor location. -TNB-
1989 * Return the number of object indexes acquired.
1991 * Valid flags are any combination of the bits:
1992 * 0x01 -- Verify item tester
1993 * 0x02 -- Marked/visible items only
1994 * 0x04 -- Only the top item
1996 bool scan_floor(int *items, int *item_num, int y, int x, int mode)
1998 int this_o_idx, next_o_idx;
2000 int num = 0;
2002 (*item_num) = 0;
2004 /* Sanity */
2005 if (!in_bounds(y, x)) return (FALSE);
2007 /* Scan all objects in the grid */
2008 for (this_o_idx = cave_o_idx[y][x]; this_o_idx; this_o_idx = next_o_idx)
2010 object_type *o_ptr;
2012 /* Get the object */
2013 o_ptr = &o_list[this_o_idx];
2015 /* Get the next object */
2016 next_o_idx = o_ptr->next_o_idx;
2018 /* Item tester */
2019 if ((mode & 0x01) && !item_tester_okay(o_ptr)) continue;
2021 /* Marked */
2022 if ((mode & 0x02) && (!o_ptr->marked || squelch_hide_item(o_ptr)))
2023 continue;
2025 /* Accept this item */
2026 items[num++] = this_o_idx;
2028 /* Only one */
2029 if (mode & 0x04) break;
2031 /* XXX Hack -- Enforce limit */
2032 if (num == MAX_FLOOR_STACK) break;
2035 /* Number of items */
2036 (*item_num) = num;
2038 /* Result */
2039 return (num != 0);
2045 * Choice window "shadow" of the "show_inven()" function
2047 void display_inven(void)
2049 register int i, n, z = 0;
2051 object_type *o_ptr;
2053 byte attr;
2055 char tmp_val[10];
2057 char o_name[80];
2060 /* Find the "final" slot */
2061 for (i = 0; i < INVEN_PACK; i++)
2063 o_ptr = &inventory[i];
2065 /* Skip non-objects */
2066 if (!o_ptr->k_idx) continue;
2068 /* Track */
2069 z = i + 1;
2072 /* Display the pack */
2073 for (i = 0; i < z; i++)
2075 /* Examine the item */
2076 o_ptr = &inventory[i];
2078 /* Start with an empty "index" */
2079 tmp_val[0] = tmp_val[1] = tmp_val[2] = ' ';
2081 /* Is this item "acceptable"? */
2082 if (item_tester_okay(o_ptr))
2084 /* Prepare an "index" */
2085 tmp_val[0] = index_to_label(i);
2087 /* Bracket the "index" --(-- */
2088 tmp_val[1] = ')';
2091 /* Display the index (or blank space) */
2092 Term_putstr(0, i, 3, TERM_WHITE, tmp_val);
2094 /* Obtain an item description */
2095 object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3);
2097 /* Obtain the length of the description */
2098 n = strlen(o_name);
2100 /* Get inventory color */
2101 attr = tval_to_attr[o_ptr->tval % N_ELEMENTS(tval_to_attr)];
2103 /* Display the entry itself */
2104 Term_putstr(3, i, n, attr, o_name);
2106 /* Erase the rest of the line */
2107 Term_erase(3+n, i, 255);
2109 /* Display the weight if needed */
2110 if (o_ptr->weight)
2112 int wgt = o_ptr->weight * o_ptr->number;
2113 strnfmt(tmp_val, sizeof(tmp_val), "%3d.%1d lb", wgt / 10, wgt % 10);
2114 Term_putstr(71, i, -1, TERM_WHITE, tmp_val);
2118 /* Erase the rest of the window */
2119 for (i = z; i < Term->hgt; i++)
2121 /* Erase the line */
2122 Term_erase(0, i, 255);
2129 * Choice window "shadow" of the "show_equip()" function
2131 void display_equip(void)
2133 register int i, n;
2134 object_type *o_ptr;
2135 byte attr;
2137 char tmp_val[10];
2139 char o_name[80];
2142 /* Display the equipment */
2143 for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
2145 /* Examine the item */
2146 o_ptr = &inventory[i];
2148 /* Start with an empty "index" */
2149 tmp_val[0] = tmp_val[1] = tmp_val[2] = ' ';
2151 /* Is this item "acceptable"? */
2152 if (item_tester_okay(o_ptr))
2154 /* Prepare an "index" */
2155 tmp_val[0] = index_to_label(i);
2157 /* Bracket the "index" --(-- */
2158 tmp_val[1] = ')';
2161 /* Display the index (or blank space) */
2162 Term_putstr(0, i - INVEN_WIELD, 3, TERM_WHITE, tmp_val);
2164 /* Obtain an item description */
2165 object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3);
2167 /* Obtain the length of the description */
2168 n = strlen(o_name);
2170 /* Get inventory color */
2171 attr = tval_to_attr[o_ptr->tval % N_ELEMENTS(tval_to_attr)];
2173 /* Display the entry itself */
2174 Term_putstr(3, i - INVEN_WIELD, n, attr, o_name);
2176 /* Erase the rest of the line */
2177 Term_erase(3+n, i - INVEN_WIELD, 255);
2179 /* Display the slot description (if needed) */
2180 if (show_labels)
2182 Term_putstr(61, i - INVEN_WIELD, -1, TERM_WHITE, "<--");
2183 Term_putstr(65, i - INVEN_WIELD, -1, TERM_WHITE, mention_use(i));
2186 /* Display the weight (if needed) */
2187 if (o_ptr->weight)
2189 int wgt = o_ptr->weight * o_ptr->number;
2190 int col = (show_labels ? 52 : 71);
2191 strnfmt(tmp_val, sizeof(tmp_val), "%3d.%1d lb", wgt / 10, wgt % 10);
2192 Term_putstr(col, i - INVEN_WIELD, -1, TERM_WHITE, tmp_val);
2196 /* Erase the rest of the window */
2197 for (i = INVEN_TOTAL - INVEN_WIELD; i < Term->hgt; i++)
2199 /* Clear that line */
2200 Term_erase(0, i, 255);
2207 * Display the inventory.
2209 * Hack -- do not display "trailing" empty slots
2211 void show_inven(void)
2213 int i, j, k, l, z = 0;
2214 int col, len, lim;
2216 object_type *o_ptr;
2218 char o_name[80];
2220 char tmp_val[80];
2222 int out_index[24];
2223 byte out_color[24];
2224 char out_desc[24][80];
2227 /* Default length */
2228 len = 79 - 50;
2230 /* Maximum space allowed for descriptions */
2231 /* screen width - "a) " - weight */
2232 lim = 79 - 3 - 9;
2235 /* Find the "final" slot */
2236 for (i = 0; i < INVEN_PACK; i++)
2238 o_ptr = &inventory[i];
2240 /* Skip non-objects */
2241 if (!o_ptr->k_idx) continue;
2243 /* Track */
2244 z = i + 1;
2247 /* Display the inventory */
2248 for (k = 0, i = 0; i < z; i++)
2250 o_ptr = &inventory[i];
2252 /* Is this item acceptable? */
2253 if (!item_tester_okay(o_ptr)) continue;
2255 /* Describe the object */
2256 object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3);
2258 /* Hack -- enforce max length */
2259 o_name[lim] = '\0';
2261 /* Save the index */
2262 out_index[k] = i;
2264 /* Get inventory color */
2265 out_color[k] = tval_to_attr[o_ptr->tval % N_ELEMENTS(tval_to_attr)];
2267 /* Save the object description */
2268 my_strcpy(out_desc[k], o_name, sizeof(out_desc[0]));
2270 /* Find the predicted "line length" */
2271 l = strlen(out_desc[k]) + 5;
2273 /* Be sure to account for the weight */
2274 l += 9;
2276 /* Maintain the maximum length */
2277 if (l > len) len = l;
2279 /* Advance to next "line" */
2280 k++;
2283 /* Find the column to start in */
2284 col = (len > 76) ? 0 : (79 - len);
2286 /* Output each entry */
2287 for (j = 0; j < k; j++)
2289 int wgt;
2291 /* Get the index */
2292 i = out_index[j];
2294 /* Get the item */
2295 o_ptr = &inventory[i];
2297 /* Clear the line */
2298 prt("", j + 1, col ? col - 2 : col);
2300 /* Prepare an index --(-- */
2301 strnfmt(tmp_val, sizeof(tmp_val), "%c)", index_to_label(i));
2303 /* Clear the line with the (possibly indented) index */
2304 put_str(tmp_val, j + 1, col);
2306 /* Display the entry itself */
2307 c_put_str(out_color[j], out_desc[j], j + 1, col + 3);
2309 /* Display the weight if needed */
2310 wgt = o_ptr->weight * o_ptr->number;
2311 strnfmt(tmp_val, sizeof(tmp_val), "%3d.%1d lb", wgt / 10, wgt % 10);
2312 put_str(tmp_val, j + 1, 71);
2315 /* Make a "shadow" below the list (only if needed) */
2316 if (j && (j < 23)) prt("", j + 1, col ? col - 2 : col);
2321 * Display the equipment.
2323 void show_equip(void)
2325 int i, j, k, l;
2326 int col, len, lim;
2328 object_type *o_ptr;
2330 char tmp_val[80];
2332 char o_name[80];
2334 int out_index[24];
2335 byte out_color[24];
2336 char out_desc[24][80];
2339 /* Default length */
2340 len = 79 - 50;
2342 /* Maximum space allowed for descriptions */
2343 lim = 79 - 3;
2345 /* Require space for labels (if needed) */
2346 if (show_labels) lim -= (14 + 2);
2348 /* Require space for weight */
2349 lim -= 9;
2351 /* Scan the equipment list */
2352 for (k = 0, i = INVEN_WIELD; i < INVEN_TOTAL; i++)
2354 o_ptr = &inventory[i];
2356 /* Is this item acceptable? */
2357 if (!item_tester_okay(o_ptr)) continue;
2359 /* Description */
2360 object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3);
2362 /* Truncate the description */
2363 o_name[lim] = 0;
2365 /* Save the index */
2366 out_index[k] = i;
2368 /* Get inventory color */
2369 out_color[k] = tval_to_attr[o_ptr->tval % N_ELEMENTS(tval_to_attr)];
2371 /* Save the description */
2372 my_strcpy(out_desc[k], o_name, sizeof(out_desc[0]));
2374 /* Extract the maximal length (see below) */
2375 l = strlen(out_desc[k]) + (2 + 3);
2377 /* Increase length for labels (if needed) */
2378 if (show_labels) l += (14 + 2);
2380 /* Increase length for weight */
2381 l += 9;
2383 /* Maintain the max-length */
2384 if (l > len) len = l;
2386 /* Advance the entry */
2387 k++;
2390 /* Hack -- Find a column to start in */
2391 col = (len > 76) ? 0 : (79 - len);
2393 /* Output each entry */
2394 for (j = 0; j < k; j++)
2396 int wgt;
2398 /* Get the index */
2399 i = out_index[j];
2401 /* Get the item */
2402 o_ptr = &inventory[i];
2404 /* Clear the line */
2405 prt("", j + 1, col ? col - 2 : col);
2407 /* Prepare an index --(-- */
2408 strnfmt(tmp_val, sizeof(tmp_val), "%c)", index_to_label(i));
2410 /* Clear the line with the (possibly indented) index */
2411 put_str(tmp_val, j+1, col);
2413 /* Use labels */
2414 if (show_labels)
2416 /* Mention the use */
2417 strnfmt(tmp_val, sizeof(tmp_val), "%-14s: ", mention_use(i));
2418 put_str(tmp_val, j+1, col + 3);
2420 /* Display the entry itself */
2421 c_put_str(out_color[j], out_desc[j], j+1, col + 3 + 14 + 2);
2424 /* No labels */
2425 else
2427 /* Display the entry itself */
2428 c_put_str(out_color[j], out_desc[j], j+1, col + 3);
2431 /* Display the weight if needed */
2432 wgt = o_ptr->weight * o_ptr->number;
2433 strnfmt(tmp_val, sizeof(tmp_val), "%3d.%d lb", wgt / 10, wgt % 10);
2434 put_str(tmp_val, j+1, 71);
2437 /* Make a "shadow" below the list (only if needed) */
2438 if (j && (j < 23)) prt("", j + 1, col ? col - 2 : col);
2443 * Display a list of the items on the floor at the given location. -TNB-
2445 void show_floor(const int *floor_list, int floor_num, bool gold)
2447 int i, j, k, l;
2448 int col, len, lim;
2450 object_type *o_ptr;
2452 char o_name[80];
2454 char tmp_val[80];
2456 int out_index[MAX_FLOOR_STACK];
2457 byte out_color[MAX_FLOOR_STACK];
2458 char out_desc[MAX_FLOOR_STACK][80];
2461 /* Default length */
2462 len = 79 - 50;
2464 /* Maximum space allowed for descriptions */
2465 lim = 79 - 3;
2467 /* Require space for weight */
2468 lim -= 9;
2470 /* Limit displayed floor items to 23 (screen limits) */
2471 if (floor_num > MAX_FLOOR_STACK) floor_num = MAX_FLOOR_STACK;
2473 /* Display the floor */
2474 for (k = 0, i = 0; i < floor_num; i++)
2476 o_ptr = &o_list[floor_list[i]];
2478 /* Optionally, show gold */
2479 if ((o_ptr->tval != TV_GOLD) || (!gold))
2481 /* Is this item acceptable? (always rejects gold) */
2482 if (!item_tester_okay(o_ptr)) continue;
2485 /* Describe the object */
2486 object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3);
2488 /* Hack -- enforce max length */
2489 o_name[lim] = '\0';
2491 /* Save the index */
2492 out_index[k] = i;
2494 /* Get inventory color */
2495 out_color[k] = tval_to_attr[o_ptr->tval % N_ELEMENTS(tval_to_attr)];
2497 /* Save the object description */
2498 my_strcpy(out_desc[k], o_name, sizeof(out_desc[0]));
2500 /* Find the predicted "line length" */
2501 l = strlen(out_desc[k]) + 5;
2503 /* Be sure to account for the weight */
2504 l += 9;
2506 /* Maintain the maximum length */
2507 if (l > len) len = l;
2509 /* Advance to next "line" */
2510 k++;
2513 /* Find the column to start in */
2514 col = (len > 76) ? 0 : (79 - len);
2516 /* Output each entry */
2517 for (j = 0; j < k; j++)
2519 int wgt;
2521 /* Get the index */
2522 i = floor_list[out_index[j]];
2524 /* Get the item */
2525 o_ptr = &o_list[i];
2527 /* Clear the line */
2528 prt("", j + 1, col ? col - 2 : col);
2530 /* Prepare an index --(-- */
2531 strnfmt(tmp_val, sizeof(tmp_val), "%c)", index_to_label(out_index[j]));
2533 /* Clear the line with the (possibly indented) index */
2534 put_str(tmp_val, j + 1, col);
2536 /* Display the entry itself */
2537 c_put_str(out_color[j], out_desc[j], j + 1, col + 3);
2539 /* Display the weight if needed */
2540 wgt = o_ptr->weight * o_ptr->number;
2541 strnfmt(tmp_val, sizeof(tmp_val), "%3d.%1d lb", wgt / 10, wgt % 10);
2542 put_str(tmp_val, j + 1, 71);
2545 /* Make a "shadow" below the list (only if needed) */
2546 if (j && (j < 23)) prt("", j + 1, col ? col - 2 : col);
2552 * Flip "inven" and "equip" in any sub-windows
2554 void toggle_inven_equip(void)
2556 int j;
2558 /* Scan windows */
2559 for (j = 0; j < ANGBAND_TERM_MAX; j++)
2561 /* Unused */
2562 if (!angband_term[j]) continue;
2564 /* Flip inven to equip */
2565 if (op_ptr->window_flag[j] & (PW_INVEN))
2567 /* Flip flags */
2568 op_ptr->window_flag[j] &= ~(PW_INVEN);
2569 op_ptr->window_flag[j] |= (PW_EQUIP);
2571 /* Window stuff */
2572 p_ptr->window |= (PW_EQUIP);
2575 /* Flip inven to equip */
2576 else if (op_ptr->window_flag[j] & (PW_EQUIP))
2578 /* Flip flags */
2579 op_ptr->window_flag[j] &= ~(PW_EQUIP);
2580 op_ptr->window_flag[j] |= (PW_INVEN);
2582 /* Window stuff */
2583 p_ptr->window |= (PW_INVEN);
2592 * Verify the choice of an item.
2594 * The item can be negative to mean "item on floor".
2596 bool verify_item(cptr prompt, int item)
2598 char o_name[80];
2600 char out_val[160];
2602 object_type *o_ptr;
2604 /* Inventory */
2605 if (item >= 0)
2607 o_ptr = &inventory[item];
2610 /* Floor */
2611 else
2613 o_ptr = &o_list[0 - item];
2616 /* Describe */
2617 object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3);
2619 /* Prompt */
2620 strnfmt(out_val, sizeof(out_val), "%s %s? ", prompt, o_name);
2622 /* Query */
2623 return (get_check(out_val));
2628 * Hack -- allow user to "prevent" certain choices.
2630 * The item can be negative to mean "item on floor".
2632 static bool get_item_allow(int item)
2634 object_type *o_ptr;
2635 char verify_inscrip[] = "!*";
2637 /* Inventory */
2638 if (item >= 0)
2640 o_ptr = &inventory[item];
2643 /* Floor */
2644 else
2646 o_ptr = &o_list[0 - item];
2649 /* Check for a "prevention" inscription */
2650 verify_inscrip[1] = p_ptr->command_cmd;
2652 if (o_ptr->note && (check_for_inscrip(o_ptr, "!*") ||
2653 check_for_inscrip(o_ptr, verify_inscrip)))
2655 /* Verify the choice */
2656 if (!verify_item("Really try", item)) return (FALSE);
2659 /* Allow it */
2660 return (TRUE);
2665 * Verify the "okayness" of a given item.
2667 * The item can be negative to mean "item on floor".
2669 static bool get_item_okay(int item)
2671 object_type *o_ptr;
2673 /* Inventory */
2674 if (item >= 0)
2676 o_ptr = &inventory[item];
2679 /* Floor */
2680 else
2682 o_ptr = &o_list[0 - item];
2685 /* Verify the item */
2686 return (item_tester_okay(o_ptr));
2692 * Find the "first" inventory object with the given "tag".
2694 * A "tag" is a char "n" appearing as "@n" anywhere in the
2695 * inscription of an object.
2697 * Also, the tag "@xn" will work as well, where "n" is a tag-char,
2698 * and "x" is the "current" p_ptr->command_cmd code.
2700 static int get_tag(int *cp, char tag)
2702 int i;
2703 cptr s;
2706 /* Check every object */
2707 for (i = 0; i < INVEN_TOTAL; ++i)
2709 object_type *o_ptr = &inventory[i];
2711 /* Skip non-objects */
2712 if (!o_ptr->k_idx) continue;
2714 /* Skip empty inscriptions */
2715 if (!o_ptr->note) continue;
2717 /* Find a '@' */
2718 s = strchr(quark_str(o_ptr->note), '@');
2720 /* Process all tags */
2721 while (s)
2723 /* Check the normal tags */
2724 if (s[1] == tag)
2726 /* Save the actual inventory ID */
2727 *cp = i;
2729 /* Success */
2730 return (TRUE);
2733 /* Check the special tags */
2734 if ((s[1] == p_ptr->command_cmd) && (s[2] == tag))
2736 /* Save the actual inventory ID */
2737 *cp = i;
2739 /* Success */
2740 return (TRUE);
2743 /* Find another '@' */
2744 s = strchr(s + 1, '@');
2748 /* No such tag */
2749 return (FALSE);
2755 * Let the user select an item, save its "index"
2757 * Return TRUE only if an acceptable item was chosen by the user.
2759 * The selected item must satisfy the "item_tester_hook()" function,
2760 * if that hook is set, and the "item_tester_tval", if that value is set.
2762 * All "item_tester" restrictions are cleared before this function returns.
2764 * The user is allowed to choose acceptable items from the equipment,
2765 * inventory, or floor, respectively, if the proper flag was given,
2766 * and there are any acceptable items in that location.
2768 * The equipment or inventory are displayed (even if no acceptable
2769 * items are in that location) if the proper flag was given.
2771 * If there are no acceptable items available anywhere, and "str" is
2772 * not NULL, then it will be used as the text of a warning message
2773 * before the function returns.
2775 * Note that the user must press "-" to specify the item on the floor,
2776 * and there is no way to "examine" the item on the floor, while the
2777 * use of "capital" letters will "examine" an inventory/equipment item,
2778 * and prompt for its use.
2780 * If a legal item is selected from the inventory, we save it in "cp"
2781 * directly (0 to 35), and return TRUE.
2783 * If a legal item is selected from the floor, we save it in "cp" as
2784 * a negative (-1 to -511), and return TRUE.
2786 * If no item is available, we do nothing to "cp", and we display a
2787 * warning message, using "str" if available, and return FALSE.
2789 * If no item is selected, we do nothing to "cp", and return FALSE.
2791 * Global "p_ptr->command_new" is used when viewing the inventory or equipment
2792 * to allow the user to enter a command while viewing those screens, and
2793 * also to induce "auto-enter" of stores, and other such stuff.
2795 * Global "p_ptr->command_see" may be set before calling this function to start
2796 * out in "browse" mode. It is cleared before this function returns.
2798 * Global "p_ptr->command_wrk" is used to choose between equip/inven/floor
2799 * listings. It is equal to USE_INVEN or USE_EQUIP or USE_FLOOR, except
2800 * when this function is first called, when it is equal to zero, which will
2801 * cause it to be set to USE_INVEN.
2803 * We always erase the prompt when we are done, leaving a blank line,
2804 * or a warning message, if appropriate, if no items are available.
2806 * Note that only "acceptable" floor objects get indexes, so between two
2807 * commands, the indexes of floor objects may change. XXX XXX XXX
2809 bool get_item(int *cp, cptr pmt, cptr str, int mode)
2811 int py = p_ptr->py;
2812 int px = p_ptr->px;
2814 char which;
2816 int j, k;
2818 int i1, i2;
2819 int e1, e2;
2820 int f1, f2;
2822 bool done, item;
2824 bool oops = FALSE;
2826 bool use_inven = ((mode & USE_INVEN) ? TRUE : FALSE);
2827 bool use_equip = ((mode & USE_EQUIP) ? TRUE : FALSE);
2828 bool use_floor = ((mode & USE_FLOOR) ? TRUE : FALSE);
2829 bool can_squelch = ((mode & CAN_SQUELCH) ? TRUE : FALSE);
2831 bool allow_inven = FALSE;
2832 bool allow_equip = FALSE;
2833 bool allow_floor = FALSE;
2835 bool toggle = FALSE;
2837 char tmp_val[160];
2838 char out_val[160];
2840 int floor_list[MAX_FLOOR_STACK];
2841 int floor_num;
2844 /* Get the item index */
2845 if (repeat_pull(cp))
2847 /* Verify the item */
2848 if (get_item_okay(*cp))
2850 /* Forget the item_tester_tval restriction */
2851 item_tester_tval = 0;
2853 /* Forget the item_tester_hook restriction */
2854 item_tester_hook = NULL;
2856 /* Success */
2857 return (TRUE);
2859 else
2861 /* Invalid repeat - reset it */
2862 repeat_clear();
2867 /* Paranoia XXX XXX XXX */
2868 message_flush();
2871 /* Not done */
2872 done = FALSE;
2874 /* No item selected */
2875 item = FALSE;
2878 /* Full inventory */
2879 i1 = 0;
2880 i2 = INVEN_PACK - 1;
2882 /* Forbid inventory */
2883 if (!use_inven) i2 = -1;
2885 /* Restrict inventory indexes */
2886 while ((i1 <= i2) && (!get_item_okay(i1))) i1++;
2887 while ((i1 <= i2) && (!get_item_okay(i2))) i2--;
2889 /* Accept inventory */
2890 if (i1 <= i2) allow_inven = TRUE;
2893 /* Full equipment */
2894 e1 = INVEN_WIELD;
2895 e2 = INVEN_TOTAL - 1;
2897 /* Forbid equipment */
2898 if (!use_equip) e2 = -1;
2900 /* Restrict equipment indexes */
2901 while ((e1 <= e2) && (!get_item_okay(e1))) e1++;
2902 while ((e1 <= e2) && (!get_item_okay(e2))) e2--;
2904 /* Accept equipment */
2905 if (e1 <= e2) allow_equip = TRUE;
2908 /* Scan all non-gold objects in the grid */
2909 (void)scan_floor(floor_list, &floor_num, py, px, 0x01);
2911 /* Full floor */
2912 f1 = 0;
2913 f2 = floor_num - 1;
2915 /* Forbid floor */
2916 if (!use_floor) f2 = -1;
2918 /* Restrict floor indexes */
2919 while ((f1 <= f2) && (!get_item_okay(0 - floor_list[f1]))) f1++;
2920 while ((f1 <= f2) && (!get_item_okay(0 - floor_list[f2]))) f2--;
2922 /* Accept floor */
2923 if (f1 <= f2) allow_floor = TRUE;
2926 /* Require at least one legal choice */
2927 if (!allow_inven && !allow_equip && !allow_floor)
2929 /* Cancel p_ptr->command_see */
2930 p_ptr->command_see = FALSE;
2932 /* Oops */
2933 oops = TRUE;
2935 /* Done */
2936 done = TRUE;
2939 /* Analyze choices */
2940 else
2942 /* Hack -- Start on equipment if requested */
2943 if (p_ptr->command_see &&
2944 (p_ptr->command_wrk == (USE_EQUIP)) &&
2945 use_equip)
2947 p_ptr->command_wrk = (USE_EQUIP);
2950 /* Use inventory if allowed */
2951 else if (use_inven)
2953 p_ptr->command_wrk = (USE_INVEN);
2956 /* Use equipment if allowed */
2957 else if (use_equip)
2959 p_ptr->command_wrk = (USE_EQUIP);
2962 /* Use floor if allowed */
2963 else if (use_floor)
2965 p_ptr->command_wrk = (USE_FLOOR);
2968 /* Hack -- Use (empty) inventory */
2969 else
2971 p_ptr->command_wrk = (USE_INVEN);
2976 /* Start out in "display" mode */
2977 if (p_ptr->command_see)
2979 /* Save screen */
2980 screen_save();
2984 /* Repeat until done */
2985 while (!done)
2987 int ni = 0;
2988 int ne = 0;
2990 /* Scan windows */
2991 for (j = 0; j < ANGBAND_TERM_MAX; j++)
2993 /* Unused */
2994 if (!angband_term[j]) continue;
2996 /* Count windows displaying inven */
2997 if (op_ptr->window_flag[j] & (PW_INVEN)) ni++;
2999 /* Count windows displaying equip */
3000 if (op_ptr->window_flag[j] & (PW_EQUIP)) ne++;
3003 /* Toggle if needed */
3004 if (((p_ptr->command_wrk == (USE_EQUIP)) && ni && !ne) ||
3005 ((p_ptr->command_wrk == (USE_INVEN)) && !ni && ne))
3007 /* Toggle */
3008 toggle_inven_equip();
3010 /* Track toggles */
3011 toggle = !toggle;
3014 /* Update */
3015 p_ptr->window |= (PW_INVEN | PW_EQUIP);
3017 /* Redraw windows */
3018 window_stuff();
3020 /* Viewing inventory */
3021 if (p_ptr->command_wrk == (USE_INVEN))
3023 /* Redraw if needed */
3024 if (p_ptr->command_see) show_inven();
3026 /* Begin the prompt */
3027 strnfmt(out_val, sizeof(out_val), "Inven:");
3029 /* List choices */
3030 if (i1 <= i2)
3032 /* Build the prompt */
3033 strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,",
3034 index_to_label(i1), index_to_label(i2));
3036 /* Append */
3037 my_strcat(out_val, tmp_val, sizeof(out_val));
3040 /* Indicate ability to "view" */
3041 if (!p_ptr->command_see) my_strcat(out_val, " * to see,", sizeof(out_val));
3043 /* Indicate legality of "toggle" */
3044 if (use_equip) my_strcat(out_val, " / for Equip,", sizeof(out_val));
3046 /* Indicate legality of the "floor" */
3047 if (allow_floor) my_strcat(out_val, " - for floor,", sizeof(out_val));
3049 /* Indicate that squelched items can be selected */
3050 if (can_squelch) my_strcat(out_val, " ! for squelched,", sizeof(out_val));
3053 /* Viewing equipment */
3054 else if (p_ptr->command_wrk == (USE_EQUIP))
3056 /* Redraw if needed */
3057 if (p_ptr->command_see) show_equip();
3059 /* Begin the prompt */
3060 strnfmt(out_val, sizeof(out_val), "Equip:");
3062 /* List choices */
3063 if (e1 <= e2)
3065 /* Build the prompt */
3066 strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,",
3067 index_to_label(e1), index_to_label(e2));
3069 /* Append */
3070 my_strcat(out_val, tmp_val, sizeof(out_val));
3073 /* Indicate ability to "view" */
3074 if (!p_ptr->command_see) my_strcat(out_val, " * to see,", sizeof(out_val));
3076 /* Indicate legality of "toggle" */
3077 if (use_inven) my_strcat(out_val, " / for Inven,", sizeof(out_val));
3079 /* Indicate legality of the "floor" */
3080 if (allow_floor) my_strcat(out_val, " - for floor,", sizeof(out_val));
3083 /* Viewing floor */
3084 else
3086 /* Redraw if needed */
3087 if (p_ptr->command_see) show_floor(floor_list, floor_num, FALSE);
3089 /* Begin the prompt */
3090 strnfmt(out_val, sizeof(out_val), "Floor:");
3092 /* List choices */
3093 if (f1 <= f2)
3095 /* Build the prompt */
3096 strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,", I2A(f1), I2A(f2));
3098 /* Append */
3099 my_strcat(out_val, tmp_val, sizeof(out_val));
3102 /* Indicate ability to "view" */
3103 if (!p_ptr->command_see) my_strcat(out_val, " * to see,", sizeof(out_val));
3105 /* Append */
3106 if (use_inven) my_strcat(out_val, " / for Inven,", sizeof(out_val));
3108 /* Append */
3109 else if (use_equip) my_strcat(out_val, " / for Equip,", sizeof(out_val));
3111 /* Indicate that squelched items can be selected */
3112 if (can_squelch) my_strcat(out_val, " ! for squelched,", sizeof(out_val));
3115 /* Finish the prompt */
3116 my_strcat(out_val, " ESC", sizeof(out_val));
3118 /* Build the prompt */
3119 strnfmt(tmp_val, sizeof(tmp_val), "(%s) %s", out_val, pmt);
3121 /* Show the prompt */
3122 prt(tmp_val, 0, 0);
3125 /* Get a key */
3126 which = inkey();
3128 /* Parse it */
3129 switch (which)
3131 case ESCAPE:
3133 done = TRUE;
3134 break;
3137 case '*':
3138 case '?':
3139 case ' ':
3141 /* Hide the list */
3142 if (p_ptr->command_see)
3144 /* Flip flag */
3145 p_ptr->command_see = FALSE;
3147 /* Load screen */
3148 screen_load();
3151 /* Show the list */
3152 else
3154 /* Save screen */
3155 screen_save();
3157 /* Flip flag */
3158 p_ptr->command_see = TRUE;
3161 break;
3164 case '/':
3166 /* Toggle to inventory */
3167 if (use_inven && (p_ptr->command_wrk != (USE_INVEN)))
3169 p_ptr->command_wrk = (USE_INVEN);
3172 /* Toggle to equipment */
3173 else if (use_equip && (p_ptr->command_wrk != (USE_EQUIP)))
3175 p_ptr->command_wrk = (USE_EQUIP);
3178 /* No toggle allowed */
3179 else
3181 bell("Cannot switch item selector!");
3182 break;
3185 /* Hack -- Fix screen */
3186 if (p_ptr->command_see)
3188 /* Load screen */
3189 screen_load();
3191 /* Save screen */
3192 screen_save();
3195 /* Need to redraw */
3196 break;
3199 case '-':
3201 /* Paranoia */
3202 if (!allow_floor)
3204 bell("Cannot select floor!");
3205 break;
3208 /* There is only one item */
3209 if (floor_num == 1)
3211 /* Auto-select */
3212 if (p_ptr->command_wrk == (USE_FLOOR))
3214 /* Special index */
3215 k = 0 - floor_list[0];
3217 /* Allow player to "refuse" certain actions */
3218 if (!get_item_allow(k))
3220 done = TRUE;
3221 break;
3224 /* Accept that choice */
3225 (*cp) = k;
3226 item = TRUE;
3227 done = TRUE;
3229 break;
3233 /* Hack -- Fix screen */
3234 if (p_ptr->command_see)
3236 /* Load screen */
3237 screen_load();
3239 /* Save screen */
3240 screen_save();
3243 p_ptr->command_wrk = (USE_FLOOR);
3245 #if 0
3246 /* Check each legal object */
3247 for (i = 0; i < floor_num; ++i)
3249 /* Special index */
3250 k = 0 - floor_list[i];
3252 /* Skip non-okay objects */
3253 if (!get_item_okay(k)) continue;
3255 /* Allow player to "refuse" certain actions */
3256 if (!get_item_allow(k)) continue;
3258 /* Accept that choice */
3259 (*cp) = k;
3260 item = TRUE;
3261 done = TRUE;
3262 break;
3264 #endif
3266 break;
3269 case '0':
3270 case '1': case '2': case '3':
3271 case '4': case '5': case '6':
3272 case '7': case '8': case '9':
3274 /* Look up the tag */
3275 if (!get_tag(&k, which))
3277 bell("Illegal object choice (tag)!");
3278 break;
3281 /* Hack -- Validate the item */
3282 if ((k < INVEN_WIELD) ? !allow_inven : !allow_equip)
3284 bell("Illegal object choice (tag)!");
3285 break;
3288 /* Validate the item */
3289 if (!get_item_okay(k))
3291 bell("Illegal object choice (tag)!");
3292 break;
3295 /* Allow player to "refuse" certain actions */
3296 if (!get_item_allow(k))
3298 done = TRUE;
3299 break;
3302 /* Accept that choice */
3303 (*cp) = k;
3304 item = TRUE;
3305 done = TRUE;
3306 break;
3309 case '\n':
3310 case '\r':
3312 /* Choose "default" inventory item */
3313 if (p_ptr->command_wrk == (USE_INVEN))
3315 if (i1 != i2)
3317 bell("Illegal object choice (default)!");
3318 break;
3321 k = i1;
3324 /* Choose "default" equipment item */
3325 else if (p_ptr->command_wrk == (USE_EQUIP))
3327 if (e1 != e2)
3329 bell("Illegal object choice (default)!");
3330 break;
3333 k = e1;
3336 /* Choose "default" floor item */
3337 else
3339 if (f1 != f2)
3341 bell("Illegal object choice (default)!");
3342 break;
3345 k = 0 - floor_list[f1];
3348 /* Validate the item */
3349 if (!get_item_okay(k))
3351 bell("Illegal object choice (default)!");
3352 break;
3355 /* Allow player to "refuse" certain actions */
3356 if (!get_item_allow(k))
3358 done = TRUE;
3359 break;
3362 /* Accept that choice */
3363 (*cp) = k;
3364 item = TRUE;
3365 done = TRUE;
3366 break;
3369 case '!':
3371 /* Try squelched items */
3372 if (can_squelch)
3374 (*cp) = ALL_SQUELCHED;
3375 item = TRUE;
3376 done = TRUE;
3377 break;
3380 /* Just fall through */
3383 default:
3385 bool verify;
3387 /* Note verify */
3388 verify = (isupper((unsigned char)which) ? TRUE : FALSE);
3390 /* Lowercase */
3391 which = tolower((unsigned char)which);
3393 /* Convert letter to inventory index */
3394 if (p_ptr->command_wrk == (USE_INVEN))
3396 k = label_to_inven(which);
3398 if (k < 0)
3400 bell("Illegal object choice (inven)!");
3401 break;
3405 /* Convert letter to equipment index */
3406 else if (p_ptr->command_wrk == (USE_EQUIP))
3408 k = label_to_equip(which);
3410 if (k < 0)
3412 bell("Illegal object choice (equip)!");
3413 break;
3417 /* Convert letter to floor index */
3418 else
3420 k = (islower((unsigned char)which) ? A2I(which) : -1);
3422 if (k < 0 || k >= floor_num)
3424 bell("Illegal object choice (floor)!");
3425 break;
3428 /* Special index */
3429 k = 0 - floor_list[k];
3432 /* Validate the item */
3433 if (!get_item_okay(k))
3435 bell("Illegal object choice (normal)!");
3436 break;
3439 /* Verify the item */
3440 if (verify && !verify_item("Try", k))
3442 done = TRUE;
3443 break;
3446 /* Allow player to "refuse" certain actions */
3447 if (!get_item_allow(k))
3449 done = TRUE;
3450 break;
3453 /* Accept that choice */
3454 (*cp) = k;
3455 item = TRUE;
3456 done = TRUE;
3457 break;
3463 /* Fix the screen if necessary */
3464 if (p_ptr->command_see)
3466 /* Load screen */
3467 screen_load();
3469 /* Hack -- Cancel "display" */
3470 p_ptr->command_see = FALSE;
3474 /* Forget the item_tester_tval restriction */
3475 item_tester_tval = 0;
3477 /* Forget the item_tester_hook restriction */
3478 item_tester_hook = NULL;
3481 /* Toggle again if needed */
3482 if (toggle) toggle_inven_equip();
3484 /* Update */
3485 p_ptr->window |= (PW_INVEN | PW_EQUIP);
3487 /* Window stuff */
3488 window_stuff();
3491 /* Clear the prompt line */
3492 prt("", 0, 0);
3494 /* Warning if needed */
3495 if (oops && str) msg_print(str);
3497 /* Save item if available */
3498 if (item) repeat_push(*cp);
3500 /* Result */
3501 return (item);