'sortloot' revamp
[aNetHack.git] / src / pickup.c
blob39effd261cca45228f0c8df7277a5b0a862f175f
1 /* NetHack 3.6 pickup.c $NHDT-Date: 1457400916 2016/03/08 01:35:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.171 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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 int FDECL(autopick, (struct obj *, int, menu_item **));
25 STATIC_DCL int FDECL(count_categories, (struct obj *, int));
26 STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long,
27 BOOLEAN_P, int *, int *));
28 STATIC_DCL int FDECL(lift_object, (struct obj *, struct obj *, long *,
29 BOOLEAN_P));
30 STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *, int));
31 STATIC_PTR int FDECL(in_container, (struct obj *));
32 STATIC_PTR int FDECL(out_container, (struct obj *));
33 STATIC_DCL void FDECL(removed_from_icebox, (struct obj *));
34 STATIC_DCL long FDECL(mbag_item_gone, (int, struct obj *));
35 STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
36 STATIC_DCL void FDECL(explain_container_prompt, (BOOLEAN_P));
37 STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
38 STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P));
39 STATIC_DCL char FDECL(in_or_out_menu, (const char *, struct obj *, BOOLEAN_P,
40 BOOLEAN_P, BOOLEAN_P, BOOLEAN_P));
41 STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
42 STATIC_DCL boolean FDECL(able_to_loot, (int, int, BOOLEAN_P));
43 STATIC_DCL boolean NDECL(reverse_loot);
44 STATIC_DCL boolean FDECL(mon_beside, (int, int));
45 STATIC_DCL int FDECL(do_loot_cont, (struct obj **, int, int));
46 STATIC_DCL void FDECL(tipcontainer, (struct obj *));
48 /* define for query_objlist() and autopickup() */
49 #define FOLLOW(curr, flags) \
50 (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
53 * How much the weight of the given container will change when the given
54 * object is removed from it. This calculation must match the one used
55 * by weight() in mkobj.c.
57 #define DELTA_CWT(cont, obj) \
58 ((cont)->cursed ? (obj)->owt * 2 : (cont)->blessed \
59 ? ((obj)->owt + 3) / 4 \
60 : ((obj)->owt + 1) / 2)
61 #define GOLD_WT(n) (((n) + 50L) / 100L)
62 /* if you can figure this out, give yourself a hearty pat on the back... */
63 #define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L)
65 /* A variable set in use_container(), to be used by the callback routines
66 in_container() and out_container() from askchain() and use_container().
67 Also used by menu_loot() and container_gone(). */
68 static NEARDATA struct obj *current_container;
69 static NEARDATA boolean abort_looting;
70 #define Icebox (current_container->otyp == ICE_BOX)
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;
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 = level.objects[u.ux][u.uy];
526 traverse_how = BY_NEXTHERE;
527 } else {
528 objchain = u.ustuck->minvent;
529 traverse_how = 0; /* nobj */
532 * Start the actual pickup process. This is split into two main
533 * sections, the newer menu and the older "traditional" methods.
534 * Automatic pickup has been split into its own menu-style routine
535 * to make things less confusing.
537 if (autopickup) {
538 n = autopick(objchain, 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, 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,
557 (traverse_how | FEEL_COCKATRICE),
558 &pick_list, PICK_ANY, all_but_uchain);
560 menu_pickup:
561 n_tried = n;
562 for (n_picked = i = 0; i < n; i++) {
563 res = pickup_object(pick_list[i].item.a_obj, pick_list[i].count,
564 FALSE);
565 if (res < 0)
566 break; /* can't continue */
567 n_picked += res;
569 if (pick_list)
570 free((genericptr_t) pick_list);
572 } else {
573 /* old style interface */
574 int ct = 0;
575 long lcount;
576 boolean all_of_a_type, selective;
577 char oclasses[MAXOCLASSES];
578 struct obj *obj, *obj2;
580 oclasses[0] = '\0'; /* types to consider (empty for all) */
581 all_of_a_type = TRUE; /* take all of considered types */
582 selective = FALSE; /* ask for each item */
584 /* check for more than one object */
585 for (obj = objchain; obj; obj = FOLLOW(obj, traverse_how))
586 ct++;
588 if (ct == 1 && count) {
589 /* if only one thing, then pick it */
590 obj = objchain;
591 lcount = min(obj->quan, (long) count);
592 n_tried++;
593 if (pickup_object(obj, lcount, FALSE) > 0)
594 n_picked++; /* picked something */
595 goto end_query;
597 } else if (ct >= 2) {
598 int via_menu = 0;
600 There("are %s objects here.", (ct <= 10) ? "several" : "many");
601 if (!query_classes(oclasses, &selective, &all_of_a_type,
602 "pick up", objchain,
603 (traverse_how & BY_NEXTHERE) ? TRUE : FALSE,
604 &via_menu)) {
605 if (!via_menu)
606 return 0;
607 if (selective)
608 traverse_how |= INVORDER_SORT;
609 n = query_objlist("Pick up what?", &objchain, traverse_how,
610 &pick_list, PICK_ANY,
611 (via_menu == -2) ? allow_all
612 : allow_category);
613 goto menu_pickup;
617 for (obj = objchain; obj; obj = obj2) {
618 obj2 = FOLLOW(obj, traverse_how);
619 if (!selective && oclasses[0] && !index(oclasses, obj->oclass))
620 continue;
622 lcount = -1L;
623 if (!all_of_a_type) {
624 char qbuf[BUFSZ];
626 (void) safe_qbuf(qbuf, "Pick up ", "?", obj, doname,
627 ansimpleoname, something);
628 switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
629 case 'q':
630 goto end_query; /* out 2 levels */
631 case 'n':
632 continue;
633 case 'a':
634 all_of_a_type = TRUE;
635 if (selective) {
636 selective = FALSE;
637 oclasses[0] = obj->oclass;
638 oclasses[1] = '\0';
640 break;
641 case '#': /* count was entered */
642 if (!yn_number)
643 continue; /* 0 count => No */
644 lcount = (long) yn_number;
645 if (lcount > obj->quan)
646 lcount = obj->quan;
647 /*FALLTHRU*/
648 default: /* 'y' */
649 break;
652 if (lcount == -1L)
653 lcount = obj->quan;
655 n_tried++;
656 if ((res = pickup_object(obj, lcount, FALSE)) < 0)
657 break;
658 n_picked += res;
660 end_query:
661 ; /* statement required after label */
664 if (!u.uswallow) {
665 if (hides_under(youmonst.data))
666 (void) hideunder(&youmonst);
668 /* position may need updating (invisible hero) */
669 if (n_picked)
670 newsym(u.ux, u.uy);
672 /* check if there's anything else here after auto-pickup is done */
673 if (autopickup)
674 check_here(n_picked > 0);
676 return (n_tried > 0);
679 boolean
680 is_autopickup_exception(obj, grab)
681 struct obj *obj;
682 boolean grab; /* forced pickup, rather than forced leave behind? */
685 * Does the text description of this match an exception?
687 char *objdesc = makesingular(doname(obj));
688 struct autopickup_exception
689 *ape = (grab) ? iflags.autopickup_exceptions[AP_GRAB]
690 : iflags.autopickup_exceptions[AP_LEAVE];
692 while (ape) {
693 if (regex_match(objdesc, ape->regex))
694 return TRUE;
695 ape = ape->next;
697 return FALSE;
701 * Pick from the given list using flags.pickup_types. Return the number
702 * of items picked (not counts). Create an array that returns pointers
703 * and counts of the items to be picked up. If the number of items
704 * picked is zero, the pickup list is left alone. The caller of this
705 * function must free the pickup list.
707 STATIC_OVL int
708 autopick(olist, follow, pick_list)
709 struct obj *olist; /* the object list */
710 int follow; /* how to follow the object list */
711 menu_item **pick_list; /* list of objects and counts to pick up */
713 menu_item *pi; /* pick item */
714 struct obj *curr;
715 int n;
716 boolean pickit;
717 const char *otypes = flags.pickup_types;
719 /* first count the number of eligible items */
720 for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
721 /* pick if in pickup_types and not unpaid item in shop */
722 pickit = ((!*otypes || index(otypes, curr->oclass))
723 && !(curr->where == OBJ_FLOOR
724 && !curr->no_charge
725 && isok(curr->ox, curr->oy)
726 && costly_spot(curr->ox, curr->oy)));
727 /* check for "always pick up */
728 if (!pickit)
729 pickit = is_autopickup_exception(curr, TRUE);
730 /* then for "never pick up */
731 if (pickit)
732 pickit = !is_autopickup_exception(curr, FALSE);
733 /* pickup_thrown overrides pickup_types and exceptions */
734 if (!pickit)
735 pickit = (flags.pickup_thrown && curr->was_thrown);
736 /* finally, do we count this object? */
737 if (pickit)
738 ++n;
741 if (n) {
742 *pick_list = pi = (menu_item *) alloc(sizeof (menu_item) * n);
743 for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
744 pickit = (!*otypes || index(otypes, curr->oclass));
745 if (!pickit)
746 pickit = is_autopickup_exception(curr, TRUE);
747 if (pickit)
748 pickit = !is_autopickup_exception(curr, FALSE);
749 if (!pickit)
750 pickit = (flags.pickup_thrown && curr->was_thrown);
751 if (pickit) {
752 pi[n].item.a_obj = curr;
753 pi[n].count = curr->quan;
754 n++;
758 return n;
762 * Put up a menu using the given object list. Only those objects on the
763 * list that meet the approval of the allow function are displayed. Return
764 * a count of the number of items selected, as well as an allocated array of
765 * menu_items, containing pointers to the objects selected and counts. The
766 * returned counts are guaranteed to be in bounds and non-zero.
768 * Query flags:
769 * BY_NEXTHERE - Follow object list via nexthere instead of nobj.
770 * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
771 * use it.
772 * USE_INVLET - Use object's invlet.
773 * INVORDER_SORT - Use hero's pack order.
774 * INCLUDE_HERO - Showing engulfer's invent; show hero too.
775 * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow".
776 * SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to
777 * pick nothing.
778 * FEEL_COCKATRICE - touch corpse.
781 query_objlist(qstr, olist_p, qflags, pick_list, how, allow)
782 const char *qstr; /* query string */
783 struct obj **olist_p; /* the list to pick from */
784 int qflags; /* options to control the query */
785 menu_item **pick_list; /* return list of items picked */
786 int how; /* type of query */
787 boolean FDECL((*allow), (OBJ_P)); /* allow function */
789 int i, n, actualn;
790 winid win;
791 struct obj *curr, *last, fake_hero_object, *olist = *olist_p;
792 char *pack;
793 anything any;
794 boolean printed_type_name,
795 sorted = (qflags & INVORDER_SORT) != 0,
796 engulfer = (qflags & INCLUDE_HERO) != 0;
798 *pick_list = (menu_item *) 0;
799 if (!olist && !engulfer)
800 return 0;
802 /* count the number of items allowed */
803 for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags))
804 if ((*allow)(curr)) {
805 last = curr;
806 n++;
808 actualn = n;
809 if (engulfer) {
810 ++n;
811 /* don't autoselect swallowed hero if it's the only choice */
812 qflags &= ~AUTOSELECT_SINGLE;
815 if (n == 0) /* nothing to pick here */
816 return (qflags & SIGNAL_NOMENU) ? -1 : 0;
818 if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
819 *pick_list = (menu_item *) alloc(sizeof (menu_item));
820 (*pick_list)->item.a_obj = last;
821 (*pick_list)->count = last->quan;
822 return 1;
825 if (sorted) {
826 sortloot(&olist,
827 (((flags.sortloot == 'f'
828 || (flags.sortloot == 'l' && !(qflags & USE_INVLET)))
829 ? SORTLOOT_LOOT
830 : (qflags & USE_INVLET) ? SORTLOOT_INVLET : 0)
831 | (flags.sortpack ? SORTLOOT_PACK : 0)),
832 (qflags & BY_NEXTHERE) ? TRUE : FALSE);
833 *olist_p = olist;
836 win = create_nhwindow(NHW_MENU);
837 start_menu(win);
838 any = zeroany;
840 * Run through the list and add the objects to the menu. If
841 * INVORDER_SORT is set, we'll run through the list once for
842 * each type so we can group them. The allow function will only
843 * be called once per object in the list.
845 pack = flags.inv_order;
846 do {
847 printed_type_name = FALSE;
848 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
849 if (sorted && curr->oclass != *pack)
850 continue;
851 if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE
852 && will_feel_cockatrice(curr, FALSE)) {
853 destroy_nhwindow(win); /* stop the menu and revert */
854 (void) look_here(0, FALSE);
855 return 0;
857 if ((*allow)(curr)) {
858 /* if sorting, print type name (once only) */
859 if (sorted && !printed_type_name) {
860 any = zeroany;
861 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
862 let_to_name(*pack, FALSE,
863 ((how != PICK_NONE)
864 && iflags.menu_head_objsym)),
865 MENU_UNSELECTED);
866 printed_type_name = TRUE;
869 any.a_obj = curr;
870 add_menu(win, obj_to_glyph(curr), &any,
871 (qflags & USE_INVLET) ? curr->invlet : 0,
872 def_oc_syms[(int) objects[curr->otyp].oc_class].sym,
873 ATR_NONE, doname_with_price(curr), MENU_UNSELECTED);
876 pack++;
877 } while (sorted && *pack);
879 if (engulfer) {
880 char buf[BUFSZ];
882 any = zeroany;
883 if (sorted && n > 1) {
884 Sprintf(buf, "%s Creatures",
885 is_animal(u.ustuck->data) ? "Swallowed" : "Engulfed");
886 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf,
887 MENU_UNSELECTED);
889 fake_hero_object = zeroobj;
890 fake_hero_object.quan = 1L; /* not strictly necessary... */
891 any.a_obj = &fake_hero_object;
892 add_menu(win, mon_to_glyph(&youmonst), &any,
893 /* fake inventory letter, no group accelerator */
894 CONTAINED_SYM, 0, ATR_NONE, an(self_lookat(buf)),
895 MENU_UNSELECTED);
898 end_menu(win, qstr);
899 n = select_menu(win, how, pick_list);
900 destroy_nhwindow(win);
902 if (n > 0) {
903 menu_item *mi;
904 int k;
906 /* fix up counts: -1 means no count used => pick all;
907 if fake_hero_object was picked, discard that choice */
908 for (i = k = 0, mi = *pick_list; i < n; i++, mi++) {
909 if (mi->item.a_obj == &fake_hero_object)
910 continue;
911 if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
912 mi->count = mi->item.a_obj->quan;
913 if (k < i)
914 (*pick_list)[k] = *mi;
915 ++k;
917 if (!k) {
918 /* fake_hero was only choice so discard whole list */
919 free((genericptr_t) *pick_list);
920 *pick_list = 0;
921 n = 0;
922 } else if (k < n) {
923 /* other stuff plus fake_hero; last slot is now unused */
924 (*pick_list)[k].item = zeroany;
925 (*pick_list)[k].count = 0L;
926 n = k;
928 } else if (n < 0) {
929 /* -1 is used for SIGNAL_NOMENU, so callers don't expect it
930 to indicate that the player declined to make a choice */
931 n = (qflags & SIGNAL_ESCAPE) ? -2 : 0;
933 return n;
937 * allow menu-based category (class) selection (for Drop,take off etc.)
941 query_category(qstr, olist, qflags, pick_list, how)
942 const char *qstr; /* query string */
943 struct obj *olist; /* the list to pick from */
944 int qflags; /* behaviour modification flags */
945 menu_item **pick_list; /* return list of items picked */
946 int how; /* type of query */
948 int n;
949 winid win;
950 struct obj *curr;
951 char *pack;
952 anything any;
953 boolean collected_type_name;
954 char invlet;
955 int ccount;
956 boolean do_unpaid = FALSE;
957 boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
958 do_buc_unknown = FALSE;
959 int num_buc_types = 0;
961 *pick_list = (menu_item *) 0;
962 if (!olist)
963 return 0;
964 if ((qflags & UNPAID_TYPES) && count_unpaid(olist))
965 do_unpaid = TRUE;
966 if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) {
967 do_blessed = TRUE;
968 num_buc_types++;
970 if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) {
971 do_cursed = TRUE;
972 num_buc_types++;
974 if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) {
975 do_uncursed = TRUE;
976 num_buc_types++;
978 if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) {
979 do_buc_unknown = TRUE;
980 num_buc_types++;
983 ccount = count_categories(olist, qflags);
984 /* no point in actually showing a menu for a single category */
985 if (ccount == 1 && !do_unpaid && num_buc_types <= 1
986 && !(qflags & BILLED_TYPES)) {
987 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
988 if ((qflags & WORN_TYPES)
989 && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
990 continue;
991 break;
993 if (curr) {
994 *pick_list = (menu_item *) alloc(sizeof(menu_item));
995 (*pick_list)->item.a_int = curr->oclass;
996 return 1;
997 } else {
998 debugpline0("query_category: no single object match");
1000 return 0;
1003 win = create_nhwindow(NHW_MENU);
1004 start_menu(win);
1005 pack = flags.inv_order;
1006 if ((qflags & ALL_TYPES) && (ccount > 1)) {
1007 invlet = 'a';
1008 any = zeroany;
1009 any.a_int = ALL_TYPES_SELECTED;
1010 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1011 (qflags & WORN_TYPES) ? "All worn types" : "All types",
1012 MENU_UNSELECTED);
1013 invlet = 'b';
1014 } else
1015 invlet = 'a';
1016 do {
1017 collected_type_name = FALSE;
1018 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
1019 if (curr->oclass == *pack) {
1020 if ((qflags & WORN_TYPES)
1021 && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
1022 continue;
1023 if (!collected_type_name) {
1024 any = zeroany;
1025 any.a_int = curr->oclass;
1026 add_menu(
1027 win, NO_GLYPH, &any, invlet++,
1028 def_oc_syms[(int) objects[curr->otyp].oc_class].sym,
1029 ATR_NONE, let_to_name(*pack, FALSE,
1030 (how != PICK_NONE)
1031 && iflags.menu_head_objsym),
1032 MENU_UNSELECTED);
1033 collected_type_name = TRUE;
1037 pack++;
1038 if (invlet >= 'u') {
1039 impossible("query_category: too many categories");
1040 return 0;
1042 } while (*pack);
1043 /* unpaid items if there are any */
1044 if (do_unpaid) {
1045 invlet = 'u';
1046 any = zeroany;
1047 any.a_int = 'u';
1048 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Unpaid items",
1049 MENU_UNSELECTED);
1051 /* billed items: checked by caller, so always include if BILLED_TYPES */
1052 if (qflags & BILLED_TYPES) {
1053 invlet = 'x';
1054 any = zeroany;
1055 any.a_int = 'x';
1056 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1057 "Unpaid items already used up", MENU_UNSELECTED);
1059 if (qflags & CHOOSE_ALL) {
1060 invlet = 'A';
1061 any = zeroany;
1062 any.a_int = 'A';
1063 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1064 (qflags & WORN_TYPES) ? "Auto-select every item being worn"
1065 : "Auto-select every item",
1066 MENU_UNSELECTED);
1068 /* items with b/u/c/unknown if there are any */
1069 if (do_blessed) {
1070 invlet = 'B';
1071 any = zeroany;
1072 any.a_int = 'B';
1073 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1074 "Items known to be Blessed", MENU_UNSELECTED);
1076 if (do_cursed) {
1077 invlet = 'C';
1078 any = zeroany;
1079 any.a_int = 'C';
1080 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1081 "Items known to be Cursed", MENU_UNSELECTED);
1083 if (do_uncursed) {
1084 invlet = 'U';
1085 any = zeroany;
1086 any.a_int = 'U';
1087 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1088 "Items known to be Uncursed", MENU_UNSELECTED);
1090 if (do_buc_unknown) {
1091 invlet = 'X';
1092 any = zeroany;
1093 any.a_int = 'X';
1094 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1095 "Items of unknown B/C/U status", MENU_UNSELECTED);
1097 end_menu(win, qstr);
1098 n = select_menu(win, how, pick_list);
1099 destroy_nhwindow(win);
1100 if (n < 0)
1101 n = 0; /* caller's don't expect -1 */
1102 return n;
1105 STATIC_OVL int
1106 count_categories(olist, qflags)
1107 struct obj *olist;
1108 int qflags;
1110 char *pack;
1111 boolean counted_category;
1112 int ccount = 0;
1113 struct obj *curr;
1115 pack = flags.inv_order;
1116 do {
1117 counted_category = FALSE;
1118 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
1119 if (curr->oclass == *pack) {
1120 if ((qflags & WORN_TYPES)
1121 && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
1122 continue;
1123 if (!counted_category) {
1124 ccount++;
1125 counted_category = TRUE;
1129 pack++;
1130 } while (*pack);
1131 return ccount;
1134 /* could we carry `obj'? if not, could we carry some of it/them? */
1135 STATIC_OVL long
1136 carry_count(obj, container, count, telekinesis, wt_before, wt_after)
1137 struct obj *obj, *container; /* object to pick up, bag it's coming out of */
1138 long count;
1139 boolean telekinesis;
1140 int *wt_before, *wt_after;
1142 boolean adjust_wt = container && carried(container),
1143 is_gold = obj->oclass == COIN_CLASS;
1144 int wt, iw, ow, oow;
1145 long qq, savequan, umoney;
1146 unsigned saveowt;
1147 const char *verb, *prefx1, *prefx2, *suffx;
1148 char obj_nambuf[BUFSZ], where[BUFSZ];
1150 savequan = obj->quan;
1151 saveowt = obj->owt;
1152 umoney = money_cnt(invent);
1153 iw = max_capacity();
1155 if (count != savequan) {
1156 obj->quan = count;
1157 obj->owt = (unsigned) weight(obj);
1159 wt = iw + (int) obj->owt;
1160 if (adjust_wt)
1161 wt -= (container->otyp == BAG_OF_HOLDING)
1162 ? (int) DELTA_CWT(container, obj)
1163 : (int) obj->owt;
1164 /* This will go with silver+copper & new gold weight */
1165 if (is_gold) /* merged gold might affect cumulative weight */
1166 wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count));
1167 if (count != savequan) {
1168 obj->quan = savequan;
1169 obj->owt = saveowt;
1171 *wt_before = iw;
1172 *wt_after = wt;
1174 if (wt < 0)
1175 return count;
1177 /* see how many we can lift */
1178 if (is_gold) {
1179 iw -= (int) GOLD_WT(umoney);
1180 if (!adjust_wt) {
1181 qq = GOLD_CAPACITY((long) iw, umoney);
1182 } else {
1183 oow = 0;
1184 qq = 50L - (umoney % 100L) - 1L;
1185 if (qq < 0L)
1186 qq += 100L;
1187 for (; qq <= count; qq += 100L) {
1188 obj->quan = qq;
1189 obj->owt = (unsigned) GOLD_WT(qq);
1190 ow = (int) GOLD_WT(umoney + qq);
1191 ow -= (container->otyp == BAG_OF_HOLDING)
1192 ? (int) DELTA_CWT(container, obj)
1193 : (int) obj->owt;
1194 if (iw + ow >= 0)
1195 break;
1196 oow = ow;
1198 iw -= oow;
1199 qq -= 100L;
1201 if (qq < 0L)
1202 qq = 0L;
1203 else if (qq > count)
1204 qq = count;
1205 wt = iw + (int) GOLD_WT(umoney + qq);
1206 } else if (count > 1 || count < obj->quan) {
1208 * Ugh. Calc num to lift by changing the quan of of the
1209 * object and calling weight.
1211 * This works for containers only because containers
1212 * don't merge. -dean
1214 for (qq = 1L; qq <= count; qq++) {
1215 obj->quan = qq;
1216 obj->owt = (unsigned) (ow = weight(obj));
1217 if (adjust_wt)
1218 ow -= (container->otyp == BAG_OF_HOLDING)
1219 ? (int) DELTA_CWT(container, obj)
1220 : (int) obj->owt;
1221 if (iw + ow >= 0)
1222 break;
1223 wt = iw + ow;
1225 --qq;
1226 } else {
1227 /* there's only one, and we can't lift it */
1228 qq = 0L;
1230 obj->quan = savequan;
1231 obj->owt = saveowt;
1233 if (qq < count) {
1234 /* some message will be given */
1235 Strcpy(obj_nambuf, doname(obj));
1236 if (container) {
1237 Sprintf(where, "in %s", the(xname(container)));
1238 verb = "carry";
1239 } else {
1240 Strcpy(where, "lying here");
1241 verb = telekinesis ? "acquire" : "lift";
1243 } else {
1244 /* lint suppression */
1245 *obj_nambuf = *where = '\0';
1246 verb = "";
1248 /* we can carry qq of them */
1249 if (qq > 0) {
1250 if (qq < count)
1251 You("can only %s %s of the %s %s.", verb,
1252 (qq == 1L) ? "one" : "some", obj_nambuf, where);
1253 *wt_after = wt;
1254 return qq;
1257 if (!container)
1258 Strcpy(where, "here"); /* slightly shorter form */
1259 if (invent || umoney) {
1260 prefx1 = "you cannot ";
1261 prefx2 = "";
1262 suffx = " any more";
1263 } else {
1264 prefx1 = (obj->quan == 1L) ? "it " : "even one ";
1265 prefx2 = "is too heavy for you to ";
1266 suffx = "";
1268 There("%s %s %s, but %s%s%s%s.", otense(obj, "are"), obj_nambuf, where,
1269 prefx1, prefx2, verb, suffx);
1271 /* *wt_after = iw; */
1272 return 0L;
1275 /* determine whether character is able and player is willing to carry `obj' */
1276 STATIC_OVL
1278 lift_object(obj, container, cnt_p, telekinesis)
1279 struct obj *obj, *container; /* object to pick up, bag it's coming out of */
1280 long *cnt_p;
1281 boolean telekinesis;
1283 int result, old_wt, new_wt, prev_encumbr, next_encumbr;
1285 if (obj->otyp == BOULDER && Sokoban) {
1286 You("cannot get your %s around this %s.", body_part(HAND),
1287 xname(obj));
1288 return -1;
1290 /* override weight consideration for loadstone picked up by anybody
1291 and for boulder picked up by hero poly'd into a giant; override
1292 availability of open inventory slot iff not already carrying one */
1293 if (obj->otyp == LOADSTONE
1294 || (obj->otyp == BOULDER && throws_rocks(youmonst.data))) {
1295 if (inv_cnt(FALSE) < 52 || !carrying(obj->otyp)
1296 || merge_choice(invent, obj))
1297 return 1; /* lift regardless of current situation */
1298 /* if we reach here, we're out of slots and already have at least
1299 one of these, so treat this one more like a normal item */
1300 You("are carrying too much stuff to pick up %s %s.",
1301 (obj->quan == 1L) ? "another" : "more", simpleonames(obj));
1302 return -1;
1305 *cnt_p = carry_count(obj, container, *cnt_p, telekinesis,
1306 &old_wt, &new_wt);
1307 if (*cnt_p < 1L) {
1308 result = -1; /* nothing lifted */
1309 } else if (obj->oclass != COIN_CLASS
1310 /* [exception for gold coins will have to change
1311 if silver/copper ones ever get implemented] */
1312 && inv_cnt(FALSE) >= 52 && !merge_choice(invent, obj)) {
1313 Your("knapsack cannot accommodate any more items.");
1314 result = -1; /* nothing lifted */
1315 } else {
1316 result = 1;
1317 prev_encumbr = near_capacity();
1318 if (prev_encumbr < flags.pickup_burden)
1319 prev_encumbr = flags.pickup_burden;
1320 next_encumbr = calc_capacity(new_wt - old_wt);
1321 if (next_encumbr > prev_encumbr) {
1322 if (telekinesis) {
1323 result = 0; /* don't lift */
1324 } else {
1325 char qbuf[BUFSZ];
1326 long savequan = obj->quan;
1328 obj->quan = *cnt_p;
1329 Strcpy(qbuf, (next_encumbr > HVY_ENCUMBER)
1330 ? overloadmsg
1331 : (next_encumbr > MOD_ENCUMBER)
1332 ? nearloadmsg
1333 : moderateloadmsg);
1334 if (container)
1335 (void) strsubst(qbuf, "lifting", "removing");
1336 Strcat(qbuf, " ");
1337 (void) safe_qbuf(qbuf, qbuf, ". Continue?", obj, doname,
1338 ansimpleoname, something);
1339 obj->quan = savequan;
1340 switch (ynq(qbuf)) {
1341 case 'q':
1342 result = -1;
1343 break;
1344 case 'n':
1345 result = 0;
1346 break;
1347 default:
1348 break; /* 'y' => result == 1 */
1350 clear_nhwindow(WIN_MESSAGE);
1355 if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container)
1356 obj->spe = 0;
1357 return result;
1361 * Pick up <count> of obj from the ground and add it to the hero's inventory.
1362 * Returns -1 if caller should break out of its loop, 0 if nothing picked
1363 * up, 1 if otherwise.
1366 pickup_object(obj, count, telekinesis)
1367 struct obj *obj;
1368 long count;
1369 boolean telekinesis; /* not picking it up directly by hand */
1371 int res, nearload;
1373 if (obj->quan < count) {
1374 impossible("pickup_object: count %ld > quan %ld?", count, obj->quan);
1375 return 0;
1378 /* In case of auto-pickup, where we haven't had a chance
1379 to look at it yet; affects docall(SCR_SCARE_MONSTER). */
1380 if (!Blind)
1381 obj->dknown = 1;
1383 if (obj == uchain) { /* do not pick up attached chain */
1384 return 0;
1385 } else if (obj->oartifact && !touch_artifact(obj, &youmonst)) {
1386 return 0;
1387 } else if (obj->otyp == CORPSE) {
1388 if (fatal_corpse_mistake(obj, telekinesis)
1389 || rider_corpse_revival(obj, telekinesis))
1390 return -1;
1391 } else if (obj->otyp == SCR_SCARE_MONSTER) {
1392 if (obj->blessed)
1393 obj->blessed = 0;
1394 else if (!obj->spe && !obj->cursed)
1395 obj->spe = 1;
1396 else {
1397 pline_The("scroll%s %s to dust as you %s %s up.", plur(obj->quan),
1398 otense(obj, "turn"), telekinesis ? "raise" : "pick",
1399 (obj->quan == 1L) ? "it" : "them");
1400 if (!(objects[SCR_SCARE_MONSTER].oc_name_known)
1401 && !(objects[SCR_SCARE_MONSTER].oc_uname))
1402 docall(obj);
1403 useupf(obj, obj->quan);
1404 return 1; /* tried to pick something up and failed, but
1405 don't want to terminate pickup loop yet */
1409 if ((res = lift_object(obj, (struct obj *) 0, &count, telekinesis)) <= 0)
1410 return res;
1412 /* Whats left of the special case for gold :-) */
1413 if (obj->oclass == COIN_CLASS)
1414 context.botl = 1;
1415 if (obj->quan != count && obj->otyp != LOADSTONE)
1416 obj = splitobj(obj, count);
1418 obj = pick_obj(obj);
1420 if (uwep && uwep == obj)
1421 mrg_to_wielded = TRUE;
1422 nearload = near_capacity();
1423 prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0, obj,
1424 count);
1425 mrg_to_wielded = FALSE;
1426 return 1;
1430 * Do the actual work of picking otmp from the floor or monster's interior
1431 * and putting it in the hero's inventory. Take care of billing. Return a
1432 * pointer to the object where otmp ends up. This may be different
1433 * from otmp because of merging.
1435 struct obj *
1436 pick_obj(otmp)
1437 struct obj *otmp;
1439 obj_extract_self(otmp);
1440 if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
1441 char saveushops[5], fakeshop[2];
1443 /* addtobill cares about your location rather than the object's;
1444 usually they'll be the same, but not when using telekinesis
1445 (if ever implemented) or a grappling hook */
1446 Strcpy(saveushops, u.ushops);
1447 fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE);
1448 fakeshop[1] = '\0';
1449 Strcpy(u.ushops, fakeshop);
1450 /* sets obj->unpaid if necessary */
1451 addtobill(otmp, TRUE, FALSE, FALSE);
1452 Strcpy(u.ushops, saveushops);
1453 /* if you're outside the shop, make shk notice */
1454 if (!index(u.ushops, *fakeshop))
1455 remote_burglary(otmp->ox, otmp->oy);
1457 newsym(otmp->ox, otmp->oy);
1458 return addinv(otmp); /* might merge it with other objects */
1462 * prints a message if encumbrance changed since the last check and
1463 * returns the new encumbrance value (from near_capacity()).
1466 encumber_msg()
1468 static int oldcap = UNENCUMBERED;
1469 int newcap = near_capacity();
1471 if (oldcap < newcap) {
1472 switch (newcap) {
1473 case 1:
1474 Your("movements are slowed slightly because of your load.");
1475 break;
1476 case 2:
1477 You("rebalance your load. Movement is difficult.");
1478 break;
1479 case 3:
1480 You("%s under your heavy load. Movement is very hard.",
1481 stagger(youmonst.data, "stagger"));
1482 break;
1483 default:
1484 You("%s move a handspan with this load!",
1485 newcap == 4 ? "can barely" : "can't even");
1486 break;
1488 context.botl = 1;
1489 } else if (oldcap > newcap) {
1490 switch (newcap) {
1491 case 0:
1492 Your("movements are now unencumbered.");
1493 break;
1494 case 1:
1495 Your("movements are only slowed slightly by your load.");
1496 break;
1497 case 2:
1498 You("rebalance your load. Movement is still difficult.");
1499 break;
1500 case 3:
1501 You("%s under your load. Movement is still very hard.",
1502 stagger(youmonst.data, "stagger"));
1503 break;
1505 context.botl = 1;
1508 oldcap = newcap;
1509 return newcap;
1512 /* Is there a container at x,y. Optional: return count of containers at x,y */
1513 STATIC_OVL int
1514 container_at(x, y, countem)
1515 int x, y;
1516 boolean countem;
1518 struct obj *cobj, *nobj;
1519 int container_count = 0;
1521 for (cobj = level.objects[x][y]; cobj; cobj = nobj) {
1522 nobj = cobj->nexthere;
1523 if (Is_container(cobj)) {
1524 container_count++;
1525 if (!countem)
1526 break;
1529 return container_count;
1532 STATIC_OVL boolean
1533 able_to_loot(x, y, looting)
1534 int x, y;
1535 boolean looting; /* loot vs tip */
1537 const char *verb = looting ? "loot" : "tip";
1539 if (!can_reach_floor(TRUE)) {
1540 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
1541 rider_cant_reach(); /* not skilled enough to reach */
1542 else
1543 cant_reach_floor(x, y, FALSE, TRUE);
1544 return FALSE;
1545 } else if ((is_pool(x, y) && (looting || !Underwater)) || is_lava(x, y)) {
1546 /* at present, can't loot in water even when Underwater;
1547 can tip underwater, but not when over--or stuck in--lava */
1548 You("cannot %s things that are deep in the %s.", verb,
1549 is_lava(x, y) ? "lava" : "water");
1550 return FALSE;
1551 } else if (nolimbs(youmonst.data)) {
1552 pline("Without limbs, you cannot %s anything.", verb);
1553 return FALSE;
1554 } else if (looting && !freehand()) {
1555 pline("Without a free %s, you cannot loot anything.",
1556 body_part(HAND));
1557 return FALSE;
1559 return TRUE;
1562 STATIC_OVL boolean
1563 mon_beside(x, y)
1564 int x, y;
1566 int i, j, nx, ny;
1568 for (i = -1; i <= 1; i++)
1569 for (j = -1; j <= 1; j++) {
1570 nx = x + i;
1571 ny = y + j;
1572 if (isok(nx, ny) && MON_AT(nx, ny))
1573 return TRUE;
1575 return FALSE;
1579 do_loot_cont(cobjp, cindex, ccount)
1580 struct obj **cobjp;
1581 int cindex, ccount; /* index of this container (1..N), number of them (N) */
1583 struct obj *cobj = *cobjp;
1585 if (!cobj)
1586 return 0;
1587 if (cobj->olocked) {
1588 if (ccount < 2)
1589 pline("%s locked.",
1590 cobj->lknown ? "It is" : "Hmmm, it turns out to be");
1591 else if (cobj->lknown)
1592 pline("%s is locked.", The(xname(cobj)));
1593 else
1594 pline("Hmmm, %s turns out to be locked.", the(xname(cobj)));
1595 cobj->lknown = 1;
1596 return 0;
1598 cobj->lknown = 1;
1600 if (cobj->otyp == BAG_OF_TRICKS) {
1601 int tmp;
1603 You("carefully open %s...", the(xname(cobj)));
1604 pline("It develops a huge set of teeth and bites you!");
1605 tmp = rnd(10);
1606 losehp(Maybe_Half_Phys(tmp), "carnivorous bag", KILLED_BY_AN);
1607 makeknown(BAG_OF_TRICKS);
1608 abort_looting = TRUE;
1609 return 1;
1612 You("%sopen %s...", (!cobj->cknown || !cobj->lknown) ? "carefully " : "",
1613 the(xname(cobj)));
1614 return use_container(cobjp, 0, (boolean) (cindex < ccount));
1617 /* loot a container on the floor or loot saddle from mon. */
1619 doloot()
1621 struct obj *cobj, *nobj;
1622 register int c = -1;
1623 int timepassed = 0;
1624 coord cc;
1625 boolean underfoot = TRUE;
1626 const char *dont_find_anything = "don't find anything";
1627 struct monst *mtmp;
1628 char qbuf[BUFSZ];
1629 int prev_inquiry = 0;
1630 boolean prev_loot = FALSE;
1631 int num_conts;
1633 abort_looting = FALSE;
1635 if (check_capacity((char *) 0)) {
1636 /* "Can't do that while carrying so much stuff." */
1637 return 0;
1639 if (nohands(youmonst.data)) {
1640 You("have no hands!"); /* not `body_part(HAND)' */
1641 return 0;
1643 if (Confusion) {
1644 if (rn2(6) && reverse_loot())
1645 return 1;
1646 if (rn2(2)) {
1647 pline("Being confused, you find nothing to loot.");
1648 return 1; /* costs a turn */
1649 } /* else fallthrough to normal looting */
1651 cc.x = u.ux;
1652 cc.y = u.uy;
1654 lootcont:
1655 if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) {
1656 boolean anyfound = FALSE;
1658 if (!able_to_loot(cc.x, cc.y, TRUE))
1659 return 0;
1661 if (num_conts > 1) {
1662 /* use a menu to loot many containers */
1663 int n, i;
1664 winid win;
1665 anything any;
1666 menu_item *pick_list = (menu_item *) 0;
1668 any.a_void = 0;
1669 win = create_nhwindow(NHW_MENU);
1670 start_menu(win);
1672 for (cobj = level.objects[cc.x][cc.y]; cobj;
1673 cobj = cobj->nexthere)
1674 if (Is_container(cobj)) {
1675 any.a_obj = cobj;
1676 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
1677 doname(cobj), MENU_UNSELECTED);
1679 end_menu(win, "Loot which containers?");
1680 n = select_menu(win, PICK_ANY, &pick_list);
1681 destroy_nhwindow(win);
1683 if (n > 0) {
1684 for (i = 1; i <= n; i++) {
1685 cobj = pick_list[i - 1].item.a_obj;
1686 timepassed |= do_loot_cont(&cobj, i, n);
1687 if (abort_looting) {
1688 /* chest trap or magic bag explosion or <esc> */
1689 free((genericptr_t) pick_list);
1690 return timepassed;
1693 free((genericptr_t) pick_list);
1695 if (n != 0)
1696 c = 'y';
1697 } else {
1698 for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
1699 nobj = cobj->nexthere;
1701 if (Is_container(cobj)) {
1702 c = ynq(safe_qbuf(qbuf, "There is ", " here, loot it?",
1703 cobj, doname, ansimpleoname,
1704 "a container"));
1705 if (c == 'q')
1706 return timepassed;
1707 if (c == 'n')
1708 continue;
1709 anyfound = TRUE;
1711 timepassed |= do_loot_cont(&cobj, 1, 1);
1712 if (abort_looting)
1713 /* chest trap or magic bag explosion or <esc> */
1714 return timepassed;
1717 if (anyfound)
1718 c = 'y';
1720 } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
1721 You("need to dig up the grave to effectively loot it...");
1724 * 3.3.1 introduced directional looting for some things.
1726 if (c != 'y' && mon_beside(u.ux, u.uy)) {
1727 if (!get_adjacent_loc("Loot in what direction?",
1728 "Invalid loot location", u.ux, u.uy, &cc))
1729 return 0;
1730 if (cc.x == u.ux && cc.y == u.uy) {
1731 underfoot = TRUE;
1732 if (container_at(cc.x, cc.y, FALSE))
1733 goto lootcont;
1734 } else
1735 underfoot = FALSE;
1736 if (u.dz < 0) {
1737 You("%s to loot on the %s.", dont_find_anything,
1738 ceiling(cc.x, cc.y));
1739 timepassed = 1;
1740 return timepassed;
1742 mtmp = m_at(cc.x, cc.y);
1743 if (mtmp)
1744 timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot);
1745 /* always use a turn when choosing a direction is impaired,
1746 even if you've successfully targetted a saddled creature
1747 and then answered "no" to the "remove its saddle?" prompt */
1748 if (Confusion || Stunned)
1749 timepassed = 1;
1751 /* Preserve pre-3.3.1 behaviour for containers.
1752 * Adjust this if-block to allow container looting
1753 * from one square away to change that in the future.
1755 if (!underfoot) {
1756 if (container_at(cc.x, cc.y, FALSE)) {
1757 if (mtmp) {
1758 You_cant("loot anything %sthere with %s in the way.",
1759 prev_inquiry ? "else " : "", mon_nam(mtmp));
1760 return timepassed;
1761 } else {
1762 You("have to be at a container to loot it.");
1764 } else {
1765 You("%s %sthere to loot.", dont_find_anything,
1766 (prev_inquiry || prev_loot) ? "else " : "");
1767 return timepassed;
1770 } else if (c != 'y' && c != 'n') {
1771 You("%s %s to loot.", dont_find_anything,
1772 underfoot ? "here" : "there");
1774 return timepassed;
1777 /* called when attempting to #loot while confused */
1778 STATIC_OVL boolean
1779 reverse_loot()
1781 struct obj *goldob = 0, *coffers, *otmp, boxdummy;
1782 struct monst *mon;
1783 long contribution;
1784 int n, x = u.ux, y = u.uy;
1786 if (!rn2(3)) {
1787 /* n objects: 1/(n+1) chance per object plus 1/(n+1) to fall off end
1789 for (n = inv_cnt(TRUE), otmp = invent; otmp; --n, otmp = otmp->nobj)
1790 if (!rn2(n + 1)) {
1791 prinv("You find old loot:", otmp, 0L);
1792 return TRUE;
1794 return FALSE;
1797 /* find a money object to mess with */
1798 for (goldob = invent; goldob; goldob = goldob->nobj)
1799 if (goldob->oclass == COIN_CLASS) {
1800 contribution = ((long) rnd(5) * goldob->quan + 4L) / 5L;
1801 if (contribution < goldob->quan)
1802 goldob = splitobj(goldob, contribution);
1803 break;
1805 if (!goldob)
1806 return FALSE;
1808 if (!IS_THRONE(levl[x][y].typ)) {
1809 dropx(goldob);
1810 /* the dropped gold might have fallen to lower level */
1811 if (g_at(x, y))
1812 pline("Ok, now there is loot here.");
1813 } else {
1814 /* find original coffers chest if present, otherwise use nearest one
1816 otmp = 0;
1817 for (coffers = fobj; coffers; coffers = coffers->nobj)
1818 if (coffers->otyp == CHEST) {
1819 if (coffers->spe == 2)
1820 break; /* a throne room chest */
1821 if (!otmp
1822 || distu(coffers->ox, coffers->oy)
1823 < distu(otmp->ox, otmp->oy))
1824 otmp = coffers; /* remember closest ordinary chest */
1826 if (!coffers)
1827 coffers = otmp;
1829 if (coffers) {
1830 verbalize("Thank you for your contribution to reduce the debt.");
1831 freeinv(goldob);
1832 (void) add_to_container(coffers, goldob);
1833 coffers->owt = weight(coffers);
1834 coffers->cknown = 0;
1835 if (!coffers->olocked) {
1836 boxdummy = zeroobj, boxdummy.otyp = SPE_WIZARD_LOCK;
1837 (void) boxlock(coffers, &boxdummy);
1839 } else if (levl[x][y].looted != T_LOOTED &&
1840 (mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) {
1841 freeinv(goldob);
1842 add_to_minv(mon, goldob);
1843 pline("The exchequer accepts your contribution.");
1844 if (!rn2(10))
1845 levl[x][y].looted = T_LOOTED;
1846 } else {
1847 You("drop %s.", doname(goldob));
1848 dropx(goldob);
1851 return TRUE;
1854 /* loot_mon() returns amount of time passed.
1857 loot_mon(mtmp, passed_info, prev_loot)
1858 struct monst *mtmp;
1859 int *passed_info;
1860 boolean *prev_loot;
1862 int c = -1;
1863 int timepassed = 0;
1864 struct obj *otmp;
1865 char qbuf[QBUFSZ];
1867 /* 3.3.1 introduced the ability to remove saddle from a steed.
1868 * *passed_info is set to TRUE if a loot query was given.
1869 * *prev_loot is set to TRUE if something was actually acquired in here.
1871 if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
1872 long unwornmask;
1874 if (passed_info)
1875 *passed_info = 1;
1876 Sprintf(qbuf, "Do you want to remove the saddle from %s?",
1877 x_monnam(mtmp, ARTICLE_THE, (char *) 0,
1878 SUPPRESS_SADDLE, FALSE));
1879 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
1880 if (nolimbs(youmonst.data)) {
1881 You_cant("do that without limbs."); /* not body_part(HAND) */
1882 return 0;
1884 if (otmp->cursed) {
1885 You("can't. The saddle seems to be stuck to %s.",
1886 x_monnam(mtmp, ARTICLE_THE, (char *) 0,
1887 SUPPRESS_SADDLE, FALSE));
1888 /* the attempt costs you time */
1889 return 1;
1891 obj_extract_self(otmp);
1892 if ((unwornmask = otmp->owornmask) != 0L) {
1893 mtmp->misc_worn_check &= ~unwornmask;
1894 otmp->owornmask = 0L;
1895 update_mon_intrinsics(mtmp, otmp, FALSE, FALSE);
1897 otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
1898 (const char *) 0);
1899 timepassed = rnd(3);
1900 if (prev_loot)
1901 *prev_loot = TRUE;
1902 } else if (c == 'q') {
1903 return 0;
1906 /* 3.4.0 introduced ability to pick things up from swallower's stomach */
1907 if (u.uswallow) {
1908 int count = passed_info ? *passed_info : 0;
1910 timepassed = pickup(count);
1912 return timepassed;
1916 * Decide whether an object being placed into a magic bag will cause
1917 * it to explode. If the object is a bag itself, check recursively.
1919 STATIC_OVL boolean
1920 mbag_explodes(obj, depthin)
1921 struct obj *obj;
1922 int depthin;
1924 /* these won't cause an explosion when they're empty */
1925 if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS)
1926 && obj->spe <= 0)
1927 return FALSE;
1929 /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
1930 if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION)
1931 && (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
1932 return TRUE;
1933 else if (Has_contents(obj)) {
1934 struct obj *otmp;
1936 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
1937 if (mbag_explodes(otmp, depthin + 1))
1938 return TRUE;
1940 return FALSE;
1943 /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
1944 STATIC_PTR int
1945 in_container(obj)
1946 register struct obj *obj;
1948 boolean floor_container = !carried(current_container);
1949 boolean was_unpaid = FALSE;
1950 char buf[BUFSZ];
1952 if (!current_container) {
1953 impossible("<in> no current_container?");
1954 return 0;
1955 } else if (obj == uball || obj == uchain) {
1956 You("must be kidding.");
1957 return 0;
1958 } else if (obj == current_container) {
1959 pline("That would be an interesting topological exercise.");
1960 return 0;
1961 } else if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) {
1962 Norep("You cannot %s %s you are wearing.",
1963 Icebox ? "refrigerate" : "stash", something);
1964 return 0;
1965 } else if ((obj->otyp == LOADSTONE) && obj->cursed) {
1966 obj->bknown = 1;
1967 pline_The("stone%s won't leave your person.", plur(obj->quan));
1968 return 0;
1969 } else if (obj->otyp == AMULET_OF_YENDOR
1970 || obj->otyp == CANDELABRUM_OF_INVOCATION
1971 || obj->otyp == BELL_OF_OPENING
1972 || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
1973 /* Prohibit Amulets in containers; if you allow it, monsters can't
1974 * steal them. It also becomes a pain to check to see if someone
1975 * has the Amulet. Ditto for the Candelabrum, the Bell and the Book.
1977 pline("%s cannot be confined in such trappings.", The(xname(obj)));
1978 return 0;
1979 } else if (obj->otyp == LEASH && obj->leashmon != 0) {
1980 pline("%s attached to your pet.", Tobjnam(obj, "are"));
1981 return 0;
1982 } else if (obj == uwep) {
1983 if (welded(obj)) {
1984 weldmsg(obj);
1985 return 0;
1987 setuwep((struct obj *) 0);
1988 /* This uwep check is obsolete. It dates to 3.0 and earlier when
1989 * unwielding Firebrand would be fatal in hell if hero had no other
1990 * fire resistance. Life-saving would force it to be re-wielded.
1992 if (uwep)
1993 return 0; /* unwielded, died, rewielded */
1994 } else if (obj == uswapwep) {
1995 setuswapwep((struct obj *) 0);
1996 } else if (obj == uquiver) {
1997 setuqwep((struct obj *) 0);
2000 if (fatal_corpse_mistake(obj, FALSE))
2001 return -1;
2003 /* boxes, boulders, and big statues can't fit into any container */
2004 if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER
2005 || (obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) {
2007 * xname() uses a static result array. Save obj's name
2008 * before current_container's name is computed. Don't
2009 * use the result of strcpy() within You() --- the order
2010 * of evaluation of the parameters is undefined.
2012 Strcpy(buf, the(xname(obj)));
2013 You("cannot fit %s into %s.", buf, the(xname(current_container)));
2014 return 0;
2017 freeinv(obj);
2019 if (obj_is_burning(obj)) /* this used to be part of freeinv() */
2020 (void) snuff_lit(obj);
2022 if (floor_container && costly_spot(u.ux, u.uy)) {
2023 if (obj->oclass == COIN_CLASS) {
2024 ; /* defer gold until after put-in message */
2025 } else if (current_container->no_charge && !obj->unpaid) {
2026 /* don't sell when putting the item into your own container */
2027 obj->no_charge = 1;
2028 } else {
2029 /* sellobj() will take an unpaid item off the shop bill */
2030 was_unpaid = obj->unpaid ? TRUE : FALSE;
2031 sellobj_state(SELL_DELIBERATE);
2032 sellobj(obj, u.ux, u.uy);
2033 sellobj_state(SELL_NORMAL);
2036 if (Icebox && !age_is_relative(obj)) {
2037 obj->age = monstermoves - obj->age; /* actual age */
2038 /* stop any corpse timeouts when frozen */
2039 if (obj->otyp == CORPSE && obj->timed) {
2040 long rot_alarm = stop_timer(ROT_CORPSE, obj_to_any(obj));
2042 (void) stop_timer(REVIVE_MON, obj_to_any(obj));
2043 /* mark a non-reviving corpse as such */
2044 if (rot_alarm)
2045 obj->norevive = 1;
2047 } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
2048 /* explicitly mention what item is triggering the explosion */
2049 pline("As you put %s inside, you are blasted by a magical explosion!",
2050 doname(obj));
2051 /* did not actually insert obj yet */
2052 if (was_unpaid)
2053 addtobill(obj, FALSE, FALSE, TRUE);
2054 obfree(obj, (struct obj *) 0);
2055 delete_contents(current_container);
2056 if (!floor_container)
2057 useup(current_container);
2058 else if (obj_here(current_container, u.ux, u.uy))
2059 useupf(current_container, current_container->quan);
2060 else
2061 panic("in_container: bag not found.");
2063 losehp(d(6, 6), "magical explosion", KILLED_BY_AN);
2064 current_container = 0; /* baggone = TRUE; */
2067 if (current_container) {
2068 Strcpy(buf, the(xname(current_container)));
2069 You("put %s into %s.", doname(obj), buf);
2071 /* gold in container always needs to be added to credit */
2072 if (floor_container && obj->oclass == COIN_CLASS)
2073 sellobj(obj, current_container->ox, current_container->oy);
2074 (void) add_to_container(current_container, obj);
2075 current_container->owt = weight(current_container);
2077 /* gold needs this, and freeinv() many lines above may cause
2078 * the encumbrance to disappear from the status, so just always
2079 * update status immediately.
2081 bot();
2082 return (current_container ? 1 : -1);
2086 ck_bag(obj)
2087 struct obj *obj;
2089 return (current_container && obj != current_container);
2092 /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
2093 STATIC_PTR int
2094 out_container(obj)
2095 register struct obj *obj;
2097 register struct obj *otmp;
2098 boolean is_gold = (obj->oclass == COIN_CLASS);
2099 int res, loadlev;
2100 long count;
2102 if (!current_container) {
2103 impossible("<out> no current_container?");
2104 return -1;
2105 } else if (is_gold) {
2106 obj->owt = weight(obj);
2109 if (obj->oartifact && !touch_artifact(obj, &youmonst))
2110 return 0;
2112 if (fatal_corpse_mistake(obj, FALSE))
2113 return -1;
2115 count = obj->quan;
2116 if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0)
2117 return res;
2119 if (obj->quan != count && obj->otyp != LOADSTONE)
2120 obj = splitobj(obj, count);
2122 /* Remove the object from the list. */
2123 obj_extract_self(obj);
2124 current_container->owt = weight(current_container);
2126 if (Icebox)
2127 removed_from_icebox(obj);
2129 if (!obj->unpaid && !carried(current_container)
2130 && costly_spot(current_container->ox, current_container->oy)) {
2131 obj->ox = current_container->ox;
2132 obj->oy = current_container->oy;
2133 addtobill(obj, FALSE, FALSE, FALSE);
2135 if (is_pick(obj))
2136 pick_pick(obj); /* shopkeeper feedback */
2138 otmp = addinv(obj);
2139 loadlev = near_capacity();
2140 prinv(loadlev ? ((loadlev < MOD_ENCUMBER)
2141 ? "You have a little trouble removing"
2142 : "You have much trouble removing")
2143 : (char *) 0,
2144 otmp, count);
2146 if (is_gold) {
2147 bot(); /* update character's gold piece count immediately */
2149 return 1;
2152 /* taking a corpse out of an ice box needs a couple of adjustments */
2153 STATIC_OVL void
2154 removed_from_icebox(obj)
2155 struct obj *obj;
2157 if (!age_is_relative(obj)) {
2158 obj->age = monstermoves - obj->age; /* actual age */
2159 if (obj->otyp == CORPSE)
2160 start_corpse_timeout(obj);
2164 /* an object inside a cursed bag of holding is being destroyed */
2165 STATIC_OVL long
2166 mbag_item_gone(held, item)
2167 int held;
2168 struct obj *item;
2170 struct monst *shkp;
2171 long loss = 0L;
2173 if (item->dknown)
2174 pline("%s %s vanished!", Doname2(item), otense(item, "have"));
2175 else
2176 You("%s %s disappear!", Blind ? "notice" : "see", doname(item));
2178 if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) {
2179 if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy))
2180 loss = stolen_value(item, u.ux, u.uy, (boolean) shkp->mpeaceful,
2181 TRUE);
2183 obfree(item, (struct obj *) 0);
2184 return loss;
2187 STATIC_OVL void
2188 observe_quantum_cat(box)
2189 struct obj *box;
2191 static NEARDATA const char sc[] = "Schroedinger's Cat";
2192 struct obj *deadcat;
2193 struct monst *livecat;
2194 xchar ox, oy;
2196 box->spe = 0; /* box->owt will be updated below */
2197 if (get_obj_location(box, &ox, &oy, 0))
2198 box->ox = ox, box->oy = oy; /* in case it's being carried */
2200 /* this isn't really right, since any form of observation
2201 (telepathic or monster/object/food detection) ought to
2202 force the determination of alive vs dead state; but basing
2203 it just on opening the box is much simpler to cope with */
2204 livecat = rn2(2)
2205 ? makemon(&mons[PM_HOUSECAT], box->ox, box->oy, NO_MINVENT)
2206 : 0;
2207 if (livecat) {
2208 livecat->mpeaceful = 1;
2209 set_malign(livecat);
2210 if (!canspotmon(livecat))
2211 You("think %s brushed your %s.", something, body_part(FOOT));
2212 else
2213 pline("%s inside the box is still alive!", Monnam(livecat));
2214 (void) christen_monst(livecat, sc);
2215 } else {
2216 deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
2217 box->ox, box->oy, sc);
2218 if (deadcat) {
2219 obj_extract_self(deadcat);
2220 (void) add_to_container(box, deadcat);
2222 pline_The("%s inside the box is dead!",
2223 Hallucination ? rndmonnam((char *) 0) : "housecat");
2225 box->owt = weight(box);
2226 return;
2229 #undef Icebox
2231 /* used by askchain() to check for magic bag explosion */
2232 boolean
2233 container_gone(fn)
2234 int FDECL((*fn), (OBJ_P));
2236 /* result is only meaningful while use_container() is executing */
2237 return ((fn == in_container || fn == out_container)
2238 && !current_container);
2241 STATIC_OVL void
2242 explain_container_prompt(more_containers)
2243 boolean more_containers;
2245 static const char *const explaintext[] = {
2246 "Container actions:", "", " : -- Look: examine contents",
2247 " o -- Out: take things out", " i -- In: put things in",
2248 " b -- Both: first take things out, then put things in",
2249 " r -- Reversed: put things in, then take things out",
2250 " s -- Stash: put one item in", "",
2251 " n -- Next: loot next selected container", " q -- Quit: finished",
2252 " ? -- Help: display this text.", "", 0
2254 const char *const *txtpp;
2255 winid win;
2257 /* "Do what with <container>? [:oibrsq or ?] (q)" */
2258 if ((win = create_nhwindow(NHW_TEXT)) != WIN_ERR) {
2259 for (txtpp = explaintext; *txtpp; ++txtpp) {
2260 if (!more_containers && !strncmp(*txtpp, " n ", 3))
2261 continue;
2262 putstr(win, 0, *txtpp);
2264 display_nhwindow(win, FALSE);
2265 destroy_nhwindow(win);
2269 boolean
2270 u_handsy()
2272 if (nohands(youmonst.data)) {
2273 You("have no hands!"); /* not `body_part(HAND)' */
2274 return FALSE;
2275 } else if (!freehand()) {
2276 You("have no free %s.", body_part(HAND));
2277 return FALSE;
2279 return TRUE;
2282 static const char stashable[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
2285 use_container(objp, held, more_containers)
2286 struct obj **objp;
2287 int held;
2288 boolean more_containers; /* True iff #loot multiple and this isn't last one */
2290 struct obj *curr, *otmp, *obj = *objp;
2291 boolean quantum_cat, cursed_mbag, loot_out, loot_in, loot_in_first,
2292 stash_one, inokay, outokay, outmaybe;
2293 char c, emptymsg[BUFSZ], qbuf[QBUFSZ], pbuf[QBUFSZ], xbuf[QBUFSZ];
2294 int used = 0;
2296 abort_looting = FALSE;
2297 emptymsg[0] = '\0';
2299 if (!u_handsy())
2300 return 0;
2302 if (obj->olocked) {
2303 pline("%s locked.", Tobjnam(obj, "are"));
2304 if (held)
2305 You("must put it down to unlock.");
2306 obj->lknown = 1;
2307 return 0;
2308 } else if (obj->otrapped) {
2309 if (held)
2310 You("open %s...", the(xname(obj)));
2311 obj->lknown = 1;
2312 (void) chest_trap(obj, HAND, FALSE);
2313 /* even if the trap fails, you've used up this turn */
2314 if (multi >= 0) { /* in case we didn't become paralyzed */
2315 nomul(-1);
2316 multi_reason = "opening a container";
2317 nomovemsg = "";
2319 abort_looting = TRUE;
2320 return 1;
2322 obj->lknown = 1;
2324 current_container = obj; /* for use by in/out_container */
2326 * From here on out, all early returns go through 'containerdone:'.
2329 /* check for Schroedinger's Cat */
2330 quantum_cat = SchroedingersBox(current_container);
2331 if (quantum_cat) {
2332 observe_quantum_cat(current_container);
2333 used = 1;
2335 /* sometimes toss objects if a cursed magic bag */
2336 cursed_mbag = (Is_mbag(current_container) && current_container->cursed
2337 && Has_contents(current_container));
2338 if (cursed_mbag) {
2339 long loss = 0L;
2341 for (curr = current_container->cobj; curr; curr = otmp) {
2342 otmp = curr->nobj;
2343 if (!rn2(13)) {
2344 obj_extract_self(curr);
2345 loss += mbag_item_gone(held, curr);
2346 used = 1;
2349 if (loss)
2350 You("owe %ld %s for lost merchandise.", loss, currency(loss));
2351 current_container->owt = weight(current_container);
2353 inokay = (invent != 0
2354 && !(invent == current_container && !current_container->nobj));
2355 outokay = Has_contents(current_container);
2356 if (!outokay) /* preformat the empty-container message */
2357 Sprintf(emptymsg, "%s is %sempty.", Ysimple_name2(current_container),
2358 (quantum_cat || cursed_mbag) ? "now " : "");
2361 * What-to-do prompt's list of possible actions:
2362 * always include the look-inside choice (':');
2363 * include the take-out choice ('o') if container
2364 * has anything in it or if player doesn't yet know
2365 * that it's empty (latter can change on subsequent
2366 * iterations if player picks ':' response);
2367 * include the put-in choices ('i','s') if hero
2368 * carries any inventory (including gold);
2369 * include do-both when 'o' is available, even if
2370 * inventory is empty--taking out could alter that;
2371 * include do-both-reversed when 'i' is available,
2372 * even if container is empty--for similar reason;
2373 * include the next container choice ('n') when
2374 * relevant, and make it the default;
2375 * always include the quit choice ('q'), and make
2376 * it the default if there's no next containter;
2377 * include the help choice (" or ?") if `cmdassist'
2378 * run-time option is set;
2379 * (Player can pick any of (o,i,b,r,n,s,?) even when
2380 * they're not listed among the available actions.)
2382 * Do what with <the/your/Shk's container>? [:oibrs nq or ?] (q)
2383 * or
2384 * <The/Your/Shk's container> is empty. Do what with it? [:irs nq or ?]
2386 for (;;) { /* repeats iff '?' or ":' gets chosen */
2387 outmaybe = (outokay || !current_container->cknown);
2388 if (!outmaybe)
2389 (void) safe_qbuf(qbuf, (char *) 0, " is empty. Do what with it?",
2390 current_container, Yname2, Ysimple_name2,
2391 "This");
2392 else
2393 (void) safe_qbuf(qbuf, "Do what with ", "?", current_container,
2394 yname, ysimple_name, "it");
2395 /* ask player about what to do with this container */
2396 if (flags.menu_style == MENU_PARTIAL
2397 || flags.menu_style == MENU_FULL) {
2398 if (!inokay && !outmaybe) {
2399 /* nothing to take out, nothing to put in;
2400 trying to do both will yield proper feedback */
2401 c = 'b';
2402 } else {
2403 c = in_or_out_menu(qbuf, current_container, outmaybe, inokay,
2404 (boolean) (used != 0), more_containers);
2406 } else { /* TRADITIONAL or COMBINATION */
2407 xbuf[0] = '\0'; /* list of extra acceptable responses */
2408 Strcpy(pbuf, ":"); /* look inside */
2409 Strcat(outmaybe ? pbuf : xbuf, "o"); /* take out */
2410 Strcat(inokay ? pbuf : xbuf, "i"); /* put in */
2411 Strcat(outmaybe ? pbuf : xbuf, "b"); /* both */
2412 Strcat(inokay ? pbuf : xbuf, "rs"); /* reversed, stash */
2413 Strcat(pbuf, " "); /* separator */
2414 Strcat(more_containers ? pbuf : xbuf, "n"); /* next container */
2415 Strcat(pbuf, "q"); /* quit */
2416 if (iflags.cmdassist)
2417 /* this unintentionally allows user to answer with 'o' or
2418 'r'; fortunately, those are already valid choices here */
2419 Strcat(pbuf, " or ?"); /* help */
2420 else
2421 Strcat(xbuf, "?");
2422 if (*xbuf)
2423 Strcat(strcat(pbuf, "\033"), xbuf);
2424 c = yn_function(qbuf, pbuf, more_containers ? 'n' : 'q');
2425 } /* PARTIAL|FULL vs other modes */
2427 if (c == '?') {
2428 explain_container_prompt(more_containers);
2429 } else if (c == ':') { /* note: will set obj->cknown */
2430 if (!current_container->cknown)
2431 used = 1; /* gaining info */
2432 container_contents(current_container, FALSE, FALSE, TRUE);
2433 } else
2434 break;
2435 } /* loop until something other than '?' or ':' is picked */
2437 if (c == 'q')
2438 abort_looting = TRUE;
2439 if (c == 'n' || c == 'q') /* [not strictly needed; falling thru works] */
2440 goto containerdone;
2441 loot_out = (c == 'o' || c == 'b' || c == 'r');
2442 loot_in = (c == 'i' || c == 'b' || c == 'r');
2443 loot_in_first = (c == 'r'); /* both, reversed */
2444 stash_one = (c == 's');
2446 /* out-only or out before in */
2447 if (loot_out && !loot_in_first) {
2448 if (!Has_contents(current_container)) {
2449 pline1(emptymsg); /* <whatever> is empty. */
2450 if (!current_container->cknown)
2451 used = 1;
2452 current_container->cknown = 1;
2453 } else {
2454 add_valid_menu_class(0); /* reset */
2455 if (flags.menu_style == MENU_TRADITIONAL)
2456 used |= traditional_loot(FALSE);
2457 else
2458 used |= (menu_loot(0, FALSE) > 0);
2462 if ((loot_in || stash_one)
2463 && (!invent || (invent == current_container && !invent->nobj))) {
2464 You("don't have anything%s to %s.", invent ? " else" : "",
2465 stash_one ? "stash" : "put in");
2466 loot_in = stash_one = FALSE;
2470 * Gone: being nice about only selecting food if we know we are
2471 * putting things in an ice chest.
2473 if (loot_in) {
2474 add_valid_menu_class(0); /* reset */
2475 if (flags.menu_style == MENU_TRADITIONAL)
2476 used |= traditional_loot(TRUE);
2477 else
2478 used |= (menu_loot(0, TRUE) > 0);
2479 } else if (stash_one) {
2480 /* put one item into container */
2481 if ((otmp = getobj(stashable, "stash")) != 0) {
2482 if (in_container(otmp)) {
2483 used = 1;
2484 } else {
2485 /* couldn't put selected item into container for some
2486 reason; might need to undo splitobj() */
2487 for (curr = invent; curr; curr = curr->nobj)
2488 if (curr->nobj == otmp)
2489 break;
2490 if (curr && curr->invlet == otmp->invlet)
2491 (void) merged(&curr, &otmp);
2495 /* putting something in might have triggered magic bag explosion */
2496 if (!current_container)
2497 loot_out = FALSE;
2499 /* out after in */
2500 if (loot_out && loot_in_first) {
2501 if (!Has_contents(current_container)) {
2502 pline1(emptymsg); /* <whatever> is empty. */
2503 if (!current_container->cknown)
2504 used = 1;
2505 current_container->cknown = 1;
2506 } else {
2507 add_valid_menu_class(0); /* reset */
2508 if (flags.menu_style == MENU_TRADITIONAL)
2509 used |= traditional_loot(FALSE);
2510 else
2511 used |= (menu_loot(0, FALSE) > 0);
2515 containerdone:
2516 if (used) {
2517 /* Not completely correct; if we put something in without knowing
2518 whatever was already inside, now we suddenly do. That can't
2519 be helped unless we want to track things item by item and then
2520 deal with containers whose contents are "partly known". */
2521 if (current_container)
2522 current_container->cknown = 1;
2523 update_inventory();
2526 *objp = current_container; /* might have become null */
2527 if (current_container)
2528 current_container = 0; /* avoid hanging on to stale pointer */
2529 else
2530 abort_looting = TRUE;
2531 return used;
2534 /* loot current_container (take things out or put things in), by prompting */
2535 STATIC_OVL int
2536 traditional_loot(put_in)
2537 boolean put_in;
2539 int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P));
2540 struct obj **objlist;
2541 char selection[MAXOCLASSES + 1];
2542 const char *action;
2543 boolean one_by_one, allflag;
2544 int used = 0, menu_on_request = 0;
2546 if (put_in) {
2547 action = "put in";
2548 objlist = &invent;
2549 actionfunc = in_container;
2550 checkfunc = ck_bag;
2551 } else {
2552 action = "take out";
2553 objlist = &(current_container->cobj);
2554 actionfunc = out_container;
2555 checkfunc = (int FDECL((*), (OBJ_P))) 0;
2558 if (query_classes(selection, &one_by_one, &allflag, action, *objlist,
2559 FALSE, &menu_on_request)) {
2560 if (askchain(objlist, (one_by_one ? (char *) 0 : selection), allflag,
2561 actionfunc, checkfunc, 0, action))
2562 used = 1;
2563 } else if (menu_on_request < 0) {
2564 used = (menu_loot(menu_on_request, put_in) > 0);
2566 return used;
2569 /* loot current_container (take things out or put things in), using a menu */
2570 STATIC_OVL int
2571 menu_loot(retry, put_in)
2572 int retry;
2573 boolean put_in;
2575 int n, i, n_looted = 0;
2576 boolean all_categories = TRUE, loot_everything = FALSE;
2577 char buf[BUFSZ];
2578 const char *action = put_in ? "Put in" : "Take out";
2579 struct obj *otmp, *otmp2;
2580 menu_item *pick_list;
2581 int mflags, res;
2582 long count;
2584 if (retry) {
2585 all_categories = (retry == -2);
2586 } else if (flags.menu_style == MENU_FULL) {
2587 all_categories = FALSE;
2588 Sprintf(buf, "%s what type of objects?", action);
2589 mflags = put_in
2590 ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN
2591 : ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
2592 n = query_category(buf, put_in ? invent : current_container->cobj,
2593 mflags, &pick_list, PICK_ANY);
2594 if (!n)
2595 return 0;
2596 for (i = 0; i < n; i++) {
2597 if (pick_list[i].item.a_int == 'A')
2598 loot_everything = TRUE;
2599 else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
2600 all_categories = TRUE;
2601 else
2602 add_valid_menu_class(pick_list[i].item.a_int);
2604 free((genericptr_t) pick_list);
2607 if (loot_everything) {
2608 current_container->cknown = 1;
2609 for (otmp = current_container->cobj; otmp; otmp = otmp2) {
2610 otmp2 = otmp->nobj;
2611 res = out_container(otmp);
2612 if (res < 0)
2613 break;
2615 } else {
2616 mflags = INVORDER_SORT;
2617 if (put_in && flags.invlet_constant)
2618 mflags |= USE_INVLET;
2619 if (!put_in)
2620 current_container->cknown = 1;
2621 Sprintf(buf, "%s what?", action);
2622 n = query_objlist(buf, put_in ? &invent : &(current_container->cobj),
2623 mflags, &pick_list, PICK_ANY,
2624 all_categories ? allow_all : allow_category);
2625 if (n) {
2626 n_looted = n;
2627 for (i = 0; i < n; i++) {
2628 otmp = pick_list[i].item.a_obj;
2629 count = pick_list[i].count;
2630 if (count > 0 && count < otmp->quan) {
2631 otmp = splitobj(otmp, count);
2632 /* special split case also handled by askchain() */
2634 res = put_in ? in_container(otmp) : out_container(otmp);
2635 if (res < 0) {
2636 if (!current_container) {
2637 /* otmp caused current_container to explode;
2638 both are now gone */
2639 otmp = 0; /* and break loop */
2640 } else if (otmp && otmp != pick_list[i].item.a_obj) {
2641 /* split occurred, merge again */
2642 (void) merged(&pick_list[i].item.a_obj, &otmp);
2644 break;
2647 free((genericptr_t) pick_list);
2650 return n_looted;
2653 STATIC_OVL char
2654 in_or_out_menu(prompt, obj, outokay, inokay, alreadyused, more_containers)
2655 const char *prompt;
2656 struct obj *obj;
2657 boolean outokay, inokay, alreadyused, more_containers;
2659 /* underscore is not a choice; it's used to skip element [0] */
2660 static const char lootchars[] = "_:oibrsnq", abc_chars[] = "_:abcdenq";
2661 winid win;
2662 anything any;
2663 menu_item *pick_list;
2664 char buf[BUFSZ];
2665 int n;
2666 const char *menuselector = flags.lootabc ? abc_chars : lootchars;
2668 any = zeroany;
2669 win = create_nhwindow(NHW_MENU);
2670 start_menu(win);
2672 any.a_int = 1; /* ':' */
2673 Sprintf(buf, "Look inside %s", thesimpleoname(obj));
2674 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf,
2675 MENU_UNSELECTED);
2676 if (outokay) {
2677 any.a_int = 2; /* 'o' */
2678 Sprintf(buf, "take %s out", something);
2679 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
2680 buf, MENU_UNSELECTED);
2682 if (inokay) {
2683 any.a_int = 3; /* 'i' */
2684 Sprintf(buf, "put %s in", something);
2685 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
2686 buf, MENU_UNSELECTED);
2688 if (outokay) {
2689 any.a_int = 4; /* 'b' */
2690 Sprintf(buf, "%stake out, then put in", inokay ? "both; " : "");
2691 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
2692 buf, MENU_UNSELECTED);
2694 if (inokay) {
2695 any.a_int = 5; /* 'r' */
2696 Sprintf(buf, "%sput in, then take out",
2697 outokay ? "both reversed; " : "");
2698 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
2699 buf, MENU_UNSELECTED);
2700 any.a_int = 6; /* 's' */
2701 Sprintf(buf, "stash one item into %s", thesimpleoname(obj));
2702 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
2703 buf, MENU_UNSELECTED);
2705 any.a_int = 0;
2706 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2707 if (more_containers) {
2708 any.a_int = 7; /* 'n' */
2709 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
2710 "loot next container", MENU_SELECTED);
2712 any.a_int = 8; /* 'q' */
2713 Strcpy(buf, alreadyused ? "done" : "do nothing");
2714 add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf,
2715 more_containers ? MENU_UNSELECTED : MENU_SELECTED);
2717 end_menu(win, prompt);
2718 n = select_menu(win, PICK_ONE, &pick_list);
2719 destroy_nhwindow(win);
2720 if (n > 0) {
2721 int k = pick_list[0].item.a_int;
2723 if (n > 1 && k == (more_containers ? 7 : 8))
2724 k = pick_list[1].item.a_int;
2725 free((genericptr_t) pick_list);
2726 return lootchars[k]; /* :,o,i,b,r,s,n,q */
2728 return (n == 0 && more_containers) ? 'n' : 'q'; /* next or quit */
2731 static const char tippables[] = { ALL_CLASSES, TOOL_CLASS, 0 };
2733 /* #tip command -- empty container contents onto floor */
2735 dotip()
2737 struct obj *cobj, *nobj;
2738 coord cc;
2739 int boxes;
2740 char c, buf[BUFSZ], qbuf[BUFSZ];
2741 const char *spillage = 0;
2744 * doesn't require free hands;
2745 * limbs are needed to tip floor containers
2748 /* at present, can only tip things at current spot, not adjacent ones */
2749 cc.x = u.ux, cc.y = u.uy;
2751 /* check floor container(s) first; at most one will be accessed */
2752 if ((boxes = container_at(cc.x, cc.y, TRUE)) > 0) {
2753 Sprintf(buf, "You can't tip %s while carrying so much.",
2754 !flags.verbose ? "a container" : (boxes > 1) ? "one" : "it");
2755 if (!check_capacity(buf) && able_to_loot(cc.x, cc.y, FALSE)) {
2756 if (boxes > 1 && (flags.menu_style != MENU_TRADITIONAL
2757 || iflags.menu_requested)) {
2758 /* use menu to pick a container to tip */
2759 int n, i;
2760 winid win;
2761 anything any;
2762 menu_item *pick_list = (menu_item *) 0;
2763 struct obj dummyobj, *otmp;
2765 any = zeroany;
2766 win = create_nhwindow(NHW_MENU);
2767 start_menu(win);
2769 for (cobj = level.objects[cc.x][cc.y], i = 0; cobj;
2770 cobj = cobj->nexthere)
2771 if (Is_container(cobj)) {
2772 ++i;
2773 any.a_obj = cobj;
2774 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
2775 doname(cobj), MENU_UNSELECTED);
2777 if (invent) {
2778 any = zeroany;
2779 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
2780 "", MENU_UNSELECTED);
2781 any.a_obj = &dummyobj;
2782 /* use 'i' for inventory unless there are so many
2783 containers that it's already being used */
2784 i = (i <= 'i' - 'a' && !flags.lootabc) ? 'i' : 0;
2785 add_menu(win, NO_GLYPH, &any, i, 0, ATR_NONE,
2786 "tip something being carried", MENU_SELECTED);
2788 end_menu(win, "Tip which container?");
2789 n = select_menu(win, PICK_ONE, &pick_list);
2790 destroy_nhwindow(win);
2792 * Deal with quirk of preselected item in pick-one menu:
2793 * n == 0 => picked preselected entry, toggling it off;
2794 * n == 1 => accepted preselected choice via SPACE or RETURN;
2795 * n == 2 => picked something other than preselected entry;
2796 * n == -1 => cancelled via ESC;
2798 otmp = (n <= 0) ? (struct obj *) 0 : pick_list[0].item.a_obj;
2799 if (n > 1 && otmp == &dummyobj)
2800 otmp = pick_list[1].item.a_obj;
2801 if (pick_list)
2802 free((genericptr_t) pick_list);
2803 if (otmp && otmp != &dummyobj) {
2804 tipcontainer(otmp);
2805 return 1;
2807 if (n == -1)
2808 return 0;
2809 /* else pick-from-invent below */
2810 } else {
2811 for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
2812 nobj = cobj->nexthere;
2813 if (!Is_container(cobj))
2814 continue;
2815 c = ynq(safe_qbuf(qbuf, "There is ", " here, tip it?",
2816 cobj,
2817 doname, ansimpleoname, "container"));
2818 if (c == 'q')
2819 return 0;
2820 if (c == 'n')
2821 continue;
2822 tipcontainer(cobj);
2823 /* can only tip one container at a time */
2824 return 1;
2830 /* either no floor container(s) or couldn't tip one or didn't tip any */
2831 cobj = getobj(tippables, "tip");
2832 if (!cobj)
2833 return 0;
2835 /* normal case */
2836 if (Is_container(cobj) || cobj->otyp == HORN_OF_PLENTY) {
2837 tipcontainer(cobj);
2838 return 1;
2840 /* assorted other cases */
2841 if (Is_candle(cobj) && cobj->lamplit) {
2842 /* note "wax" even for tallow candles to avoid giving away info */
2843 spillage = "wax";
2844 } else if ((cobj->otyp == POT_OIL && cobj->lamplit)
2845 || (cobj->otyp == OIL_LAMP && cobj->age != 0L)
2846 || (cobj->otyp == MAGIC_LAMP && cobj->spe != 0)) {
2847 spillage = "oil";
2848 /* todo: reduce potion's remaining burn timer or oil lamp's fuel */
2849 } else if (cobj->otyp == CAN_OF_GREASE && cobj->spe > 0) {
2850 /* charged consumed below */
2851 spillage = "grease";
2852 } else if (cobj->otyp == FOOD_RATION || cobj->otyp == CRAM_RATION
2853 || cobj->otyp == LEMBAS_WAFER) {
2854 spillage = "crumbs";
2855 } else if (cobj->oclass == VENOM_CLASS) {
2856 spillage = "venom";
2858 if (spillage) {
2859 buf[0] = '\0';
2860 if (is_pool(u.ux, u.uy))
2861 Sprintf(buf, " and gradually %s", vtense(spillage, "dissipate"));
2862 else if (is_lava(u.ux, u.uy))
2863 Sprintf(buf, " and immediately %s away",
2864 vtense(spillage, "burn"));
2865 pline("Some %s %s onto the %s%s.", spillage,
2866 vtense(spillage, "spill"), surface(u.ux, u.uy), buf);
2867 /* shop usage message comes after the spill message */
2868 if (cobj->otyp == CAN_OF_GREASE && cobj->spe > 0) {
2869 consume_obj_charge(cobj, TRUE);
2871 /* something [useless] happened */
2872 return 1;
2874 /* anything not covered yet */
2875 if (cobj->oclass == POTION_CLASS) /* can't pour potions... */
2876 pline_The("%s %s securely sealed.", xname(cobj), otense(cobj, "are"));
2877 else if (cobj->otyp == STATUE)
2878 pline("Nothing interesting happens.");
2879 else
2880 pline1(nothing_happens);
2881 return 0;
2884 STATIC_OVL void
2885 tipcontainer(box)
2886 struct obj *box; /* or bag */
2888 xchar ox = u.ux, oy = u.uy; /* #tip only works at hero's location */
2889 boolean empty_it = FALSE,
2890 /* Shop handling: can't rely on the container's own unpaid
2891 or no_charge status because contents might differ with it.
2892 A carried container's contents will be flagged as unpaid
2893 or not, as appropriate, and need no special handling here.
2894 Items owned by the hero get sold to the shop without
2895 confirmation as with other uncontrolled drops. A floor
2896 container's contents will be marked no_charge if owned by
2897 hero, otherwise they're owned by the shop. By passing
2898 the contents through shop billing, they end up getting
2899 treated the same as in the carried case. We do so one
2900 item at a time instead of doing whole container at once
2901 to reduce the chance of exhausting shk's billing capacity. */
2902 maybeshopgoods = !carried(box) && costly_spot(ox, oy);
2904 /* caveat: this assumes that cknown, lknown, olocked, and otrapped
2905 fields haven't been overloaded to mean something special for the
2906 non-standard "container" horn of plenty */
2907 box->lknown = 1;
2908 if (box->olocked) {
2909 pline("It's locked.");
2910 } else if (box->otrapped) {
2911 /* we're not reaching inside but we're still handling it... */
2912 (void) chest_trap(box, HAND, FALSE);
2913 /* even if the trap fails, you've used up this turn */
2914 if (multi >= 0) { /* in case we didn't become paralyzed */
2915 nomul(-1);
2916 multi_reason = "tipping a container";
2917 nomovemsg = "";
2919 } else if (box->otyp == BAG_OF_TRICKS || box->otyp == HORN_OF_PLENTY) {
2920 boolean bag = box->otyp == BAG_OF_TRICKS;
2921 int old_spe = box->spe, seen = 0;
2923 if (maybeshopgoods && !box->no_charge)
2924 addtobill(box, FALSE, FALSE, TRUE);
2925 /* apply this bag/horn until empty or monster/object creation fails
2926 (if the latter occurs, force the former...) */
2927 do {
2928 if (!(bag ? bagotricks(box, TRUE, &seen)
2929 : hornoplenty(box, TRUE)))
2930 break;
2931 } while (box->spe > 0);
2933 if (box->spe < old_spe) {
2934 if (bag)
2935 pline((seen == 0) ? "Nothing seems to happen."
2936 : (seen == 1) ? "A monster appears."
2937 : "Monsters appear!");
2938 /* check_unpaid wants to see a non-zero charge count */
2939 box->spe = old_spe;
2940 check_unpaid_usage(box, TRUE);
2941 box->spe = 0; /* empty */
2942 box->cknown = 1;
2944 if (maybeshopgoods && !box->no_charge)
2945 subfrombill(box, shop_keeper(*in_rooms(ox, oy, SHOPBASE)));
2946 } else if (SchroedingersBox(box)) {
2947 char yourbuf[BUFSZ];
2949 observe_quantum_cat(box);
2950 if (!Has_contents(box)) /* evidently a live cat came out */
2951 /* container type of "large box" is inferred */
2952 pline("%sbox is now empty.", Shk_Your(yourbuf, box));
2953 else /* holds cat corpse */
2954 empty_it = TRUE;
2955 box->cknown = 1;
2956 } else if (!Has_contents(box)) {
2957 box->cknown = 1;
2958 pline("It's empty.");
2959 } else {
2960 empty_it = TRUE;
2963 if (empty_it) {
2964 struct obj *otmp, *nobj;
2965 boolean verbose = FALSE, highdrop = !can_reach_floor(TRUE),
2966 altarizing = IS_ALTAR(levl[ox][oy].typ),
2967 cursed_mbag = (Is_mbag(box) && box->cursed);
2968 int held = carried(box);
2969 long loss = 0L;
2971 if (u.uswallow)
2972 highdrop = altarizing = FALSE;
2973 box->cknown = 1;
2974 pline("%s out%c",
2975 box->cobj->nobj ? "Objects spill" : "An object spills",
2976 !(highdrop || altarizing) ? ':' : '.');
2977 for (otmp = box->cobj; otmp; otmp = nobj) {
2978 nobj = otmp->nobj;
2979 obj_extract_self(otmp);
2981 if (box->otyp == ICE_BOX) {
2982 removed_from_icebox(otmp); /* resume rotting for corpse */
2983 } else if (cursed_mbag && !rn2(13)) {
2984 loss += mbag_item_gone(held, otmp);
2985 /* abbreviated drop format is no longer appropriate */
2986 verbose = TRUE;
2987 continue;
2990 if (maybeshopgoods) {
2991 addtobill(otmp, FALSE, FALSE, TRUE);
2992 iflags.suppress_price++; /* doname formatting */
2995 if (highdrop) {
2996 /* might break or fall down stairs; handles altars itself */
2997 hitfloor(otmp);
2998 } else {
2999 if (altarizing)
3000 doaltarobj(otmp);
3001 else if (verbose)
3002 pline("%s %s to the %s.", Doname2(otmp),
3003 otense(otmp, "drop"), surface(ox, oy));
3004 else
3005 pline("%s%c", doname(otmp), nobj ? ',' : '.');
3006 dropy(otmp);
3008 if (maybeshopgoods)
3009 iflags.suppress_price--; /* reset */
3011 if (loss) /* magic bag lost some shop goods */
3012 You("owe %ld %s for lost merchandise.", loss, currency(loss));
3013 box->owt = weight(box); /* mbag_item_gone() doesn't update this */
3014 if (held)
3015 (void) encumber_msg();
3019 /*pickup.c*/