1 /* NetHack 3.6 pickup.c $NHDT-Date: 1470449858 2016/08/06 02:17:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.184 $ */
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 boolean
FDECL(autopick_testobj
, (struct obj
*, BOOLEAN_P
));
25 STATIC_DCL
int FDECL(autopick
, (struct obj
*, int, menu_item
**));
26 STATIC_DCL
int FDECL(count_categories
, (struct obj
*, int));
27 STATIC_DCL
long FDECL(carry_count
, (struct obj
*, struct obj
*, long,
28 BOOLEAN_P
, int *, int *));
29 STATIC_DCL
int FDECL(lift_object
, (struct obj
*, struct obj
*, long *,
31 STATIC_DCL boolean
FDECL(mbag_explodes
, (struct obj
*, int));
32 STATIC_PTR
int FDECL(in_container
, (struct obj
*));
33 STATIC_PTR
int FDECL(out_container
, (struct obj
*));
34 STATIC_DCL
void FDECL(removed_from_icebox
, (struct obj
*));
35 STATIC_DCL
long FDECL(mbag_item_gone
, (int, struct obj
*));
36 STATIC_DCL
void FDECL(observe_quantum_cat
, (struct obj
*));
37 STATIC_DCL
void FDECL(explain_container_prompt
, (BOOLEAN_P
));
38 STATIC_DCL
int FDECL(traditional_loot
, (BOOLEAN_P
));
39 STATIC_DCL
int FDECL(menu_loot
, (int, BOOLEAN_P
));
40 STATIC_DCL
char FDECL(in_or_out_menu
, (const char *, struct obj
*, BOOLEAN_P
,
41 BOOLEAN_P
, BOOLEAN_P
, 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_p
;
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_p
= &level
.objects
[u
.ux
][u
.uy
];
526 traverse_how
= BY_NEXTHERE
;
528 objchain_p
= &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_p
, 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_p
, 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_p
,
557 (traverse_how
| FEEL_COCKATRICE
),
558 &pick_list
, PICK_ANY
, all_but_uchain
);
563 for (n_picked
= i
= 0; i
< n
; i
++) {
564 res
= pickup_object(pick_list
[i
].item
.a_obj
, pick_list
[i
].count
,
567 break; /* can't continue */
571 free((genericptr_t
) pick_list
);
574 /* old style interface */
577 boolean all_of_a_type
, selective
;
578 char oclasses
[MAXOCLASSES
];
579 struct obj
*obj
, *obj2
;
581 oclasses
[0] = '\0'; /* types to consider (empty for all) */
582 all_of_a_type
= TRUE
; /* take all of considered types */
583 selective
= FALSE
; /* ask for each item */
585 /* check for more than one object */
586 for (obj
= *objchain_p
; obj
; obj
= FOLLOW(obj
, traverse_how
))
589 if (ct
== 1 && count
) {
590 /* if only one thing, then pick it */
592 lcount
= min(obj
->quan
, (long) count
);
594 if (pickup_object(obj
, lcount
, FALSE
) > 0)
595 n_picked
++; /* picked something */
598 } else if (ct
>= 2) {
601 There("are %s objects here.", (ct
<= 10) ? "several" : "many");
602 if (!query_classes(oclasses
, &selective
, &all_of_a_type
,
603 "pick up", *objchain_p
,
604 (traverse_how
& BY_NEXTHERE
) ? TRUE
: FALSE
,
609 traverse_how
|= INVORDER_SORT
;
610 n
= query_objlist("Pick up what?", objchain_p
, traverse_how
,
611 &pick_list
, PICK_ANY
,
612 (via_menu
== -2) ? allow_all
618 for (obj
= *objchain_p
; obj
; obj
= obj2
) {
619 obj2
= FOLLOW(obj
, traverse_how
);
620 if (!selective
&& oclasses
[0] && !index(oclasses
, obj
->oclass
))
624 if (!all_of_a_type
) {
627 (void) safe_qbuf(qbuf
, "Pick up ", "?", obj
, doname
,
628 ansimpleoname
, something
);
629 switch ((obj
->quan
< 2L) ? ynaq(qbuf
) : ynNaq(qbuf
)) {
631 goto end_query
; /* out 2 levels */
635 all_of_a_type
= TRUE
;
638 oclasses
[0] = obj
->oclass
;
642 case '#': /* count was entered */
644 continue; /* 0 count => No */
645 lcount
= (long) yn_number
;
646 if (lcount
> obj
->quan
)
657 if ((res
= pickup_object(obj
, lcount
, FALSE
)) < 0)
662 ; /* statement required after label */
666 if (hides_under(youmonst
.data
))
667 (void) hideunder(&youmonst
);
669 /* position may need updating (invisible hero) */
673 /* check if there's anything else here after auto-pickup is done */
675 check_here(n_picked
> 0);
677 return (n_tried
> 0);
681 is_autopickup_exception(obj
, grab
)
683 boolean grab
; /* forced pickup, rather than forced leave behind? */
686 * Does the text description of this match an exception?
688 struct autopickup_exception
689 *ape
= (grab
) ? iflags
.autopickup_exceptions
[AP_GRAB
]
690 : iflags
.autopickup_exceptions
[AP_LEAVE
];
693 char *objdesc
= makesingular(doname(obj
));
696 if (regex_match(objdesc
, ape
->regex
))
705 autopick_testobj(otmp
, calc_costly
)
709 static boolean costly
= FALSE
;
710 const char *otypes
= flags
.pickup_types
;
713 /* calculate 'costly' just once for a given autopickup operation */
715 costly
= (otmp
->where
== OBJ_FLOOR
716 && costly_spot(otmp
->ox
, otmp
->oy
));
718 /* first check: reject if an unpaid item in a shop */
719 if (costly
&& !otmp
->no_charge
)
722 /* check for pickup_types */
723 pickit
= (!*otypes
|| index(otypes
, otmp
->oclass
));
724 /* check for "always pick up */
726 pickit
= is_autopickup_exception(otmp
, TRUE
);
727 /* then for "never pick up */
729 pickit
= !is_autopickup_exception(otmp
, FALSE
);
730 /* pickup_thrown overrides pickup_types and exceptions */
732 pickit
= (flags
.pickup_thrown
&& otmp
->was_thrown
);
737 * Pick from the given list using flags.pickup_types. Return the number
738 * of items picked (not counts). Create an array that returns pointers
739 * and counts of the items to be picked up. If the number of items
740 * picked is zero, the pickup list is left alone. The caller of this
741 * function must free the pickup list.
744 autopick(olist
, follow
, pick_list
)
745 struct obj
*olist
; /* the object list */
746 int follow
; /* how to follow the object list */
747 menu_item
**pick_list
; /* list of objects and counts to pick up */
749 menu_item
*pi
; /* pick item */
752 boolean check_costly
= TRUE
;
754 /* first count the number of eligible items */
755 for (n
= 0, curr
= olist
; curr
; curr
= FOLLOW(curr
, follow
)) {
756 if (autopick_testobj(curr
, check_costly
))
758 check_costly
= FALSE
; /* only need to check once per autopickup */
762 *pick_list
= pi
= (menu_item
*) alloc(sizeof (menu_item
) * n
);
763 for (n
= 0, curr
= olist
; curr
; curr
= FOLLOW(curr
, follow
)) {
764 if (autopick_testobj(curr
, FALSE
)) {
765 pi
[n
].item
.a_obj
= curr
;
766 pi
[n
].count
= curr
->quan
;
775 * Put up a menu using the given object list. Only those objects on the
776 * list that meet the approval of the allow function are displayed. Return
777 * a count of the number of items selected, as well as an allocated array of
778 * menu_items, containing pointers to the objects selected and counts. The
779 * returned counts are guaranteed to be in bounds and non-zero.
782 * BY_NEXTHERE - Follow object list via nexthere instead of nobj.
783 * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
785 * USE_INVLET - Use object's invlet.
786 * INVORDER_SORT - Use hero's pack order.
787 * INCLUDE_HERO - Showing engulfer's invent; show hero too.
788 * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow".
789 * SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to
791 * FEEL_COCKATRICE - touch corpse.
794 query_objlist(qstr
, olist_p
, qflags
, pick_list
, how
, allow
)
795 const char *qstr
; /* query string */
796 struct obj
**olist_p
; /* the list to pick from */
797 int qflags
; /* options to control the query */
798 menu_item
**pick_list
; /* return list of items picked */
799 int how
; /* type of query */
800 boolean
FDECL((*allow
), (OBJ_P
)); /* allow function */
804 struct obj
*curr
, *last
, fake_hero_object
, *olist
= *olist_p
;
807 boolean printed_type_name
, first
,
808 sorted
= (qflags
& INVORDER_SORT
) != 0,
809 engulfer
= (qflags
& INCLUDE_HERO
) != 0;
811 *pick_list
= (menu_item
*) 0;
812 if (!olist
&& !engulfer
)
815 /* count the number of items allowed */
816 for (n
= 0, last
= 0, curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
))
817 if ((*allow
)(curr
)) {
824 /* don't autoselect swallowed hero if it's the only choice */
825 qflags
&= ~AUTOSELECT_SINGLE
;
828 if (n
== 0) /* nothing to pick here */
829 return (qflags
& SIGNAL_NOMENU
) ? -1 : 0;
831 if (n
== 1 && (qflags
& AUTOSELECT_SINGLE
)) {
832 *pick_list
= (menu_item
*) alloc(sizeof (menu_item
));
833 (*pick_list
)->item
.a_obj
= last
;
834 (*pick_list
)->count
= last
->quan
;
838 if (sorted
|| flags
.sortloot
!= 'n') {
840 (((flags
.sortloot
== 'f'
841 || (flags
.sortloot
== 'l' && !(qflags
& USE_INVLET
)))
843 : (qflags
& USE_INVLET
) ? SORTLOOT_INVLET
: 0)
844 | (flags
.sortpack
? SORTLOOT_PACK
: 0)),
845 (qflags
& BY_NEXTHERE
) ? TRUE
: FALSE
);
849 win
= create_nhwindow(NHW_MENU
);
853 * Run through the list and add the objects to the menu. If
854 * INVORDER_SORT is set, we'll run through the list once for
855 * each type so we can group them. The allow function will only
856 * be called once per object in the list.
858 pack
= flags
.inv_order
;
861 printed_type_name
= FALSE
;
862 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
863 if (sorted
&& curr
->oclass
!= *pack
)
865 if ((qflags
& FEEL_COCKATRICE
) && curr
->otyp
== CORPSE
866 && will_feel_cockatrice(curr
, FALSE
)) {
867 destroy_nhwindow(win
); /* stop the menu and revert */
868 (void) look_here(0, FALSE
);
871 if ((*allow
)(curr
)) {
872 /* if sorting, print type name (once only) */
873 if (sorted
&& !printed_type_name
) {
875 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
876 let_to_name(*pack
, FALSE
,
878 && iflags
.menu_head_objsym
)),
880 printed_type_name
= TRUE
;
884 add_menu(win
, obj_to_glyph(curr
), &any
,
885 (qflags
& USE_INVLET
) ? curr
->invlet
886 : (first
&& curr
->oclass
== COIN_CLASS
) ? '$' : 0,
887 def_oc_syms
[(int) objects
[curr
->otyp
].oc_class
].sym
,
888 ATR_NONE
, doname_with_price(curr
), MENU_UNSELECTED
);
893 } while (sorted
&& *pack
);
899 if (sorted
&& n
> 1) {
900 Sprintf(buf
, "%s Creatures",
901 is_animal(u
.ustuck
->data
) ? "Swallowed" : "Engulfed");
902 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
, buf
,
905 fake_hero_object
= zeroobj
;
906 fake_hero_object
.quan
= 1L; /* not strictly necessary... */
907 any
.a_obj
= &fake_hero_object
;
908 add_menu(win
, mon_to_glyph(&youmonst
), &any
,
909 /* fake inventory letter, no group accelerator */
910 CONTAINED_SYM
, 0, ATR_NONE
, an(self_lookat(buf
)),
915 n
= select_menu(win
, how
, pick_list
);
916 destroy_nhwindow(win
);
922 /* fix up counts: -1 means no count used => pick all;
923 if fake_hero_object was picked, discard that choice */
924 for (i
= k
= 0, mi
= *pick_list
; i
< n
; i
++, mi
++) {
925 if (mi
->item
.a_obj
== &fake_hero_object
)
927 if (mi
->count
== -1L || mi
->count
> mi
->item
.a_obj
->quan
)
928 mi
->count
= mi
->item
.a_obj
->quan
;
930 (*pick_list
)[k
] = *mi
;
934 /* fake_hero was only choice so discard whole list */
935 free((genericptr_t
) *pick_list
);
939 /* other stuff plus fake_hero; last slot is now unused */
940 (*pick_list
)[k
].item
= zeroany
;
941 (*pick_list
)[k
].count
= 0L;
945 /* -1 is used for SIGNAL_NOMENU, so callers don't expect it
946 to indicate that the player declined to make a choice */
947 n
= (qflags
& SIGNAL_ESCAPE
) ? -2 : 0;
953 * allow menu-based category (class) selection (for Drop,take off etc.)
957 query_category(qstr
, olist
, qflags
, pick_list
, how
)
958 const char *qstr
; /* query string */
959 struct obj
*olist
; /* the list to pick from */
960 int qflags
; /* behaviour modification flags */
961 menu_item
**pick_list
; /* return list of items picked */
962 int how
; /* type of query */
969 boolean collected_type_name
;
972 boolean do_unpaid
= FALSE
;
973 boolean do_blessed
= FALSE
, do_cursed
= FALSE
, do_uncursed
= FALSE
,
974 do_buc_unknown
= FALSE
;
975 int num_buc_types
= 0;
977 *pick_list
= (menu_item
*) 0;
980 if ((qflags
& UNPAID_TYPES
) && count_unpaid(olist
))
982 if ((qflags
& BUC_BLESSED
) && count_buc(olist
, BUC_BLESSED
)) {
986 if ((qflags
& BUC_CURSED
) && count_buc(olist
, BUC_CURSED
)) {
990 if ((qflags
& BUC_UNCURSED
) && count_buc(olist
, BUC_UNCURSED
)) {
994 if ((qflags
& BUC_UNKNOWN
) && count_buc(olist
, BUC_UNKNOWN
)) {
995 do_buc_unknown
= TRUE
;
999 ccount
= count_categories(olist
, qflags
);
1000 /* no point in actually showing a menu for a single category */
1001 if (ccount
== 1 && !do_unpaid
&& num_buc_types
<= 1
1002 && !(qflags
& BILLED_TYPES
)) {
1003 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
1004 if ((qflags
& WORN_TYPES
)
1005 && !(curr
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_WEAPON
)))
1010 *pick_list
= (menu_item
*) alloc(sizeof(menu_item
));
1011 (*pick_list
)->item
.a_int
= curr
->oclass
;
1014 debugpline0("query_category: no single object match");
1019 win
= create_nhwindow(NHW_MENU
);
1021 pack
= flags
.inv_order
;
1022 if ((qflags
& ALL_TYPES
) && (ccount
> 1)) {
1025 any
.a_int
= ALL_TYPES_SELECTED
;
1026 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1027 (qflags
& WORN_TYPES
) ? "All worn types" : "All types",
1033 collected_type_name
= FALSE
;
1034 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
1035 if (curr
->oclass
== *pack
) {
1036 if ((qflags
& WORN_TYPES
)
1037 && !(curr
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_WEAPON
)))
1039 if (!collected_type_name
) {
1041 any
.a_int
= curr
->oclass
;
1043 win
, NO_GLYPH
, &any
, invlet
++,
1044 def_oc_syms
[(int) objects
[curr
->otyp
].oc_class
].sym
,
1045 ATR_NONE
, let_to_name(*pack
, FALSE
,
1047 && iflags
.menu_head_objsym
),
1049 collected_type_name
= TRUE
;
1054 if (invlet
>= 'u') {
1055 impossible("query_category: too many categories");
1059 /* unpaid items if there are any */
1064 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
, "Unpaid items",
1067 /* billed items: checked by caller, so always include if BILLED_TYPES */
1068 if (qflags
& BILLED_TYPES
) {
1072 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1073 "Unpaid items already used up", MENU_UNSELECTED
);
1075 if (qflags
& CHOOSE_ALL
) {
1079 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1080 (qflags
& WORN_TYPES
) ? "Auto-select every item being worn"
1081 : "Auto-select every item",
1084 /* items with b/u/c/unknown if there are any */
1089 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1090 "Items known to be Blessed", MENU_UNSELECTED
);
1096 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1097 "Items known to be Cursed", MENU_UNSELECTED
);
1103 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1104 "Items known to be Uncursed", MENU_UNSELECTED
);
1106 if (do_buc_unknown
) {
1110 add_menu(win
, NO_GLYPH
, &any
, invlet
, 0, ATR_NONE
,
1111 "Items of unknown B/C/U status", MENU_UNSELECTED
);
1113 end_menu(win
, qstr
);
1114 n
= select_menu(win
, how
, pick_list
);
1115 destroy_nhwindow(win
);
1117 n
= 0; /* caller's don't expect -1 */
1122 count_categories(olist
, qflags
)
1127 boolean counted_category
;
1131 pack
= flags
.inv_order
;
1133 counted_category
= FALSE
;
1134 for (curr
= olist
; curr
; curr
= FOLLOW(curr
, qflags
)) {
1135 if (curr
->oclass
== *pack
) {
1136 if ((qflags
& WORN_TYPES
)
1137 && !(curr
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_WEAPON
)))
1139 if (!counted_category
) {
1141 counted_category
= TRUE
;
1150 /* could we carry `obj'? if not, could we carry some of it/them? */
1152 carry_count(obj
, container
, count
, telekinesis
, wt_before
, wt_after
)
1153 struct obj
*obj
, *container
; /* object to pick up, bag it's coming out of */
1155 boolean telekinesis
;
1156 int *wt_before
, *wt_after
;
1158 boolean adjust_wt
= container
&& carried(container
),
1159 is_gold
= obj
->oclass
== COIN_CLASS
;
1160 int wt
, iw
, ow
, oow
;
1161 long qq
, savequan
, umoney
;
1163 const char *verb
, *prefx1
, *prefx2
, *suffx
;
1164 char obj_nambuf
[BUFSZ
], where
[BUFSZ
];
1166 savequan
= obj
->quan
;
1168 umoney
= money_cnt(invent
);
1169 iw
= max_capacity();
1171 if (count
!= savequan
) {
1173 obj
->owt
= (unsigned) weight(obj
);
1175 wt
= iw
+ (int) obj
->owt
;
1177 wt
-= (container
->otyp
== BAG_OF_HOLDING
)
1178 ? (int) DELTA_CWT(container
, obj
)
1180 /* This will go with silver+copper & new gold weight */
1181 if (is_gold
) /* merged gold might affect cumulative weight */
1182 wt
-= (GOLD_WT(umoney
) + GOLD_WT(count
) - GOLD_WT(umoney
+ count
));
1183 if (count
!= savequan
) {
1184 obj
->quan
= savequan
;
1193 /* see how many we can lift */
1195 iw
-= (int) GOLD_WT(umoney
);
1197 qq
= GOLD_CAPACITY((long) iw
, umoney
);
1200 qq
= 50L - (umoney
% 100L) - 1L;
1203 for (; qq
<= count
; qq
+= 100L) {
1205 obj
->owt
= (unsigned) GOLD_WT(qq
);
1206 ow
= (int) GOLD_WT(umoney
+ qq
);
1207 ow
-= (container
->otyp
== BAG_OF_HOLDING
)
1208 ? (int) DELTA_CWT(container
, obj
)
1219 else if (qq
> count
)
1221 wt
= iw
+ (int) GOLD_WT(umoney
+ qq
);
1222 } else if (count
> 1 || count
< obj
->quan
) {
1224 * Ugh. Calc num to lift by changing the quan of of the
1225 * object and calling weight.
1227 * This works for containers only because containers
1228 * don't merge. -dean
1230 for (qq
= 1L; qq
<= count
; qq
++) {
1232 obj
->owt
= (unsigned) (ow
= weight(obj
));
1234 ow
-= (container
->otyp
== BAG_OF_HOLDING
)
1235 ? (int) DELTA_CWT(container
, obj
)
1243 /* there's only one, and we can't lift it */
1246 obj
->quan
= savequan
;
1250 /* some message will be given */
1251 Strcpy(obj_nambuf
, doname(obj
));
1253 Sprintf(where
, "in %s", the(xname(container
)));
1256 Strcpy(where
, "lying here");
1257 verb
= telekinesis
? "acquire" : "lift";
1260 /* lint suppression */
1261 *obj_nambuf
= *where
= '\0';
1264 /* we can carry qq of them */
1267 You("can only %s %s of the %s %s.", verb
,
1268 (qq
== 1L) ? "one" : "some", obj_nambuf
, where
);
1274 Strcpy(where
, "here"); /* slightly shorter form */
1275 if (invent
|| umoney
) {
1276 prefx1
= "you cannot ";
1278 suffx
= " any more";
1280 prefx1
= (obj
->quan
== 1L) ? "it " : "even one ";
1281 prefx2
= "is too heavy for you to ";
1284 There("%s %s %s, but %s%s%s%s.", otense(obj
, "are"), obj_nambuf
, where
,
1285 prefx1
, prefx2
, verb
, suffx
);
1287 /* *wt_after = iw; */
1291 /* determine whether character is able and player is willing to carry `obj' */
1294 lift_object(obj
, container
, cnt_p
, telekinesis
)
1295 struct obj
*obj
, *container
; /* object to pick up, bag it's coming out of */
1297 boolean telekinesis
;
1299 int result
, old_wt
, new_wt
, prev_encumbr
, next_encumbr
;
1301 if (obj
->otyp
== BOULDER
&& Sokoban
) {
1302 You("cannot get your %s around this %s.", body_part(HAND
),
1306 /* override weight consideration for loadstone picked up by anybody
1307 and for boulder picked up by hero poly'd into a giant; override
1308 availability of open inventory slot iff not already carrying one */
1309 if (obj
->otyp
== LOADSTONE
1310 || (obj
->otyp
== BOULDER
&& throws_rocks(youmonst
.data
))) {
1311 if (inv_cnt(FALSE
) < 52 || !carrying(obj
->otyp
)
1312 || merge_choice(invent
, obj
))
1313 return 1; /* lift regardless of current situation */
1314 /* if we reach here, we're out of slots and already have at least
1315 one of these, so treat this one more like a normal item */
1316 You("are carrying too much stuff to pick up %s %s.",
1317 (obj
->quan
== 1L) ? "another" : "more", simpleonames(obj
));
1321 *cnt_p
= carry_count(obj
, container
, *cnt_p
, telekinesis
,
1324 result
= -1; /* nothing lifted */
1325 } else if (obj
->oclass
!= COIN_CLASS
1326 /* [exception for gold coins will have to change
1327 if silver/copper ones ever get implemented] */
1328 && inv_cnt(FALSE
) >= 52 && !merge_choice(invent
, obj
)) {
1329 Your("knapsack cannot accommodate any more items.");
1330 result
= -1; /* nothing lifted */
1333 prev_encumbr
= near_capacity();
1334 if (prev_encumbr
< flags
.pickup_burden
)
1335 prev_encumbr
= flags
.pickup_burden
;
1336 next_encumbr
= calc_capacity(new_wt
- old_wt
);
1337 if (next_encumbr
> prev_encumbr
) {
1339 result
= 0; /* don't lift */
1342 long savequan
= obj
->quan
;
1345 Strcpy(qbuf
, (next_encumbr
> HVY_ENCUMBER
)
1347 : (next_encumbr
> MOD_ENCUMBER
)
1351 (void) strsubst(qbuf
, "lifting", "removing");
1353 (void) safe_qbuf(qbuf
, qbuf
, ". Continue?", obj
, doname
,
1354 ansimpleoname
, something
);
1355 obj
->quan
= savequan
;
1356 switch (ynq(qbuf
)) {
1364 break; /* 'y' => result == 1 */
1366 clear_nhwindow(WIN_MESSAGE
);
1371 if (obj
->otyp
== SCR_SCARE_MONSTER
&& result
<= 0 && !container
)
1377 * Pick up <count> of obj from the ground and add it to the hero's inventory.
1378 * Returns -1 if caller should break out of its loop, 0 if nothing picked
1379 * up, 1 if otherwise.
1382 pickup_object(obj
, count
, telekinesis
)
1385 boolean telekinesis
; /* not picking it up directly by hand */
1389 if (obj
->quan
< count
) {
1390 impossible("pickup_object: count %ld > quan %ld?", count
, obj
->quan
);
1394 /* In case of auto-pickup, where we haven't had a chance
1395 to look at it yet; affects docall(SCR_SCARE_MONSTER). */
1399 if (obj
== uchain
) { /* do not pick up attached chain */
1401 } else if (obj
->oartifact
&& !touch_artifact(obj
, &youmonst
)) {
1403 } else if (obj
->otyp
== CORPSE
) {
1404 if (fatal_corpse_mistake(obj
, telekinesis
)
1405 || rider_corpse_revival(obj
, telekinesis
))
1407 } else if (obj
->otyp
== SCR_SCARE_MONSTER
) {
1410 else if (!obj
->spe
&& !obj
->cursed
)
1413 pline_The("scroll%s %s to dust as you %s %s up.", plur(obj
->quan
),
1414 otense(obj
, "turn"), telekinesis
? "raise" : "pick",
1415 (obj
->quan
== 1L) ? "it" : "them");
1416 if (!(objects
[SCR_SCARE_MONSTER
].oc_name_known
)
1417 && !(objects
[SCR_SCARE_MONSTER
].oc_uname
))
1419 useupf(obj
, obj
->quan
);
1420 return 1; /* tried to pick something up and failed, but
1421 don't want to terminate pickup loop yet */
1425 if ((res
= lift_object(obj
, (struct obj
*) 0, &count
, telekinesis
)) <= 0)
1428 /* Whats left of the special case for gold :-) */
1429 if (obj
->oclass
== COIN_CLASS
)
1431 if (obj
->quan
!= count
&& obj
->otyp
!= LOADSTONE
)
1432 obj
= splitobj(obj
, count
);
1434 obj
= pick_obj(obj
);
1436 if (uwep
&& uwep
== obj
)
1437 mrg_to_wielded
= TRUE
;
1438 nearload
= near_capacity();
1439 prinv(nearload
== SLT_ENCUMBER
? moderateloadmsg
: (char *) 0, obj
,
1441 mrg_to_wielded
= FALSE
;
1446 * Do the actual work of picking otmp from the floor or monster's interior
1447 * and putting it in the hero's inventory. Take care of billing. Return a
1448 * pointer to the object where otmp ends up. This may be different
1449 * from otmp because of merging.
1455 obj_extract_self(otmp
);
1456 if (!u
.uswallow
&& otmp
!= uball
&& costly_spot(otmp
->ox
, otmp
->oy
)) {
1457 char saveushops
[5], fakeshop
[2];
1459 /* addtobill cares about your location rather than the object's;
1460 usually they'll be the same, but not when using telekinesis
1461 (if ever implemented) or a grappling hook */
1462 Strcpy(saveushops
, u
.ushops
);
1463 fakeshop
[0] = *in_rooms(otmp
->ox
, otmp
->oy
, SHOPBASE
);
1465 Strcpy(u
.ushops
, fakeshop
);
1466 /* sets obj->unpaid if necessary */
1467 addtobill(otmp
, TRUE
, FALSE
, FALSE
);
1468 Strcpy(u
.ushops
, saveushops
);
1469 /* if you're outside the shop, make shk notice */
1470 if (!index(u
.ushops
, *fakeshop
))
1471 remote_burglary(otmp
->ox
, otmp
->oy
);
1473 newsym(otmp
->ox
, otmp
->oy
);
1474 return addinv(otmp
); /* might merge it with other objects */
1478 * prints a message if encumbrance changed since the last check and
1479 * returns the new encumbrance value (from near_capacity()).
1484 static int oldcap
= UNENCUMBERED
;
1485 int newcap
= near_capacity();
1487 if (oldcap
< newcap
) {
1490 Your("movements are slowed slightly because of your load.");
1493 You("rebalance your load. Movement is difficult.");
1496 You("%s under your heavy load. Movement is very hard.",
1497 stagger(youmonst
.data
, "stagger"));
1500 You("%s move a handspan with this load!",
1501 newcap
== 4 ? "can barely" : "can't even");
1505 } else if (oldcap
> newcap
) {
1508 Your("movements are now unencumbered.");
1511 Your("movements are only slowed slightly by your load.");
1514 You("rebalance your load. Movement is still difficult.");
1517 You("%s under your load. Movement is still very hard.",
1518 stagger(youmonst
.data
, "stagger"));
1528 /* Is there a container at x,y. Optional: return count of containers at x,y */
1530 container_at(x
, y
, countem
)
1534 struct obj
*cobj
, *nobj
;
1535 int container_count
= 0;
1537 for (cobj
= level
.objects
[x
][y
]; cobj
; cobj
= nobj
) {
1538 nobj
= cobj
->nexthere
;
1539 if (Is_container(cobj
)) {
1545 return container_count
;
1549 able_to_loot(x
, y
, looting
)
1551 boolean looting
; /* loot vs tip */
1553 const char *verb
= looting
? "loot" : "tip";
1555 if (!can_reach_floor(TRUE
)) {
1556 if (u
.usteed
&& P_SKILL(P_RIDING
) < P_BASIC
)
1557 rider_cant_reach(); /* not skilled enough to reach */
1559 cant_reach_floor(x
, y
, FALSE
, TRUE
);
1561 } else if ((is_pool(x
, y
) && (looting
|| !Underwater
)) || is_lava(x
, y
)) {
1562 /* at present, can't loot in water even when Underwater;
1563 can tip underwater, but not when over--or stuck in--lava */
1564 You("cannot %s things that are deep in the %s.", verb
,
1565 hliquid(is_lava(x
, y
) ? "lava" : "water"));
1567 } else if (nolimbs(youmonst
.data
)) {
1568 pline("Without limbs, you cannot %s anything.", verb
);
1570 } else if (looting
&& !freehand()) {
1571 pline("Without a free %s, you cannot loot anything.",
1584 for (i
= -1; i
<= 1; i
++)
1585 for (j
= -1; j
<= 1; j
++) {
1588 if (isok(nx
, ny
) && MON_AT(nx
, ny
))
1595 do_loot_cont(cobjp
, cindex
, ccount
)
1597 int cindex
, ccount
; /* index of this container (1..N), number of them (N) */
1599 struct obj
*cobj
= *cobjp
;
1603 if (cobj
->olocked
) {
1606 cobj
->lknown
? "It is" : "Hmmm, it turns out to be");
1607 else if (cobj
->lknown
)
1608 pline("%s is locked.", The(xname(cobj
)));
1610 pline("Hmmm, %s turns out to be locked.", the(xname(cobj
)));
1616 if (cobj
->otyp
== BAG_OF_TRICKS
) {
1619 You("carefully open %s...", the(xname(cobj
)));
1620 pline("It develops a huge set of teeth and bites you!");
1622 losehp(Maybe_Half_Phys(tmp
), "carnivorous bag", KILLED_BY_AN
);
1623 makeknown(BAG_OF_TRICKS
);
1624 abort_looting
= TRUE
;
1628 You("%sopen %s...", (!cobj
->cknown
|| !cobj
->lknown
) ? "carefully " : "",
1630 return use_container(cobjp
, 0, (boolean
) (cindex
< ccount
));
1633 /* loot a container on the floor or loot saddle from mon. */
1637 struct obj
*cobj
, *nobj
;
1638 register int c
= -1;
1641 boolean underfoot
= TRUE
;
1642 const char *dont_find_anything
= "don't find anything";
1645 int prev_inquiry
= 0;
1646 boolean prev_loot
= FALSE
;
1649 abort_looting
= FALSE
;
1651 if (check_capacity((char *) 0)) {
1652 /* "Can't do that while carrying so much stuff." */
1655 if (nohands(youmonst
.data
)) {
1656 You("have no hands!"); /* not `body_part(HAND)' */
1660 if (rn2(6) && reverse_loot())
1663 pline("Being confused, you find nothing to loot.");
1664 return 1; /* costs a turn */
1665 } /* else fallthrough to normal looting */
1670 if (iflags
.menu_requested
)
1674 if ((num_conts
= container_at(cc
.x
, cc
.y
, TRUE
)) > 0) {
1675 boolean anyfound
= FALSE
;
1677 if (!able_to_loot(cc
.x
, cc
.y
, TRUE
))
1680 if (Blind
&& !uarmg
) {
1681 /* if blind and without gloves, attempting to #loot at the
1682 location of a cockatrice corpse is fatal before asking
1683 whether to manipulate any containers */
1684 for (nobj
= sobj_at(CORPSE
, cc
.x
, cc
.y
); nobj
;
1685 nobj
= nxtobj(nobj
, CORPSE
, TRUE
))
1686 if (will_feel_cockatrice(nobj
, FALSE
)) {
1687 feel_cockatrice(nobj
, FALSE
);
1688 /* if life-saved (or poly'd into stone golem),
1689 terminate attempt to loot */
1694 if (num_conts
> 1) {
1695 /* use a menu to loot many containers */
1699 menu_item
*pick_list
= (menu_item
*) 0;
1702 win
= create_nhwindow(NHW_MENU
);
1705 for (cobj
= level
.objects
[cc
.x
][cc
.y
]; cobj
;
1706 cobj
= cobj
->nexthere
)
1707 if (Is_container(cobj
)) {
1709 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1710 doname(cobj
), MENU_UNSELECTED
);
1712 end_menu(win
, "Loot which containers?");
1713 n
= select_menu(win
, PICK_ANY
, &pick_list
);
1714 destroy_nhwindow(win
);
1717 for (i
= 1; i
<= n
; i
++) {
1718 cobj
= pick_list
[i
- 1].item
.a_obj
;
1719 timepassed
|= do_loot_cont(&cobj
, i
, n
);
1720 if (abort_looting
) {
1721 /* chest trap or magic bag explosion or <esc> */
1722 free((genericptr_t
) pick_list
);
1726 free((genericptr_t
) pick_list
);
1731 for (cobj
= level
.objects
[cc
.x
][cc
.y
]; cobj
; cobj
= nobj
) {
1732 nobj
= cobj
->nexthere
;
1734 if (Is_container(cobj
)) {
1735 c
= ynq(safe_qbuf(qbuf
, "There is ", " here, loot it?",
1736 cobj
, doname
, ansimpleoname
,
1744 timepassed
|= do_loot_cont(&cobj
, 1, 1);
1746 /* chest trap or magic bag explosion or <esc> */
1753 } else if (IS_GRAVE(levl
[cc
.x
][cc
.y
].typ
)) {
1754 You("need to dig up the grave to effectively loot it...");
1758 * 3.3.1 introduced directional looting for some things.
1761 if (c
!= 'y' && mon_beside(u
.ux
, u
.uy
)) {
1762 if (!get_adjacent_loc("Loot in what direction?",
1763 "Invalid loot location", u
.ux
, u
.uy
, &cc
))
1765 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
1767 if (container_at(cc
.x
, cc
.y
, FALSE
))
1772 You("%s to loot on the %s.", dont_find_anything
,
1773 ceiling(cc
.x
, cc
.y
));
1777 mtmp
= m_at(cc
.x
, cc
.y
);
1779 timepassed
= loot_mon(mtmp
, &prev_inquiry
, &prev_loot
);
1780 /* always use a turn when choosing a direction is impaired,
1781 even if you've successfully targetted a saddled creature
1782 and then answered "no" to the "remove its saddle?" prompt */
1783 if (Confusion
|| Stunned
)
1786 /* Preserve pre-3.3.1 behaviour for containers.
1787 * Adjust this if-block to allow container looting
1788 * from one square away to change that in the future.
1791 if (container_at(cc
.x
, cc
.y
, FALSE
)) {
1793 You_cant("loot anything %sthere with %s in the way.",
1794 prev_inquiry
? "else " : "", mon_nam(mtmp
));
1797 You("have to be at a container to loot it.");
1800 You("%s %sthere to loot.", dont_find_anything
,
1801 (prev_inquiry
|| prev_loot
) ? "else " : "");
1805 } else if (c
!= 'y' && c
!= 'n') {
1806 You("%s %s to loot.", dont_find_anything
,
1807 underfoot
? "here" : "there");
1812 /* called when attempting to #loot while confused */
1816 struct obj
*goldob
= 0, *coffers
, *otmp
, boxdummy
;
1819 int n
, x
= u
.ux
, y
= u
.uy
;
1822 /* n objects: 1/(n+1) chance per object plus 1/(n+1) to fall off end
1824 for (n
= inv_cnt(TRUE
), otmp
= invent
; otmp
; --n
, otmp
= otmp
->nobj
)
1826 prinv("You find old loot:", otmp
, 0L);
1832 /* find a money object to mess with */
1833 for (goldob
= invent
; goldob
; goldob
= goldob
->nobj
)
1834 if (goldob
->oclass
== COIN_CLASS
) {
1835 contribution
= ((long) rnd(5) * goldob
->quan
+ 4L) / 5L;
1836 if (contribution
< goldob
->quan
)
1837 goldob
= splitobj(goldob
, contribution
);
1843 if (!IS_THRONE(levl
[x
][y
].typ
)) {
1845 /* the dropped gold might have fallen to lower level */
1847 pline("Ok, now there is loot here.");
1849 /* find original coffers chest if present, otherwise use nearest one
1852 for (coffers
= fobj
; coffers
; coffers
= coffers
->nobj
)
1853 if (coffers
->otyp
== CHEST
) {
1854 if (coffers
->spe
== 2)
1855 break; /* a throne room chest */
1857 || distu(coffers
->ox
, coffers
->oy
)
1858 < distu(otmp
->ox
, otmp
->oy
))
1859 otmp
= coffers
; /* remember closest ordinary chest */
1865 verbalize("Thank you for your contribution to reduce the debt.");
1867 (void) add_to_container(coffers
, goldob
);
1868 coffers
->owt
= weight(coffers
);
1869 coffers
->cknown
= 0;
1870 if (!coffers
->olocked
) {
1871 boxdummy
= zeroobj
, boxdummy
.otyp
= SPE_WIZARD_LOCK
;
1872 (void) boxlock(coffers
, &boxdummy
);
1874 } else if (levl
[x
][y
].looted
!= T_LOOTED
1875 && (mon
= makemon(courtmon(), x
, y
, NO_MM_FLAGS
)) != 0) {
1877 add_to_minv(mon
, goldob
);
1878 pline("The exchequer accepts your contribution.");
1880 levl
[x
][y
].looted
= T_LOOTED
;
1882 You("drop %s.", doname(goldob
));
1889 /* loot_mon() returns amount of time passed.
1892 loot_mon(mtmp
, passed_info
, prev_loot
)
1902 /* 3.3.1 introduced the ability to remove saddle from a steed.
1903 * *passed_info is set to TRUE if a loot query was given.
1904 * *prev_loot is set to TRUE if something was actually acquired in here.
1906 if (mtmp
&& mtmp
!= u
.usteed
&& (otmp
= which_armor(mtmp
, W_SADDLE
))) {
1911 Sprintf(qbuf
, "Do you want to remove the saddle from %s?",
1912 x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1913 SUPPRESS_SADDLE
, FALSE
));
1914 if ((c
= yn_function(qbuf
, ynqchars
, 'n')) == 'y') {
1915 if (nolimbs(youmonst
.data
)) {
1916 You_cant("do that without limbs."); /* not body_part(HAND) */
1920 You("can't. The saddle seems to be stuck to %s.",
1921 x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1922 SUPPRESS_SADDLE
, FALSE
));
1923 /* the attempt costs you time */
1926 obj_extract_self(otmp
);
1927 if ((unwornmask
= otmp
->owornmask
) != 0L) {
1928 mtmp
->misc_worn_check
&= ~unwornmask
;
1929 otmp
->owornmask
= 0L;
1930 update_mon_intrinsics(mtmp
, otmp
, FALSE
, FALSE
);
1932 otmp
= hold_another_object(otmp
, "You drop %s!", doname(otmp
),
1934 timepassed
= rnd(3);
1937 } else if (c
== 'q') {
1941 /* 3.4.0 introduced ability to pick things up from swallower's stomach */
1943 int count
= passed_info
? *passed_info
: 0;
1945 timepassed
= pickup(count
);
1951 * Decide whether an object being placed into a magic bag will cause
1952 * it to explode. If the object is a bag itself, check recursively.
1955 mbag_explodes(obj
, depthin
)
1959 /* these won't cause an explosion when they're empty */
1960 if ((obj
->otyp
== WAN_CANCELLATION
|| obj
->otyp
== BAG_OF_TRICKS
)
1964 /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
1965 if ((Is_mbag(obj
) || obj
->otyp
== WAN_CANCELLATION
)
1966 && (rn2(1 << (depthin
> 7 ? 7 : depthin
)) <= depthin
))
1968 else if (Has_contents(obj
)) {
1971 for (otmp
= obj
->cobj
; otmp
; otmp
= otmp
->nobj
)
1972 if (mbag_explodes(otmp
, depthin
+ 1))
1978 /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
1981 register struct obj
*obj
;
1983 boolean floor_container
= !carried(current_container
);
1984 boolean was_unpaid
= FALSE
;
1987 if (!current_container
) {
1988 impossible("<in> no current_container?");
1990 } else if (obj
== uball
|| obj
== uchain
) {
1991 You("must be kidding.");
1993 } else if (obj
== current_container
) {
1994 pline("That would be an interesting topological exercise.");
1996 } else if (obj
->owornmask
& (W_ARMOR
| W_ACCESSORY
)) {
1997 Norep("You cannot %s %s you are wearing.",
1998 Icebox
? "refrigerate" : "stash", something
);
2000 } else if ((obj
->otyp
== LOADSTONE
) && obj
->cursed
) {
2002 pline_The("stone%s won't leave your person.", plur(obj
->quan
));
2004 } else if (obj
->otyp
== AMULET_OF_YENDOR
2005 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
2006 || obj
->otyp
== BELL_OF_OPENING
2007 || obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
2008 /* Prohibit Amulets in containers; if you allow it, monsters can't
2009 * steal them. It also becomes a pain to check to see if someone
2010 * has the Amulet. Ditto for the Candelabrum, the Bell and the Book.
2012 pline("%s cannot be confined in such trappings.", The(xname(obj
)));
2014 } else if (obj
->otyp
== LEASH
&& obj
->leashmon
!= 0) {
2015 pline("%s attached to your pet.", Tobjnam(obj
, "are"));
2017 } else if (obj
== uwep
) {
2022 setuwep((struct obj
*) 0);
2023 /* This uwep check is obsolete. It dates to 3.0 and earlier when
2024 * unwielding Firebrand would be fatal in hell if hero had no other
2025 * fire resistance. Life-saving would force it to be re-wielded.
2028 return 0; /* unwielded, died, rewielded */
2029 } else if (obj
== uswapwep
) {
2030 setuswapwep((struct obj
*) 0);
2031 } else if (obj
== uquiver
) {
2032 setuqwep((struct obj
*) 0);
2035 if (fatal_corpse_mistake(obj
, FALSE
))
2038 /* boxes, boulders, and big statues can't fit into any container */
2039 if (obj
->otyp
== ICE_BOX
|| Is_box(obj
) || obj
->otyp
== BOULDER
2040 || (obj
->otyp
== STATUE
&& bigmonst(&mons
[obj
->corpsenm
]))) {
2042 * xname() uses a static result array. Save obj's name
2043 * before current_container's name is computed. Don't
2044 * use the result of strcpy() within You() --- the order
2045 * of evaluation of the parameters is undefined.
2047 Strcpy(buf
, the(xname(obj
)));
2048 You("cannot fit %s into %s.", buf
, the(xname(current_container
)));
2054 if (obj_is_burning(obj
)) /* this used to be part of freeinv() */
2055 (void) snuff_lit(obj
);
2057 if (floor_container
&& costly_spot(u
.ux
, u
.uy
)) {
2058 /* defer gold until after put-in message */
2059 if (obj
->oclass
!= COIN_CLASS
) {
2060 /* sellobj() will take an unpaid item off the shop bill */
2061 was_unpaid
= obj
->unpaid
? TRUE
: FALSE
;
2062 /* don't sell when putting the item into your own container,
2063 * but handle billing correctly */
2064 sellobj_state(current_container
->no_charge
2065 ? SELL_DONTSELL
: SELL_DELIBERATE
);
2066 sellobj(obj
, u
.ux
, u
.uy
);
2067 sellobj_state(SELL_NORMAL
);
2070 if (Icebox
&& !age_is_relative(obj
)) {
2071 obj
->age
= monstermoves
- obj
->age
; /* actual age */
2072 /* stop any corpse timeouts when frozen */
2073 if (obj
->otyp
== CORPSE
&& obj
->timed
) {
2074 long rot_alarm
= stop_timer(ROT_CORPSE
, obj_to_any(obj
));
2076 (void) stop_timer(REVIVE_MON
, obj_to_any(obj
));
2077 /* mark a non-reviving corpse as such */
2081 } else if (Is_mbag(current_container
) && mbag_explodes(obj
, 0)) {
2082 /* explicitly mention what item is triggering the explosion */
2083 pline("As you put %s inside, you are blasted by a magical explosion!",
2085 /* did not actually insert obj yet */
2087 addtobill(obj
, FALSE
, FALSE
, TRUE
);
2088 obfree(obj
, (struct obj
*) 0);
2089 delete_contents(current_container
);
2090 if (!floor_container
)
2091 useup(current_container
);
2092 else if (obj_here(current_container
, u
.ux
, u
.uy
))
2093 useupf(current_container
, current_container
->quan
);
2095 panic("in_container: bag not found.");
2097 losehp(d(6, 6), "magical explosion", KILLED_BY_AN
);
2098 current_container
= 0; /* baggone = TRUE; */
2101 if (current_container
) {
2102 Strcpy(buf
, the(xname(current_container
)));
2103 You("put %s into %s.", doname(obj
), buf
);
2105 /* gold in container always needs to be added to credit */
2106 if (floor_container
&& obj
->oclass
== COIN_CLASS
)
2107 sellobj(obj
, current_container
->ox
, current_container
->oy
);
2108 (void) add_to_container(current_container
, obj
);
2109 current_container
->owt
= weight(current_container
);
2111 /* gold needs this, and freeinv() many lines above may cause
2112 * the encumbrance to disappear from the status, so just always
2113 * update status immediately.
2116 return (current_container
? 1 : -1);
2123 return (current_container
&& obj
!= current_container
);
2126 /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
2129 register struct obj
*obj
;
2131 register struct obj
*otmp
;
2132 boolean is_gold
= (obj
->oclass
== COIN_CLASS
);
2136 if (!current_container
) {
2137 impossible("<out> no current_container?");
2139 } else if (is_gold
) {
2140 obj
->owt
= weight(obj
);
2143 if (obj
->oartifact
&& !touch_artifact(obj
, &youmonst
))
2146 if (fatal_corpse_mistake(obj
, FALSE
))
2150 if ((res
= lift_object(obj
, current_container
, &count
, FALSE
)) <= 0)
2153 if (obj
->quan
!= count
&& obj
->otyp
!= LOADSTONE
)
2154 obj
= splitobj(obj
, count
);
2156 /* Remove the object from the list. */
2157 obj_extract_self(obj
);
2158 current_container
->owt
= weight(current_container
);
2161 removed_from_icebox(obj
);
2163 if (!obj
->unpaid
&& !carried(current_container
)
2164 && costly_spot(current_container
->ox
, current_container
->oy
)) {
2165 obj
->ox
= current_container
->ox
;
2166 obj
->oy
= current_container
->oy
;
2167 addtobill(obj
, FALSE
, FALSE
, FALSE
);
2170 pick_pick(obj
); /* shopkeeper feedback */
2173 loadlev
= near_capacity();
2174 prinv(loadlev
? ((loadlev
< MOD_ENCUMBER
)
2175 ? "You have a little trouble removing"
2176 : "You have much trouble removing")
2181 bot(); /* update character's gold piece count immediately */
2186 /* taking a corpse out of an ice box needs a couple of adjustments */
2188 removed_from_icebox(obj
)
2191 if (!age_is_relative(obj
)) {
2192 obj
->age
= monstermoves
- obj
->age
; /* actual age */
2193 if (obj
->otyp
== CORPSE
)
2194 start_corpse_timeout(obj
);
2198 /* an object inside a cursed bag of holding is being destroyed */
2200 mbag_item_gone(held
, item
)
2208 pline("%s %s vanished!", Doname2(item
), otense(item
, "have"));
2210 You("%s %s disappear!", Blind
? "notice" : "see", doname(item
));
2212 if (*u
.ushops
&& (shkp
= shop_keeper(*u
.ushops
)) != 0) {
2213 if (held
? (boolean
) item
->unpaid
: costly_spot(u
.ux
, u
.uy
))
2214 loss
= stolen_value(item
, u
.ux
, u
.uy
, (boolean
) shkp
->mpeaceful
,
2217 obfree(item
, (struct obj
*) 0);
2222 observe_quantum_cat(box
)
2225 static NEARDATA
const char sc
[] = "Schroedinger's Cat";
2226 struct obj
*deadcat
;
2227 struct monst
*livecat
;
2230 box
->spe
= 0; /* box->owt will be updated below */
2231 if (get_obj_location(box
, &ox
, &oy
, 0))
2232 box
->ox
= ox
, box
->oy
= oy
; /* in case it's being carried */
2234 /* this isn't really right, since any form of observation
2235 (telepathic or monster/object/food detection) ought to
2236 force the determination of alive vs dead state; but basing
2237 it just on opening the box is much simpler to cope with */
2239 ? makemon(&mons
[PM_HOUSECAT
], box
->ox
, box
->oy
, NO_MINVENT
)
2242 livecat
->mpeaceful
= 1;
2243 set_malign(livecat
);
2244 if (!canspotmon(livecat
))
2245 You("think %s brushed your %s.", something
, body_part(FOOT
));
2247 pline("%s inside the box is still alive!", Monnam(livecat
));
2248 (void) christen_monst(livecat
, sc
);
2250 deadcat
= mk_named_object(CORPSE
, &mons
[PM_HOUSECAT
],
2251 box
->ox
, box
->oy
, sc
);
2253 obj_extract_self(deadcat
);
2254 (void) add_to_container(box
, deadcat
);
2256 pline_The("%s inside the box is dead!",
2257 Hallucination
? rndmonnam((char *) 0) : "housecat");
2259 box
->owt
= weight(box
);
2265 /* used by askchain() to check for magic bag explosion */
2268 int FDECL((*fn
), (OBJ_P
));
2270 /* result is only meaningful while use_container() is executing */
2271 return ((fn
== in_container
|| fn
== out_container
)
2272 && !current_container
);
2276 explain_container_prompt(more_containers
)
2277 boolean more_containers
;
2279 static const char *const explaintext
[] = {
2280 "Container actions:", "", " : -- Look: examine contents",
2281 " o -- Out: take things out", " i -- In: put things in",
2282 " b -- Both: first take things out, then put things in",
2283 " r -- Reversed: put things in, then take things out",
2284 " s -- Stash: put one item in", "",
2285 " n -- Next: loot next selected container", " q -- Quit: finished",
2286 " ? -- Help: display this text.", "", 0
2288 const char *const *txtpp
;
2291 /* "Do what with <container>? [:oibrsq or ?] (q)" */
2292 if ((win
= create_nhwindow(NHW_TEXT
)) != WIN_ERR
) {
2293 for (txtpp
= explaintext
; *txtpp
; ++txtpp
) {
2294 if (!more_containers
&& !strncmp(*txtpp
, " n ", 3))
2296 putstr(win
, 0, *txtpp
);
2298 display_nhwindow(win
, FALSE
);
2299 destroy_nhwindow(win
);
2306 if (nohands(youmonst
.data
)) {
2307 You("have no hands!"); /* not `body_part(HAND)' */
2309 } else if (!freehand()) {
2310 You("have no free %s.", body_part(HAND
));
2316 static const char stashable
[] = { ALLOW_COUNT
, COIN_CLASS
, ALL_CLASSES
, 0 };
2319 use_container(objp
, held
, more_containers
)
2322 boolean more_containers
; /* True iff #loot multiple and this isn't last one */
2324 struct obj
*curr
, *otmp
, *obj
= *objp
;
2325 boolean quantum_cat
, cursed_mbag
, loot_out
, loot_in
, loot_in_first
,
2326 stash_one
, inokay
, outokay
, outmaybe
;
2327 char c
, emptymsg
[BUFSZ
], qbuf
[QBUFSZ
], pbuf
[QBUFSZ
], xbuf
[QBUFSZ
];
2330 abort_looting
= FALSE
;
2337 pline("%s locked.", Tobjnam(obj
, "are"));
2339 You("must put it down to unlock.");
2342 } else if (obj
->otrapped
) {
2344 You("open %s...", the(xname(obj
)));
2346 (void) chest_trap(obj
, HAND
, FALSE
);
2347 /* even if the trap fails, you've used up this turn */
2348 if (multi
>= 0) { /* in case we didn't become paralyzed */
2350 multi_reason
= "opening a container";
2353 abort_looting
= TRUE
;
2358 current_container
= obj
; /* for use by in/out_container */
2360 * From here on out, all early returns go through 'containerdone:'.
2363 /* check for Schroedinger's Cat */
2364 quantum_cat
= SchroedingersBox(current_container
);
2366 observe_quantum_cat(current_container
);
2369 /* sometimes toss objects if a cursed magic bag */
2370 cursed_mbag
= (Is_mbag(current_container
) && current_container
->cursed
2371 && Has_contents(current_container
));
2375 for (curr
= current_container
->cobj
; curr
; curr
= otmp
) {
2378 obj_extract_self(curr
);
2379 loss
+= mbag_item_gone(held
, curr
);
2384 You("owe %ld %s for lost merchandise.", loss
, currency(loss
));
2385 current_container
->owt
= weight(current_container
);
2387 inokay
= (invent
!= 0
2388 && !(invent
== current_container
&& !current_container
->nobj
));
2389 outokay
= Has_contents(current_container
);
2390 if (!outokay
) /* preformat the empty-container message */
2391 Sprintf(emptymsg
, "%s is %sempty.", Ysimple_name2(current_container
),
2392 (quantum_cat
|| cursed_mbag
) ? "now " : "");
2395 * What-to-do prompt's list of possible actions:
2396 * always include the look-inside choice (':');
2397 * include the take-out choice ('o') if container
2398 * has anything in it or if player doesn't yet know
2399 * that it's empty (latter can change on subsequent
2400 * iterations if player picks ':' response);
2401 * include the put-in choices ('i','s') if hero
2402 * carries any inventory (including gold);
2403 * include do-both when 'o' is available, even if
2404 * inventory is empty--taking out could alter that;
2405 * include do-both-reversed when 'i' is available,
2406 * even if container is empty--for similar reason;
2407 * include the next container choice ('n') when
2408 * relevant, and make it the default;
2409 * always include the quit choice ('q'), and make
2410 * it the default if there's no next containter;
2411 * include the help choice (" or ?") if `cmdassist'
2412 * run-time option is set;
2413 * (Player can pick any of (o,i,b,r,n,s,?) even when
2414 * they're not listed among the available actions.)
2416 * Do what with <the/your/Shk's container>? [:oibrs nq or ?] (q)
2418 * <The/Your/Shk's container> is empty. Do what with it? [:irs nq or ?]
2420 for (;;) { /* repeats iff '?' or ":' gets chosen */
2421 outmaybe
= (outokay
|| !current_container
->cknown
);
2423 (void) safe_qbuf(qbuf
, (char *) 0, " is empty. Do what with it?",
2424 current_container
, Yname2
, Ysimple_name2
,
2427 (void) safe_qbuf(qbuf
, "Do what with ", "?", current_container
,
2428 yname
, ysimple_name
, "it");
2429 /* ask player about what to do with this container */
2430 if (flags
.menu_style
== MENU_PARTIAL
2431 || flags
.menu_style
== MENU_FULL
) {
2432 if (!inokay
&& !outmaybe
) {
2433 /* nothing to take out, nothing to put in;
2434 trying to do both will yield proper feedback */
2437 c
= in_or_out_menu(qbuf
, current_container
, outmaybe
, inokay
,
2438 (boolean
) (used
!= 0), more_containers
);
2440 } else { /* TRADITIONAL or COMBINATION */
2441 xbuf
[0] = '\0'; /* list of extra acceptable responses */
2442 Strcpy(pbuf
, ":"); /* look inside */
2443 Strcat(outmaybe
? pbuf
: xbuf
, "o"); /* take out */
2444 Strcat(inokay
? pbuf
: xbuf
, "i"); /* put in */
2445 Strcat(outmaybe
? pbuf
: xbuf
, "b"); /* both */
2446 Strcat(inokay
? pbuf
: xbuf
, "rs"); /* reversed, stash */
2447 Strcat(pbuf
, " "); /* separator */
2448 Strcat(more_containers
? pbuf
: xbuf
, "n"); /* next container */
2449 Strcat(pbuf
, "q"); /* quit */
2450 if (iflags
.cmdassist
)
2451 /* this unintentionally allows user to answer with 'o' or
2452 'r'; fortunately, those are already valid choices here */
2453 Strcat(pbuf
, " or ?"); /* help */
2457 Strcat(strcat(pbuf
, "\033"), xbuf
);
2458 c
= yn_function(qbuf
, pbuf
, more_containers
? 'n' : 'q');
2459 } /* PARTIAL|FULL vs other modes */
2462 explain_container_prompt(more_containers
);
2463 } else if (c
== ':') { /* note: will set obj->cknown */
2464 if (!current_container
->cknown
)
2465 used
= 1; /* gaining info */
2466 container_contents(current_container
, FALSE
, FALSE
, TRUE
);
2469 } /* loop until something other than '?' or ':' is picked */
2472 abort_looting
= TRUE
;
2473 if (c
== 'n' || c
== 'q') /* [not strictly needed; falling thru works] */
2475 loot_out
= (c
== 'o' || c
== 'b' || c
== 'r');
2476 loot_in
= (c
== 'i' || c
== 'b' || c
== 'r');
2477 loot_in_first
= (c
== 'r'); /* both, reversed */
2478 stash_one
= (c
== 's');
2480 /* out-only or out before in */
2481 if (loot_out
&& !loot_in_first
) {
2482 if (!Has_contents(current_container
)) {
2483 pline1(emptymsg
); /* <whatever> is empty. */
2484 if (!current_container
->cknown
)
2486 current_container
->cknown
= 1;
2488 add_valid_menu_class(0); /* reset */
2489 if (flags
.menu_style
== MENU_TRADITIONAL
)
2490 used
|= traditional_loot(FALSE
);
2492 used
|= (menu_loot(0, FALSE
) > 0);
2496 if ((loot_in
|| stash_one
)
2497 && (!invent
|| (invent
== current_container
&& !invent
->nobj
))) {
2498 You("don't have anything%s to %s.", invent
? " else" : "",
2499 stash_one
? "stash" : "put in");
2500 loot_in
= stash_one
= FALSE
;
2504 * Gone: being nice about only selecting food if we know we are
2505 * putting things in an ice chest.
2508 add_valid_menu_class(0); /* reset */
2509 if (flags
.menu_style
== MENU_TRADITIONAL
)
2510 used
|= traditional_loot(TRUE
);
2512 used
|= (menu_loot(0, TRUE
) > 0);
2513 } else if (stash_one
) {
2514 /* put one item into container */
2515 if ((otmp
= getobj(stashable
, "stash")) != 0) {
2516 if (in_container(otmp
)) {
2519 /* couldn't put selected item into container for some
2520 reason; might need to undo splitobj() */
2521 (void) unsplitobj(otmp
);
2525 /* putting something in might have triggered magic bag explosion */
2526 if (!current_container
)
2530 if (loot_out
&& loot_in_first
) {
2531 if (!Has_contents(current_container
)) {
2532 pline1(emptymsg
); /* <whatever> is empty. */
2533 if (!current_container
->cknown
)
2535 current_container
->cknown
= 1;
2537 add_valid_menu_class(0); /* reset */
2538 if (flags
.menu_style
== MENU_TRADITIONAL
)
2539 used
|= traditional_loot(FALSE
);
2541 used
|= (menu_loot(0, FALSE
) > 0);
2547 /* Not completely correct; if we put something in without knowing
2548 whatever was already inside, now we suddenly do. That can't
2549 be helped unless we want to track things item by item and then
2550 deal with containers whose contents are "partly known". */
2551 if (current_container
)
2552 current_container
->cknown
= 1;
2556 *objp
= current_container
; /* might have become null */
2557 if (current_container
)
2558 current_container
= 0; /* avoid hanging on to stale pointer */
2560 abort_looting
= TRUE
;
2564 /* loot current_container (take things out or put things in), by prompting */
2566 traditional_loot(put_in
)
2569 int FDECL((*actionfunc
), (OBJ_P
)), FDECL((*checkfunc
), (OBJ_P
));
2570 struct obj
**objlist
;
2571 char selection
[MAXOCLASSES
+ 1];
2573 boolean one_by_one
, allflag
;
2574 int used
= 0, menu_on_request
= 0;
2579 actionfunc
= in_container
;
2582 action
= "take out";
2583 objlist
= &(current_container
->cobj
);
2584 actionfunc
= out_container
;
2585 checkfunc
= (int FDECL((*), (OBJ_P
))) 0;
2588 if (query_classes(selection
, &one_by_one
, &allflag
, action
, *objlist
,
2589 FALSE
, &menu_on_request
)) {
2590 if (askchain(objlist
, (one_by_one
? (char *) 0 : selection
), allflag
,
2591 actionfunc
, checkfunc
, 0, action
))
2593 } else if (menu_on_request
< 0) {
2594 used
= (menu_loot(menu_on_request
, put_in
) > 0);
2599 /* loot current_container (take things out or put things in), using a menu */
2601 menu_loot(retry
, put_in
)
2605 int n
, i
, n_looted
= 0;
2606 boolean all_categories
= TRUE
, loot_everything
= FALSE
;
2608 const char *action
= put_in
? "Put in" : "Take out";
2609 struct obj
*otmp
, *otmp2
;
2610 menu_item
*pick_list
;
2615 all_categories
= (retry
== -2);
2616 } else if (flags
.menu_style
== MENU_FULL
) {
2617 all_categories
= FALSE
;
2618 Sprintf(buf
, "%s what type of objects?", action
);
2619 mflags
= (ALL_TYPES
| BUC_ALLBKNOWN
| BUC_UNKNOWN
);
2621 mflags
|= CHOOSE_ALL
;
2622 n
= query_category(buf
, put_in
? invent
: current_container
->cobj
,
2623 mflags
, &pick_list
, PICK_ANY
);
2626 for (i
= 0; i
< n
; i
++) {
2627 if (pick_list
[i
].item
.a_int
== 'A')
2628 loot_everything
= TRUE
;
2629 else if (pick_list
[i
].item
.a_int
== ALL_TYPES_SELECTED
)
2630 all_categories
= TRUE
;
2632 add_valid_menu_class(pick_list
[i
].item
.a_int
);
2634 free((genericptr_t
) pick_list
);
2637 if (loot_everything
) {
2638 current_container
->cknown
= 1;
2639 for (otmp
= current_container
->cobj
; otmp
; otmp
= otmp2
) {
2641 res
= out_container(otmp
);
2646 mflags
= INVORDER_SORT
;
2647 if (put_in
&& flags
.invlet_constant
)
2648 mflags
|= USE_INVLET
;
2650 current_container
->cknown
= 1;
2651 Sprintf(buf
, "%s what?", action
);
2652 n
= query_objlist(buf
, put_in
? &invent
: &(current_container
->cobj
),
2653 mflags
, &pick_list
, PICK_ANY
,
2654 all_categories
? allow_all
: allow_category
);
2657 for (i
= 0; i
< n
; i
++) {
2658 otmp
= pick_list
[i
].item
.a_obj
;
2659 count
= pick_list
[i
].count
;
2660 if (count
> 0 && count
< otmp
->quan
) {
2661 otmp
= splitobj(otmp
, count
);
2662 /* special split case also handled by askchain() */
2664 res
= put_in
? in_container(otmp
) : out_container(otmp
);
2666 if (!current_container
) {
2667 /* otmp caused current_container to explode;
2668 both are now gone */
2669 otmp
= 0; /* and break loop */
2670 } else if (otmp
&& otmp
!= pick_list
[i
].item
.a_obj
) {
2671 /* split occurred, merge again */
2672 (void) merged(&pick_list
[i
].item
.a_obj
, &otmp
);
2677 free((genericptr_t
) pick_list
);
2684 in_or_out_menu(prompt
, obj
, outokay
, inokay
, alreadyused
, more_containers
)
2687 boolean outokay
, inokay
, alreadyused
, more_containers
;
2689 /* underscore is not a choice; it's used to skip element [0] */
2690 static const char lootchars
[] = "_:oibrsnq", abc_chars
[] = "_:abcdenq";
2693 menu_item
*pick_list
;
2696 const char *menuselector
= flags
.lootabc
? abc_chars
: lootchars
;
2699 win
= create_nhwindow(NHW_MENU
);
2702 any
.a_int
= 1; /* ':' */
2703 Sprintf(buf
, "Look inside %s", thesimpleoname(obj
));
2704 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
, buf
,
2707 any
.a_int
= 2; /* 'o' */
2708 Sprintf(buf
, "take %s out", something
);
2709 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2710 buf
, MENU_UNSELECTED
);
2713 any
.a_int
= 3; /* 'i' */
2714 Sprintf(buf
, "put %s in", something
);
2715 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2716 buf
, MENU_UNSELECTED
);
2719 any
.a_int
= 4; /* 'b' */
2720 Sprintf(buf
, "%stake out, then put in", inokay
? "both; " : "");
2721 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2722 buf
, MENU_UNSELECTED
);
2725 any
.a_int
= 5; /* 'r' */
2726 Sprintf(buf
, "%sput in, then take out",
2727 outokay
? "both reversed; " : "");
2728 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2729 buf
, MENU_UNSELECTED
);
2730 any
.a_int
= 6; /* 's' */
2731 Sprintf(buf
, "stash one item into %s", thesimpleoname(obj
));
2732 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2733 buf
, MENU_UNSELECTED
);
2736 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
2737 if (more_containers
) {
2738 any
.a_int
= 7; /* 'n' */
2739 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
,
2740 "loot next container", MENU_SELECTED
);
2742 any
.a_int
= 8; /* 'q' */
2743 Strcpy(buf
, alreadyused
? "done" : "do nothing");
2744 add_menu(win
, NO_GLYPH
, &any
, menuselector
[any
.a_int
], 0, ATR_NONE
, buf
,
2745 more_containers
? MENU_UNSELECTED
: MENU_SELECTED
);
2747 end_menu(win
, prompt
);
2748 n
= select_menu(win
, PICK_ONE
, &pick_list
);
2749 destroy_nhwindow(win
);
2751 int k
= pick_list
[0].item
.a_int
;
2753 if (n
> 1 && k
== (more_containers
? 7 : 8))
2754 k
= pick_list
[1].item
.a_int
;
2755 free((genericptr_t
) pick_list
);
2756 return lootchars
[k
]; /* :,o,i,b,r,s,n,q */
2758 return (n
== 0 && more_containers
) ? 'n' : 'q'; /* next or quit */
2761 static const char tippables
[] = { ALL_CLASSES
, TOOL_CLASS
, 0 };
2763 /* #tip command -- empty container contents onto floor */
2767 struct obj
*cobj
, *nobj
;
2770 char c
, buf
[BUFSZ
], qbuf
[BUFSZ
];
2771 const char *spillage
= 0;
2774 * doesn't require free hands;
2775 * limbs are needed to tip floor containers
2778 /* at present, can only tip things at current spot, not adjacent ones */
2779 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
2781 /* check floor container(s) first; at most one will be accessed */
2782 if ((boxes
= container_at(cc
.x
, cc
.y
, TRUE
)) > 0) {
2783 Sprintf(buf
, "You can't tip %s while carrying so much.",
2784 !flags
.verbose
? "a container" : (boxes
> 1) ? "one" : "it");
2785 if (!check_capacity(buf
) && able_to_loot(cc
.x
, cc
.y
, FALSE
)) {
2786 if (boxes
> 1 && (flags
.menu_style
!= MENU_TRADITIONAL
2787 || iflags
.menu_requested
)) {
2788 /* use menu to pick a container to tip */
2792 menu_item
*pick_list
= (menu_item
*) 0;
2793 struct obj dummyobj
, *otmp
;
2796 win
= create_nhwindow(NHW_MENU
);
2799 for (cobj
= level
.objects
[cc
.x
][cc
.y
], i
= 0; cobj
;
2800 cobj
= cobj
->nexthere
)
2801 if (Is_container(cobj
)) {
2804 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
2805 doname(cobj
), MENU_UNSELECTED
);
2809 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
2810 "", MENU_UNSELECTED
);
2811 any
.a_obj
= &dummyobj
;
2812 /* use 'i' for inventory unless there are so many
2813 containers that it's already being used */
2814 i
= (i
<= 'i' - 'a' && !flags
.lootabc
) ? 'i' : 0;
2815 add_menu(win
, NO_GLYPH
, &any
, i
, 0, ATR_NONE
,
2816 "tip something being carried", MENU_SELECTED
);
2818 end_menu(win
, "Tip which container?");
2819 n
= select_menu(win
, PICK_ONE
, &pick_list
);
2820 destroy_nhwindow(win
);
2822 * Deal with quirk of preselected item in pick-one menu:
2823 * n == 0 => picked preselected entry, toggling it off;
2824 * n == 1 => accepted preselected choice via SPACE or RETURN;
2825 * n == 2 => picked something other than preselected entry;
2826 * n == -1 => cancelled via ESC;
2828 otmp
= (n
<= 0) ? (struct obj
*) 0 : pick_list
[0].item
.a_obj
;
2829 if (n
> 1 && otmp
== &dummyobj
)
2830 otmp
= pick_list
[1].item
.a_obj
;
2832 free((genericptr_t
) pick_list
);
2833 if (otmp
&& otmp
!= &dummyobj
) {
2839 /* else pick-from-invent below */
2841 for (cobj
= level
.objects
[cc
.x
][cc
.y
]; cobj
; cobj
= nobj
) {
2842 nobj
= cobj
->nexthere
;
2843 if (!Is_container(cobj
))
2845 c
= ynq(safe_qbuf(qbuf
, "There is ", " here, tip it?",
2847 doname
, ansimpleoname
, "container"));
2853 /* can only tip one container at a time */
2860 /* either no floor container(s) or couldn't tip one or didn't tip any */
2861 cobj
= getobj(tippables
, "tip");
2866 if (Is_container(cobj
) || cobj
->otyp
== HORN_OF_PLENTY
) {
2870 /* assorted other cases */
2871 if (Is_candle(cobj
) && cobj
->lamplit
) {
2872 /* note "wax" even for tallow candles to avoid giving away info */
2874 } else if ((cobj
->otyp
== POT_OIL
&& cobj
->lamplit
)
2875 || (cobj
->otyp
== OIL_LAMP
&& cobj
->age
!= 0L)
2876 || (cobj
->otyp
== MAGIC_LAMP
&& cobj
->spe
!= 0)) {
2878 /* todo: reduce potion's remaining burn timer or oil lamp's fuel */
2879 } else if (cobj
->otyp
== CAN_OF_GREASE
&& cobj
->spe
> 0) {
2880 /* charged consumed below */
2881 spillage
= "grease";
2882 } else if (cobj
->otyp
== FOOD_RATION
|| cobj
->otyp
== CRAM_RATION
2883 || cobj
->otyp
== LEMBAS_WAFER
) {
2884 spillage
= "crumbs";
2885 } else if (cobj
->oclass
== VENOM_CLASS
) {
2890 if (is_pool(u
.ux
, u
.uy
))
2891 Sprintf(buf
, " and gradually %s", vtense(spillage
, "dissipate"));
2892 else if (is_lava(u
.ux
, u
.uy
))
2893 Sprintf(buf
, " and immediately %s away",
2894 vtense(spillage
, "burn"));
2895 pline("Some %s %s onto the %s%s.", spillage
,
2896 vtense(spillage
, "spill"), surface(u
.ux
, u
.uy
), buf
);
2897 /* shop usage message comes after the spill message */
2898 if (cobj
->otyp
== CAN_OF_GREASE
&& cobj
->spe
> 0) {
2899 consume_obj_charge(cobj
, TRUE
);
2901 /* something [useless] happened */
2904 /* anything not covered yet */
2905 if (cobj
->oclass
== POTION_CLASS
) /* can't pour potions... */
2906 pline_The("%s %s securely sealed.", xname(cobj
), otense(cobj
, "are"));
2907 else if (cobj
->otyp
== STATUE
)
2908 pline("Nothing interesting happens.");
2910 pline1(nothing_happens
);
2916 struct obj
*box
; /* or bag */
2918 xchar ox
= u
.ux
, oy
= u
.uy
; /* #tip only works at hero's location */
2919 boolean empty_it
= FALSE
, maybeshopgoods
;
2921 /* box is either held or on floor at hero's spot; no need to check for
2922 nesting; when held, we need to update its location to match hero's;
2923 for floor, the coordinate updating is redundant */
2924 if (get_obj_location(box
, &ox
, &oy
, 0))
2925 box
->ox
= ox
, box
->oy
= oy
;
2927 /* Shop handling: can't rely on the container's own unpaid
2928 or no_charge status because contents might differ with it.
2929 A carried container's contents will be flagged as unpaid
2930 or not, as appropriate, and need no special handling here.
2931 Items owned by the hero get sold to the shop without
2932 confirmation as with other uncontrolled drops. A floor
2933 container's contents will be marked no_charge if owned by
2934 hero, otherwise they're owned by the shop. By passing
2935 the contents through shop billing, they end up getting
2936 treated the same as in the carried case. We do so one
2937 item at a time instead of doing whole container at once
2938 to reduce the chance of exhausting shk's billing capacity. */
2939 maybeshopgoods
= !carried(box
) && costly_spot(box
->ox
, box
->oy
);
2941 /* caveat: this assumes that cknown, lknown, olocked, and otrapped
2942 fields haven't been overloaded to mean something special for the
2943 non-standard "container" horn of plenty */
2946 pline("It's locked.");
2947 } else if (box
->otrapped
) {
2948 /* we're not reaching inside but we're still handling it... */
2949 (void) chest_trap(box
, HAND
, FALSE
);
2950 /* even if the trap fails, you've used up this turn */
2951 if (multi
>= 0) { /* in case we didn't become paralyzed */
2953 multi_reason
= "tipping a container";
2956 } else if (box
->otyp
== BAG_OF_TRICKS
|| box
->otyp
== HORN_OF_PLENTY
) {
2957 boolean bag
= box
->otyp
== BAG_OF_TRICKS
;
2958 int old_spe
= box
->spe
, seen
= 0;
2960 if (maybeshopgoods
&& !box
->no_charge
)
2961 addtobill(box
, FALSE
, FALSE
, TRUE
);
2962 /* apply this bag/horn until empty or monster/object creation fails
2963 (if the latter occurs, force the former...) */
2965 if (!(bag
? bagotricks(box
, TRUE
, &seen
)
2966 : hornoplenty(box
, TRUE
)))
2968 } while (box
->spe
> 0);
2970 if (box
->spe
< old_spe
) {
2972 pline((seen
== 0) ? "Nothing seems to happen."
2973 : (seen
== 1) ? "A monster appears."
2974 : "Monsters appear!");
2975 /* check_unpaid wants to see a non-zero charge count */
2977 check_unpaid_usage(box
, TRUE
);
2978 box
->spe
= 0; /* empty */
2981 if (maybeshopgoods
&& !box
->no_charge
)
2982 subfrombill(box
, shop_keeper(*in_rooms(ox
, oy
, SHOPBASE
)));
2983 } else if (SchroedingersBox(box
)) {
2984 char yourbuf
[BUFSZ
];
2986 observe_quantum_cat(box
);
2987 if (!Has_contents(box
)) /* evidently a live cat came out */
2988 /* container type of "large box" is inferred */
2989 pline("%sbox is now empty.", Shk_Your(yourbuf
, box
));
2990 else /* holds cat corpse */
2993 } else if (!Has_contents(box
)) {
2995 pline("It's empty.");
3001 struct obj
*otmp
, *nobj
;
3002 boolean terse
, highdrop
= !can_reach_floor(TRUE
),
3003 altarizing
= IS_ALTAR(levl
[ox
][oy
].typ
),
3004 cursed_mbag
= (Is_mbag(box
) && box
->cursed
);
3005 int held
= carried(box
);
3009 highdrop
= altarizing
= FALSE
;
3010 terse
= !(highdrop
|| altarizing
|| costly_spot(box
->ox
, box
->oy
));
3012 /* Terse formatting is
3013 * "Objects spill out: obj1, obj2, obj3, ..., objN."
3014 * If any other messages intervene between objects, we revert to
3015 * "ObjK drops to the floor.", "ObjL drops to the floor.", &c.
3018 box
->cobj
->nobj
? "Objects spill" : "An object spills",
3020 for (otmp
= box
->cobj
; otmp
; otmp
= nobj
) {
3022 obj_extract_self(otmp
);
3023 otmp
->ox
= box
->ox
, otmp
->oy
= box
->oy
;
3025 if (box
->otyp
== ICE_BOX
) {
3026 removed_from_icebox(otmp
); /* resume rotting for corpse */
3027 } else if (cursed_mbag
&& !rn2(13)) {
3028 loss
+= mbag_item_gone(held
, otmp
);
3029 /* abbreviated drop format is no longer appropriate */
3034 if (maybeshopgoods
) {
3035 addtobill(otmp
, FALSE
, FALSE
, TRUE
);
3036 iflags
.suppress_price
++; /* doname formatting */
3040 /* might break or fall down stairs; handles altars itself */
3045 } else if (!terse
) {
3046 pline("%s %s to the %s.", Doname2(otmp
),
3047 otense(otmp
, "drop"), surface(ox
, oy
));
3049 pline("%s%c", doname(otmp
), nobj
? ',' : '.');
3050 iflags
.last_msg
= PLNMSG_OBJNAM_ONLY
;
3053 if (iflags
.last_msg
!= PLNMSG_OBJNAM_ONLY
)
3054 terse
= FALSE
; /* terse formatting has been interrupted */
3057 iflags
.suppress_price
--; /* reset */
3059 if (loss
) /* magic bag lost some shop goods */
3060 You("owe %ld %s for lost merchandise.", loss
, currency(loss
));
3061 box
->owt
= weight(box
); /* mbag_item_gone() doesn't update this */
3063 (void) encumber_msg();