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