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