dumplog message history groundwork
[aNetHack.git] / src / pickup.c
blob4b42be7080aa2cd21e27d286654a1b6584c3b096
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. */
5 /*
6 * Contains code for picking objects up, and container use.
7 */
9 #include "hack.h"
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 *,
16 BOOLEAN_P, int *));
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 *));
21 #if 0 /* not used */
22 STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
23 #endif
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 *,
30 BOOLEAN_P));
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)
72 static const char
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
78 touching them */
79 /* much simpler version of the look-here code; used by query_classes() */
80 STATIC_OVL void
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.
89 if (!otmp) {
90 impossible("simple_look(null)");
91 } else if (!(here ? otmp->nexthere : otmp->nobj)) {
92 pline1(doname(otmp));
93 } else {
94 winid tmpwin = create_nhwindow(NHW_MENU);
96 putstr(tmpwin, 0, "");
97 do {
98 putstr(tmpwin, 0, doname(otmp));
99 otmp = here ? otmp->nexthere : otmp->nobj;
100 } while (otmp);
101 display_nhwindow(tmpwin, TRUE);
102 destroy_nhwindow(tmpwin);
107 collect_obj_classes(ilets, otmp, here, filter, itemcount)
108 char ilets[];
109 register struct obj *otmp;
110 boolean here;
111 boolean FDECL((*filter), (OBJ_P));
112 int *itemcount;
114 register int iletct = 0;
115 register char c;
117 *itemcount = 0;
118 ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
119 while (otmp) {
120 c = def_oc_syms[(int) otmp->oclass].sym;
121 if (!index(ilets, c) && (!filter || (*filter)(otmp)))
122 ilets[iletct++] = c, ilets[iletct] = '\0';
123 *itemcount += 1;
124 otmp = here ? otmp->nexthere : otmp->nobj;
127 return iletct;
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").
142 STATIC_OVL boolean
143 query_classes(oclasses, one_at_a_time, everything, action, objs, here,
144 menu_on_demand)
145 char oclasses[];
146 boolean *one_at_a_time, *everything;
147 const char *action;
148 struct obj *objs;
149 boolean here;
150 int *menu_on_demand;
152 char ilets[30], inbuf[BUFSZ]; /* FIXME: hardcoded ilets[] length */
153 int iletct, oclassct;
154 boolean not_everything;
155 char qbuf[QBUFSZ];
156 boolean m_seen;
157 int itemcount;
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);
163 if (iletct == 0) {
164 return FALSE;
165 } else if (iletct == 1) {
166 oclasses[0] = def_char_to_objclass(ilets[0]);
167 oclasses[1] = '\0';
168 if (itemcount && menu_on_demand) {
169 ilets[iletct++] = 'm';
170 *menu_on_demand = 0;
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';
184 *menu_on_demand = 0;
186 ilets[iletct] = '\0';
187 ask_again:
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,
192 ilets);
193 getlin(qbuf, inbuf);
194 if (*inbuf == '\033')
195 return FALSE;
197 for (p = inbuf; (sym = *p++) != 0; ) {
198 if (sym == ' ')
199 continue;
200 else if (sym == 'A')
201 *one_at_a_time = TRUE;
202 else if (sym == 'a')
203 *everything = 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;
210 goto ask_again;
211 } else if (sym == 'i') {
212 (void) display_inventory((char *) 0, TRUE);
213 goto ask_again;
214 } else if (sym == 'm') {
215 m_seen = TRUE;
216 } else {
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';
222 } else {
223 if (!where)
224 where = !strcmp(action, "pick up") ? "here"
225 : !strcmp(action, "take out") ? "inside" : "";
226 if (*where)
227 There("are no %c's %s.", sym, where);
228 else
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;
236 return FALSE;
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' */
245 return TRUE;
248 /* check whether hero is bare-handedly touching a cockatrice corpse */
249 STATIC_OVL boolean
250 fatal_corpse_mistake(obj, remotely)
251 struct obj *obj;
252 boolean remotely;
254 if (uarmg || remotely || obj->otyp != CORPSE
255 || !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance)
256 return FALSE;
258 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
259 display_nhwindow(WIN_MESSAGE, FALSE); /* --More-- */
260 return FALSE;
263 pline("Touching %s is a fatal mistake.",
264 corpse_xname(obj, (const char *) 0, CXN_SINGULAR | CXN_ARTICLE));
265 instapetrify(killer_xname(obj));
266 return TRUE;
269 /* attempting to manipulate a Rider's corpse triggers its revival */
270 boolean
271 rider_corpse_revival(obj, remotely)
272 struct obj *obj;
273 boolean remotely;
275 if (!obj || obj->otyp != CORPSE || !is_rider(&mons[obj->corpsenm]))
276 return FALSE;
278 pline("At your %s, the corpse suddenly moves...",
279 remotely ? "attempted acquisition" : "touch");
280 (void) revive_corpse(obj);
281 exercise(A_WIS, FALSE);
282 return TRUE;
285 /* look at the objects at our location, unless there are too many of them */
286 STATIC_OVL void
287 check_here(picked_some)
288 boolean picked_some;
290 register struct obj *obj;
291 register int ct = 0;
293 /* count the objects here */
294 for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) {
295 if (obj != uchain)
296 ct++;
299 /* If there are objects here, take a look. */
300 if (ct) {
301 if (context.run)
302 nomul(0);
303 flush_screen(1);
304 (void) look_here(ct, picked_some);
305 } else {
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 */
314 STATIC_OVL boolean
315 n_or_more(obj)
316 struct obj *obj;
318 if (obj == uchain)
319 return FALSE;
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;
328 void
329 add_valid_menu_class(c)
330 int c;
332 static int vmc_count = 0;
334 if (c == 0) { /* reset */
335 vmc_count = 0;
336 class_filter = bucx_filter = shop_filter = FALSE;
337 } else {
338 valid_menu_classes[vmc_count++] = (char) c;
339 /* categorize the new class */
340 switch (c) {
341 case 'B':
342 case 'U':
343 case 'C': /*FALLTHRU*/
344 case 'X':
345 bucx_filter = TRUE;
346 break;
347 case 'u':
348 shop_filter = TRUE;
349 break;
350 default:
351 class_filter = TRUE;
352 break;
355 valid_menu_classes[vmc_count] = '\0';
358 /* query_objlist callback: return TRUE if not uchain */
359 STATIC_OVL boolean
360 all_but_uchain(obj)
361 struct obj *obj;
363 return (boolean) (obj != uchain);
366 /* query_objlist callback: return TRUE */
367 /*ARGUSED*/
368 boolean
369 allow_all(obj)
370 struct obj *obj UNUSED;
372 return TRUE;
375 boolean
376 allow_category(obj)
377 struct obj *obj;
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))
384 obj->bknown = TRUE;
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))
405 return FALSE;
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))
410 return FALSE;
411 /* check for particular bless/curse state */
412 if (bucx_filter) {
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))
419 return FALSE;
421 /* obj didn't fail any of the filter checks, so accept */
422 return TRUE;
425 #if 0 /* not used */
426 /* query_objlist callback: return TRUE if valid category (class), no uchain */
427 STATIC_OVL boolean
428 allow_cat_no_uchain(obj)
429 struct obj *obj;
431 if (obj != uchain
432 && ((index(valid_menu_classes,'u') && obj->unpaid)
433 || index(valid_menu_classes, obj->oclass)))
434 return TRUE;
435 return FALSE;
437 #endif
439 /* query_objlist callback: return TRUE if valid class and worn */
440 boolean
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.
452 * Arg what:
453 * >0 autopickup
454 * =0 interactive
455 * <0 pickup count of something
457 * Returns 1 if tried to pick something up, whether
458 * or not it succeeded.
461 pickup(what)
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;
468 int traverse_how;
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())
476 return 0;
478 if (what < 0) /* pick N of something */
479 count = -what;
480 else /* pick anything */
481 count = 0;
483 if (!u.uswallow) {
484 struct trap *ttmp;
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);
491 return 0;
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);
499 return 0;
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)) {
506 check_here(FALSE);
507 return 0;
509 if (notake(youmonst.data)) {
510 if (!autopickup)
511 You("are physically incapable of picking anything up.");
512 else
513 check_here(FALSE);
514 return 0;
517 /* if there's anything here, stop running */
518 if (OBJ_AT(u.ux, u.uy) && context.run && context.run != 8
519 && !context.nopick)
520 nomul(0);
523 add_valid_menu_class(0); /* reset */
524 if (!u.uswallow) {
525 objchain_p = &level.objects[u.ux][u.uy];
526 traverse_how = BY_NEXTHERE;
527 } else {
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.
537 if (autopickup) {
538 n = autopick(*objchain_p, traverse_how, &pick_list);
539 goto menu_pickup;
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 */
546 char qbuf[QBUFSZ];
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;
555 } else {
556 n = query_objlist("Pick up what?", objchain_p,
557 (traverse_how | FEEL_COCKATRICE),
558 &pick_list, PICK_ANY, all_but_uchain);
561 menu_pickup:
562 n_tried = n;
563 for (n_picked = i = 0; i < n; i++) {
564 res = pickup_object(pick_list[i].item.a_obj, pick_list[i].count,
565 FALSE);
566 if (res < 0)
567 break; /* can't continue */
568 n_picked += res;
570 if (pick_list)
571 free((genericptr_t) pick_list);
573 } else {
574 /* old style interface */
575 int ct = 0;
576 long lcount;
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))
587 ct++;
589 if (ct == 1 && count) {
590 /* if only one thing, then pick it */
591 obj = *objchain_p;
592 lcount = min(obj->quan, (long) count);
593 n_tried++;
594 if (pickup_object(obj, lcount, FALSE) > 0)
595 n_picked++; /* picked something */
596 goto end_query;
598 } else if (ct >= 2) {
599 int via_menu = 0;
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,
605 &via_menu)) {
606 if (!via_menu)
607 return 0;
608 if (selective)
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
613 : allow_category);
614 goto menu_pickup;
618 for (obj = *objchain_p; obj; obj = obj2) {
619 obj2 = FOLLOW(obj, traverse_how);
620 if (!selective && oclasses[0] && !index(oclasses, obj->oclass))
621 continue;
623 lcount = -1L;
624 if (!all_of_a_type) {
625 char qbuf[BUFSZ];
627 (void) safe_qbuf(qbuf, "Pick up ", "?", obj, doname,
628 ansimpleoname, something);
629 switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
630 case 'q':
631 goto end_query; /* out 2 levels */
632 case 'n':
633 continue;
634 case 'a':
635 all_of_a_type = TRUE;
636 if (selective) {
637 selective = FALSE;
638 oclasses[0] = obj->oclass;
639 oclasses[1] = '\0';
641 break;
642 case '#': /* count was entered */
643 if (!yn_number)
644 continue; /* 0 count => No */
645 lcount = (long) yn_number;
646 if (lcount > obj->quan)
647 lcount = obj->quan;
648 /*FALLTHRU*/
649 default: /* 'y' */
650 break;
653 if (lcount == -1L)
654 lcount = obj->quan;
656 n_tried++;
657 if ((res = pickup_object(obj, lcount, FALSE)) < 0)
658 break;
659 n_picked += res;
661 end_query:
662 ; /* statement required after label */
665 if (!u.uswallow) {
666 if (hides_under(youmonst.data))
667 (void) hideunder(&youmonst);
669 /* position may need updating (invisible hero) */
670 if (n_picked)
671 newsym(u.ux, u.uy);
673 /* check if there's anything else here after auto-pickup is done */
674 if (autopickup)
675 check_here(n_picked > 0);
677 return (n_tried > 0);
680 boolean
681 is_autopickup_exception(obj, grab)
682 struct obj *obj;
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];
692 if (ape) {
693 char *objdesc = makesingular(doname(obj));
695 while (ape) {
696 if (regex_match(objdesc, ape->regex))
697 return TRUE;
698 ape = ape->next;
701 return FALSE;
704 STATIC_OVL boolean
705 autopick_testobj(otmp, calc_costly)
706 struct obj *otmp;
707 boolean calc_costly;
709 static boolean costly = FALSE;
710 const char *otypes = flags.pickup_types;
711 boolean pickit;
713 /* calculate 'costly' just once for a given autopickup operation */
714 if (calc_costly)
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)
720 return FALSE;
722 /* check for pickup_types */
723 pickit = (!*otypes || index(otypes, otmp->oclass));
724 /* check for "always pick up */
725 if (!pickit)
726 pickit = is_autopickup_exception(otmp, TRUE);
727 /* then for "never pick up */
728 if (pickit)
729 pickit = !is_autopickup_exception(otmp, FALSE);
730 /* pickup_thrown overrides pickup_types and exceptions */
731 if (!pickit)
732 pickit = (flags.pickup_thrown && otmp->was_thrown);
733 return pickit;
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.
743 STATIC_OVL int
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 */
750 struct obj *curr;
751 int n;
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))
757 ++n;
758 check_costly = FALSE; /* only need to check once per autopickup */
761 if (n) {
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;
767 n++;
771 return n;
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.
781 * Query flags:
782 * BY_NEXTHERE - Follow object list via nexthere instead of nobj.
783 * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
784 * use it.
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
790 * pick nothing.
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 */
802 int i, n, actualn;
803 winid win;
804 struct obj *curr, *last, fake_hero_object, *olist = *olist_p;
805 char *pack;
806 anything any;
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)
813 return 0;
815 /* count the number of items allowed */
816 for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags))
817 if ((*allow)(curr)) {
818 last = curr;
819 n++;
821 actualn = n;
822 if (engulfer) {
823 ++n;
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;
835 return 1;
838 if (sorted || flags.sortloot != 'n') {
839 sortloot(&olist,
840 (((flags.sortloot == 'f'
841 || (flags.sortloot == 'l' && !(qflags & USE_INVLET)))
842 ? SORTLOOT_LOOT
843 : (qflags & USE_INVLET) ? SORTLOOT_INVLET : 0)
844 | (flags.sortpack ? SORTLOOT_PACK : 0)),
845 (qflags & BY_NEXTHERE) ? TRUE : FALSE);
846 *olist_p = olist;
849 win = create_nhwindow(NHW_MENU);
850 start_menu(win);
851 any = zeroany;
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;
859 first = TRUE;
860 do {
861 printed_type_name = FALSE;
862 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
863 if (sorted && curr->oclass != *pack)
864 continue;
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);
869 return 0;
871 if ((*allow)(curr)) {
872 /* if sorting, print type name (once only) */
873 if (sorted && !printed_type_name) {
874 any = zeroany;
875 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
876 let_to_name(*pack, FALSE,
877 ((how != PICK_NONE)
878 && iflags.menu_head_objsym)),
879 MENU_UNSELECTED);
880 printed_type_name = TRUE;
883 any.a_obj = curr;
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);
889 first = FALSE;
892 pack++;
893 } while (sorted && *pack);
895 if (engulfer) {
896 char buf[BUFSZ];
898 any = zeroany;
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,
903 MENU_UNSELECTED);
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)),
911 MENU_UNSELECTED);
914 end_menu(win, qstr);
915 n = select_menu(win, how, pick_list);
916 destroy_nhwindow(win);
918 if (n > 0) {
919 menu_item *mi;
920 int k;
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)
926 continue;
927 if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
928 mi->count = mi->item.a_obj->quan;
929 if (k < i)
930 (*pick_list)[k] = *mi;
931 ++k;
933 if (!k) {
934 /* fake_hero was only choice so discard whole list */
935 free((genericptr_t) *pick_list);
936 *pick_list = 0;
937 n = 0;
938 } else if (k < n) {
939 /* other stuff plus fake_hero; last slot is now unused */
940 (*pick_list)[k].item = zeroany;
941 (*pick_list)[k].count = 0L;
942 n = k;
944 } else if (n < 0) {
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;
949 return n;
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 */
964 int n;
965 winid win;
966 struct obj *curr;
967 char *pack;
968 anything any;
969 boolean collected_type_name;
970 char invlet;
971 int ccount;
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;
978 if (!olist)
979 return 0;
980 if ((qflags & UNPAID_TYPES) && count_unpaid(olist))
981 do_unpaid = TRUE;
982 if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) {
983 do_blessed = TRUE;
984 num_buc_types++;
986 if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) {
987 do_cursed = TRUE;
988 num_buc_types++;
990 if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) {
991 do_uncursed = TRUE;
992 num_buc_types++;
994 if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) {
995 do_buc_unknown = TRUE;
996 num_buc_types++;
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)))
1006 continue;
1007 break;
1009 if (curr) {
1010 *pick_list = (menu_item *) alloc(sizeof(menu_item));
1011 (*pick_list)->item.a_int = curr->oclass;
1012 return 1;
1013 } else {
1014 debugpline0("query_category: no single object match");
1016 return 0;
1019 win = create_nhwindow(NHW_MENU);
1020 start_menu(win);
1021 pack = flags.inv_order;
1022 if ((qflags & ALL_TYPES) && (ccount > 1)) {
1023 invlet = 'a';
1024 any = zeroany;
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",
1028 MENU_UNSELECTED);
1029 invlet = 'b';
1030 } else
1031 invlet = 'a';
1032 do {
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)))
1038 continue;
1039 if (!collected_type_name) {
1040 any = zeroany;
1041 any.a_int = curr->oclass;
1042 add_menu(
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,
1046 (how != PICK_NONE)
1047 && iflags.menu_head_objsym),
1048 MENU_UNSELECTED);
1049 collected_type_name = TRUE;
1053 pack++;
1054 if (invlet >= 'u') {
1055 impossible("query_category: too many categories");
1056 return 0;
1058 } while (*pack);
1059 /* unpaid items if there are any */
1060 if (do_unpaid) {
1061 invlet = 'u';
1062 any = zeroany;
1063 any.a_int = 'u';
1064 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Unpaid items",
1065 MENU_UNSELECTED);
1067 /* billed items: checked by caller, so always include if BILLED_TYPES */
1068 if (qflags & BILLED_TYPES) {
1069 invlet = 'x';
1070 any = zeroany;
1071 any.a_int = 'x';
1072 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1073 "Unpaid items already used up", MENU_UNSELECTED);
1075 if (qflags & CHOOSE_ALL) {
1076 invlet = 'A';
1077 any = zeroany;
1078 any.a_int = 'A';
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",
1082 MENU_UNSELECTED);
1084 /* items with b/u/c/unknown if there are any */
1085 if (do_blessed) {
1086 invlet = 'B';
1087 any = zeroany;
1088 any.a_int = 'B';
1089 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1090 "Items known to be Blessed", MENU_UNSELECTED);
1092 if (do_cursed) {
1093 invlet = 'C';
1094 any = zeroany;
1095 any.a_int = 'C';
1096 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1097 "Items known to be Cursed", MENU_UNSELECTED);
1099 if (do_uncursed) {
1100 invlet = 'U';
1101 any = zeroany;
1102 any.a_int = 'U';
1103 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1104 "Items known to be Uncursed", MENU_UNSELECTED);
1106 if (do_buc_unknown) {
1107 invlet = 'X';
1108 any = zeroany;
1109 any.a_int = 'X';
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);
1116 if (n < 0)
1117 n = 0; /* caller's don't expect -1 */
1118 return n;
1121 STATIC_OVL int
1122 count_categories(olist, qflags)
1123 struct obj *olist;
1124 int qflags;
1126 char *pack;
1127 boolean counted_category;
1128 int ccount = 0;
1129 struct obj *curr;
1131 pack = flags.inv_order;
1132 do {
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)))
1138 continue;
1139 if (!counted_category) {
1140 ccount++;
1141 counted_category = TRUE;
1145 pack++;
1146 } while (*pack);
1147 return ccount;
1150 /* could we carry `obj'? if not, could we carry some of it/them? */
1151 STATIC_OVL long
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 */
1154 long count;
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;
1162 unsigned saveowt;
1163 const char *verb, *prefx1, *prefx2, *suffx;
1164 char obj_nambuf[BUFSZ], where[BUFSZ];
1166 savequan = obj->quan;
1167 saveowt = obj->owt;
1168 umoney = money_cnt(invent);
1169 iw = max_capacity();
1171 if (count != savequan) {
1172 obj->quan = count;
1173 obj->owt = (unsigned) weight(obj);
1175 wt = iw + (int) obj->owt;
1176 if (adjust_wt)
1177 wt -= (container->otyp == BAG_OF_HOLDING)
1178 ? (int) DELTA_CWT(container, obj)
1179 : (int) obj->owt;
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;
1185 obj->owt = saveowt;
1187 *wt_before = iw;
1188 *wt_after = wt;
1190 if (wt < 0)
1191 return count;
1193 /* see how many we can lift */
1194 if (is_gold) {
1195 iw -= (int) GOLD_WT(umoney);
1196 if (!adjust_wt) {
1197 qq = GOLD_CAPACITY((long) iw, umoney);
1198 } else {
1199 oow = 0;
1200 qq = 50L - (umoney % 100L) - 1L;
1201 if (qq < 0L)
1202 qq += 100L;
1203 for (; qq <= count; qq += 100L) {
1204 obj->quan = qq;
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)
1209 : (int) obj->owt;
1210 if (iw + ow >= 0)
1211 break;
1212 oow = ow;
1214 iw -= oow;
1215 qq -= 100L;
1217 if (qq < 0L)
1218 qq = 0L;
1219 else if (qq > count)
1220 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++) {
1231 obj->quan = qq;
1232 obj->owt = (unsigned) (ow = weight(obj));
1233 if (adjust_wt)
1234 ow -= (container->otyp == BAG_OF_HOLDING)
1235 ? (int) DELTA_CWT(container, obj)
1236 : (int) obj->owt;
1237 if (iw + ow >= 0)
1238 break;
1239 wt = iw + ow;
1241 --qq;
1242 } else {
1243 /* there's only one, and we can't lift it */
1244 qq = 0L;
1246 obj->quan = savequan;
1247 obj->owt = saveowt;
1249 if (qq < count) {
1250 /* some message will be given */
1251 Strcpy(obj_nambuf, doname(obj));
1252 if (container) {
1253 Sprintf(where, "in %s", the(xname(container)));
1254 verb = "carry";
1255 } else {
1256 Strcpy(where, "lying here");
1257 verb = telekinesis ? "acquire" : "lift";
1259 } else {
1260 /* lint suppression */
1261 *obj_nambuf = *where = '\0';
1262 verb = "";
1264 /* we can carry qq of them */
1265 if (qq > 0) {
1266 if (qq < count)
1267 You("can only %s %s of the %s %s.", verb,
1268 (qq == 1L) ? "one" : "some", obj_nambuf, where);
1269 *wt_after = wt;
1270 return qq;
1273 if (!container)
1274 Strcpy(where, "here"); /* slightly shorter form */
1275 if (invent || umoney) {
1276 prefx1 = "you cannot ";
1277 prefx2 = "";
1278 suffx = " any more";
1279 } else {
1280 prefx1 = (obj->quan == 1L) ? "it " : "even one ";
1281 prefx2 = "is too heavy for you to ";
1282 suffx = "";
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; */
1288 return 0L;
1291 /* determine whether character is able and player is willing to carry `obj' */
1292 STATIC_OVL
1294 lift_object(obj, container, cnt_p, telekinesis)
1295 struct obj *obj, *container; /* object to pick up, bag it's coming out of */
1296 long *cnt_p;
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),
1303 xname(obj));
1304 return -1;
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));
1318 return -1;
1321 *cnt_p = carry_count(obj, container, *cnt_p, telekinesis,
1322 &old_wt, &new_wt);
1323 if (*cnt_p < 1L) {
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 */
1331 } else {
1332 result = 1;
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) {
1338 if (telekinesis) {
1339 result = 0; /* don't lift */
1340 } else {
1341 char qbuf[BUFSZ];
1342 long savequan = obj->quan;
1344 obj->quan = *cnt_p;
1345 Strcpy(qbuf, (next_encumbr > HVY_ENCUMBER)
1346 ? overloadmsg
1347 : (next_encumbr > MOD_ENCUMBER)
1348 ? nearloadmsg
1349 : moderateloadmsg);
1350 if (container)
1351 (void) strsubst(qbuf, "lifting", "removing");
1352 Strcat(qbuf, " ");
1353 (void) safe_qbuf(qbuf, qbuf, ". Continue?", obj, doname,
1354 ansimpleoname, something);
1355 obj->quan = savequan;
1356 switch (ynq(qbuf)) {
1357 case 'q':
1358 result = -1;
1359 break;
1360 case 'n':
1361 result = 0;
1362 break;
1363 default:
1364 break; /* 'y' => result == 1 */
1366 clear_nhwindow(WIN_MESSAGE);
1371 if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container)
1372 obj->spe = 0;
1373 return result;
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)
1383 struct obj *obj;
1384 long count;
1385 boolean telekinesis; /* not picking it up directly by hand */
1387 int res, nearload;
1389 if (obj->quan < count) {
1390 impossible("pickup_object: count %ld > quan %ld?", count, obj->quan);
1391 return 0;
1394 /* In case of auto-pickup, where we haven't had a chance
1395 to look at it yet; affects docall(SCR_SCARE_MONSTER). */
1396 if (!Blind)
1397 obj->dknown = 1;
1399 if (obj == uchain) { /* do not pick up attached chain */
1400 return 0;
1401 } else if (obj->oartifact && !touch_artifact(obj, &youmonst)) {
1402 return 0;
1403 } else if (obj->otyp == CORPSE) {
1404 if (fatal_corpse_mistake(obj, telekinesis)
1405 || rider_corpse_revival(obj, telekinesis))
1406 return -1;
1407 } else if (obj->otyp == SCR_SCARE_MONSTER) {
1408 if (obj->blessed)
1409 obj->blessed = 0;
1410 else if (!obj->spe && !obj->cursed)
1411 obj->spe = 1;
1412 else {
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))
1418 docall(obj);
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)
1426 return res;
1428 /* Whats left of the special case for gold :-) */
1429 if (obj->oclass == COIN_CLASS)
1430 context.botl = 1;
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,
1440 count);
1441 mrg_to_wielded = FALSE;
1442 return 1;
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.
1451 struct obj *
1452 pick_obj(otmp)
1453 struct obj *otmp;
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);
1464 fakeshop[1] = '\0';
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()).
1482 encumber_msg()
1484 static int oldcap = UNENCUMBERED;
1485 int newcap = near_capacity();
1487 if (oldcap < newcap) {
1488 switch (newcap) {
1489 case 1:
1490 Your("movements are slowed slightly because of your load.");
1491 break;
1492 case 2:
1493 You("rebalance your load. Movement is difficult.");
1494 break;
1495 case 3:
1496 You("%s under your heavy load. Movement is very hard.",
1497 stagger(youmonst.data, "stagger"));
1498 break;
1499 default:
1500 You("%s move a handspan with this load!",
1501 newcap == 4 ? "can barely" : "can't even");
1502 break;
1504 context.botl = 1;
1505 } else if (oldcap > newcap) {
1506 switch (newcap) {
1507 case 0:
1508 Your("movements are now unencumbered.");
1509 break;
1510 case 1:
1511 Your("movements are only slowed slightly by your load.");
1512 break;
1513 case 2:
1514 You("rebalance your load. Movement is still difficult.");
1515 break;
1516 case 3:
1517 You("%s under your load. Movement is still very hard.",
1518 stagger(youmonst.data, "stagger"));
1519 break;
1521 context.botl = 1;
1524 oldcap = newcap;
1525 return newcap;
1528 /* Is there a container at x,y. Optional: return count of containers at x,y */
1530 container_at(x, y, countem)
1531 int x, y;
1532 boolean 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)) {
1540 container_count++;
1541 if (!countem)
1542 break;
1545 return container_count;
1548 STATIC_OVL boolean
1549 able_to_loot(x, y, looting)
1550 int x, y;
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 */
1558 else
1559 cant_reach_floor(x, y, FALSE, TRUE);
1560 return FALSE;
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"));
1566 return FALSE;
1567 } else if (nolimbs(youmonst.data)) {
1568 pline("Without limbs, you cannot %s anything.", verb);
1569 return FALSE;
1570 } else if (looting && !freehand()) {
1571 pline("Without a free %s, you cannot loot anything.",
1572 body_part(HAND));
1573 return FALSE;
1575 return TRUE;
1578 STATIC_OVL boolean
1579 mon_beside(x, y)
1580 int x, y;
1582 int i, j, nx, ny;
1584 for (i = -1; i <= 1; i++)
1585 for (j = -1; j <= 1; j++) {
1586 nx = x + i;
1587 ny = y + j;
1588 if (isok(nx, ny) && MON_AT(nx, ny))
1589 return TRUE;
1591 return FALSE;
1595 do_loot_cont(cobjp, cindex, ccount)
1596 struct obj **cobjp;
1597 int cindex, ccount; /* index of this container (1..N), number of them (N) */
1599 struct obj *cobj = *cobjp;
1601 if (!cobj)
1602 return 0;
1603 if (cobj->olocked) {
1604 if (ccount < 2)
1605 pline("%s locked.",
1606 cobj->lknown ? "It is" : "Hmmm, it turns out to be");
1607 else if (cobj->lknown)
1608 pline("%s is locked.", The(xname(cobj)));
1609 else
1610 pline("Hmmm, %s turns out to be locked.", the(xname(cobj)));
1611 cobj->lknown = 1;
1612 return 0;
1614 cobj->lknown = 1;
1616 if (cobj->otyp == BAG_OF_TRICKS) {
1617 int tmp;
1619 You("carefully open %s...", the(xname(cobj)));
1620 pline("It develops a huge set of teeth and bites you!");
1621 tmp = rnd(10);
1622 losehp(Maybe_Half_Phys(tmp), "carnivorous bag", KILLED_BY_AN);
1623 makeknown(BAG_OF_TRICKS);
1624 abort_looting = TRUE;
1625 return 1;
1628 You("%sopen %s...", (!cobj->cknown || !cobj->lknown) ? "carefully " : "",
1629 the(xname(cobj)));
1630 return use_container(cobjp, 0, (boolean) (cindex < ccount));
1633 /* loot a container on the floor or loot saddle from mon. */
1635 doloot()
1637 struct obj *cobj, *nobj;
1638 register int c = -1;
1639 int timepassed = 0;
1640 coord cc;
1641 boolean underfoot = TRUE;
1642 const char *dont_find_anything = "don't find anything";
1643 struct monst *mtmp;
1644 char qbuf[BUFSZ];
1645 int prev_inquiry = 0;
1646 boolean prev_loot = FALSE;
1647 int num_conts = 0;
1649 abort_looting = FALSE;
1651 if (check_capacity((char *) 0)) {
1652 /* "Can't do that while carrying so much stuff." */
1653 return 0;
1655 if (nohands(youmonst.data)) {
1656 You("have no hands!"); /* not `body_part(HAND)' */
1657 return 0;
1659 if (Confusion) {
1660 if (rn2(6) && reverse_loot())
1661 return 1;
1662 if (rn2(2)) {
1663 pline("Being confused, you find nothing to loot.");
1664 return 1; /* costs a turn */
1665 } /* else fallthrough to normal looting */
1667 cc.x = u.ux;
1668 cc.y = u.uy;
1670 if (iflags.menu_requested)
1671 goto lootmon;
1673 lootcont:
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))
1678 return 0;
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 */
1690 return 1;
1694 if (num_conts > 1) {
1695 /* use a menu to loot many containers */
1696 int n, i;
1697 winid win;
1698 anything any;
1699 menu_item *pick_list = (menu_item *) 0;
1701 any.a_void = 0;
1702 win = create_nhwindow(NHW_MENU);
1703 start_menu(win);
1705 for (cobj = level.objects[cc.x][cc.y]; cobj;
1706 cobj = cobj->nexthere)
1707 if (Is_container(cobj)) {
1708 any.a_obj = 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);
1716 if (n > 0) {
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);
1723 return timepassed;
1726 free((genericptr_t) pick_list);
1728 if (n != 0)
1729 c = 'y';
1730 } else {
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,
1737 "a container"));
1738 if (c == 'q')
1739 return timepassed;
1740 if (c == 'n')
1741 continue;
1742 anyfound = TRUE;
1744 timepassed |= do_loot_cont(&cobj, 1, 1);
1745 if (abort_looting)
1746 /* chest trap or magic bag explosion or <esc> */
1747 return timepassed;
1750 if (anyfound)
1751 c = 'y';
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.
1760 lootmon:
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))
1764 return 0;
1765 if (cc.x == u.ux && cc.y == u.uy) {
1766 underfoot = TRUE;
1767 if (container_at(cc.x, cc.y, FALSE))
1768 goto lootcont;
1769 } else
1770 underfoot = FALSE;
1771 if (u.dz < 0) {
1772 You("%s to loot on the %s.", dont_find_anything,
1773 ceiling(cc.x, cc.y));
1774 timepassed = 1;
1775 return timepassed;
1777 mtmp = m_at(cc.x, cc.y);
1778 if (mtmp)
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)
1784 timepassed = 1;
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.
1790 if (!underfoot) {
1791 if (container_at(cc.x, cc.y, FALSE)) {
1792 if (mtmp) {
1793 You_cant("loot anything %sthere with %s in the way.",
1794 prev_inquiry ? "else " : "", mon_nam(mtmp));
1795 return timepassed;
1796 } else {
1797 You("have to be at a container to loot it.");
1799 } else {
1800 You("%s %sthere to loot.", dont_find_anything,
1801 (prev_inquiry || prev_loot) ? "else " : "");
1802 return timepassed;
1805 } else if (c != 'y' && c != 'n') {
1806 You("%s %s to loot.", dont_find_anything,
1807 underfoot ? "here" : "there");
1809 return timepassed;
1812 /* called when attempting to #loot while confused */
1813 STATIC_OVL boolean
1814 reverse_loot()
1816 struct obj *goldob = 0, *coffers, *otmp, boxdummy;
1817 struct monst *mon;
1818 long contribution;
1819 int n, x = u.ux, y = u.uy;
1821 if (!rn2(3)) {
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)
1825 if (!rn2(n + 1)) {
1826 prinv("You find old loot:", otmp, 0L);
1827 return TRUE;
1829 return FALSE;
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);
1838 break;
1840 if (!goldob)
1841 return FALSE;
1843 if (!IS_THRONE(levl[x][y].typ)) {
1844 dropx(goldob);
1845 /* the dropped gold might have fallen to lower level */
1846 if (g_at(x, y))
1847 pline("Ok, now there is loot here.");
1848 } else {
1849 /* find original coffers chest if present, otherwise use nearest one
1851 otmp = 0;
1852 for (coffers = fobj; coffers; coffers = coffers->nobj)
1853 if (coffers->otyp == CHEST) {
1854 if (coffers->spe == 2)
1855 break; /* a throne room chest */
1856 if (!otmp
1857 || distu(coffers->ox, coffers->oy)
1858 < distu(otmp->ox, otmp->oy))
1859 otmp = coffers; /* remember closest ordinary chest */
1861 if (!coffers)
1862 coffers = otmp;
1864 if (coffers) {
1865 verbalize("Thank you for your contribution to reduce the debt.");
1866 freeinv(goldob);
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) {
1876 freeinv(goldob);
1877 add_to_minv(mon, goldob);
1878 pline("The exchequer accepts your contribution.");
1879 if (!rn2(10))
1880 levl[x][y].looted = T_LOOTED;
1881 } else {
1882 You("drop %s.", doname(goldob));
1883 dropx(goldob);
1886 return TRUE;
1889 /* loot_mon() returns amount of time passed.
1892 loot_mon(mtmp, passed_info, prev_loot)
1893 struct monst *mtmp;
1894 int *passed_info;
1895 boolean *prev_loot;
1897 int c = -1;
1898 int timepassed = 0;
1899 struct obj *otmp;
1900 char qbuf[QBUFSZ];
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))) {
1907 long unwornmask;
1909 if (passed_info)
1910 *passed_info = 1;
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) */
1917 return 0;
1919 if (otmp->cursed) {
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 */
1924 return 1;
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),
1933 (const char *) 0);
1934 timepassed = rnd(3);
1935 if (prev_loot)
1936 *prev_loot = TRUE;
1937 } else if (c == 'q') {
1938 return 0;
1941 /* 3.4.0 introduced ability to pick things up from swallower's stomach */
1942 if (u.uswallow) {
1943 int count = passed_info ? *passed_info : 0;
1945 timepassed = pickup(count);
1947 return timepassed;
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.
1954 STATIC_OVL boolean
1955 mbag_explodes(obj, depthin)
1956 struct obj *obj;
1957 int depthin;
1959 /* these won't cause an explosion when they're empty */
1960 if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS)
1961 && obj->spe <= 0)
1962 return FALSE;
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))
1967 return TRUE;
1968 else if (Has_contents(obj)) {
1969 struct obj *otmp;
1971 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
1972 if (mbag_explodes(otmp, depthin + 1))
1973 return TRUE;
1975 return FALSE;
1978 /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
1979 STATIC_PTR int
1980 in_container(obj)
1981 register struct obj *obj;
1983 boolean floor_container = !carried(current_container);
1984 boolean was_unpaid = FALSE;
1985 char buf[BUFSZ];
1987 if (!current_container) {
1988 impossible("<in> no current_container?");
1989 return 0;
1990 } else if (obj == uball || obj == uchain) {
1991 You("must be kidding.");
1992 return 0;
1993 } else if (obj == current_container) {
1994 pline("That would be an interesting topological exercise.");
1995 return 0;
1996 } else if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) {
1997 Norep("You cannot %s %s you are wearing.",
1998 Icebox ? "refrigerate" : "stash", something);
1999 return 0;
2000 } else if ((obj->otyp == LOADSTONE) && obj->cursed) {
2001 obj->bknown = 1;
2002 pline_The("stone%s won't leave your person.", plur(obj->quan));
2003 return 0;
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)));
2013 return 0;
2014 } else if (obj->otyp == LEASH && obj->leashmon != 0) {
2015 pline("%s attached to your pet.", Tobjnam(obj, "are"));
2016 return 0;
2017 } else if (obj == uwep) {
2018 if (welded(obj)) {
2019 weldmsg(obj);
2020 return 0;
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.
2027 if (uwep)
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))
2036 return -1;
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)));
2049 return 0;
2052 freeinv(obj);
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 */
2078 if (rot_alarm)
2079 obj->norevive = 1;
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!",
2084 doname(obj));
2085 /* did not actually insert obj yet */
2086 if (was_unpaid)
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);
2094 else
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.
2115 bot();
2116 return (current_container ? 1 : -1);
2120 ck_bag(obj)
2121 struct obj *obj;
2123 return (current_container && obj != current_container);
2126 /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
2127 STATIC_PTR int
2128 out_container(obj)
2129 register struct obj *obj;
2131 register struct obj *otmp;
2132 boolean is_gold = (obj->oclass == COIN_CLASS);
2133 int res, loadlev;
2134 long count;
2136 if (!current_container) {
2137 impossible("<out> no current_container?");
2138 return -1;
2139 } else if (is_gold) {
2140 obj->owt = weight(obj);
2143 if (obj->oartifact && !touch_artifact(obj, &youmonst))
2144 return 0;
2146 if (fatal_corpse_mistake(obj, FALSE))
2147 return -1;
2149 count = obj->quan;
2150 if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0)
2151 return res;
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);
2160 if (Icebox)
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);
2169 if (is_pick(obj))
2170 pick_pick(obj); /* shopkeeper feedback */
2172 otmp = addinv(obj);
2173 loadlev = near_capacity();
2174 prinv(loadlev ? ((loadlev < MOD_ENCUMBER)
2175 ? "You have a little trouble removing"
2176 : "You have much trouble removing")
2177 : (char *) 0,
2178 otmp, count);
2180 if (is_gold) {
2181 bot(); /* update character's gold piece count immediately */
2183 return 1;
2186 /* taking a corpse out of an ice box needs a couple of adjustments */
2187 STATIC_OVL void
2188 removed_from_icebox(obj)
2189 struct obj *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 */
2199 STATIC_OVL long
2200 mbag_item_gone(held, item)
2201 int held;
2202 struct obj *item;
2204 struct monst *shkp;
2205 long loss = 0L;
2207 if (item->dknown)
2208 pline("%s %s vanished!", Doname2(item), otense(item, "have"));
2209 else
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,
2215 TRUE);
2217 obfree(item, (struct obj *) 0);
2218 return loss;
2221 STATIC_OVL void
2222 observe_quantum_cat(box)
2223 struct obj *box;
2225 static NEARDATA const char sc[] = "Schroedinger's Cat";
2226 struct obj *deadcat;
2227 struct monst *livecat;
2228 xchar ox, oy;
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 */
2238 livecat = rn2(2)
2239 ? makemon(&mons[PM_HOUSECAT], box->ox, box->oy, NO_MINVENT)
2240 : 0;
2241 if (livecat) {
2242 livecat->mpeaceful = 1;
2243 set_malign(livecat);
2244 if (!canspotmon(livecat))
2245 You("think %s brushed your %s.", something, body_part(FOOT));
2246 else
2247 pline("%s inside the box is still alive!", Monnam(livecat));
2248 (void) christen_monst(livecat, sc);
2249 } else {
2250 deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
2251 box->ox, box->oy, sc);
2252 if (deadcat) {
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);
2260 return;
2263 #undef Icebox
2265 /* used by askchain() to check for magic bag explosion */
2266 boolean
2267 container_gone(fn)
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);
2275 STATIC_OVL void
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;
2289 winid win;
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))
2295 continue;
2296 putstr(win, 0, *txtpp);
2298 display_nhwindow(win, FALSE);
2299 destroy_nhwindow(win);
2303 boolean
2304 u_handsy()
2306 if (nohands(youmonst.data)) {
2307 You("have no hands!"); /* not `body_part(HAND)' */
2308 return FALSE;
2309 } else if (!freehand()) {
2310 You("have no free %s.", body_part(HAND));
2311 return FALSE;
2313 return TRUE;
2316 static const char stashable[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
2319 use_container(objp, held, more_containers)
2320 struct obj **objp;
2321 int held;
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];
2328 int used = 0;
2330 abort_looting = FALSE;
2331 emptymsg[0] = '\0';
2333 if (!u_handsy())
2334 return 0;
2336 if (obj->olocked) {
2337 pline("%s locked.", Tobjnam(obj, "are"));
2338 if (held)
2339 You("must put it down to unlock.");
2340 obj->lknown = 1;
2341 return 0;
2342 } else if (obj->otrapped) {
2343 if (held)
2344 You("open %s...", the(xname(obj)));
2345 obj->lknown = 1;
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 */
2349 nomul(-1);
2350 multi_reason = "opening a container";
2351 nomovemsg = "";
2353 abort_looting = TRUE;
2354 return 1;
2356 obj->lknown = 1;
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);
2365 if (quantum_cat) {
2366 observe_quantum_cat(current_container);
2367 used = 1;
2369 /* sometimes toss objects if a cursed magic bag */
2370 cursed_mbag = (Is_mbag(current_container) && current_container->cursed
2371 && Has_contents(current_container));
2372 if (cursed_mbag) {
2373 long loss = 0L;
2375 for (curr = current_container->cobj; curr; curr = otmp) {
2376 otmp = curr->nobj;
2377 if (!rn2(13)) {
2378 obj_extract_self(curr);
2379 loss += mbag_item_gone(held, curr);
2380 used = 1;
2383 if (loss)
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)
2417 * or
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);
2422 if (!outmaybe)
2423 (void) safe_qbuf(qbuf, (char *) 0, " is empty. Do what with it?",
2424 current_container, Yname2, Ysimple_name2,
2425 "This");
2426 else
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 */
2435 c = 'b';
2436 } else {
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 */
2454 else
2455 Strcat(xbuf, "?");
2456 if (*xbuf)
2457 Strcat(strcat(pbuf, "\033"), xbuf);
2458 c = yn_function(qbuf, pbuf, more_containers ? 'n' : 'q');
2459 } /* PARTIAL|FULL vs other modes */
2461 if (c == '?') {
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);
2467 } else
2468 break;
2469 } /* loop until something other than '?' or ':' is picked */
2471 if (c == 'q')
2472 abort_looting = TRUE;
2473 if (c == 'n' || c == 'q') /* [not strictly needed; falling thru works] */
2474 goto containerdone;
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)
2485 used = 1;
2486 current_container->cknown = 1;
2487 } else {
2488 add_valid_menu_class(0); /* reset */
2489 if (flags.menu_style == MENU_TRADITIONAL)
2490 used |= traditional_loot(FALSE);
2491 else
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.
2507 if (loot_in) {
2508 add_valid_menu_class(0); /* reset */
2509 if (flags.menu_style == MENU_TRADITIONAL)
2510 used |= traditional_loot(TRUE);
2511 else
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)) {
2517 used = 1;
2518 } else {
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)
2527 loot_out = FALSE;
2529 /* out after in */
2530 if (loot_out && loot_in_first) {
2531 if (!Has_contents(current_container)) {
2532 pline1(emptymsg); /* <whatever> is empty. */
2533 if (!current_container->cknown)
2534 used = 1;
2535 current_container->cknown = 1;
2536 } else {
2537 add_valid_menu_class(0); /* reset */
2538 if (flags.menu_style == MENU_TRADITIONAL)
2539 used |= traditional_loot(FALSE);
2540 else
2541 used |= (menu_loot(0, FALSE) > 0);
2545 containerdone:
2546 if (used) {
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;
2553 update_inventory();
2556 *objp = current_container; /* might have become null */
2557 if (current_container)
2558 current_container = 0; /* avoid hanging on to stale pointer */
2559 else
2560 abort_looting = TRUE;
2561 return used;
2564 /* loot current_container (take things out or put things in), by prompting */
2565 STATIC_OVL int
2566 traditional_loot(put_in)
2567 boolean put_in;
2569 int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P));
2570 struct obj **objlist;
2571 char selection[MAXOCLASSES + 1];
2572 const char *action;
2573 boolean one_by_one, allflag;
2574 int used = 0, menu_on_request = 0;
2576 if (put_in) {
2577 action = "put in";
2578 objlist = &invent;
2579 actionfunc = in_container;
2580 checkfunc = ck_bag;
2581 } else {
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))
2592 used = 1;
2593 } else if (menu_on_request < 0) {
2594 used = (menu_loot(menu_on_request, put_in) > 0);
2596 return used;
2599 /* loot current_container (take things out or put things in), using a menu */
2600 STATIC_OVL int
2601 menu_loot(retry, put_in)
2602 int retry;
2603 boolean put_in;
2605 int n, i, n_looted = 0;
2606 boolean all_categories = TRUE, loot_everything = FALSE;
2607 char buf[BUFSZ];
2608 const char *action = put_in ? "Put in" : "Take out";
2609 struct obj *otmp, *otmp2;
2610 menu_item *pick_list;
2611 int mflags, res;
2612 long count;
2614 if (retry) {
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);
2620 if (put_in)
2621 mflags |= CHOOSE_ALL;
2622 n = query_category(buf, put_in ? invent : current_container->cobj,
2623 mflags, &pick_list, PICK_ANY);
2624 if (!n)
2625 return 0;
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;
2631 else
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) {
2640 otmp2 = otmp->nobj;
2641 res = out_container(otmp);
2642 if (res < 0)
2643 break;
2645 } else {
2646 mflags = INVORDER_SORT;
2647 if (put_in && flags.invlet_constant)
2648 mflags |= USE_INVLET;
2649 if (!put_in)
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);
2655 if (n) {
2656 n_looted = n;
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);
2665 if (res < 0) {
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);
2674 break;
2677 free((genericptr_t) pick_list);
2680 return n_looted;
2683 STATIC_OVL char
2684 in_or_out_menu(prompt, obj, outokay, inokay, alreadyused, more_containers)
2685 const char *prompt;
2686 struct obj *obj;
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";
2691 winid win;
2692 anything any;
2693 menu_item *pick_list;
2694 char buf[BUFSZ];
2695 int n;
2696 const char *menuselector = flags.lootabc ? abc_chars : lootchars;
2698 any = zeroany;
2699 win = create_nhwindow(NHW_MENU);
2700 start_menu(win);
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,
2705 MENU_UNSELECTED);
2706 if (outokay) {
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);
2712 if (inokay) {
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);
2718 if (outokay) {
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);
2724 if (inokay) {
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);
2735 any.a_int = 0;
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);
2750 if (n > 0) {
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 */
2765 dotip()
2767 struct obj *cobj, *nobj;
2768 coord cc;
2769 int boxes;
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 */
2789 int n, i;
2790 winid win;
2791 anything any;
2792 menu_item *pick_list = (menu_item *) 0;
2793 struct obj dummyobj, *otmp;
2795 any = zeroany;
2796 win = create_nhwindow(NHW_MENU);
2797 start_menu(win);
2799 for (cobj = level.objects[cc.x][cc.y], i = 0; cobj;
2800 cobj = cobj->nexthere)
2801 if (Is_container(cobj)) {
2802 ++i;
2803 any.a_obj = cobj;
2804 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
2805 doname(cobj), MENU_UNSELECTED);
2807 if (invent) {
2808 any = zeroany;
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;
2831 if (pick_list)
2832 free((genericptr_t) pick_list);
2833 if (otmp && otmp != &dummyobj) {
2834 tipcontainer(otmp);
2835 return 1;
2837 if (n == -1)
2838 return 0;
2839 /* else pick-from-invent below */
2840 } else {
2841 for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
2842 nobj = cobj->nexthere;
2843 if (!Is_container(cobj))
2844 continue;
2845 c = ynq(safe_qbuf(qbuf, "There is ", " here, tip it?",
2846 cobj,
2847 doname, ansimpleoname, "container"));
2848 if (c == 'q')
2849 return 0;
2850 if (c == 'n')
2851 continue;
2852 tipcontainer(cobj);
2853 /* can only tip one container at a time */
2854 return 1;
2860 /* either no floor container(s) or couldn't tip one or didn't tip any */
2861 cobj = getobj(tippables, "tip");
2862 if (!cobj)
2863 return 0;
2865 /* normal case */
2866 if (Is_container(cobj) || cobj->otyp == HORN_OF_PLENTY) {
2867 tipcontainer(cobj);
2868 return 1;
2870 /* assorted other cases */
2871 if (Is_candle(cobj) && cobj->lamplit) {
2872 /* note "wax" even for tallow candles to avoid giving away info */
2873 spillage = "wax";
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)) {
2877 spillage = "oil";
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) {
2886 spillage = "venom";
2888 if (spillage) {
2889 buf[0] = '\0';
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 */
2902 return 1;
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.");
2909 else
2910 pline1(nothing_happens);
2911 return 0;
2914 STATIC_OVL void
2915 tipcontainer(box)
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 */
2944 box->lknown = 1;
2945 if (box->olocked) {
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 */
2952 nomul(-1);
2953 multi_reason = "tipping a container";
2954 nomovemsg = "";
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...) */
2964 do {
2965 if (!(bag ? bagotricks(box, TRUE, &seen)
2966 : hornoplenty(box, TRUE)))
2967 break;
2968 } while (box->spe > 0);
2970 if (box->spe < old_spe) {
2971 if (bag)
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 */
2976 box->spe = old_spe;
2977 check_unpaid_usage(box, TRUE);
2978 box->spe = 0; /* empty */
2979 box->cknown = 1;
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 */
2991 empty_it = TRUE;
2992 box->cknown = 1;
2993 } else if (!Has_contents(box)) {
2994 box->cknown = 1;
2995 pline("It's empty.");
2996 } else {
2997 empty_it = TRUE;
3000 if (empty_it) {
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);
3006 long loss = 0L;
3008 if (u.uswallow)
3009 highdrop = altarizing = FALSE;
3010 terse = !(highdrop || altarizing || costly_spot(box->ox, box->oy));
3011 box->cknown = 1;
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.
3017 pline("%s out%c",
3018 box->cobj->nobj ? "Objects spill" : "An object spills",
3019 terse ? ':' : '.');
3020 for (otmp = box->cobj; otmp; otmp = nobj) {
3021 nobj = 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 */
3030 terse = FALSE;
3031 continue;
3034 if (maybeshopgoods) {
3035 addtobill(otmp, FALSE, FALSE, TRUE);
3036 iflags.suppress_price++; /* doname formatting */
3039 if (highdrop) {
3040 /* might break or fall down stairs; handles altars itself */
3041 hitfloor(otmp);
3042 } else {
3043 if (altarizing) {
3044 doaltarobj(otmp);
3045 } else if (!terse) {
3046 pline("%s %s to the %s.", Doname2(otmp),
3047 otense(otmp, "drop"), surface(ox, oy));
3048 } else {
3049 pline("%s%c", doname(otmp), nobj ? ',' : '.');
3050 iflags.last_msg = PLNMSG_OBJNAM_ONLY;
3052 dropy(otmp);
3053 if (iflags.last_msg != PLNMSG_OBJNAM_ONLY)
3054 terse = FALSE; /* terse formatting has been interrupted */
3056 if (maybeshopgoods)
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 */
3062 if (held)
3063 (void) encumber_msg();
3067 /*pickup.c*/