1 /* NetHack 3.6 pickup.c $NHDT-Date: 1457400916 2016/03/08 01:35:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.171 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
6 * Contains code for picking objects up, and container use.
11 #define CONTAINED_SYM '>' /* from invent.c */
13 STATIC_DCL
void FDECL(simple_look
, (struct obj
*, BOOLEAN_P
));
14 STATIC_DCL boolean
FDECL(query_classes
, (char *, boolean
*, boolean
*,
15 const char *, struct obj
*,
17 STATIC_DCL boolean
FDECL(fatal_corpse_mistake
, (struct obj
*, BOOLEAN_P
));
18 STATIC_DCL
void FDECL(check_here
, (BOOLEAN_P
));
19 STATIC_DCL boolean
FDECL(n_or_more
, (struct obj
*));
20 STATIC_DCL boolean
FDECL(all_but_uchain
, (struct obj
*));
22 STATIC_DCL boolean
FDECL(allow_cat_no_uchain
, (struct obj
*));
24 STATIC_DCL
int FDECL(autopick
, (struct obj
*, int, menu_item
**));
25 STATIC_DCL
int FDECL(count_categories
, (struct obj
*, int));
26 STATIC_DCL
long FDECL(carry_count
, (struct obj
*, struct obj
*, long,
27 BOOLEAN_P
, int *, int *));
28 STATIC_DCL
int FDECL(lift_object
, (struct obj
*, struct obj
*, long *,
30 STATIC_DCL boolean
FDECL(mbag_explodes
, (struct obj
*, int));
31 STATIC_PTR
int FDECL(in_container
, (struct obj
*));
32 STATIC_PTR
int FDECL(out_container
, (struct obj
*));
33 STATIC_DCL
void FDECL(removed_from_icebox
, (struct obj
*));
34 STATIC_DCL
long FDECL(mbag_item_gone
, (int, struct obj
*));
35 STATIC_DCL
void FDECL(observe_quantum_cat
, (struct obj
*));
36 STATIC_DCL
void FDECL(explain_container_prompt
, (BOOLEAN_P
));
37 STATIC_DCL
int FDECL(traditional_loot
, (BOOLEAN_P
));
38 STATIC_DCL
int FDECL(menu_loot
, (int, BOOLEAN_P
));
39 STATIC_DCL
char FDECL(in_or_out_menu
, (const char *, struct obj
*, BOOLEAN_P
,
40 BOOLEAN_P
, BOOLEAN_P
, BOOLEAN_P
));
41 STATIC_DCL
int FDECL(container_at
, (int, int, BOOLEAN_P
));
42 STATIC_DCL boolean
FDECL(able_to_loot
, (int, int, BOOLEAN_P
));
43 STATIC_DCL boolean
NDECL(reverse_loot
);
44 STATIC_DCL boolean
FDECL(mon_beside
, (int, int));
45 STATIC_DCL
int FDECL(do_loot_cont
, (struct obj
**, int, int));
46 STATIC_DCL
void FDECL(tipcontainer
, (struct obj
*));
48 /* define for query_objlist() and autopickup() */
49 #define FOLLOW(curr, flags) \
50 (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
53 * How much the weight of the given container will change when the given
54 * object is removed from it. This calculation must match the one used
55 * by weight() in mkobj.c.
57 #define DELTA_CWT(cont, obj) \
58 ((cont)->cursed ? (obj)->owt * 2 : (cont)->blessed \
59 ? ((obj)->owt + 3) / 4 \
60 : ((obj)->owt + 1) / 2)
61 #define GOLD_WT(n) (((n) + 50L) / 100L)
62 /* if you can figure this out, give yourself a hearty pat on the back... */
63 #define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L)
65 /* A variable set in use_container(), to be used by the callback routines
66 in_container() and out_container() from askchain() and use_container().
67 Also used by menu_loot() and container_gone(). */
68 static NEARDATA
struct obj
*current_container
;
69 static NEARDATA boolean abort_looting
;
70 #define Icebox (current_container->otyp == ICE_BOX)
73 moderateloadmsg
[] = "You have a little trouble lifting",
74 nearloadmsg
[] = "You have much trouble lifting",
75 overloadmsg
[] = "You have extreme difficulty lifting";
77 /* BUG: this lets you look at cockatrice corpses while blind without
79 /* much simpler version of the look-here code; used by query_classes() */
81 simple_look(otmp
, here
)
82 struct obj
*otmp
; /* list of objects */
83 boolean here
; /* flag for type of obj list linkage */
85 /* Neither of the first two cases is expected to happen, since
86 * we're only called after multiple classes of objects have been
87 * detected, hence multiple objects must be present.
90 impossible("simple_look(null)");
91 } else if (!(here
? otmp
->nexthere
: otmp
->nobj
)) {
94 winid tmpwin
= create_nhwindow(NHW_MENU
);
96 putstr(tmpwin
, 0, "");
98 putstr(tmpwin
, 0, doname(otmp
));
99 otmp
= here
? otmp
->nexthere
: otmp
->nobj
;
101 display_nhwindow(tmpwin
, TRUE
);
102 destroy_nhwindow(tmpwin
);
107 collect_obj_classes(ilets
, otmp
, here
, filter
, itemcount
)
109 register struct obj
*otmp
;
111 boolean
FDECL((*filter
), (OBJ_P
));
114 register int iletct
= 0;
118 ilets
[iletct
] = '\0'; /* terminate ilets so that index() will work */
120 c
= def_oc_syms
[(int) otmp
->oclass
].sym
;
121 if (!index(ilets
, c
) && (!filter
|| (*filter
)(otmp
)))
122 ilets
[iletct
++] = c
, ilets
[iletct
] = '\0';
124 otmp
= here
? otmp
->nexthere
: otmp
->nobj
;
131 * Suppose some '?' and '!' objects are present, but '/' objects aren't:
132 * "a" picks all items without further prompting;
133 * "A" steps through all items, asking one by one;
134 * "?" steps through '?' items, asking, and ignores '!' ones;
135 * "/" becomes 'A', since no '/' present;
136 * "?a" or "a?" picks all '?' without further prompting;
137 * "/a" or "a/" becomes 'A' since there aren't any '/'
138 * (bug fix: 3.1.0 thru 3.1.3 treated it as "a");
139 * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
140 * (ie, treated as if it had just been "?a").
143 query_classes(oclasses
, one_at_a_time
, everything
, action
, objs
, here
,
146 boolean
*one_at_a_time
, *everything
;
152 char ilets
[30], inbuf
[BUFSZ
]; /* FIXME: hardcoded ilets[] length */
153 int iletct
, oclassct
;
154 boolean not_everything
;
159 oclasses
[oclassct
= 0] = '\0';
160 *one_at_a_time
= *everything
= m_seen
= FALSE
;
161 iletct
= collect_obj_classes(ilets
, objs
, here
,
162 (boolean
FDECL((*), (OBJ_P
))) 0, &itemcount
);
165 } else if (iletct
== 1) {
166 oclasses
[0] = def_char_to_objclass(ilets
[0]);
168 if (itemcount
&& menu_on_demand
) {
169 ilets
[iletct
++] = 'm';
171 ilets
[iletct
] = '\0';
173 } else { /* more than one choice available */
174 const char *where
= 0;
175 char sym
, oc_of_sym
, *p
;
177 /* additional choices */
178 ilets
[iletct
++] = ' ';
179 ilets
[iletct
++] = 'a';
180 ilets
[iletct
++] = 'A';
181 ilets
[iletct
++] = (objs
== invent
? 'i' : ':');
182 if (menu_on_demand
) {
183 ilets
[iletct
++] = 'm';
186 ilets
[iletct
] = '\0';
188 oclasses
[oclassct
= 0] = '\0';
189 *one_at_a_time
= *everything
= FALSE
;
190 not_everything
= FALSE
;
191 Sprintf(qbuf
, "What kinds of thing do you want to %s? [%s]", action
,
194 if (*inbuf
== '\033')
197 for (p
= inbuf
; (sym
= *p
++) != 0; ) {
201 *one_at_a_time
= TRUE
;
204 else if (sym
== ':') {
205 simple_look(objs
, here
); /* dumb if objs==invent */
206 /* if we just scanned the contents of a container
207 then mark it as having known contents */
208 if (objs
->where
== OBJ_CONTAINED
)
209 objs
->ocontainer
->cknown
= 1;
211 } else if (sym
== 'i') {
212 (void) display_inventory((char *) 0, TRUE
);
214 } else if (sym
== 'm') {
217 oc_of_sym
= def_char_to_objclass(sym
);
218 if (index(ilets
, sym
)) {
219 add_valid_menu_class(oc_of_sym
);
220 oclasses
[oclassct
++] = oc_of_sym
;
221 oclasses
[oclassct
] = '\0';
224 where
= !strcmp(action
, "pick up") ? "here"
225 : !strcmp(action
, "take out") ? "inside" : "";
227 There("are no %c's %s.", sym
, where
);
229 You("have no %c's.", sym
);
230 not_everything
= TRUE
;
234 if (m_seen
&& menu_on_demand
) {
235 *menu_on_demand
= (*everything
|| !oclassct
) ? -2 : -3;
238 if (!oclassct
&& (!*everything
|| not_everything
)) {
239 /* didn't pick anything,
240 or tried to pick something that's not present */
241 *one_at_a_time
= TRUE
; /* force 'A' */
242 *everything
= FALSE
; /* inhibit 'a' */
248 /* check whether hero is bare-handedly touching a cockatrice corpse */
250 fatal_corpse_mistake(obj
, remotely
)
254 if (uarmg
|| remotely
|| obj
->otyp
!= CORPSE
255 || !touch_petrifies(&mons
[obj
->corpsenm
]) || Stone_resistance
)
258 if (poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
)) {
259 display_nhwindow(WIN_MESSAGE
, FALSE
); /* --More-- */
263 pline("Touching %s is a fatal mistake.",
264 corpse_xname(obj
, (const char *) 0, CXN_SINGULAR
| CXN_ARTICLE
));
265 instapetrify(killer_xname(obj
));
269 /* attempting to manipulate a Rider's corpse triggers its revival */
271 rider_corpse_revival(obj
, remotely
)
275 if (!obj
|| obj
->otyp
!= CORPSE
|| !is_rider(&mons
[obj
->corpsenm
]))
278 pline("At your %s, the corpse suddenly moves...",
279 remotely
? "attempted acquisition" : "touch");
280 (void) revive_corpse(obj
);
281 exercise(A_WIS
, FALSE
);
285 /* look at the objects at our location, unless there are too many of them */
287 check_here(picked_some
)
290 register struct obj
*obj
;
293 /* count the objects here */
294 for (obj
= level
.objects
[u
.ux
][u
.uy
]; obj
; obj
= obj
->nexthere
) {
299 /* If there are objects here, take a look. */
304 (void) look_here(ct
, picked_some
);
306 read_engr_at(u
.ux
, u
.uy
);
310 /* Value set by query_objlist() for n_or_more(). */
311 static long val_for_n_or_more
;
313 /* query_objlist callback: return TRUE if obj's count is >= reference value */
320 return (boolean
) (obj
->quan
>= val_for_n_or_more
);
323 /* list of valid menu classes for query_objlist() and allow_category callback
324 (with room for all object classes, 'u'npaid, BUCX, and terminator) */
325 static char valid_menu_classes
[MAXOCLASSES
+ 1 + 4 + 1];
326 static boolean class_filter
, bucx_filter
, shop_filter
;
329 add_valid_menu_class(c
)
332 static int vmc_count
= 0;
334 if (c
== 0) { /* reset */
336 class_filter
= bucx_filter
= shop_filter
= FALSE
;
338 valid_menu_classes
[vmc_count
++] = (char) c
;
339 /* categorize the new class */
343 case 'C': /*FALLTHRU*/
355 valid_menu_classes
[vmc_count
] = '\0';
358 /* query_objlist callback: return TRUE if not uchain */
363 return (boolean
) (obj
!= uchain
);
366 /* query_objlist callback: return TRUE */
370 struct obj
*obj UNUSED
;
379 /* unpaid and BUC checks don't apply to coins */
380 if (obj
->oclass
== COIN_CLASS
)
381 return index(valid_menu_classes
, COIN_CLASS
) ? TRUE
: FALSE
;
383 if (Role_if(PM_PRIEST
))
387 * There are three types of filters possible and the first and
388 * third can have more than one entry:
389 * 1) object class (armor, potion, &c);
390 * 2) unpaid shop item;
391 * 3) bless/curse state (blessed, uncursed, cursed, BUC-unknown).
392 * When only one type is present, the situation is simple:
393 * to be accepted, obj's status must match one of the entries.
394 * When more than one type is present, the obj will now only
395 * be accepted when it matches one entry of each type.
396 * So ?!B will accept blessed scrolls or potions, and [u will
397 * accept unpaid armor. (In 3.4.3, an object was accepted by
398 * this filter if it met any entry of any type, so ?!B resulted
399 * in accepting all scrolls and potions regardless of bless/curse
400 * state plus all blessed non-scroll, non-potion objects.)
403 /* if class is expected but obj's class is not in the list, reject */
404 if (class_filter
&& !index(valid_menu_classes
, obj
->oclass
))
406 /* if unpaid is expected and obj isn't unpaid, reject (treat a container
407 holding any unpaid object as unpaid even if isn't unpaid itself) */
408 if (shop_filter
&& !obj
->unpaid
409 && !(Has_contents(obj
) && count_unpaid(obj
->cobj
) > 0))
411 /* check for particular bless/curse state */
413 /* first categorize this object's bless/curse state */
414 char bucx
= !obj
->bknown
? 'X'
415 : obj
->blessed
? 'B' : obj
->cursed
? 'C' : 'U';
417 /* if its category is not in the list, reject */
418 if (!index(valid_menu_classes
, bucx
))
421 /* obj didn't fail any of the filter checks, so accept */
426 /* query_objlist callback: return TRUE if valid category (class), no uchain */
428 allow_cat_no_uchain(obj
)
432 && ((index(valid_menu_classes
,'u') && obj
->unpaid
)
433 || index(valid_menu_classes
, obj
->oclass
)))
439 /* query_objlist callback: return TRUE if valid class and worn */
441 is_worn_by_type(otmp
)
442 register struct obj
*otmp
;
444 return (boolean
) (!!(otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_WEAPON
))
445 && index(valid_menu_classes
, otmp
->oclass
) != 0);
449 * Have the hero pick things from the ground
450 * or a monster's inventory if swallowed.
455 * <0 pickup count of something
457 * Returns 1 if tried to pick something up, whether
458 * or not it succeeded.
462 int what
; /* should be a long */
464 int i
, n
, res
, count
, n_tried
= 0, n_picked
= 0;
465 menu_item
*pick_list
= (menu_item
*) 0;
466 boolean autopickup
= what
> 0;
467 struct obj
*objchain
;
470 /* we might have arrived here while fainted or sleeping, via
471 random teleport or levitation timeout; if so, skip check_here
472 and read_engr_at in addition to bypassing autopickup itself
473 [probably ought to check whether hero is using a cockatrice
474 corpse for a pillow here... (also at initial faint/sleep)] */
475 if (autopickup
&& multi
< 0 && unconscious())
478 if (what
< 0) /* pick N of something */
480 else /* pick anything */
486 /* no auto-pick if no-pick move, nothing there, or in a pool */
487 if (autopickup
&& (context
.nopick
|| !OBJ_AT(u
.ux
, u
.uy
)
488 || (is_pool(u
.ux
, u
.uy
) && !Underwater
)
489 || is_lava(u
.ux
, u
.uy
))) {
490 read_engr_at(u
.ux
, u
.uy
);
493 /* no pickup if levitating & not on air or water level */
494 if (!can_reach_floor(TRUE
)) {
495 if ((multi
&& !context
.run
) || (autopickup
&& !flags
.pickup
)
496 || ((ttmp
= t_at(u
.ux
, u
.uy
)) != 0
497 && uteetering_at_seen_pit(ttmp
)))
498 read_engr_at(u
.ux
, u
.uy
);
501 /* multi && !context.run means they are in the middle of some other
502 * action, or possibly paralyzed, sleeping, etc.... and they just
503 * teleported onto the object. They shouldn't pick it up.
505 if ((multi
&& !context
.run
) || (autopickup
&& !flags
.pickup
)) {
509 if (notake(youmonst
.data
)) {
511 You("are physically incapable of picking anything up.");
517 /* if there's anything here, stop running */
518 if (OBJ_AT(u
.ux
, u
.uy
) && context
.run
&& context
.run
!= 8
523 add_valid_menu_class(0); /* reset */
525 objchain
= level
.objects
[u
.ux
][u
.uy
];
526 traverse_how
= BY_NEXTHERE
;
528 objchain
= u
.ustuck
->minvent
;
529 traverse_how
= 0; /* nobj */
532 * Start the actual pickup process. This is split into two main
533 * sections, the newer menu and the older "traditional" methods.
534 * Automatic pickup has been split into its own menu-style routine
535 * to make things less confusing.
538 n
= autopick(objchain
, traverse_how
, &pick_list
);
542 if (flags
.menu_style
!= MENU_TRADITIONAL
|| iflags
.menu_requested
) {
543 /* use menus exclusively */
544 traverse_how
|= AUTOSELECT_SINGLE
| INVORDER_SORT
;
545 if (count
) { /* looking for N of something */
548 Sprintf(qbuf
, "Pick %d of what?", count
);
549 val_for_n_or_more
= count
; /* set up callback selector */
550 n
= query_objlist(qbuf
, &objchain
, traverse_how
,
551 &pick_list
, PICK_ONE
, n_or_more
);
552 /* correct counts, if any given */
553 for (i
= 0; i
< n
; i
++)
554 pick_list
[i
].count
= count
;
556 n
= query_objlist("Pick up what?", &objchain
,
557 (traverse_how
| FEEL_COCKATRICE
),
558 &pick_list
, PICK_ANY
, all_but_uchain
);
562 for (n_picked
= i
= 0; i
< n
; i
++) {
563 res
= pickup_object(pick_list
[i
].item
.a_obj
, pick_list
[i
].count
,
566 break; /* can't continue */
570 free((genericptr_t
) pick_list
);
573 /* old style interface */
576 boolean all_of_a_type
, selective
;
577 char oclasses
[MAXOCLASSES
];
578 struct obj
*obj
, *obj2
;
580 oclasses
[0] = '\0'; /* types to consider (empty for all) */
581 all_of_a_type
= TRUE
; /* take all of considered types */
582 selective
= FALSE
; /* ask for each item */
584 /* check for more than one object */
585 for (obj
= objchain
; obj
; obj
= FOLLOW(obj
, traverse_how
))
588 if (ct
== 1 && count
) {
589 /* if only one thing, then pick it */
591 lcount
= min(obj
->quan
, (long) count
);
593 if (pickup_object(obj
, lcount
, FALSE
) > 0)
594 n_picked
++; /* picked something */
597 } else if (ct
>= 2) {
600 There("are %s objects here.", (ct
<= 10) ? "several" : "many");
601 if (!query_classes(oclasses
, &selective
, &all_of_a_type
,
603 (traverse_how
& BY_NEXTHERE
) ? TRUE
: FALSE
,
608 traverse_how
|= INVORDER_SORT
;
609 n
= query_objlist("Pick up what?", &objchain
, traverse_how
,
610 &pick_list
, PICK_ANY
,
611 (via_menu
== -2) ? allow_all
617 for (obj
= objchain
; obj
; obj
= obj2
) {
618 obj2
= FOLLOW(obj
, traverse_how
);
619 if (!selective
&& oclasses
[0] && !index(oclasses
, obj
->oclass
))
623 if (!all_of_a_type
) {
626 (void) safe_qbuf(qbuf
, "Pick up ", "?", obj
, doname
,
627 ansimpleoname
, something
);
628 switch ((obj
->quan
< 2L) ? ynaq(qbuf
) : ynNaq(qbuf
)) {
630 goto end_query
; /* out 2 levels */
634 all_of_a_type
= TRUE
;
637 oclasses
[0] = obj
->oclass
;
641 case '#': /* count was entered */
643 continue; /* 0 count => No */
644 lcount
= (long) yn_number
;
645 if (lcount
> obj
->quan
)
656 if ((res
= pickup_object(obj
, lcount
, FALSE
)) < 0)
661 ; /* statement required after label */
665 if (hides_under(youmonst
.data
))
666 (void) hideunder(&youmonst
);
668 /* position may need updating (invisible hero) */
672 /* check if there's anything else here after auto-pickup is done */
674 check_here(n_picked
> 0);
676 return (n_tried
> 0);
680 is_autopickup_exception(obj
, grab
)
682 boolean grab
; /* forced pickup, rather than forced leave behind? */
685 * Does the text description of this match an exception?
687 char *objdesc
= makesingular(doname(obj
));
688 struct autopickup_exception
689 *ape
= (grab
) ? iflags
.autopickup_exceptions
[AP_GRAB
]
690 : iflags
.autopickup_exceptions
[AP_LEAVE
];
693 if (regex_match(objdesc
, ape
->regex
))
701 * Pick from the given list using flags.pickup_types. Return the number
702 * of items picked (not counts). Create an array that returns pointers
703 * and counts of the items to be picked up. If the number of items
704 * picked is zero, the pickup list is left alone. The caller of this
705 * function must free the pickup list.
708 autopick(olist
, follow
, pick_list
)
709 struct obj
*olist
; /* the object list */
710 int follow
; /* how to follow the object list */
711 menu_item
**pick_list
; /* list of objects and counts to pick up */
713 menu_item
*pi
; /* pick item */
717 const char *otypes
= flags
.pickup_types
;
719 /* first count the number of eligible items */
720 for (n
= 0, curr
= olist
; curr
; curr
= FOLLOW(curr
, follow
)) {
721 /* pick if in pickup_types and not unpaid item in shop */
722 pickit
= ((!*otypes
|| index(otypes
, curr
->oclass
))
723 && !(curr
->where
== OBJ_FLOOR
725 && isok(curr
->ox
, curr
->oy
)
726 && costly_spot(curr
->ox
, curr
->oy
)));
727 /* check for "always pick up */
729 pickit
= is_autopickup_exception(curr
, TRUE
);
730 /* then for "never pick up */
732 pickit
= !is_autopickup_exception(curr
, FALSE
);
733 /* pickup_thrown overrides pickup_types and exceptions */
735 pickit
= (flags
.pickup_thrown
&& curr
->was_thrown
);
736 /* finally, do we count this object? */
742 *pick_list
= pi
= (menu_item
*) alloc(sizeof (menu_item
) * n
);
743 for (n
= 0, curr
= olist
; curr
; curr
= FOLLOW(curr
, follow
)) {
744 pickit
= (!*otypes
|| index(otypes
, curr
->oclass
));
746 pickit
= is_autopickup_exception(curr
, TRUE
);
748 pickit
= !is_autopickup_exception(curr
, FALSE
);
750 pickit
= (flags
.pickup_thrown
&& curr
->was_thrown
);
752 pi
[n
].item
.a_obj
= curr
;
753 pi
[n
].count
= curr
->quan
;
762 * Put up a menu using the given object list. Only those objects on the
763 * list that meet the approval of the allow function are displayed. Return
764 * a count of the number of items selected, as well as an allocated array of
765 * menu_items, containing pointers to the objects selected and counts. The
766 * returned counts are guaranteed to be in bounds and non-zero.
769 * BY_NEXTHERE - Follow object list via nexthere instead of nobj.
770 * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
772 * USE_INVLET - Use object's invlet.
773 * INVORDER_SORT - Use hero's pack order.
774 * INCLUDE_HERO - Showing engulfer's invent; show hero too.
775 * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow".
776 * SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to
778 * FEEL_COCKATRICE - touch corpse.
781 query_objlist(qstr
, olist_p
, qflags
, pick_list
, how
, allow
)
782 const char *qstr
; /* query string */
783 struct obj
**olist_p
; /* the list to pick from */
784 int qflags
; /* options to control the query */
785 menu_item
**pick_list
; /* return list of items picked */
786 int how
; /* type of query */
787 boolean
FDECL((*allow
), (OBJ_P
)); /* allow function */
791 struct obj
*curr
, *last
, fake_hero_object
, *olist
= *olist_p
;
794 boolean printed_type_name
,
795 sorted
= (qflags
& INVORDER_SORT
) != 0,
796 engulfer
= (qflags
& INCLUDE_HERO
) != 0;
798 *pick_list
= (menu_item
*) 0;
799 if (!olist
&& !engulfer
)
802 /* count the number of items allowed */
803 for (n
= 0, last
= 0, curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
))
804 if ((*allow
)(curr
)) {
811 /* don't autoselect swallowed hero if it's the only choice */
812 qflags
&= ~AUTOSELECT_SINGLE
;
815 if (n
== 0) /* nothing to pick here */
816 return (qflags
& SIGNAL_NOMENU
) ? -1 : 0;
818 if (n
== 1 && (qflags
& AUTOSELECT_SINGLE
)) {
819 *pick_list
= (menu_item
*) alloc(sizeof (menu_item
));
820 (*pick_list
)->item
.a_obj
= last
;
821 (*pick_list
)->count
= last
->quan
;
827 (((flags
.sortloot
== 'f'
828 || (flags
.sortloot
== 'l' && !(qflags
& USE_INVLET
)))
830 : (qflags
& USE_INVLET
) ? SORTLOOT_INVLET
: 0)
831 | (flags
.sortpack
? SORTLOOT_PACK
: 0)),
832 (qflags
& BY_NEXTHERE
) ? TRUE
: FALSE
);
836 win
= create_nhwindow(NHW_MENU
);
840 * Run through the list and add the objects to the menu. If
841 * INVORDER_SORT is set, we'll run through the list once for
842 * each type so we can group them. The allow function will only
843 * be called once per object in the list.
845 pack
= flags
.inv_order
;
847 printed_type_name
= FALSE
;
848 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
849 if (sorted
&& curr
->oclass
!= *pack
)
851 if ((qflags
& FEEL_COCKATRICE
) && curr
->otyp
== CORPSE
852 && will_feel_cockatrice(curr
, FALSE
)) {
853 destroy_nhwindow(win
); /* stop the menu and revert */
854 (void) look_here(0, FALSE
);
857 if ((*allow
)(curr
)) {
858 /* if sorting, print type name (once only) */
859 if (sorted
&& !printed_type_name
) {
861 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
862 let_to_name(*pack
, FALSE
,
864 && iflags
.menu_head_objsym
)),
866 printed_type_name
= TRUE
;
870 add_menu(win
, obj_to_glyph(curr
), &any
,
871 (qflags
& USE_INVLET
) ? curr
->invlet
: 0,
872 def_oc_syms
[(int) objects
[curr
->otyp
].oc_class
].sym
,
873 ATR_NONE
, doname_with_price(curr
), MENU_UNSELECTED
);
877 } while (sorted
&& *pack
);
883 if (sorted
&& n
> 1) {
884 Sprintf(buf
, "%s Creatures",
885 is_animal(u
.ustuck
->data
) ? "Swallowed" : "Engulfed");
886 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
, buf
,
889 fake_hero_object
= zeroobj
;
890 fake_hero_object
.quan
= 1L; /* not strictly necessary... */
891 any
.a_obj
= &fake_hero_object
;
892 add_menu(win
, mon_to_glyph(&youmonst
), &any
,
893 /* fake inventory letter, no group accelerator */
894 CONTAINED_SYM
, 0, ATR_NONE
, an(self_lookat(buf
)),
899 n
= select_menu(win
, how
, pick_list
);
900 destroy_nhwindow(win
);
906 /* fix up counts: -1 means no count used => pick all;
907 if fake_hero_object was picked, discard that choice */
908 for (i
= k
= 0, mi
= *pick_list
; i
< n
; i
++, mi
++) {
909 if (mi
->item
.a_obj
== &fake_hero_object
)
911 if (mi
->count
== -1L || mi
->count
> mi
->item
.a_obj
->quan
)
912 mi
->count
= mi
->item
.a_obj
->quan
;
914 (*pick_list
)[k
] = *mi
;
918 /* fake_hero was only choice so discard whole list */
919 free((genericptr_t
) *pick_list
);
923 /* other stuff plus fake_hero; last slot is now unused */
924 (*pick_list
)[k
].item
= zeroany
;
925 (*pick_list
)[k
].count
= 0L;
929 /* -1 is used for SIGNAL_NOMENU, so callers don't expect it
930 to indicate that the player declined to make a choice */
931 n
= (qflags
& SIGNAL_ESCAPE
) ? -2 : 0;
937 * allow menu-based category (class) selection (for Drop,take off etc.)
941 query_category(qstr
, olist
, qflags
, pick_list
, how
)
942 const char *qstr
; /* query string */
943 struct obj
*olist
; /* the list to pick from */
944 int qflags
; /* behaviour modification flags */
945 menu_item
**pick_list
; /* return list of items picked */
946 int how
; /* type of query */
953 boolean collected_type_name
;
956 boolean do_unpaid
= FALSE
;
957 boolean do_blessed
= FALSE
, do_cursed
= FALSE
, do_uncursed
= FALSE
,
958 do_buc_unknown
= FALSE
;
959 int num_buc_types
= 0;
961 *pick_list
= (menu_item
*) 0;
964 if ((qflags
& UNPAID_TYPES
) && count_unpaid(olist
))
966 if ((qflags
& BUC_BLESSED
) && count_buc(olist
, BUC_BLESSED
)) {
970 if ((qflags
& BUC_CURSED
) && count_buc(olist
, BUC_CURSED
)) {
974 if ((qflags
& BUC_UNCURSED
) && count_buc(olist
, BUC_UNCURSED
)) {
978 if ((qflags
& BUC_UNKNOWN
) && count_buc(olist
, BUC_UNKNOWN
)) {
979 do_buc_unknown
= TRUE
;
983 ccount
= count_categories(olist
, qflags
);
984 /* no point in actually showing a menu for a single category */
985 if (ccount
== 1 && !do_unpaid
&& num_buc_types
<= 1
986 && !(qflags
& BILLED_TYPES
)) {
987 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
988 if ((qflags
& WORN_TYPES
)
989 && !(curr
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_WEAPON
)))
994 *pick_list
= (menu_item
*) alloc(sizeof(menu_item
));
995 (*pick_list
)->item
.a_int
= curr
->oclass
;
998 debugpline0("query_category: no single object match");
1003 win
= create_nhwindow(NHW_MENU
);
1005 pack
= flags
.inv_order
;
1006 if ((qflags
& ALL_TYPES
) && (ccount
> 1)) {
1009 any
.a_int
= ALL_TYPES_SELECTED
;
1010 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1011 (qflags
& WORN_TYPES
) ? "All worn types" : "All types",
1017 collected_type_name
= FALSE
;
1018 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
1019 if (curr
->oclass
== *pack
) {
1020 if ((qflags
& WORN_TYPES
)
1021 && !(curr
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_WEAPON
)))
1023 if (!collected_type_name
) {
1025 any
.a_int
= curr
->oclass
;
1027 win
, NO_GLYPH
, &any
, invlet
++,
1028 def_oc_syms
[(int) objects
[curr
->otyp
].oc_class
].sym
,
1029 ATR_NONE
, let_to_name(*pack
, FALSE
,
1031 && iflags
.menu_head_objsym
),
1033 collected_type_name
= TRUE
;
1038 if (invlet
>= 'u') {
1039 impossible("query_category: too many categories");
1043 /* unpaid items if there are any */
1048 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
, "Unpaid items",
1051 /* billed items: checked by caller, so always include if BILLED_TYPES */
1052 if (qflags
& BILLED_TYPES
) {
1056 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1057 "Unpaid items already used up", MENU_UNSELECTED
);
1059 if (qflags
& CHOOSE_ALL
) {
1063 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1064 (qflags
& WORN_TYPES
) ? "Auto-select every item being worn"
1065 : "Auto-select every item",
1068 /* items with b/u/c/unknown if there are any */
1073 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1074 "Items known to be Blessed", MENU_UNSELECTED
);
1080 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1081 "Items known to be Cursed", MENU_UNSELECTED
);
1087 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1088 "Items known to be Uncursed", MENU_UNSELECTED
);
1090 if (do_buc_unknown
) {
1094 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1095 "Items of unknown B/C/U status", MENU_UNSELECTED
);
1097 end_menu(win
, qstr
);
1098 n
= select_menu(win
, how
, pick_list
);
1099 destroy_nhwindow(win
);
1101 n
= 0; /* caller's don't expect -1 */
1106 count_categories(olist
, qflags
)
1111 boolean counted_category
;
1115 pack
= flags
.inv_order
;
1117 counted_category
= FALSE
;
1118 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
1119 if (curr
->oclass
== *pack
) {
1120 if ((qflags
& WORN_TYPES
)
1121 && !(curr
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_WEAPON
)))
1123 if (!counted_category
) {
1125 counted_category
= TRUE
;
1134 /* could we carry `obj'? if not, could we carry some of it/them? */
1136 carry_count(obj
, container
, count
, telekinesis
, wt_before
, wt_after
)
1137 struct obj
*obj
, *container
; /* object to pick up, bag it's coming out of */
1139 boolean telekinesis
;
1140 int *wt_before
, *wt_after
;
1142 boolean adjust_wt
= container
&& carried(container
),
1143 is_gold
= obj
->oclass
== COIN_CLASS
;
1144 int wt
, iw
, ow
, oow
;
1145 long qq
, savequan
, umoney
;
1147 const char *verb
, *prefx1
, *prefx2
, *suffx
;
1148 char obj_nambuf
[BUFSZ
], where
[BUFSZ
];
1150 savequan
= obj
->quan
;
1152 umoney
= money_cnt(invent
);
1153 iw
= max_capacity();
1155 if (count
!= savequan
) {
1157 obj
->owt
= (unsigned) weight(obj
);
1159 wt
= iw
+ (int) obj
->owt
;
1161 wt
-= (container
->otyp
== BAG_OF_HOLDING
)
1162 ? (int) DELTA_CWT(container
, obj
)
1164 /* This will go with silver+copper & new gold weight */
1165 if (is_gold
) /* merged gold might affect cumulative weight */
1166 wt
-= (GOLD_WT(umoney
) + GOLD_WT(count
) - GOLD_WT(umoney
+ count
));
1167 if (count
!= savequan
) {
1168 obj
->quan
= savequan
;
1177 /* see how many we can lift */
1179 iw
-= (int) GOLD_WT(umoney
);
1181 qq
= GOLD_CAPACITY((long) iw
, umoney
);
1184 qq
= 50L - (umoney
% 100L) - 1L;
1187 for (; qq
<= count
; qq
+= 100L) {
1189 obj
->owt
= (unsigned) GOLD_WT(qq
);
1190 ow
= (int) GOLD_WT(umoney
+ qq
);
1191 ow
-= (container
->otyp
== BAG_OF_HOLDING
)
1192 ? (int) DELTA_CWT(container
, obj
)
1203 else if (qq
> count
)
1205 wt
= iw
+ (int) GOLD_WT(umoney
+ qq
);
1206 } else if (count
> 1 || count
< obj
->quan
) {
1208 * Ugh. Calc num to lift by changing the quan of of the
1209 * object and calling weight.
1211 * This works for containers only because containers
1212 * don't merge. -dean
1214 for (qq
= 1L; qq
<= count
; qq
++) {
1216 obj
->owt
= (unsigned) (ow
= weight(obj
));
1218 ow
-= (container
->otyp
== BAG_OF_HOLDING
)
1219 ? (int) DELTA_CWT(container
, obj
)
1227 /* there's only one, and we can't lift it */
1230 obj
->quan
= savequan
;
1234 /* some message will be given */
1235 Strcpy(obj_nambuf
, doname(obj
));
1237 Sprintf(where
, "in %s", the(xname(container
)));
1240 Strcpy(where
, "lying here");
1241 verb
= telekinesis
? "acquire" : "lift";
1244 /* lint suppression */
1245 *obj_nambuf
= *where
= '\0';
1248 /* we can carry qq of them */
1251 You("can only %s %s of the %s %s.", verb
,
1252 (qq
== 1L) ? "one" : "some", obj_nambuf
, where
);
1258 Strcpy(where
, "here"); /* slightly shorter form */
1259 if (invent
|| umoney
) {
1260 prefx1
= "you cannot ";
1262 suffx
= " any more";
1264 prefx1
= (obj
->quan
== 1L) ? "it " : "even one ";
1265 prefx2
= "is too heavy for you to ";
1268 There("%s %s %s, but %s%s%s%s.", otense(obj
, "are"), obj_nambuf
, where
,
1269 prefx1
, prefx2
, verb
, suffx
);
1271 /* *wt_after = iw; */
1275 /* determine whether character is able and player is willing to carry `obj' */
1278 lift_object(obj
, container
, cnt_p
, telekinesis
)
1279 struct obj
*obj
, *container
; /* object to pick up, bag it's coming out of */
1281 boolean telekinesis
;
1283 int result
, old_wt
, new_wt
, prev_encumbr
, next_encumbr
;
1285 if (obj
->otyp
== BOULDER
&& Sokoban
) {
1286 You("cannot get your %s around this %s.", body_part(HAND
),
1290 /* override weight consideration for loadstone picked up by anybody
1291 and for boulder picked up by hero poly'd into a giant; override
1292 availability of open inventory slot iff not already carrying one */
1293 if (obj
->otyp
== LOADSTONE
1294 || (obj
->otyp
== BOULDER
&& throws_rocks(youmonst
.data
))) {
1295 if (inv_cnt(FALSE
) < 52 || !carrying(obj
->otyp
)
1296 || merge_choice(invent
, obj
))
1297 return 1; /* lift regardless of current situation */
1298 /* if we reach here, we're out of slots and already have at least
1299 one of these, so treat this one more like a normal item */
1300 You("are carrying too much stuff to pick up %s %s.",
1301 (obj
->quan
== 1L) ? "another" : "more", simpleonames(obj
));
1305 *cnt_p
= carry_count(obj
, container
, *cnt_p
, telekinesis
,
1308 result
= -1; /* nothing lifted */
1309 } else if (obj
->oclass
!= COIN_CLASS
1310 /* [exception for gold coins will have to change
1311 if silver/copper ones ever get implemented] */
1312 && inv_cnt(FALSE
) >= 52 && !merge_choice(invent
, obj
)) {
1313 Your("knapsack cannot accommodate any more items.");
1314 result
= -1; /* nothing lifted */
1317 prev_encumbr
= near_capacity();
1318 if (prev_encumbr
< flags
.pickup_burden
)
1319 prev_encumbr
= flags
.pickup_burden
;
1320 next_encumbr
= calc_capacity(new_wt
- old_wt
);
1321 if (next_encumbr
> prev_encumbr
) {
1323 result
= 0; /* don't lift */
1326 long savequan
= obj
->quan
;
1329 Strcpy(qbuf
, (next_encumbr
> HVY_ENCUMBER
)
1331 : (next_encumbr
> MOD_ENCUMBER
)
1335 (void) strsubst(qbuf
, "lifting", "removing");
1337 (void) safe_qbuf(qbuf
, qbuf
, ". Continue?", obj
, doname
,
1338 ansimpleoname
, something
);
1339 obj
->quan
= savequan
;
1340 switch (ynq(qbuf
)) {
1348 break; /* 'y' => result == 1 */
1350 clear_nhwindow(WIN_MESSAGE
);
1355 if (obj
->otyp
== SCR_SCARE_MONSTER
&& result
<= 0 && !container
)
1361 * Pick up <count> of obj from the ground and add it to the hero's inventory.
1362 * Returns -1 if caller should break out of its loop, 0 if nothing picked
1363 * up, 1 if otherwise.
1366 pickup_object(obj
, count
, telekinesis
)
1369 boolean telekinesis
; /* not picking it up directly by hand */
1373 if (obj
->quan
< count
) {
1374 impossible("pickup_object: count %ld > quan %ld?", count
, obj
->quan
);
1378 /* In case of auto-pickup, where we haven't had a chance
1379 to look at it yet; affects docall(SCR_SCARE_MONSTER). */
1383 if (obj
== uchain
) { /* do not pick up attached chain */
1385 } else if (obj
->oartifact
&& !touch_artifact(obj
, &youmonst
)) {
1387 } else if (obj
->otyp
== CORPSE
) {
1388 if (fatal_corpse_mistake(obj
, telekinesis
)
1389 || rider_corpse_revival(obj
, telekinesis
))
1391 } else if (obj
->otyp
== SCR_SCARE_MONSTER
) {
1394 else if (!obj
->spe
&& !obj
->cursed
)
1397 pline_The("scroll%s %s to dust as you %s %s up.", plur(obj
->quan
),
1398 otense(obj
, "turn"), telekinesis
? "raise" : "pick",
1399 (obj
->quan
== 1L) ? "it" : "them");
1400 if (!(objects
[SCR_SCARE_MONSTER
].oc_name_known
)
1401 && !(objects
[SCR_SCARE_MONSTER
].oc_uname
))
1403 useupf(obj
, obj
->quan
);
1404 return 1; /* tried to pick something up and failed, but
1405 don't want to terminate pickup loop yet */
1409 if ((res
= lift_object(obj
, (struct obj
*) 0, &count
, telekinesis
)) <= 0)
1412 /* Whats left of the special case for gold :-) */
1413 if (obj
->oclass
== COIN_CLASS
)
1415 if (obj
->quan
!= count
&& obj
->otyp
!= LOADSTONE
)
1416 obj
= splitobj(obj
, count
);
1418 obj
= pick_obj(obj
);
1420 if (uwep
&& uwep
== obj
)
1421 mrg_to_wielded
= TRUE
;
1422 nearload
= near_capacity();
1423 prinv(nearload
== SLT_ENCUMBER
? moderateloadmsg
: (char *) 0, obj
,
1425 mrg_to_wielded
= FALSE
;
1430 * Do the actual work of picking otmp from the floor or monster's interior
1431 * and putting it in the hero's inventory. Take care of billing. Return a
1432 * pointer to the object where otmp ends up. This may be different
1433 * from otmp because of merging.
1439 obj_extract_self(otmp
);
1440 if (!u
.uswallow
&& otmp
!= uball
&& costly_spot(otmp
->ox
, otmp
->oy
)) {
1441 char saveushops
[5], fakeshop
[2];
1443 /* addtobill cares about your location rather than the object's;
1444 usually they'll be the same, but not when using telekinesis
1445 (if ever implemented) or a grappling hook */
1446 Strcpy(saveushops
, u
.ushops
);
1447 fakeshop
[0] = *in_rooms(otmp
->ox
, otmp
->oy
, SHOPBASE
);
1449 Strcpy(u
.ushops
, fakeshop
);
1450 /* sets obj->unpaid if necessary */
1451 addtobill(otmp
, TRUE
, FALSE
, FALSE
);
1452 Strcpy(u
.ushops
, saveushops
);
1453 /* if you're outside the shop, make shk notice */
1454 if (!index(u
.ushops
, *fakeshop
))
1455 remote_burglary(otmp
->ox
, otmp
->oy
);
1457 newsym(otmp
->ox
, otmp
->oy
);
1458 return addinv(otmp
); /* might merge it with other objects */
1462 * prints a message if encumbrance changed since the last check and
1463 * returns the new encumbrance value (from near_capacity()).
1468 static int oldcap
= UNENCUMBERED
;
1469 int newcap
= near_capacity();
1471 if (oldcap
< newcap
) {
1474 Your("movements are slowed slightly because of your load.");
1477 You("rebalance your load. Movement is difficult.");
1480 You("%s under your heavy load. Movement is very hard.",
1481 stagger(youmonst
.data
, "stagger"));
1484 You("%s move a handspan with this load!",
1485 newcap
== 4 ? "can barely" : "can't even");
1489 } else if (oldcap
> newcap
) {
1492 Your("movements are now unencumbered.");
1495 Your("movements are only slowed slightly by your load.");
1498 You("rebalance your load. Movement is still difficult.");
1501 You("%s under your load. Movement is still very hard.",
1502 stagger(youmonst
.data
, "stagger"));
1512 /* Is there a container at x,y. Optional: return count of containers at x,y */
1514 container_at(x
, y
, countem
)
1518 struct obj
*cobj
, *nobj
;
1519 int container_count
= 0;
1521 for (cobj
= level
.objects
[x
][y
]; cobj
; cobj
= nobj
) {
1522 nobj
= cobj
->nexthere
;
1523 if (Is_container(cobj
)) {
1529 return container_count
;
1533 able_to_loot(x
, y
, looting
)
1535 boolean looting
; /* loot vs tip */
1537 const char *verb
= looting
? "loot" : "tip";
1539 if (!can_reach_floor(TRUE
)) {
1540 if (u
.usteed
&& P_SKILL(P_RIDING
) < P_BASIC
)
1541 rider_cant_reach(); /* not skilled enough to reach */
1543 cant_reach_floor(x
, y
, FALSE
, TRUE
);
1545 } else if ((is_pool(x
, y
) && (looting
|| !Underwater
)) || is_lava(x
, y
)) {
1546 /* at present, can't loot in water even when Underwater;
1547 can tip underwater, but not when over--or stuck in--lava */
1548 You("cannot %s things that are deep in the %s.", verb
,
1549 is_lava(x
, y
) ? "lava" : "water");
1551 } else if (nolimbs(youmonst
.data
)) {
1552 pline("Without limbs, you cannot %s anything.", verb
);
1554 } else if (looting
&& !freehand()) {
1555 pline("Without a free %s, you cannot loot anything.",
1568 for (i
= -1; i
<= 1; i
++)
1569 for (j
= -1; j
<= 1; j
++) {
1572 if (isok(nx
, ny
) && MON_AT(nx
, ny
))
1579 do_loot_cont(cobjp
, cindex
, ccount
)
1581 int cindex
, ccount
; /* index of this container (1..N), number of them (N) */
1583 struct obj
*cobj
= *cobjp
;
1587 if (cobj
->olocked
) {
1590 cobj
->lknown
? "It is" : "Hmmm, it turns out to be");
1591 else if (cobj
->lknown
)
1592 pline("%s is locked.", The(xname(cobj
)));
1594 pline("Hmmm, %s turns out to be locked.", the(xname(cobj
)));
1600 if (cobj
->otyp
== BAG_OF_TRICKS
) {
1603 You("carefully open %s...", the(xname(cobj
)));
1604 pline("It develops a huge set of teeth and bites you!");
1606 losehp(Maybe_Half_Phys(tmp
), "carnivorous bag", KILLED_BY_AN
);
1607 makeknown(BAG_OF_TRICKS
);
1608 abort_looting
= TRUE
;
1612 You("%sopen %s...", (!cobj
->cknown
|| !cobj
->lknown
) ? "carefully " : "",
1614 return use_container(cobjp
, 0, (boolean
) (cindex
< ccount
));
1617 /* loot a container on the floor or loot saddle from mon. */
1621 struct obj
*cobj
, *nobj
;
1622 register int c
= -1;
1625 boolean underfoot
= TRUE
;
1626 const char *dont_find_anything
= "don't find anything";
1629 int prev_inquiry
= 0;
1630 boolean prev_loot
= FALSE
;
1633 abort_looting
= FALSE
;
1635 if (check_capacity((char *) 0)) {
1636 /* "Can't do that while carrying so much stuff." */
1639 if (nohands(youmonst
.data
)) {
1640 You("have no hands!"); /* not `body_part(HAND)' */
1644 if (rn2(6) && reverse_loot())
1647 pline("Being confused, you find nothing to loot.");
1648 return 1; /* costs a turn */
1649 } /* else fallthrough to normal looting */
1655 if ((num_conts
= container_at(cc
.x
, cc
.y
, TRUE
)) > 0) {
1656 boolean anyfound
= FALSE
;
1658 if (!able_to_loot(cc
.x
, cc
.y
, TRUE
))
1661 if (num_conts
> 1) {
1662 /* use a menu to loot many containers */
1666 menu_item
*pick_list
= (menu_item
*) 0;
1669 win
= create_nhwindow(NHW_MENU
);
1672 for (cobj
= level
.objects
[cc
.x
][cc
.y
]; cobj
;
1673 cobj
= cobj
->nexthere
)
1674 if (Is_container(cobj
)) {
1676 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1677 doname(cobj
), MENU_UNSELECTED
);
1679 end_menu(win
, "Loot which containers?");
1680 n
= select_menu(win
, PICK_ANY
, &pick_list
);
1681 destroy_nhwindow(win
);
1684 for (i
= 1; i
<= n
; i
++) {
1685 cobj
= pick_list
[i
- 1].item
.a_obj
;
1686 timepassed
|= do_loot_cont(&cobj
, i
, n
);
1687 if (abort_looting
) {
1688 /* chest trap or magic bag explosion or <esc> */
1689 free((genericptr_t
) pick_list
);
1693 free((genericptr_t
) pick_list
);
1698 for (cobj
= level
.objects
[cc
.x
][cc
.y
]; cobj
; cobj
= nobj
) {
1699 nobj
= cobj
->nexthere
;
1701 if (Is_container(cobj
)) {
1702 c
= ynq(safe_qbuf(qbuf
, "There is ", " here, loot it?",
1703 cobj
, doname
, ansimpleoname
,
1711 timepassed
|= do_loot_cont(&cobj
, 1, 1);
1713 /* chest trap or magic bag explosion or <esc> */
1720 } else if (IS_GRAVE(levl
[cc
.x
][cc
.y
].typ
)) {
1721 You("need to dig up the grave to effectively loot it...");
1724 * 3.3.1 introduced directional looting for some things.
1726 if (c
!= 'y' && mon_beside(u
.ux
, u
.uy
)) {
1727 if (!get_adjacent_loc("Loot in what direction?",
1728 "Invalid loot location", u
.ux
, u
.uy
, &cc
))
1730 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
1732 if (container_at(cc
.x
, cc
.y
, FALSE
))
1737 You("%s to loot on the %s.", dont_find_anything
,
1738 ceiling(cc
.x
, cc
.y
));
1742 mtmp
= m_at(cc
.x
, cc
.y
);
1744 timepassed
= loot_mon(mtmp
, &prev_inquiry
, &prev_loot
);
1745 /* always use a turn when choosing a direction is impaired,
1746 even if you've successfully targetted a saddled creature
1747 and then answered "no" to the "remove its saddle?" prompt */
1748 if (Confusion
|| Stunned
)
1751 /* Preserve pre-3.3.1 behaviour for containers.
1752 * Adjust this if-block to allow container looting
1753 * from one square away to change that in the future.
1756 if (container_at(cc
.x
, cc
.y
, FALSE
)) {
1758 You_cant("loot anything %sthere with %s in the way.",
1759 prev_inquiry
? "else " : "", mon_nam(mtmp
));
1762 You("have to be at a container to loot it.");
1765 You("%s %sthere to loot.", dont_find_anything
,
1766 (prev_inquiry
|| prev_loot
) ? "else " : "");
1770 } else if (c
!= 'y' && c
!= 'n') {
1771 You("%s %s to loot.", dont_find_anything
,
1772 underfoot
? "here" : "there");
1777 /* called when attempting to #loot while confused */
1781 struct obj
*goldob
= 0, *coffers
, *otmp
, boxdummy
;
1784 int n
, x
= u
.ux
, y
= u
.uy
;
1787 /* n objects: 1/(n+1) chance per object plus 1/(n+1) to fall off end
1789 for (n
= inv_cnt(TRUE
), otmp
= invent
; otmp
; --n
, otmp
= otmp
->nobj
)
1791 prinv("You find old loot:", otmp
, 0L);
1797 /* find a money object to mess with */
1798 for (goldob
= invent
; goldob
; goldob
= goldob
->nobj
)
1799 if (goldob
->oclass
== COIN_CLASS
) {
1800 contribution
= ((long) rnd(5) * goldob
->quan
+ 4L) / 5L;
1801 if (contribution
< goldob
->quan
)
1802 goldob
= splitobj(goldob
, contribution
);
1808 if (!IS_THRONE(levl
[x
][y
].typ
)) {
1810 /* the dropped gold might have fallen to lower level */
1812 pline("Ok, now there is loot here.");
1814 /* find original coffers chest if present, otherwise use nearest one
1817 for (coffers
= fobj
; coffers
; coffers
= coffers
->nobj
)
1818 if (coffers
->otyp
== CHEST
) {
1819 if (coffers
->spe
== 2)
1820 break; /* a throne room chest */
1822 || distu(coffers
->ox
, coffers
->oy
)
1823 < distu(otmp
->ox
, otmp
->oy
))
1824 otmp
= coffers
; /* remember closest ordinary chest */
1830 verbalize("Thank you for your contribution to reduce the debt.");
1832 (void) add_to_container(coffers
, goldob
);
1833 coffers
->owt
= weight(coffers
);
1834 coffers
->cknown
= 0;
1835 if (!coffers
->olocked
) {
1836 boxdummy
= zeroobj
, boxdummy
.otyp
= SPE_WIZARD_LOCK
;
1837 (void) boxlock(coffers
, &boxdummy
);
1839 } else if (levl
[x
][y
].looted
!= T_LOOTED
&&
1840 (mon
= makemon(courtmon(), x
, y
, NO_MM_FLAGS
)) != 0) {
1842 add_to_minv(mon
, goldob
);
1843 pline("The exchequer accepts your contribution.");
1845 levl
[x
][y
].looted
= T_LOOTED
;
1847 You("drop %s.", doname(goldob
));
1854 /* loot_mon() returns amount of time passed.
1857 loot_mon(mtmp
, passed_info
, prev_loot
)
1867 /* 3.3.1 introduced the ability to remove saddle from a steed.
1868 * *passed_info is set to TRUE if a loot query was given.
1869 * *prev_loot is set to TRUE if something was actually acquired in here.
1871 if (mtmp
&& mtmp
!= u
.usteed
&& (otmp
= which_armor(mtmp
, W_SADDLE
))) {
1876 Sprintf(qbuf
, "Do you want to remove the saddle from %s?",
1877 x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1878 SUPPRESS_SADDLE
, FALSE
));
1879 if ((c
= yn_function(qbuf
, ynqchars
, 'n')) == 'y') {
1880 if (nolimbs(youmonst
.data
)) {
1881 You_cant("do that without limbs."); /* not body_part(HAND) */
1885 You("can't. The saddle seems to be stuck to %s.",
1886 x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1887 SUPPRESS_SADDLE
, FALSE
));
1888 /* the attempt costs you time */
1891 obj_extract_self(otmp
);
1892 if ((unwornmask
= otmp
->owornmask
) != 0L) {
1893 mtmp
->misc_worn_check
&= ~unwornmask
;
1894 otmp
->owornmask
= 0L;
1895 update_mon_intrinsics(mtmp
, otmp
, FALSE
, FALSE
);
1897 otmp
= hold_another_object(otmp
, "You drop %s!", doname(otmp
),
1899 timepassed
= rnd(3);
1902 } else if (c
== 'q') {
1906 /* 3.4.0 introduced ability to pick things up from swallower's stomach */
1908 int count
= passed_info
? *passed_info
: 0;
1910 timepassed
= pickup(count
);
1916 * Decide whether an object being placed into a magic bag will cause
1917 * it to explode. If the object is a bag itself, check recursively.
1920 mbag_explodes(obj
, depthin
)
1924 /* these won't cause an explosion when they're empty */
1925 if ((obj
->otyp
== WAN_CANCELLATION
|| obj
->otyp
== BAG_OF_TRICKS
)
1929 /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
1930 if ((Is_mbag(obj
) || obj
->otyp
== WAN_CANCELLATION
)
1931 && (rn2(1 << (depthin
> 7 ? 7 : depthin
)) <= depthin
))
1933 else if (Has_contents(obj
)) {
1936 for (otmp
= obj
->cobj
; otmp
; otmp
= otmp
->nobj
)
1937 if (mbag_explodes(otmp
, depthin
+ 1))
1943 /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
1946 register struct obj
*obj
;
1948 boolean floor_container
= !carried(current_container
);
1949 boolean was_unpaid
= FALSE
;
1952 if (!current_container
) {
1953 impossible("<in> no current_container?");
1955 } else if (obj
== uball
|| obj
== uchain
) {
1956 You("must be kidding.");
1958 } else if (obj
== current_container
) {
1959 pline("That would be an interesting topological exercise.");
1961 } else if (obj
->owornmask
& (W_ARMOR
| W_ACCESSORY
)) {
1962 Norep("You cannot %s %s you are wearing.",
1963 Icebox
? "refrigerate" : "stash", something
);
1965 } else if ((obj
->otyp
== LOADSTONE
) && obj
->cursed
) {
1967 pline_The("stone%s won't leave your person.", plur(obj
->quan
));
1969 } else if (obj
->otyp
== AMULET_OF_YENDOR
1970 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
1971 || obj
->otyp
== BELL_OF_OPENING
1972 || obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
1973 /* Prohibit Amulets in containers; if you allow it, monsters can't
1974 * steal them. It also becomes a pain to check to see if someone
1975 * has the Amulet. Ditto for the Candelabrum, the Bell and the Book.
1977 pline("%s cannot be confined in such trappings.", The(xname(obj
)));
1979 } else if (obj
->otyp
== LEASH
&& obj
->leashmon
!= 0) {
1980 pline("%s attached to your pet.", Tobjnam(obj
, "are"));
1982 } else if (obj
== uwep
) {
1987 setuwep((struct obj
*) 0);
1988 /* This uwep check is obsolete. It dates to 3.0 and earlier when
1989 * unwielding Firebrand would be fatal in hell if hero had no other
1990 * fire resistance. Life-saving would force it to be re-wielded.
1993 return 0; /* unwielded, died, rewielded */
1994 } else if (obj
== uswapwep
) {
1995 setuswapwep((struct obj
*) 0);
1996 } else if (obj
== uquiver
) {
1997 setuqwep((struct obj
*) 0);
2000 if (fatal_corpse_mistake(obj
, FALSE
))
2003 /* boxes, boulders, and big statues can't fit into any container */
2004 if (obj
->otyp
== ICE_BOX
|| Is_box(obj
) || obj
->otyp
== BOULDER
2005 || (obj
->otyp
== STATUE
&& bigmonst(&mons
[obj
->corpsenm
]))) {
2007 * xname() uses a static result array. Save obj's name
2008 * before current_container's name is computed. Don't
2009 * use the result of strcpy() within You() --- the order
2010 * of evaluation of the parameters is undefined.
2012 Strcpy(buf
, the(xname(obj
)));
2013 You("cannot fit %s into %s.", buf
, the(xname(current_container
)));
2019 if (obj_is_burning(obj
)) /* this used to be part of freeinv() */
2020 (void) snuff_lit(obj
);
2022 if (floor_container
&& costly_spot(u
.ux
, u
.uy
)) {
2023 if (obj
->oclass
== COIN_CLASS
) {
2024 ; /* defer gold until after put-in message */
2025 } else if (current_container
->no_charge
&& !obj
->unpaid
) {
2026 /* don't sell when putting the item into your own container */
2029 /* sellobj() will take an unpaid item off the shop bill */
2030 was_unpaid
= obj
->unpaid
? TRUE
: FALSE
;
2031 sellobj_state(SELL_DELIBERATE
);
2032 sellobj(obj
, u
.ux
, u
.uy
);
2033 sellobj_state(SELL_NORMAL
);
2036 if (Icebox
&& !age_is_relative(obj
)) {
2037 obj
->age
= monstermoves
- obj
->age
; /* actual age */
2038 /* stop any corpse timeouts when frozen */
2039 if (obj
->otyp
== CORPSE
&& obj
->timed
) {
2040 long rot_alarm
= stop_timer(ROT_CORPSE
, obj_to_any(obj
));
2042 (void) stop_timer(REVIVE_MON
, obj_to_any(obj
));
2043 /* mark a non-reviving corpse as such */
2047 } else if (Is_mbag(current_container
) && mbag_explodes(obj
, 0)) {
2048 /* explicitly mention what item is triggering the explosion */
2049 pline("As you put %s inside, you are blasted by a magical explosion!",
2051 /* did not actually insert obj yet */
2053 addtobill(obj
, FALSE
, FALSE
, TRUE
);
2054 obfree(obj
, (struct obj
*) 0);
2055 delete_contents(current_container
);
2056 if (!floor_container
)
2057 useup(current_container
);
2058 else if (obj_here(current_container
, u
.ux
, u
.uy
))
2059 useupf(current_container
, current_container
->quan
);
2061 panic("in_container: bag not found.");
2063 losehp(d(6, 6), "magical explosion", KILLED_BY_AN
);
2064 current_container
= 0; /* baggone = TRUE; */
2067 if (current_container
) {
2068 Strcpy(buf
, the(xname(current_container
)));
2069 You("put %s into %s.", doname(obj
), buf
);
2071 /* gold in container always needs to be added to credit */
2072 if (floor_container
&& obj
->oclass
== COIN_CLASS
)
2073 sellobj(obj
, current_container
->ox
, current_container
->oy
);
2074 (void) add_to_container(current_container
, obj
);
2075 current_container
->owt
= weight(current_container
);
2077 /* gold needs this, and freeinv() many lines above may cause
2078 * the encumbrance to disappear from the status, so just always
2079 * update status immediately.
2082 return (current_container
? 1 : -1);
2089 return (current_container
&& obj
!= current_container
);
2092 /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
2095 register struct obj
*obj
;
2097 register struct obj
*otmp
;
2098 boolean is_gold
= (obj
->oclass
== COIN_CLASS
);
2102 if (!current_container
) {
2103 impossible("<out> no current_container?");
2105 } else if (is_gold
) {
2106 obj
->owt
= weight(obj
);
2109 if (obj
->oartifact
&& !touch_artifact(obj
, &youmonst
))
2112 if (fatal_corpse_mistake(obj
, FALSE
))
2116 if ((res
= lift_object(obj
, current_container
, &count
, FALSE
)) <= 0)
2119 if (obj
->quan
!= count
&& obj
->otyp
!= LOADSTONE
)
2120 obj
= splitobj(obj
, count
);
2122 /* Remove the object from the list. */
2123 obj_extract_self(obj
);
2124 current_container
->owt
= weight(current_container
);
2127 removed_from_icebox(obj
);
2129 if (!obj
->unpaid
&& !carried(current_container
)
2130 && costly_spot(current_container
->ox
, current_container
->oy
)) {
2131 obj
->ox
= current_container
->ox
;
2132 obj
->oy
= current_container
->oy
;
2133 addtobill(obj
, FALSE
, FALSE
, FALSE
);
2136 pick_pick(obj
); /* shopkeeper feedback */
2139 loadlev
= near_capacity();
2140 prinv(loadlev
? ((loadlev
< MOD_ENCUMBER
)
2141 ? "You have a little trouble removing"
2142 : "You have much trouble removing")
2147 bot(); /* update character's gold piece count immediately */
2152 /* taking a corpse out of an ice box needs a couple of adjustments */
2154 removed_from_icebox(obj
)
2157 if (!age_is_relative(obj
)) {
2158 obj
->age
= monstermoves
- obj
->age
; /* actual age */
2159 if (obj
->otyp
== CORPSE
)
2160 start_corpse_timeout(obj
);
2164 /* an object inside a cursed bag of holding is being destroyed */
2166 mbag_item_gone(held
, item
)
2174 pline("%s %s vanished!", Doname2(item
), otense(item
, "have"));
2176 You("%s %s disappear!", Blind
? "notice" : "see", doname(item
));
2178 if (*u
.ushops
&& (shkp
= shop_keeper(*u
.ushops
)) != 0) {
2179 if (held
? (boolean
) item
->unpaid
: costly_spot(u
.ux
, u
.uy
))
2180 loss
= stolen_value(item
, u
.ux
, u
.uy
, (boolean
) shkp
->mpeaceful
,
2183 obfree(item
, (struct obj
*) 0);
2188 observe_quantum_cat(box
)
2191 static NEARDATA
const char sc
[] = "Schroedinger's Cat";
2192 struct obj
*deadcat
;
2193 struct monst
*livecat
;
2196 box
->spe
= 0; /* box->owt will be updated below */
2197 if (get_obj_location(box
, &ox
, &oy
, 0))
2198 box
->ox
= ox
, box
->oy
= oy
; /* in case it's being carried */
2200 /* this isn't really right, since any form of observation
2201 (telepathic or monster/object/food detection) ought to
2202 force the determination of alive vs dead state; but basing
2203 it just on opening the box is much simpler to cope with */
2205 ? makemon(&mons
[PM_HOUSECAT
], box
->ox
, box
->oy
, NO_MINVENT
)
2208 livecat
->mpeaceful
= 1;
2209 set_malign(livecat
);
2210 if (!canspotmon(livecat
))
2211 You("think %s brushed your %s.", something
, body_part(FOOT
));
2213 pline("%s inside the box is still alive!", Monnam(livecat
));
2214 (void) christen_monst(livecat
, sc
);
2216 deadcat
= mk_named_object(CORPSE
, &mons
[PM_HOUSECAT
],
2217 box
->ox
, box
->oy
, sc
);
2219 obj_extract_self(deadcat
);
2220 (void) add_to_container(box
, deadcat
);
2222 pline_The("%s inside the box is dead!",
2223 Hallucination
? rndmonnam((char *) 0) : "housecat");
2225 box
->owt
= weight(box
);
2231 /* used by askchain() to check for magic bag explosion */
2234 int FDECL((*fn
), (OBJ_P
));
2236 /* result is only meaningful while use_container() is executing */
2237 return ((fn
== in_container
|| fn
== out_container
)
2238 && !current_container
);
2242 explain_container_prompt(more_containers
)
2243 boolean more_containers
;
2245 static const char *const explaintext
[] = {
2246 "Container actions:", "", " : -- Look: examine contents",
2247 " o -- Out: take things out", " i -- In: put things in",
2248 " b -- Both: first take things out, then put things in",
2249 " r -- Reversed: put things in, then take things out",
2250 " s -- Stash: put one item in", "",
2251 " n -- Next: loot next selected container", " q -- Quit: finished",
2252 " ? -- Help: display this text.", "", 0
2254 const char *const *txtpp
;
2257 /* "Do what with <container>? [:oibrsq or ?] (q)" */
2258 if ((win
= create_nhwindow(NHW_TEXT
)) != WIN_ERR
) {
2259 for (txtpp
= explaintext
; *txtpp
; ++txtpp
) {
2260 if (!more_containers
&& !strncmp(*txtpp
, " n ", 3))
2262 putstr(win
, 0, *txtpp
);
2264 display_nhwindow(win
, FALSE
);
2265 destroy_nhwindow(win
);
2272 if (nohands(youmonst
.data
)) {
2273 You("have no hands!"); /* not `body_part(HAND)' */
2275 } else if (!freehand()) {
2276 You("have no free %s.", body_part(HAND
));
2282 static const char stashable
[] = { ALLOW_COUNT
, COIN_CLASS
, ALL_CLASSES
, 0 };
2285 use_container(objp
, held
, more_containers
)
2288 boolean more_containers
; /* True iff #loot multiple and this isn't last one */
2290 struct obj
*curr
, *otmp
, *obj
= *objp
;
2291 boolean quantum_cat
, cursed_mbag
, loot_out
, loot_in
, loot_in_first
,
2292 stash_one
, inokay
, outokay
, outmaybe
;
2293 char c
, emptymsg
[BUFSZ
], qbuf
[QBUFSZ
], pbuf
[QBUFSZ
], xbuf
[QBUFSZ
];
2296 abort_looting
= FALSE
;
2303 pline("%s locked.", Tobjnam(obj
, "are"));
2305 You("must put it down to unlock.");
2308 } else if (obj
->otrapped
) {
2310 You("open %s...", the(xname(obj
)));
2312 (void) chest_trap(obj
, HAND
, FALSE
);
2313 /* even if the trap fails, you've used up this turn */
2314 if (multi
>= 0) { /* in case we didn't become paralyzed */
2316 multi_reason
= "opening a container";
2319 abort_looting
= TRUE
;
2324 current_container
= obj
; /* for use by in/out_container */
2326 * From here on out, all early returns go through 'containerdone:'.
2329 /* check for Schroedinger's Cat */
2330 quantum_cat
= SchroedingersBox(current_container
);
2332 observe_quantum_cat(current_container
);
2335 /* sometimes toss objects if a cursed magic bag */
2336 cursed_mbag
= (Is_mbag(current_container
) && current_container
->cursed
2337 && Has_contents(current_container
));
2341 for (curr
= current_container
->cobj
; curr
; curr
= otmp
) {
2344 obj_extract_self(curr
);
2345 loss
+= mbag_item_gone(held
, curr
);
2350 You("owe %ld %s for lost merchandise.", loss
, currency(loss
));
2351 current_container
->owt
= weight(current_container
);
2353 inokay
= (invent
!= 0
2354 && !(invent
== current_container
&& !current_container
->nobj
));
2355 outokay
= Has_contents(current_container
);
2356 if (!outokay
) /* preformat the empty-container message */
2357 Sprintf(emptymsg
, "%s is %sempty.", Ysimple_name2(current_container
),
2358 (quantum_cat
|| cursed_mbag
) ? "now " : "");
2361 * What-to-do prompt's list of possible actions:
2362 * always include the look-inside choice (':');
2363 * include the take-out choice ('o') if container
2364 * has anything in it or if player doesn't yet know
2365 * that it's empty (latter can change on subsequent
2366 * iterations if player picks ':' response);
2367 * include the put-in choices ('i','s') if hero
2368 * carries any inventory (including gold);
2369 * include do-both when 'o' is available, even if
2370 * inventory is empty--taking out could alter that;
2371 * include do-both-reversed when 'i' is available,
2372 * even if container is empty--for similar reason;
2373 * include the next container choice ('n') when
2374 * relevant, and make it the default;
2375 * always include the quit choice ('q'), and make
2376 * it the default if there's no next containter;
2377 * include the help choice (" or ?") if `cmdassist'
2378 * run-time option is set;
2379 * (Player can pick any of (o,i,b,r,n,s,?) even when
2380 * they're not listed among the available actions.)
2382 * Do what with <the/your/Shk's container>? [:oibrs nq or ?] (q)
2384 * <The/Your/Shk's container> is empty. Do what with it? [:irs nq or ?]
2386 for (;;) { /* repeats iff '?' or ":' gets chosen */
2387 outmaybe
= (outokay
|| !current_container
->cknown
);
2389 (void) safe_qbuf(qbuf
, (char *) 0, " is empty. Do what with it?",
2390 current_container
, Yname2
, Ysimple_name2
,
2393 (void) safe_qbuf(qbuf
, "Do what with ", "?", current_container
,
2394 yname
, ysimple_name
, "it");
2395 /* ask player about what to do with this container */
2396 if (flags
.menu_style
== MENU_PARTIAL
2397 || flags
.menu_style
== MENU_FULL
) {
2398 if (!inokay
&& !outmaybe
) {
2399 /* nothing to take out, nothing to put in;
2400 trying to do both will yield proper feedback */
2403 c
= in_or_out_menu(qbuf
, current_container
, outmaybe
, inokay
,
2404 (boolean
) (used
!= 0), more_containers
);
2406 } else { /* TRADITIONAL or COMBINATION */
2407 xbuf
[0] = '\0'; /* list of extra acceptable responses */
2408 Strcpy(pbuf
, ":"); /* look inside */
2409 Strcat(outmaybe
? pbuf
: xbuf
, "o"); /* take out */
2410 Strcat(inokay
? pbuf
: xbuf
, "i"); /* put in */
2411 Strcat(outmaybe
? pbuf
: xbuf
, "b"); /* both */
2412 Strcat(inokay
? pbuf
: xbuf
, "rs"); /* reversed, stash */
2413 Strcat(pbuf
, " "); /* separator */
2414 Strcat(more_containers
? pbuf
: xbuf
, "n"); /* next container */
2415 Strcat(pbuf
, "q"); /* quit */
2416 if (iflags
.cmdassist
)
2417 /* this unintentionally allows user to answer with 'o' or
2418 'r'; fortunately, those are already valid choices here */
2419 Strcat(pbuf
, " or ?"); /* help */
2423 Strcat(strcat(pbuf
, "\033"), xbuf
);
2424 c
= yn_function(qbuf
, pbuf
, more_containers
? 'n' : 'q');
2425 } /* PARTIAL|FULL vs other modes */
2428 explain_container_prompt(more_containers
);
2429 } else if (c
== ':') { /* note: will set obj->cknown */
2430 if (!current_container
->cknown
)
2431 used
= 1; /* gaining info */
2432 container_contents(current_container
, FALSE
, FALSE
, TRUE
);
2435 } /* loop until something other than '?' or ':' is picked */
2438 abort_looting
= TRUE
;
2439 if (c
== 'n' || c
== 'q') /* [not strictly needed; falling thru works] */
2441 loot_out
= (c
== 'o' || c
== 'b' || c
== 'r');
2442 loot_in
= (c
== 'i' || c
== 'b' || c
== 'r');
2443 loot_in_first
= (c
== 'r'); /* both, reversed */
2444 stash_one
= (c
== 's');
2446 /* out-only or out before in */
2447 if (loot_out
&& !loot_in_first
) {
2448 if (!Has_contents(current_container
)) {
2449 pline1(emptymsg
); /* <whatever> is empty. */
2450 if (!current_container
->cknown
)
2452 current_container
->cknown
= 1;
2454 add_valid_menu_class(0); /* reset */
2455 if (flags
.menu_style
== MENU_TRADITIONAL
)
2456 used
|= traditional_loot(FALSE
);
2458 used
|= (menu_loot(0, FALSE
) > 0);
2462 if ((loot_in
|| stash_one
)
2463 && (!invent
|| (invent
== current_container
&& !invent
->nobj
))) {
2464 You("don't have anything%s to %s.", invent
? " else" : "",
2465 stash_one
? "stash" : "put in");
2466 loot_in
= stash_one
= FALSE
;
2470 * Gone: being nice about only selecting food if we know we are
2471 * putting things in an ice chest.
2474 add_valid_menu_class(0); /* reset */
2475 if (flags
.menu_style
== MENU_TRADITIONAL
)
2476 used
|= traditional_loot(TRUE
);
2478 used
|= (menu_loot(0, TRUE
) > 0);
2479 } else if (stash_one
) {
2480 /* put one item into container */
2481 if ((otmp
= getobj(stashable
, "stash")) != 0) {
2482 if (in_container(otmp
)) {
2485 /* couldn't put selected item into container for some
2486 reason; might need to undo splitobj() */
2487 for (curr
= invent
; curr
; curr
= curr
->nobj
)
2488 if (curr
->nobj
== otmp
)
2490 if (curr
&& curr
->invlet
== otmp
->invlet
)
2491 (void) merged(&curr
, &otmp
);
2495 /* putting something in might have triggered magic bag explosion */
2496 if (!current_container
)
2500 if (loot_out
&& loot_in_first
) {
2501 if (!Has_contents(current_container
)) {
2502 pline1(emptymsg
); /* <whatever> is empty. */
2503 if (!current_container
->cknown
)
2505 current_container
->cknown
= 1;
2507 add_valid_menu_class(0); /* reset */
2508 if (flags
.menu_style
== MENU_TRADITIONAL
)
2509 used
|= traditional_loot(FALSE
);
2511 used
|= (menu_loot(0, FALSE
) > 0);
2517 /* Not completely correct; if we put something in without knowing
2518 whatever was already inside, now we suddenly do. That can't
2519 be helped unless we want to track things item by item and then
2520 deal with containers whose contents are "partly known". */
2521 if (current_container
)
2522 current_container
->cknown
= 1;
2526 *objp
= current_container
; /* might have become null */
2527 if (current_container
)
2528 current_container
= 0; /* avoid hanging on to stale pointer */
2530 abort_looting
= TRUE
;
2534 /* loot current_container (take things out or put things in), by prompting */
2536 traditional_loot(put_in
)
2539 int FDECL((*actionfunc
), (OBJ_P
)), FDECL((*checkfunc
), (OBJ_P
));
2540 struct obj
**objlist
;
2541 char selection
[MAXOCLASSES
+ 1];
2543 boolean one_by_one
, allflag
;
2544 int used
= 0, menu_on_request
= 0;
2549 actionfunc
= in_container
;
2552 action
= "take out";
2553 objlist
= &(current_container
->cobj
);
2554 actionfunc
= out_container
;
2555 checkfunc
= (int FDECL((*), (OBJ_P
))) 0;
2558 if (query_classes(selection
, &one_by_one
, &allflag
, action
, *objlist
,
2559 FALSE
, &menu_on_request
)) {
2560 if (askchain(objlist
, (one_by_one
? (char *) 0 : selection
), allflag
,
2561 actionfunc
, checkfunc
, 0, action
))
2563 } else if (menu_on_request
< 0) {
2564 used
= (menu_loot(menu_on_request
, put_in
) > 0);
2569 /* loot current_container (take things out or put things in), using a menu */
2571 menu_loot(retry
, put_in
)
2575 int n
, i
, n_looted
= 0;
2576 boolean all_categories
= TRUE
, loot_everything
= FALSE
;
2578 const char *action
= put_in
? "Put in" : "Take out";
2579 struct obj
*otmp
, *otmp2
;
2580 menu_item
*pick_list
;
2585 all_categories
= (retry
== -2);
2586 } else if (flags
.menu_style
== MENU_FULL
) {
2587 all_categories
= FALSE
;
2588 Sprintf(buf
, "%s what type of objects?", action
);
2590 ? ALL_TYPES
| BUC_ALLBKNOWN
| BUC_UNKNOWN
2591 : ALL_TYPES
| CHOOSE_ALL
| BUC_ALLBKNOWN
| BUC_UNKNOWN
;
2592 n
= query_category(buf
, put_in
? invent
: current_container
->cobj
,
2593 mflags
, &pick_list
, PICK_ANY
);
2596 for (i
= 0; i
< n
; i
++) {
2597 if (pick_list
[i
].item
.a_int
== 'A')
2598 loot_everything
= TRUE
;
2599 else if (pick_list
[i
].item
.a_int
== ALL_TYPES_SELECTED
)
2600 all_categories
= TRUE
;
2602 add_valid_menu_class(pick_list
[i
].item
.a_int
);
2604 free((genericptr_t
) pick_list
);
2607 if (loot_everything
) {
2608 current_container
->cknown
= 1;
2609 for (otmp
= current_container
->cobj
; otmp
; otmp
= otmp2
) {
2611 res
= out_container(otmp
);
2616 mflags
= INVORDER_SORT
;
2617 if (put_in
&& flags
.invlet_constant
)
2618 mflags
|= USE_INVLET
;
2620 current_container
->cknown
= 1;
2621 Sprintf(buf
, "%s what?", action
);
2622 n
= query_objlist(buf
, put_in
? &invent
: &(current_container
->cobj
),
2623 mflags
, &pick_list
, PICK_ANY
,
2624 all_categories
? allow_all
: allow_category
);
2627 for (i
= 0; i
< n
; i
++) {
2628 otmp
= pick_list
[i
].item
.a_obj
;
2629 count
= pick_list
[i
].count
;
2630 if (count
> 0 && count
< otmp
->quan
) {
2631 otmp
= splitobj(otmp
, count
);
2632 /* special split case also handled by askchain() */
2634 res
= put_in
? in_container(otmp
) : out_container(otmp
);
2636 if (!current_container
) {
2637 /* otmp caused current_container to explode;
2638 both are now gone */
2639 otmp
= 0; /* and break loop */
2640 } else if (otmp
&& otmp
!= pick_list
[i
].item
.a_obj
) {
2641 /* split occurred, merge again */
2642 (void) merged(&pick_list
[i
].item
.a_obj
, &otmp
);
2647 free((genericptr_t
) pick_list
);
2654 in_or_out_menu(prompt
, obj
, outokay
, inokay
, alreadyused
, more_containers
)
2657 boolean outokay
, inokay
, alreadyused
, more_containers
;
2659 /* underscore is not a choice; it's used to skip element [0] */
2660 static const char lootchars
[] = "_:oibrsnq", abc_chars
[] = "_:abcdenq";
2663 menu_item
*pick_list
;
2666 const char *menuselector
= flags
.lootabc
? abc_chars
: lootchars
;
2669 win
= create_nhwindow(NHW_MENU
);
2672 any
.a_int
= 1; /* ':' */
2673 Sprintf(buf
, "Look inside %s", thesimpleoname(obj
));
2674 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
, buf
,
2677 any
.a_int
= 2; /* 'o' */
2678 Sprintf(buf
, "take %s out", something
);
2679 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2680 buf
, MENU_UNSELECTED
);
2683 any
.a_int
= 3; /* 'i' */
2684 Sprintf(buf
, "put %s in", something
);
2685 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2686 buf
, MENU_UNSELECTED
);
2689 any
.a_int
= 4; /* 'b' */
2690 Sprintf(buf
, "%stake out, then put in", inokay
? "both; " : "");
2691 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2692 buf
, MENU_UNSELECTED
);
2695 any
.a_int
= 5; /* 'r' */
2696 Sprintf(buf
, "%sput in, then take out",
2697 outokay
? "both reversed; " : "");
2698 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2699 buf
, MENU_UNSELECTED
);
2700 any
.a_int
= 6; /* 's' */
2701 Sprintf(buf
, "stash one item into %s", thesimpleoname(obj
));
2702 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2703 buf
, MENU_UNSELECTED
);
2706 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
2707 if (more_containers
) {
2708 any
.a_int
= 7; /* 'n' */
2709 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2710 "loot next container", MENU_SELECTED
);
2712 any
.a_int
= 8; /* 'q' */
2713 Strcpy(buf
, alreadyused
? "done" : "do nothing");
2714 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
, buf
,
2715 more_containers
? MENU_UNSELECTED
: MENU_SELECTED
);
2717 end_menu(win
, prompt
);
2718 n
= select_menu(win
, PICK_ONE
, &pick_list
);
2719 destroy_nhwindow(win
);
2721 int k
= pick_list
[0].item
.a_int
;
2723 if (n
> 1 && k
== (more_containers
? 7 : 8))
2724 k
= pick_list
[1].item
.a_int
;
2725 free((genericptr_t
) pick_list
);
2726 return lootchars
[k
]; /* :,o,i,b,r,s,n,q */
2728 return (n
== 0 && more_containers
) ? 'n' : 'q'; /* next or quit */
2731 static const char tippables
[] = { ALL_CLASSES
, TOOL_CLASS
, 0 };
2733 /* #tip command -- empty container contents onto floor */
2737 struct obj
*cobj
, *nobj
;
2740 char c
, buf
[BUFSZ
], qbuf
[BUFSZ
];
2741 const char *spillage
= 0;
2744 * doesn't require free hands;
2745 * limbs are needed to tip floor containers
2748 /* at present, can only tip things at current spot, not adjacent ones */
2749 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
2751 /* check floor container(s) first; at most one will be accessed */
2752 if ((boxes
= container_at(cc
.x
, cc
.y
, TRUE
)) > 0) {
2753 Sprintf(buf
, "You can't tip %s while carrying so much.",
2754 !flags
.verbose
? "a container" : (boxes
> 1) ? "one" : "it");
2755 if (!check_capacity(buf
) && able_to_loot(cc
.x
, cc
.y
, FALSE
)) {
2756 if (boxes
> 1 && (flags
.menu_style
!= MENU_TRADITIONAL
2757 || iflags
.menu_requested
)) {
2758 /* use menu to pick a container to tip */
2762 menu_item
*pick_list
= (menu_item
*) 0;
2763 struct obj dummyobj
, *otmp
;
2766 win
= create_nhwindow(NHW_MENU
);
2769 for (cobj
= level
.objects
[cc
.x
][cc
.y
], i
= 0; cobj
;
2770 cobj
= cobj
->nexthere
)
2771 if (Is_container(cobj
)) {
2774 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
2775 doname(cobj
), MENU_UNSELECTED
);
2779 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
2780 "", MENU_UNSELECTED
);
2781 any
.a_obj
= &dummyobj
;
2782 /* use 'i' for inventory unless there are so many
2783 containers that it's already being used */
2784 i
= (i
<= 'i' - 'a' && !flags
.lootabc
) ? 'i' : 0;
2785 add_menu(win
, NO_GLYPH
, &any
, i
, 0, ATR_NONE
,
2786 "tip something being carried", MENU_SELECTED
);
2788 end_menu(win
, "Tip which container?");
2789 n
= select_menu(win
, PICK_ONE
, &pick_list
);
2790 destroy_nhwindow(win
);
2792 * Deal with quirk of preselected item in pick-one menu:
2793 * n == 0 => picked preselected entry, toggling it off;
2794 * n == 1 => accepted preselected choice via SPACE or RETURN;
2795 * n == 2 => picked something other than preselected entry;
2796 * n == -1 => cancelled via ESC;
2798 otmp
= (n
<= 0) ? (struct obj
*) 0 : pick_list
[0].item
.a_obj
;
2799 if (n
> 1 && otmp
== &dummyobj
)
2800 otmp
= pick_list
[1].item
.a_obj
;
2802 free((genericptr_t
) pick_list
);
2803 if (otmp
&& otmp
!= &dummyobj
) {
2809 /* else pick-from-invent below */
2811 for (cobj
= level
.objects
[cc
.x
][cc
.y
]; cobj
; cobj
= nobj
) {
2812 nobj
= cobj
->nexthere
;
2813 if (!Is_container(cobj
))
2815 c
= ynq(safe_qbuf(qbuf
, "There is ", " here, tip it?",
2817 doname
, ansimpleoname
, "container"));
2823 /* can only tip one container at a time */
2830 /* either no floor container(s) or couldn't tip one or didn't tip any */
2831 cobj
= getobj(tippables
, "tip");
2836 if (Is_container(cobj
) || cobj
->otyp
== HORN_OF_PLENTY
) {
2840 /* assorted other cases */
2841 if (Is_candle(cobj
) && cobj
->lamplit
) {
2842 /* note "wax" even for tallow candles to avoid giving away info */
2844 } else if ((cobj
->otyp
== POT_OIL
&& cobj
->lamplit
)
2845 || (cobj
->otyp
== OIL_LAMP
&& cobj
->age
!= 0L)
2846 || (cobj
->otyp
== MAGIC_LAMP
&& cobj
->spe
!= 0)) {
2848 /* todo: reduce potion's remaining burn timer or oil lamp's fuel */
2849 } else if (cobj
->otyp
== CAN_OF_GREASE
&& cobj
->spe
> 0) {
2850 /* charged consumed below */
2851 spillage
= "grease";
2852 } else if (cobj
->otyp
== FOOD_RATION
|| cobj
->otyp
== CRAM_RATION
2853 || cobj
->otyp
== LEMBAS_WAFER
) {
2854 spillage
= "crumbs";
2855 } else if (cobj
->oclass
== VENOM_CLASS
) {
2860 if (is_pool(u
.ux
, u
.uy
))
2861 Sprintf(buf
, " and gradually %s", vtense(spillage
, "dissipate"));
2862 else if (is_lava(u
.ux
, u
.uy
))
2863 Sprintf(buf
, " and immediately %s away",
2864 vtense(spillage
, "burn"));
2865 pline("Some %s %s onto the %s%s.", spillage
,
2866 vtense(spillage
, "spill"), surface(u
.ux
, u
.uy
), buf
);
2867 /* shop usage message comes after the spill message */
2868 if (cobj
->otyp
== CAN_OF_GREASE
&& cobj
->spe
> 0) {
2869 consume_obj_charge(cobj
, TRUE
);
2871 /* something [useless] happened */
2874 /* anything not covered yet */
2875 if (cobj
->oclass
== POTION_CLASS
) /* can't pour potions... */
2876 pline_The("%s %s securely sealed.", xname(cobj
), otense(cobj
, "are"));
2877 else if (cobj
->otyp
== STATUE
)
2878 pline("Nothing interesting happens.");
2880 pline1(nothing_happens
);
2886 struct obj
*box
; /* or bag */
2888 xchar ox
= u
.ux
, oy
= u
.uy
; /* #tip only works at hero's location */
2889 boolean empty_it
= FALSE
,
2890 /* Shop handling: can't rely on the container's own unpaid
2891 or no_charge status because contents might differ with it.
2892 A carried container's contents will be flagged as unpaid
2893 or not, as appropriate, and need no special handling here.
2894 Items owned by the hero get sold to the shop without
2895 confirmation as with other uncontrolled drops. A floor
2896 container's contents will be marked no_charge if owned by
2897 hero, otherwise they're owned by the shop. By passing
2898 the contents through shop billing, they end up getting
2899 treated the same as in the carried case. We do so one
2900 item at a time instead of doing whole container at once
2901 to reduce the chance of exhausting shk's billing capacity. */
2902 maybeshopgoods
= !carried(box
) && costly_spot(ox
, oy
);
2904 /* caveat: this assumes that cknown, lknown, olocked, and otrapped
2905 fields haven't been overloaded to mean something special for the
2906 non-standard "container" horn of plenty */
2909 pline("It's locked.");
2910 } else if (box
->otrapped
) {
2911 /* we're not reaching inside but we're still handling it... */
2912 (void) chest_trap(box
, HAND
, FALSE
);
2913 /* even if the trap fails, you've used up this turn */
2914 if (multi
>= 0) { /* in case we didn't become paralyzed */
2916 multi_reason
= "tipping a container";
2919 } else if (box
->otyp
== BAG_OF_TRICKS
|| box
->otyp
== HORN_OF_PLENTY
) {
2920 boolean bag
= box
->otyp
== BAG_OF_TRICKS
;
2921 int old_spe
= box
->spe
, seen
= 0;
2923 if (maybeshopgoods
&& !box
->no_charge
)
2924 addtobill(box
, FALSE
, FALSE
, TRUE
);
2925 /* apply this bag/horn until empty or monster/object creation fails
2926 (if the latter occurs, force the former...) */
2928 if (!(bag
? bagotricks(box
, TRUE
, &seen
)
2929 : hornoplenty(box
, TRUE
)))
2931 } while (box
->spe
> 0);
2933 if (box
->spe
< old_spe
) {
2935 pline((seen
== 0) ? "Nothing seems to happen."
2936 : (seen
== 1) ? "A monster appears."
2937 : "Monsters appear!");
2938 /* check_unpaid wants to see a non-zero charge count */
2940 check_unpaid_usage(box
, TRUE
);
2941 box
->spe
= 0; /* empty */
2944 if (maybeshopgoods
&& !box
->no_charge
)
2945 subfrombill(box
, shop_keeper(*in_rooms(ox
, oy
, SHOPBASE
)));
2946 } else if (SchroedingersBox(box
)) {
2947 char yourbuf
[BUFSZ
];
2949 observe_quantum_cat(box
);
2950 if (!Has_contents(box
)) /* evidently a live cat came out */
2951 /* container type of "large box" is inferred */
2952 pline("%sbox is now empty.", Shk_Your(yourbuf
, box
));
2953 else /* holds cat corpse */
2956 } else if (!Has_contents(box
)) {
2958 pline("It's empty.");
2964 struct obj
*otmp
, *nobj
;
2965 boolean verbose
= FALSE
, highdrop
= !can_reach_floor(TRUE
),
2966 altarizing
= IS_ALTAR(levl
[ox
][oy
].typ
),
2967 cursed_mbag
= (Is_mbag(box
) && box
->cursed
);
2968 int held
= carried(box
);
2972 highdrop
= altarizing
= FALSE
;
2975 box
->cobj
->nobj
? "Objects spill" : "An object spills",
2976 !(highdrop
|| altarizing
) ? ':' : '.');
2977 for (otmp
= box
->cobj
; otmp
; otmp
= nobj
) {
2979 obj_extract_self(otmp
);
2981 if (box
->otyp
== ICE_BOX
) {
2982 removed_from_icebox(otmp
); /* resume rotting for corpse */
2983 } else if (cursed_mbag
&& !rn2(13)) {
2984 loss
+= mbag_item_gone(held
, otmp
);
2985 /* abbreviated drop format is no longer appropriate */
2990 if (maybeshopgoods
) {
2991 addtobill(otmp
, FALSE
, FALSE
, TRUE
);
2992 iflags
.suppress_price
++; /* doname formatting */
2996 /* might break or fall down stairs; handles altars itself */
3002 pline("%s %s to the %s.", Doname2(otmp
),
3003 otense(otmp
, "drop"), surface(ox
, oy
));
3005 pline("%s%c", doname(otmp
), nobj
? ',' : '.');
3009 iflags
.suppress_price
--; /* reset */
3011 if (loss
) /* magic bag lost some shop goods */
3012 You("owe %ld %s for lost merchandise.", loss
, currency(loss
));
3013 box
->owt
= weight(box
); /* mbag_item_gone() doesn't update this */
3015 (void) encumber_msg();