1 /* NetHack 3.6 invent.c $NHDT-Date: 1447576348 2015/11/15 08:32:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.179 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
8 #define CONTAINED_SYM '>' /* designator for inside a container */
10 STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (struct obj *, struct obj *));
11 STATIC_DCL void NDECL(reorder_invent);
12 STATIC_DCL boolean FDECL(mergable, (struct obj *, struct obj *));
13 STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
14 STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *));
15 STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
16 STATIC_DCL boolean FDECL(only_here, (struct obj *));
17 STATIC_DCL void FDECL(compactify, (char *));
18 STATIC_DCL boolean FDECL(splittable, (struct obj *));
19 STATIC_DCL boolean FDECL(taking_off, (const char *));
20 STATIC_DCL boolean FDECL(putting_on, (const char *));
21 STATIC_PTR int FDECL(ckunpaid, (struct obj *));
22 STATIC_PTR int FDECL(ckvalidcat, (struct obj *));
23 STATIC_PTR char *FDECL(safeq_xprname, (struct obj *));
24 STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
25 STATIC_DCL char FDECL(display_pickinv, (const char *, BOOLEAN_P, long *));
26 STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
27 STATIC_DCL void FDECL(tally_BUCX,
28 (struct obj *, int *, int *, int *, int *, int *));
29 STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
30 STATIC_DCL void NDECL(dounpaid);
31 STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
32 STATIC_DCL void FDECL(menu_identify, (int));
33 STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
34 STATIC_DCL char FDECL(obj_to_let, (struct obj *));
36 static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
38 /* wizards can wish for venom, which will become an invisible inventory
39 * item without this. putting it in inv_order would mean venom would
40 * suddenly become a choice for all the inventory-class commands, which
41 * would probably cause mass confusion. the test for inventory venom
42 * is only WIZARD and not wizard because the wizard can leave venom lying
43 * around on a bones level for normal players to find. [Note to the
44 * confused: 'WIZARD' used to be a compile-time conditional so this was
45 * guarded by #ifdef WIZARD/.../#endif.]
47 static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
49 STATIC_OVL int CFDECLSPEC
50 sortloot_cmp(obj1, obj2)
57 /* Sort object names in lexicographical order, ignoring quantity. */
58 int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2));
64 /* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown
67 ? (obj1->blessed << 2)
68 + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed
71 ? (obj2->blessed << 2)
72 + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed
75 return val2 - val1; /* Because bigger is better. */
78 /* Sort by greasing. This will put the objects in degreasing order. */
82 return val2 - val1; /* Because bigger is better. */
85 /* Sort by erosion. The effective amount is what matters. */
86 val1 = greatest_erosion(obj1);
87 val2 = greatest_erosion(obj2);
89 return val1 - val2; /* Because bigger is WORSE. */
92 /* Sort by erodeproofing. Map known-invulnerable to 1, and both
93 * known-vulnerable and unknown-vulnerability to 0, because that's how
94 * they're displayed. */
95 val1 = obj1->rknown && obj1->oerodeproof;
96 val2 = obj2->rknown && obj2->oerodeproof;
98 return val2 - val1; /* Because bigger is better. */
101 /* Sort by enchantment. Map unknown to -1000, which is comfortably below
102 * the range of ->spe. */
103 val1 = obj1->known ? obj1->spe : -1000;
104 val2 = obj2->known ? obj2->spe : -1000;
106 return val2 - val1; /* Because bigger is better. */
109 /* They're identical, as far as we're concerned,
110 but we want to force a determistic order between them. */
111 return (obj1->o_id > obj2->o_id) ? 1 : -1;
118 return (struct obj **) alloc(n * sizeof(struct obj *));
122 objarr_set(otmp, idx, oarray, dosort)
130 for (j = idx; j; j--) {
131 if (sortloot_cmp(otmp, oarray[j - 1]) > 0)
133 oarray[j] = oarray[j - 1];
143 register struct obj *otmp;
147 register struct obj *obj;
149 /* there should be at most one of these in inventory... */
150 if (otmp->oclass == COIN_CLASS) {
151 otmp->invlet = GOLD_SYM;
155 for (i = 0; i < 52; i++)
157 for (obj = invent; obj; obj = obj->nobj)
160 if ('a' <= i && i <= 'z')
161 inuse[i - 'a'] = TRUE;
162 else if ('A' <= i && i <= 'Z')
163 inuse[i - 'A' + 26] = TRUE;
164 if (i == otmp->invlet)
167 if ((i = otmp->invlet)
168 && (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
170 for (i = lastinvnr + 1; i != lastinvnr; i++) {
179 (inuse[i] ? NOINVSYM : (i < 26) ? ('a' + i) : ('A' + i - 26));
183 /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
184 #define inv_rank(o) ((o)->invlet ^ 040)
186 /* sort the inventory; used by addinv() and doorganize() */
190 struct obj *otmp, *prev, *next;
191 boolean need_more_sorting;
195 * We expect at most one item to be out of order, so this
196 * isn't nearly as inefficient as it may first appear.
198 need_more_sorting = FALSE;
199 for (otmp = invent, prev = 0; otmp;) {
201 if (next && inv_rank(next) < inv_rank(otmp)) {
202 need_more_sorting = TRUE;
207 otmp->nobj = next->nobj;
215 } while (need_more_sorting);
220 /* scan a list of objects to see whether another object will merge with
221 one of them; used in pickup.c when all 52 inventory slots are in use,
222 to figure out whether another object could still be picked up */
224 merge_choice(objlist, obj)
225 struct obj *objlist, *obj;
230 if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */
231 return (struct obj *) 0;
232 /* if this is an item on the shop floor, the attributes it will
233 have when carried are different from what they are now; prevent
234 that from eliciting an incorrect result from mergable() */
235 save_nocharge = obj->no_charge;
236 if (objlist == invent && obj->where == OBJ_FLOOR
237 && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
240 /* A billable object won't have its `unpaid' bit set, so would
241 erroneously seem to be a candidate to merge with a similar
242 ordinary object. That's no good, because once it's really
243 picked up, it won't merge after all. It might merge with
244 another unpaid object, but we can't check that here (depends
245 too much upon shk's bill) and if it doesn't merge it would
246 end up in the '#' overflow inventory slot, so reject it now. */
247 else if (inhishop(shkp))
248 return (struct obj *) 0;
251 if (mergable(objlist, obj))
253 objlist = objlist->nobj;
255 obj->no_charge = save_nocharge;
259 /* merge obj with otmp and delete obj if types agree */
262 struct obj **potmp, **pobj;
264 register struct obj *otmp = *potmp, *obj = *pobj;
266 if (mergable(otmp, obj)) {
267 /* Approximate age: we do it this way because if we were to
268 * do it "accurately" (merge only when ages are identical)
269 * we'd wind up never merging any corpses.
270 * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
272 * Don't do the age manipulation if lit. We would need
273 * to stop the burn on both items, then merge the age,
274 * then restart the burn.
277 otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
278 / (otmp->quan + obj->quan);
280 otmp->quan += obj->quan;
281 /* temporary special case for gold objects!!!! */
282 if (otmp->oclass == COIN_CLASS)
283 otmp->owt = weight(otmp);
284 /* and puddings!!!1!!one! */
285 else if (!Is_pudding(otmp))
286 otmp->owt += obj->owt;
287 if (!has_oname(otmp) && has_oname(obj))
288 otmp = *potmp = oname(otmp, ONAME(obj));
289 obj_extract_self(obj);
291 /* really should merge the timeouts */
293 obj_merge_light_sources(obj, otmp);
295 obj_stop_timers(obj); /* follows lights */
297 /* fixup for `#adjust' merging wielded darts, daggers, &c */
298 if (obj->owornmask && carried(otmp)) {
299 long wmask = otmp->owornmask | obj->owornmask;
301 /* Both the items might be worn in competing slots;
302 merger preference (regardless of which is which):
303 primary weapon + alternate weapon -> primary weapon;
304 primary weapon + quiver -> primary weapon;
305 alternate weapon + quiver -> alternate weapon.
306 (Prior to 3.3.0, it was not possible for the two
307 stacks to be worn in different slots and `obj'
308 didn't need to be unworn when merging.) */
311 else if (wmask & W_SWAPWEP)
313 else if (wmask & W_QUIVER)
316 impossible("merging strangely worn items (%lx)", wmask);
317 wmask = otmp->owornmask;
319 if ((otmp->owornmask & ~wmask) != 0L)
321 setworn(otmp, wmask);
324 /* (this should not be necessary, since items
325 already in a monster's inventory don't ever get
326 merged into other objects [only vice versa]) */
327 } else if (obj->owornmask && mcarried(otmp)) {
328 if (obj == MON_WEP(otmp->ocarry)) {
329 MON_WEP(otmp->ocarry) = otmp;
330 otmp->owornmask = W_WEP;
335 /* handle puddings a bit differently; absorption will
336 * free the other object automatically so we can just
337 * return out from here. */
338 if (Is_pudding(obj)) {
339 pudding_merge_message(otmp, obj);
340 obj_absorb(potmp, pobj);
344 obfree(obj, otmp); /* free(obj), bill->otmp */
351 * Adjust hero intrinsics as if this object was being added to the hero's
352 * inventory. Called _before_ the object has been added to the hero's
355 * This is called when adding objects to the hero's inventory normally (via
356 * addinv) or when an object in the hero's inventory has been polymorphed
359 * It may be valid to merge this code with with addinv_core2().
365 if (obj->oclass == COIN_CLASS) {
367 } else if (obj->otyp == AMULET_OF_YENDOR) {
369 impossible("already have amulet?");
371 u.uachieve.amulet = 1;
372 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
374 impossible("already have candelabrum?");
376 u.uachieve.menorah = 1;
377 } else if (obj->otyp == BELL_OF_OPENING) {
379 impossible("already have silver bell?");
382 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
384 impossible("already have the book?");
387 } else if (obj->oartifact) {
388 if (is_quest_artifact(obj)) {
389 if (u.uhave.questart)
390 impossible("already have quest artifact?");
391 u.uhave.questart = 1;
394 set_artifact_intrinsic(obj, 1, W_ART);
396 if (obj->otyp == LUCKSTONE && obj->record_achieve_special) {
397 u.uachieve.mines_luckstone = 1;
398 obj->record_achieve_special = 0;
399 } else if ((obj->otyp == AMULET_OF_REFLECTION
400 || obj->otyp == BAG_OF_HOLDING)
401 && obj->record_achieve_special) {
402 u.uachieve.finish_sokoban = 1;
403 obj->record_achieve_special = 0;
408 * Adjust hero intrinsics as if this object was being added to the hero's
409 * inventory. Called _after_ the object has been added to the hero's
412 * This is called when adding objects to the hero's inventory normally (via
413 * addinv) or when an object in the hero's inventory has been polymorphed
420 if (confers_luck(obj)) {
421 /* new luckstone must be in inventory by this point
422 * for correct calculation */
428 * Add obj to the hero's inventory. Make sure the object is "free".
429 * Adjust hero attributes as necessary.
435 struct obj *otmp, *prev;
436 int saved_otyp = (int) obj->otyp; /* for panic */
438 if (obj->where != OBJ_FREE)
439 panic("addinv: obj not free");
440 /* normally addtobill() clears no_charge when items in a shop are
441 picked up, but won't do so if the shop has become untended */
442 obj->no_charge = 0; /* should not be set in hero's invent */
443 if (Has_contents(obj))
444 picked_container(obj); /* clear no_charge */
445 obj->was_thrown = 0; /* not meaningful for invent */
449 /* merge with quiver in preference to any other inventory slot
450 in case quiver and wielded weapon are both eligible; adding
451 extra to quivered stack is more useful than to wielded one */
452 if (uquiver && merged(&uquiver, &obj)) {
455 panic("addinv: null obj after quiver merge otyp=%d", saved_otyp);
458 /* merge if possible; find end of chain in the process */
459 for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
460 if (merged(&otmp, &obj)) {
463 panic("addinv: null obj after merge otyp=%d", saved_otyp);
466 /* didn't merge, so insert into chain */
468 if (flags.invlet_constant || !prev) {
469 obj->nobj = invent; /* insert at beginning */
471 if (flags.invlet_constant)
474 prev->nobj = obj; /* insert at end */
477 obj->where = OBJ_INVENT;
481 carry_obj_effects(obj); /* carrying affects the obj */
487 * Some objects are affected by being carried.
488 * Make those adjustments here. Called _after_ the object
489 * has been added to the hero's or monster's inventory,
490 * and after hero's intrinsics have been updated.
493 carry_obj_effects(obj)
496 /* Cursed figurines can spontaneously transform
498 if (obj->otyp == FIGURINE) {
499 if (obj->cursed && obj->corpsenm != NON_PM
500 && !dead_species(obj->corpsenm, TRUE)) {
501 attach_fig_transform_timeout(obj);
506 /* Add an item to the inventory unless we're fumbling or it refuses to be
507 * held (via touch_artifact), and give a message.
508 * If there aren't any free inventory slots, we'll drop it instead.
509 * If both success and failure messages are NULL, then we're just doing the
510 * fumbling/slot-limit checking for a silent grab. In any case,
511 * touch_artifact will print its own messages if they are warranted.
514 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
516 const char *drop_fmt, *drop_arg, *hold_msg;
521 obj->dknown = 1; /* maximize mergibility */
522 if (obj->oartifact) {
523 /* place_object may change these */
524 boolean crysknife = (obj->otyp == CRYSKNIFE);
525 int oerode = obj->oerodeproof;
526 boolean wasUpolyd = Upolyd;
528 /* in case touching this object turns out to be fatal */
529 place_object(obj, u.ux, u.uy);
531 if (!touch_artifact(obj, &youmonst)) {
532 obj_extract_self(obj); /* remove it from the floor */
533 dropy(obj); /* now put it back again :-) */
535 } else if (wasUpolyd && !Upolyd) {
536 /* loose your grip if you revert your form */
538 pline(drop_fmt, drop_arg);
539 obj_extract_self(obj);
543 obj_extract_self(obj);
545 obj->otyp = CRYSKNIFE;
546 obj->oerodeproof = oerode;
551 pline(drop_fmt, drop_arg);
554 long oquan = obj->quan;
555 int prev_encumbr = near_capacity(); /* before addinv() */
557 /* encumbrance only matters if it would now become worse
558 than max( current_value, stressed ) */
559 if (prev_encumbr < MOD_ENCUMBER)
560 prev_encumbr = MOD_ENCUMBER;
561 /* addinv() may redraw the entire inventory, overwriting
562 drop_arg when it comes from something like doname() */
564 drop_arg = strcpy(buf, drop_arg);
567 if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
568 && near_capacity() > prev_encumbr)) {
570 pline(drop_fmt, drop_arg);
571 /* undo any merge which took place */
572 if (obj->quan > oquan)
573 obj = splitobj(obj, oquan);
576 if (flags.autoquiver && !uquiver && !obj->owornmask
577 && (is_missile(obj) || ammo_and_launcher(obj, uwep)
578 || ammo_and_launcher(obj, uswapwep)))
580 if (hold_msg || drop_fmt)
581 prinv(hold_msg, obj, oquan);
587 /* useup() all of an item regardless of its quantity */
594 obfree(obj, (struct obj *) 0); /* deletes contents also */
599 register struct obj *obj;
601 /* Note: This works correctly for containers because they (containers)
603 if (obj->quan > 1L) {
604 obj->in_use = FALSE; /* no longer in use */
606 obj->owt = weight(obj);
613 /* use one charge from an item and possibly incur shop debt for it */
615 consume_obj_charge(obj, maybe_unpaid)
617 boolean maybe_unpaid; /* false if caller handles shop billing */
627 * Adjust hero's attributes as if this object was being removed from the
628 * hero's inventory. This should only be called from freeinv() and
629 * where we are polymorphing an object already in the hero's inventory.
631 * Should think of a better name...
637 if (obj->oclass == COIN_CLASS) {
640 } else if (obj->otyp == AMULET_OF_YENDOR) {
642 impossible("don't have amulet?");
644 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
645 if (!u.uhave.menorah)
646 impossible("don't have candelabrum?");
648 } else if (obj->otyp == BELL_OF_OPENING) {
650 impossible("don't have silver bell?");
652 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
654 impossible("don't have the book?");
656 } else if (obj->oartifact) {
657 if (is_quest_artifact(obj)) {
658 if (!u.uhave.questart)
659 impossible("don't have quest artifact?");
660 u.uhave.questart = 0;
662 set_artifact_intrinsic(obj, 0, W_ART);
665 if (obj->otyp == LOADSTONE) {
667 } else if (confers_luck(obj)) {
670 } else if (obj->otyp == FIGURINE && obj->timed) {
671 (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
675 /* remove an object from the hero's inventory */
678 register struct obj *obj;
680 extract_nobj(obj, &invent);
689 struct obj *otmp, *otmp2;
691 for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
694 /* after unpunish(), or might get deallocated chain */
695 otmp2 = otmp->nexthere;
702 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
705 register struct obj *obj;
709 if (obj->otyp == AMULET_OF_YENDOR
710 || obj->otyp == CANDELABRUM_OF_INVOCATION
711 || obj->otyp == BELL_OF_OPENING
712 || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
713 /* player might be doing something stupid, but we
714 * can't guarantee that. assume special artifacts
715 * are indestructible via drawbridges, and exploding
716 * chests, and golem creation, and ...
720 update_map = (obj->where == OBJ_FLOOR);
721 obj_extract_self(obj);
723 newsym(obj->ox, obj->oy);
724 obfree(obj, (struct obj *) 0); /* frees contents also */
727 /* try to find a particular type of object at designated map location */
733 register struct obj *otmp;
735 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
736 if (otmp->otyp == otyp)
742 /* sobj_at(&c) traversal -- find next object of specified type */
744 nxtobj(obj, type, by_nexthere)
749 register struct obj *otmp;
751 otmp = obj; /* start with the object after this one */
753 otmp = !by_nexthere ? otmp->nobj : otmp->nexthere;
756 } while (otmp->otyp != type);
765 register struct obj *otmp;
767 for (otmp = invent; otmp; otmp = otmp->nobj)
768 if (otmp->otyp == type)
770 return (struct obj *) 0;
773 /* Fictional and not-so-fictional currencies.
774 * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
776 static const char *const currencies[] = {
777 "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
778 "Ankh-Morpork Dollar", /* Discworld */
779 "auric", /* The Domination of Draka */
780 "buckazoid", /* Space Quest */
781 "cirbozoid", /* Starslip */
782 "credit chit", /* Deus Ex */
783 "cubit", /* Battlestar Galactica */
784 "Flanian Pobble Bead", /* The Hitchhiker's Guide to the Galaxy */
785 "fretzer", /* Jules Verne */
786 "imperial credit", /* Star Wars */
787 "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
788 "kongbuck", /* Snow Crash */
789 "nanite", /* System Shock 2 */
790 "quatloo", /* Star Trek, Sim City */
791 "simoleon", /* Sim City */
792 "solari", /* Spaceballs */
793 "spacebuck", /* Spaceballs */
794 "sporebuck", /* Spore */
795 "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */
796 "woolong", /* Cowboy Bebop */
797 "zorkmid", /* Zork, NetHack */
806 res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
808 res = makeplural(res);
815 register struct obj *otmp;
817 for (otmp = invent; otmp; otmp = otmp->nobj)
818 if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
827 register struct obj *otmp;
829 for (otmp = invent; otmp; otmp = otmp->nobj)
830 if (otmp->otyp == SPE_NOVEL)
832 return (struct obj *) 0;
838 register struct obj *objchn;
843 if (objchn->o_id == id)
845 if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
847 objchn = objchn->nobj;
849 return (struct obj *) 0;
854 register struct obj *obj;
857 register struct obj *otmp;
859 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
869 register struct obj *obj = level.objects[x][y];
872 if (obj->oclass == COIN_CLASS)
876 return (struct obj *) 0;
879 /* compact a string of inventory letters by dashing runs of letters */
884 register int i1 = 1, i2 = 1;
885 register char ilet, ilet1, ilet2;
889 buf[++i2] = buf[++i1];
892 if (ilet == ilet1 + 1) {
893 if (ilet1 == ilet2 + 1)
894 buf[i2 - 1] = ilet1 = '-';
895 else if (ilet2 == '-') {
896 buf[i2 - 1] = ++ilet1;
901 } else if (ilet == NOINVSYM) {
902 /* compact three or more consecutive '#'
903 characters into "#-#" */
904 if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM)
906 else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-'
907 && buf[i2 - 1] == NOINVSYM)
912 buf[++i2] = buf[++i1];
917 /* some objects shouldn't be split when count given to getobj or askchain */
922 return !((obj->otyp == LOADSTONE && obj->cursed)
923 || (obj == uwep && welded(uwep)));
926 /* match the prompt for either 'T' or 'R' command */
931 return !strcmp(action, "take off") || !strcmp(action, "remove");
934 /* match the prompt for either 'W' or 'P' command */
939 return !strcmp(action, "wear") || !strcmp(action, "put on");
944 * struct obj *xxx: object to do something with.
945 * (struct obj *) 0 error return: no object.
946 * &zeroobj explicitly no object (as in w-).
947 !!!! test if gold can be used in unusual ways (eaten etc.)
948 !!!! may be able to remove "usegold"
952 register const char *let, *word;
954 register struct obj *otmp;
956 char buf[BUFSZ], qbuf[QBUFSZ];
957 char lets[BUFSZ], altlets[BUFSZ], *ap;
958 register int foo = 0;
959 register char *bp = buf;
960 xchar allowcnt = 0; /* 0, 1 or 2 */
961 struct obj *firstobj = invent;
962 boolean usegold = FALSE; /* can't use gold because its illegal */
963 boolean allowall = FALSE;
964 boolean allownone = FALSE;
965 boolean useboulder = FALSE;
971 if (*let == ALLOW_COUNT)
973 if (*let == COIN_CLASS)
974 let++, usegold = TRUE;
976 /* Equivalent of an "ugly check" for gold */
977 if (usegold && !strcmp(word, "eat")
978 && (!metallivorous(youmonst.data)
979 || youmonst.data == &mons[PM_RUST_MONSTER]))
982 if (*let == ALL_CLASSES)
983 let++, allowall = TRUE;
984 if (*let == ALLOW_NONE)
985 let++, allownone = TRUE;
986 /* "ugly check" for reading fortune cookies, part 1.
987 * The normal 'ugly check' keeps the object on the inventory list.
988 * We don't want to do that for shirts/cookies, so the check for
989 * them is handled a bit differently (and also requires that we set
990 * allowall in the caller).
992 if (allowall && !strcmp(word, "read"))
995 /* another ugly check: show boulders (not statues) */
996 if (*let == WEAPON_CLASS && !strcmp(word, "throw")
997 && throws_rocks(youmonst.data))
1002 if (bp > buf && bp[-1] == '-')
1006 if (!flags.invlet_constant)
1009 for (otmp = firstobj; otmp; otmp = otmp->nobj) {
1010 if (&bp[foo] == &buf[sizeof buf - 1]
1011 || ap == &altlets[sizeof altlets - 1]) {
1012 /* we must have a huge number of NOINVSYM items somehow */
1013 impossible("getobj: inventory overflow");
1017 if (!*let || index(let, otmp->oclass)
1018 || (usegold && otmp->invlet == GOLD_SYM)
1019 || (useboulder && otmp->otyp == BOULDER)) {
1020 register int otyp = otmp->otyp;
1021 bp[foo++] = otmp->invlet;
1023 /* clang-format off */
1025 /* ugly check: remove inappropriate things */
1027 (taking_off(word) /* exclude if not worn */
1028 && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1029 || (putting_on(word) /* exclude if already worn */
1030 && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1031 #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
1032 || (!strcmp(word, "wield")
1033 && (otmp->owornmask & W_WEP))
1035 || (!strcmp(word, "ready") /* exclude if wielded */
1036 && (otmp == uwep || (otmp == uswapwep && u.twoweap)))
1037 || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
1038 && inaccessible_equipment(otmp, (const char *) 0, FALSE))
1043 /* Second ugly check; unlike the first it won't trigger an
1044 * "else" in "you don't have anything else to ___".
1048 && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
1049 || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
1050 && otyp != TOWEL && otyp != LENSES)))
1051 || (!strcmp(word, "wield")
1052 && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
1053 || (!strcmp(word, "eat") && !is_edible(otmp))
1054 || (!strcmp(word, "sacrifice")
1055 && (otyp != CORPSE && otyp != AMULET_OF_YENDOR
1056 && otyp != FAKE_AMULET_OF_YENDOR))
1057 || (!strcmp(word, "write with")
1058 && (otmp->oclass == TOOL_CLASS
1059 && otyp != MAGIC_MARKER && otyp != TOWEL))
1060 || (!strcmp(word, "tin")
1061 && (otyp != CORPSE || !tinnable(otmp)))
1062 || (!strcmp(word, "rub")
1063 && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP
1064 && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN)
1065 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1066 || (!strcmp(word, "use or apply")
1067 /* Picks, axes, pole-weapons, bullwhips */
1068 && ((otmp->oclass == WEAPON_CLASS
1069 && !is_pick(otmp) && !is_axe(otmp)
1070 && !is_pole(otmp) && otyp != BULLWHIP)
1071 || (otmp->oclass == POTION_CLASS
1072 /* only applicable potion is oil, and it will only
1073 be offered as a choice when already discovered */
1074 && (otyp != POT_OIL || !otmp->dknown
1075 || !objects[POT_OIL].oc_name_known))
1076 || (otmp->oclass == FOOD_CLASS
1077 && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF)
1078 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1079 || (!strcmp(word, "invoke")
1081 && !objects[otyp].oc_unique
1082 && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known)
1083 && otyp != CRYSTAL_BALL /* synonym for apply */
1084 /* note: presenting the possibility of invoking non-artifact
1085 mirrors and/or lamps is simply a cruel deception... */
1087 && otyp != MAGIC_LAMP
1088 && (otyp != OIL_LAMP /* don't list known oil lamp */
1089 || (otmp->dknown && objects[OIL_LAMP].oc_name_known)))
1090 || (!strcmp(word, "untrap with")
1091 && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)
1092 || (otmp->oclass == POTION_CLASS
1093 /* only applicable potion is oil, and it will only
1094 be offered as a choice when already discovered */
1095 && (otyp != POT_OIL || !otmp->dknown
1096 || !objects[POT_OIL].oc_name_known))))
1097 || (!strcmp(word, "tip") && !Is_container(otmp)
1098 /* include horn of plenty if sufficiently discovered */
1099 && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
1100 || !objects[HORN_OF_PLENTY].oc_name_known))
1101 || (!strcmp(word, "charge") && !is_chargeable(otmp))
1102 || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
1106 /* Third ugly check: acceptable but not listed as likely
1107 * candidates in the prompt or in the inventory subset if
1108 * player responds with '?'.
1111 /* ugly check for unworn armor that can't be worn */
1112 (putting_on(word) && *let == ARMOR_CLASS
1113 && !canwearobj(otmp, &dummymask, FALSE))
1114 /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
1115 || ((putting_on(word) || taking_off(word))
1116 && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
1117 /* or unsuitable items rubbed on known touchstone */
1118 || (!strncmp(word, "rub on the stone", 16)
1119 && *let == GEM_CLASS && otmp->dknown
1120 && objects[otyp].oc_name_known)
1121 /* suppress corpses on astral, amulets elsewhere */
1122 || (!strcmp(word, "sacrifice")
1123 /* (!astral && amulet) || (astral && !amulet) */
1124 && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
1125 /* suppress container being stashed into */
1126 || (!strcmp(word, "stash") && !ck_bag(otmp))
1127 /* worn armor or accessory covered by cursed worn armor */
1128 || (taking_off(word)
1129 && inaccessible_equipment(otmp, (const char *) 0, TRUE))
1131 /* acceptable but not listed as likely candidate */
1134 *ap++ = otmp->invlet;
1137 /* clang-format on */
1139 /* "ugly check" for reading fortune cookies, part 2 */
1140 if ((!strcmp(word, "read") && is_readable(otmp)))
1141 allowall = usegold = TRUE;
1146 if (foo == 0 && bp > buf && bp[-1] == ' ')
1148 Strcpy(lets, bp); /* necessary since we destroy buf */
1149 if (foo > 5) /* compactify string */
1153 if (!foo && !allowall && !allownone) {
1154 You("don't have anything %sto %s.", foox ? "else " : "", word);
1155 return (struct obj *) 0;
1160 allowcnt = 1; /* abort previous count */
1163 Sprintf(qbuf, "What do you want to %s? [*]", word);
1165 Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf);
1170 ilet = yn_function(qbuf, (char *) 0, '\0');
1171 if (digit(ilet) && !allowcnt) {
1172 pline("No count allowed with this command.");
1177 while (digit(ilet)) {
1178 if (ilet != '?' && ilet != '*')
1180 /* accumulate unless cnt has overflowed */
1183 cnt = 10L * cnt + (long) (ilet - '0');
1184 /* signal presence of cnt */
1185 allowcnt = (cnt >= prevcnt) ? 2 : 3;
1189 if (allowcnt == 3) {
1190 /* overflow detected; force cnt to be invalid */
1194 if (index(quitchars, ilet)) {
1197 return (struct obj *) 0;
1201 char *suf = (char *) 0;
1204 if ((bp = strstr(buf, " on the ")) != 0) {
1205 /* rub on the stone[s] */
1209 if ((bp = strstr(buf, " or ")) != 0) {
1211 bp = (rn2(2) ? buf : (bp + 4));
1214 You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
1217 return (allownone ? &zeroobj : (struct obj *) 0);
1219 /* since gold is now kept in inventory, we need to do processing for
1220 select-from-invent before checking whether gold has been picked */
1221 if (ilet == '?' || ilet == '*') {
1222 char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
1225 if (ilet == '?' && !*lets && *altlets)
1226 allowed_choices = altlets;
1227 ilet = display_pickinv(allowed_choices, TRUE,
1228 allowcnt ? &ctmp : (long *) 0);
1231 if (allowcnt && ctmp >= 0) {
1237 if (ilet == '\033') {
1240 return (struct obj *) 0;
1242 /* they typed a letter (not a space) at the prompt */
1244 /* find the item which was picked */
1245 for (otmp = invent; otmp; otmp = otmp->nobj)
1246 if (otmp->invlet == ilet)
1248 /* some items have restrictions */
1249 if (ilet == def_oc_syms[COIN_CLASS].sym
1250 /* guard against the [hypothetical] chace of having more
1251 than one invent slot of gold and picking the non-'$' one */
1252 || (otmp && otmp->oclass == COIN_CLASS)) {
1254 You("cannot %s gold.", word);
1255 return (struct obj *) 0;
1257 /* Historic note: early Nethack had a bug which was
1258 * first reported for Larn, where trying to drop 2^32-n
1259 * gold pieces was allowed, and did interesting things
1260 * to your money supply. The LRS is the tax bureau
1263 if (allowcnt == 2 && cnt <= 0) {
1264 if (cnt < 0 || !prezero)
1266 "LRS would be very interested to know you have that much.");
1267 return (struct obj *) 0;
1270 if (allowcnt == 2 && !strcmp(word, "throw")) {
1271 /* permit counts for throwing gold, but don't accept
1272 * counts for other things since the throw code will
1273 * split off a single item anyway */
1274 if (ilet != def_oc_syms[COIN_CLASS].sym
1275 && !(otmp && otmp->oclass == COIN_CLASS))
1277 if (cnt == 0 && prezero)
1278 return (struct obj *) 0;
1280 You("can only throw one item at a time.");
1284 context.botl = 1; /* May have changed the amount of money */
1286 /* [we used to set otmp (by finding ilet in invent) here, but
1287 that's been moved above so that otmp can be checked earlier] */
1288 /* verify the chosen object */
1290 You("don't have that object.");
1292 return (struct obj *) 0;
1294 } else if (cnt < 0 || otmp->quan < cnt) {
1295 You("don't have that many! You have only %ld.", otmp->quan);
1297 return (struct obj *) 0;
1302 if (!allowall && let && !index(let, otmp->oclass)
1303 && !(usegold && otmp->oclass == COIN_CLASS)) {
1304 silly_thing(word, otmp);
1305 return (struct obj *) 0;
1307 if (allowcnt == 2) { /* cnt given */
1309 return (struct obj *) 0;
1310 if (cnt != otmp->quan) {
1311 /* don't split a stack of cursed loadstones */
1312 if (splittable(otmp))
1313 otmp = splitobj(otmp, cnt);
1314 else if (otmp->otyp == LOADSTONE && otmp->cursed)
1315 /* kludge for canletgo()'s can't-drop-this message */
1316 otmp->corpsenm = (int) cnt;
1323 silly_thing(word, otmp)
1327 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1330 const char *s1, *s2, *s3, *what;
1331 int ocls = otmp->oclass, otyp = otmp->otyp;
1334 /* check for attempted use of accessory commands ('P','R') on armor
1335 and for corresponding armor commands ('W','T') on accessories */
1336 if (ocls == ARMOR_CLASS) {
1337 if (!strcmp(word, "put on"))
1338 s1 = "W", s2 = "wear", s3 = "";
1339 else if (!strcmp(word, "remove"))
1340 s1 = "T", s2 = "take", s3 = " off";
1341 } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
1342 || ocls == AMULET_CLASS
1343 || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1344 if (!strcmp(word, "wear"))
1345 s1 = "P", s2 = "put", s3 = " on";
1346 else if (!strcmp(word, "take off"))
1347 s1 = "R", s2 = "remove", s3 = "";
1351 /* quantity for armor and accessory objects is always 1,
1352 but some things should be referred to as plural */
1353 if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp))
1355 pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
1358 pline(silly_thing_to, word);
1365 /* use allow_category() from pickup.c */
1366 return (int) allow_category(otmp);
1373 return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
1379 return (boolean) (uarm || uarmc || uarmf || uarmg
1380 || uarmh || uarms || uarmu);
1387 return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON))
1392 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1393 STATIC_VAR struct xprnctx {
1398 /* safe_qbuf() -> short_oname() callback */
1403 return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot,
1407 /* alternate safe_qbuf() -> short_oname() callback */
1409 safeq_shortxprname(obj)
1412 return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let,
1413 safeq_xprn_ctx.dot, 0L, 0L);
1416 static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
1417 RING_CLASS, AMULET_CLASS,
1420 /* interactive version of getobj - used for Drop, Identify and */
1421 /* Takeoff (A). Return the number of times fn was called successfully */
1422 /* If combo is TRUE, we just use this to get a category list */
1424 ggetobj(word, fn, mx, combo, resultflags)
1426 int FDECL((*fn), (OBJ_P)), mx;
1427 boolean combo; /* combination menu flag */
1428 unsigned *resultflags;
1430 int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
1431 boolean FDECL((*filter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
1432 boolean takeoff, ident, allflag, m_seen;
1434 int oletct, iletct, unpaid, oc_of_sym;
1435 char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5];
1436 char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
1437 char buf[BUFSZ], qbuf[QBUFSZ];
1441 takeoff = ident = allflag = m_seen = FALSE;
1443 You("have nothing to %s.", word);
1446 add_valid_menu_class(0); /* reset */
1447 if (taking_off(word)) {
1450 } else if (!strcmp(word, "identify")) {
1452 filter = not_fully_identified;
1455 iletct = collect_obj_classes(ilets, invent, FALSE, filter, &itemcount);
1456 unpaid = count_unpaid(invent);
1458 if (ident && !iletct) {
1459 return -1; /* no further identifications */
1460 } else if (!takeoff && (unpaid || invent)) {
1461 ilets[iletct++] = ' ';
1463 ilets[iletct++] = 'u';
1464 if (count_buc(invent, BUC_BLESSED))
1465 ilets[iletct++] = 'B';
1466 if (count_buc(invent, BUC_UNCURSED))
1467 ilets[iletct++] = 'U';
1468 if (count_buc(invent, BUC_CURSED))
1469 ilets[iletct++] = 'C';
1470 if (count_buc(invent, BUC_UNKNOWN))
1471 ilets[iletct++] = 'X';
1473 ilets[iletct++] = 'a';
1474 } else if (takeoff && invent) {
1475 ilets[iletct++] = ' ';
1477 ilets[iletct++] = 'i';
1479 ilets[iletct++] = 'm'; /* allow menu presentation on request */
1480 ilets[iletct] = '\0';
1483 Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", word,
1486 if (buf[0] == '\033')
1488 if (index(buf, 'i')) {
1489 if (display_inventory((char *) 0, TRUE) == '\033')
1495 extra_removeables[0] = '\0';
1497 /* arbitrary types of items can be placed in the weapon slots
1498 [any duplicate entries in extra_removeables[] won't matter] */
1500 (void) strkitten(extra_removeables, uwep->oclass);
1502 (void) strkitten(extra_removeables, uswapwep->oclass);
1504 (void) strkitten(extra_removeables, uquiver->oclass);
1508 olets[oletct = 0] = '\0';
1509 while ((sym = *ip++) != '\0') {
1512 oc_of_sym = def_char_to_objclass(sym);
1513 if (takeoff && oc_of_sym != MAXOCLASSES) {
1514 if (index(extra_removeables, oc_of_sym)) {
1515 ; /* skip rest of takeoff checks */
1516 } else if (!index(removeables, oc_of_sym)) {
1517 pline("Not applicable.");
1519 } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1522 } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep
1524 You("are not wielding anything.");
1526 } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1527 You("are not wearing rings.");
1529 } else if (oc_of_sym == AMULET_CLASS && !uamul) {
1530 You("are not wearing an amulet.");
1532 } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1533 You("are not wearing a blindfold.");
1538 if (oc_of_sym == COIN_CLASS && !combo) {
1540 } else if (sym == 'a') {
1542 } else if (sym == 'A') {
1543 /* same as the default */;
1544 } else if (sym == 'u') {
1545 add_valid_menu_class('u');
1547 } else if (sym == 'B') {
1548 add_valid_menu_class('B');
1550 } else if (sym == 'U') {
1551 add_valid_menu_class('U');
1553 } else if (sym == 'C') {
1554 add_valid_menu_class('C');
1556 } else if (sym == 'X') {
1557 add_valid_menu_class('X');
1559 } else if (sym == 'm') {
1561 } else if (oc_of_sym == MAXOCLASSES) {
1562 You("don't have any %c's.", sym);
1563 } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
1564 if (!index(olets, oc_of_sym)) {
1565 add_valid_menu_class(oc_of_sym);
1566 olets[oletct++] = oc_of_sym;
1573 return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
1574 } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
1577 /* !!!! test gold dropping */
1578 } else if (allowgold == 2 && !oletct) {
1579 return 1; /* you dropped gold (or at least tried to) */
1582 int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
1584 * askchain() has already finished the job in this case
1585 * so set a special flag to convey that back to the caller
1586 * so that it won't continue processing.
1587 * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
1589 if (combo && allflag && resultflags)
1590 *resultflags |= ALL_FINISHED;
1596 * Walk through the chain starting at objchn and ask for all objects
1597 * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1598 * whether the action in question (i.e., fn) has to be performed.
1599 * If allflag then no questions are asked. Max gives the max nr of
1600 * objects to be treated. Return the number of objects treated.
1603 askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1604 struct obj **objchn;
1605 register int allflag, mx;
1606 register const char *olets, *word; /* olets is an Obj Class char array */
1607 register int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
1609 struct obj *otmp, *otmpo;
1610 register char sym, ilet;
1611 register int cnt = 0, dud = 0, tmp;
1612 boolean takeoff, nodot, ident, take_out, put_in, first, ininv;
1613 char qbuf[QBUFSZ], qpfx[QBUFSZ];
1615 takeoff = taking_off(word);
1616 ident = !strcmp(word, "identify");
1617 take_out = !strcmp(word, "take out");
1618 put_in = !strcmp(word, "put in");
1619 nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
1620 || takeoff || take_out || put_in);
1621 ininv = (*objchn == invent);
1623 /* Changed so the askchain is interrogated in the order specified.
1624 * For example, if a person specifies =/ then first all rings will be
1625 * asked about followed by all wands -dgk
1629 if (*objchn && (*objchn)->oclass == COIN_CLASS)
1630 ilet--; /* extra iteration */
1632 * Multiple Drop can change the invent chain while it operates
1633 * (dropping a burning potion of oil while levitating creates
1634 * an explosion which can destroy inventory items), so simple
1636 * for (otmp = *objchn; otmp; otmp = otmp2) {
1637 * otmp2 = otmp->nobj;
1640 * is inadequate here. Use each object's bypass bit to keep
1641 * track of which list elements have already been processed.
1643 bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
1644 while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
1649 if (olets && *olets && otmp->oclass != *olets)
1651 if (takeoff && !is_worn(otmp))
1653 if (ident && !not_fully_identified(otmp))
1655 if (ckfn && !(*ckfn)(otmp))
1658 safeq_xprn_ctx.let = ilet;
1659 safeq_xprn_ctx.dot = !nodot;
1662 /* traditional_loot() skips prompting when only one
1663 class of objects is involved, so prefix the first
1664 object being queried here with an explanation why */
1665 if (take_out || put_in)
1666 Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
1670 qbuf, qpfx, "?", otmp, ininv ? safeq_xprname : doname,
1671 ininv ? safeq_shortxprname : ansimpleoname, "item");
1672 sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
1679 /* Number was entered; split the object unless it corresponds
1680 to 'none' or 'all'. 2 special cases: cursed loadstones and
1681 welded weapons (eg, multiple daggers) will remain as merged
1682 unit; done to avoid splitting an object that won't be
1683 droppable (even if we're picking up rather than dropping).
1689 if (yn_number < otmp->quan && splittable(otmp))
1690 otmp = splitobj(otmp, yn_number);
1699 if (container_gone(fn)) {
1700 /* otmp caused magic bag to explode;
1701 both are now gone */
1702 otmp = 0; /* and return */
1703 } else if (otmp && otmp != otmpo) {
1704 /* split occurred, merge again */
1705 (void) merged(&otmpo, &otmp);
1718 /* special case for seffects() */
1724 if (olets && *olets && *++olets)
1726 if (!takeoff && (dud || cnt))
1727 pline("That was all.");
1728 else if (!dud && !cnt)
1729 pline("No applicable objects.");
1731 bypass_objlist(*objchn, FALSE);
1736 * Object identification routines:
1739 /* make an object actually be identified; no display updating */
1741 fully_identify_obj(otmp)
1744 makeknown(otmp->otyp);
1745 if (otmp->oartifact)
1746 discover_artifact((xchar) otmp->oartifact);
1747 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1748 if (Is_container(otmp) || otmp->otyp == STATUE)
1749 otmp->cknown = otmp->lknown = 1;
1750 if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1751 learn_egg_type(otmp->corpsenm);
1754 /* ggetobj callback routine; identify an object and give immediate feedback */
1759 fully_identify_obj(otmp);
1760 prinv((char *) 0, otmp, 0L);
1764 /* menu of unidentified objects; select and identify up to id_limit of them */
1766 menu_identify(id_limit)
1769 menu_item *pick_list;
1770 int n, i, first = 1, tryct = 5;
1772 /* assumptions: id_limit > 0 and at least one unID'd item is present */
1775 Sprintf(buf, "What would you like to identify %s?",
1776 first ? "first" : "next");
1777 n = query_objlist(buf, invent, SIGNAL_NOMENU | SIGNAL_ESCAPE
1778 | USE_INVLET | INVORDER_SORT,
1779 &pick_list, PICK_ANY, not_fully_identified);
1784 for (i = 0; i < n; i++, id_limit--)
1785 (void) identify(pick_list[i].item.a_obj);
1786 free((genericptr_t) pick_list);
1787 mark_synch(); /* Before we loop to pop open another menu */
1789 } else if (n == -2) { /* player used ESC to quit menu */
1791 } else if (n == -1) { /* no eligible items found */
1792 pline("That was all.");
1794 } else if (!--tryct) { /* stop re-prompting */
1795 pline1(thats_enough_tries);
1797 } else { /* try again */
1798 pline("Choose an item; use ESC to decline.");
1803 /* dialog with user to identify a given number of items; 0 means all */
1805 identify_pack(id_limit, learning_id)
1807 boolean learning_id; /* true if we just read unknown identify scroll */
1809 struct obj *obj, *the_obj;
1813 the_obj = 0; /* if unid_cnt ends up 1, this will be it */
1814 for (obj = invent; obj; obj = obj->nobj)
1815 if (not_fully_identified(obj))
1816 ++unid_cnt, the_obj = obj;
1819 You("have already identified all %sof your possessions.",
1820 learning_id ? "the rest " : "");
1821 } else if (!id_limit || id_limit >= unid_cnt) {
1822 /* identify everything */
1823 if (unid_cnt == 1) {
1824 (void) identify(the_obj);
1826 /* TODO: use fully_identify_obj and cornline/menu/whatever here
1828 for (obj = invent; obj; obj = obj->nobj)
1829 if (not_fully_identified(obj))
1830 (void) identify(obj);
1833 /* identify up to `id_limit' items */
1835 if (flags.menu_style == MENU_TRADITIONAL)
1837 n = ggetobj("identify", identify, id_limit, FALSE,
1840 break; /* quit or no eligible items */
1841 } while ((id_limit -= n) > 0);
1842 if (n == 0 || n < -1)
1843 menu_identify(id_limit);
1848 /* called when regaining sight; mark inventory objects which were picked
1849 up while blind as now having been seen */
1851 learn_unseen_invent()
1856 return; /* sanity check */
1858 for (otmp = invent; otmp; otmp = otmp->nobj) {
1860 continue; /* already seen */
1861 /* set dknown, perhaps bknown (for priest[ess]) */
1864 * If object->eknown gets implemented (see learnwand(zap.c)),
1865 * handle deferred discovery here.
1871 /* should of course only be called for things in invent */
1876 if (!flags.invlet_constant) {
1877 obj->invlet = NOINVSYM;
1884 * Print the indicated quantity of the given object. If quan == 0L then use
1885 * the current quantity.
1888 prinv(prefix, obj, quan)
1895 pline("%s%s%s", prefix, *prefix ? " " : "",
1896 xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan));
1900 xprname(obj, txt, let, dot, cost, quan)
1902 const char *txt; /* text to print instead of obj */
1903 char let; /* inventory letter */
1904 boolean dot; /* append period; (dot && cost => Iu) */
1905 long cost; /* cost (for inventory of unpaid or expended items) */
1906 long quan; /* if non-0, print this quantity, not obj->quan */
1908 #ifdef LINT /* handle static char li[BUFSZ]; */
1911 static char li[BUFSZ];
1913 boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
1917 savequan = obj->quan;
1923 * * Then obj == null and we are printing a total amount.
1924 * > Then the object is contained and doesn't have an inventory letter.
1926 if (cost != 0 || let == '*') {
1927 /* if dot is true, we're doing Iu, otherwise Ix */
1928 Sprintf(li, "%c - %-45s %6ld %s",
1929 (dot && use_invlet ? obj->invlet : let),
1930 (txt ? txt : doname(obj)), cost, currency(cost));
1932 /* ordinary inventory display or pickup message */
1933 Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
1934 (txt ? txt : doname(obj)), (dot ? "." : ""));
1937 obj->quan = savequan;
1942 /* the 'i' command */
1946 (void) display_inventory((char *) 0, FALSE);
1953 * Scan the given list of objects. If last_found is NULL, return the first
1954 * unpaid object found. If last_found is not NULL, then skip over unpaid
1955 * objects until last_found is reached, then set last_found to NULL so the
1956 * next unpaid object is returned. This routine recursively follows
1959 STATIC_OVL struct obj *
1960 find_unpaid(list, last_found)
1961 struct obj *list, **last_found;
1968 /* still looking for previous unpaid object */
1969 if (list == *last_found)
1970 *last_found = (struct obj *) 0;
1972 return ((*last_found = list));
1974 if (Has_contents(list)) {
1975 if ((obj = find_unpaid(list->cobj, last_found)) != 0)
1980 return (struct obj *) 0;
1983 /* for perm_invent when operating on a partial inventory display, so that
1984 the persistent one doesn't get shrunk during filtering for item selection
1985 then regrown to full inventory, possibly being resized in the process */
1986 static winid cached_pickinv_win = WIN_ERR;
1989 free_pickinv_cache()
1991 if (cached_pickinv_win != WIN_ERR) {
1992 destroy_nhwindow(cached_pickinv_win);
1993 cached_pickinv_win = WIN_ERR;
1998 * Internal function used by display_inventory and getobj that can display
1999 * inventory and return a count as well as a letter. If out_cnt is not null,
2000 * any count returned from the menu selection is placed here.
2003 display_pickinv(lets, want_reply, out_cnt)
2004 register const char *lets;
2010 char *invlet = flags.inv_order;
2011 int i, n, classcount;
2012 winid win; /* windows being used */
2014 menu_item *selected;
2015 struct obj **oarray;
2017 if (flags.perm_invent && lets && *lets) {
2018 /* partial inventory in perm_invent setting; don't operate on
2019 full inventory window, use an alternate one instead; create
2020 the first time needed and keep it for re-use as needed later */
2021 if (cached_pickinv_win == WIN_ERR)
2022 cached_pickinv_win = create_nhwindow(NHW_MENU);
2023 win = cached_pickinv_win;
2028 * Exit early if no inventory -- but keep going if we are doing
2029 * a permanent inventory update. We need to keep going so the
2030 * permanent inventory window updates itself to remove the last
2031 * item(s) dropped. One down side: the addition of the exception
2032 * for permanent inventory window updates _can_ pop the window
2033 * up when it's not displayed -- even if it's empty -- because we
2034 * don't know at this level if its up or not. This may not be
2035 * an issue if empty checks are done before hand and the call
2036 * to here is short circuited away.
2038 if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
2039 pline("Not carrying anything.");
2043 /* oxymoron? temporarily assign permanent inventory letters */
2044 if (!flags.invlet_constant)
2047 if (lets && strlen(lets) == 1 && !iflags.override_ID) {
2048 /* when only one item of interest, use pline instead of menus;
2049 we actually use a fake message-line menu in order to allow
2050 the user to perform selection at the --More-- prompt for tty */
2052 for (otmp = invent; otmp; otmp = otmp->nobj) {
2053 if (otmp->invlet == lets[0]) {
2055 lets[0], want_reply ? PICK_ONE : PICK_NONE,
2056 xprname(otmp, (char *) 0, lets[0], TRUE, 0L, 0L));
2058 *out_cnt = -1L; /* select all */
2065 /* count the number of items */
2066 for (n = 0, otmp = invent; otmp; otmp = otmp->nobj)
2067 if (!lets || !*lets || index(lets, otmp->invlet))
2070 oarray = objarr_init(n);
2072 /* Add objects to the array */
2074 for (otmp = invent; otmp; otmp = otmp->nobj)
2075 if (!lets || !*lets || index(lets, otmp->invlet)) {
2076 objarr_set(otmp, i++, oarray, (flags.sortloot == 'f'));
2081 if (wizard && iflags.override_ID) {
2084 /* wiz_identify stuffed the wiz_identify cmd character
2085 into iflags.override_ID */
2086 Sprintf(prompt, "Debug Identify (%s to permanently identify)",
2087 visctrl(iflags.override_ID));
2088 add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
2089 prompt, MENU_UNSELECTED);
2093 any = zeroany; /* set all bits to zero */
2094 for (i = 0; i < n; i++) {
2096 ilet = otmp->invlet;
2097 any = zeroany; /* zero */
2098 if (!flags.sortpack || otmp->oclass == *invlet) {
2099 if (flags.sortpack && !classcount) {
2100 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2101 let_to_name(*invlet, FALSE,
2102 (want_reply && iflags.menu_head_objsym)),
2107 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2108 doname(otmp), MENU_UNSELECTED);
2111 if (flags.sortpack) {
2114 if (--invlet != venom_inv) {
2120 end_menu(win, (char *) 0);
2122 n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
2124 ret = selected[0].item.a_char;
2126 *out_cnt = selected[0].count;
2127 free((genericptr_t) selected);
2129 ret = !n ? '\0' : '\033'; /* cancelled */
2135 * If lets == NULL or "", list all objects in the inventory. Otherwise,
2136 * list all objects with object classes that match the order in lets.
2138 * Returns the letter identifier of a selected item, or 0 if nothing
2142 display_inventory(lets, want_reply)
2146 return display_pickinv(lets, want_reply, (long *) 0);
2150 * Show what is current using inventory letters.
2154 display_used_invlets(avoidlet)
2159 char *invlet = flags.inv_order;
2160 int n, classcount, invdone = 0;
2163 menu_item *selected;
2166 win = create_nhwindow(NHW_MENU);
2169 any = zeroany; /* set all bits to zero */
2171 for (otmp = invent; otmp; otmp = otmp->nobj) {
2172 ilet = otmp->invlet;
2173 if (ilet == avoidlet)
2175 if (!flags.sortpack || otmp->oclass == *invlet) {
2176 if (flags.sortpack && !classcount) {
2177 any = zeroany; /* zero */
2178 add_menu(win, NO_GLYPH, &any, 0, 0,
2179 iflags.menu_headings,
2180 let_to_name(*invlet, FALSE, FALSE),
2185 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2186 doname(otmp), MENU_UNSELECTED);
2189 if (flags.sortpack && *++invlet)
2193 end_menu(win, "Inventory letters used:");
2195 n = select_menu(win, PICK_NONE, &selected);
2197 ret = selected[0].item.a_char;
2198 free((genericptr_t) selected);
2200 ret = !n ? '\0' : '\033'; /* cancelled */
2201 destroy_nhwindow(win);
2207 * Returns the number of unpaid items within the given list. This includes
2208 * contained objects.
2219 if (Has_contents(list))
2220 count += count_unpaid(list->cobj);
2227 * Returns the number of items with b/u/c/unknown within the given list.
2228 * This does NOT include contained objects.
2230 * Assumes that the hero sees or touches or otherwise senses the objects
2231 * at some point: bknown is forced for priest[ess], like in xname().
2234 count_buc(list, type)
2240 for (; list; list = list->nobj) {
2241 /* coins are "none of the above" as far as BUCX filtering goes */
2242 if (list->oclass == COIN_CLASS)
2244 /* priests always know bless/curse state */
2245 if (Role_if(PM_PRIEST))
2248 /* check whether this object matches the requested type */
2250 ? (type == BUC_UNKNOWN)
2251 : list->blessed ? (type == BUC_BLESSED)
2252 : list->cursed ? (type == BUC_CURSED)
2253 : (type == BUC_UNCURSED))
2259 /* similar to count_buc(), but tallies all states at once
2260 rather than looking for a specific type */
2262 tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
2264 int *bcp, *ucp, *ccp, *xcp, *ocp;
2266 *bcp = *ucp = *ccp = *xcp = *ocp = 0;
2267 for (; list; list = list->nobj) {
2268 if (list->oclass == COIN_CLASS) {
2269 ++(*ocp); /* "other" */
2272 /* priests always know bless/curse state */
2273 if (Role_if(PM_PRIEST))
2278 else if (list->blessed)
2280 else if (list->cursed)
2282 else /* neither blessed nor cursed => uncursed */
2288 count_contents(container, nested, quantity, everything)
2289 struct obj *container;
2290 boolean nested, /* include contents of any nested containers */
2291 quantity, /* count all vs count separate stacks */
2292 everything; /* all objects vs only unpaid objects */
2297 for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
2298 if (nested && Has_contents(otmp))
2299 count += count_contents(otmp, nested, quantity, everything);
2300 if (everything || otmp->unpaid)
2301 count += quantity ? otmp->quan : 1L;
2310 struct obj *otmp, *marker;
2312 char *invlet = flags.inv_order;
2313 int classcount, count, num_so_far;
2316 count = count_unpaid(invent);
2319 marker = (struct obj *) 0;
2320 otmp = find_unpaid(invent, &marker);
2321 cost = unpaid_cost(otmp, FALSE);
2322 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2323 pline1(xprname(otmp, distant_name(otmp, doname),
2324 carried(otmp) ? otmp->invlet : CONTAINED_SYM, TRUE,
2326 iflags.suppress_price--;
2330 win = create_nhwindow(NHW_MENU);
2332 num_so_far = 0; /* count of # printed so far */
2333 if (!flags.invlet_constant)
2338 for (otmp = invent; otmp; otmp = otmp->nobj) {
2339 ilet = otmp->invlet;
2341 if (!flags.sortpack || otmp->oclass == *invlet) {
2342 if (flags.sortpack && !classcount) {
2343 putstr(win, 0, let_to_name(*invlet, TRUE, FALSE));
2347 totcost += cost = unpaid_cost(otmp, FALSE);
2348 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2349 putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
2350 ilet, TRUE, cost, 0L));
2351 iflags.suppress_price--;
2356 } while (flags.sortpack && (*++invlet));
2358 if (count > num_so_far) {
2359 /* something unpaid is contained */
2361 putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE, FALSE));
2363 * Search through the container objects in the inventory for
2364 * unpaid items. The top level inventory items have already
2367 for (otmp = invent; otmp; otmp = otmp->nobj) {
2368 if (Has_contents(otmp)) {
2371 marker = (struct obj *) 0; /* haven't found any */
2372 while (find_unpaid(otmp->cobj, &marker)) {
2373 totcost += cost = unpaid_cost(marker, FALSE);
2376 iflags.suppress_price++; /* suppress "(unpaid)" sfx */
2378 xprname(marker, distant_name(marker, doname),
2379 CONTAINED_SYM, TRUE, cost, 0L));
2380 iflags.suppress_price--;
2383 if (!otmp->cknown) {
2384 char contbuf[BUFSZ];
2386 /* Shopkeeper knows what to charge for contents */
2387 Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
2389 xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
2390 TRUE, contcost, 0L));
2398 xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
2399 display_nhwindow(win, FALSE);
2400 destroy_nhwindow(win);
2403 /* query objlist callback: return TRUE if obj type matches "this_type" */
2404 static int this_type;
2410 boolean res = (obj->oclass == this_type);
2412 if (obj->oclass != COIN_CLASS) {
2413 switch (this_type) {
2415 res = (obj->bknown && obj->blessed);
2418 res = (obj->bknown && !(obj->blessed || obj->cursed));
2421 res = (obj->bknown && obj->cursed);
2427 break; /* use 'res' as-is */
2433 /* the 'I' command */
2439 char *extra_types, types[BUFSZ];
2440 int class_count, oclass, unpaid_count, itemcount;
2441 int bcnt, ccnt, ucnt, xcnt, ocnt;
2442 boolean billx = *u.ushops && doinvbill(0);
2443 menu_item *pick_list;
2444 boolean traditional = TRUE;
2445 const char *prompt = "What type of object do you want an inventory of?";
2447 if (!invent && !billx) {
2448 You("aren't carrying anything.");
2451 unpaid_count = count_unpaid(invent);
2452 tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
2454 if (flags.menu_style != MENU_TRADITIONAL) {
2455 if (flags.menu_style == MENU_FULL
2456 || flags.menu_style == MENU_PARTIAL) {
2457 traditional = FALSE;
2469 n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
2472 this_type = c = pick_list[0].item.a_int;
2473 free((genericptr_t) pick_list);
2477 /* collect a list of classes of objects carried, for use as a prompt
2481 collect_obj_classes(types, invent, FALSE,
2482 (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
2483 if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
2484 types[class_count++] = ' ';
2486 types[class_count++] = 'u';
2488 types[class_count++] = 'x';
2490 types[class_count++] = 'B';
2492 types[class_count++] = 'U';
2494 types[class_count++] = 'C';
2496 types[class_count++] = 'X';
2497 types[class_count] = '\0';
2498 /* add everything not already included; user won't see these */
2499 extra_types = eos(types);
2500 *extra_types++ = '\033';
2502 *extra_types++ = 'u';
2504 *extra_types++ = 'x';
2506 *extra_types++ = 'B';
2508 *extra_types++ = 'U';
2510 *extra_types++ = 'C';
2512 *extra_types++ = 'X';
2513 *extra_types = '\0'; /* for index() */
2514 for (i = 0; i < MAXOCLASSES; i++)
2515 if (!index(types, def_oc_syms[i].sym)) {
2516 *extra_types++ = def_oc_syms[i].sym;
2517 *extra_types = '\0';
2520 if (class_count > 1) {
2521 c = yn_function(prompt, types, '\0');
2524 clear_nhwindow(WIN_MESSAGE);
2528 /* only one thing to itemize */
2537 if (c == 'x' || (c == 'X' && billx && !xcnt)) {
2539 (void) doinvbill(1);
2541 pline("No used-up objects%s.",
2542 unpaid_count ? " on your shopping bill" : "");
2545 if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) {
2549 You("are not carrying any unpaid objects.");
2553 if (index("BUCX", c))
2554 oclass = c; /* not a class but understood by this_type_only() */
2556 oclass = def_char_to_objclass(c); /* change to object class */
2558 if (oclass == COIN_CLASS)
2560 if (index(types, c) > index(types, '\033')) {
2561 /* '> ESC' => hidden choice, something known not to be carried */
2562 const char *which = 0;
2566 which = "known to be blessed";
2569 which = "known to be uncursed";
2572 which = "known to be cursed";
2576 "have no objects whose blessed/uncursed/cursed status is unknown.");
2577 break; /* better phrasing is desirable */
2583 You("have no %s objects.", which);
2588 if (query_objlist((char *) 0, invent,
2589 (flags.invlet_constant ? USE_INVLET : 0)
2591 &pick_list, PICK_NONE, this_type_only) > 0)
2592 free((genericptr_t) pick_list);
2596 /* return a string describing the dungeon feature at <x,y> if there
2597 is one worth mentioning at that location; otherwise null */
2599 dfeature_at(x, y, buf)
2603 struct rm *lev = &levl[x][y];
2604 int ltyp = lev->typ, cmap = -1;
2605 const char *dfeature = 0;
2606 static char altbuf[BUFSZ];
2608 if (IS_DOOR(ltyp)) {
2609 switch (lev->doormask) {
2612 break; /* "doorway" */
2615 break; /* "open door" */
2617 dfeature = "broken door";
2621 break; /* "closed door" */
2623 /* override door description for open drawbridge */
2624 if (is_drawbridge_wall(x, y) >= 0)
2625 dfeature = "open drawbridge portcullis", cmap = -1;
2626 } else if (IS_FOUNTAIN(ltyp))
2627 cmap = S_fountain; /* "fountain" */
2628 else if (IS_THRONE(ltyp))
2629 cmap = S_throne; /* "opulent throne" */
2630 else if (is_lava(x, y))
2631 cmap = S_lava; /* "molten lava" */
2632 else if (is_ice(x, y))
2633 cmap = S_ice; /* "ice" */
2634 else if (is_pool(x, y))
2635 dfeature = "pool of water";
2636 else if (IS_SINK(ltyp))
2637 cmap = S_sink; /* "sink" */
2638 else if (IS_ALTAR(ltyp)) {
2639 Sprintf(altbuf, "%saltar to %s (%s)",
2640 ((lev->altarmask & AM_SHRINE)
2641 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
2645 align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
2647 } else if ((x == xupstair && y == yupstair)
2648 || (x == sstairs.sx && y == sstairs.sy && sstairs.up))
2649 cmap = S_upstair; /* "staircase up" */
2650 else if ((x == xdnstair && y == ydnstair)
2651 || (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
2652 cmap = S_dnstair; /* "staircase down" */
2653 else if (x == xupladder && y == yupladder)
2654 cmap = S_upladder; /* "ladder up" */
2655 else if (x == xdnladder && y == ydnladder)
2656 cmap = S_dnladder; /* "ladder down" */
2657 else if (ltyp == DRAWBRIDGE_DOWN)
2658 cmap = S_vodbridge; /* "lowered drawbridge" */
2659 else if (ltyp == DBWALL)
2660 cmap = S_vcdbridge; /* "raised drawbridge" */
2661 else if (IS_GRAVE(ltyp))
2662 cmap = S_grave; /* "grave" */
2663 else if (ltyp == TREE)
2664 cmap = S_tree; /* "tree" */
2665 else if (ltyp == IRONBARS)
2666 dfeature = "set of iron bars";
2669 dfeature = defsyms[cmap].explanation;
2671 Strcpy(buf, dfeature);
2675 /* look at what is here; if there are many objects (pile_limit or more),
2676 don't show them unless obj_cnt is 0 */
2678 look_here(obj_cnt, picked_some)
2679 int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */
2680 boolean picked_some;
2684 const char *verb = Blind ? "feel" : "see";
2685 const char *dfeature = (char *) 0;
2686 char fbuf[BUFSZ], fbuf2[BUFSZ];
2688 boolean skip_objects, felt_cockatrice = FALSE;
2690 /* default pile_limit is 5; a value of 0 means "never skip"
2691 (and 1 effectively forces "always skip") */
2692 skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
2693 if (u.uswallow && u.ustuck) {
2694 struct monst *mtmp = u.ustuck;
2695 Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
2696 mbodypart(mtmp, STOMACH));
2697 /* Skip "Contents of " by using fbuf index 12 */
2698 You("%s to %s what is lying in %s.", Blind ? "try" : "look around",
2700 otmp = mtmp->minvent;
2702 for (; otmp; otmp = otmp->nobj) {
2703 /* If swallower is an animal, it should have become stone
2705 if (otmp->otyp == CORPSE)
2706 feel_cockatrice(otmp, FALSE);
2709 Strcpy(fbuf, "You feel");
2711 (void) display_minventory(mtmp, MINV_ALL, fbuf);
2713 You("%s no objects here.", verb);
2717 if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
2718 There("is %s here.",
2719 an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
2721 otmp = level.objects[u.ux][u.uy];
2722 dfeature = dfeature_at(u.ux, u.uy, fbuf2);
2723 if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
2727 boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
2729 if (dfeature && !strncmp(dfeature, "altar ", 6)) {
2730 /* don't say "altar" twice, dfeature has more info */
2731 You("try to feel what is here.");
2733 const char *where = (Blind && !can_reach_floor(TRUE))
2734 ? "lying beneath you"
2735 : "lying here on the ",
2736 *onwhat = (Blind && !can_reach_floor(TRUE))
2738 : surface(u.ux, u.uy);
2740 You("try to feel what is %s%s.", drift ? "floating here" : where,
2741 drift ? "" : onwhat);
2743 if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy)))
2744 dfeature = 0; /* ice already identified */
2745 if (!can_reach_floor(TRUE)) {
2746 pline("But you can't reach it!");
2752 Sprintf(fbuf, "There is %s here.", an(dfeature));
2754 if (!otmp || is_lava(u.ux, u.uy)
2755 || (is_pool(u.ux, u.uy) && !Underwater)) {
2758 read_engr_at(u.ux, u.uy); /* Eric Backus */
2759 if (!skip_objects && (Blind || !dfeature))
2760 You("%s no objects here.", verb);
2763 /* we know there is something here */
2768 read_engr_at(u.ux, u.uy); /* Eric Backus */
2769 if (obj_cnt == 1 && otmp->quan == 1L)
2770 There("is %s object here.", picked_some ? "another" : "an");
2772 There("are %s%s objects here.",
2778 picked_some ? " more" : "");
2779 for (; otmp; otmp = otmp->nexthere)
2780 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2787 corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
2788 poly_when_stoned(youmonst.data)
2790 : ", unfortunately");
2791 feel_cockatrice(otmp, FALSE);
2794 } else if (!otmp->nexthere) {
2795 /* only one object */
2798 read_engr_at(u.ux, u.uy); /* Eric Backus */
2799 You("%s here %s.", verb, doname_with_price(otmp));
2800 iflags.last_msg = PLNMSG_ONE_ITEM_HERE;
2801 if (otmp->otyp == CORPSE)
2802 feel_cockatrice(otmp, FALSE);
2806 display_nhwindow(WIN_MESSAGE, FALSE);
2807 tmpwin = create_nhwindow(NHW_MENU);
2809 putstr(tmpwin, 0, fbuf);
2810 putstr(tmpwin, 0, "");
2812 Sprintf(buf, "%s that %s here:",
2813 picked_some ? "Other things" : "Things",
2814 Blind ? "you feel" : "are");
2815 putstr(tmpwin, 0, buf);
2816 for (; otmp; otmp = otmp->nexthere) {
2817 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2818 felt_cockatrice = TRUE;
2819 Sprintf(buf, "%s...", doname(otmp));
2820 putstr(tmpwin, 0, buf);
2823 putstr(tmpwin, 0, doname_with_price(otmp));
2825 display_nhwindow(tmpwin, TRUE);
2826 destroy_nhwindow(tmpwin);
2827 if (felt_cockatrice)
2828 feel_cockatrice(otmp, FALSE);
2829 read_engr_at(u.ux, u.uy); /* Eric Backus */
2834 /* the ':' command - explicitly look at what is here, including all objects */
2838 return look_here(0, FALSE);
2842 will_feel_cockatrice(otmp, force_touch)
2844 boolean force_touch;
2846 if ((Blind || force_touch) && !uarmg && !Stone_resistance
2847 && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
2853 feel_cockatrice(otmp, force_touch)
2855 boolean force_touch;
2859 if (will_feel_cockatrice(otmp, force_touch)) {
2860 /* "the <cockatrice> corpse" */
2861 Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
2863 if (poly_when_stoned(youmonst.data))
2864 You("touched %s with your bare %s.", kbuf,
2865 makeplural(body_part(HAND)));
2867 pline("Touching %s is a fatal mistake...", kbuf);
2868 /* normalize body shape here; hand, not body_part(HAND) */
2869 Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp));
2870 /* will call polymon() for the poly_when_stoned() case */
2881 for (otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
2882 if (otmp != obj && merged(&obj, &otmp))
2887 /* returns TRUE if obj & otmp can be merged */
2890 register struct obj *otmp, *obj;
2892 int objnamelth = 0, otmpnamelth = 0;
2894 return FALSE; /* already the same object */
2895 if (obj->otyp != otmp->otyp)
2897 /* coins of the same kind will always merge */
2898 if (obj->oclass == COIN_CLASS)
2900 if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
2901 || obj->dknown != otmp->dknown
2902 || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
2903 || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
2904 || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
2905 || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
2906 || obj->greased != otmp->greased || obj->oeroded != otmp->oeroded
2907 || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass)
2910 if (obj->nomerge) /* explicitly marked to prevent merge */
2913 if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
2914 && (obj->oerodeproof != otmp->oerodeproof
2915 || obj->rknown != otmp->rknown))
2918 if (obj->oclass == FOOD_CLASS
2919 && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
2922 if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
2923 if (obj->corpsenm != otmp->corpsenm)
2927 /* hatching eggs don't merge; ditto for revivable corpses */
2928 if ((obj->otyp == EGG && (obj->timed || otmp->timed))
2929 || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM
2930 && is_reviver(&mons[otmp->corpsenm])))
2933 /* allow candle merging only if their ages are close */
2934 /* see begin_burn() for a reference for the magic "25" */
2935 if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
2938 /* burning potions of oil never merge */
2939 if (obj->otyp == POT_OIL && obj->lamplit)
2942 /* don't merge surcharged item with base-cost item */
2943 if (obj->unpaid && !same_price(obj, otmp))
2946 /* if they have names, make sure they're the same */
2947 objnamelth = strlen(safe_oname(obj));
2948 otmpnamelth = strlen(safe_oname(otmp));
2949 if ((objnamelth != otmpnamelth
2950 && ((objnamelth && otmpnamelth) || obj->otyp == CORPSE))
2951 || (objnamelth && otmpnamelth
2952 && strncmp(ONAME(obj), ONAME(otmp), objnamelth)))
2955 /* for the moment, any additional information is incompatible */
2956 if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || has_omonst(otmp)
2957 || has_omid(otmp) || has_olong(otmp))
2960 if (obj->oartifact != otmp->oartifact)
2963 if (obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) {
2964 return (boolean) objects[obj->otyp].oc_merge;
2969 /* the '$' command */
2973 /* the messages used to refer to "carrying gold", but that didn't
2974 take containers into account */
2975 long umoney = money_cnt(invent);
2977 Your("wallet is empty.");
2979 Your("wallet contains %ld %s.", umoney, currency(umoney));
2980 shopper_financial_report();
2984 /* the ')' command */
2989 You("are empty %s.", body_part(HANDED));
2991 prinv((char *) 0, uwep, 0L);
2993 prinv((char *) 0, uswapwep, 0L);
2998 /* caller is responsible for checking !wearing_armor() */
3000 noarmor(report_uskin)
3001 boolean report_uskin;
3003 if (!uskin || !report_uskin) {
3004 You("are not wearing any armor.");
3006 char *p, *uskinname, buf[BUFSZ];
3008 uskinname = strcpy(buf, simpleonames(uskin));
3009 /* shorten "set of <color> dragon scales" to "<color> scales"
3010 and "<color> dragon scale mail" to "<color> scale mail" */
3011 if (!strncmpi(uskinname, "set of ", 7))
3013 if ((p = strstri(uskinname, " dragon ")) != 0)
3014 while ((p[1] = p[8]) != '\0')
3017 You("are not wearing armor but have %s embedded in your skin.",
3022 /* the '[' command */
3027 register int ct = 0;
3029 * Note: players sometimes get here by pressing a function key which
3030 * transmits ''ESC [ <something>'' rather than by pressing '[';
3031 * there's nothing we can--or should-do about that here.
3034 if (!wearing_armor()) {
3038 lets[ct++] = obj_to_let(uarmu);
3040 lets[ct++] = obj_to_let(uarm);
3042 lets[ct++] = obj_to_let(uarmc);
3044 lets[ct++] = obj_to_let(uarmh);
3046 lets[ct++] = obj_to_let(uarms);
3048 lets[ct++] = obj_to_let(uarmg);
3050 lets[ct++] = obj_to_let(uarmf);
3052 (void) display_inventory(lets, FALSE);
3057 /* the '=' command */
3061 if (!uleft && !uright)
3062 You("are not wearing any rings.");
3065 register int ct = 0;
3068 lets[ct++] = obj_to_let(uleft);
3070 lets[ct++] = obj_to_let(uright);
3072 (void) display_inventory(lets, FALSE);
3077 /* the '"' command */
3082 You("are not wearing an amulet.");
3084 prinv((char *) 0, uamul, 0L);
3092 if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L)
3094 if (obj->oclass != TOOL_CLASS)
3096 return (boolean) (obj == uwep || obj->lamplit
3097 || (obj->otyp == LEASH && obj->leashmon));
3100 /* the '(' command */
3108 for (otmp = invent; otmp; otmp = otmp->nobj)
3109 if (tool_in_use(otmp))
3110 lets[ct++] = obj_to_let(otmp);
3113 You("are not using any tools.");
3115 (void) display_inventory(lets, FALSE);
3119 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3120 show inventory of all currently wielded, worn, or used objects */
3128 for (otmp = invent; otmp; otmp = otmp->nobj)
3129 if (is_worn(otmp) || tool_in_use(otmp))
3130 lets[ct++] = obj_to_let(otmp);
3133 You("are not wearing or wielding anything.");
3135 (void) display_inventory(lets, FALSE);
3140 * uses up an object that's on the floor, charging for it as necessary
3143 useupf(obj, numused)
3144 register struct obj *obj;
3147 register struct obj *otmp;
3148 boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
3150 /* burn_floor_objects() keeps an object pointer that it tries to
3151 * useupf() multiple times, so obj must survive if plural */
3152 if (obj->quan > numused)
3153 otmp = splitobj(obj, numused);
3156 if (costly_spot(otmp->ox, otmp->oy)) {
3157 if (index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
3158 addtobill(otmp, FALSE, FALSE, FALSE);
3160 (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
3163 if (at_u && u.uundetected && hides_under(youmonst.data))
3164 (void) hideunder(&youmonst);
3168 * Conversion from a class to a string for printing.
3169 * This must match the object class order.
3171 STATIC_VAR NEARDATA const char *names[] = {
3172 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
3173 "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
3174 "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
3177 static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
3179 static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
3181 static NEARDATA char *invbuf = (char *) 0;
3182 static NEARDATA unsigned invbufsiz = 0;
3185 let_to_name(let, unpaid, showsym)
3187 boolean unpaid, showsym;
3189 const char *ocsymfmt = " ('%c')";
3190 const int invbuf_sympadding = 8; /* arbitrary */
3191 const char *class_name;
3193 int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
3197 class_name = names[oclass];
3198 else if ((pos = index(oth_symbols, let)) != 0)
3199 class_name = oth_names[pos - oth_symbols];
3201 class_name = names[0];
3203 len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "")
3204 + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0);
3205 if (len > invbufsiz) {
3207 free((genericptr_t) invbuf);
3208 invbufsiz = len + 10; /* add slop to reduce incremental realloc */
3209 invbuf = (char *) alloc(invbufsiz);
3212 Strcat(strcpy(invbuf, "Unpaid "), class_name);
3214 Strcpy(invbuf, class_name);
3215 if ((oclass != 0) && showsym) {
3216 char *bp = eos(invbuf);
3217 int mlen = invbuf_sympadding - strlen(class_name);
3218 while (--mlen > 0) {
3223 Sprintf(eos(invbuf), ocsymfmt, def_oc_syms[oclass].sym);
3228 /* release the static buffer used by let_to_name() */
3233 free((genericptr_t) invbuf), invbuf = (char *) 0;
3237 /* give consecutive letters to every item in inventory (for !fixinv mode);
3238 gold is always forced to '$' slot at head of list */
3243 struct obj *obj, *prevobj, *goldobj;
3245 /* first, remove [first instance of] gold from invent, if present */
3246 prevobj = goldobj = 0;
3247 for (obj = invent; obj; prevobj = obj, obj = obj->nobj)
3248 if (obj->oclass == COIN_CLASS) {
3251 prevobj->nobj = goldobj->nobj;
3253 invent = goldobj->nobj;
3256 /* second, re-letter the rest of the list */
3257 for (obj = invent, i = 0; obj; obj = obj->nobj, i++)
3259 (i < 26) ? ('a' + i) : (i < 52) ? ('A' + i - 26) : NOINVSYM;
3260 /* third, assign gold the "letter" '$' and re-insert it at head */
3262 goldobj->invlet = GOLD_SYM;
3263 goldobj->nobj = invent;
3273 * User specifies a 'from' slot for inventory stack to move,
3274 * then a 'to' slot for its destination. Open slots and those
3275 * filled by compatible stacks are listed as likely candidates
3276 * but user can pick any inventory letter (including 'from').
3277 * All compatible items found are gathered into the 'from'
3278 * stack as it is moved. If the 'to' slot isn't empty and
3279 * doesn't merge, then its stack is swapped to the 'from' slot.
3281 * If the user specifies a count when choosing the 'from' slot,
3282 * and that count is less than the full size of the stack,
3283 * then the stack will be split. The 'count' portion is moved
3284 * to the destination, and the only candidate for merging with
3285 * it is the stack already at the 'to' slot, if any. When the
3286 * destination is non-empty but won't merge, whatever is there
3287 * will be moved to an open slot; if there isn't any open slot
3288 * available, the adjustment attempt fails.
3290 * Splitting has one special case: if 'to' slot is non-empty
3291 * and is compatible with 'from' in all respects except for
3292 * user-assigned names, the 'count' portion being moved is
3293 * effectively renamed so that it will merge with 'to' stack.
3296 doorganize() /* inventory organizer by Del Lamb */
3298 struct obj *obj, *otmp, *splitting, *bumped;
3299 int ix, cur, trycnt;
3301 char alphabet[52 + 1], buf[52 + 1];
3303 char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
3304 const char *adj_type;
3307 You("aren't carrying anything to adjust.");
3311 if (!flags.invlet_constant)
3313 /* get object the user wants to organize (the 'from' slot) */
3314 allowall[0] = ALLOW_COUNT;
3315 allowall[1] = ALL_CLASSES;
3317 if (!(obj = getobj(allowall, "adjust")))
3320 /* figure out whether user gave a split count to getobj() */
3321 splitting = bumped = 0;
3322 for (otmp = invent; otmp; otmp = otmp->nobj)
3323 if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
3324 if (otmp->invlet == obj->invlet)
3329 /* initialize the list with all lower and upper case letters */
3330 for (ix = 0, let = 'a'; let <= 'z';)
3331 alphabet[ix++] = let++;
3332 for (let = 'A'; let <= 'Z';)
3333 alphabet[ix++] = let++;
3334 alphabet[ix] = '\0';
3335 /* for floating inv letters, truncate list after the first open slot */
3336 if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52)
3337 alphabet[ix + (splitting ? 0 : 1)] = '\0';
3339 /* blank out all the letters currently in use in the inventory */
3340 /* except those that will be merged with the selected object */
3341 for (otmp = invent; otmp; otmp = otmp->nobj)
3342 if (otmp != obj && !mergable(otmp, obj)) {
3344 if (let >= 'a' && let <= 'z')
3345 alphabet[let - 'a'] = ' ';
3346 else if (let >= 'A' && let <= 'Z')
3347 alphabet[let - 'A' + 26] = ' ';
3350 /* compact the list by removing all the blanks */
3351 for (ix = cur = 0; alphabet[ix]; ix++)
3352 if (alphabet[ix] != ' ')
3353 buf[cur++] = alphabet[ix];
3354 if (!cur && obj->invlet == NOINVSYM)
3355 buf[cur++] = NOINVSYM;
3357 /* and by dashing runs of letters */
3361 /* get 'to' slot to use as destination */
3362 Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf,
3363 invent ? " (? see used letters)" : "");
3364 for (trycnt = 1; ; ++trycnt) {
3365 let = yn_function(qbuf, (char *) 0, '\0');
3366 if (let == '?' || let == '*') {
3367 let = display_used_invlets(splitting ? obj->invlet : 0);
3373 if (index(quitchars, let)
3374 /* adjusting to same slot is meaningful since all
3375 compatible stacks get collected along the way,
3376 but splitting to same slot is not */
3377 || (splitting && let == obj->invlet)) {
3380 (void) merged(&splitting, &obj);
3384 if ((letter(let) && let != '@') || index(buf, let))
3385 break; /* got one */
3388 pline("Select an inventory slot letter."); /* else try again */
3391 /* change the inventory and print the resulting item */
3392 adj_type = !splitting ? "Moving:" : "Splitting:";
3395 * don't use freeinv/addinv to avoid double-touching artifacts,
3396 * dousing lamps, losing luck, cursing loadstone, etc.
3398 extract_nobj(obj, &invent);
3400 for (otmp = invent; otmp;) {
3402 if (merged(&otmp, &obj)) {
3403 adj_type = "Merging:";
3406 extract_nobj(obj, &invent);
3407 continue; /* otmp has already been updated */
3408 } else if (otmp->invlet == let) {
3409 adj_type = "Swapping:";
3410 otmp->invlet = obj->invlet;
3413 /* splitting: don't merge extra compatible stacks;
3414 if destination is compatible, do merge with it,
3415 otherwise bump whatever is there to an open slot */
3416 if (otmp->invlet == let) {
3420 olth = strlen(ONAME(obj));
3421 /* ugly hack: if these objects aren't going to merge
3422 solely because they have conflicting user-assigned
3423 names, strip off the name of the one being moved */
3424 if (olth && !obj->oartifact && !mergable(otmp, obj)) {
3425 char *holdname = ONAME(obj);
3426 ONAME(obj) = (char *) 0;
3427 /* restore name iff merging is still not possible */
3428 if (!mergable(otmp, obj)) {
3429 ONAME(obj) = holdname;
3430 holdname = (char *) 0;
3432 free((genericptr_t) holdname);
3435 if (merged(&otmp, &obj)) {
3437 extract_nobj(obj, &invent);
3438 } else if (inv_cnt(FALSE) >= 52) {
3439 (void) merged(&splitting, &obj); /* undo split */
3440 /* "knapsack cannot accommodate any more items" */
3441 Your("pack is too full.");
3445 extract_nobj(bumped, &invent);
3448 } /* found 'to' slot */
3453 /* inline addinv; insert loose object at beginning of inventory */
3456 obj->where = OBJ_INVENT;
3460 /* splitting the 'from' stack is causing an incompatible
3461 stack in the 'to' slot to be moved into an open one;
3462 we need to do another inline insertion to inventory */
3463 assigninvlet(bumped);
3464 bumped->nobj = invent;
3465 bumped->where = OBJ_INVENT;
3470 /* messages deferred until inventory has been fully reestablished */
3471 prinv(adj_type, obj, 0L);
3473 prinv("Moving:", bumped, 0L);
3475 clear_splitobjs(); /* reset splitobj context */
3480 /* common to display_minventory and display_cinventory */
3482 invdisp_nothing(hdr, txt)
3483 const char *hdr, *txt;
3487 menu_item *selected;
3490 win = create_nhwindow(NHW_MENU);
3492 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr,
3494 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3495 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
3496 end_menu(win, (char *) 0);
3497 if (select_menu(win, PICK_NONE, &selected) > 0)
3498 free((genericptr_t) selected);
3499 destroy_nhwindow(win);
3503 /* query_objlist callback: return things that are worn or wielded */
3505 worn_wield_only(obj)
3509 /* check for things that *are* worn or wielded (only used for monsters,
3510 so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
3511 return (boolean) (obj->owornmask != 0L);
3513 /* this used to check for things that *might* be worn or wielded,
3514 but that's not particularly interesting */
3515 if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING)
3517 return (boolean) (obj->oclass == WEAPON_CLASS
3518 || obj->oclass == ARMOR_CLASS
3519 || obj->oclass == AMULET_CLASS
3520 || obj->oclass == RING_CLASS);
3525 * Display a monster's inventory.
3526 * Returns a pointer to the object from the monster's inventory selected
3527 * or NULL if nothing was selected.
3529 * By default, only worn and wielded items are displayed. The caller
3530 * can pick one. Modifier flags are:
3532 * MINV_NOLET - nothing selectable
3533 * MINV_ALL - display all inventory
3536 display_minventory(mon, dflags, title)
3537 register struct monst *mon;
3544 menu_item *selected = 0;
3545 int do_all = (dflags & MINV_ALL) != 0,
3546 incl_hero = (do_all && u.uswallow && mon == u.ustuck),
3547 have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero);
3549 Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
3550 do_all ? "possessions" : "armament");
3552 if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) {
3553 /* Fool the 'weapon in hand' routine into
3554 * displaying 'weapon in claw', etc. properly.
3556 youmonst.data = mon->data;
3558 n = query_objlist(title ? title : tmp, mon->minvent,
3559 INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0),
3561 (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
3562 do_all ? allow_all : worn_wield_only);
3566 invdisp_nothing(title ? title : tmp, "(none)");
3571 ret = selected[0].item.a_obj;
3572 free((genericptr_t) selected);
3574 ret = (struct obj *) 0;
3579 * Display the contents of a container in inventory style.
3580 * Currently, this is only used for statues, via wand of probing.
3583 display_cinventory(obj)
3584 register struct obj *obj;
3589 menu_item *selected = 0;
3591 (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
3595 n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected,
3596 PICK_NONE, allow_all);
3598 invdisp_nothing(qbuf, "(empty)");
3602 ret = selected[0].item.a_obj;
3603 free((genericptr_t) selected);
3605 ret = (struct obj *) 0;
3610 /* query objlist callback: return TRUE if obj is at given location */
3617 return (obj->ox == only.x && obj->oy == only.y);
3621 * Display a list of buried items in inventory style. Return a non-zero
3622 * value if there were items at that spot.
3624 * Currently, this is only used with a wand of probing zapped downwards.
3627 display_binventory(x, y, as_if_seen)
3632 menu_item *selected = 0;
3635 /* count # of objects here */
3636 for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
3637 if (obj->ox == x && obj->oy == y) {
3646 if (query_objlist("Things that are buried here:", level.buriedobjlist,
3647 INVORDER_SORT, &selected, PICK_NONE, only_here) > 0)
3648 free((genericptr_t) selected);
3649 only.x = only.y = 0;