1 /* NetHack 3.6	invent.c	$NHDT-Date: 1575245062 2019/12/02 00:04:22 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.267 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Derek S. Ray, 2015. */
4 /* NetHack may be freely redistributed.  See license for details. */
5 
6 #include "hack.h"
7 
8 #ifndef C /* same as cmd.c */
9 #define C(c) (0x1f & (c))
10 #endif
11 
12 #define NOINVSYM '#'
13 #define CONTAINED_SYM '>' /* designator for inside a container */
14 #define HANDS_SYM '-'
15 
16 STATIC_DCL void FDECL(loot_classify, (Loot *, struct obj *));
17 STATIC_DCL char *FDECL(loot_xname, (struct obj *));
18 STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr,
19                                                const genericptr));
20 STATIC_DCL void NDECL(reorder_invent);
21 STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
22 STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *));
23 STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
24 STATIC_DCL boolean FDECL(only_here, (struct obj *));
25 STATIC_DCL void FDECL(compactify, (char *));
26 STATIC_DCL boolean FDECL(taking_off, (const char *));
27 STATIC_DCL boolean FDECL(putting_on, (const char *));
28 STATIC_PTR int FDECL(ckvalidcat, (struct obj *));
29 STATIC_PTR int FDECL(ckunpaid, (struct obj *));
30 STATIC_PTR char *FDECL(safeq_xprname, (struct obj *));
31 STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
32 STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
33                                         const char *, BOOLEAN_P, long *));
34 STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
35 STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
36 STATIC_DCL void NDECL(dounpaid);
37 STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
38 STATIC_DCL void FDECL(menu_identify, (int));
39 STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
40 STATIC_DCL char FDECL(obj_to_let, (struct obj *));
41 
42 static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
43 
44 /* wizards can wish for venom, which will become an invisible inventory
45  * item without this.  putting it in inv_order would mean venom would
46  * suddenly become a choice for all the inventory-class commands, which
47  * would probably cause mass confusion.  the test for inventory venom
48  * is only WIZARD and not wizard because the wizard can leave venom lying
49  * around on a bones level for normal players to find.  [Note to the
50  * confused:  'WIZARD' used to be a compile-time conditional so this was
51  * guarded by #ifdef WIZARD/.../#endif.]
52  */
53 static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
54 
55 /* sortloot() classification; called at most once [per sort] for each object */
56 STATIC_OVL void
loot_classify(sort_item,obj)57 loot_classify(sort_item, obj)
58 Loot *sort_item;
59 struct obj *obj;
60 {
61     /* we may eventually make this a settable option to always use
62        with sortloot instead of only when the 'sortpack' option isn't
63        set; it is similar to sortpack's inv_order but items most
64        likely to be picked up are moved to the front */
65     static char def_srt_order[MAXOCLASSES] = {
66         COIN_CLASS, AMULET_CLASS, RING_CLASS, WAND_CLASS, POTION_CLASS,
67         SCROLL_CLASS, SPBOOK_CLASS, GEM_CLASS, FOOD_CLASS, TOOL_CLASS,
68         WEAPON_CLASS, ARMOR_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
69     };
70     static char armcat[8];
71     const char *classorder;
72     char *p;
73     int k, otyp = obj->otyp, oclass = obj->oclass;
74     boolean seen, discovered = objects[otyp].oc_name_known ? TRUE : FALSE;
75 
76     /*
77      * For the value types assigned by this classification, sortloot()
78      * will put lower valued ones before higher valued ones.
79      */
80     if (!Blind)
81         obj->dknown = 1; /* xname(obj) does this; we want it sooner */
82     seen = obj->dknown ? TRUE : FALSE,
83     /* class order */
84     classorder = flags.sortpack ? flags.inv_order : def_srt_order;
85     p = index(classorder, oclass);
86     if (p)
87         k = 1 + (int) (p - classorder);
88     else
89         k = 1 + (int) strlen(classorder) + (oclass != VENOM_CLASS);
90     sort_item->orderclass = (xchar) k;
91     /* subclass designation; only a few classes have subclasses
92        and the non-armor ones we use are fairly arbitrary */
93     switch (oclass) {
94     case ARMOR_CLASS:
95         if (!armcat[7]) {
96             /* one-time init; we use a different order than the subclass
97                values defined by objclass.h */
98             armcat[ARM_HELM]   = 1; /* [2] */
99             armcat[ARM_GLOVES] = 2; /* [3] */
100             armcat[ARM_BOOTS]  = 3; /* [4] */
101             armcat[ARM_SHIELD] = 4; /* [1] */
102             armcat[ARM_CLOAK]  = 5; /* [5] */
103             armcat[ARM_SHIRT]  = 6; /* [6] */
104             armcat[ARM_SUIT]   = 7; /* [0] */
105             armcat[7]          = 8; /* sanity protection */
106         }
107         k = objects[otyp].oc_armcat;
108         /* oc_armcat overloads oc_subtyp which is an 'schar' so guard
109            against somebody assigning something unexpected to it */
110         if (k < 0 || k >= 7)
111             k = 7;
112         k = armcat[k];
113         break;
114     case WEAPON_CLASS:
115         /* for weapons, group by ammo (arrows, bolts), launcher (bows),
116            missile (darts, boomerangs), stackable (daggers, knives, spears),
117            'other' (swords, axes, &c), polearms */
118         k = objects[otyp].oc_skill;
119         k = (k < 0) ? ((k >= -P_CROSSBOW && k <= -P_BOW) ? 1 : 3)
120                     : ((k >= P_BOW && k <= P_CROSSBOW) ? 2
121                        : (k == P_SPEAR || k == P_DAGGER || k == P_KNIFE) ? 4
122                           : !is_pole(obj) ? 5 : 6);
123         break;
124     case TOOL_CLASS:
125         if (seen && discovered
126             && (otyp == BAG_OF_TRICKS || otyp == HORN_OF_PLENTY))
127             k = 2; /* known pseudo-container */
128         else if (Is_container(obj))
129             k = 1; /* regular container or unknown bag of tricks */
130         else
131             switch (otyp) {
132             case WOODEN_FLUTE:
133             case MAGIC_FLUTE:
134             case TOOLED_HORN:
135             case FROST_HORN:
136             case FIRE_HORN:
137             case WOODEN_HARP:
138             case MAGIC_HARP:
139             case BUGLE:
140             case LEATHER_DRUM:
141             case DRUM_OF_EARTHQUAKE:
142             case HORN_OF_PLENTY: /* not a musical instrument */
143                 k = 3; /* instrument or unknown horn of plenty */
144                 break;
145             default:
146                 k = 4; /* 'other' tool */
147                 break;
148             }
149         break;
150     case FOOD_CLASS:
151         /* [what about separating "partly eaten" within each group?] */
152         switch (otyp) {
153         case SLIME_MOLD:
154             k = 1;
155             break;
156         default:
157             /* [maybe separate one-bite foods from rations and such?] */
158             k = obj->globby ? 6 : 2;
159             break;
160         case TIN:
161             k = 3;
162             break;
163         case EGG:
164             k = 4;
165             break;
166         case CORPSE:
167             k = 5;
168             break;
169         }
170         break;
171     case GEM_CLASS:
172         /*
173          * Normally subclass takes priority over discovery status, but
174          * that would give away information for gems (assuming we'll
175          * group them as valuable gems, next glass, then gray stones,
176          * and finally rocks once they're all fully identified).
177          *
178          * Order:
179          *  1) unseen gems and glass ("gem")
180          *  2) seen but undiscovered gems and glass ("blue gem"),
181          *  3) discovered gems ("sapphire"),
182          *  4) discovered glass ("worthless pieced of blue glass"),
183          *  5) unseen gray stones and rocks ("stone"),
184          *  6) seen but undiscovered gray stones ("gray stone"),
185          *  7) discovered gray stones ("touchstone"),
186          *  8) seen rocks ("rock").
187          */
188         switch (objects[obj->otyp].oc_material) {
189         case GEMSTONE:
190             k = !seen ? 1 : !discovered ? 2 : 3;
191             break;
192         case GLASS:
193             k = !seen ? 1 : !discovered ? 2 : 4;
194             break;
195         default: /* MINERAL */
196             k = !seen ? 5 : (obj->otyp != ROCK) ? (!discovered ? 6 : 7) : 8;
197             break;
198         }
199         break;
200     default:
201         /* other classes don't have subclasses; we assign a nonzero
202            value because sortloot() uses 0 to mean 'not yet classified' */
203         k = 1; /* any non-zero would do */
204         break;
205     }
206     sort_item->subclass = (xchar) k;
207     /* discovery status */
208     k = !seen ? 1 /* unseen */
209         : (discovered || !OBJ_DESCR(objects[otyp])) ? 4
210           : (objects[otyp].oc_uname) ? 3 /* named (partially discovered) */
211             : 2; /* undiscovered */
212     sort_item->disco = (xchar) k;
213 }
214 
215 /* sortloot() formatting routine; for alphabetizing, not shown to user */
216 STATIC_OVL char *
loot_xname(obj)217 loot_xname(obj)
218 struct obj *obj;
219 {
220     struct obj saveo;
221     boolean save_debug;
222     char *res, *save_oname;
223 
224     /*
225      * Deal with things that xname() includes as a prefix.  We don't
226      * want such because they change alphabetical ordering.  First,
227      * remember 'obj's current settings.
228      */
229     saveo.odiluted = obj->odiluted;
230     saveo.blessed = obj->blessed, saveo.cursed = obj->cursed;
231     saveo.spe = obj->spe;
232     saveo.owt = obj->owt;
233     save_oname = has_oname(obj) ? ONAME(obj) : 0;
234     save_debug = flags.debug;
235     /* suppress "diluted" for potions and "holy/unholy" for water;
236        sortloot() will deal with them using other criteria than name */
237     if (obj->oclass == POTION_CLASS) {
238         obj->odiluted = 0;
239         if (obj->otyp == POT_WATER)
240             obj->blessed = 0, obj->cursed = 0;
241     }
242     /* make "wet towel" and "moist towel" format as "towel" so that all
243        three group together */
244     if (obj->otyp == TOWEL)
245         obj->spe = 0;
246     /* group "<size> glob of <foo>" by <foo> rather than by <size> */
247     if (obj->globby)
248         obj->owt = 200; /* 200: weight of combined glob from ten creatures
249                            (five or fewer is "small", more than fifteen is
250                            "large", in between has no prefix) */
251     /* suppress user-assigned name */
252     if (save_oname && !obj->oartifact)
253         ONAME(obj) = 0;
254     /* avoid wizard mode formatting variations */
255     if (wizard) { /* flags.debug */
256         /* paranoia:  before toggling off wizard mode, guard against a
257            panic in xname() producing a normal mode panic save file */
258         program_state.something_worth_saving = 0;
259         flags.debug = FALSE;
260     }
261 
262     res = cxname_singular(obj);
263 
264     if (save_debug) {
265         flags.debug = TRUE;
266         program_state.something_worth_saving = 1;
267     }
268     /* restore the object */
269     if (obj->oclass == POTION_CLASS) {
270         obj->odiluted = saveo.odiluted;
271         if (obj->otyp == POT_WATER)
272             obj->blessed = saveo.blessed, obj->cursed = saveo.cursed;
273     }
274     if (obj->otyp == TOWEL) {
275         obj->spe = saveo.spe;
276         /* give "towel" a suffix that will force wet ones to come first,
277            moist ones next, and dry ones last regardless of whether
278            they've been flagged as having spe known */
279         Strcat(res, is_wet_towel(obj) ? ((obj->spe >= 3) ? "x" : "y") : "z");
280     }
281     if (obj->globby) {
282         obj->owt = saveo.owt;
283         /* we've suppressed the size prefix (above); there normally won't
284            be more than one of a given creature type because they coalesce,
285            but globs with different bless/curse state won't merge so it is
286            feasible to have multiple at the same location; add a suffix to
287            get such sorted by size (small first) */
288         Strcat(res, (obj->owt <= 100) ? "a"
289                     : (obj->owt <= 300) ? "b"
290                       : (obj->owt <= 500) ? "c"
291                         : "d");
292     }
293     if (save_oname && !obj->oartifact)
294         ONAME(obj) = save_oname;
295 
296     return res;
297 }
298 
299 /* set by sortloot() for use by sortloot_cmp(); reset by sortloot when done */
300 static unsigned sortlootmode = 0;
301 
302 /* qsort comparison routine for sortloot() */
303 STATIC_OVL int CFDECLSPEC
sortloot_cmp(vptr1,vptr2)304 sortloot_cmp(vptr1, vptr2)
305 const genericptr vptr1;
306 const genericptr vptr2;
307 {
308     struct sortloot_item *sli1 = (struct sortloot_item *) vptr1,
309                          *sli2 = (struct sortloot_item *) vptr2;
310     struct obj *obj1 = sli1->obj,
311                *obj2 = sli2->obj;
312     char *nam1, *nam2;
313     int val1, val2, c, namcmp;
314 
315     /* order by object class unless we're doing by-invlet without sortpack */
316     if ((sortlootmode & (SORTLOOT_PACK | SORTLOOT_INVLET))
317         != SORTLOOT_INVLET) {
318         /* Classify each object at most once no matter how many
319            comparisons it is involved in. */
320         if (!sli1->orderclass)
321             loot_classify(sli1, obj1);
322         if (!sli2->orderclass)
323             loot_classify(sli2, obj2);
324 
325         /* Sort by class. */
326         val1 = sli1->orderclass;
327         val2 = sli2->orderclass;
328         if (val1 != val2)
329             return (int) (val1 - val2);
330 
331         /* skip sub-classes when ordering by sortpack+invlet */
332         if ((sortlootmode & SORTLOOT_INVLET) == 0) {
333             /* Class matches; sort by subclass. */
334             val1 = sli1->subclass;
335             val2 = sli2->subclass;
336             if (val1 != val2)
337                 return val1 - val2;
338 
339             /* Class and subclass match; sort by discovery status:
340              * first unseen, then seen but not named or discovered,
341              * then named, lastly discovered.
342              * 1) potion
343              * 2) pink potion
344              * 3) dark green potion called confusion
345              * 4) potion of healing
346              * Multiple entries within each group will be put into
347              * alphabetical order below.
348              */
349             val1 = sli1->disco;
350             val2 = sli2->disco;
351             if (val1 != val2)
352                 return val1 - val2;
353         }
354     }
355 
356     /* order by assigned inventory letter */
357     if ((sortlootmode & SORTLOOT_INVLET) != 0) {
358         c = obj1->invlet;
359         val1 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
360                : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
361                  : (c == '$') ? 1
362                    : (c == '#') ? 1 + 52 + 1
363                      : 1 + 52 + 1 + 1; /* none of the above */
364         c = obj2->invlet;
365         val2 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
366                : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
367                  : (c == '$') ? 1
368                    : (c == '#') ? 1 + 52 + 1
369                      : 1 + 52 + 1 + 1; /* none of the above */
370         if (val1 != val2)
371             return val1 - val2;
372     }
373 
374     if ((sortlootmode & SORTLOOT_LOOT) == 0)
375         goto tiebreak;
376 
377     /*
378      * Sort object names in lexicographical order, ignoring quantity.
379      *
380      * Each obj gets formatted at most once (per sort) no matter how many
381      * comparisons it gets subjected to.
382      */
383     nam1 = sli1->str;
384     if (!nam1)
385         nam1 = sli1->str = dupstr(loot_xname(obj1));
386     nam2 = sli2->str;
387     if (!nam2)
388         nam2 = sli2->str = dupstr(loot_xname(obj2));
389     if ((namcmp = strcmpi(nam1, nam2)) != 0)
390         return namcmp;
391 
392     /* Sort by BUCX. */
393     val1 = obj1->bknown ? (obj1->blessed ? 3 : !obj1->cursed ? 2 : 1) : 0;
394     val2 = obj2->bknown ? (obj2->blessed ? 3 : !obj2->cursed ? 2 : 1) : 0;
395     if (val1 != val2)
396         return val2 - val1; /* bigger is better */
397 
398     /* Sort by greasing.  This will put the objects in degreasing order. */
399     val1 = obj1->greased;
400     val2 = obj2->greased;
401     if (val1 != val2)
402         return val2 - val1; /* bigger is better */
403 
404     /* Sort by erosion.  The effective amount is what matters. */
405     val1 = greatest_erosion(obj1);
406     val2 = greatest_erosion(obj2);
407     if (val1 != val2)
408         return val1 - val2; /* bigger is WORSE */
409 
410     /* Sort by erodeproofing.  Map known-invulnerable to 1, and both
411        known-vulnerable and unknown-vulnerability to 0, because that's
412        how they're displayed. */
413     val1 = obj1->rknown && obj1->oerodeproof;
414     val2 = obj2->rknown && obj2->oerodeproof;
415     if (val1 != val2)
416         return val2 - val1; /* bigger is better */
417 
418     /* Sort by enchantment.  Map unknown to -1000, which is comfortably
419        below the range of obj->spe.  oc_uses_known means that obj->known
420        matters, which usually indirectly means that obj->spe is relevant.
421        Lots of objects use obj->spe for some other purpose (see obj.h). */
422     if (objects[obj1->otyp].oc_uses_known
423         /* exclude eggs (laid by you) and tins (homemade, pureed, &c) */
424         && obj1->oclass != FOOD_CLASS) {
425         val1 = obj1->known ? obj1->spe : -1000;
426         val2 = obj2->known ? obj2->spe : -1000;
427         if (val1 != val2)
428             return val2 - val1; /* bigger is better */
429     }
430 
431  tiebreak:
432     /* They're identical, as far as we're concerned.  We want
433        to force a deterministic order, and do so by producing a
434        stable sort: maintain the original order of equal items. */
435     return (sli1->indx - sli2->indx);
436 }
437 
438 /*
439  * sortloot() - the story so far...
440  *
441  *      The original implementation constructed and returned an array
442  *      of pointers to objects in the requested order.  Callers had to
443  *      count the number of objects, allocate the array, pass one
444  *      object at a time to the routine which populates it, traverse
445  *      the objects via stepping through the array, then free the
446  *      array.  The ordering process used a basic insertion sort which
447  *      is fine for short lists but inefficient for long ones.
448  *
449  *      3.6.0 (and continuing with 3.6.1) changed all that so that
450  *      sortloot was self-contained as far as callers were concerned.
451  *      It reordered the linked list into the requested order and then
452  *      normal list traversal was used to process it.  It also switched
453  *      to qsort() on the assumption that the C library implementation
454  *      put some effort into sorting efficiently.  It also checked
455  *      whether the list was already sorted as it got ready to do the
456  *      sorting, so re-examining inventory or a pile of objects without
457  *      having changed anything would gobble up less CPU than a full
458  *      sort.  But it had at least two problems (aside from the ordinary
459  *      complement of bugs):
460  *      1) some players wanted to get the original order back when they
461  *      changed the 'sortloot' option back to 'none', but the list
462  *      reordering made that infeasible;
463  *      2) object identification giving the 'ID whole pack' result
464  *      would call makeknown() on each newly ID'd object, that would
465  *      call update_inventory() to update the persistent inventory
466  *      window if one existed, the interface would call the inventory
467  *      display routine which would call sortloot() which might change
468  *      the order of the list being traversed by the identify code,
469  *      possibly skipping the ID of some objects.  That could have been
470  *      avoided by suppressing 'perm_invent' during identification
471  *      (fragile) or by avoiding sortloot() during inventory display
472  *      (more robust).
473  *
474  *      As of 3.6.2: revert to the temporary array of ordered obj pointers
475  *      but have sortloot() do the counting and allocation.  Callers
476  *      need to use array traversal instead of linked list traversal
477  *      and need to free the temporary array when done.  And the
478  *      array contains 'struct sortloot_item' (aka 'Loot') entries
479  *      instead of simple 'struct obj *' entries.
480  */
481 Loot *
sortloot(olist,mode,by_nexthere,filterfunc)482 sortloot(olist, mode, by_nexthere, filterfunc)
483 struct obj **olist; /* previous version might have changed *olist, we don't */
484 unsigned mode; /* flags for sortloot_cmp() */
485 boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
486 boolean FDECL((*filterfunc), (OBJ_P));
487 {
488     Loot *sliarray;
489     struct obj *o;
490     unsigned n, i;
491     boolean augment_filter;
492 
493     for (n = 0, o = *olist; o; o = by_nexthere ? o->nexthere : o->nobj)
494         ++n;
495     /* note: if there is a filter function, this might overallocate */
496     sliarray = (Loot *) alloc((n + 1) * sizeof *sliarray);
497 
498     /* the 'keep cockatrice corpses' flag is overloaded with sort mode */
499     augment_filter = (mode & SORTLOOT_PETRIFY) ? TRUE : FALSE;
500     mode &= ~SORTLOOT_PETRIFY; /* remove flag, leaving mode */
501     /* populate aliarray[0..n-1] */
502     for (i = 0, o = *olist; o; o = by_nexthere ? o->nexthere : o->nobj) {
503         if (filterfunc && !(*filterfunc)(o)
504             /* caller may be asking us to override filterfunc (in order
505                to do a cockatrice corpse touch check during pickup even
506                if/when the filter rejects food class) */
507             && (!augment_filter || o->otyp != CORPSE
508                 || !touch_petrifies(&mons[o->corpsenm])))
509             continue;
510         sliarray[i].obj = o, sliarray[i].indx = (int) i;
511         sliarray[i].str = (char *) 0;
512         sliarray[i].orderclass = sliarray[i].subclass = sliarray[i].disco = 0;
513         ++i;
514     }
515     n = i;
516     /* add a terminator so that we don't have to pass 'n' back to caller */
517     sliarray[n].obj = (struct obj *) 0, sliarray[n].indx = -1;
518     sliarray[n].str = (char *) 0;
519     sliarray[n].orderclass = sliarray[n].subclass = sliarray[n].disco = 0;
520 
521     /* do the sort; if no sorting is requested, we'll just return
522        a sortloot_item array reflecting the current ordering */
523     if (mode && n > 1) {
524         sortlootmode = mode; /* extra input for sortloot_cmp() */
525         qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
526         sortlootmode = 0; /* reset static mode flags */
527         /* if sortloot_cmp formatted any objects, discard their strings now */
528         for (i = 0; i < n; ++i)
529             if (sliarray[i].str)
530                 free((genericptr_t) sliarray[i].str), sliarray[i].str = 0;
531     }
532     return sliarray;
533 }
534 
535 /* sortloot() callers should use this to free up memory it allocates */
536 void
unsortloot(loot_array_p)537 unsortloot(loot_array_p)
538 Loot **loot_array_p;
539 {
540     if (*loot_array_p)
541         free((genericptr_t) *loot_array_p), *loot_array_p = (Loot *) 0;
542 }
543 
544 #if 0 /* 3.6.0 'revamp' */
545 void
546 sortloot(olist, mode, by_nexthere)
547 struct obj **olist;
548 unsigned mode; /* flags for sortloot_cmp() */
549 boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
550 {
551     struct sortloot_item *sliarray, osli, nsli;
552     struct obj *o, **nxt_p;
553     unsigned n, i;
554     boolean already_sorted = TRUE;
555 
556     sortlootmode = mode; /* extra input for sortloot_cmp() */
557     for (n = osli.indx = 0, osli.obj = *olist; (o = osli.obj) != 0;
558          osli = nsli) {
559         nsli.obj = by_nexthere ? o->nexthere : o->nobj;
560         nsli.indx = (int) ++n;
561         if (nsli.obj && already_sorted
562             && sortloot_cmp((genericptr_t) &osli, (genericptr_t) &nsli) > 0)
563             already_sorted = FALSE;
564     }
565     if (n > 1 && !already_sorted) {
566         sliarray = (struct sortloot_item *) alloc(n * sizeof *sliarray);
567         for (i = 0, o = *olist; o;
568              ++i, o = by_nexthere ? o->nexthere : o->nobj)
569             sliarray[i].obj = o, sliarray[i].indx = (int) i;
570 
571         qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
572         for (i = 0; i < n; ++i) {
573             o = sliarray[i].obj;
574             nxt_p = by_nexthere ? &(o->nexthere) : &(o->nobj);
575             *nxt_p = (i < n - 1) ? sliarray[i + 1].obj : (struct obj *) 0;
576         }
577         *olist = sliarray[0].obj;
578         free((genericptr_t) sliarray);
579     }
580     sortlootmode = 0;
581 }
582 #endif /*0*/
583 
584 void
assigninvlet(otmp)585 assigninvlet(otmp)
586 register struct obj *otmp;
587 {
588     boolean inuse[52];
589     register int i;
590     register struct obj *obj;
591 
592     /* there should be at most one of these in inventory... */
593     if (otmp->oclass == COIN_CLASS) {
594         otmp->invlet = GOLD_SYM;
595         return;
596     }
597 
598     for (i = 0; i < 52; i++)
599         inuse[i] = FALSE;
600     for (obj = invent; obj; obj = obj->nobj)
601         if (obj != otmp) {
602             i = obj->invlet;
603             if ('a' <= i && i <= 'z')
604                 inuse[i - 'a'] = TRUE;
605             else if ('A' <= i && i <= 'Z')
606                 inuse[i - 'A' + 26] = TRUE;
607             if (i == otmp->invlet)
608                 otmp->invlet = 0;
609         }
610     if ((i = otmp->invlet)
611         && (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
612         return;
613     for (i = lastinvnr + 1; i != lastinvnr; i++) {
614         if (i == 52) {
615             i = -1;
616             continue;
617         }
618         if (!inuse[i])
619             break;
620     }
621     otmp->invlet =
622         (inuse[i] ? NOINVSYM : (i < 26) ? ('a' + i) : ('A' + i - 26));
623     lastinvnr = i;
624 }
625 
626 /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
627 #define inv_rank(o) ((o)->invlet ^ 040)
628 
629 /* sort the inventory; used by addinv() and doorganize() */
630 STATIC_OVL void
reorder_invent()631 reorder_invent()
632 {
633     struct obj *otmp, *prev, *next;
634     boolean need_more_sorting;
635 
636     do {
637         /*
638          * We expect at most one item to be out of order, so this
639          * isn't nearly as inefficient as it may first appear.
640          */
641         need_more_sorting = FALSE;
642         for (otmp = invent, prev = 0; otmp;) {
643             next = otmp->nobj;
644             if (next && inv_rank(next) < inv_rank(otmp)) {
645                 need_more_sorting = TRUE;
646                 if (prev)
647                     prev->nobj = next;
648                 else
649                     invent = next;
650                 otmp->nobj = next->nobj;
651                 next->nobj = otmp;
652                 prev = next;
653             } else {
654                 prev = otmp;
655                 otmp = next;
656             }
657         }
658     } while (need_more_sorting);
659 }
660 
661 #undef inv_rank
662 
663 /* scan a list of objects to see whether another object will merge with
664    one of them; used in pickup.c when all 52 inventory slots are in use,
665    to figure out whether another object could still be picked up */
666 struct obj *
merge_choice(objlist,obj)667 merge_choice(objlist, obj)
668 struct obj *objlist, *obj;
669 {
670     struct monst *shkp;
671     int save_nocharge;
672 
673     if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */
674         return (struct obj *) 0;
675     /* if this is an item on the shop floor, the attributes it will
676        have when carried are different from what they are now; prevent
677        that from eliciting an incorrect result from mergable() */
678     save_nocharge = obj->no_charge;
679     if (objlist == invent && obj->where == OBJ_FLOOR
680         && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
681         if (obj->no_charge)
682             obj->no_charge = 0;
683         /* A billable object won't have its `unpaid' bit set, so would
684            erroneously seem to be a candidate to merge with a similar
685            ordinary object.  That's no good, because once it's really
686            picked up, it won't merge after all.  It might merge with
687            another unpaid object, but we can't check that here (depends
688            too much upon shk's bill) and if it doesn't merge it would
689            end up in the '#' overflow inventory slot, so reject it now. */
690         else if (inhishop(shkp))
691             return (struct obj *) 0;
692     }
693     while (objlist) {
694         if (mergable(objlist, obj))
695             break;
696         objlist = objlist->nobj;
697     }
698     obj->no_charge = save_nocharge;
699     return objlist;
700 }
701 
702 /* merge obj with otmp and delete obj if types agree */
703 int
merged(potmp,pobj)704 merged(potmp, pobj)
705 struct obj **potmp, **pobj;
706 {
707     register struct obj *otmp = *potmp, *obj = *pobj;
708 
709     if (mergable(otmp, obj)) {
710         /* Approximate age: we do it this way because if we were to
711          * do it "accurately" (merge only when ages are identical)
712          * we'd wind up never merging any corpses.
713          * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
714          *
715          * Don't do the age manipulation if lit.  We would need
716          * to stop the burn on both items, then merge the age,
717          * then restart the burn.  Glob ages are averaged in the
718          * absorb routine, which uses weight rather than quantity
719          * to adjust for proportion (glob quantity is always 1).
720          */
721         if (!obj->lamplit && !obj->globby)
722             otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
723                         / (otmp->quan + obj->quan);
724 
725         if (!otmp->globby)
726             otmp->quan += obj->quan;
727         /* temporary special case for gold objects!!!! */
728         if (otmp->oclass == COIN_CLASS)
729             otmp->owt = weight(otmp), otmp->bknown = 0;
730         /* and puddings!!!1!!one! */
731         else if (!Is_pudding(otmp))
732             otmp->owt += obj->owt;
733         if (!has_oname(otmp) && has_oname(obj))
734             otmp = *potmp = oname(otmp, ONAME(obj));
735         obj_extract_self(obj);
736 
737         /* really should merge the timeouts */
738         if (obj->lamplit)
739             obj_merge_light_sources(obj, otmp);
740         if (obj->timed)
741             obj_stop_timers(obj); /* follows lights */
742 
743         /* fixup for `#adjust' merging wielded darts, daggers, &c */
744         if (obj->owornmask && carried(otmp)) {
745             long wmask = otmp->owornmask | obj->owornmask;
746 
747             /* Both the items might be worn in competing slots;
748                merger preference (regardless of which is which):
749              primary weapon + alternate weapon -> primary weapon;
750              primary weapon + quiver -> primary weapon;
751              alternate weapon + quiver -> alternate weapon.
752                (Prior to 3.3.0, it was not possible for the two
753                stacks to be worn in different slots and `obj'
754                didn't need to be unworn when merging.) */
755             if (wmask & W_WEP)
756                 wmask = W_WEP;
757             else if (wmask & W_SWAPWEP)
758                 wmask = W_SWAPWEP;
759             else if (wmask & W_QUIVER)
760                 wmask = W_QUIVER;
761             else {
762                 impossible("merging strangely worn items (%lx)", wmask);
763                 wmask = otmp->owornmask;
764             }
765             if ((otmp->owornmask & ~wmask) != 0L)
766                 setnotworn(otmp);
767             setworn(otmp, wmask);
768             setnotworn(obj);
769 #if 0
770         /* (this should not be necessary, since items
771             already in a monster's inventory don't ever get
772             merged into other objects [only vice versa]) */
773         } else if (obj->owornmask && mcarried(otmp)) {
774             if (obj == MON_WEP(otmp->ocarry)) {
775                 MON_WEP(otmp->ocarry) = otmp;
776                 otmp->owornmask = W_WEP;
777             }
778 #endif /*0*/
779         }
780 
781         /* handle puddings a bit differently; absorption will free the
782            other object automatically so we can just return out from here */
783         if (obj->globby) {
784             pudding_merge_message(otmp, obj);
785             obj_absorb(potmp, pobj);
786             return 1;
787         }
788 
789         obfree(obj, otmp); /* free(obj), bill->otmp */
790         return 1;
791     }
792     return 0;
793 }
794 
795 /*
796  * Adjust hero intrinsics as if this object was being added to the hero's
797  * inventory.  Called _before_ the object has been added to the hero's
798  * inventory.
799  *
800  * This is called when adding objects to the hero's inventory normally (via
801  * addinv) or when an object in the hero's inventory has been polymorphed
802  * in-place.
803  *
804  * It may be valid to merge this code with with addinv_core2().
805  */
806 void
addinv_core1(obj)807 addinv_core1(obj)
808 struct obj *obj;
809 {
810     if (obj->oclass == COIN_CLASS) {
811         context.botl = 1;
812     } else if (obj->otyp == AMULET_OF_YENDOR) {
813         if (u.uhave.amulet)
814             impossible("already have amulet?");
815         u.uhave.amulet = 1;
816         u.uachieve.amulet = 1;
817     } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
818         if (u.uhave.menorah)
819             impossible("already have candelabrum?");
820         u.uhave.menorah = 1;
821         u.uachieve.menorah = 1;
822     } else if (obj->otyp == BELL_OF_OPENING) {
823         if (u.uhave.bell)
824             impossible("already have silver bell?");
825         u.uhave.bell = 1;
826         u.uachieve.bell = 1;
827     } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
828         if (u.uhave.book)
829             impossible("already have the book?");
830         u.uhave.book = 1;
831         u.uachieve.book = 1;
832     } else if (obj->oartifact) {
833         if (is_quest_artifact(obj)) {
834             if (u.uhave.questart)
835                 impossible("already have quest artifact?");
836             u.uhave.questart = 1;
837             artitouch(obj);
838         }
839         set_artifact_intrinsic(obj, 1, W_ART);
840     }
841 
842     /* "special achievements" aren't discoverable during play, they
843        end up being recorded in XLOGFILE at end of game, nowhere else;
844        record_achieve_special overloads corpsenm which is ordinarily
845        initialized to NON_PM (-1) rather than to 0; any special prize
846        must never be a corpse, egg, tin, figurine, or statue because
847        their use of obj->corpsenm for monster type would conflict,
848        nor be a leash (corpsenm overloaded for m_id of leashed
849        monster) or a novel (corpsenm overloaded for novel index) */
850     if (is_mines_prize(obj)) {
851         u.uachieve.mines_luckstone = 1;
852         obj->record_achieve_special = NON_PM;
853         obj->nomerge = 0;
854     } else if (is_soko_prize(obj)) {
855         u.uachieve.finish_sokoban = 1;
856         obj->record_achieve_special = NON_PM;
857         obj->nomerge = 0;
858     }
859 }
860 
861 /*
862  * Adjust hero intrinsics as if this object was being added to the hero's
863  * inventory.  Called _after_ the object has been added to the hero's
864  * inventory.
865  *
866  * This is called when adding objects to the hero's inventory normally (via
867  * addinv) or when an object in the hero's inventory has been polymorphed
868  * in-place.
869  */
870 void
addinv_core2(obj)871 addinv_core2(obj)
872 struct obj *obj;
873 {
874     if (confers_luck(obj)) {
875         /* new luckstone must be in inventory by this point
876          * for correct calculation */
877         set_moreluck();
878     }
879 }
880 
881 /*
882  * Add obj to the hero's inventory.  Make sure the object is "free".
883  * Adjust hero attributes as necessary.
884  */
885 struct obj *
addinv(obj)886 addinv(obj)
887 struct obj *obj;
888 {
889     struct obj *otmp, *prev;
890     int saved_otyp = (int) obj->otyp; /* for panic */
891     boolean obj_was_thrown;
892 
893     if (obj->where != OBJ_FREE)
894         panic("addinv: obj not free");
895     /* normally addtobill() clears no_charge when items in a shop are
896        picked up, but won't do so if the shop has become untended */
897     obj->no_charge = 0; /* should not be set in hero's invent */
898     if (Has_contents(obj))
899         picked_container(obj); /* clear no_charge */
900     obj_was_thrown = obj->was_thrown;
901     obj->was_thrown = 0;       /* not meaningful for invent */
902 
903     addinv_core1(obj);
904 
905     /* merge with quiver in preference to any other inventory slot
906        in case quiver and wielded weapon are both eligible; adding
907        extra to quivered stack is more useful than to wielded one */
908     if (uquiver && merged(&uquiver, &obj)) {
909         obj = uquiver;
910         if (!obj)
911             panic("addinv: null obj after quiver merge otyp=%d", saved_otyp);
912         goto added;
913     }
914     /* merge if possible; find end of chain in the process */
915     for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
916         if (merged(&otmp, &obj)) {
917             obj = otmp;
918             if (!obj)
919                 panic("addinv: null obj after merge otyp=%d", saved_otyp);
920             goto added;
921         }
922     /* didn't merge, so insert into chain */
923     assigninvlet(obj);
924     if (flags.invlet_constant || !prev) {
925         obj->nobj = invent; /* insert at beginning */
926         invent = obj;
927         if (flags.invlet_constant)
928             reorder_invent();
929     } else {
930         prev->nobj = obj; /* insert at end */
931         obj->nobj = 0;
932     }
933     obj->where = OBJ_INVENT;
934 
935     /* fill empty quiver if obj was thrown */
936     if (flags.pickup_thrown && !uquiver && obj_was_thrown
937         /* if Mjollnir is thrown and fails to return, we want to
938            auto-pick it when we move to its spot, but not into quiver;
939            aklyses behave like Mjollnir when thrown while wielded, but
940            we lack sufficient information here make them exceptions */
941         && obj->oartifact != ART_MJOLLNIR
942         && (throwing_weapon(obj) || is_ammo(obj)))
943         setuqwep(obj);
944  added:
945     addinv_core2(obj);
946     carry_obj_effects(obj); /* carrying affects the obj */
947     update_inventory();
948     return obj;
949 }
950 
951 /*
952  * Some objects are affected by being carried.
953  * Make those adjustments here. Called _after_ the object
954  * has been added to the hero's or monster's inventory,
955  * and after hero's intrinsics have been updated.
956  */
957 void
carry_obj_effects(obj)958 carry_obj_effects(obj)
959 struct obj *obj;
960 {
961     /* Cursed figurines can spontaneously transform when carried. */
962     if (obj->otyp == FIGURINE) {
963         if (obj->cursed && obj->corpsenm != NON_PM
964             && !dead_species(obj->corpsenm, TRUE)) {
965             attach_fig_transform_timeout(obj);
966         }
967     }
968 }
969 
970 /* Add an item to the inventory unless we're fumbling or it refuses to be
971  * held (via touch_artifact), and give a message.
972  * If there aren't any free inventory slots, we'll drop it instead.
973  * If both success and failure messages are NULL, then we're just doing the
974  * fumbling/slot-limit checking for a silent grab.  In any case,
975  * touch_artifact will print its own messages if they are warranted.
976  */
977 struct obj *
hold_another_object(obj,drop_fmt,drop_arg,hold_msg)978 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
979 struct obj *obj;
980 const char *drop_fmt, *drop_arg, *hold_msg;
981 {
982     char buf[BUFSZ];
983 
984     if (!Blind)
985         obj->dknown = 1; /* maximize mergibility */
986     if (obj->oartifact) {
987         /* place_object may change these */
988         boolean crysknife = (obj->otyp == CRYSKNIFE);
989         int oerode = obj->oerodeproof;
990         boolean wasUpolyd = Upolyd;
991 
992         /* in case touching this object turns out to be fatal */
993         place_object(obj, u.ux, u.uy);
994 
995         if (!touch_artifact(obj, &youmonst)) {
996             obj_extract_self(obj); /* remove it from the floor */
997             dropy(obj);            /* now put it back again :-) */
998             return obj;
999         } else if (wasUpolyd && !Upolyd) {
1000             /* loose your grip if you revert your form */
1001             if (drop_fmt)
1002                 pline(drop_fmt, drop_arg);
1003             obj_extract_self(obj);
1004             dropy(obj);
1005             return obj;
1006         }
1007         obj_extract_self(obj);
1008         if (crysknife) {
1009             obj->otyp = CRYSKNIFE;
1010             obj->oerodeproof = oerode;
1011         }
1012     }
1013     if (Fumbling) {
1014         obj->nomerge = 1;
1015         obj = addinv(obj); /* dropping expects obj to be in invent */
1016         goto drop_it;
1017     } else {
1018         long oquan = obj->quan;
1019         int prev_encumbr = near_capacity(); /* before addinv() */
1020 
1021         /* encumbrance only matters if it would now become worse
1022            than max( current_value, stressed ) */
1023         if (prev_encumbr < MOD_ENCUMBER)
1024             prev_encumbr = MOD_ENCUMBER;
1025         /* addinv() may redraw the entire inventory, overwriting
1026            drop_arg when it comes from something like doname() */
1027         if (drop_arg)
1028             drop_arg = strcpy(buf, drop_arg);
1029 
1030         obj = addinv(obj);
1031         if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
1032                                     && near_capacity() > prev_encumbr)) {
1033             /* undo any merge which took place */
1034             if (obj->quan > oquan)
1035                 obj = splitobj(obj, oquan);
1036             goto drop_it;
1037         } else {
1038             if (flags.autoquiver && !uquiver && !obj->owornmask
1039                 && (is_missile(obj) || ammo_and_launcher(obj, uwep)
1040                     || ammo_and_launcher(obj, uswapwep)))
1041                 setuqwep(obj);
1042             if (hold_msg || drop_fmt)
1043                 prinv(hold_msg, obj, oquan);
1044         }
1045     }
1046     return obj;
1047 
1048  drop_it:
1049     if (drop_fmt)
1050         pline(drop_fmt, drop_arg);
1051     obj->nomerge = 0;
1052     if (can_reach_floor(TRUE)) {
1053         dropx(obj);
1054     } else {
1055         freeinv(obj);
1056         hitfloor(obj, FALSE);
1057     }
1058     return (struct obj *) 0; /* might be gone */
1059 }
1060 
1061 /* useup() all of an item regardless of its quantity */
1062 void
useupall(obj)1063 useupall(obj)
1064 struct obj *obj;
1065 {
1066     setnotworn(obj);
1067     freeinv(obj);
1068     obfree(obj, (struct obj *) 0); /* deletes contents also */
1069 }
1070 
1071 void
useup(obj)1072 useup(obj)
1073 register struct obj *obj;
1074 {
1075     /* Note:  This works correctly for containers because they (containers)
1076        don't merge. */
1077     if (obj->quan > 1L) {
1078         obj->in_use = FALSE; /* no longer in use */
1079         obj->quan--;
1080         obj->owt = weight(obj);
1081         update_inventory();
1082     } else {
1083         useupall(obj);
1084     }
1085 }
1086 
1087 /* use one charge from an item and possibly incur shop debt for it */
1088 void
consume_obj_charge(obj,maybe_unpaid)1089 consume_obj_charge(obj, maybe_unpaid)
1090 struct obj *obj;
1091 boolean maybe_unpaid; /* false if caller handles shop billing */
1092 {
1093     if (maybe_unpaid)
1094         check_unpaid(obj);
1095     obj->spe -= 1;
1096     if (obj->known)
1097         update_inventory();
1098 }
1099 
1100 /*
1101  * Adjust hero's attributes as if this object was being removed from the
1102  * hero's inventory.  This should only be called from freeinv() and
1103  * where we are polymorphing an object already in the hero's inventory.
1104  *
1105  * Should think of a better name...
1106  */
1107 void
freeinv_core(obj)1108 freeinv_core(obj)
1109 struct obj *obj;
1110 {
1111     if (obj->oclass == COIN_CLASS) {
1112         context.botl = 1;
1113         return;
1114     } else if (obj->otyp == AMULET_OF_YENDOR) {
1115         if (!u.uhave.amulet)
1116             impossible("don't have amulet?");
1117         u.uhave.amulet = 0;
1118     } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
1119         if (!u.uhave.menorah)
1120             impossible("don't have candelabrum?");
1121         u.uhave.menorah = 0;
1122     } else if (obj->otyp == BELL_OF_OPENING) {
1123         if (!u.uhave.bell)
1124             impossible("don't have silver bell?");
1125         u.uhave.bell = 0;
1126     } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
1127         if (!u.uhave.book)
1128             impossible("don't have the book?");
1129         u.uhave.book = 0;
1130     } else if (obj->oartifact) {
1131         if (is_quest_artifact(obj)) {
1132             if (!u.uhave.questart)
1133                 impossible("don't have quest artifact?");
1134             u.uhave.questart = 0;
1135         }
1136         set_artifact_intrinsic(obj, 0, W_ART);
1137     }
1138 
1139     if (obj->otyp == LOADSTONE) {
1140         curse(obj);
1141     } else if (confers_luck(obj)) {
1142         set_moreluck();
1143         context.botl = 1;
1144     } else if (obj->otyp == FIGURINE && obj->timed) {
1145         (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
1146     }
1147 }
1148 
1149 /* remove an object from the hero's inventory */
1150 void
freeinv(obj)1151 freeinv(obj)
1152 register struct obj *obj;
1153 {
1154     extract_nobj(obj, &invent);
1155     freeinv_core(obj);
1156     update_inventory();
1157 }
1158 
1159 void
delallobj(x,y)1160 delallobj(x, y)
1161 int x, y;
1162 {
1163     struct obj *otmp, *otmp2;
1164 
1165     for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
1166         if (otmp == uball)
1167             unpunish();
1168         /* after unpunish(), or might get deallocated chain */
1169         otmp2 = otmp->nexthere;
1170         if (otmp == uchain)
1171             continue;
1172         delobj(otmp);
1173     }
1174 }
1175 
1176 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
1177 void
delobj(obj)1178 delobj(obj)
1179 register struct obj *obj;
1180 {
1181     boolean update_map;
1182 
1183     if (obj->otyp == AMULET_OF_YENDOR
1184         || obj->otyp == CANDELABRUM_OF_INVOCATION
1185         || obj->otyp == BELL_OF_OPENING
1186         || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
1187         /* player might be doing something stupid, but we
1188          * can't guarantee that.  assume special artifacts
1189          * are indestructible via drawbridges, and exploding
1190          * chests, and golem creation, and ...
1191          */
1192         return;
1193     }
1194     update_map = (obj->where == OBJ_FLOOR);
1195     obj_extract_self(obj);
1196     if (update_map)
1197         newsym(obj->ox, obj->oy);
1198     obfree(obj, (struct obj *) 0); /* frees contents also */
1199 }
1200 
1201 /* try to find a particular type of object at designated map location */
1202 struct obj *
sobj_at(otyp,x,y)1203 sobj_at(otyp, x, y)
1204 int otyp;
1205 int x, y;
1206 {
1207     register struct obj *otmp;
1208 
1209     for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
1210         if (otmp->otyp == otyp)
1211             break;
1212 
1213     return otmp;
1214 }
1215 
1216 /* sobj_at(&c) traversal -- find next object of specified type */
1217 struct obj *
nxtobj(obj,type,by_nexthere)1218 nxtobj(obj, type, by_nexthere)
1219 struct obj *obj;
1220 int type;
1221 boolean by_nexthere;
1222 {
1223     register struct obj *otmp;
1224 
1225     otmp = obj; /* start with the object after this one */
1226     do {
1227         otmp = !by_nexthere ? otmp->nobj : otmp->nexthere;
1228         if (!otmp)
1229             break;
1230     } while (otmp->otyp != type);
1231 
1232     return otmp;
1233 }
1234 
1235 struct obj *
carrying(type)1236 carrying(type)
1237 register int type;
1238 {
1239     register struct obj *otmp;
1240 
1241     for (otmp = invent; otmp; otmp = otmp->nobj)
1242         if (otmp->otyp == type)
1243             return  otmp;
1244     return (struct obj *) 0;
1245 }
1246 
1247 /* Fictional and not-so-fictional currencies.
1248  * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
1249  */
1250 static const char *const currencies[] = {
1251     "Altarian Dollar",       /* The Hitchhiker's Guide to the Galaxy */
1252     "Ankh-Morpork Dollar",   /* Discworld */
1253     "auric",                 /* The Domination of Draka */
1254     "buckazoid",             /* Space Quest */
1255     "cirbozoid",             /* Starslip */
1256     "credit chit",           /* Deus Ex */
1257     "cubit",                 /* Battlestar Galactica */
1258     "Flanian Pobble Bead",   /* The Hitchhiker's Guide to the Galaxy */
1259     "fretzer",               /* Jules Verne */
1260     "imperial credit",       /* Star Wars */
1261     "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
1262     "kongbuck",              /* Snow Crash */
1263     "nanite",                /* System Shock 2 */
1264     "quatloo",               /* Star Trek, Sim City */
1265     "simoleon",              /* Sim City */
1266     "solari",                /* Spaceballs */
1267     "spacebuck",             /* Spaceballs */
1268     "sporebuck",             /* Spore */
1269     "Triganic Pu",           /* The Hitchhiker's Guide to the Galaxy */
1270     "woolong",               /* Cowboy Bebop */
1271     "zorkmid",               /* Zork, NetHack */
1272 };
1273 
1274 const char *
currency(amount)1275 currency(amount)
1276 long amount;
1277 {
1278     const char *res;
1279 
1280     res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
1281     if (amount != 1L)
1282         res = makeplural(res);
1283     return res;
1284 }
1285 
1286 boolean
have_lizard()1287 have_lizard()
1288 {
1289     register struct obj *otmp;
1290 
1291     for (otmp = invent; otmp; otmp = otmp->nobj)
1292         if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
1293             return  TRUE;
1294     return FALSE;
1295 }
1296 
1297 /* 3.6 tribute */
1298 struct obj *
u_have_novel()1299 u_have_novel()
1300 {
1301     register struct obj *otmp;
1302 
1303     for (otmp = invent; otmp; otmp = otmp->nobj)
1304         if (otmp->otyp == SPE_NOVEL)
1305             return otmp;
1306     return (struct obj *) 0;
1307 }
1308 
1309 struct obj *
o_on(id,objchn)1310 o_on(id, objchn)
1311 unsigned int id;
1312 register struct obj *objchn;
1313 {
1314     struct obj *temp;
1315 
1316     while (objchn) {
1317         if (objchn->o_id == id)
1318             return objchn;
1319         if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
1320             return temp;
1321         objchn = objchn->nobj;
1322     }
1323     return (struct obj *) 0;
1324 }
1325 
1326 boolean
obj_here(obj,x,y)1327 obj_here(obj, x, y)
1328 register struct obj *obj;
1329 int x, y;
1330 {
1331     register struct obj *otmp;
1332 
1333     for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
1334         if (obj == otmp)
1335             return TRUE;
1336     return FALSE;
1337 }
1338 
1339 struct obj *
g_at(x,y)1340 g_at(x, y)
1341 register int x, y;
1342 {
1343     register struct obj *obj = level.objects[x][y];
1344 
1345     while (obj) {
1346         if (obj->oclass == COIN_CLASS)
1347             return obj;
1348         obj = obj->nexthere;
1349     }
1350     return (struct obj *) 0;
1351 }
1352 
1353 /* compact a string of inventory letters by dashing runs of letters */
1354 STATIC_OVL void
compactify(buf)1355 compactify(buf)
1356 register char *buf;
1357 {
1358     register int i1 = 1, i2 = 1;
1359     register char ilet, ilet1, ilet2;
1360 
1361     ilet2 = buf[0];
1362     ilet1 = buf[1];
1363     buf[++i2] = buf[++i1];
1364     ilet = buf[i1];
1365     while (ilet) {
1366         if (ilet == ilet1 + 1) {
1367             if (ilet1 == ilet2 + 1)
1368                 buf[i2 - 1] = ilet1 = '-';
1369             else if (ilet2 == '-') {
1370                 buf[i2 - 1] = ++ilet1;
1371                 buf[i2] = buf[++i1];
1372                 ilet = buf[i1];
1373                 continue;
1374             }
1375         } else if (ilet == NOINVSYM) {
1376             /* compact three or more consecutive '#'
1377                characters into "#-#" */
1378             if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM)
1379                 buf[i2 - 1] = '-';
1380             else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-'
1381                      && buf[i2 - 1] == NOINVSYM)
1382                 --i2;
1383         }
1384         ilet2 = ilet1;
1385         ilet1 = ilet;
1386         buf[++i2] = buf[++i1];
1387         ilet = buf[i1];
1388     }
1389 }
1390 
1391 /* some objects shouldn't be split when count given to getobj or askchain */
1392 boolean
splittable(obj)1393 splittable(obj)
1394 struct obj *obj;
1395 {
1396     return !((obj->otyp == LOADSTONE && obj->cursed)
1397              || (obj == uwep && welded(uwep)));
1398 }
1399 
1400 /* match the prompt for either 'T' or 'R' command */
1401 STATIC_OVL boolean
taking_off(action)1402 taking_off(action)
1403 const char *action;
1404 {
1405     return !strcmp(action, "take off") || !strcmp(action, "remove");
1406 }
1407 
1408 /* match the prompt for either 'W' or 'P' command */
1409 STATIC_OVL boolean
putting_on(action)1410 putting_on(action)
1411 const char *action;
1412 {
1413     return !strcmp(action, "wear") || !strcmp(action, "put on");
1414 }
1415 
1416 /*
1417  * getobj returns:
1418  *      struct obj *xxx:        object to do something with.
1419  *      (struct obj *) 0        error return: no object.
1420  *      &zeroobj                explicitly no object (as in w-).
1421 !!!! test if gold can be used in unusual ways (eaten etc.)
1422 !!!! may be able to remove "usegold"
1423  */
1424 struct obj *
getobj(let,word)1425 getobj(let, word)
1426 register const char *let, *word;
1427 {
1428     register struct obj *otmp;
1429     register char ilet = 0;
1430     char buf[BUFSZ], qbuf[QBUFSZ];
1431     char lets[BUFSZ], altlets[BUFSZ], *ap;
1432     register int foo = 0;
1433     register char *bp = buf;
1434     xchar allowcnt = 0; /* 0, 1 or 2 */
1435     boolean usegold = FALSE; /* can't use gold because its illegal */
1436     boolean allowall = FALSE;
1437     boolean allownone = FALSE;
1438     boolean useboulder = FALSE;
1439     xchar foox = 0;
1440     long cnt;
1441     boolean cntgiven = FALSE;
1442     boolean msggiven = FALSE;
1443     boolean oneloop = FALSE;
1444     long dummymask;
1445     Loot *sortedinvent, *srtinv;
1446 
1447     if (*let == ALLOW_COUNT)
1448         let++, allowcnt = 1;
1449     if (*let == COIN_CLASS)
1450         let++, usegold = TRUE;
1451 
1452     /* Equivalent of an "ugly check" for gold */
1453     if (usegold && !strcmp(word, "eat")
1454         && (!metallivorous(youmonst.data)
1455             || youmonst.data == &mons[PM_RUST_MONSTER]))
1456         usegold = FALSE;
1457 
1458     if (*let == ALL_CLASSES)
1459         let++, allowall = TRUE;
1460     if (*let == ALLOW_NONE)
1461         let++, allownone = TRUE;
1462     /* "ugly check" for reading fortune cookies, part 1.
1463      * The normal 'ugly check' keeps the object on the inventory list.
1464      * We don't want to do that for shirts/cookies, so the check for
1465      * them is handled a bit differently (and also requires that we set
1466      * allowall in the caller).
1467      */
1468     if (allowall && !strcmp(word, "read"))
1469         allowall = FALSE;
1470 
1471     /* another ugly check: show boulders (not statues) */
1472     if (*let == WEAPON_CLASS && !strcmp(word, "throw")
1473         && throws_rocks(youmonst.data))
1474         useboulder = TRUE;
1475 
1476     if (allownone)
1477         *bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
1478     ap = altlets;
1479 
1480     if (!flags.invlet_constant)
1481         reassign();
1482 
1483     /* force invent to be in invlet order before collecting candidate
1484        inventory letters */
1485     sortedinvent = sortloot(&invent, SORTLOOT_INVLET, FALSE,
1486                             (boolean FDECL((*), (OBJ_P))) 0);
1487 
1488     for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
1489         if (&bp[foo] == &buf[sizeof buf - 1]
1490             || ap == &altlets[sizeof altlets - 1]) {
1491             /* we must have a huge number of NOINVSYM items somehow */
1492             impossible("getobj: inventory overflow");
1493             break;
1494         }
1495 
1496         if (!*let || index(let, otmp->oclass)
1497             || (usegold && otmp->invlet == GOLD_SYM)
1498             || (useboulder && otmp->otyp == BOULDER)) {
1499             register int otyp = otmp->otyp;
1500 
1501             bp[foo++] = otmp->invlet;
1502 /* clang-format off */
1503 /* *INDENT-OFF* */
1504             /* ugly check: remove inappropriate things */
1505             if (
1506                 (taking_off(word) /* exclude if not worn */
1507                  && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1508              || (putting_on(word) /* exclude if already worn */
1509                  && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1510 #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
1511              || (!strcmp(word, "wield")
1512                  && (otmp->owornmask & W_WEP))
1513 #endif
1514              || (!strcmp(word, "ready")    /* exclude when wielded... */
1515                  && ((otmp == uwep || (otmp == uswapwep && u.twoweap))
1516                      && otmp->quan == 1L)) /* ...unless more than one */
1517              || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
1518                  && inaccessible_equipment(otmp, (const char *) 0, FALSE))
1519              ) {
1520                 foo--;
1521                 foox++;
1522             }
1523             /* Second ugly check; unlike the first it won't trigger an
1524              * "else" in "you don't have anything else to ___".
1525              */
1526             else if (
1527                 (putting_on(word)
1528                  && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
1529                      || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
1530                          && otyp != TOWEL && otyp != LENSES)))
1531              || (!strcmp(word, "wield")
1532                  && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
1533              || (!strcmp(word, "eat") && !is_edible(otmp))
1534              || (!strcmp(word, "sacrifice")
1535                  && (otyp != CORPSE && otyp != AMULET_OF_YENDOR
1536                      && otyp != FAKE_AMULET_OF_YENDOR))
1537              || (!strcmp(word, "write with")
1538                  && (otmp->oclass == TOOL_CLASS
1539                      && otyp != MAGIC_MARKER && otyp != TOWEL))
1540              || (!strcmp(word, "tin")
1541                  && (otyp != CORPSE || !tinnable(otmp)))
1542              || (!strcmp(word, "rub")
1543                  && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP
1544                       && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN)
1545                      || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1546              || (!strcmp(word, "use or apply")
1547                  /* Picks, axes, pole-weapons, bullwhips */
1548                  && ((otmp->oclass == WEAPON_CLASS
1549                       && !is_pick(otmp) && !is_axe(otmp)
1550                       && !is_pole(otmp) && otyp != BULLWHIP)
1551                      || (otmp->oclass == POTION_CLASS
1552                          /* only applicable potion is oil, and it will only
1553                             be offered as a choice when already discovered */
1554                          && (otyp != POT_OIL || !otmp->dknown
1555                              || !objects[POT_OIL].oc_name_known))
1556                      || (otmp->oclass == FOOD_CLASS
1557                          && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF)
1558                      || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1559              || (!strcmp(word, "invoke")
1560                  && !otmp->oartifact
1561                  && !objects[otyp].oc_unique
1562                  && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known)
1563                  && otyp != CRYSTAL_BALL /* synonym for apply */
1564                  /* note: presenting the possibility of invoking non-artifact
1565                     mirrors and/or lamps is simply a cruel deception... */
1566                  && otyp != MIRROR
1567                  && otyp != MAGIC_LAMP
1568                  && (otyp != OIL_LAMP /* don't list known oil lamp */
1569                      || (otmp->dknown && objects[OIL_LAMP].oc_name_known)))
1570              || (!strcmp(word, "untrap with")
1571                  && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)
1572                      || (otmp->oclass == POTION_CLASS
1573                          /* only applicable potion is oil, and it will only
1574                             be offered as a choice when already discovered */
1575                          && (otyp != POT_OIL || !otmp->dknown
1576                              || !objects[POT_OIL].oc_name_known))))
1577              || (!strcmp(word, "tip") && !Is_container(otmp)
1578                  /* include horn of plenty if sufficiently discovered */
1579                  && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
1580                      || !objects[HORN_OF_PLENTY].oc_name_known))
1581              || (!strcmp(word, "charge") && !is_chargeable(otmp))
1582              || (!strcmp(word, "open") && otyp != TIN)
1583              || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
1584              || (!strcmp(word, "adjust") && otmp->oclass == COIN_CLASS
1585                  && !usegold)
1586              ) {
1587                 foo--;
1588             }
1589             /* Third ugly check:  acceptable but not listed as likely
1590              * candidates in the prompt or in the inventory subset if
1591              * player responds with '?'.
1592              */
1593             else if (
1594              /* ugly check for unworn armor that can't be worn */
1595                 (putting_on(word) && *let == ARMOR_CLASS
1596                  && !canwearobj(otmp, &dummymask, FALSE))
1597              /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
1598              || ((putting_on(word) || taking_off(word))
1599                  && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
1600              /* or unsuitable items rubbed on known touchstone */
1601              || (!strncmp(word, "rub on the stone", 16)
1602                  && *let == GEM_CLASS && otmp->dknown
1603                  && objects[otyp].oc_name_known)
1604              /* suppress corpses on astral, amulets elsewhere */
1605              || (!strcmp(word, "sacrifice")
1606                  /* (!astral && amulet) || (astral && !amulet) */
1607                  && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
1608              /* suppress container being stashed into */
1609              || (!strcmp(word, "stash") && !ck_bag(otmp))
1610              /* worn armor (shirt, suit) covered by worn armor (suit, cloak)
1611                 or accessory (ring) covered by cursed worn armor (gloves) */
1612              || (taking_off(word)
1613                  && inaccessible_equipment(otmp, (const char *) 0,
1614                                       (boolean) (otmp->oclass == RING_CLASS)))
1615              || (!strcmp(word, "write on")
1616                  && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
1617                      || !otmp->dknown || !objects[otyp].oc_name_known))
1618              ) {
1619                 /* acceptable but not listed as likely candidate */
1620                 foo--;
1621                 allowall = TRUE;
1622                 *ap++ = otmp->invlet;
1623             }
1624 /* *INDENT-ON* */
1625 /* clang-format on */
1626         } else {
1627             /* "ugly check" for reading fortune cookies, part 2 */
1628             if ((!strcmp(word, "read") && is_readable(otmp)))
1629                 allowall = usegold = TRUE;
1630         }
1631     }
1632     unsortloot(&sortedinvent);
1633 
1634     bp[foo] = 0;
1635     if (foo == 0 && bp > buf && bp[-1] == ' ')
1636         *--bp = 0;
1637     Strcpy(lets, bp); /* necessary since we destroy buf */
1638     if (foo > 5)      /* compactify string */
1639         compactify(bp);
1640     *ap = '\0';
1641 
1642     if (!foo && !allowall && !allownone) {
1643         You("don't have anything %sto %s.", foox ? "else " : "", word);
1644         return (struct obj *) 0;
1645     } else if (!strcmp(word, "write on")) { /* ugly check for magic marker */
1646         /* we wanted all scrolls and books in altlets[], but that came with
1647            'allowall' which we don't want since it prevents "silly thing"
1648            result if anything other than scroll or spellbook is chosen */
1649         allowall = FALSE;
1650     }
1651     for (;;) {
1652         cnt = 0;
1653         cntgiven = FALSE;
1654         Sprintf(qbuf, "What do you want to %s?", word);
1655         if (in_doagain)
1656             ilet = readchar();
1657         else if (iflags.force_invmenu) {
1658             /* don't overwrite a possible quitchars */
1659             if (!oneloop)
1660                 ilet = *let ? '?' : '*';
1661             if (!msggiven)
1662                 putmsghistory(qbuf, FALSE);
1663             msggiven = TRUE;
1664             oneloop = TRUE;
1665         } else {
1666             if (!buf[0])
1667                 Strcat(qbuf, " [*]");
1668             else
1669                 Sprintf(eos(qbuf), " [%s or ?*]", buf);
1670             ilet = yn_function(qbuf, (char *) 0, '\0');
1671         }
1672         if (digit(ilet)) {
1673             long tmpcnt = 0;
1674 
1675             if (!allowcnt) {
1676                 pline("No count allowed with this command.");
1677                 continue;
1678             }
1679             ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt, TRUE);
1680             if (tmpcnt) {
1681                 cnt = tmpcnt;
1682                 cntgiven = TRUE;
1683             }
1684         }
1685         if (index(quitchars, ilet)) {
1686             if (flags.verbose)
1687                 pline1(Never_mind);
1688             return (struct obj *) 0;
1689         }
1690         if (ilet == HANDS_SYM) { /* '-' */
1691             if (!allownone) {
1692                 char *suf = (char *) 0;
1693 
1694                 strcpy(buf, word);
1695                 if ((bp = strstr(buf, " on the ")) != 0) {
1696                     /* rub on the stone[s] */
1697                     *bp = '\0';
1698                     suf = (bp + 1);
1699                 }
1700                 if ((bp = strstr(buf, " or ")) != 0) {
1701                     *bp = '\0';
1702                     bp = (rn2(2) ? buf : (bp + 4));
1703                 } else
1704                     bp = buf;
1705                 You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
1706                     suf ? suf : "");
1707             }
1708             return (allownone ? (struct obj *) &zeroobj : (struct obj *) 0);
1709         }
1710  redo_menu:
1711         /* since gold is now kept in inventory, we need to do processing for
1712            select-from-invent before checking whether gold has been picked */
1713         if (ilet == '?' || ilet == '*') {
1714             char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
1715             long ctmp = 0;
1716             char menuquery[QBUFSZ];
1717 
1718             menuquery[0] = qbuf[0] = '\0';
1719             if (iflags.force_invmenu)
1720                 Sprintf(menuquery, "What do you want to %s?", word);
1721             if (!strcmp(word, "grease"))
1722                 Sprintf(qbuf, "your %s", fingers_or_gloves(FALSE));
1723             else if (!strcmp(word, "write with"))
1724                 Sprintf(qbuf, "your %s", body_part(FINGERTIP));
1725             else if (!strcmp(word, "wield"))
1726                 Sprintf(qbuf, "your %s %s%s", uarmg ? "gloved" : "bare",
1727                         makeplural(body_part(HAND)),
1728                         !uwep ? " (wielded)" : "");
1729             else if (!strcmp(word, "ready"))
1730                 Sprintf(qbuf, "empty quiver%s",
1731                         !uquiver ? " (nothing readied)" : "");
1732 
1733             if (ilet == '?' && !*lets && *altlets)
1734                 allowed_choices = altlets;
1735             ilet = display_pickinv(allowed_choices, *qbuf ? qbuf : (char *) 0,
1736                                    menuquery,
1737                                    TRUE, allowcnt ? &ctmp : (long *) 0);
1738             if (!ilet)
1739                 continue;
1740             if (ilet == HANDS_SYM)
1741                 return (struct obj *) &zeroobj; /* cast away 'const' */
1742             if (ilet == '\033') {
1743                 if (flags.verbose)
1744                     pline1(Never_mind);
1745                 return (struct obj *) 0;
1746             }
1747             if (ilet == '*')
1748                 goto redo_menu;
1749             if (allowcnt && ctmp >= 0) {
1750                 cnt = ctmp;
1751                 cntgiven = TRUE;
1752             }
1753             /* they typed a letter (not a space) at the prompt */
1754         }
1755         /* find the item which was picked */
1756         for (otmp = invent; otmp; otmp = otmp->nobj)
1757             if (otmp->invlet == ilet)
1758                 break;
1759         /* some items have restrictions */
1760         if (ilet == def_oc_syms[COIN_CLASS].sym
1761             /* guard against the [hypothetical] chace of having more
1762                than one invent slot of gold and picking the non-'$' one */
1763             || (otmp && otmp->oclass == COIN_CLASS)) {
1764             if (!usegold) {
1765                 You("cannot %s gold.", word);
1766                 return (struct obj *) 0;
1767             }
1768             /* Historic note: early Nethack had a bug which was
1769              * first reported for Larn, where trying to drop 2^32-n
1770              * gold pieces was allowed, and did interesting things
1771              * to your money supply.  The LRS is the tax bureau
1772              * from Larn.
1773              */
1774             if (cntgiven && cnt <= 0) {
1775                 if (cnt < 0)
1776                     pline_The(
1777                   "LRS would be very interested to know you have that much.");
1778                 return (struct obj *) 0;
1779             }
1780         }
1781         if (cntgiven && !strcmp(word, "throw")) {
1782             /* permit counts for throwing gold, but don't accept
1783              * counts for other things since the throw code will
1784              * split off a single item anyway */
1785             if (cnt == 0)
1786                 return (struct obj *) 0;
1787             if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym
1788                 && !(otmp && otmp->oclass == COIN_CLASS))) {
1789                 You("can only throw one item at a time.");
1790                 continue;
1791             }
1792         }
1793         context.botl = 1; /* May have changed the amount of money */
1794         savech(ilet);
1795         /* [we used to set otmp (by finding ilet in invent) here, but
1796            that's been moved above so that otmp can be checked earlier] */
1797         /* verify the chosen object */
1798         if (!otmp) {
1799             You("don't have that object.");
1800             if (in_doagain)
1801                 return (struct obj *) 0;
1802             continue;
1803         } else if (cnt < 0 || otmp->quan < cnt) {
1804             You("don't have that many!  You have only %ld.", otmp->quan);
1805             if (in_doagain)
1806                 return (struct obj *) 0;
1807             continue;
1808         }
1809         break;
1810     }
1811     if (!allowall && let && !index(let, otmp->oclass)
1812         && !(usegold && otmp->oclass == COIN_CLASS)) {
1813         silly_thing(word, otmp);
1814         return (struct obj *) 0;
1815     }
1816     if (cntgiven) {
1817         if (cnt == 0)
1818             return (struct obj *) 0;
1819         if (cnt != otmp->quan) {
1820             /* don't split a stack of cursed loadstones */
1821             if (splittable(otmp))
1822                 otmp = splitobj(otmp, cnt);
1823             else if (otmp->otyp == LOADSTONE && otmp->cursed)
1824                 /* kludge for canletgo()'s can't-drop-this message */
1825                 otmp->corpsenm = (int) cnt;
1826         }
1827     }
1828     return otmp;
1829 }
1830 
1831 void
silly_thing(word,otmp)1832 silly_thing(word, otmp)
1833 const char *word;
1834 struct obj *otmp;
1835 {
1836 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1837     nhUse(otmp);
1838 #else
1839     const char *s1, *s2, *s3;
1840     int ocls = otmp->oclass, otyp = otmp->otyp;
1841 
1842     s1 = s2 = s3 = 0;
1843     /* check for attempted use of accessory commands ('P','R') on armor
1844        and for corresponding armor commands ('W','T') on accessories */
1845     if (ocls == ARMOR_CLASS) {
1846         if (!strcmp(word, "put on"))
1847             s1 = "W", s2 = "wear", s3 = "";
1848         else if (!strcmp(word, "remove"))
1849             s1 = "T", s2 = "take", s3 = " off";
1850     } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
1851                || ocls == AMULET_CLASS
1852                || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1853         if (!strcmp(word, "wear"))
1854             s1 = "P", s2 = "put", s3 = " on";
1855         else if (!strcmp(word, "take off"))
1856             s1 = "R", s2 = "remove", s3 = "";
1857     }
1858     if (s1)
1859         pline("Use the '%s' command to %s %s%s.", s1, s2,
1860               !(is_plural(otmp) || pair_of(otmp)) ? "that" : "those", s3);
1861     else
1862 #endif
1863         pline(silly_thing_to, word);
1864 }
1865 
1866 STATIC_PTR int
ckvalidcat(otmp)1867 ckvalidcat(otmp)
1868 struct obj *otmp;
1869 {
1870     /* use allow_category() from pickup.c */
1871     return (int) allow_category(otmp);
1872 }
1873 
1874 STATIC_PTR int
ckunpaid(otmp)1875 ckunpaid(otmp)
1876 struct obj *otmp;
1877 {
1878     return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
1879 }
1880 
1881 boolean
wearing_armor()1882 wearing_armor()
1883 {
1884     return (boolean) (uarm || uarmc || uarmf || uarmg
1885                       || uarmh || uarms || uarmu);
1886 }
1887 
1888 boolean
is_worn(otmp)1889 is_worn(otmp)
1890 struct obj *otmp;
1891 {
1892     return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPONS))
1893             ? TRUE
1894             : FALSE;
1895 }
1896 
1897 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1898 STATIC_VAR struct xprnctx {
1899     char let;
1900     boolean dot;
1901 } safeq_xprn_ctx;
1902 
1903 /* safe_qbuf() -> short_oname() callback */
1904 STATIC_PTR char *
safeq_xprname(obj)1905 safeq_xprname(obj)
1906 struct obj *obj;
1907 {
1908     return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot,
1909                    0L, 0L);
1910 }
1911 
1912 /* alternate safe_qbuf() -> short_oname() callback */
1913 STATIC_PTR char *
safeq_shortxprname(obj)1914 safeq_shortxprname(obj)
1915 struct obj *obj;
1916 {
1917     return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let,
1918                    safeq_xprn_ctx.dot, 0L, 0L);
1919 }
1920 
1921 static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
1922                                              RING_CLASS,  AMULET_CLASS,
1923                                              TOOL_CLASS,  0 };
1924 
1925 /* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
1926    Return the number of times fn was called successfully.
1927    If combo is TRUE, we just use this to get a category list. */
1928 int
ggetobj(word,fn,mx,combo,resultflags)1929 ggetobj(word, fn, mx, combo, resultflags)
1930 const char *word;
1931 int FDECL((*fn), (OBJ_P)), mx;
1932 boolean combo; /* combination menu flag */
1933 unsigned *resultflags;
1934 {
1935     int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
1936     boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
1937     boolean takeoff, ident, allflag, m_seen;
1938     int itemcount;
1939     int oletct, iletct, unpaid, oc_of_sym;
1940     char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 10];
1941     char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
1942     char buf[BUFSZ] = DUMMY, qbuf[QBUFSZ];
1943 
1944     if (!invent) {
1945         You("have nothing to %s.", word);
1946         if (resultflags)
1947             *resultflags = ALL_FINISHED;
1948         return 0;
1949     }
1950     if (resultflags)
1951         *resultflags = 0;
1952     takeoff = ident = allflag = m_seen = FALSE;
1953     add_valid_menu_class(0); /* reset */
1954     if (taking_off(word)) {
1955         takeoff = TRUE;
1956         ofilter = is_worn;
1957     } else if (!strcmp(word, "identify")) {
1958         ident = TRUE;
1959         ofilter = not_fully_identified;
1960     }
1961 
1962     iletct = collect_obj_classes(ilets, invent, FALSE, ofilter, &itemcount);
1963     unpaid = count_unpaid(invent);
1964 
1965     if (ident && !iletct) {
1966         return -1; /* no further identifications */
1967     } else if (invent) {
1968         ilets[iletct++] = ' ';
1969         if (unpaid)
1970             ilets[iletct++] = 'u';
1971         if (count_buc(invent, BUC_BLESSED, ofilter))
1972             ilets[iletct++] = 'B';
1973         if (count_buc(invent, BUC_UNCURSED, ofilter))
1974             ilets[iletct++] = 'U';
1975         if (count_buc(invent, BUC_CURSED, ofilter))
1976             ilets[iletct++] = 'C';
1977         if (count_buc(invent, BUC_UNKNOWN, ofilter))
1978             ilets[iletct++] = 'X';
1979         ilets[iletct++] = 'a';
1980     }
1981     ilets[iletct++] = 'i';
1982     if (!combo)
1983         ilets[iletct++] = 'm'; /* allow menu presentation on request */
1984     ilets[iletct] = '\0';
1985 
1986     for (;;) {
1987         Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]",
1988                 word, ilets);
1989         getlin(qbuf, buf);
1990         if (buf[0] == '\033')
1991             return 0;
1992         if (index(buf, 'i')) {
1993             char ailets[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
1994             struct obj *otmp;
1995 
1996             /* applicable inventory letters; if empty, show entire invent */
1997             ailets[0] = '\0';
1998             if (ofilter)
1999                 for (otmp = invent; otmp; otmp = otmp->nobj)
2000                     /* index() check: limit overflow items to one '#' */
2001                     if ((*ofilter)(otmp) && !index(ailets, otmp->invlet))
2002                         (void) strkitten(ailets, otmp->invlet);
2003             if (display_inventory(ailets, TRUE) == '\033')
2004                 return 0;
2005         } else
2006             break;
2007     }
2008 
2009     extra_removeables[0] = '\0';
2010     if (takeoff) {
2011         /* arbitrary types of items can be placed in the weapon slots
2012            [any duplicate entries in extra_removeables[] won't matter] */
2013         if (uwep)
2014             (void) strkitten(extra_removeables, uwep->oclass);
2015         if (uswapwep)
2016             (void) strkitten(extra_removeables, uswapwep->oclass);
2017         if (uquiver)
2018             (void) strkitten(extra_removeables, uquiver->oclass);
2019     }
2020 
2021     ip = buf;
2022     olets[oletct = 0] = '\0';
2023     while ((sym = *ip++) != '\0') {
2024         if (sym == ' ')
2025             continue;
2026         oc_of_sym = def_char_to_objclass(sym);
2027         if (takeoff && oc_of_sym != MAXOCLASSES) {
2028             if (index(extra_removeables, oc_of_sym)) {
2029                 ; /* skip rest of takeoff checks */
2030             } else if (!index(removeables, oc_of_sym)) {
2031                 pline("Not applicable.");
2032                 return 0;
2033             } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
2034                 noarmor(FALSE);
2035                 return 0;
2036             } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep
2037                        && !uquiver) {
2038                 You("are not wielding anything.");
2039                 return 0;
2040             } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
2041                 You("are not wearing rings.");
2042                 return 0;
2043             } else if (oc_of_sym == AMULET_CLASS && !uamul) {
2044                 You("are not wearing an amulet.");
2045                 return 0;
2046             } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
2047                 You("are not wearing a blindfold.");
2048                 return 0;
2049             }
2050         }
2051 
2052         if (oc_of_sym == COIN_CLASS && !combo) {
2053             context.botl = 1;
2054         } else if (sym == 'a') {
2055             allflag = TRUE;
2056         } else if (sym == 'A') {
2057             ; /* same as the default */
2058         } else if (sym == 'u') {
2059             add_valid_menu_class('u');
2060             ckfn = ckunpaid;
2061         } else if (index("BUCX", sym)) {
2062             add_valid_menu_class(sym); /* 'B','U','C',or 'X' */
2063             ckfn = ckvalidcat;
2064         } else if (sym == 'm') {
2065             m_seen = TRUE;
2066         } else if (oc_of_sym == MAXOCLASSES) {
2067             You("don't have any %c's.", sym);
2068         } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
2069             if (!index(olets, oc_of_sym)) {
2070                 add_valid_menu_class(oc_of_sym);
2071                 olets[oletct++] = oc_of_sym;
2072                 olets[oletct] = 0;
2073             }
2074         }
2075     }
2076 
2077     if (m_seen) {
2078         return (allflag
2079                 || (!oletct && ckfn != ckunpaid && ckfn != ckvalidcat))
2080                ? -2 : -3;
2081     } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
2082         return 0;
2083 #if 0
2084     /* !!!! test gold dropping */
2085     } else if (allowgold == 2 && !oletct) {
2086         return 1; /* you dropped gold (or at least tried to)  */
2087 #endif
2088     } else {
2089         int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
2090         /*
2091          * askchain() has already finished the job in this case
2092          * so set a special flag to convey that back to the caller
2093          * so that it won't continue processing.
2094          * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
2095          */
2096         if (combo && allflag && resultflags)
2097             *resultflags |= ALL_FINISHED;
2098         return cnt;
2099     }
2100 }
2101 
2102 /*
2103  * Walk through the chain starting at objchn and ask for all objects
2104  * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
2105  * whether the action in question (i.e., fn) has to be performed.
2106  * If allflag then no questions are asked.  Mx gives the max number
2107  * of objects to be treated.  Return the number of objects treated.
2108  */
2109 int
askchain(objchn,olets,allflag,fn,ckfn,mx,word)2110 askchain(objchn, olets, allflag, fn, ckfn, mx, word)
2111 struct obj **objchn; /* *objchn might change */
2112 int allflag, mx;
2113 const char *olets, *word; /* olets is an Obj Class char array */
2114 int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
2115 {
2116     struct obj *otmp, *otmpo;
2117     register char sym, ilet;
2118     int cnt = 0, dud = 0, tmp;
2119     boolean takeoff, nodot, ident, take_out, put_in, first, ininv, bycat;
2120     char qbuf[QBUFSZ], qpfx[QBUFSZ];
2121     Loot *sortedchn = 0;
2122 
2123     takeoff = taking_off(word);
2124     ident = !strcmp(word, "identify");
2125     take_out = !strcmp(word, "take out");
2126     put_in = !strcmp(word, "put in");
2127     nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
2128              || takeoff || take_out || put_in);
2129     ininv = (*objchn == invent);
2130     bycat = (menu_class_present('u')
2131              || menu_class_present('B') || menu_class_present('U')
2132              || menu_class_present('C') || menu_class_present('X'));
2133 
2134     /* someday maybe we'll sort by 'olets' too (temporarily replace
2135        flags.packorder and pass SORTLOOT_PACK), but not yet... */
2136     sortedchn = sortloot(objchn, SORTLOOT_INVLET, FALSE,
2137                          (boolean FDECL((*), (OBJ_P))) 0);
2138 
2139     first = TRUE;
2140     /*
2141      * Interrogate in the object class order specified.
2142      * For example, if a person specifies =/ then first all rings
2143      * will be asked about followed by all wands.  -dgk
2144      */
2145  nextclass:
2146     ilet = 'a' - 1;
2147     if (*objchn && (*objchn)->oclass == COIN_CLASS)
2148         ilet--;                     /* extra iteration */
2149     /*
2150      * Multiple Drop can change the invent chain while it operates
2151      * (dropping a burning potion of oil while levitating creates
2152      * an explosion which can destroy inventory items), so simple
2153      * list traversal
2154      *  for (otmp = *objchn; otmp; otmp = otmp2) {
2155      *      otmp2 = otmp->nobj;
2156      *      ...
2157      *  }
2158      * is inadequate here.  Use each object's bypass bit to keep
2159      * track of which list elements have already been processed.
2160      */
2161     bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
2162     while ((otmp = nxt_unbypassed_loot(sortedchn, *objchn)) != 0) {
2163         if (ilet == 'z')
2164             ilet = 'A';
2165         else if (ilet == 'Z')
2166             ilet = NOINVSYM; /* '#' */
2167         else
2168             ilet++;
2169         if (olets && *olets && otmp->oclass != *olets)
2170             continue;
2171         if (takeoff && !is_worn(otmp))
2172             continue;
2173         if (ident && !not_fully_identified(otmp))
2174             continue;
2175         if (ckfn && !(*ckfn)(otmp))
2176             continue;
2177         if (bycat && !ckvalidcat(otmp))
2178             continue;
2179         if (!allflag) {
2180             safeq_xprn_ctx.let = ilet;
2181             safeq_xprn_ctx.dot = !nodot;
2182             *qpfx = '\0';
2183             if (first) {
2184                 /* traditional_loot() skips prompting when only one
2185                    class of objects is involved, so prefix the first
2186                    object being queried here with an explanation why */
2187                 if (take_out || put_in)
2188                     Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
2189                 first = FALSE;
2190             }
2191             (void) safe_qbuf(qbuf, qpfx, "?", otmp,
2192                              ininv ? safeq_xprname : doname,
2193                              ininv ? safeq_shortxprname : ansimpleoname,
2194                              "item");
2195             sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
2196                                                         : nyNaq(qbuf);
2197         } else
2198             sym = 'y';
2199 
2200         otmpo = otmp;
2201         if (sym == '#') {
2202             /* Number was entered; split the object unless it corresponds
2203                to 'none' or 'all'.  2 special cases: cursed loadstones and
2204                welded weapons (eg, multiple daggers) will remain as merged
2205                unit; done to avoid splitting an object that won't be
2206                droppable (even if we're picking up rather than dropping). */
2207             if (!yn_number) {
2208                 sym = 'n';
2209             } else {
2210                 sym = 'y';
2211                 if (yn_number < otmp->quan && splittable(otmp))
2212                     otmp = splitobj(otmp, yn_number);
2213             }
2214         }
2215         switch (sym) {
2216         case 'a':
2217             allflag = 1;
2218             /*FALLTHRU*/
2219         case 'y':
2220             tmp = (*fn)(otmp);
2221             if (tmp < 0) {
2222                 if (container_gone(fn)) {
2223                     /* otmp caused magic bag to explode;
2224                        both are now gone */
2225                     otmp = 0; /* and return */
2226                 } else if (otmp && otmp != otmpo) {
2227                     /* split occurred, merge again */
2228                     (void) merged(&otmpo, &otmp);
2229                 }
2230                 goto ret;
2231             }
2232             cnt += tmp;
2233             if (--mx == 0)
2234                 goto ret;
2235             /*FALLTHRU*/
2236         case 'n':
2237             if (nodot)
2238                 dud++;
2239         default:
2240             break;
2241         case 'q':
2242             /* special case for seffects() */
2243             if (ident)
2244                 cnt = -1;
2245             goto ret;
2246         }
2247     }
2248     if (olets && *olets && *++olets)
2249         goto nextclass;
2250 
2251     if (!takeoff && (dud || cnt))
2252         pline("That was all.");
2253     else if (!dud && !cnt)
2254         pline("No applicable objects.");
2255  ret:
2256     unsortloot(&sortedchn);
2257     bypass_objlist(*objchn, FALSE);
2258     return cnt;
2259 }
2260 
2261 /*
2262  *      Object identification routines:
2263  */
2264 
2265 /* make an object actually be identified; no display updating */
2266 void
fully_identify_obj(otmp)2267 fully_identify_obj(otmp)
2268 struct obj *otmp;
2269 {
2270     makeknown(otmp->otyp);
2271     if (otmp->oartifact)
2272         discover_artifact((xchar) otmp->oartifact);
2273     otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
2274     if (Is_container(otmp) || otmp->otyp == STATUE)
2275         otmp->cknown = otmp->lknown = 1;
2276     if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
2277         learn_egg_type(otmp->corpsenm);
2278 }
2279 
2280 /* ggetobj callback routine; identify an object and give immediate feedback */
2281 int
identify(otmp)2282 identify(otmp)
2283 struct obj *otmp;
2284 {
2285     fully_identify_obj(otmp);
2286     prinv((char *) 0, otmp, 0L);
2287     return 1;
2288 }
2289 
2290 /* menu of unidentified objects; select and identify up to id_limit of them */
2291 STATIC_OVL void
menu_identify(id_limit)2292 menu_identify(id_limit)
2293 int id_limit;
2294 {
2295     menu_item *pick_list;
2296     int n, i, first = 1, tryct = 5;
2297     char buf[BUFSZ];
2298     /* assumptions:  id_limit > 0 and at least one unID'd item is present */
2299 
2300     while (id_limit) {
2301         Sprintf(buf, "What would you like to identify %s?",
2302                 first ? "first" : "next");
2303         n = query_objlist(buf, &invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE
2304                                          | USE_INVLET | INVORDER_SORT),
2305                           &pick_list, PICK_ANY, not_fully_identified);
2306 
2307         if (n > 0) {
2308             if (n > id_limit)
2309                 n = id_limit;
2310             for (i = 0; i < n; i++, id_limit--)
2311                 (void) identify(pick_list[i].item.a_obj);
2312             free((genericptr_t) pick_list);
2313             mark_synch(); /* Before we loop to pop open another menu */
2314             first = 0;
2315         } else if (n == -2) { /* player used ESC to quit menu */
2316             break;
2317         } else if (n == -1) { /* no eligible items found */
2318             pline("That was all.");
2319             break;
2320         } else if (!--tryct) { /* stop re-prompting */
2321             pline1(thats_enough_tries);
2322             break;
2323         } else { /* try again */
2324             pline("Choose an item; use ESC to decline.");
2325         }
2326     }
2327 }
2328 /* count the unidentified items */
2329 int
count_unidentified(objchn)2330 count_unidentified(objchn)
2331 struct obj *objchn;
2332 {
2333     int unid_cnt = 0;
2334     struct obj *obj;
2335 
2336     for (obj = objchn; obj; obj = obj->nobj)
2337         if (not_fully_identified(obj))
2338             ++unid_cnt;
2339     return unid_cnt;
2340 }
2341 
2342 /* dialog with user to identify a given number of items; 0 means all */
2343 void
identify_pack(id_limit,learning_id)2344 identify_pack(id_limit, learning_id)
2345 int id_limit;
2346 boolean learning_id; /* true if we just read unknown identify scroll */
2347 {
2348     struct obj *obj;
2349     int n, unid_cnt = count_unidentified(invent);
2350 
2351     if (!unid_cnt) {
2352         You("have already identified all %sof your possessions.",
2353             learning_id ? "the rest " : "");
2354     } else if (!id_limit || id_limit >= unid_cnt) {
2355         /* identify everything */
2356         /* TODO:  use fully_identify_obj and cornline/menu/whatever here */
2357         for (obj = invent; obj; obj = obj->nobj) {
2358             if (not_fully_identified(obj)) {
2359                 (void) identify(obj);
2360                 if (unid_cnt == 1)
2361                     break;
2362             }
2363         }
2364     } else {
2365         /* identify up to `id_limit' items */
2366         n = 0;
2367         if (flags.menu_style == MENU_TRADITIONAL)
2368             do {
2369                 n = ggetobj("identify", identify, id_limit, FALSE,
2370                             (unsigned *) 0);
2371                 if (n < 0)
2372                     break; /* quit or no eligible items */
2373             } while ((id_limit -= n) > 0);
2374         if (n == 0 || n < -1)
2375             menu_identify(id_limit);
2376     }
2377     update_inventory();
2378 }
2379 
2380 /* called when regaining sight; mark inventory objects which were picked
2381    up while blind as now having been seen */
2382 void
learn_unseen_invent()2383 learn_unseen_invent()
2384 {
2385     struct obj *otmp;
2386 
2387     if (Blind)
2388         return; /* sanity check */
2389 
2390     for (otmp = invent; otmp; otmp = otmp->nobj) {
2391         if (otmp->dknown)
2392             continue; /* already seen */
2393         /* set dknown, perhaps bknown (for priest[ess]) */
2394         (void) xname(otmp);
2395         /*
2396          * If object->eknown gets implemented (see learnwand(zap.c)),
2397          * handle deferred discovery here.
2398          */
2399     }
2400     update_inventory();
2401 }
2402 
2403 /* persistent inventory window is maintained by interface code;
2404    'update_inventory' used to be a macro for
2405    (*windowprocs.win_update_inventory) but the restore hackery
2406    was getting out of hand; this is now a central call point */
2407 void
update_inventory()2408 update_inventory()
2409 {
2410     if (restoring)
2411         return;
2412 
2413     /*
2414      * Ought to check (windowprocs.wincap2 & WC2_PERM_INVENT) here....
2415      *
2416      * We currently don't skip this call when iflags.perm_invent is False
2417      * because curses uses that to disable a previous perm_invent window
2418      * (after toggle via 'O'; perhaps the options code should handle that).
2419      */
2420     (*windowprocs.win_update_inventory)();
2421 }
2422 
2423 /* should of course only be called for things in invent */
2424 STATIC_OVL char
obj_to_let(obj)2425 obj_to_let(obj)
2426 struct obj *obj;
2427 {
2428     if (!flags.invlet_constant) {
2429         obj->invlet = NOINVSYM;
2430         reassign();
2431     }
2432     return obj->invlet;
2433 }
2434 
2435 /*
2436  * Print the indicated quantity of the given object.  If quan == 0L then use
2437  * the current quantity.
2438  */
2439 void
prinv(prefix,obj,quan)2440 prinv(prefix, obj, quan)
2441 const char *prefix;
2442 struct obj *obj;
2443 long quan;
2444 {
2445     if (!prefix)
2446         prefix = "";
2447     pline("%s%s%s", prefix, *prefix ? " " : "",
2448           xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan));
2449 }
2450 
2451 char *
xprname(obj,txt,let,dot,cost,quan)2452 xprname(obj, txt, let, dot, cost, quan)
2453 struct obj *obj;
2454 const char *txt; /* text to print instead of obj */
2455 char let;        /* inventory letter */
2456 boolean dot;     /* append period; (dot && cost => Iu) */
2457 long cost;       /* cost (for inventory of unpaid or expended items) */
2458 long quan;       /* if non-0, print this quantity, not obj->quan */
2459 {
2460 #ifdef LINT /* handle static char li[BUFSZ]; */
2461     char li[BUFSZ];
2462 #else
2463     static char li[BUFSZ];
2464 #endif
2465     boolean use_invlet = (flags.invlet_constant
2466                           && let != CONTAINED_SYM && let != HANDS_SYM);
2467     long savequan = 0;
2468 
2469     if (quan && obj) {
2470         savequan = obj->quan;
2471         obj->quan = quan;
2472     }
2473     /*
2474      * If let is:
2475      *  -  Then obj == null and 'txt' refers to hands or fingers.
2476      *  *  Then obj == null and we are printing a total amount.
2477      *  >  Then the object is contained and doesn't have an inventory letter.
2478      */
2479     if (cost != 0 || let == '*') {
2480         /* if dot is true, we're doing Iu, otherwise Ix */
2481         Sprintf(li,
2482                 iflags.menu_tab_sep ? "%c - %s\t%6ld %s"
2483                                     : "%c - %-45s %6ld %s",
2484                 (dot && use_invlet ? obj->invlet : let),
2485                 (txt ? txt : doname(obj)), cost, currency(cost));
2486     } else {
2487         /* ordinary inventory display or pickup message */
2488         Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
2489                 (txt ? txt : doname(obj)), (dot ? "." : ""));
2490     }
2491     if (savequan)
2492         obj->quan = savequan;
2493 
2494     return li;
2495 }
2496 
2497 /* the 'i' command */
2498 int
ddoinv()2499 ddoinv()
2500 {
2501     (void) display_inventory((char *) 0, FALSE);
2502     return 0;
2503 }
2504 
2505 /*
2506  * find_unpaid()
2507  *
2508  * Scan the given list of objects.  If last_found is NULL, return the first
2509  * unpaid object found.  If last_found is not NULL, then skip over unpaid
2510  * objects until last_found is reached, then set last_found to NULL so the
2511  * next unpaid object is returned.  This routine recursively follows
2512  * containers.
2513  */
2514 STATIC_OVL struct obj *
find_unpaid(list,last_found)2515 find_unpaid(list, last_found)
2516 struct obj *list, **last_found;
2517 {
2518     struct obj *obj;
2519 
2520     while (list) {
2521         if (list->unpaid) {
2522             if (*last_found) {
2523                 /* still looking for previous unpaid object */
2524                 if (list == *last_found)
2525                     *last_found = (struct obj *) 0;
2526             } else
2527                 return ((*last_found = list));
2528         }
2529         if (Has_contents(list)) {
2530             if ((obj = find_unpaid(list->cobj, last_found)) != 0)
2531                 return obj;
2532         }
2533         list = list->nobj;
2534     }
2535     return (struct obj *) 0;
2536 }
2537 
2538 /* for perm_invent when operating on a partial inventory display, so that
2539    the persistent one doesn't get shrunk during filtering for item selection
2540    then regrown to full inventory, possibly being resized in the process */
2541 static winid cached_pickinv_win = WIN_ERR;
2542 
2543 void
free_pickinv_cache()2544 free_pickinv_cache()
2545 {
2546     if (cached_pickinv_win != WIN_ERR) {
2547         destroy_nhwindow(cached_pickinv_win);
2548         cached_pickinv_win = WIN_ERR;
2549     }
2550 }
2551 
2552 /*
2553  * Internal function used by display_inventory and getobj that can display
2554  * inventory and return a count as well as a letter. If out_cnt is not null,
2555  * any count returned from the menu selection is placed here.
2556  */
2557 STATIC_OVL char
display_pickinv(lets,xtra_choice,query,want_reply,out_cnt)2558 display_pickinv(lets, xtra_choice, query, want_reply, out_cnt)
2559 register const char *lets;
2560 const char *xtra_choice; /* "fingers", pick hands rather than an object */
2561 const char *query;
2562 boolean want_reply;
2563 long *out_cnt;
2564 {
2565     static const char not_carrying_anything[] = "Not carrying anything";
2566     struct obj *otmp, wizid_fakeobj;
2567     char ilet, ret;
2568     char *invlet = flags.inv_order;
2569     int n, classcount;
2570     winid win;                        /* windows being used */
2571     anything any;
2572     menu_item *selected;
2573     unsigned sortflags;
2574     Loot *sortedinvent, *srtinv;
2575     boolean wizid = (wizard && iflags.override_ID), gotsomething = FALSE;
2576 
2577     if (lets && !*lets)
2578         lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */
2579 
2580     if (iflags.perm_invent && (lets || xtra_choice || wizid)) {
2581         /* partial inventory in perm_invent setting; don't operate on
2582            full inventory window, use an alternate one instead; create
2583            the first time needed and keep it for re-use as needed later */
2584         if (cached_pickinv_win == WIN_ERR)
2585             cached_pickinv_win = create_nhwindow(NHW_MENU);
2586         win = cached_pickinv_win;
2587     } else
2588         win = WIN_INVEN;
2589 
2590     /*
2591      * Exit early if no inventory -- but keep going if we are doing
2592      * a permanent inventory update.  We need to keep going so the
2593      * permanent inventory window updates itself to remove the last
2594      * item(s) dropped.  One down side:  the addition of the exception
2595      * for permanent inventory window updates _can_ pop the window
2596      * up when it's not displayed -- even if it's empty -- because we
2597      * don't know at this level if its up or not.  This may not be
2598      * an issue if empty checks are done before hand and the call
2599      * to here is short circuited away.
2600      *
2601      * 2: our count here is only to distinguish between 0 and 1 and
2602      * more than 1; for the last one, we don't need a precise number.
2603      * For perm_invent update we force 'more than 1'.
2604      */
2605     n = (iflags.perm_invent && !lets && !want_reply) ? 2
2606         : lets ? (int) strlen(lets)
2607                : !invent ? 0 : !invent->nobj ? 1 : 2;
2608     /* for xtra_choice, there's another 'item' not included in initial 'n';
2609        for !lets (full invent) and for override_ID (wizard mode identify),
2610        skip message_menu handling of single item even if item count was 1 */
2611     if (xtra_choice || (n == 1 && (!lets || iflags.override_ID)))
2612         ++n;
2613 
2614     if (n == 0) {
2615         pline("%s.", not_carrying_anything);
2616         return 0;
2617     }
2618 
2619     /* oxymoron? temporarily assign permanent inventory letters */
2620     if (!flags.invlet_constant)
2621         reassign();
2622 
2623     if (n == 1 && !iflags.force_invmenu) {
2624         /* when only one item of interest, use pline instead of menus;
2625            we actually use a fake message-line menu in order to allow
2626            the user to perform selection at the --More-- prompt for tty */
2627         ret = '\0';
2628         if (xtra_choice) {
2629             /* xtra_choice is "bare hands" (wield), "fingertip" (Engrave),
2630                "nothing" (ready Quiver), or "fingers" (apply grease) */
2631             ret = message_menu(HANDS_SYM, PICK_ONE,
2632                                xprname((struct obj *) 0, xtra_choice,
2633                                        HANDS_SYM, TRUE, 0L, 0L)); /* '-' */
2634         } else {
2635             for (otmp = invent; otmp; otmp = otmp->nobj)
2636                 if (!lets || otmp->invlet == lets[0])
2637                     break;
2638             if (otmp)
2639                 ret = message_menu(otmp->invlet,
2640                                    want_reply ? PICK_ONE : PICK_NONE,
2641                                    xprname(otmp, (char *) 0, lets[0],
2642                                            TRUE, 0L, 0L));
2643         }
2644         if (out_cnt)
2645             *out_cnt = -1L; /* select all */
2646         return ret;
2647     }
2648 
2649     sortflags = (flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET;
2650     if (flags.sortpack)
2651         sortflags |= SORTLOOT_PACK;
2652     sortedinvent = sortloot(&invent, sortflags, FALSE,
2653                             (boolean FDECL((*), (OBJ_P))) 0);
2654 
2655     start_menu(win);
2656     any = zeroany;
2657     if (wizard && iflags.override_ID) {
2658         int unid_cnt;
2659         char prompt[QBUFSZ];
2660 
2661         unid_cnt = count_unidentified(invent);
2662         Sprintf(prompt, "Debug Identify"); /* 'title' rather than 'prompt' */
2663         if (unid_cnt)
2664             Sprintf(eos(prompt),
2665                     " -- unidentified or partially identified item%s",
2666                     plur(unid_cnt));
2667         add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, MENU_UNSELECTED);
2668         if (!unid_cnt) {
2669             add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
2670                      "(all items are permanently identified already)",
2671                      MENU_UNSELECTED);
2672             gotsomething = TRUE;
2673         } else {
2674             any.a_obj = &wizid_fakeobj;
2675             Sprintf(prompt, "select %s to permanently identify",
2676                     (unid_cnt == 1) ? "it": "any or all of them");
2677             /* wiz_identify stuffed the wiz_identify command character (^I)
2678                into iflags.override_ID for our use as an accelerator;
2679                it could be ambiguous if player has assigned a letter to
2680                the #wizidentify command, so include it as a group accelator
2681                but use '_' as the primary selector */
2682             if (unid_cnt > 1)
2683                 Sprintf(eos(prompt), " (%s for all)",
2684                         visctrl(iflags.override_ID));
2685             add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
2686                      prompt, MENU_UNSELECTED);
2687             gotsomething = TRUE;
2688         }
2689    } else if (xtra_choice) {
2690         /* wizard override ID and xtra_choice are mutually exclusive */
2691         if (flags.sortpack)
2692             add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2693                      "Miscellaneous", MENU_UNSELECTED);
2694         any.a_char = HANDS_SYM; /* '-' */
2695         add_menu(win, NO_GLYPH, &any, HANDS_SYM, 0, ATR_NONE,
2696                  xtra_choice, MENU_UNSELECTED);
2697         gotsomething = TRUE;
2698     }
2699  nextclass:
2700     classcount = 0;
2701     for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
2702         if (lets && !index(lets, otmp->invlet))
2703             continue;
2704         if (!flags.sortpack || otmp->oclass == *invlet) {
2705             if (wizid && !not_fully_identified(otmp))
2706                 continue;
2707             any = zeroany; /* all bits zero */
2708             ilet = otmp->invlet;
2709             if (flags.sortpack && !classcount) {
2710                 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2711                          let_to_name(*invlet, FALSE,
2712                                      (want_reply && iflags.menu_head_objsym)),
2713                          MENU_UNSELECTED);
2714                 classcount++;
2715             }
2716             if (wizid)
2717                 any.a_obj = otmp;
2718             else
2719                 any.a_char = ilet;
2720             add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng), &any, ilet,
2721                      wizid ? def_oc_syms[(int) otmp->oclass].sym : 0,
2722                      ATR_NONE, doname(otmp), MENU_UNSELECTED);
2723             gotsomething = TRUE;
2724         }
2725     }
2726     if (flags.sortpack) {
2727         if (*++invlet)
2728             goto nextclass;
2729         if (--invlet != venom_inv) {
2730             invlet = venom_inv;
2731             goto nextclass;
2732         }
2733     }
2734     if (iflags.force_invmenu && lets && want_reply) {
2735         any = zeroany;
2736         add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2737                  "Special", MENU_UNSELECTED);
2738         any.a_char = '*';
2739         add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE,
2740                  "(list everything)", MENU_UNSELECTED);
2741         gotsomething = TRUE;
2742     }
2743     unsortloot(&sortedinvent);
2744     /* for permanent inventory where we intend to show everything but
2745        nothing has been listed (because there isn't anyhing to list;
2746        the n==0 case above gets skipped for perm_invent), put something
2747        into the menu */
2748     if (iflags.perm_invent && !lets && !gotsomething) {
2749         any = zeroany;
2750         add_menu(win, NO_GLYPH, &any, 0, 0, 0,
2751                  not_carrying_anything, MENU_UNSELECTED);
2752         want_reply = FALSE;
2753     }
2754     end_menu(win, query && *query ? query : (char *) 0);
2755 
2756     n = select_menu(win,
2757                     wizid ? PICK_ANY : want_reply ? PICK_ONE : PICK_NONE,
2758                     &selected);
2759     if (n > 0) {
2760         if (wizid) {
2761             int i;
2762 
2763             /* identifying items will update perm_invent, calling this
2764                routine recursively, and we don't want the nested call
2765                to filter on unID'd items */
2766             iflags.override_ID = 0;
2767             ret = '\0';
2768             for (i = 0; i < n; ++i) {
2769                 otmp = selected[i].item.a_obj;
2770                 if (otmp == &wizid_fakeobj) {
2771                     identify_pack(0, FALSE);
2772                 } else {
2773                     if (not_fully_identified(otmp))
2774                         (void) identify(otmp);
2775                 }
2776             }
2777         } else {
2778             ret = selected[0].item.a_char;
2779             if (out_cnt)
2780                 *out_cnt = selected[0].count;
2781         }
2782         free((genericptr_t) selected);
2783     } else
2784         ret = !n ? '\0' : '\033'; /* cancelled */
2785 
2786     return ret;
2787 }
2788 
2789 /*
2790  * If lets == NULL or "", list all objects in the inventory.  Otherwise,
2791  * list all objects with object classes that match the order in lets.
2792  *
2793  * Returns the letter identifier of a selected item, or 0 if nothing
2794  * was selected.
2795  */
2796 char
display_inventory(lets,want_reply)2797 display_inventory(lets, want_reply)
2798 const char *lets;
2799 boolean want_reply;
2800 {
2801     return display_pickinv(lets, (char *) 0, (char *) 0,
2802                            want_reply, (long *) 0);
2803 }
2804 
2805 /*
2806  * Show what is current using inventory letters.
2807  *
2808  */
2809 STATIC_OVL char
display_used_invlets(avoidlet)2810 display_used_invlets(avoidlet)
2811 char avoidlet;
2812 {
2813     struct obj *otmp;
2814     char ilet, ret = 0;
2815     char *invlet = flags.inv_order;
2816     int n, classcount, invdone = 0;
2817     winid win;
2818     anything any;
2819     menu_item *selected;
2820 
2821     if (invent) {
2822         win = create_nhwindow(NHW_MENU);
2823         start_menu(win);
2824         while (!invdone) {
2825             any = zeroany; /* set all bits to zero */
2826             classcount = 0;
2827             for (otmp = invent; otmp; otmp = otmp->nobj) {
2828                 ilet = otmp->invlet;
2829                 if (ilet == avoidlet)
2830                     continue;
2831                 if (!flags.sortpack || otmp->oclass == *invlet) {
2832                     if (flags.sortpack && !classcount) {
2833                         any = zeroany; /* zero */
2834                         add_menu(win, NO_GLYPH, &any, 0, 0,
2835                                  iflags.menu_headings,
2836                                  let_to_name(*invlet, FALSE, FALSE),
2837                                  MENU_UNSELECTED);
2838                         classcount++;
2839                     }
2840                     any.a_char = ilet;
2841                     add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng),
2842                              &any, ilet, 0, ATR_NONE,
2843                              doname(otmp), MENU_UNSELECTED);
2844                 }
2845             }
2846             if (flags.sortpack && *++invlet)
2847                 continue;
2848             invdone = 1;
2849         }
2850         end_menu(win, "Inventory letters used:");
2851 
2852         n = select_menu(win, PICK_ONE, &selected);
2853         if (n > 0) {
2854             ret = selected[0].item.a_char;
2855             free((genericptr_t) selected);
2856         } else
2857             ret = !n ? '\0' : '\033'; /* cancelled */
2858         destroy_nhwindow(win);
2859     }
2860     return ret;
2861 }
2862 
2863 /*
2864  * Returns the number of unpaid items within the given list.  This includes
2865  * contained objects.
2866  */
2867 int
count_unpaid(list)2868 count_unpaid(list)
2869 struct obj *list;
2870 {
2871     int count = 0;
2872 
2873     while (list) {
2874         if (list->unpaid)
2875             count++;
2876         if (Has_contents(list))
2877             count += count_unpaid(list->cobj);
2878         list = list->nobj;
2879     }
2880     return count;
2881 }
2882 
2883 /*
2884  * Returns the number of items with b/u/c/unknown within the given list.
2885  * This does NOT include contained objects.
2886  *
2887  * Assumes that the hero sees or touches or otherwise senses the objects
2888  * at some point:  bknown is forced for priest[ess], like in xname().
2889  */
2890 int
count_buc(list,type,filterfunc)2891 count_buc(list, type, filterfunc)
2892 struct obj *list;
2893 int type;
2894 boolean FDECL((*filterfunc), (OBJ_P));
2895 {
2896     int count = 0;
2897 
2898     for (; list; list = list->nobj) {
2899         /* priests always know bless/curse state */
2900         if (Role_if(PM_PRIEST))
2901             list->bknown = (list->oclass != COIN_CLASS);
2902         /* some actions exclude some or most items */
2903         if (filterfunc && !(*filterfunc)(list))
2904             continue;
2905 
2906         /* coins are either uncursed or unknown based upon option setting */
2907         if (list->oclass == COIN_CLASS) {
2908             if (type == (iflags.goldX ? BUC_UNKNOWN : BUC_UNCURSED))
2909                 ++count;
2910             continue;
2911         }
2912         /* check whether this object matches the requested type */
2913         if (!list->bknown
2914                 ? (type == BUC_UNKNOWN)
2915                 : list->blessed ? (type == BUC_BLESSED)
2916                                 : list->cursed ? (type == BUC_CURSED)
2917                                                : (type == BUC_UNCURSED))
2918             ++count;
2919     }
2920     return count;
2921 }
2922 
2923 /* similar to count_buc(), but tallies all states at once
2924    rather than looking for a specific type */
2925 void
tally_BUCX(list,by_nexthere,bcp,ucp,ccp,xcp,ocp)2926 tally_BUCX(list, by_nexthere, bcp, ucp, ccp, xcp, ocp)
2927 struct obj *list;
2928 boolean by_nexthere;
2929 int *bcp, *ucp, *ccp, *xcp, *ocp;
2930 {
2931     /* Future extensions:
2932      *  Skip current_container when list is invent, uchain when
2933      *  first object of list is located on the floor.  'ocp' will then
2934      *  have a function again (it was a counter for having skipped gold,
2935      *  but that's not skipped anymore).
2936      */
2937     *bcp = *ucp = *ccp = *xcp = *ocp = 0;
2938     for ( ; list; list = (by_nexthere ? list->nexthere : list->nobj)) {
2939         /* priests always know bless/curse state */
2940         if (Role_if(PM_PRIEST))
2941             list->bknown = (list->oclass != COIN_CLASS);
2942         /* coins are either uncursed or unknown based upon option setting */
2943         if (list->oclass == COIN_CLASS) {
2944             if (iflags.goldX)
2945                 ++(*xcp);
2946             else
2947                 ++(*ucp);
2948             continue;
2949         }
2950         /* ordinary items */
2951         if (!list->bknown)
2952             ++(*xcp);
2953         else if (list->blessed)
2954             ++(*bcp);
2955         else if (list->cursed)
2956             ++(*ccp);
2957         else /* neither blessed nor cursed => uncursed */
2958             ++(*ucp);
2959     }
2960 }
2961 
2962 /* count everything inside a container, or just shop-owned items inside */
2963 long
count_contents(container,nested,quantity,everything,newdrop)2964 count_contents(container, nested, quantity, everything, newdrop)
2965 struct obj *container;
2966 boolean nested, /* include contents of any nested containers */
2967     quantity,   /* count all vs count separate stacks */
2968     everything, /* all objects vs only unpaid objects */
2969     newdrop;    /* on floor, but hero-owned items haven't been marked
2970                  * no_charge yet and shop-owned items are still marked
2971                  * unpaid -- used when asking the player whether to sell */
2972 {
2973     struct obj *otmp, *topc;
2974     boolean shoppy = FALSE;
2975     long count = 0L;
2976 
2977     if (!everything && !newdrop) {
2978         xchar x, y;
2979 
2980         for (topc = container; topc->where == OBJ_CONTAINED;
2981              topc = topc->ocontainer)
2982             continue;
2983         if (topc->where == OBJ_FLOOR && get_obj_location(topc, &x, &y, 0))
2984             shoppy = costly_spot(x, y);
2985     }
2986     for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
2987         if (nested && Has_contents(otmp))
2988             count += count_contents(otmp, nested, quantity, everything,
2989                                     newdrop);
2990         if (everything || otmp->unpaid || (shoppy && !otmp->no_charge))
2991             count += quantity ? otmp->quan : 1L;
2992     }
2993     return count;
2994 }
2995 
2996 STATIC_OVL void
dounpaid()2997 dounpaid()
2998 {
2999     winid win;
3000     struct obj *otmp, *marker, *contnr;
3001     register char ilet;
3002     char *invlet = flags.inv_order;
3003     int classcount, count, num_so_far;
3004     long cost, totcost;
3005 
3006     count = count_unpaid(invent);
3007     otmp = marker = contnr = (struct obj *) 0;
3008 
3009     if (count == 1) {
3010         otmp = find_unpaid(invent, &marker);
3011         contnr = unknwn_contnr_contents(otmp);
3012     }
3013     if  (otmp && !contnr) {
3014         /* 1 item; use pline instead of popup menu */
3015         cost = unpaid_cost(otmp, FALSE);
3016         iflags.suppress_price++; /* suppress "(unpaid)" suffix */
3017         pline1(xprname(otmp, distant_name(otmp, doname),
3018                        carried(otmp) ? otmp->invlet : CONTAINED_SYM,
3019                        TRUE, cost, 0L));
3020         iflags.suppress_price--;
3021         return;
3022     }
3023 
3024     win = create_nhwindow(NHW_MENU);
3025     cost = totcost = 0;
3026     num_so_far = 0; /* count of # printed so far */
3027     if (!flags.invlet_constant)
3028         reassign();
3029 
3030     do {
3031         classcount = 0;
3032         for (otmp = invent; otmp; otmp = otmp->nobj) {
3033             ilet = otmp->invlet;
3034             if (otmp->unpaid) {
3035                 if (!flags.sortpack || otmp->oclass == *invlet) {
3036                     if (flags.sortpack && !classcount) {
3037                         putstr(win, 0, let_to_name(*invlet, TRUE, FALSE));
3038                         classcount++;
3039                     }
3040 
3041                     totcost += cost = unpaid_cost(otmp, FALSE);
3042                     iflags.suppress_price++; /* suppress "(unpaid)" suffix */
3043                     putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
3044                                            ilet, TRUE, cost, 0L));
3045                     iflags.suppress_price--;
3046                     num_so_far++;
3047                 }
3048             }
3049         }
3050     } while (flags.sortpack && (*++invlet));
3051 
3052     if (count > num_so_far) {
3053         /* something unpaid is contained */
3054         if (flags.sortpack)
3055             putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE, FALSE));
3056         /*
3057          * Search through the container objects in the inventory for
3058          * unpaid items.  The top level inventory items have already
3059          * been listed.
3060          */
3061         for (otmp = invent; otmp; otmp = otmp->nobj) {
3062             if (Has_contents(otmp)) {
3063                 long contcost = 0L;
3064 
3065                 marker = (struct obj *) 0; /* haven't found any */
3066                 while (find_unpaid(otmp->cobj, &marker)) {
3067                     totcost += cost = unpaid_cost(marker, FALSE);
3068                     contcost += cost;
3069                     if (otmp->cknown) {
3070                         iflags.suppress_price++; /* suppress "(unpaid)" sfx */
3071                         putstr(win, 0,
3072                                xprname(marker, distant_name(marker, doname),
3073                                        CONTAINED_SYM, TRUE, cost, 0L));
3074                         iflags.suppress_price--;
3075                     }
3076                 }
3077                 if (!otmp->cknown) {
3078                     char contbuf[BUFSZ];
3079 
3080                     /* Shopkeeper knows what to charge for contents */
3081                     Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
3082                     putstr(win, 0,
3083                            xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
3084                                    TRUE, contcost, 0L));
3085                 }
3086             }
3087         }
3088     }
3089 
3090     putstr(win, 0, "");
3091     putstr(win, 0,
3092            xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
3093     display_nhwindow(win, FALSE);
3094     destroy_nhwindow(win);
3095 }
3096 
3097 /* query objlist callback: return TRUE if obj type matches "this_type" */
3098 static int this_type;
3099 
3100 STATIC_OVL boolean
this_type_only(obj)3101 this_type_only(obj)
3102 struct obj *obj;
3103 {
3104     boolean res = (obj->oclass == this_type);
3105 
3106     if (obj->oclass == COIN_CLASS) {
3107         /* if filtering by bless/curse state, gold is classified as
3108            either unknown or uncursed based on user option setting */
3109         if (this_type && index("BUCX", this_type))
3110             res = (this_type == (iflags.goldX ? 'X' : 'U'));
3111     } else {
3112         switch (this_type) {
3113         case 'B':
3114             res = (obj->bknown && obj->blessed);
3115             break;
3116         case 'U':
3117             res = (obj->bknown && !(obj->blessed || obj->cursed));
3118             break;
3119         case 'C':
3120             res = (obj->bknown && obj->cursed);
3121             break;
3122         case 'X':
3123             res = !obj->bknown;
3124             break;
3125         default:
3126             break; /* use 'res' as-is */
3127         }
3128     }
3129     return res;
3130 }
3131 
3132 /* the 'I' command */
3133 int
dotypeinv()3134 dotypeinv()
3135 {
3136     char c = '\0';
3137     int n, i = 0;
3138     char *extra_types, types[BUFSZ];
3139     int class_count, oclass, unpaid_count, itemcount;
3140     int bcnt, ccnt, ucnt, xcnt, ocnt;
3141     boolean billx = *u.ushops && doinvbill(0);
3142     menu_item *pick_list;
3143     boolean traditional = TRUE;
3144     const char *prompt = "What type of object do you want an inventory of?";
3145 
3146     if (!invent && !billx) {
3147         You("aren't carrying anything.");
3148         return 0;
3149     }
3150     unpaid_count = count_unpaid(invent);
3151     tally_BUCX(invent, FALSE, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
3152 
3153     if (flags.menu_style != MENU_TRADITIONAL) {
3154         if (flags.menu_style == MENU_FULL
3155             || flags.menu_style == MENU_PARTIAL) {
3156             traditional = FALSE;
3157             i = UNPAID_TYPES;
3158             if (billx)
3159                 i |= BILLED_TYPES;
3160             if (bcnt)
3161                 i |= BUC_BLESSED;
3162             if (ucnt)
3163                 i |= BUC_UNCURSED;
3164             if (ccnt)
3165                 i |= BUC_CURSED;
3166             if (xcnt)
3167                 i |= BUC_UNKNOWN;
3168             n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
3169             if (!n)
3170                 return 0;
3171             this_type = c = pick_list[0].item.a_int;
3172             free((genericptr_t) pick_list);
3173         }
3174     }
3175     if (traditional) {
3176         /* collect a list of classes of objects carried, for use as a prompt
3177          */
3178         types[0] = 0;
3179         class_count = collect_obj_classes(types, invent, FALSE,
3180                                           (boolean FDECL((*), (OBJ_P))) 0,
3181                                           &itemcount);
3182         if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
3183             types[class_count++] = ' ';
3184         if (unpaid_count)
3185             types[class_count++] = 'u';
3186         if (billx)
3187             types[class_count++] = 'x';
3188         if (bcnt)
3189             types[class_count++] = 'B';
3190         if (ucnt)
3191             types[class_count++] = 'U';
3192         if (ccnt)
3193             types[class_count++] = 'C';
3194         if (xcnt)
3195             types[class_count++] = 'X';
3196         types[class_count] = '\0';
3197         /* add everything not already included; user won't see these */
3198         extra_types = eos(types);
3199         *extra_types++ = '\033';
3200         if (!unpaid_count)
3201             *extra_types++ = 'u';
3202         if (!billx)
3203             *extra_types++ = 'x';
3204         if (!bcnt)
3205             *extra_types++ = 'B';
3206         if (!ucnt)
3207             *extra_types++ = 'U';
3208         if (!ccnt)
3209             *extra_types++ = 'C';
3210         if (!xcnt)
3211             *extra_types++ = 'X';
3212         *extra_types = '\0'; /* for index() */
3213         for (i = 0; i < MAXOCLASSES; i++)
3214             if (!index(types, def_oc_syms[i].sym)) {
3215                 *extra_types++ = def_oc_syms[i].sym;
3216                 *extra_types = '\0';
3217             }
3218 
3219         if (class_count > 1) {
3220             c = yn_function(prompt, types, '\0');
3221             savech(c);
3222             if (c == '\0') {
3223                 clear_nhwindow(WIN_MESSAGE);
3224                 return 0;
3225             }
3226         } else {
3227             /* only one thing to itemize */
3228             if (unpaid_count)
3229                 c = 'u';
3230             else if (billx)
3231                 c = 'x';
3232             else
3233                 c = types[0];
3234         }
3235     }
3236     if (c == 'x' || (c == 'X' && billx && !xcnt)) {
3237         if (billx)
3238             (void) doinvbill(1);
3239         else
3240             pline("No used-up objects%s.",
3241                   unpaid_count ? " on your shopping bill" : "");
3242         return 0;
3243     }
3244     if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) {
3245         if (unpaid_count)
3246             dounpaid();
3247         else
3248             You("are not carrying any unpaid objects.");
3249         return 0;
3250     }
3251     if (traditional) {
3252         if (index("BUCX", c))
3253             oclass = c; /* not a class but understood by this_type_only() */
3254         else
3255             oclass = def_char_to_objclass(c); /* change to object class */
3256 
3257         if (oclass == COIN_CLASS)
3258             return doprgold();
3259         if (index(types, c) > index(types, '\033')) {
3260             /* '> ESC' => hidden choice, something known not to be carried */
3261             const char *before = "", *after = "";
3262 
3263             switch (c) {
3264             case 'B':
3265                 before = "known to be blessed ";
3266                 break;
3267             case 'U':
3268                 before = "known to be uncursed ";
3269                 break;
3270             case 'C':
3271                 before = "known to be cursed ";
3272                 break;
3273             case 'X':
3274                 after = " whose blessed/uncursed/cursed status is unknown";
3275                 break; /* better phrasing is desirable */
3276             default:
3277                 /* 'c' is an object class, because we've already handled
3278                    all the non-class letters which were put into 'types[]';
3279                    could/should move object class names[] array from below
3280                    to somewhere above so that we can access it here (via
3281                    lcase(strcpy(classnamebuf, names[(int) c]))), but the
3282                    game-play value of doing so is low... */
3283                 before = "such ";
3284                 break;
3285             }
3286             You("have no %sobjects%s.", before, after);
3287             return 0;
3288         }
3289         this_type = oclass;
3290     }
3291     if (query_objlist((char *) 0, &invent,
3292                       ((flags.invlet_constant ? USE_INVLET : 0)
3293                        | INVORDER_SORT),
3294                       &pick_list, PICK_NONE, this_type_only) > 0)
3295         free((genericptr_t) pick_list);
3296     return 0;
3297 }
3298 
3299 /* return a string describing the dungeon feature at <x,y> if there
3300    is one worth mentioning at that location; otherwise null */
3301 const char *
dfeature_at(x,y,buf)3302 dfeature_at(x, y, buf)
3303 int x, y;
3304 char *buf;
3305 {
3306     struct rm *lev = &levl[x][y];
3307     int ltyp = lev->typ, cmap = -1;
3308     const char *dfeature = 0;
3309     static char altbuf[BUFSZ];
3310 
3311     if (IS_DOOR(ltyp)) {
3312         switch (lev->doormask) {
3313         case D_NODOOR:
3314             cmap = S_ndoor;
3315             break; /* "doorway" */
3316         case D_ISOPEN:
3317             cmap = S_vodoor;
3318             break; /* "open door" */
3319         case D_BROKEN:
3320             dfeature = "broken door";
3321             break;
3322         default:
3323             cmap = S_vcdoor;
3324             break; /* "closed door" */
3325         }
3326         /* override door description for open drawbridge */
3327         if (is_drawbridge_wall(x, y) >= 0)
3328             dfeature = "open drawbridge portcullis", cmap = -1;
3329     } else if (IS_FOUNTAIN(ltyp))
3330         cmap = S_fountain; /* "fountain" */
3331     else if (IS_THRONE(ltyp))
3332         cmap = S_throne; /* "opulent throne" */
3333     else if (is_lava(x, y))
3334         cmap = S_lava; /* "molten lava" */
3335     else if (is_ice(x, y))
3336         cmap = S_ice; /* "ice" */
3337     else if (is_pool(x, y))
3338         dfeature = "pool of water";
3339     else if (IS_SINK(ltyp))
3340         cmap = S_sink; /* "sink" */
3341     else if (IS_ALTAR(ltyp)) {
3342         Sprintf(altbuf, "%saltar to %s (%s)",
3343                 ((lev->altarmask & AM_SHRINE)
3344                  && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
3345                     ? "high "
3346                     : "",
3347                 a_gname(),
3348                 align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
3349         dfeature = altbuf;
3350     } else if ((x == xupstair && y == yupstair)
3351                || (x == sstairs.sx && y == sstairs.sy && sstairs.up))
3352         cmap = S_upstair; /* "staircase up" */
3353     else if ((x == xdnstair && y == ydnstair)
3354              || (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
3355         cmap = S_dnstair; /* "staircase down" */
3356     else if (x == xupladder && y == yupladder)
3357         cmap = S_upladder; /* "ladder up" */
3358     else if (x == xdnladder && y == ydnladder)
3359         cmap = S_dnladder; /* "ladder down" */
3360     else if (ltyp == DRAWBRIDGE_DOWN)
3361         cmap = S_vodbridge; /* "lowered drawbridge" */
3362     else if (ltyp == DBWALL)
3363         cmap = S_vcdbridge; /* "raised drawbridge" */
3364     else if (IS_GRAVE(ltyp))
3365         cmap = S_grave; /* "grave" */
3366     else if (ltyp == TREE)
3367         cmap = S_tree; /* "tree" */
3368     else if (ltyp == IRONBARS)
3369         dfeature = "set of iron bars";
3370 
3371     if (cmap >= 0)
3372         dfeature = defsyms[cmap].explanation;
3373     if (dfeature)
3374         Strcpy(buf, dfeature);
3375     return dfeature;
3376 }
3377 
3378 /* look at what is here; if there are many objects (pile_limit or more),
3379    don't show them unless obj_cnt is 0 */
3380 int
look_here(obj_cnt,picked_some)3381 look_here(obj_cnt, picked_some)
3382 int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */
3383 boolean picked_some;
3384 {
3385     struct obj *otmp;
3386     struct trap *trap;
3387     const char *verb = Blind ? "feel" : "see";
3388     const char *dfeature = (char *) 0;
3389     char fbuf[BUFSZ], fbuf2[BUFSZ];
3390     winid tmpwin;
3391     boolean skip_objects, felt_cockatrice = FALSE;
3392 
3393     /* default pile_limit is 5; a value of 0 means "never skip"
3394        (and 1 effectively forces "always skip") */
3395     skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
3396     if (u.uswallow && u.ustuck) {
3397         struct monst *mtmp = u.ustuck;
3398 
3399         /*
3400          * FIXME?
3401          *  Engulfer's inventory can include worn items (specific case is
3402          *  Juiblex being created with an amulet as random defensive item)
3403          *  which will be flagged as "(being worn)".  This code includes
3404          *  such a worn item under the header "Contents of <mon>'s stomach",
3405          *  a nifty trick for how/where to wear stuff.  The situation is
3406          *  rare enough to turn a blind eye.
3407          *
3408          *  3.6.3:  Pickup has been changed to decline to pick up a worn
3409          *  item from inside an engulfer, but if player tries, it just
3410          *  says "you can't" without giving a reason why (which would be
3411          *  something along the lines of "because it's worn on the outside
3412          *  so is unreachable from in here...").
3413          */
3414         Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
3415                 mbodypart(mtmp, STOMACH));
3416         /* Skip "Contents of " by using fbuf index 12 */
3417         You("%s to %s what is lying in %s.", Blind ? "try" : "look around",
3418             verb, &fbuf[12]);
3419         otmp = mtmp->minvent;
3420         if (otmp) {
3421             for (; otmp; otmp = otmp->nobj) {
3422                 /* If swallower is an animal, it should have become stone
3423                  * but... */
3424                 if (otmp->otyp == CORPSE)
3425                     feel_cockatrice(otmp, FALSE);
3426             }
3427             if (Blind)
3428                 Strcpy(fbuf, "You feel");
3429             Strcat(fbuf, ":");
3430             (void) display_minventory(mtmp, MINV_ALL | PICK_NONE, fbuf);
3431         } else {
3432             You("%s no objects here.", verb);
3433         }
3434         return !!Blind;
3435     }
3436     if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
3437         There("is %s here.",
3438               an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
3439 
3440     otmp = level.objects[u.ux][u.uy];
3441     dfeature = dfeature_at(u.ux, u.uy, fbuf2);
3442     if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
3443         dfeature = 0;
3444 
3445     if (Blind) {
3446         boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
3447 
3448         if (dfeature && !strncmp(dfeature, "altar ", 6)) {
3449             /* don't say "altar" twice, dfeature has more info */
3450             You("try to feel what is here.");
3451         } else {
3452             const char *where = (Blind && !can_reach_floor(TRUE))
3453                                     ? "lying beneath you"
3454                                     : "lying here on the ",
3455                        *onwhat = (Blind && !can_reach_floor(TRUE))
3456                                      ? ""
3457                                      : surface(u.ux, u.uy);
3458 
3459             You("try to feel what is %s%s.", drift ? "floating here" : where,
3460                 drift ? "" : onwhat);
3461         }
3462         if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy)))
3463             dfeature = 0; /* ice already identified */
3464         if (!can_reach_floor(TRUE)) {
3465             pline("But you can't reach it!");
3466             return 0;
3467         }
3468     }
3469 
3470     if (dfeature)
3471         Sprintf(fbuf, "There is %s here.", an(dfeature));
3472 
3473     if (!otmp || is_lava(u.ux, u.uy)
3474         || (is_pool(u.ux, u.uy) && !Underwater)) {
3475         if (dfeature)
3476             pline1(fbuf);
3477         read_engr_at(u.ux, u.uy); /* Eric Backus */
3478         if (!skip_objects && (Blind || !dfeature))
3479             You("%s no objects here.", verb);
3480         return !!Blind;
3481     }
3482     /* we know there is something here */
3483 
3484     if (skip_objects) {
3485         if (dfeature)
3486             pline1(fbuf);
3487         read_engr_at(u.ux, u.uy); /* Eric Backus */
3488         if (obj_cnt == 1 && otmp->quan == 1L)
3489             There("is %s object here.", picked_some ? "another" : "an");
3490         else
3491             There("are %s%s objects here.",
3492                   (obj_cnt < 5)
3493                       ? "a few"
3494                       : (obj_cnt < 10)
3495                           ? "several"
3496                           : "many",
3497                   picked_some ? " more" : "");
3498         for (; otmp; otmp = otmp->nexthere)
3499             if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
3500                 pline("%s %s%s.",
3501                       (obj_cnt > 1)
3502                           ? "Including"
3503                           : (otmp->quan > 1L)
3504                               ? "They're"
3505                               : "It's",
3506                       corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
3507                       poly_when_stoned(youmonst.data)
3508                           ? ""
3509                           : ", unfortunately");
3510                 feel_cockatrice(otmp, FALSE);
3511                 break;
3512             }
3513     } else if (!otmp->nexthere) {
3514         /* only one object */
3515         if (dfeature)
3516             pline1(fbuf);
3517         read_engr_at(u.ux, u.uy); /* Eric Backus */
3518         You("%s here %s.", verb, doname_with_price(otmp));
3519         iflags.last_msg = PLNMSG_ONE_ITEM_HERE;
3520         if (otmp->otyp == CORPSE)
3521             feel_cockatrice(otmp, FALSE);
3522     } else {
3523         char buf[BUFSZ];
3524 
3525         display_nhwindow(WIN_MESSAGE, FALSE);
3526         tmpwin = create_nhwindow(NHW_MENU);
3527         if (dfeature) {
3528             putstr(tmpwin, 0, fbuf);
3529             putstr(tmpwin, 0, "");
3530         }
3531         Sprintf(buf, "%s that %s here:",
3532                 picked_some ? "Other things" : "Things",
3533                 Blind ? "you feel" : "are");
3534         putstr(tmpwin, 0, buf);
3535         for (; otmp; otmp = otmp->nexthere) {
3536             if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
3537                 felt_cockatrice = TRUE;
3538                 Sprintf(buf, "%s...", doname(otmp));
3539                 putstr(tmpwin, 0, buf);
3540                 break;
3541             }
3542             putstr(tmpwin, 0, doname_with_price(otmp));
3543         }
3544         display_nhwindow(tmpwin, TRUE);
3545         destroy_nhwindow(tmpwin);
3546         if (felt_cockatrice)
3547             feel_cockatrice(otmp, FALSE);
3548         read_engr_at(u.ux, u.uy); /* Eric Backus */
3549     }
3550     return !!Blind;
3551 }
3552 
3553 /* the ':' command - explicitly look at what is here, including all objects */
3554 int
dolook()3555 dolook()
3556 {
3557     int res;
3558 
3559     /* don't let
3560        MSGTYPE={norep,noshow} "You see here"
3561        interfere with feedback from the look-here command */
3562     hide_unhide_msgtypes(TRUE, MSGTYP_MASK_REP_SHOW);
3563     res = look_here(0, FALSE);
3564     /* restore normal msgtype handling */
3565     hide_unhide_msgtypes(FALSE, MSGTYP_MASK_REP_SHOW);
3566     return res;
3567 }
3568 
3569 boolean
will_feel_cockatrice(otmp,force_touch)3570 will_feel_cockatrice(otmp, force_touch)
3571 struct obj *otmp;
3572 boolean force_touch;
3573 {
3574     if ((Blind || force_touch) && !uarmg && !Stone_resistance
3575         && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
3576         return TRUE;
3577     return FALSE;
3578 }
3579 
3580 void
feel_cockatrice(otmp,force_touch)3581 feel_cockatrice(otmp, force_touch)
3582 struct obj *otmp;
3583 boolean force_touch;
3584 {
3585     char kbuf[BUFSZ];
3586 
3587     if (will_feel_cockatrice(otmp, force_touch)) {
3588         /* "the <cockatrice> corpse" */
3589         Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
3590 
3591         if (poly_when_stoned(youmonst.data))
3592             You("touched %s with your bare %s.", kbuf,
3593                 makeplural(body_part(HAND)));
3594         else
3595             pline("Touching %s is a fatal mistake...", kbuf);
3596         /* normalize body shape here; hand, not body_part(HAND) */
3597         Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp));
3598         /* will call polymon() for the poly_when_stoned() case */
3599         instapetrify(kbuf);
3600     }
3601 }
3602 
3603 void
stackobj(obj)3604 stackobj(obj)
3605 struct obj *obj;
3606 {
3607     struct obj *otmp;
3608 
3609     for (otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
3610         if (otmp != obj && merged(&obj, &otmp))
3611             break;
3612     return;
3613 }
3614 
3615 /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
3616 boolean
mergable(otmp,obj)3617 mergable(otmp, obj)
3618 register struct obj *otmp, *obj;
3619 {
3620     int objnamelth = 0, otmpnamelth = 0;
3621 
3622     /* fail if already the same object, if different types, if either is
3623        explicitly marked to prevent merge, or if not mergable in general */
3624     if (obj == otmp || obj->otyp != otmp->otyp
3625         || obj->nomerge || otmp->nomerge || !objects[obj->otyp].oc_merge)
3626         return FALSE;
3627 
3628     /* coins of the same kind will always merge */
3629     if (obj->oclass == COIN_CLASS)
3630         return TRUE;
3631 
3632     if (obj->bypass != otmp->bypass
3633         || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed)
3634         return FALSE;
3635 
3636     if (obj->globby)
3637         return TRUE;
3638     /* Checks beyond this point either aren't applicable to globs
3639      * or don't inhibit their merger.
3640      */
3641 
3642     if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
3643         || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
3644         || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit)
3645         return FALSE;
3646 
3647     if (obj->oclass == FOOD_CLASS
3648         && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
3649         return FALSE;
3650 
3651     if (obj->dknown != otmp->dknown
3652         || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
3653         || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2
3654         || obj->greased != otmp->greased)
3655         return FALSE;
3656 
3657     if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
3658         && (obj->oerodeproof != otmp->oerodeproof
3659             || obj->rknown != otmp->rknown))
3660         return FALSE;
3661 
3662     if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
3663         if (obj->corpsenm != otmp->corpsenm)
3664             return FALSE;
3665     }
3666 
3667     /* hatching eggs don't merge; ditto for revivable corpses */
3668     if ((obj->otyp == EGG && (obj->timed || otmp->timed))
3669         || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM
3670             && is_reviver(&mons[otmp->corpsenm])))
3671         return FALSE;
3672 
3673     /* allow candle merging only if their ages are close */
3674     /* see begin_burn() for a reference for the magic "25" */
3675     if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
3676         return FALSE;
3677 
3678     /* burning potions of oil never merge */
3679     if (obj->otyp == POT_OIL && obj->lamplit)
3680         return FALSE;
3681 
3682     /* don't merge surcharged item with base-cost item */
3683     if (obj->unpaid && !same_price(obj, otmp))
3684         return FALSE;
3685 
3686     /* if they have names, make sure they're the same */
3687     objnamelth = strlen(safe_oname(obj));
3688     otmpnamelth = strlen(safe_oname(otmp));
3689     if ((objnamelth != otmpnamelth
3690          && ((objnamelth && otmpnamelth) || obj->otyp == CORPSE))
3691         || (objnamelth && otmpnamelth
3692             && strncmp(ONAME(obj), ONAME(otmp), objnamelth)))
3693         return FALSE;
3694 
3695     /* for the moment, any additional information is incompatible */
3696     if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || has_omonst(otmp)
3697         || has_omid(otmp) || has_olong(otmp))
3698         return FALSE;
3699 
3700     if (obj->oartifact != otmp->oartifact)
3701         return FALSE;
3702 
3703     if (obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) {
3704         return (boolean) objects[obj->otyp].oc_merge;
3705     } else
3706         return FALSE;
3707 }
3708 
3709 /* the '$' command */
3710 int
doprgold()3711 doprgold()
3712 {
3713     /* the messages used to refer to "carrying gold", but that didn't
3714        take containers into account */
3715     long umoney = money_cnt(invent);
3716 
3717     if (!umoney)
3718         Your("wallet is empty.");
3719     else
3720         Your("wallet contains %ld %s.", umoney, currency(umoney));
3721     shopper_financial_report();
3722     return 0;
3723 }
3724 
3725 /* the ')' command */
3726 int
doprwep()3727 doprwep()
3728 {
3729     if (!uwep) {
3730         You("are empty %s.", body_part(HANDED));
3731     } else {
3732         prinv((char *) 0, uwep, 0L);
3733         if (u.twoweap)
3734             prinv((char *) 0, uswapwep, 0L);
3735     }
3736     return 0;
3737 }
3738 
3739 /* caller is responsible for checking !wearing_armor() */
3740 STATIC_OVL void
noarmor(report_uskin)3741 noarmor(report_uskin)
3742 boolean report_uskin;
3743 {
3744     if (!uskin || !report_uskin) {
3745         You("are not wearing any armor.");
3746     } else {
3747         char *p, *uskinname, buf[BUFSZ];
3748 
3749         uskinname = strcpy(buf, simpleonames(uskin));
3750         /* shorten "set of <color> dragon scales" to "<color> scales"
3751            and "<color> dragon scale mail" to "<color> scale mail" */
3752         if (!strncmpi(uskinname, "set of ", 7))
3753             uskinname += 7;
3754         if ((p = strstri(uskinname, " dragon ")) != 0)
3755             while ((p[1] = p[8]) != '\0')
3756                 ++p;
3757 
3758         You("are not wearing armor but have %s embedded in your skin.",
3759             uskinname);
3760     }
3761 }
3762 
3763 /* the '[' command */
3764 int
doprarm()3765 doprarm()
3766 {
3767     char lets[8];
3768     register int ct = 0;
3769     /*
3770      * Note:  players sometimes get here by pressing a function key which
3771      * transmits ''ESC [ <something>'' rather than by pressing '[';
3772      * there's nothing we can--or should-do about that here.
3773      */
3774 
3775     if (!wearing_armor()) {
3776         noarmor(TRUE);
3777     } else {
3778         if (uarmu)
3779             lets[ct++] = obj_to_let(uarmu);
3780         if (uarm)
3781             lets[ct++] = obj_to_let(uarm);
3782         if (uarmc)
3783             lets[ct++] = obj_to_let(uarmc);
3784         if (uarmh)
3785             lets[ct++] = obj_to_let(uarmh);
3786         if (uarms)
3787             lets[ct++] = obj_to_let(uarms);
3788         if (uarmg)
3789             lets[ct++] = obj_to_let(uarmg);
3790         if (uarmf)
3791             lets[ct++] = obj_to_let(uarmf);
3792         lets[ct] = 0;
3793         (void) display_inventory(lets, FALSE);
3794     }
3795     return 0;
3796 }
3797 
3798 /* the '=' command */
3799 int
doprring()3800 doprring()
3801 {
3802     if (!uleft && !uright)
3803         You("are not wearing any rings.");
3804     else {
3805         char lets[3];
3806         register int ct = 0;
3807 
3808         if (uleft)
3809             lets[ct++] = obj_to_let(uleft);
3810         if (uright)
3811             lets[ct++] = obj_to_let(uright);
3812         lets[ct] = 0;
3813         (void) display_inventory(lets, FALSE);
3814     }
3815     return 0;
3816 }
3817 
3818 /* the '"' command */
3819 int
dopramulet()3820 dopramulet()
3821 {
3822     if (!uamul)
3823         You("are not wearing an amulet.");
3824     else
3825         prinv((char *) 0, uamul, 0L);
3826     return 0;
3827 }
3828 
3829 STATIC_OVL boolean
tool_in_use(obj)3830 tool_in_use(obj)
3831 struct obj *obj;
3832 {
3833     if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L)
3834         return TRUE;
3835     if (obj->oclass != TOOL_CLASS)
3836         return FALSE;
3837     return (boolean) (obj == uwep || obj->lamplit
3838                       || (obj->otyp == LEASH && obj->leashmon));
3839 }
3840 
3841 /* the '(' command */
3842 int
doprtool()3843 doprtool()
3844 {
3845     struct obj *otmp;
3846     int ct = 0;
3847     char lets[52 + 1];
3848 
3849     for (otmp = invent; otmp; otmp = otmp->nobj)
3850         if (tool_in_use(otmp))
3851             lets[ct++] = obj_to_let(otmp);
3852     lets[ct] = '\0';
3853     if (!ct)
3854         You("are not using any tools.");
3855     else
3856         (void) display_inventory(lets, FALSE);
3857     return 0;
3858 }
3859 
3860 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3861    show inventory of all currently wielded, worn, or used objects */
3862 int
doprinuse()3863 doprinuse()
3864 {
3865     struct obj *otmp;
3866     int ct = 0;
3867     char lets[52 + 1];
3868 
3869     for (otmp = invent; otmp; otmp = otmp->nobj)
3870         if (is_worn(otmp) || tool_in_use(otmp))
3871             lets[ct++] = obj_to_let(otmp);
3872     lets[ct] = '\0';
3873     if (!ct)
3874         You("are not wearing or wielding anything.");
3875     else
3876         (void) display_inventory(lets, FALSE);
3877     return 0;
3878 }
3879 
3880 /*
3881  * uses up an object that's on the floor, charging for it as necessary
3882  */
3883 void
useupf(obj,numused)3884 useupf(obj, numused)
3885 register struct obj *obj;
3886 long numused;
3887 {
3888     register struct obj *otmp;
3889     boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
3890 
3891     /* burn_floor_objects() keeps an object pointer that it tries to
3892      * useupf() multiple times, so obj must survive if plural */
3893     if (obj->quan > numused)
3894         otmp = splitobj(obj, numused);
3895     else
3896         otmp = obj;
3897     if (costly_spot(otmp->ox, otmp->oy)) {
3898         if (index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
3899             addtobill(otmp, FALSE, FALSE, FALSE);
3900         else
3901             (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
3902     }
3903     delobj(otmp);
3904     if (at_u && u.uundetected && hides_under(youmonst.data))
3905         (void) hideunder(&youmonst);
3906 }
3907 
3908 /*
3909  * Conversion from a class to a string for printing.
3910  * This must match the object class order.
3911  */
3912 STATIC_VAR NEARDATA const char *names[] = {
3913     0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
3914     "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
3915     "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
3916 };
3917 STATIC_VAR NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
3918 STATIC_VAR NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
3919 
3920 STATIC_VAR NEARDATA char *invbuf = (char *) 0;
3921 STATIC_VAR NEARDATA unsigned invbufsiz = 0;
3922 
3923 char *
let_to_name(let,unpaid,showsym)3924 let_to_name(let, unpaid, showsym)
3925 char let;
3926 boolean unpaid, showsym;
3927 {
3928     const char *ocsymfmt = "  ('%c')";
3929     const int invbuf_sympadding = 8; /* arbitrary */
3930     const char *class_name;
3931     const char *pos;
3932     int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
3933     unsigned len;
3934 
3935     if (oclass)
3936         class_name = names[oclass];
3937     else if ((pos = index(oth_symbols, let)) != 0)
3938         class_name = oth_names[pos - oth_symbols];
3939     else
3940         class_name = names[0];
3941 
3942     len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "")
3943           + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0);
3944     if (len > invbufsiz) {
3945         if (invbuf)
3946             free((genericptr_t) invbuf);
3947         invbufsiz = len + 10; /* add slop to reduce incremental realloc */
3948         invbuf = (char *) alloc(invbufsiz);
3949     }
3950     if (unpaid)
3951         Strcat(strcpy(invbuf, "Unpaid "), class_name);
3952     else
3953         Strcpy(invbuf, class_name);
3954     if ((oclass != 0) && showsym) {
3955         char *bp = eos(invbuf);
3956         int mlen = invbuf_sympadding - strlen(class_name);
3957         while (--mlen > 0) {
3958             *bp = ' ';
3959             bp++;
3960         }
3961         *bp = '\0';
3962         Sprintf(eos(invbuf), ocsymfmt, def_oc_syms[oclass].sym);
3963     }
3964     return invbuf;
3965 }
3966 
3967 /* release the static buffer used by let_to_name() */
3968 void
free_invbuf()3969 free_invbuf()
3970 {
3971     if (invbuf)
3972         free((genericptr_t) invbuf), invbuf = (char *) 0;
3973     invbufsiz = 0;
3974 }
3975 
3976 /* give consecutive letters to every item in inventory (for !fixinv mode);
3977    gold is always forced to '$' slot at head of list */
3978 void
reassign()3979 reassign()
3980 {
3981     int i;
3982     struct obj *obj, *prevobj, *goldobj;
3983 
3984     /* first, remove [first instance of] gold from invent, if present */
3985     prevobj = goldobj = 0;
3986     for (obj = invent; obj; prevobj = obj, obj = obj->nobj)
3987         if (obj->oclass == COIN_CLASS) {
3988             goldobj = obj;
3989             if (prevobj)
3990                 prevobj->nobj = goldobj->nobj;
3991             else
3992                 invent = goldobj->nobj;
3993             break;
3994         }
3995     /* second, re-letter the rest of the list */
3996     for (obj = invent, i = 0; obj; obj = obj->nobj, i++)
3997         obj->invlet =
3998             (i < 26) ? ('a' + i) : (i < 52) ? ('A' + i - 26) : NOINVSYM;
3999     /* third, assign gold the "letter" '$' and re-insert it at head */
4000     if (goldobj) {
4001         goldobj->invlet = GOLD_SYM;
4002         goldobj->nobj = invent;
4003         invent = goldobj;
4004     }
4005     if (i >= 52)
4006         i = 52 - 1;
4007     lastinvnr = i;
4008 }
4009 
4010 /* #adjust command
4011  *
4012  *      User specifies a 'from' slot for inventory stack to move,
4013  *      then a 'to' slot for its destination.  Open slots and those
4014  *      filled by compatible stacks are listed as likely candidates
4015  *      but user can pick any inventory letter (including 'from').
4016  *
4017  *  to == from, 'from' has a name
4018  *      All compatible items (same name or no name) are gathered
4019  *      into the 'from' stack.  No count is allowed.
4020  *  to == from, 'from' does not have a name
4021  *      All compatible items without a name are gathered into the
4022  *      'from' stack.  No count is allowed.  Compatible stacks with
4023  *      names are left as-is.
4024  *  to != from, no count
4025  *      Move 'from' to 'to'.  If 'to' is not empty, merge 'from'
4026  *      into it if possible, otherwise swap it with the 'from' slot.
4027  *  to != from, count given
4028  *      If the user specifies a count when choosing the 'from' slot,
4029  *      and that count is less than the full size of the stack,
4030  *      then the stack will be split.  The 'count' portion is moved
4031  *      to the destination, and the only candidate for merging with
4032  *      it is the stack already at the 'to' slot, if any.  When the
4033  *      destination is non-empty but won't merge, whatever is there
4034  *      will be moved to an open slot; if there isn't any open slot
4035  *      available, the adjustment attempt fails.
4036  *
4037  *      To minimize merging for 'from == to', unnamed stacks will
4038  *      merge with named 'from' but named ones won't merge with
4039  *      unnamed 'from'.  Otherwise attempting to collect all unnamed
4040  *      stacks would lump the first compatible named stack with them
4041  *      and give them its name.
4042  *
4043  *      To maximize merging for 'from != to', compatible stacks will
4044  *      merge when either lacks a name (or they already have the same
4045  *      name).  When no count is given and one stack has a name and
4046  *      the other doesn't, the merged result will have that name.
4047  *      However, when splitting results in a merger, the name of the
4048  *      destination overrides that of the source, even if destination
4049  *      is unnamed and source is named.
4050  */
4051 int
doorganize()4052 doorganize() /* inventory organizer by Del Lamb */
4053 {
4054     struct obj *obj, *otmp, *splitting, *bumped;
4055     int ix, cur, trycnt, goldstacks;
4056     char let;
4057 #define GOLD_INDX   0
4058 #define GOLD_OFFSET 1
4059 #define OVRFLW_INDX (GOLD_OFFSET + 52) /* past gold and 2*26 letters */
4060     char lets[1 + 52 + 1 + 1]; /* room for '$a-zA-Z#\0' */
4061     char qbuf[QBUFSZ];
4062     char allowall[4]; /* { ALLOW_COUNT, ALL_CLASSES, 0, 0 } */
4063     char *objname, *otmpname;
4064     const char *adj_type;
4065     boolean ever_mind = FALSE, collect;
4066 
4067     /* when no invent, or just gold in '$' slot, there's nothing to adjust */
4068     if (!invent || (invent->oclass == COIN_CLASS
4069                     && invent->invlet == GOLD_SYM && !invent->nobj)) {
4070         You("aren't carrying anything %s.",
4071             !invent ? "to adjust" : "adjustable");
4072         return 0;
4073     }
4074 
4075     if (!flags.invlet_constant)
4076         reassign();
4077     /* get object the user wants to organize (the 'from' slot) */
4078     allowall[0] = ALLOW_COUNT;
4079     allowall[1] = ALL_CLASSES;
4080     allowall[2] = '\0';
4081     for (goldstacks = 0, otmp = invent; otmp; otmp = otmp->nobj) {
4082         /* gold should never end up in a letter slot, nor should two '$'
4083            slots occur, but if they ever do, allow #adjust to handle them
4084            (in the past, things like this have happened, usually due to
4085            bknown being erroneously set on one stack, clear on another;
4086            object merger isn't fooled by that anymore) */
4087         if (otmp->oclass == COIN_CLASS
4088             && (otmp->invlet != GOLD_SYM || ++goldstacks > 1)) {
4089             allowall[1] = COIN_CLASS;
4090             allowall[2] = ALL_CLASSES;
4091             allowall[3] = '\0';
4092             break;
4093         }
4094     }
4095     if (!(obj = getobj(allowall, "adjust")))
4096         return 0;
4097 
4098     /* figure out whether user gave a split count to getobj() */
4099     splitting = bumped = 0;
4100     for (otmp = invent; otmp; otmp = otmp->nobj)
4101         if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
4102             if (otmp->invlet == obj->invlet)
4103                 splitting = otmp;
4104             break;
4105         }
4106 
4107     /* initialize the list with all lower and upper case letters */
4108     lets[GOLD_INDX] = (obj->oclass == COIN_CLASS) ? GOLD_SYM : ' ';
4109     for (ix = GOLD_OFFSET, let = 'a'; let <= 'z';)
4110         lets[ix++] = let++;
4111     for (let = 'A'; let <= 'Z';)
4112         lets[ix++] = let++;
4113     lets[OVRFLW_INDX] = ' ';
4114     lets[sizeof lets - 1] = '\0';
4115     /* for floating inv letters, truncate list after the first open slot */
4116     if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52)
4117         lets[ix + (splitting ? 0 : 1)] = '\0';
4118 
4119     /* blank out all the letters currently in use in the inventory
4120        except those that will be merged with the selected object */
4121     for (otmp = invent; otmp; otmp = otmp->nobj)
4122         if (otmp != obj && !mergable(otmp, obj)) {
4123             let = otmp->invlet;
4124             if (let >= 'a' && let <= 'z')
4125                 lets[GOLD_OFFSET + let - 'a'] = ' ';
4126             else if (let >= 'A' && let <= 'Z')
4127                 lets[GOLD_OFFSET + let - 'A' + 26] = ' ';
4128             /* overflow defaults to off, but it we find a stack using that
4129                slot, switch to on -- the opposite of normal invlet handling */
4130             else if (let == NOINVSYM)
4131                 lets[OVRFLW_INDX] = NOINVSYM;
4132         }
4133 
4134     /* compact the list by removing all the blanks */
4135     for (ix = cur = 0; lets[ix]; ix++)
4136         if (lets[ix] != ' ' && cur++ < ix)
4137             lets[cur - 1] = lets[ix];
4138     lets[cur] = '\0';
4139     /* and by dashing runs of letters */
4140     if (cur > 5)
4141         compactify(lets);
4142 
4143     /* get 'to' slot to use as destination */
4144     Sprintf(qbuf, "Adjust letter to what [%s]%s?", lets,
4145             invent ? " (? see used letters)" : "");
4146     for (trycnt = 1; ; ++trycnt) {
4147         let = yn_function(qbuf, (char *) 0, '\0');
4148         if (let == '?' || let == '*') {
4149             let = display_used_invlets(splitting ? obj->invlet : 0);
4150             if (!let)
4151                 continue;
4152             if (let == '\033')
4153                 goto noadjust;
4154         }
4155         if (index(quitchars, let)
4156             /* adjusting to same slot is meaningful since all
4157                compatible stacks get collected along the way,
4158                but splitting to same slot is not */
4159             || (splitting && let == obj->invlet)) {
4160  noadjust:
4161             if (splitting)
4162                 (void) merged(&splitting, &obj);
4163             if (!ever_mind)
4164                 pline1(Never_mind);
4165             return 0;
4166         } else if (let == GOLD_SYM && obj->oclass != COIN_CLASS) {
4167             pline("Only gold coins may be moved into the '%c' slot.",
4168                   GOLD_SYM);
4169             ever_mind = TRUE;
4170             goto noadjust;
4171         }
4172         /* letter() classifies '@' as one; compactify() can put '-' in lets;
4173            the only thing of interest that index() might find is '$' or '#'
4174            since letter() catches everything else that we put into lets[] */
4175         if ((letter(let) && let != '@') || (index(lets, let) && let != '-'))
4176             break; /* got one */
4177         if (trycnt == 5)
4178             goto noadjust;
4179         pline("Select an inventory slot letter."); /* else try again */
4180     }
4181 
4182     collect = (let == obj->invlet);
4183     /* change the inventory and print the resulting item */
4184     adj_type = collect ? "Collecting" : !splitting ? "Moving:" : "Splitting:";
4185 
4186     /*
4187      * don't use freeinv/addinv to avoid double-touching artifacts,
4188      * dousing lamps, losing luck, cursing loadstone, etc.
4189      */
4190     extract_nobj(obj, &invent);
4191 
4192     for (otmp = invent; otmp;) {
4193         /* it's tempting to pull this outside the loop, but merged() could
4194            free ONAME(obj) [via obfree()] and replace it with ONAME(otmp) */
4195         objname = has_oname(obj) ? ONAME(obj) : (char *) 0;
4196 
4197         if (collect) {
4198             /* Collecting: #adjust an inventory stack into its same slot;
4199                keep it there and merge other compatible stacks into it.
4200                Traditional inventory behavior is to merge unnamed stacks
4201                with compatible named ones; we only want that if it is
4202                the 'from' stack (obj) with a name and candidate (otmp)
4203                without one, not unnamed 'from' with named candidate. */
4204             otmpname = has_oname(otmp) ? ONAME(otmp) : (char *) 0;
4205             if ((!otmpname || (objname && !strcmp(objname, otmpname)))
4206                 && merged(&otmp, &obj)) {
4207                 adj_type = "Merging:";
4208                 obj = otmp;
4209                 otmp = otmp->nobj;
4210                 extract_nobj(obj, &invent);
4211                 continue; /* otmp has already been updated */
4212             }
4213         } else if (otmp->invlet == let) {
4214             /* Moving or splitting: don't merge extra compatible stacks.
4215                Found 'otmp' in destination slot; merge if compatible,
4216                otherwise bump whatever is there to an open slot. */
4217             if (!splitting) {
4218                 adj_type = "Swapping:";
4219                 otmp->invlet = obj->invlet;
4220             } else {
4221                 /* strip 'from' name if it has one */
4222                 if (objname && !obj->oartifact)
4223                     ONAME(obj) = (char *) 0;
4224                 if (!mergable(otmp, obj)) {
4225                     /* won't merge; put 'from' name back */
4226                     if (objname)
4227                         ONAME(obj) = objname;
4228                 } else {
4229                     /* will merge; discard 'from' name */
4230                     if (objname)
4231                         free((genericptr_t) objname), objname = 0;
4232                 }
4233 
4234                 if (merged(&otmp, &obj)) {
4235                     adj_type = "Splitting and merging:";
4236                     obj = otmp;
4237                     extract_nobj(obj, &invent);
4238                 } else if (inv_cnt(FALSE) >= 52) {
4239                     (void) merged(&splitting, &obj); /* undo split */
4240                     /* "knapsack cannot accommodate any more items" */
4241                     Your("pack is too full.");
4242                     return 0;
4243                 } else {
4244                     bumped = otmp;
4245                     extract_nobj(bumped, &invent);
4246                 }
4247             } /* moving vs splitting */
4248             break; /* not collecting and found 'to' slot */
4249         } /* collect */
4250         otmp = otmp->nobj;
4251     }
4252 
4253     /* inline addinv; insert loose object at beginning of inventory */
4254     obj->invlet = let;
4255     obj->nobj = invent;
4256     obj->where = OBJ_INVENT;
4257     invent = obj;
4258     reorder_invent();
4259     if (bumped) {
4260         /* splitting the 'from' stack is causing an incompatible
4261            stack in the 'to' slot to be moved into an open one;
4262            we need to do another inline insertion to inventory */
4263         assigninvlet(bumped);
4264         bumped->nobj = invent;
4265         bumped->where = OBJ_INVENT;
4266         invent = bumped;
4267         reorder_invent();
4268     }
4269 
4270     /* messages deferred until inventory has been fully reestablished */
4271     prinv(adj_type, obj, 0L);
4272     if (bumped)
4273         prinv("Moving:", bumped, 0L);
4274     if (splitting)
4275         clear_splitobjs(); /* reset splitobj context */
4276     update_inventory();
4277     return 0;
4278 }
4279 
4280 /* common to display_minventory and display_cinventory */
4281 STATIC_OVL void
invdisp_nothing(hdr,txt)4282 invdisp_nothing(hdr, txt)
4283 const char *hdr, *txt;
4284 {
4285     winid win;
4286     anything any;
4287     menu_item *selected;
4288 
4289     any = zeroany;
4290     win = create_nhwindow(NHW_MENU);
4291     start_menu(win);
4292     add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr,
4293              MENU_UNSELECTED);
4294     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
4295     add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
4296     end_menu(win, (char *) 0);
4297     if (select_menu(win, PICK_NONE, &selected) > 0)
4298         free((genericptr_t) selected);
4299     destroy_nhwindow(win);
4300     return;
4301 }
4302 
4303 /* query_objlist callback: return things that are worn or wielded */
4304 STATIC_OVL boolean
worn_wield_only(obj)4305 worn_wield_only(obj)
4306 struct obj *obj;
4307 {
4308 #if 1
4309     /* check for things that *are* worn or wielded (only used for monsters,
4310        so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
4311     return (boolean) (obj->owornmask != 0L);
4312 #else
4313     /* this used to check for things that *might* be worn or wielded,
4314        but that's not particularly interesting */
4315     if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING)
4316         return TRUE;
4317     return (boolean) (obj->oclass == WEAPON_CLASS
4318                       || obj->oclass == ARMOR_CLASS
4319                       || obj->oclass == AMULET_CLASS
4320                       || obj->oclass == RING_CLASS);
4321 #endif
4322 }
4323 
4324 /*
4325  * Display a monster's inventory.
4326  * Returns a pointer to the object from the monster's inventory selected
4327  * or NULL if nothing was selected.
4328  *
4329  * By default, only worn and wielded items are displayed.  The caller
4330  * can pick one.  Modifier flags are:
4331  *
4332  *      PICK_NONE, PICK_ONE - standard menu control
4333  *      PICK_ANY            - allowed, but we only return a single object
4334  *      MINV_NOLET          - nothing selectable
4335  *      MINV_ALL            - display all inventory
4336  */
4337 struct obj *
display_minventory(mon,dflags,title)4338 display_minventory(mon, dflags, title)
4339 register struct monst *mon;
4340 int dflags;
4341 char *title;
4342 {
4343     struct obj *ret;
4344     char tmp[QBUFSZ];
4345     int n;
4346     menu_item *selected = 0;
4347     int do_all = (dflags & MINV_ALL) != 0,
4348         incl_hero = (do_all && u.uswallow && mon == u.ustuck),
4349         have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero),
4350         pickings = (dflags & MINV_PICKMASK);
4351 
4352     Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
4353             do_all ? "possessions" : "armament");
4354 
4355     if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) {
4356         /* Fool the 'weapon in hand' routine into
4357          * displaying 'weapon in claw', etc. properly.
4358          */
4359         youmonst.data = mon->data;
4360         /* in case inside a shop, don't append "for sale" prices */
4361         iflags.suppress_price++;
4362 
4363         n = query_objlist(title ? title : tmp, &(mon->minvent),
4364                           (INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)),
4365                           &selected, pickings,
4366                           do_all ? allow_all : worn_wield_only);
4367 
4368         iflags.suppress_price--;
4369         /* was 'set_uasmon();' but that potentially has side-effects */
4370         youmonst.data = &mons[u.umonnum]; /* most basic part of set_uasmon */
4371     } else {
4372         invdisp_nothing(title ? title : tmp, "(none)");
4373         n = 0;
4374     }
4375 
4376     if (n > 0) {
4377         ret = selected[0].item.a_obj;
4378         free((genericptr_t) selected);
4379     } else
4380         ret = (struct obj *) 0;
4381     return ret;
4382 }
4383 
4384 /*
4385  * Display the contents of a container in inventory style.
4386  * Currently, this is only used for statues, via wand of probing.
4387  */
4388 struct obj *
display_cinventory(obj)4389 display_cinventory(obj)
4390 register struct obj *obj;
4391 {
4392     struct obj *ret;
4393     char qbuf[QBUFSZ];
4394     int n;
4395     menu_item *selected = 0;
4396 
4397     (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
4398                      "that");
4399 
4400     if (obj->cobj) {
4401         n = query_objlist(qbuf, &(obj->cobj), INVORDER_SORT,
4402                           &selected, PICK_NONE, allow_all);
4403     } else {
4404         invdisp_nothing(qbuf, "(empty)");
4405         n = 0;
4406     }
4407     if (n > 0) {
4408         ret = selected[0].item.a_obj;
4409         free((genericptr_t) selected);
4410     } else
4411         ret = (struct obj *) 0;
4412     obj->cknown = 1;
4413     return ret;
4414 }
4415 
4416 /* query objlist callback: return TRUE if obj is at given location */
4417 static coord only;
4418 
4419 STATIC_OVL boolean
only_here(obj)4420 only_here(obj)
4421 struct obj *obj;
4422 {
4423     return (obj->ox == only.x && obj->oy == only.y);
4424 }
4425 
4426 /*
4427  * Display a list of buried items in inventory style.  Return a non-zero
4428  * value if there were items at that spot.
4429  *
4430  * Currently, this is only used with a wand of probing zapped downwards.
4431  */
4432 int
display_binventory(x,y,as_if_seen)4433 display_binventory(x, y, as_if_seen)
4434 int x, y;
4435 boolean as_if_seen;
4436 {
4437     struct obj *obj;
4438     menu_item *selected = 0;
4439     int n;
4440 
4441     /* count # of objects here */
4442     for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
4443         if (obj->ox == x && obj->oy == y) {
4444             if (as_if_seen)
4445                 obj->dknown = 1;
4446             n++;
4447         }
4448 
4449     if (n) {
4450         only.x = x;
4451         only.y = y;
4452         if (query_objlist("Things that are buried here:",
4453                           &level.buriedobjlist, INVORDER_SORT,
4454                           &selected, PICK_NONE, only_here) > 0)
4455             free((genericptr_t) selected);
4456         only.x = only.y = 0;
4457     }
4458     return n;
4459 }
4460 
4461 /*invent.c*/
4462