Blindfold removal fix
[slashemextended.git] / src / pickup.c
blobe4565f46bdd8889307e65bb1d54575db2c932ef5
1 /* SCCS Id: @(#)pickup.c 3.4 2003/07/27 */
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 STATIC_DCL void simple_look(struct obj *,BOOLEAN_P);
12 #ifndef GOLDOBJ
13 STATIC_DCL boolean query_classes(char *,boolean *,boolean *,
14 const char *,struct obj *,BOOLEAN_P,BOOLEAN_P,int *);
15 #else
16 STATIC_DCL boolean query_classes(char *,boolean *,boolean *,
17 const char *,struct obj *,BOOLEAN_P,int *);
18 #endif
19 STATIC_DCL void check_here(BOOLEAN_P);
20 STATIC_DCL boolean n_or_more(struct obj *);
21 STATIC_DCL boolean all_but_uchain(struct obj *);
22 #if 0 /* not used */
23 STATIC_DCL boolean allow_cat_no_uchain(struct obj *);
24 #endif
25 STATIC_DCL int autopick(struct obj*, int, menu_item **);
26 STATIC_DCL int count_categories(struct obj *,int);
27 STATIC_DCL long carry_count(struct obj *,struct obj *,long,BOOLEAN_P,int *,int *);
28 STATIC_DCL int lift_object(struct obj *,struct obj *,long *,BOOLEAN_P,BOOLEAN_P);
29 STATIC_PTR int in_container_(struct obj *,BOOLEAN_P);
30 STATIC_PTR int in_container(struct obj *);
31 STATIC_PTR int ck_bag(struct obj *);
32 STATIC_PTR int out_container(struct obj *);
33 STATIC_DCL void observe_quantum_cat(struct obj *);
34 STATIC_DCL int menu_loot(int, struct obj *, BOOLEAN_P);
35 STATIC_DCL int in_or_out_menu(const char *,struct obj *, BOOLEAN_P, BOOLEAN_P);
36 STATIC_DCL int container_at(int, int, BOOLEAN_P);
37 STATIC_DCL boolean able_to_loot(int, int);
38 STATIC_DCL boolean mon_beside(int, int);
40 /* define for query_objlist() and autopickup() */
41 #define FOLLOW(curr, flags) \
42 (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
44 #define CEILDIV(x,y) (((x)+(y)-1)/(y)) /* ceil(x/y) */
46 * How much the weight of the given container will change when the given
47 * object is removed from it. This calculation must match the one used
48 * by weight() in mkobj.c.
50 #define DELTA_CWT(cont,obj) \
51 ((cont)->cursed ? (obj)->owt * ((cont)->oartifact ? 4 : 2) : \
52 CEILDIV((obj)->owt, ((cont)->oartifact ? 3 : 2) * ((cont)->blessed ? 2 : 1)))
54 #define HANDYBAG_CWT(cont,obj) \
55 (flags.female ? ((obj)->owt * 4 / 5) : (obj)->owt )
57 #define GOLD_WT(n) (((n) + 50L) / 100L)
58 /* if you can figure this out, give yourself a hearty pat on the back... */
59 #define GOLD_CAPACITY(w,n) (((w) * -100L) - ((n) + 50L) - 1L)
61 /* A variable set in use_container(), to be used by the callback routines */
62 /* in_container() and out_container() from askchain() and use_container(). */
63 /* Also used by memu_loot() and container_gone(). */
64 static NEARDATA struct obj *current_container;
65 #define Icebox (current_container->otyp == ICE_BOX || current_container->otyp == DISPERSION_BOX || current_container->otyp == ICE_BOX_OF_HOLDING || current_container->otyp == ICE_BOX_OF_WATERPROOFING || current_container->otyp == ICE_BOX_OF_DIGESTION)
67 static const char moderateloadmsg[] = "You have a little trouble lifting";
68 static const char nearloadmsg[] = "You have much trouble lifting";
69 static const char overloadmsg[] = "You have extreme difficulty lifting";
71 /* BUG: this lets you look at cockatrice corpses while blind without
72 touching them */
73 /* much simpler version of the look-here code; used by query_classes() */
74 STATIC_OVL void
75 simple_look(otmp, here)
76 struct obj *otmp; /* list of objects */
77 boolean here; /* flag for type of obj list linkage */
79 /* Neither of the first two cases is expected to happen, since
80 * we're only called after multiple classes of objects have been
81 * detected, hence multiple objects must be present.
84 if (InventoryDoesNotGo && !program_state.gameover) {
85 pline("Not enough memory to create inventory window");
86 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
87 return;
90 if (!otmp) {
91 impossible("simple_look(null)");
92 } else if (!(here ? otmp->nexthere : otmp->nobj)) {
93 pline("%s", doname(otmp));
94 } else {
95 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);
106 #ifndef GOLDOBJ
108 collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount)
109 char ilets[];
110 register struct obj *otmp;
111 boolean here, incl_gold;
112 boolean (*filter)(OBJ_P);
113 int *itemcount;
114 #else
116 collect_obj_classes(ilets, otmp, here, filter, itemcount)
117 char ilets[];
118 register struct obj *otmp;
119 boolean here;
120 boolean (*filter)(OBJ_P);
121 int *itemcount;
122 #endif
124 register int iletct = 0;
125 register char c;
127 *itemcount = 0;
128 #ifndef GOLDOBJ
129 if (incl_gold)
130 ilets[iletct++] = def_oc_syms[COIN_CLASS];
131 #endif
132 ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
133 while (otmp) {
134 c = def_oc_syms[(int)otmp->oclass];
135 if (!index(ilets, c) && (!filter || (*filter)(otmp)))
136 ilets[iletct++] = c, ilets[iletct] = '\0';
137 *itemcount += 1;
138 otmp = here ? otmp->nexthere : otmp->nobj;
141 return iletct;
145 * Suppose some '?' and '!' objects are present, but '/' objects aren't:
146 * "a" picks all items without further prompting;
147 * "A" steps through all items, asking one by one;
148 * "?" steps through '?' items, asking, and ignores '!' ones;
149 * "/" becomes 'A', since no '/' present;
150 * "?a" or "a?" picks all '?' without further prompting;
151 * "/a" or "a/" becomes 'A' since there aren't any '/'
152 * (bug fix: 3.1.0 thru 3.1.3 treated it as "a");
153 * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
154 * (ie, treated as if it had just been "?a").
156 #ifndef GOLDOBJ
157 STATIC_OVL boolean
158 query_classes(oclasses, one_at_a_time, everything, action, objs,
159 here, incl_gold, menu_on_demand)
160 char oclasses[];
161 boolean *one_at_a_time, *everything;
162 const char *action;
163 struct obj *objs;
164 boolean here, incl_gold;
165 int *menu_on_demand;
166 #else
167 STATIC_OVL boolean
168 query_classes(oclasses, one_at_a_time, everything, action, objs,
169 here, menu_on_demand)
170 char oclasses[];
171 boolean *one_at_a_time, *everything;
172 const char *action;
173 struct obj *objs;
174 boolean here;
175 int *menu_on_demand;
176 #endif
178 char ilets[20], inbuf[BUFSZ];
179 int iletct, oclassct;
180 boolean not_everything;
181 char qbuf[QBUFSZ];
182 boolean m_seen;
183 int itemcount;
185 oclasses[oclassct = 0] = '\0';
186 *one_at_a_time = *everything = m_seen = FALSE;
187 iletct = collect_obj_classes(ilets, objs, here,
188 #ifndef GOLDOBJ
189 incl_gold,
190 #endif
191 (boolean (*)(OBJ_P)) 0, &itemcount);
192 if (iletct == 0) {
193 return FALSE;
194 } else if (iletct == 1) {
195 oclasses[0] = def_char_to_objclass(ilets[0]);
196 oclasses[1] = '\0';
197 if (itemcount && menu_on_demand) {
198 ilets[iletct++] = 'm';
199 *menu_on_demand = 0;
200 ilets[iletct] = '\0';
202 } else { /* more than one choice available */
203 const char *where = 0;
204 register char sym, oc_of_sym, *p;
205 /* additional choices */
206 ilets[iletct++] = ' ';
207 ilets[iletct++] = 'a';
208 ilets[iletct++] = 'A';
209 ilets[iletct++] = (objs == invent ? 'i' : ':');
210 if (menu_on_demand) {
211 ilets[iletct++] = 'm';
212 *menu_on_demand = 0;
214 ilets[iletct] = '\0';
215 ask_again:
216 oclasses[oclassct = 0] = '\0';
217 *one_at_a_time = *everything = FALSE;
218 not_everything = FALSE;
219 sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
220 action, ilets);
221 getlin(qbuf,inbuf);
222 if (*inbuf == '\033') return FALSE;
224 for (p = inbuf; (sym = *p++); ) {
225 /* new A function (selective all) added by GAN 01/09/87 */
226 if (sym == ' ') continue;
227 else if (sym == 'A') *one_at_a_time = TRUE;
228 else if (sym == 'a') {
229 if (yn("You decided to autoselect everything, please confirm with y if that's what you really wanted") == 'y') *everything = TRUE;
230 } else if (sym == ':') {
231 simple_look(objs, here); /* dumb if objs==invent */
232 goto ask_again;
233 } else if (sym == 'i') {
234 (void) display_inventory((char *)0, TRUE);
235 goto ask_again;
236 } else if (sym == 'm') {
237 m_seen = TRUE;
238 } else {
239 oc_of_sym = def_char_to_objclass(sym);
240 if (index(ilets,sym)) {
241 add_valid_menu_class(oc_of_sym);
242 oclasses[oclassct++] = oc_of_sym;
243 oclasses[oclassct] = '\0';
244 } else {
245 if (!where)
246 where = !strcmp(action,"pick up") ? "here" :
247 !strcmp(action,"take out") ?
248 "inside" : "";
249 if (*where)
250 There("are no %c's %s.", sym, where);
251 else
252 You("have no %c's.", sym);
253 not_everything = TRUE;
257 if (m_seen && menu_on_demand) {
258 *menu_on_demand = (*everything || !oclassct) ? -2 : -3;
259 return FALSE;
261 if (!oclassct && (!*everything || not_everything)) {
262 /* didn't pick anything,
263 or tried to pick something that's not present */
264 *one_at_a_time = TRUE; /* force 'A' */
265 *everything = FALSE; /* inhibit 'a' */
268 return TRUE;
271 /* look at the objects at our location, unless there are too many of them */
272 STATIC_OVL void
273 check_here(picked_some)
274 boolean picked_some;
276 register struct obj *obj;
277 register int ct = 0;
279 /* count the objects here */
280 for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) {
281 if ((obj != uchain) && !obj->dynamitekaboom)
282 ct++;
285 /* If there are objects here, take a look. */
286 if (ct) {
287 if (flags.run) nomul(0, 0, FALSE);
288 flush_screen(1);
289 (void) look_here(ct, picked_some);
290 } else {
291 sense_engr_at(u.ux, u.uy, FALSE);
295 /* Value set by query_objlist() for n_or_more(). */
296 static long val_for_n_or_more;
298 /* query_objlist callback: return TRUE if obj's count is >= reference value */
299 STATIC_OVL boolean
300 n_or_more(obj)
301 struct obj *obj;
303 if (obj == uchain) return FALSE;
304 if (obj->dynamitekaboom) return FALSE;
305 return (obj->quan >= val_for_n_or_more);
308 /* List of valid menu classes for query_objlist() and allow_category callback */
309 static char valid_menu_classes[MAXOCLASSES + 2];
311 void
312 add_valid_menu_class(c)
313 int c;
315 static int vmc_count = 0;
317 if (c == 0) /* reset */
318 vmc_count = 0;
319 else
320 valid_menu_classes[vmc_count++] = (char)c;
321 valid_menu_classes[vmc_count] = '\0';
324 /* query_objlist callback: return TRUE if not uchain */
325 STATIC_OVL boolean
326 all_but_uchain(obj)
327 struct obj *obj;
329 return ((obj != uchain) && !obj->dynamitekaboom);
332 /* query_objlist callback: return TRUE */
333 /*ARGSUSED*/
334 boolean
335 allow_all(obj)
336 struct obj *obj;
338 return TRUE;
341 boolean
342 allow_category(obj)
343 struct obj *obj;
345 if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
346 if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid && !Hallucination ) ||
347 (index(valid_menu_classes, obj->oclass) != (char *)0))
348 return TRUE;
349 else if (((index(valid_menu_classes,'I') != (char *)0) && not_fully_identified(obj) && !Hallucination) ||
350 (index(valid_menu_classes, obj->oclass) != (char *)0))
351 return TRUE;
352 else if (((index(valid_menu_classes,'U') != (char *)0) &&
353 (obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed && !Hallucination)))
354 return TRUE;
355 else if (((index(valid_menu_classes,'B') != (char *)0) &&
356 (obj->oclass != COIN_CLASS && obj->bknown && obj->blessed && !Hallucination)))
357 return TRUE;
358 else if (((index(valid_menu_classes,'C') != (char *)0) &&
359 (obj->oclass != COIN_CLASS && obj->bknown && obj->cursed && !Hallucination)))
360 return TRUE;
361 else if (((index(valid_menu_classes,'X') != (char *)0) &&
362 (obj->oclass != COIN_CLASS && !obj->bknown && !Hallucination)))
363 return TRUE;
364 else
365 return FALSE;
368 #if 0 /* not used */
369 /* query_objlist callback: return TRUE if valid category (class), no uchain */
370 STATIC_OVL boolean
371 allow_cat_no_uchain(obj)
372 struct obj *obj;
374 if ((obj != uchain) &&
375 (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
376 (index(valid_menu_classes, obj->oclass) != (char *)0)))
377 return TRUE;
378 else
379 return FALSE;
381 #endif
383 /* query_objlist callback: return TRUE if valid class and worn */
384 boolean
385 is_worn_by_type(otmp)
386 register struct obj *otmp;
388 return((boolean)(!!(otmp->owornmask &
389 (W_ARMOR | W_RING | W_AMUL | W_IMPLANT | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER)))
390 && (index(valid_menu_classes, otmp->oclass) != (char *)0));
394 * Have the hero pick things from the ground
395 * or a monster's inventory if swallowed.
397 * Arg what:
398 * >0 autopickup
399 * =0 interactive
400 * <0 pickup count of something
402 * Returns 1 if tried to pick something up, whether
403 * or not it succeeded.
406 pickup(what)
407 int what; /* should be a long */
409 int i, n, res, count, n_tried = 0, n_picked = 0;
410 menu_item *pick_list = (menu_item *) 0;
411 boolean autopickup = what > 0;
412 struct obj *objchain;
413 int traverse_how;
415 if (what < 0) /* pick N of something */
416 count = -what;
417 else /* pick anything */
418 count = 0;
420 if (!u.uswallow) {
421 struct trap *ttmp = t_at(u.ux, u.uy);
422 /* no auto-pick if no-pick move, nothing there, or in a pool */
423 if (autopickup && (flags.nopick || !OBJ_AT(u.ux, u.uy) ||
424 (is_waterypool(u.ux, u.uy) && !is_crystalwater(u.ux, u.uy) && !Underwater) || (is_watertunnel(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) {
425 sense_engr_at(u.ux, u.uy, FALSE);
426 return (0);
429 /* no pickup if levitating & not on air or water level */
430 if (!can_reach_floor()) {
431 if ((multi && !flags.run) || (autopickup && !flags.pickup))
432 sense_engr_at(u.ux, u.uy, FALSE);
433 return (0);
435 if (ttmp && ttmp->tseen) {
436 /* Allow pickup from holes and trap doors that you escaped
437 * from because that stuff is teetering on the edge just
438 * like you, but not pits, because there is an elevation
439 * discrepancy with stuff in pits.
441 if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT || ttmp->ttyp == GIANT_CHASM || ttmp->ttyp == SHIT_PIT || ttmp->ttyp == MANA_PIT || ttmp->ttyp == ANOXIC_PIT || ttmp->ttyp == HYPOXIC_PIT || ttmp->ttyp == ACID_PIT) &&
442 (!u.utrap || (u.utrap && u.utraptype != TT_PIT)) && !Passes_walls && !Flying) {
443 sense_engr_at(u.ux, u.uy, FALSE);
444 return(0);
447 /* multi && !flags.run means they are in the middle of some other
448 * action, or possibly paralyzed, sleeping, etc.... and they just
449 * teleported onto the object. They shouldn't pick it up.
451 if ((multi && !flags.run) || (autopickup && !flags.pickup)) {
452 check_here(FALSE);
453 return (0);
455 if (notake(youmonst.data) && !(uarmg && itemhasappearance(uarmg, APP_HOOKED_GLOVES)) && !Race_if(PM_TRANSFORMER) ) {
456 if (!autopickup) {
457 You("are physically incapable of picking anything up.");
458 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
460 if (yn("But maybe you can reach the items anyway. Try it?") == 'y') {
461 if (rn2(3) && !polyskillchance()) {
462 make_hallucinated(HHallucination + rnd(50),FALSE,0L);
463 pline("Oh wow! Is that your own shiny reflection you just saw?");
464 if (!rn2(20)) badeffect();
465 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
466 return 1;
469 else {return(0);}
473 else
474 { check_here(FALSE);
475 return (0); }
478 /* if there's anything here, stop running */
479 if (OBJ_AT(u.ux,u.uy) && flags.run && flags.run != 8 && !flags.nopick) nomul(0, 0, FALSE);
482 add_valid_menu_class(0); /* reset */
483 if (!u.uswallow) {
484 objchain = level.objects[u.ux][u.uy];
485 traverse_how = BY_NEXTHERE;
486 } else {pline(FunnyHallu ? "There's something embedded here, but you can't dislodge it..." : "You can't take items out of a monster's interior!");
487 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
488 return (0); /* otherwise the player could snatch worn amulets of life saving or similar stuff! --Amy */
490 } /*{
491 objchain = u.ustuck->minvent;
492 traverse_how = 0;*/ /* nobj */
493 /*}*/
495 * Start the actual pickup process. This is split into two main
496 * sections, the newer menu and the older "traditional" methods.
497 * Automatic pickup has been split into its own menu-style routine
498 * to make things less confusing.
500 if (autopickup) {
501 n = autopick(objchain, traverse_how, &pick_list);
502 goto menu_pickup;
505 if ((flags.menu_style != MENU_TRADITIONAL && !InventoryDoesNotGo) || iflags.menu_requested) {
507 /* use menus exclusively */
508 if (count) { /* looking for N of something */
509 char buf[QBUFSZ];
510 sprintf(buf, "Pick %d of what?", count);
511 val_for_n_or_more = count; /* set up callback selector */
512 n = query_objlist(buf, objchain,
513 traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT,
514 &pick_list, PICK_ONE, n_or_more);
515 /* correct counts, if any given */
516 for (i = 0; i < n; i++)
517 pick_list[i].count = count;
518 } else {
519 n = query_objlist("Pick up what?", objchain,
520 traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT|FEEL_COCKATRICE,
521 &pick_list, PICK_ANY, all_but_uchain);
523 menu_pickup:
524 n_tried = n;
525 for (n_picked = i = 0 ; i < n; i++) {
526 res = pickup_object(pick_list[i].item.a_obj,pick_list[i].count,
527 FALSE, FALSE);
528 if (res < 0) break; /* can't continue */
529 n_picked += res;
531 if (pick_list) free((void *)pick_list);
533 } else {
534 /* old style interface */
535 int ct = 0;
536 long lcount;
537 boolean all_of_a_type, selective;
538 char oclasses[MAXOCLASSES];
539 struct obj *obj, *obj2;
541 oclasses[0] = '\0'; /* types to consider (empty for all) */
542 all_of_a_type = TRUE; /* take all of considered types */
543 selective = FALSE; /* ask for each item */
545 /* check for more than one object */
546 for (obj = objchain;
547 obj; obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj)
548 ct++;
550 if (ct == 1 && count) {
551 /* if only one thing, then pick it */
552 obj = objchain;
553 lcount = min(obj->quan, (long)count);
554 n_tried++;
555 if (pickup_object(obj, lcount, FALSE, FALSE) > 0)
556 n_picked++; /* picked something */
557 goto end_query;
559 } else if (ct >= 2) {
560 int via_menu = 0;
562 There("are %s objects here.",
563 (ct <= 10) ? "several" : "many");
564 if (!query_classes(oclasses, &selective, &all_of_a_type,
565 "pick up", objchain,
566 traverse_how == BY_NEXTHERE,
567 #ifndef GOLDOBJ
568 FALSE,
569 #endif
570 &via_menu)) {
571 if (!via_menu) return (0);
572 n = query_objlist("Pick up what?",
573 objchain,
574 traverse_how|(selective ? 0 : INVORDER_SORT),
575 &pick_list, PICK_ANY,
576 via_menu == -2 ? allow_all : allow_category);
577 goto menu_pickup;
581 for (obj = objchain; obj; obj = obj2) {
582 if (traverse_how == BY_NEXTHERE)
583 obj2 = obj->nexthere; /* perhaps obj will be picked up */
584 else
585 obj2 = obj->nobj;
586 lcount = -1L;
588 if (!selective && oclasses[0] && !index(oclasses,obj->oclass))
589 continue;
591 if (!all_of_a_type) {
592 char qbuf[BUFSZ];
593 sprintf(qbuf, "Pick up %s?",
594 safe_qbuf("", sizeof("Pick up ?"), doname(obj),
595 an(simple_typename(obj->otyp)), "something"));
596 switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
597 case 'q': goto end_query; /* out 2 levels */
598 case 'n': continue;
599 case 'a':
600 all_of_a_type = TRUE;
601 if (selective) {
602 selective = FALSE;
603 oclasses[0] = obj->oclass;
604 oclasses[1] = '\0';
606 break;
607 case '#': /* count was entered */
608 if (!yn_number) continue; /* 0 count => No */
609 lcount = (long) yn_number;
610 if (lcount > obj->quan) lcount = obj->quan;
611 /* fall thru */
612 default: /* 'y' */
613 break;
616 if (lcount == -1L) lcount = obj->quan;
618 n_tried++;
619 if ((res = pickup_object(obj, lcount, FALSE, FALSE)) < 0) break;
620 n_picked += res;
622 end_query:
623 ; /* semicolon needed by brain-damaged compilers */
626 if (!u.uswallow) {
627 if (!OBJ_AT(u.ux,u.uy)) u.uundetected = 0;
629 /* position may need updating (invisible hero) */
630 if (n_picked) newsym(u.ux,u.uy);
632 /* see whether there's anything else here, after auto-pickup is done */
633 if (autopickup) check_here(n_picked > 0);
636 /* Picking up stuff no longer consumes turns. --Amy */
637 /* See comment in do.c about soviet mode */
638 /* message is only given if you actually tried to pick something up */
640 if (issoviet) {
641 if (!rn2(10) && n_tried) pline("Eto zanimayet ochered' potomu, chto sovetskiy khochet, chtoby igra byla der'mo.");
642 return (n_tried > 0);
643 /* I considered making it "return 1" just to spite the player, but decided to be lenient. */
645 return /*(n_tried > */0/*)*/;
648 #ifdef AUTOPICKUP_EXCEPTIONS
649 boolean
650 is_autopickup_exception(obj, grab)
651 struct obj *obj;
652 boolean grab; /* forced pickup, rather than forced leave behind? */
655 * Does the text description of this match an exception?
657 char *objdesc = makesingular(doname(obj));
658 struct autopickup_exception *ape = (grab) ?
659 iflags.autopickup_exceptions[AP_GRAB] :
660 iflags.autopickup_exceptions[AP_LEAVE];
661 while (ape) {
662 if (pmatch(ape->pattern, objdesc)) return TRUE;
663 ape = ape->next;
665 return FALSE;
667 #endif /* AUTOPICKUP_EXCEPTIONS */
670 * Pick from the given list using flags.pickup_types. Return the number
671 * of items picked (not counts). Create an array that returns pointers
672 * and counts of the items to be picked up. If the number of items
673 * picked is zero, the pickup list is left alone. The caller of this
674 * function must free the pickup list.
676 STATIC_OVL int
677 autopick(olist, follow, pick_list)
678 struct obj *olist; /* the object list */
679 int follow; /* how to follow the object list */
680 menu_item **pick_list; /* list of objects and counts to pick up */
682 menu_item *pi; /* pick item */
683 struct obj *curr;
684 int n;
685 const char *otypes = flags.pickup_types;
687 /* first count the number of eligible items */
688 for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
690 if (AlwaysAutopickup || u.uprops[AUTOPICKUP_ALWAYS].extrinsic || have_autopickupstone()) n++;
691 else {
693 #ifndef AUTOPICKUP_EXCEPTIONS
694 if (/*!*otypes || */index(otypes, curr->oclass) ||
695 (flags.pickup_thrown && curr->was_thrown && !(curr->cursed && curr->bknown && !flags.pickup_cursed && !Hallucination && !(PlayerUninformation) ) ) )
696 #else
697 if ((/*!*otypes || */index(otypes, curr->oclass) ||
698 (flags.pickup_thrown && curr->was_thrown && !(curr->cursed && curr->bknown && !flags.pickup_cursed && !Hallucination && !(PlayerUninformation) ) ) ||
699 is_autopickup_exception(curr, TRUE)) &&
700 !is_autopickup_exception(curr, FALSE))
701 #endif
702 n++;
706 if (n) {
707 *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n);
708 for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
710 if (AlwaysAutopickup || u.uprops[AUTOPICKUP_ALWAYS].extrinsic || have_autopickupstone()) {
711 pi[n].item.a_obj = curr;
712 pi[n].count = curr->quan;
713 n++;
715 } else {
717 #ifndef AUTOPICKUP_EXCEPTIONS
718 if (/*!*otypes || */index(otypes, curr->oclass) ||
719 (flags.pickup_thrown && curr->was_thrown && !(curr->cursed && curr->bknown && !flags.pickup_cursed && !Hallucination && !(PlayerUninformation) ) ) ) {
720 #else
721 if ((/*!*otypes || */index(otypes, curr->oclass) ||
722 (flags.pickup_thrown && curr->was_thrown && !(curr->cursed && curr->bknown && !flags.pickup_cursed && !Hallucination && !(PlayerUninformation) ) ) ||
723 is_autopickup_exception(curr, TRUE)) && !is_autopickup_exception(curr, FALSE)) {
724 #endif
725 pi[n].item.a_obj = curr;
726 pi[n].count = curr->quan;
727 n++;
734 return n;
739 * Put up a menu using the given object list. Only those objects on the
740 * list that meet the approval of the allow function are displayed. Return
741 * a count of the number of items selected, as well as an allocated array of
742 * menu_items, containing pointers to the objects selected and counts. The
743 * returned counts are guaranteed to be in bounds and non-zero.
745 * Query flags:
746 * BY_NEXTHERE - Follow object list via nexthere instead of nobj.
747 * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
748 * use it.
749 * USE_INVLET - Use object's invlet.
750 * INVORDER_SORT - Use hero's pack order.
751 * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow".
752 * SIGNAL_CANCEL - Return -2 rather than 0 if player cancels.
755 query_objlist(qstr, olist, qflags, pick_list, how, allow)
756 const char *qstr; /* query string */
757 struct obj *olist; /* the list to pick from */
758 int qflags; /* options to control the query */
759 menu_item **pick_list; /* return list of items picked */
760 int how; /* type of query */
761 boolean (*allow)(OBJ_P);/* allow function */
763 int i, j;
764 int n;
765 winid win;
766 struct obj *curr, *last;
767 struct obj **oarray;
768 char *pack;
769 anything any;
770 boolean printed_type_name;
772 if (InventoryDoesNotGo && !program_state.gameover) {pline("Not enough memory to create inventory window");
773 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
774 return 0;
777 *pick_list = (menu_item *) 0;
778 if (!olist) return 0;
780 /* count the number of items allowed */
781 for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags)) {
783 if ((*allow)(curr)) {
784 last = curr;
785 n++;
789 if (n == 0) /* nothing to pick here */
790 return (qflags & SIGNAL_NOMENU) ? -1 : 0;
792 if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
793 *pick_list = (menu_item *) alloc(sizeof(menu_item));
794 (*pick_list)->item.a_obj = last;
795 (*pick_list)->count = last->quan;
796 return 1;
799 /* Make a temporary array to store the objects sorted */
800 oarray = (struct obj **)alloc(n*sizeof(struct obj*));
802 /* Add objects to the array */
803 i = 0;
804 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
805 if ((*allow)(curr)) {
806 if ((iflags.sortloot == 'f' ||
807 (iflags.sortloot == 'l' && !(qflags & USE_INVLET))) && !(Hallucination || PlayerUninformation))
809 /* Insert object at correct index */
810 for (j = i; j; j--)
812 if (strcmpi(cxname3(curr), cxname3(oarray[j-1]))>0) break;
813 oarray[j] = oarray[j-1];
815 oarray[j] = curr;
816 i++;
817 } else {
818 /* Just add it to the array */
819 oarray[i++] = curr;
824 win = create_nhwindow(NHW_MENU);
825 start_menu(win);
826 any.a_obj = (struct obj *) 0;
829 * Run through the list and add the objects to the menu. If
830 * INVORDER_SORT is set, we'll run through the list once for
831 * each type so we can group them. The allow function will only
832 * be called once per object in the list.
834 pack = flags.inv_order;
835 do {
836 printed_type_name = FALSE;
837 /*for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {*/
838 for (i = 0; i < n; i++) {
839 curr = oarray[i];
841 if ((qflags & FEEL_COCKATRICE) && (curr->otyp == CORPSE || curr->otyp == EGG) &&
842 will_feel_cockatrice(curr, FALSE)) {
843 destroy_nhwindow(win); /* stop the menu and revert */
844 (void) look_here(0, FALSE);
845 return 0;
847 if ((!(qflags & INVORDER_SORT) || curr->oclass == *pack)
848 && (*allow)(curr)) {
850 /* if sorting, print type name (once only) */
851 if (qflags & INVORDER_SORT && !printed_type_name) {
852 any.a_obj = (struct obj *) 0;
853 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
854 let_to_name(*pack, FALSE, iflags.showsym), MENU_UNSELECTED);
855 printed_type_name = TRUE;
858 any.a_obj = curr;
859 add_menu(win, obj_to_glyph(curr), &any,
860 qflags & USE_INVLET ? curr->invlet : 0,
861 def_oc_syms[(int)objects[curr->otyp].oc_class],
862 ATR_NONE, doname(curr), MENU_UNSELECTED);
865 pack++;
866 } while (qflags & INVORDER_SORT && *pack);
868 free(oarray);
869 end_menu(win, qstr);
870 n = select_menu(win, how, pick_list);
871 destroy_nhwindow(win);
873 if (n > 0) {
874 menu_item *mi;
875 int i;
877 /* fix up counts: -1 means no count used => pick all */
878 for (i = 0, mi = *pick_list; i < n; i++, mi++)
879 if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
880 mi->count = mi->item.a_obj->quan;
881 } else if (n < 0) {
882 /* caller's don't expect -1 */
883 n = (qflags & SIGNAL_CANCEL) ? -2 : 0;
885 return n;
889 * allow menu-based category (class) selection (for Drop,take off etc.)
893 query_category(qstr, olist, qflags, pick_list, how)
894 const char *qstr; /* query string */
895 struct obj *olist; /* the list to pick from */
896 int qflags; /* behaviour modification flags */
897 menu_item **pick_list; /* return list of items picked */
898 int how; /* type of query */
900 int n;
901 winid win;
902 struct obj *curr;
903 char *pack;
904 anything any;
905 boolean collected_type_name;
906 char invlet;
907 int ccount;
908 boolean do_unpaid = FALSE;
909 boolean do_unided = FALSE;
910 boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
911 do_buc_unknown = FALSE;
912 int num_buc_types = 0;
914 *pick_list = (menu_item *) 0;
915 if (!olist) return 0;
916 if ((qflags & UNPAID_TYPES) && count_unpaid(olist) && !Hallucination) do_unpaid = TRUE;
917 if ((qflags & NOTFULLYIDED) && count_notfullyided(olist) && !Hallucination) do_unided = TRUE;
918 if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED) && !Hallucination && !(PlayerUninformation) ) {
919 do_blessed = TRUE;
920 num_buc_types++;
922 if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED) && !Hallucination && !(PlayerUninformation) ) {
923 do_cursed = TRUE;
924 num_buc_types++;
926 if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED) && !Hallucination && !(PlayerUninformation) ) {
927 do_uncursed = TRUE;
928 num_buc_types++;
930 if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN) && !Hallucination && !(PlayerUninformation) ) {
931 do_buc_unknown = TRUE;
932 num_buc_types++;
935 ccount = count_categories(olist, qflags);
936 /* no point in actually showing a menu for a single category */
937 if (ccount == 1 && !do_unpaid && num_buc_types <= 1 && !(qflags & BILLED_TYPES)) {
938 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
939 if ((qflags & WORN_TYPES) &&
940 !(curr->owornmask & (W_ARMOR|W_RING|W_AMUL|W_IMPLANT|W_TOOL|W_WEP|W_SWAPWEP|W_QUIVER)))
941 continue;
942 break;
944 if (curr) {
945 *pick_list = (menu_item *) alloc(sizeof(menu_item));
946 (*pick_list)->item.a_int = curr->oclass;
947 return 1;
948 } else {
949 #ifdef DEBUG
950 impossible("query_category: no single object match");
951 #endif
953 return 0;
956 win = create_nhwindow(NHW_MENU);
957 start_menu(win);
958 pack = flags.inv_order;
959 if ((qflags & ALL_TYPES) && (ccount > 1)) {
960 invlet = 'a';
961 any.a_void = 0;
962 any.a_int = ALL_TYPES_SELECTED;
963 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
964 (qflags & WORN_TYPES) ? "All worn types" : "All types",
965 MENU_UNSELECTED);
966 invlet = 'b';
967 } else
968 invlet = 'a';
969 do {
970 collected_type_name = FALSE;
971 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
972 if (curr->oclass == *pack) {
973 if ((qflags & WORN_TYPES) &&
974 !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_IMPLANT | W_TOOL |
975 W_WEP | W_SWAPWEP | W_QUIVER)))
976 continue;
977 if (!collected_type_name) {
978 any.a_void = 0;
979 any.a_int = curr->oclass;
980 add_menu(win, NO_GLYPH, &any, invlet++,
981 def_oc_syms[(int)objects[curr->otyp].oc_class],
982 ATR_NONE, let_to_name(*pack, FALSE, iflags.showsym),
983 MENU_UNSELECTED);
984 collected_type_name = TRUE;
988 pack++;
989 if (invlet >= 'u') {
990 impossible("query_category: too many categories");
991 return 0;
993 } while (*pack);
995 /* unidentified items */
996 if (do_unided) {
997 invlet = 'I';
998 any.a_void = 0;
999 any.a_int = 'I';
1000 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1001 "Unidentified items", MENU_UNSELECTED);
1003 /* unpaid items if there are any */
1004 if (do_unpaid) {
1005 invlet = 'u';
1006 any.a_void = 0;
1007 any.a_int = 'u';
1008 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1009 "Unpaid items", MENU_UNSELECTED);
1011 /* billed items: checked by caller, so always include if BILLED_TYPES */
1012 if (qflags & BILLED_TYPES) {
1013 invlet = 'x';
1014 any.a_void = 0;
1015 any.a_int = 'x';
1016 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1017 "Unpaid items already used up", MENU_UNSELECTED);
1019 if (qflags & CHOOSE_ALL) {
1020 invlet = 'A';
1021 any.a_void = 0;
1022 any.a_int = 'A';
1023 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1024 (qflags & WORN_TYPES) ?
1025 "Auto-select every item being worn" :
1026 "Auto-select every item", MENU_UNSELECTED);
1028 /* items with b/u/c/unknown if there are any */
1029 if (do_blessed) {
1030 invlet = 'B';
1031 any.a_void = 0;
1032 any.a_int = 'B';
1033 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1034 "Items known to be Blessed", MENU_UNSELECTED);
1036 if (do_cursed) {
1037 invlet = 'C';
1038 any.a_void = 0;
1039 any.a_int = 'C';
1040 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1041 "Items known to be Cursed", MENU_UNSELECTED);
1043 if (do_uncursed) {
1044 invlet = 'U';
1045 any.a_void = 0;
1046 any.a_int = 'U';
1047 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1048 "Items known to be Uncursed", MENU_UNSELECTED);
1050 if (do_buc_unknown) {
1051 invlet = 'X';
1052 any.a_void = 0;
1053 any.a_int = 'X';
1054 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
1055 "Items of unknown B/C/U status",
1056 MENU_UNSELECTED);
1058 end_menu(win, qstr);
1059 n = select_menu(win, how, pick_list);
1060 destroy_nhwindow(win);
1061 if (n < 0)
1062 n = 0; /* caller's don't expect -1 */
1063 return n;
1066 STATIC_OVL int
1067 count_categories(olist, qflags)
1068 struct obj *olist;
1069 int qflags;
1071 char *pack;
1072 boolean counted_category;
1073 int ccount = 0;
1074 struct obj *curr;
1076 pack = flags.inv_order;
1077 do {
1078 counted_category = FALSE;
1079 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
1080 if (curr->oclass == *pack) {
1081 if ((qflags & WORN_TYPES) &&
1082 !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_IMPLANT | W_TOOL |
1083 W_WEP | W_SWAPWEP | W_QUIVER)))
1084 continue;
1085 if (!counted_category) {
1086 ccount++;
1087 counted_category = TRUE;
1091 pack++;
1092 } while (*pack);
1093 return ccount;
1096 /* could we carry `obj'? if not, could we carry some of it/them? */
1097 STATIC_OVL long
1098 carry_count(obj, container, count, telekinesis, wt_before, wt_after)
1099 struct obj *obj, *container; /* object to pick up, bag it's coming out of */
1100 long count;
1101 boolean telekinesis;
1102 int *wt_before, *wt_after;
1104 boolean adjust_wt = container && carried(container),
1105 is_gold = obj->oclass == COIN_CLASS;
1106 int wt, iw, ow, oow;
1107 long qq, savequan;
1108 #ifdef GOLDOBJ
1109 long umoney = money_cnt(invent);
1110 #endif
1111 unsigned saveowt;
1112 const char *verb, *prefx1, *prefx2, *suffx;
1113 char obj_nambuf[BUFSZ], where[BUFSZ];
1115 savequan = obj->quan;
1116 saveowt = obj->owt;
1118 iw = max_capacity();
1120 if (count != savequan) {
1121 obj->quan = count;
1122 obj->owt = (unsigned)weight(obj);
1124 wt = iw + (int)obj->owt;
1125 if (adjust_wt)
1126 wt -= (container->otyp == BAG_OF_HOLDING || container->otyp == ICE_BOX_OF_HOLDING || container->otyp == CHEST_OF_HOLDING || container->oartifact == ART_SACK_OF_HOLDING) ?
1127 (int)DELTA_CWT(container, obj) : (container->otyp == HANDYBAG) ? (int)HANDYBAG_CWT(container, obj) : (int)obj->owt;
1128 #ifndef GOLDOBJ
1129 if (is_gold) /* merged gold might affect cumulative weight */
1130 wt -= (GOLD_WT(u.ugold) + GOLD_WT(count) - GOLD_WT(u.ugold + count));
1131 #else
1132 /* This will go with silver+copper & new gold weight */
1133 if (is_gold) /* merged gold might affect cumulative weight */
1134 wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count));
1135 #endif
1136 if (count != savequan) {
1137 obj->quan = savequan;
1138 obj->owt = saveowt;
1140 *wt_before = iw;
1141 *wt_after = wt;
1143 if (wt < 0)
1144 return count;
1146 /* see how many we can lift */
1147 if (is_gold) {
1148 #ifndef GOLDOBJ
1149 iw -= (int)GOLD_WT(u.ugold);
1150 if (!adjust_wt) {
1151 qq = GOLD_CAPACITY((long)iw, u.ugold);
1152 } else {
1153 oow = 0;
1154 qq = 50L - (u.ugold % 100L) - 1L;
1155 #else
1156 iw -= (int)GOLD_WT(umoney);
1157 if (!adjust_wt) {
1158 qq = GOLD_CAPACITY((long)iw, umoney);
1159 } else {
1160 oow = 0;
1161 qq = 50L - (umoney % 100L) - 1L;
1162 #endif
1163 if (qq < 0L) qq += 100L;
1164 for ( ; qq <= count; qq += 100L) {
1165 obj->quan = qq;
1166 obj->owt = (unsigned)GOLD_WT(qq);
1167 #ifndef GOLDOBJ
1168 ow = (int)GOLD_WT(u.ugold + qq);
1169 #else
1170 ow = (int)GOLD_WT(umoney + qq);
1171 #endif
1172 ow -= (container->otyp == BAG_OF_HOLDING || container->otyp == ICE_BOX_OF_HOLDING || container->otyp == CHEST_OF_HOLDING || container->oartifact == ART_SACK_OF_HOLDING) ?
1173 (int)DELTA_CWT(container, obj) : (container->otyp == HANDYBAG) ? (int)HANDYBAG_CWT(container, obj) : (int)obj->owt;
1174 if (iw + ow >= 0) break;
1175 oow = ow;
1177 iw -= oow;
1178 qq -= 100L;
1180 if (qq < 0L) qq = 0L;
1181 else if (qq > count) qq = count;
1182 #ifndef GOLDOBJ
1183 wt = iw + (int)GOLD_WT(u.ugold + qq);
1184 #else
1185 wt = iw + (int)GOLD_WT(umoney + qq);
1186 #endif
1187 } else if (count > 1 || count < obj->quan) {
1189 * Ugh. Calc num to lift by changing the quan of of the
1190 * object and calling weight.
1192 * This works for containers only because containers
1193 * don't merge. -dean
1195 for (qq = 1L; qq <= count; qq++) {
1196 obj->quan = qq;
1197 obj->owt = (unsigned)(ow = weight(obj));
1198 if (adjust_wt)
1199 ow -= (container->otyp == BAG_OF_HOLDING || container->otyp == ICE_BOX_OF_HOLDING || container->otyp == CHEST_OF_HOLDING || container->oartifact == ART_SACK_OF_HOLDING) ?
1200 (int)DELTA_CWT(container, obj) : (container->otyp == HANDYBAG) ? (int)HANDYBAG_CWT(container, obj) : (int)obj->owt;
1201 if (iw + ow >= 0)
1202 break;
1203 wt = iw + ow;
1205 --qq;
1206 } else {
1207 /* there's only one, and we can't lift it */
1208 qq = 0L;
1210 obj->quan = savequan;
1211 obj->owt = saveowt;
1213 if (qq < count) {
1214 /* some message will be given */
1215 strcpy(obj_nambuf, doname(obj));
1216 if (container) {
1217 sprintf(where, "in %s", the(xname(container)));
1218 verb = "carry";
1219 } else {
1220 strcpy(where, "lying here");
1221 verb = telekinesis ? "acquire" : "lift";
1223 } else {
1224 /* lint supppression */
1225 *obj_nambuf = *where = '\0';
1226 verb = "";
1228 /* we can carry qq of them */
1229 if (qq > 0) {
1230 if (qq < count)
1231 You("can only %s %s of the %s %s.",
1232 verb, (qq == 1L) ? "one" : "some", obj_nambuf, where);
1233 *wt_after = wt;
1234 return qq;
1237 if (!container) strcpy(where, "here"); /* slightly shorter form */
1238 #ifndef GOLDOBJ
1239 if (invent || u.ugold) {
1240 #else
1241 if (invent || umoney) {
1242 #endif
1243 prefx1 = "you cannot ";
1244 prefx2 = "";
1245 suffx = " any more";
1246 } else {
1247 prefx1 = (obj->quan == 1L) ? "it " : "even one ";
1248 prefx2 = "is too heavy for you to ";
1249 suffx = "";
1251 There("%s %s %s, but %s%s%s%s.",
1252 otense(obj, "are"), obj_nambuf, where,
1253 prefx1, prefx2, verb, suffx);
1255 /* *wt_after = iw; */
1256 return 0L;
1259 /* determine whether character is able and player is willing to carry `obj' */
1260 STATIC_OVL
1261 int
1262 lift_object(obj, container, cnt_p, telekinesis, alwaysflag)
1263 struct obj *obj, *container; /* object to pick up, bag it's coming out of */
1264 long *cnt_p;
1265 boolean telekinesis;
1266 boolean alwaysflag;
1268 int result, old_wt, new_wt, prev_encumbr, next_encumbr;
1270 if (obj->otyp == BOULDER && In_sokoban(&u.uz)) {
1271 You("cannot get your %s around this %s.",
1272 body_part(HAND), xname(obj));
1273 return -1;
1275 if (obj->otyp == LOADSTONE || obj->otyp == LOADBOULDER || obj->otyp == STARLIGHTSTONE || alwaysflag ||
1276 (obj->otyp == BOULDER && (throws_rocks(youmonst.data) || (uarmg && uarmg->oartifact == ART_MOUNTAIN_FISTS)) ) ||
1277 (obj->oartifact && arti_is_evil(obj)) )
1278 return 1; /* lift regardless of current situation */
1280 *cnt_p = carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt);
1281 if (*cnt_p < 1L) {
1282 result = -1; /* nothing lifted */
1284 /* Trying to allow the player to pick up as much as they want. --Amy
1285 * If you REALLY want the limit to come back for some weird reason, enable the knapsacklimit option */
1287 #ifndef GOLDOBJ
1288 } else if ((flags.knapsacklimit || InventorySizeLimited) && obj->otyp != LOADSTONE && obj->otyp != HEALTHSTONE && obj->otyp != LUCKSTONE && obj->otyp != MANASTONE && obj->otyp != SLEEPSTONE && obj->otyp != LOADBOULDER && obj->otyp != STARLIGHTSTONE && obj->otyp != STONE_OF_MAGIC_RESISTANCE && !is_nastygraystone(obj) && !is_feminismstone(obj) && obj->oclass != COIN_CLASS && inv_cnt() >= (InventorySizeXtra ? 26 : 52) &&
1289 !merge_choice(invent, obj)) {
1290 #else
1291 } else if ((flags.knapsacklimit || InventorySizeLimited) && obj->otyp != LOADSTONE && obj->otyp != HEALTHSTONE && obj->otyp != LUCKSTONE && obj->otyp != MANASTONE && obj->otyp != SLEEPSTONE && obj->otyp != LOADBOULDER && obj->otyp != STARLIGHTSTONE && obj->otyp != STONE_OF_MAGIC_RESISTANCE && !is_nastygraystone(obj) && !is_feminismstone(obj) && inv_cnt() >= (InventorySizeXtra ? 26 : 52) && !merge_choice(invent, obj)) {
1292 #endif
1293 Your("knapsack cannot accommodate any more items.");
1294 result = -1; /* nothing lifted */
1295 } else {
1296 result = 1;
1297 prev_encumbr = near_capacity();
1298 if (prev_encumbr < flags.pickup_burden)
1299 prev_encumbr = flags.pickup_burden;
1300 next_encumbr = calc_capacity(new_wt - old_wt);
1301 if (next_encumbr > prev_encumbr && !(AlwaysAutopickup || u.uprops[AUTOPICKUP_ALWAYS].extrinsic || have_autopickupstone()) ) {
1302 /* if (telekinesis) {
1303 result = 0; */ /* don't lift */ /* Amy edit: nonsense! let the player pick up the goddamn item! */
1304 /*} else*/ {
1305 char qbuf[BUFSZ];
1306 long savequan = obj->quan;
1308 obj->quan = *cnt_p;
1309 strcpy(qbuf,
1310 (next_encumbr > HVY_ENCUMBER) ? overloadmsg :
1311 (next_encumbr > MOD_ENCUMBER) ? nearloadmsg :
1312 moderateloadmsg);
1313 sprintf(eos(qbuf), " %s. Continue?",
1314 safe_qbuf(qbuf, sizeof(" . Continue?"),
1315 doname(obj), an(simple_typename(obj->otyp)), "something"));
1316 obj->quan = savequan;
1317 switch (ynq(qbuf)) {
1318 case 'q': result = -1; break;
1319 case 'n': result = 0; break;
1320 default: break; /* 'y' => result == 1 */
1322 clear_nhwindow(WIN_MESSAGE);
1327 if (obj->otyp == SCR_SCARE_MONSTER && !stack_too_big(obj) && result <= 0 && !container)
1328 obj->spe = 0;
1329 return result;
1332 /* To prevent qbuf overflow in prompts use planA only
1333 * if it fits, or planB if PlanA doesn't fit,
1334 * finally using the fallback as a last resort.
1335 * last_restort is expected to be very short.
1337 const char *
1338 safe_qbuf(qbuf, padlength, planA, planB, last_resort)
1339 const char *qbuf, *planA, *planB, *last_resort;
1340 unsigned padlength;
1342 /* convert size_t (or int for ancient systems) to ordinary unsigned */
1343 unsigned len_qbuf = (unsigned)strlen(qbuf),
1344 len_planA = (unsigned)strlen(planA),
1345 len_planB = (unsigned)strlen(planB),
1346 len_lastR = (unsigned)strlen(last_resort);
1347 unsigned textleft = QBUFSZ - (len_qbuf + padlength);
1349 if (len_lastR >= textleft) {
1350 impossible("safe_qbuf: last_resort too large at %u characters.",
1351 len_lastR);
1352 return "";
1354 return (len_planA < textleft) ? planA :
1355 (len_planB < textleft) ? planB : last_resort;
1359 * Pick up <count> of obj from the ground and add it to the hero's inventory.
1360 * Returns -1 if caller should break out of its loop, 0 if nothing picked
1361 * up, 1 if otherwise.
1364 pickup_object(obj, count, telekinesis, alwaysflag)
1365 struct obj *obj;
1366 long count;
1367 boolean telekinesis; /* not picking it up directly by hand */
1368 boolean alwaysflag; /* force the item to be picked up even if it burdens you --Amy */
1370 int res, nearload;
1371 #ifndef GOLDOBJ
1372 const char *where = (obj->ox == u.ux && obj->oy == u.uy) ?
1373 "here" : "there";
1374 #endif
1376 if (obj->quan < count) {
1377 impossible("pickup_object: count %ld > quan %ld?",
1378 count, obj->quan);
1379 return 0;
1382 /* In case of auto-pickup, where we haven't had a chance
1383 to look at it yet; affects docall(SCR_SCARE_MONSTER). */
1384 if (!Blind)
1385 if ((!obj->oinvis || See_invisible) && !obj->oinvisreal)
1386 obj->dknown = 1;
1388 if (obj == uchain) { /* do not pick up attached chain */
1389 return 0;
1390 } else if (obj->dynamitekaboom) {
1391 return 0;
1392 } else if ( (obj == uball) && obj->otyp == GOLD_PIECE) {
1393 return 0;
1394 } else if (obj->oartifact && !touch_artifact(obj,&youmonst)) {
1395 return 0;
1396 #ifndef GOLDOBJ
1397 } else if (obj->oclass == COIN_CLASS) {
1398 /* Special consideration for gold pieces... */
1399 long iw = (long)max_capacity() - GOLD_WT(u.ugold);
1400 long gold_capacity = GOLD_CAPACITY(iw, u.ugold);
1402 if (gold_capacity <= 0L) {
1403 pline(
1404 "There %s %ld gold piece%s %s, but you cannot carry any more.",
1405 otense(obj, "are"),
1406 obj->quan, plur(obj->quan), where);
1407 return 0;
1408 } else if (gold_capacity < count) {
1409 You("can only %s %s of the %ld gold pieces lying %s.",
1410 telekinesis ? "acquire" : "carry",
1411 gold_capacity == 1L ? "one" : "some", obj->quan, where);
1412 pline("%s %ld gold piece%s.",
1413 nearloadmsg, gold_capacity, plur(gold_capacity));
1414 u.ugold += gold_capacity;
1415 obj->quan -= gold_capacity;
1416 costly_gold(obj->ox, obj->oy, gold_capacity);
1417 } else {
1418 /* The SC343-20 bugfix causes phantom crash bugs BECAUSE OBJ IS BEING DELETED. --Amy */
1419 u.ugold += count;
1420 if ((nearload = near_capacity()) != 0)
1421 pline("%s %ld gold piece%s.",
1422 nearload < MOD_ENCUMBER ?
1423 moderateloadmsg : nearloadmsg,
1424 count, plur(count));
1425 else
1426 prinv((char *) 0, obj, count);
1427 costly_gold(obj->ox, obj->oy, count);
1428 if (count == obj->quan)
1429 delobj(obj);
1430 else
1431 obj->quan -= count;
1433 flags.botl = 1;
1434 if (flags.run) nomul(0, 0, FALSE);
1435 return 1;
1436 #endif
1437 } else if (obj->otyp == PETRIFYIUM_BAR) {
1438 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && !telekinesis) {
1439 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1440 display_nhwindow(WIN_MESSAGE, FALSE);
1441 else {
1442 static char kbuf[BUFSZ];
1444 strcpy(kbuf, "touching a petrifyium bar");
1445 pline("Touching a petrifyium bar is a fatal mistake.");
1446 instapetrify(kbuf);
1447 return -1;
1452 } else if (obj->otyp == PETRIFYIUM_BRA) {
1453 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && !telekinesis) {
1454 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1455 display_nhwindow(WIN_MESSAGE, FALSE);
1456 else {
1457 static char kbuf[BUFSZ];
1459 strcpy(kbuf, "touching a petrifyium bra");
1460 pline("Touching a petrifyium bra is a fatal mistake.");
1461 instapetrify(kbuf);
1462 return -1;
1467 } else if (obj->otyp == CORPSE) {
1468 if ( (touch_petrifies(&mons[obj->corpsenm])) && (!uarmg || FingerlessGloves)
1469 && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && !telekinesis) {
1470 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1471 display_nhwindow(WIN_MESSAGE, FALSE);
1472 else {
1473 static char kbuf[BUFSZ];
1475 pline("Touching this type of corpse is a fatal mistake.");
1476 strcpy(kbuf, "touching a petrifying corpse");
1477 instapetrify(kbuf);
1478 return -1;
1480 } else if (is_rider(&mons[obj->corpsenm]) || is_deadlysin(&mons[obj->corpsenm])) {
1481 pline("At your %s, the corpse suddenly moves...",
1482 telekinesis ? "attempted acquisition" : "touch");
1483 (void) revive_corpse(obj, FALSE);
1484 exercise(A_WIS, FALSE);
1485 return -1;
1487 } else if (obj->otyp == EGG) {
1488 if ( (touch_petrifies(&mons[obj->corpsenm])) && obj->corpsenm != PM_PLAYERMON && (!uarmg || FingerlessGloves)
1489 && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && !telekinesis) {
1490 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1491 display_nhwindow(WIN_MESSAGE, FALSE);
1492 else {
1493 static char kbuf[BUFSZ];
1494 strcpy(kbuf, "coming into contact with a petrifying object");
1496 pline("Touching a petrifying egg is a fatal mistake.");
1497 instapetrify(kbuf);
1498 return -1;
1501 } else if (obj->otyp == SCR_SCARE_MONSTER && !stack_too_big(obj)) {
1502 if (obj->blessed) obj->blessed = 0;
1503 else if (!obj->spe && !obj->cursed) obj->spe = 1;
1504 else {
1505 pline_The("scroll%s %s to dust as you %s %s up.",
1506 plur(obj->quan), otense(obj, "turn"),
1507 telekinesis ? "raise" : "pick",
1508 (obj->quan == 1L) ? "it" : "them");
1509 if (!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
1510 !(objects[SCR_SCARE_MONSTER].oc_uname))
1511 docall(obj);
1512 useupf(obj, obj->quan);
1513 return 1; /* tried to pick something up and failed, but
1514 don't want to terminate pickup loop yet */
1516 } else if (obj->otyp == SCR_INSTANT_AMNESIA) {
1518 useupf(obj, obj->quan);
1519 forget(ALL_SPELLS|ALL_MAP, FALSE);
1520 pline("If ever I should forget, May God make me more wretched Than ever I have been yet!");
1521 return 1; /* tried to pick something up and failed, but
1522 don't want to terminate pickup loop yet */
1523 } else if (obj && obj->oclass == SCROLL_CLASS && !rn2(2) && (DustbinBug || u.uprops[DUSTBIN_BUG].extrinsic || have_dustbinstone())) {
1524 useupf(obj, obj->quan);
1525 pline("Your clumsy %s accidentally rip the paper to pieces.", makeplural(body_part(HAND)));
1526 return 1; /* tried to pick something up and failed, but
1527 don't want to terminate pickup loop yet */
1531 if (Role_if(PM_YAUTJA) && obj && obj->otyp == CHEMISTRY_SET) obj->known = TRUE;
1532 if (Role_if(PM_CRACKER) && obj && obj->oclass == SCROLL_CLASS) obj->bknown = TRUE;
1534 if (obj && obj->oclass == WAND_CLASS && (ManaBatteryBug || u.uprops[MANA_BATTERY_BUG].extrinsic || have_batterystone()) && obj->spe >= 0) {
1536 if (obj->spe == 0) obj->spe = -1;
1537 else {
1538 obj->spe -= rnd(obj->spe);
1539 if (!rn2(3)) obj->spe = 0;
1543 if (obj && obj->oclass == POTION_CLASS && !rn2(3) && (Monsterfingers || u.uprops[MONSTERFINGERS_EFFECT].extrinsic || have_butterfingerstone()) ) {
1544 pline("Whoops, the bottle breaks unexpectedly!");
1545 potionbreathe(obj);
1546 useupf(obj, obj->quan);
1547 return 1; /* tried to pick something up and failed, but
1548 don't want to terminate pickup loop yet */
1551 if (obj && obj->oartifact == ART_HAAAAAAAAAAAAA_LELUJA) {
1552 obj->bknown = 1;
1553 obj->cursed = obj->hvycurse = obj->prmcurse = obj->evilcurse = obj->morgcurse = obj->bbrcurse = obj->stckcurse = 0;
1554 obj->blessed = 1;
1557 if ((res = lift_object(obj, (struct obj *)0, &count, telekinesis, alwaysflag)) <= 0)
1558 return res;
1560 #ifdef GOLDOBJ
1561 /* Whats left of the special case for gold :-) */
1562 if (obj->oclass == COIN_CLASS) flags.botl = 1;
1563 #endif
1564 if (obj->quan != count && obj->otyp != LOADSTONE && obj->otyp != LUCKSTONE && obj->otyp != HEALTHSTONE && obj->otyp != MANASTONE && obj->otyp != SLEEPSTONE && obj->otyp != LOADBOULDER && obj->otyp != STARLIGHTSTONE && obj->otyp != STONE_OF_MAGIC_RESISTANCE && !is_nastygraystone(obj) && !is_feminismstone(obj) )
1565 obj = splitobj(obj, count);
1567 if (TooHeavyEffect || u.uprops[TOO_HEAVY_EFFECT].extrinsic || have_tooheavystone() || (uamul && uamul->oartifact == ART_THAT_OLD_BUG) || (uarmg && uarmg->oartifact == ART_SUPERHEAVYKLONK) ) {
1568 if (IncreasedGravity < 10000000) IncreasedGravity += 50;
1571 obj = pick_obj(obj);
1573 /* evil patch addition: Nasty gray stones aren't usually generated cursed, but they autocurse if you pick them up. BUC testing won't save you! --Amy */
1574 if (is_nastygraystone(obj)) curse(obj);
1575 if (is_feminismstone(obj)) {
1576 curse(obj);
1577 pline("Oh no, apparently there is some sort of curse on this gem. It won't leave your inventory as long as it's still cursed.");
1580 /* artifact versions of such stones should be harder to get rid of --Amy */
1581 if ( (is_nastygraystone(obj) || is_feminismstone(obj)) ) {
1582 if (obj->oartifact) {
1583 if (!rn2(3)) obj->cursed = obj->hvycurse = TRUE;
1584 if (!rn2(3)) obj->cursed = obj->stckcurse = TRUE;
1588 if (uwep && uwep == obj) mrg_to_wielded = TRUE;
1589 nearload = near_capacity();
1590 prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0,
1591 obj, count);
1592 mrg_to_wielded = FALSE;
1593 return 1;
1597 * Do the actual work of picking otmp from the floor or monster's interior
1598 * and putting it in the hero's inventory. Take care of billing. Return a
1599 * pointer to the object where otmp ends up. This may be different
1600 * from otmp because of merging.
1602 * Gold never reaches this routine unless GOLDOBJ is defined.
1604 struct obj *
1605 pick_obj(otmp)
1606 struct obj *otmp;
1608 obj_extract_self(otmp);
1609 if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
1610 char saveushops[5], fakeshop[2];
1612 /* addtobill cares about your location rather than the object's;
1613 usually they'll be the same, but not when using telekinesis
1614 (if ever implemented) or a grappling hook */
1615 strcpy(saveushops, u.ushops);
1616 fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE);
1617 fakeshop[1] = '\0';
1618 strcpy(u.ushops, fakeshop);
1619 /* sets obj->unpaid if necessary */
1620 addtobill(otmp, TRUE, FALSE, FALSE);
1621 strcpy(u.ushops, saveushops);
1622 /* if you're outside the shop, make shk notice */
1623 if (!index(u.ushops, *fakeshop))
1624 remote_burglary(otmp->ox, otmp->oy);
1626 if (otmp->no_charge) /* only applies to objects outside invent */
1627 otmp->no_charge = 0;
1628 if (otmp->was_thrown) /* likewise */
1629 otmp->was_thrown = 0;
1630 newsym(otmp->ox, otmp->oy);
1631 return addinv(otmp); /* might merge it with other objects */
1635 * prints a message if encumbrance changed since the last check and
1636 * returns the new encumbrance value (from near_capacity()).
1639 encumber_msg()
1641 static int oldcap = UNENCUMBERED;
1642 int newcap = near_capacity();
1644 if(oldcap < newcap) {
1645 switch(newcap) {
1646 case 1: Your("movements are slowed slightly because of your load.");
1647 break;
1648 case 2: You("rebalance your load. Movement is difficult.");
1649 break;
1650 case 3: You("%s under your heavy load. Movement is very hard.",
1651 stagger(youmonst.data, "stagger"));
1652 break;
1653 default: You("%s move a handspan with this load!",
1654 newcap == 4 ? "can barely" : "can't even");
1655 break;
1657 flags.botl = 1;
1658 } else if(oldcap > newcap) {
1659 switch(newcap) {
1660 case 0: Your("movements are now unencumbered.");
1661 break;
1662 case 1: Your("movements are only slowed slightly by your load.");
1663 break;
1664 case 2: You("rebalance your load. Movement is still difficult.");
1665 break;
1666 case 3: You("%s under your load. Movement is still very hard.",
1667 stagger(youmonst.data, "stagger"));
1668 break;
1670 flags.botl = 1;
1673 oldcap = newcap;
1674 return (newcap);
1677 /* Is there a container at x,y. Optional: return count of containers at x,y */
1678 STATIC_OVL int
1679 container_at(x, y, countem)
1680 int x,y;
1681 boolean countem;
1683 struct obj *cobj, *nobj;
1684 int container_count = 0;
1686 for(cobj = level.objects[x][y]; cobj; cobj = nobj) {
1687 nobj = cobj->nexthere;
1688 if(Is_container(cobj)) {
1689 container_count++;
1690 if (!countem) break;
1693 return container_count;
1696 STATIC_OVL boolean
1697 able_to_loot(x, y)
1698 int x, y;
1700 if (!can_reach_floor()) {
1701 if (u.usteed && !(uwep && uwep->oartifact == ART_SORTIE_A_GAUCHE) && !(powerfulimplants() && uimplant && uimplant->oartifact == ART_READY_FOR_A_RIDE) && !FemtrapActiveKerstin && !(bmwride(ART_DEEPER_LAID_BMW)) && (PlayerCannotUseSkills || P_SKILL(P_RIDING) < P_BASIC) )
1702 rider_cant_reach(); /* not skilled enough to reach */
1703 else
1704 You("cannot reach the %s.", surface(x, y));
1706 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1707 return FALSE;
1708 } else if ((is_waterypool(x, y) || is_watertunnel(x,y) || is_lava(x, y)) && !is_crystalwater(x, y)) {
1709 /* at present, can't loot in water even when Underwater */
1710 You("cannot loot things that are deep in the %s.",
1711 is_lava(x, y) ? "lava" : "water");
1712 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1713 return FALSE;
1714 } else if (nolimbs(youmonst.data) && !Race_if(PM_TRANSFORMER) ) {
1715 pline("Without limbs, you cannot loot anything.");
1716 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1717 return FALSE;
1718 } else if (!freehandX() && !(Role_if(PM_CELLAR_CHILD) && uwep && (weapon_type(uwep) == P_QUARTERSTAFF)) ) {
1719 pline("Without a free %s, you cannot loot anything.",
1720 body_part(HAND));
1721 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1722 return FALSE;
1724 return TRUE;
1727 STATIC_OVL boolean
1728 mon_beside(x,y)
1729 int x, y;
1731 int i,j,nx,ny;
1732 for(i = -1; i <= 1; i++)
1733 for(j = -1; j <= 1; j++) {
1734 nx = x + i;
1735 ny = y + j;
1736 if(isok(nx, ny) && MON_AT(nx, ny))
1737 return TRUE;
1739 return FALSE;
1743 doloot() /* loot a container on the floor or loot saddle from mon. */
1746 if (MenuIsBugged) {
1747 pline("The loot command is currently unavailable!");
1748 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1749 return 0;
1752 struct obj *cobj, *nobj;
1753 register int c = -1;
1754 int timepassed = 0;
1755 coord cc;
1756 boolean underfoot = TRUE;
1757 const char *dont_find_anything = "don't find anything";
1758 struct monst *mtmp;
1759 char qbuf[BUFSZ];
1760 int prev_inquiry = 0;
1761 boolean prev_loot = FALSE;
1762 struct trap *trap;
1764 if (trap = t_at(u.ux, u.uy)) {
1765 if (trap->ttyp == VIVISECTION_TRAP) {
1766 You("are in vivisection, and therefore unable to loot anything!");
1767 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1768 return 0;
1772 if (check_capacity((char *)0)) {
1773 /* "Can't do that while carrying so much stuff." */
1774 return 0;
1777 /* It used to check for hands here, but I removed that because actually looting a container already checks if your
1778 * form has hands. It was really annoying that you could have twice the failure chance when looting off the ground
1779 * as opposed to applying a container in your inventory, so I changed that. --Amy */
1781 cc.x = u.ux; cc.y = u.uy;
1783 lootcont:
1785 if (container_at(cc.x, cc.y, FALSE)) {
1786 boolean any = FALSE;
1788 if (!able_to_loot(cc.x, cc.y)) return 0;
1789 for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
1790 nobj = cobj->nexthere;
1792 if (Is_container(cobj)) {
1793 sprintf(qbuf, "There is %s here, loot it?",
1794 safe_qbuf("", sizeof("There is here, loot it?"),
1795 doname(cobj), an(simple_typename(cobj->otyp)),
1796 "a container"));
1797 c = ynq(qbuf);
1798 if (c == 'q') return (timepassed);
1799 if (c == 'n') continue;
1800 any = TRUE;
1802 if (cobj->olocked) {
1803 if (uwep && uwep->oartifact == ART_FINAL_DOOR_SOLUTION) {
1804 cobj->olocked = FALSE;
1805 pline("kloeck!");
1806 } else {
1807 pline("Hmmm, it seems to be locked.");
1808 continue;
1811 if (cobj->otyp == BAG_OF_TRICKS) {
1812 int tmp;
1813 You("carefully open the bag...");
1814 pline("It develops a huge set of teeth and bites you!");
1815 tmp = rnd(10);
1816 if (Half_physical_damage && (rn2(2) || (uwep && uwep->oartifact == ART_SOOTHE_)) ) tmp = (tmp+1) / 2;
1817 if (StrongHalf_physical_damage && (rn2(2) || (uwep && uwep->oartifact == ART_SOOTHE_)) ) tmp = (tmp+1) / 2;
1818 losehp(tmp, "carnivorous bag", KILLED_BY_AN);
1819 makeknown(BAG_OF_TRICKS);
1820 timepassed = 1;
1821 continue;
1824 You("carefully open %s...", the(xname(cobj)));
1825 if ((cobj->otyp == BAG_OF_DIGESTION || cobj->otyp == LARGE_BOX_OF_DIGESTION || cobj->otyp == ICE_BOX_OF_DIGESTION) && !timepassed) timepassed = 1;
1826 if ((cobj->otyp == BAG_OF_HOLDING || cobj->otyp == CHEST_OF_HOLDING || cobj->oartifact == ART_SACK_OF_HOLDING || cobj->otyp == ICE_BOX_OF_HOLDING) && cobj->cursed && !timepassed) timepassed = 1;
1827 timepassed |= use_container(&cobj, 0); /* ATTENTION: cobj might be gone now (boh explosion) --Amy */
1829 /* might have triggered chest trap or magic bag explosion */
1830 if (multi < 0 || !cobj) return 1;
1833 if (any) c = 'y';
1834 } else if (Confusion) {
1835 #ifndef GOLDOBJ
1836 if (u.ugold){
1837 long contribution = rnd((int)min(LARGEST_INT,u.ugold));
1838 struct obj *goldob = mkgoldobj(contribution);
1839 #else
1840 struct obj *goldob;
1841 /* Find a money object to mess with */
1842 for (goldob = invent; goldob; goldob = goldob->nobj) {
1843 if (goldob->oclass == COIN_CLASS) break;
1845 if (goldob){
1846 long contribution = rnd((int)min(LARGEST_INT, goldob->quan));
1847 if (contribution < goldob->quan)
1848 goldob = splitobj(goldob, contribution);
1849 freeinv(goldob);
1850 #endif
1851 if (IS_THRONE(levl[u.ux][u.uy].typ)){
1852 struct obj *coffers;
1853 int pass;
1854 /* find the original coffers chest, or any chest */
1855 for (pass = 2; pass > -1; pass -= 2)
1856 for (coffers = fobj; coffers; coffers = coffers->nobj)
1857 if (coffers->otyp == CHEST && coffers->spe == pass)
1858 goto gotit; /* two level break */
1859 gotit:
1860 if (coffers) {
1861 verbalize("Thank you for your contribution to reduce the debt.");
1862 (void) add_to_container(coffers, goldob, TRUE);
1863 coffers->owt = weight(coffers);
1864 } else {
1865 struct monst *mon = makemon(courtmon(),
1866 u.ux, u.uy, NO_MM_FLAGS);
1867 if (mon) {
1868 #ifndef GOLDOBJ
1869 mon->mgold += goldob->quan;
1870 delobj(goldob);
1871 pline("The exchequer accepts your contribution.");
1872 } else {
1873 dropx(goldob);
1876 if (!rn2(5) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* reduce player's farming ability */
1877 /* may have teleported */
1878 levl[u.ux][u.uy].typ = ROOM;
1879 pline_The("throne vanishes in a puff of logic.");
1880 newsym(u.ux,u.uy);
1882 return 1; /* this is supposed to take time! --Amy */
1885 } else {
1886 dropx(goldob);
1887 #else
1888 add_to_minv(mon, goldob);
1889 pline("The exchequer accepts your contribution.");
1890 } else {
1891 dropy(goldob);
1894 } else {
1895 dropy(goldob);
1896 #endif
1897 pline("Ok, now there is loot here.");
1900 } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
1901 You("need to dig up the grave to effectively loot it...");
1904 * 3.3.1 introduced directional looting for some things.
1906 if (c != 'y' && mon_beside(u.ux, u.uy)) {
1907 if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location",
1908 u.ux, u.uy, &cc)) return 0;
1909 if (cc.x == u.ux && cc.y == u.uy) {
1910 underfoot = TRUE;
1911 if (container_at(cc.x, cc.y, FALSE))
1912 goto lootcont;
1913 } else
1914 underfoot = FALSE;
1915 if (u.dz < 0) {
1916 You("%s to loot on the %s.", dont_find_anything,
1917 ceiling(cc.x, cc.y));
1918 timepassed = 1;
1919 return timepassed;
1921 mtmp = m_at(cc.x, cc.y);
1922 if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot);
1924 /* Preserve pre-3.3.1 behaviour for containers.
1925 * Adjust this if-block to allow container looting
1926 * from one square away to change that in the future.
1928 if (!underfoot) {
1929 if (container_at(cc.x, cc.y, FALSE)) {
1930 if (mtmp) {
1931 You_cant("loot anything %sthere with %s in the way.",
1932 prev_inquiry ? "else " : "", mon_nam(mtmp));
1933 return timepassed;
1934 } else {
1935 You("have to be at a container to loot it.");
1937 } else {
1938 You("%s %sthere to loot.", dont_find_anything,
1939 (prev_inquiry || prev_loot) ? "else " : "");
1940 return timepassed;
1943 } else if (c != 'y' && c != 'n') {
1944 You("%s %s to loot.", dont_find_anything,
1945 underfoot ? "here" : "there");
1947 return (timepassed);
1950 /* loot_mon() returns amount of time passed.
1953 loot_mon(mtmp, passed_info, prev_loot)
1954 struct monst *mtmp;
1955 int *passed_info;
1956 boolean *prev_loot;
1958 int c = -1;
1959 int timepassed = 0;
1960 struct obj *otmp;
1961 char qbuf[QBUFSZ];
1963 /* 3.3.1 introduced the ability to remove saddle from a steed */
1964 /* *passed_info is set to TRUE if a loot query was given. */
1965 /* *prev_loot is set to TRUE if something was actually acquired in here. */
1966 if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
1967 long unwornmask;
1968 if (passed_info) *passed_info = 1;
1969 sprintf(qbuf, "Do you want to remove the saddle from %s?",
1970 x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE));
1971 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
1972 if (nolimbs(youmonst.data) && !Race_if(PM_TRANSFORMER) ) {
1973 You_cant("do that without limbs."); /* not body_part(HAND) */
1974 return (0);
1976 if (otmp->cursed) {
1977 You("can't. The saddle seems to be stuck to %s.",
1978 x_monnam(mtmp, ARTICLE_THE, (char *)0,
1979 SUPPRESS_SADDLE, FALSE));
1981 /* the attempt costs you time */
1982 return (1);
1984 /* wtf, why was it guaranteed to work even for a hostile horse trying to kill you??? --Amy */
1985 if (!mtmp->mtame && !mtmp->mpeaceful) {
1986 pline("%s doesn't just let you remove the saddle!", Monnam(mtmp));
1987 return (1);
1989 obj_extract_self(otmp);
1990 if ((unwornmask = otmp->owornmask) != 0L) {
1991 mtmp->misc_worn_check &= ~unwornmask;
1992 otmp->owornmask = 0L;
1993 update_mon_intrinsics(mtmp, otmp, FALSE, FALSE);
1995 otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
1996 (const char *)0);
1997 timepassed = rnd(3);
1998 if (prev_loot) *prev_loot = TRUE;
1999 } else if (c == 'q') {
2000 return (0);
2003 /* 3.4.0 introduced the ability to pick things up from within swallower's stomach */
2004 if (u.uswallow) {
2005 int count = passed_info ? *passed_info : 0;
2006 timepassed = pickup(count);
2008 return timepassed;
2012 * Decide whether an object being placed into a magic bag will cause
2013 * it to explode. If the object is a bag itself, check recursively.
2015 boolean
2016 mbag_explodes(obj, depthin)
2017 struct obj *obj;
2018 int depthin;
2020 /* these won't cause an explosion when they're empty */
2021 if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS) &&
2022 obj->spe <= 0)
2023 return FALSE;
2025 /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
2026 if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION) &&
2027 (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
2028 return TRUE;
2029 else if (Has_contents(obj)) {
2030 struct obj *otmp;
2032 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
2033 if (mbag_explodes(otmp, depthin+1)) return TRUE;
2035 return FALSE;
2038 void
2039 destroy_mbag(bomb, silent)
2040 struct obj *bomb;
2041 boolean silent;
2043 xchar x,y;
2044 boolean underwater;
2045 struct monst *mtmp = (struct monst *)0;
2047 if (get_obj_location(bomb, &x, &y, BURIED_TOO | CONTAINED_TOO)) {
2048 switch(bomb->where) {
2049 case OBJ_MINVENT:
2050 mtmp = bomb->ocarry;
2051 if (bomb == MON_WEP(mtmp)) {
2052 bomb->owornmask &= ~W_WEP;
2053 MON_NOWEP(mtmp);
2055 if (!silent && canseemon(mtmp))
2056 You("see %s engulfed in an explosion!", mon_nam(mtmp));
2057 mtmp->mhp -= d(6,6);
2058 if (mtmp->mhp < 1) {
2059 if (!bomb->yours)
2060 monkilled(mtmp, silent ? "" : "explosion", AD_PHYS);
2061 else xkilled(mtmp, !silent);
2063 break;
2064 case OBJ_INVENT:
2065 /* This shouldn't be silent! */
2066 pline("Something explodes inside your knapsack!");
2067 if (bomb == uwep) {
2068 uwepgone();
2069 stop_occupation();
2070 } else if (bomb == uswapwep) {
2071 uswapwepgone();
2072 stop_occupation();
2073 } else if (bomb == uquiver) {
2074 uqwepgone();
2075 stop_occupation();
2077 losehp(d(6,6), "carrying live explosives", KILLED_BY);
2078 break;
2079 case OBJ_FLOOR:
2080 underwater = (is_waterypool(x, y) || is_watertunnel(x,y));
2081 if (!silent) {
2082 if (x == u.ux && y == u.uy) {
2083 if (underwater && (Flying || Levitation))
2084 pline_The("water boils beneath you.");
2085 else if (underwater && (Wwalking || Race_if(PM_KORONST)))
2086 pline_The("water erupts around you.");
2087 else pline("A bag explodes under your %s!",
2088 makeplural(body_part(FOOT)));
2089 } else if (cansee(x, y))
2090 You(underwater ?
2091 "see a plume of water shoot up." :
2092 "see a bag explode.");
2094 if (underwater && (Flying || Levitation || Wwalking || Race_if(PM_KORONST))) {
2095 if ((Wwalking || Race_if(PM_KORONST)) && x == u.ux && y == u.uy) {
2096 struct trap trap;
2097 trap.ntrap = NULL;
2098 trap.tx = x;
2099 trap.ty = y;
2100 trap.launch.x = -1;
2101 trap.launch.y = -1;
2102 trap.ttyp = RUST_TRAP;
2103 trap.tseen = 0;
2104 trap.once = 0;
2105 trap.madeby_u = 0;
2106 trap.dst.dnum = -1;
2107 trap.dst.dlevel = -1;
2108 dotrap(&trap, 0);
2110 goto free_bomb;
2112 break;
2113 default: /* Buried, contained, etc. */
2114 if (!silent)
2115 You_hear("a muffled explosion.");
2116 goto free_bomb;
2117 break;
2121 free_bomb:
2122 if (Has_contents(bomb))
2123 delete_contents(bomb);
2125 obj_extract_self(bomb);
2126 obfree(bomb, (struct obj *)0);
2127 newsym(x,y);
2130 int put_into_container(struct obj *container, struct obj *obj)
2132 struct obj *t;
2134 t = current_container;
2135 current_container = container;
2136 in_container_(obj,FALSE);
2137 current_container = t;
2139 /* control reaches end of non-void function, but is this one even used anywhere?! --Amy */
2140 return 1; /* eh, let's return 1 for now, can still change it if necessary */
2144 /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
2145 STATIC_PTR int
2146 in_container_(obj,invobj)
2147 register struct obj *obj;
2148 boolean invobj;
2150 boolean floor_container = !carried(current_container);
2151 boolean was_unpaid = FALSE;
2152 char buf[BUFSZ];
2154 if (!current_container) {
2155 impossible("<in> no current_container?");
2156 return 0;
2157 } else if (obj == uball || obj == uchain) {
2158 You("must be kidding.");
2159 return 0;
2160 } else if (obj == current_container) {
2161 pline(FunnyHallu ? "You try folding it with some ikebana technique but to no avail." : "That would be an interesting topological exercise.");
2162 return 0;
2163 } else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_IMPLANT | W_TOOL)) {
2164 Norep("You cannot %s %s you are wearing.",
2165 Icebox ? "refrigerate" : "stash", something);
2166 return 0;
2167 } else if ((obj->otyp == LOADSTONE || obj->otyp == LUCKSTONE || obj->otyp == HEALTHSTONE || obj->otyp == MANASTONE || obj->otyp == SLEEPSTONE || obj->otyp == LOADBOULDER || obj->otyp == STARLIGHTSTONE || obj->otyp == STONE_OF_MAGIC_RESISTANCE || is_nastygraystone(obj) ) && obj->cursed) {
2168 obj->bknown = 1;
2169 pline_The("stone%s won't leave your person.", plur(obj->quan));
2170 return 0;
2171 } else if (obj->otyp == LUCKSTONE && isevilvariant && !obj->cursed && !obj->blessed && Luck < 0) {
2172 pline("Har har har, an evil presence prevents you from getting rid of that!");
2173 return(FALSE);
2174 } else if (is_feminismstone(obj) && obj->cursed) {
2175 obj->bknown = 1;
2176 pline_The("gem%s will not leave your inventory as long as they're cursed.", plur(obj->quan));
2177 return 0;
2178 } else if ( (obj->otyp == AMULET_OF_YENDOR && !u.freeplaymode) || (obj->otyp == FAKE_AMULET_OF_YENDOR && !u.freeplaymode) ||
2179 (obj->otyp == CANDELABRUM_OF_INVOCATION && !u.uevent.invoked) ||
2180 (obj->otyp == BELL_OF_OPENING && !u.uevent.invoked) ||
2181 (obj->oartifact == ART_KEY_OF_LAW && !u.uevent.invoked) ||
2182 (obj->oartifact == ART_GAUNTLET_KEY && !u.uevent.invoked) ||
2183 (obj->oartifact == ART_KEY_OF_NEUTRALITY && !u.uevent.invoked) ||
2184 (obj->oartifact == ART_KEY_OF_CHAOS && !u.uevent.invoked) ||
2185 (obj->otyp == SPE_BOOK_OF_THE_DEAD && !u.uevent.invoked) ) {
2186 /* Prohibit Amulets in containers; if you allow it, monsters can't
2187 * steal them. It also becomes a pain to check to see if someone
2188 * has the Amulet. Ditto for the Candelabrum, the Bell and the Book.
2190 pline("%s cannot be confined in such trappings.", The(xname(obj)));
2191 return 0;
2192 } else if (obj->otyp == LEATHER_LEASH && obj->leashmon != 0) {
2193 pline("%s attached to your pet.", Tobjnam(obj, "are"));
2194 return 0;
2195 } else if (obj->otyp == INKA_LEASH && obj->leashmon != 0) {
2196 pline("%s attached to your pet.", Tobjnam(obj, "are"));
2197 return 0;
2198 } else if (obj->otyp == ADAMANT_LEASH && obj->leashmon != 0) {
2199 pline("%s attached to your pet.", Tobjnam(obj, "are"));
2200 return 0;
2201 } else if (obj == uwep) {
2202 if (welded(obj)) {
2203 weldmsg(obj);
2204 return 0;
2206 setuwep((struct obj *) 0, FALSE, TRUE);
2207 if (uwep) return 0; /* unwielded, died, rewielded */
2208 } else if (obj == uswapwep) {
2209 setuswapwep((struct obj *) 0, FALSE);
2210 if (uswapwep) return 0; /* unwielded, died, rewielded */
2211 } else if (obj == uquiver) {
2212 setuqwep((struct obj *) 0);
2213 if (uquiver) return 0; /* unwielded, died, rewielded */
2216 if (obj->otyp == CORPSE) {
2217 if ( (touch_petrifies(&mons[obj->corpsenm])) && (!uarmg || FingerlessGloves)
2218 && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2219 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2220 display_nhwindow(WIN_MESSAGE, FALSE);
2221 else {
2222 static char kbuf[BUFSZ];
2224 pline("Touching this type of corpse is a fatal mistake.");
2225 strcpy(kbuf, "touching a petrifying corpse");
2226 instapetrify(kbuf);
2227 return -1;
2232 if (obj->otyp == PETRIFYIUM_BAR) {
2233 if ((!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2234 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2235 display_nhwindow(WIN_MESSAGE, FALSE);
2236 else {
2237 static char kbuf[BUFSZ];
2239 strcpy(kbuf, "touching a petrifyium bar");
2240 pline("Touching a petrifyium bar is a fatal mistake.");
2241 instapetrify(kbuf);
2242 return -1;
2247 if (obj->otyp == PETRIFYIUM_BRA) {
2248 if ((!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2249 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2250 display_nhwindow(WIN_MESSAGE, FALSE);
2251 else {
2252 static char kbuf[BUFSZ];
2254 strcpy(kbuf, "touching a petrifyium bra");
2255 pline("Touching a petrifyium bra is a fatal mistake.");
2256 instapetrify(kbuf);
2257 return -1;
2262 if (obj->otyp == EGG) {
2263 if ( (touch_petrifies(&mons[obj->corpsenm])) && obj->corpsenm != PM_PLAYERMON && (!uarmg || FingerlessGloves)
2264 && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2265 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2266 display_nhwindow(WIN_MESSAGE, FALSE);
2267 else {
2268 static char kbuf[BUFSZ];
2270 pline("Touching a petrifying egg is a fatal mistake.");
2271 strcpy(kbuf, "touching a petrifying egg");
2272 instapetrify(kbuf);
2273 return -1;
2278 /* boxes, boulders, and big statues can't fit into any container */
2279 if (obj->otyp == ICE_BOX || obj->otyp == DISPERSION_BOX || obj->otyp == ICE_BOX_OF_HOLDING || obj->otyp == ICE_BOX_OF_WATERPROOFING || obj->otyp == ICE_BOX_OF_DIGESTION || Is_box(obj) || obj->otyp == BOULDER ||
2280 (obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) {
2282 * xname() uses a static result array. Save obj's name
2283 * before current_container's name is computed. Don't
2284 * use the result of strcpy() within You() --- the order
2285 * of evaluation of the parameters is undefined.
2287 strcpy(buf, the(xname(obj)));
2288 You("cannot fit %s into %s.", buf,
2289 the(xname(current_container)));
2290 return 0;
2293 if (invobj) freeinv(obj);
2295 if (obj_is_burning(obj)) /* this used to be part of freeinv() */
2296 (void) snuff_lit(obj);
2298 if (floor_container && costly_spot(u.ux, u.uy)) {
2299 if (current_container->no_charge && !obj->unpaid) {
2300 /* don't sell when putting the item into your own container */
2301 obj->no_charge = 1;
2302 } else if (obj->oclass != COIN_CLASS) {
2303 /* sellobj() will take an unpaid item off the shop bill
2304 * note: coins are handled later */
2305 was_unpaid = obj->unpaid ? TRUE : FALSE;
2306 sellobj_state(SELL_DELIBERATE);
2307 sellobj(obj, u.ux, u.uy);
2308 sellobj_state(SELL_NORMAL);
2311 if (Icebox && !age_is_relative(obj) && !is_lightsaber(obj)) {
2312 obj->icedobject = TRUE;
2313 obj->age = monstermoves - obj->age; /* actual age */
2314 /* stop any corpse timeouts when frozen */
2315 if (obj->otyp == CORPSE && obj->timed) {
2316 long rot_alarm = stop_timer(ROT_CORPSE, (void *)obj);
2317 (void) stop_timer(MOLDY_CORPSE, (void *)obj);
2318 (void) stop_timer(REVIVE_MON, (void *)obj);
2319 /* mark a non-reviving corpse as such */
2320 if (rot_alarm) obj->norevive = 1;
2324 /* There are ice boxes of holding --Amy */
2325 if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
2326 /* explicitly mention what item is triggering the explosion */
2327 pline(
2328 "As you put %s inside, you are blasted by a magical explosion!",
2329 doname(obj));
2330 if (PlayerHearsSoundEffects) pline(issoviet ? "VD GA GA GA vy takoy nemnogo nub, kto ne znayet, kak igrat' na vsekh! Ya ne byl by nastol'ko glup, no vy poteryali sumku provedeniya v nastoyashcheye vremya i, veroyatno, slomal vse zel'ya, kotoryye byli v nem. TY POLNYY OTSTOY!" : "Caeauwaesh! Well and?");
2331 if (Has_contents(obj)) {
2332 struct obj *otmp;
2333 while((otmp = container_extract_indestructable(obj)))
2334 if (!flooreffects(otmp, u.ux, u.uy, "fall"))
2335 place_object(otmp, u.ux, u.uy);
2338 /* did not actually insert obj yet */
2339 if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE);
2341 /* if (Has_contents(obj))
2342 delete_contents(obj);
2343 obfree(obj, (struct obj *)0);
2344 delete_contents(current_container);
2345 if (!floor_container)
2346 useup(current_container);
2347 else if (obj_here(current_container, u.ux, u.uy))
2348 useupf(current_container, current_container->quan);
2349 else
2350 panic("in_container: bag not found."); */
2352 /* dump it out onto the floor so the scatterage can take effect */
2353 if (dump_container(current_container, TRUE, u.ux, u.uy)) {
2354 pline("The contents fly everywhere!");
2356 scatter(u.ux,u.uy,10,VIS_EFFECTS|MAY_HIT|MAY_DESTROY|MAY_FRACTURE,0);
2358 losehp(d(6,6),"magical explosion", KILLED_BY_AN);
2359 current_container = 0; /* baggone = TRUE; */
2362 if (current_container) {
2363 strcpy(buf, the(xname(current_container)));
2364 if (invobj) You("put %s into %s.", doname(obj), buf);
2366 /* gold in container always needs to be added to credit */
2367 if (floor_container && obj->oclass == COIN_CLASS)
2368 sellobj(obj, current_container->ox, current_container->oy);
2369 (void) add_to_container(current_container, obj, TRUE);
2370 current_container->owt = weight(current_container);
2372 /* gold needs this, and freeinv() many lines above may cause
2373 * the encumbrance to disappear from the status, so just always
2374 * update status immediately.
2376 bot();
2378 return(current_container ? 1 : -1);
2381 STATIC_PTR int
2382 in_container(obj)
2383 register struct obj *obj;
2385 return in_container_(obj,TRUE);
2389 STATIC_PTR int
2390 ck_bag(obj)
2391 struct obj *obj;
2393 return current_container && obj != current_container;
2397 /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
2398 STATIC_PTR int
2399 out_container(obj)
2400 register struct obj *obj;
2402 register struct obj *otmp;
2403 boolean is_gold = (obj->oclass == COIN_CLASS);
2404 int res, loadlev;
2405 long count;
2407 if (!current_container) {
2408 impossible("<out> no current_container?");
2409 return -1;
2410 } else if (is_gold) {
2411 obj->owt = weight(obj);
2414 if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0;
2416 if (obj->otyp == CORPSE) {
2417 if ( (touch_petrifies(&mons[obj->corpsenm])) && (!uarmg || FingerlessGloves)
2418 && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2419 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2420 display_nhwindow(WIN_MESSAGE, FALSE);
2421 else {
2422 static char kbuf[BUFSZ];
2424 pline("Touching this type of corpse is a fatal mistake.");
2425 strcpy(kbuf, "touching a petrifying corpse");
2426 instapetrify(kbuf);
2427 return -1;
2432 if (obj->otyp == PETRIFYIUM_BAR) {
2433 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2434 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2435 display_nhwindow(WIN_MESSAGE, FALSE);
2436 else {
2437 static char kbuf[BUFSZ];
2439 strcpy(kbuf, "touching a petrifyium bar");
2440 pline("Touching a petrifyium bar is a fatal mistake.");
2441 instapetrify(kbuf);
2442 return -1;
2447 if (obj->otyp == PETRIFYIUM_BRA) {
2448 if ( (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2449 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2450 display_nhwindow(WIN_MESSAGE, FALSE);
2451 else {
2452 static char kbuf[BUFSZ];
2454 strcpy(kbuf, "touching a petrifyium bra");
2455 pline("Touching a petrifyium bra is a fatal mistake.");
2456 instapetrify(kbuf);
2457 return -1;
2462 if (obj->otyp == EGG) {
2463 if ( (touch_petrifies(&mons[obj->corpsenm])) && obj->corpsenm != PM_PLAYERMON && (!uarmg || FingerlessGloves)
2464 && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
2465 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2466 display_nhwindow(WIN_MESSAGE, FALSE);
2467 else {
2468 static char kbuf[BUFSZ];
2470 pline("Touching a petrifying egg is a fatal mistake.");
2471 strcpy(kbuf, "touching a petrifying egg");
2472 instapetrify(kbuf);
2473 return -1;
2478 count = obj->quan;
2479 if ((res = lift_object(obj, current_container, &count, FALSE, FALSE)) <= 0)
2480 return res;
2482 if (obj->quan != count && obj->otyp != LOADSTONE && obj->otyp != LUCKSTONE && obj->otyp != HEALTHSTONE && obj->otyp != MANASTONE && obj->otyp != SLEEPSTONE && obj->otyp != LOADBOULDER && obj->otyp != STARLIGHTSTONE && obj->otyp != STONE_OF_MAGIC_RESISTANCE && !is_nastygraystone(obj) && !is_feminismstone(obj) )
2483 obj = splitobj(obj, count);
2485 /* Remove the object from the list. */
2486 obj_extract_self(obj);
2487 current_container->owt = weight(current_container);
2489 if (Icebox && !age_is_relative(obj) && !is_lightsaber(obj)) {
2490 obj->icedobject = TRUE;
2491 obj->age = monstermoves - obj->age; /* actual age */
2492 if (obj->otyp == CORPSE)
2493 start_corpse_timeout(obj);
2495 /* simulated point of time */
2497 if(!obj->unpaid && !carried(current_container) &&
2498 costly_spot(current_container->ox, current_container->oy)) {
2499 obj->ox = current_container->ox;
2500 obj->oy = current_container->oy;
2501 addtobill(obj, FALSE, FALSE, FALSE);
2503 if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops))
2504 verbalize("You sneaky cad! Get out of here with that pick!");
2506 otmp = addinv(obj);
2507 loadlev = near_capacity();
2508 prinv(loadlev ?
2509 (loadlev < MOD_ENCUMBER ?
2510 "You have a little trouble removing" :
2511 "You have much trouble removing") : (char *)0,
2512 otmp, count);
2514 if (is_gold) {
2515 #ifndef GOLDOBJ
2516 dealloc_obj(obj);
2517 #endif
2518 bot(); /* update character's gold piece count immediately */
2520 return 1;
2523 /* an object inside a cursed bag of holding is being destroyed */
2524 long
2525 mbag_item_gone(held, item, yourfault)
2526 int held;
2527 struct obj *item;
2528 boolean yourfault;
2530 struct monst *shkp;
2531 long loss = 0L;
2533 /* In the Evil Variant, you aren't told which items have been destroyed. --Amy */
2534 if (yourfault) {
2535 if (evilfriday)
2536 Norep("Stuff has vanished!");
2537 else if (item->dknown)
2538 pline("%s %s vanished!", Doname2(item), otense(item, "have"));
2539 else
2540 You("%s %s disappear!", Blind ? "notice" : "see", doname(item));
2542 if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) {
2543 if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy))
2544 loss = stolen_value(item, u.ux, u.uy,
2545 (boolean)shkp->mpeaceful, TRUE, TRUE);
2549 /* [ALI] In Slash'EM we must delete the contents of containers before
2550 * we call obj_extract_self() so that any indestructable items can
2551 * migrate into the bag of holding. We are also constrained by the
2552 * need to wait until after we have calculated any loss.
2554 if (Has_contents(item)) delete_contents(item);
2555 obj_extract_self(item);
2556 obfree(item, (struct obj *) 0);
2557 return loss;
2560 STATIC_OVL void
2561 observe_quantum_cat(box)
2562 struct obj *box;
2564 static NEARDATA const char sc[] = "Schroedinger's Cat";
2565 struct obj *deadcat;
2566 struct monst *livecat;
2567 xchar ox, oy;
2569 box->spe = 0; /* box->owt will be updated below */
2570 if (get_obj_location(box, &ox, &oy, 0))
2571 box->ox = ox, box->oy = oy; /* in case it's being carried */
2573 /* this isn't really right, since any form of observation
2574 (telepathic or monster/object/food detection) ought to
2575 force the determination of alive vs dead state; but basing
2576 it just on opening the box is much simpler to cope with */
2577 livecat = rn2(2) ? makemon(&mons[PM_HOUSECAT],
2578 box->ox, box->oy, NO_MINVENT) : 0;
2579 if (livecat) {
2580 livecat->mpeaceful = 1;
2581 set_malign(livecat);
2582 if (!canspotmon(livecat))
2583 You("think %s brushed your %s.", something, body_part(FOOT));
2584 else
2585 pline("%s inside the box is still alive!", Monnam(livecat));
2586 (void) christen_monst(livecat, sc);
2587 } else {
2588 deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
2589 box->ox, box->oy, sc);
2590 if (deadcat) {
2591 obj_extract_self(deadcat);
2592 (void) add_to_container(box, deadcat, TRUE);
2594 pline_The("%s inside the box is dead!",
2595 Hallucination ? rndmonnam() : "housecat");
2597 box->owt = weight(box);
2598 return;
2601 #undef Icebox
2603 void
2604 containerkaboom()
2606 switch(rn2(26)) {
2607 case 25:
2608 case 24:
2609 case 23:
2610 case 22:
2611 case 21:
2612 pline("You're hit by a massive explosion!");
2613 wake_nearby();
2614 losehp( (d(6,6) + rnd((monster_difficulty()) + 1) ), "massive explosion", KILLED_BY_AN);
2615 exercise(A_STR, FALSE);
2616 break;
2617 case 20:
2618 case 19:
2619 case 18:
2620 case 17:
2621 pline("A cloud of noxious gas billows out at you.");
2622 poisoned("gas cloud", A_STR, "cloud of poison gas",15);
2623 exercise(A_CON, FALSE);
2624 break;
2625 case 16:
2626 case 15:
2627 case 14:
2628 case 13:
2629 You_feel("a needle prick your %s.",body_part(ARM));
2630 poisoned("needle", A_CON, "poisoned needle",10);
2631 exercise(A_CON, FALSE);
2632 break;
2633 case 12:
2634 case 11:
2635 case 10:
2636 case 9:
2637 dofiretrap((struct obj *)0);
2638 break;
2639 case 8:
2640 case 7:
2641 case 6: {
2642 int dmg;
2644 You("are jolted by a surge of electricity!");
2645 if((Shock_resistance && (StrongShock_resistance || rn2(10))) || ShockImmunity) {
2646 shieldeff(u.ux, u.uy);
2647 You("don't seem to be affected.");
2648 break;
2649 } else
2650 losehp(d(4, 4) + rnd((monster_difficulty() / 2) + 1), "electric shock", KILLED_BY_AN);
2651 if (isevilvariant || !rn2(issoviet ? 6 : 33)) /* new calculations --Amy */ destroy_item(RING_CLASS, AD_ELEC);
2652 if (isevilvariant || !rn2(issoviet ? 6 : 33)) /* new calculations --Amy */ destroy_item(WAND_CLASS, AD_ELEC);
2653 if (isevilvariant || !rn2(issoviet ? 30 : 165)) /* new calculations --Amy */ destroy_item(AMULET_CLASS, AD_ELEC);
2654 break;
2656 case 5:
2657 case 4:
2658 case 3:
2659 if (!Free_action || !rn2(StrongFree_action ? 100 : 20)) {
2660 pline("Suddenly you are frozen in place!");
2661 if (PlayerHearsSoundEffects) pline(issoviet ? "Teper' vy ne mozhete dvigat'sya. Nadeyus', chto-to ubivayet vas, prezhde chem vash paralich zakonchitsya." : "Klltsch-tsch-tsch-tsch-tsch!");
2662 if (isstunfish) nomul(-rnz(11), "frozen by a container kaboom", TRUE);
2663 else nomul(-rn1(5, 6), "frozen by a container kaboom", TRUE);
2664 exercise(A_DEX, FALSE);
2665 nomovemsg = You_can_move_again;
2666 } else You("momentarily stiffen.");
2667 break;
2668 case 2:
2669 case 1:
2670 case 0:
2671 pline("A cloud of %s gas billows out at you.", Blind ? "booming" : rndcolor() );
2672 if(!Stunned) {
2673 if (Blind)
2674 You("%s and get dizzy...",
2675 stagger(youmonst.data, "stagger"));
2676 else
2677 You("%s and your vision blurs...",
2678 stagger(youmonst.data, "stagger"));
2679 if (PlayerHearsSoundEffects) pline(issoviet ? "Imet' delo s effektami statusa ili sdat'sya!" : "Wrueue-ue-e-ue-e-ue-e...");
2681 make_stunned(HStun + rn1(7, 16) + rnd((monster_difficulty() / 2) + 1),FALSE);
2682 (void) make_hallucinated(HHallucination + rn1(5, 16) + rnd((monster_difficulty() / 2) + 1),FALSE,0L);
2683 break;
2684 default: impossible("bad kaboom trap");
2685 break;
2689 /* used by askchain() to check for magic bag explosion */
2690 boolean
2691 container_gone(fn)
2692 int (*fn)(OBJ_P);
2694 /* result is only meaningful while use_container() is executing */
2695 return ((fn == in_container || fn == out_container) && !current_container);
2699 use_container(objp, held)
2700 struct obj **objp;
2701 int held;
2703 struct obj *curr, *otmp, *obj = *objp;
2704 #ifndef GOLDOBJ
2705 struct obj *u_gold = (struct obj *)0;
2706 #endif
2707 struct monst *shkp;
2708 boolean one_by_one, allflag, quantum_cat = FALSE,
2709 loot_out = FALSE, loot_in = FALSE, loot_reverse = FALSE;
2710 char select[MAXOCLASSES+1];
2711 char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ];
2712 long loss = 0L;
2713 int cnt = 0, used = 0, lcnt = 0,
2714 menu_on_request;
2715 int monsterator = 0;
2717 if (obj && obj->oartifact == ART_SNAP_TOO && !rn2(100)) {
2718 obj->olocked = TRUE;
2719 obj->obroken = FALSE;
2721 if (obj && obj->oartifact == ART_CANNOTRAP) obj->otrapped = FALSE;
2723 emptymsg[0] = '\0';
2724 if (nohands(youmonst.data) && !Race_if(PM_TRANSFORMER) && !(obj && obj->otyp == HANDYBAG) ) {
2725 You("have no hands!"); /* not `body_part(HAND)' */
2726 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
2728 if (yn("Try to open the container with another part of your body instead?") == 'y') {
2729 if (rn2(3) && !polyskillchance()) {
2730 You_feel("a wrenching sensation.");
2731 if (!rn2(20)) badeffect();
2732 if (PlayerHearsSoundEffects) pline(issoviet ? "Tam net nikakoy zashchity. Tam net nikakoy nadezhdy. Yedinstvennoye, chto yest'? Uverennost' v tom, chto vy, igrok, budet umeret' uzhasnoy i muchitel'noy smert'yu." : "SCHRING!");
2733 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
2734 flags.soundok = 0;
2735 if (isstunfish) nomul(-rnz(10), "wrenched in a container", TRUE);
2736 else nomul(-rnd(10), "wrenched in a container", TRUE);
2737 nomovemsg = "You are conscious again.";
2738 afternmv = Hear_again;
2739 return 1;
2742 else {return(0);}
2744 } else if (!freehandX() && !(obj->oartifact == ART_MINNIE_S_HANDBAG) && !(Role_if(PM_CELLAR_CHILD) && uwep && (weapon_type(uwep) == P_QUARTERSTAFF)) ) {
2745 You("have no free %s.", body_part(HAND));
2746 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
2747 return 0;
2749 if (obj->olocked) {
2751 if (uwep && uwep->oartifact == ART_FINAL_DOOR_SOLUTION) {
2752 obj->olocked = FALSE;
2753 pline("kloeck!");
2754 } else {
2755 pline("%s to be locked.", Tobjnam(obj, "seem"));
2756 if (held) You("must put it down to unlock.");
2757 return 0;
2760 if (obj->otrapped) {
2761 if (held) You("open %s...", the(xname(obj)));
2762 if (Role_if(PM_CYBERNINJA) && rn2(5)) {
2763 You("discover a trap on %s and disarm it.", the(xname(obj)));
2764 obj->otrapped = FALSE;
2765 return 1;
2767 (void) chest_trap(obj, HAND, FALSE);
2768 /* even if the trap fails, you've used up this turn */
2769 if (multi >= 0) { /* in case we didn't become paralyzed */
2770 nomul(-1, "opening a trapped container", TRUE);
2771 nomovemsg = "";
2773 return 1;
2776 current_container = obj; /* for use by in/out_container */
2777 /* from here on out, all early returns go through containerdone */
2779 if (obj->oartifact == ART_ELECTRONIC_LOCK) {
2780 if (ContainerKaboom < 10000) ContainerKaboom = 10000;
2783 if (obj->oartifact == ART_DEMONSEAL) {
2784 if (obj->invoketimer <= monstermoves) {
2785 int pm;
2787 pm = rn2(2) ? dprince(rn2((int)A_LAWFUL+2) - 1) : dlord(rn2((int)A_LAWFUL+2) - 1);
2788 if (pm >= PM_ORCUS && pm <= PM_DEMOGORGON) u.conclusiocount++;
2789 if (pm && (pm != NON_PM)) {
2790 (void) makemon(&mons[pm], u.ux, u.uy, MM_ADJACENTOK|MM_ANGRY|MM_FRENZIED);
2791 You("triggered an ancient trap on this container...");
2794 int artitimeout = rnz(2000);
2795 if (!rn2(5)) artitimeout = rnz(20000); /* squeaking does not help here, as it's not an actual invoke --Amy */
2796 obj->invoketimer = (monstermoves + artitimeout);
2800 if (obj->spe == 1) {
2801 observe_quantum_cat(obj);
2802 used = 1;
2803 quantum_cat = TRUE; /* for adjusting "it's empty" message */
2805 /* [ALI] If a container vanishes which contains indestructible
2806 * objects then these will be added to the magic bag. This makes
2807 * it very hard to combine the count and vanish loops so we do
2808 * them seperately.
2810 /* Sometimes toss objects if a cursed magic bag or a bag of digestion */
2811 if (Is_mbag(obj) && obj->cursed) {
2812 for (curr = obj->cobj; curr; curr = otmp) {
2813 otmp = curr->nobj;
2814 if (!rn2(13) && !evades_destruction(curr) && !stack_too_big(curr)) {
2815 if (obj && obj->oartifact == ART_RECYCLER_BIN) {
2816 adjalign(1);
2817 if (curr->oartifact) {
2818 adjalign(50);
2819 u.alignlim += 5;
2820 pline("Wow, that must have been expensive!");
2823 if (obj && obj->oartifact == ART_MONSTERATOR) {
2824 monsterator++;
2826 loss += mbag_item_gone(held, curr, TRUE);
2827 used = 1;
2831 if ( (obj->otyp == BAG_OF_DIGESTION || obj->otyp == ICE_BOX_OF_DIGESTION || obj->otyp == LARGE_BOX_OF_DIGESTION) && !rn2(obj->blessed ? 20 : (obj->cursed ? 2 : 10))) {
2832 for (curr = obj->cobj; curr; curr = otmp) {
2833 otmp = curr->nobj;
2834 if (!evades_destruction(curr) && !stack_too_big(curr)) {
2835 if (obj && obj->oartifact == ART_RECYCLER_BIN) {
2836 adjalign(1);
2837 if (curr->oartifact) {
2838 adjalign(50);
2839 u.alignlim += 5;
2840 pline("Wow, that must have been expensive!");
2843 if (obj && obj->oartifact == ART_MONSTERATOR) {
2844 monsterator++;
2846 loss += mbag_item_gone(held, curr, TRUE);
2847 used = 1;
2851 /* Count the number of contained objects. */
2852 for (curr = obj->cobj; curr; curr = curr->nobj)
2853 cnt++;
2855 if (loss) /* magic bag lost some shop goods */
2856 You("owe %ld %s for lost merchandise.", loss, currency(loss));
2857 obj->owt = weight(obj); /* in case any items were lost */
2859 if (monsterator > 10) {
2861 if (Aggravate_monster) {
2862 u.aggravation = 1;
2863 reset_rndmonst(NON_PM);
2866 if (monsterator > 200) monsterator = 200;
2868 u.lamefarmer = TRUE;
2870 while (monsterator > 0) {
2872 (void) makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS);
2873 u.ublesscnt += 50;
2874 monsterator--;
2875 if (monsterator < 0) monsterator = 0; /* fail safe */
2878 u.aggravation = 0;
2879 u.lamefarmer = FALSE;
2883 if (ContainerKaboom || u.uprops[CONTAINER_KABOOM].extrinsic || have_containerkaboomstone()) {
2884 containerkaboom();
2887 if (!cnt)
2888 sprintf(emptymsg, "%s is %sempty.", Yname2(obj),
2889 quantum_cat ? "now " : "");
2890 if (current_container->otyp == MEDICAL_KIT) {
2891 if (!cnt)
2892 pline("%s", emptymsg);
2893 else
2894 (void) display_cinventory(current_container);
2895 return 0;
2897 if (cnt || (flags.menu_style == MENU_FULL && !InventoryDoesNotGo)) {
2898 strcpy(qbuf, "Do you want to take something out of ");
2899 sprintf(eos(qbuf), "%s?",
2900 safe_qbuf(qbuf, 1, yname(obj), ysimple_name(obj), "it"));
2901 if (flags.menu_style != MENU_TRADITIONAL && !InventoryDoesNotGo) {
2902 if (flags.menu_style == MENU_FULL) {
2903 int t;
2904 char menuprompt[BUFSZ];
2905 boolean outokay = (cnt != 0),
2906 inokay = (invent != 0);
2908 #ifndef GOLDOBJ
2909 if (u.ugold) inokay = TRUE;
2910 #endif
2911 if (!outokay && !inokay) {
2912 pline("%s", emptymsg);
2913 You("don't have anything to put in.");
2914 goto containerdone;
2916 menuprompt[0] = '\0';
2917 if (!cnt) sprintf(menuprompt, "%s ", emptymsg);
2918 strcat(menuprompt, "Do what?");
2919 t = in_or_out_menu(menuprompt, current_container,
2920 outokay, inokay);
2921 if (t <= 0) {
2922 used = 0;
2923 goto containerdone;
2925 loot_out = (t & 0x01) != 0;
2926 loot_in = (t & 0x02) != 0;
2927 loot_reverse = 0;
2928 if (t & 0x04) {
2929 loot_out = loot_in = loot_reverse = 1;
2931 } else { /* MENU_COMBINATION or MENU_PARTIAL */
2932 loot_out = (yn_function(qbuf, "ynq", 'n') == 'y');
2934 if (loot_out && !loot_reverse) {
2935 add_valid_menu_class(0); /* reset */
2936 used |= menu_loot(0, current_container, FALSE) > 0;
2938 } else {
2939 /* traditional code */
2940 ask_again2:
2941 menu_on_request = 0;
2942 add_valid_menu_class(0); /* reset */
2943 strcpy(pbuf, ":ynq");
2944 if (cnt) strcat(pbuf, "m");
2945 switch (yn_function(qbuf, pbuf, 'n')) {
2946 case ':':
2947 if (InventoryDoesNotGo) {
2948 pline("Not enough memory to create inventory window");
2949 goto ask_again2;
2951 container_contents(current_container, FALSE, FALSE);
2952 goto ask_again2;
2953 case 'y':
2954 if (query_classes(select, &one_by_one, &allflag,
2955 "take out", current_container->cobj,
2956 FALSE,
2957 #ifndef GOLDOBJ
2958 FALSE,
2959 #endif
2960 &menu_on_request)) {
2961 if (askchain((struct obj **)&current_container->cobj,
2962 (one_by_one ? (char *)0 : select),
2963 allflag, out_container,
2964 (int (*)(OBJ_P))0,
2965 0, "nodot")) {
2966 if (current_container->oartifact != ART_GITTA_S_HANDBAG && !(uarmc && uarmc->otyp == UTILITY_CLOAK && rn2(2)) && current_container->oartifact != ART_GIDDEM_FAST_) {
2967 used = 1;
2970 } else if (menu_on_request < 0) {
2971 used |= menu_loot(menu_on_request,
2972 current_container, FALSE) > 0;
2974 /*FALLTHRU*/
2975 case 'n':
2976 break;
2977 case 'm':
2978 menu_on_request = -2; /* triggers ALL_CLASSES */
2979 used |= menu_loot(menu_on_request, current_container, FALSE) > 0;
2980 break;
2981 case 'q':
2982 default:
2983 goto containerdone;
2986 } else {
2987 pline("%s", emptymsg); /* <whatever> is empty. */
2990 #ifndef GOLDOBJ
2991 if (!invent && u.ugold == 0) {
2992 #else
2993 if (!invent) {
2994 #endif
2995 /* nothing to put in, but some feedback is necessary */
2996 You("don't have anything to put in.");
2997 goto containerdone;
2999 if (flags.menu_style != MENU_FULL || InventoryDoesNotGo) {
3000 sprintf(qbuf, "Do you wish to put %s in?", something);
3001 strcpy(pbuf, ynqchars);
3002 if ((flags.menu_style == MENU_TRADITIONAL || InventoryDoesNotGo) && invent && inv_cnt() > 0)
3003 strcat(pbuf, "m");
3004 switch (yn_function(qbuf, pbuf, 'n')) {
3005 case 'y':
3006 loot_in = TRUE;
3007 break;
3008 case 'n':
3009 break;
3010 case 'm':
3011 add_valid_menu_class(0); /* reset */
3012 menu_on_request = -2; /* triggers ALL_CLASSES */
3013 used |= menu_loot(menu_on_request, current_container, TRUE) > 0;
3014 break;
3015 case 'q':
3016 default:
3017 goto containerdone;
3021 * Gone: being nice about only selecting food if we know we are
3022 * putting things in an ice chest.
3024 if (loot_in) {
3025 #ifndef GOLDOBJ
3026 if (u.ugold) {
3028 * Hack: gold is not in the inventory, so make a gold object
3029 * and put it at the head of the inventory list.
3031 u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */
3032 u_gold->in_use = TRUE;
3033 u.ugold = u_gold->quan; /* put the gold back */
3034 assigninvlet(u_gold); /* might end up as NOINVSYM */
3035 u_gold->nobj = invent;
3036 invent = u_gold;
3038 #endif
3039 add_valid_menu_class(0); /* reset */
3040 if (flags.menu_style != MENU_TRADITIONAL && !InventoryDoesNotGo) {
3041 used |= menu_loot(0, current_container, TRUE) > 0;
3042 } else {
3043 /* traditional code */
3044 menu_on_request = 0;
3045 if (query_classes(select, &one_by_one, &allflag, "put in",
3046 invent, FALSE,
3047 #ifndef GOLDOBJ
3048 (u.ugold != 0L),
3049 #endif
3050 &menu_on_request)) {
3051 (void) askchain((struct obj **)&invent,
3052 (one_by_one ? (char *)0 : select), allflag,
3053 in_container, ck_bag, 0, "nodot");
3054 if (current_container->oartifact != ART_KLARABELLA_S_HANDBAG && !(uarmc && uarmc->otyp == UTILITY_CLOAK && rn2(2)) && current_container->oartifact != ART_STASHIT) {
3055 used = 1;
3057 } else if (menu_on_request < 0) {
3058 used |= menu_loot(menu_on_request,
3059 current_container, TRUE) > 0;
3064 #ifndef GOLDOBJ
3065 if (u_gold && invent && invent->oclass == COIN_CLASS) {
3066 /* didn't stash [all of] it */
3067 u_gold = invent;
3068 invent = u_gold->nobj;
3069 u_gold->in_use = FALSE;
3070 dealloc_obj(u_gold);
3072 #endif
3074 if (loot_out && loot_reverse) {
3075 add_valid_menu_class(0); /* reset */
3076 used |= menu_loot(0, current_container, FALSE) > 0;
3079 #ifndef GOLDOBJ
3080 if (u_gold && invent && invent->oclass == COIN_CLASS) {
3081 /* didn't stash [all of] it */
3082 u_gold = invent;
3083 invent = u_gold->nobj;
3084 u_gold->in_use = FALSE;
3085 dealloc_obj(u_gold);
3087 #endif
3089 containerdone:
3090 *objp = current_container; /* might have become null */
3091 current_container = 0; /* avoid hanging on to stale pointer */
3092 return used;
3095 /* Loot a container (take things out, put things in), using a menu. */
3096 STATIC_OVL int
3097 menu_loot(retry, container, put_in)
3098 int retry;
3099 struct obj *container;
3100 boolean put_in;
3102 int n, i, n_looted = 0;
3103 boolean all_categories = TRUE, loot_everything = FALSE;
3104 char buf[BUFSZ];
3105 const char *takeout = "Take out", *putin = "Put in";
3106 struct obj *otmp, *otmp2;
3107 menu_item *pick_list;
3108 int mflags, res;
3109 long count;
3111 if (retry) {
3112 all_categories = (retry == -2);
3113 } else if (flags.menu_style == MENU_FULL && !InventoryDoesNotGo) {
3114 all_categories = FALSE;
3115 sprintf(buf,"%s what type of objects?", put_in ? putin : takeout);
3116 mflags = put_in ? ALL_TYPES | NOTFULLYIDED | BUC_ALLBKNOWN | BUC_UNKNOWN :
3117 ALL_TYPES | NOTFULLYIDED | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
3118 n = query_category(buf, put_in ? invent : container->cobj,
3119 mflags, &pick_list, PICK_ANY);
3120 if (!n) return 0;
3121 for (i = 0; i < n; i++) {
3122 if (pick_list[i].item.a_int == 'A') {
3123 if (yn("You decided to autoselect everything, please confirm with y if that's what you really wanted") == 'y') loot_everything = TRUE;
3124 } else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
3125 all_categories = TRUE;
3126 else
3127 add_valid_menu_class(pick_list[i].item.a_int);
3129 free((void *) pick_list);
3132 if (loot_everything) {
3133 for (otmp = container->cobj; otmp; otmp = otmp2) {
3134 otmp2 = otmp->nobj;
3135 res = out_container(otmp);
3136 if (res < 0) break;
3138 } else {
3139 mflags = INVORDER_SORT;
3140 if (put_in && flags.invlet_constant) mflags |= USE_INVLET;
3141 sprintf(buf,"%s what?", put_in ? putin : takeout);
3142 n = query_objlist(buf, put_in ? invent : container->cobj,
3143 mflags, &pick_list, PICK_ANY,
3144 all_categories ? allow_all : allow_category);
3145 if (n) {
3146 n_looted = n;
3147 for (i = 0; i < n; i++) {
3148 otmp = pick_list[i].item.a_obj;
3149 count = pick_list[i].count;
3150 if (count > 0 && count < otmp->quan) {
3151 otmp = splitobj(otmp, count);
3152 /* special split case also handled by askchain() */
3154 res = put_in ? in_container(otmp) : out_container(otmp);
3155 if (res < 0) {
3156 if (!current_container) {
3157 /* otmp caused current_container to explode;
3158 both are now gone */
3159 otmp = 0; /* and break loop */
3160 } else if (otmp && otmp != pick_list[i].item.a_obj) {
3161 /* split occurred, merge again */
3162 (void) merged(&pick_list[i].item.a_obj, &otmp);
3164 break;
3167 free((void *)pick_list);
3171 if (uarmc && uarmc->otyp == UTILITY_CLOAK && rn2(2)) return 0;
3173 if (container && container->oartifact == ART_GITTA_S_HANDBAG && !put_in) return 0;
3174 if (container && container->oartifact == ART_GIDDEM_FAST_ && !put_in) return 0;
3175 if (container && container->oartifact == ART_KLARABELLA_S_HANDBAG && put_in) return 0;
3176 if (container && container->oartifact == ART_STASHIT && put_in) return 0;
3177 return n_looted;
3180 STATIC_OVL int
3181 in_or_out_menu(prompt, obj, outokay, inokay)
3182 const char *prompt;
3183 struct obj *obj;
3184 boolean outokay, inokay;
3186 winid win;
3187 anything any;
3188 menu_item *pick_list;
3189 char buf[BUFSZ];
3190 int n;
3191 const char *menuselector = iflags.lootabc ? "abcd" : "oibr";
3193 any.a_void = 0;
3194 win = create_nhwindow(NHW_MENU);
3195 start_menu(win);
3196 if (outokay) {
3197 any.a_int = 1;
3198 sprintf(buf,"Take %s out of %s", something, the(xname(obj)));
3199 add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
3200 buf, MENU_UNSELECTED);
3202 menuselector++;
3203 if (inokay) {
3204 any.a_int = 2;
3205 sprintf(buf,"Put %s into %s", something, the(xname(obj)));
3206 add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED);
3208 menuselector++;
3209 if (outokay && inokay) {
3210 any.a_int = 3;
3211 add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
3212 "Both of the above, out first", MENU_UNSELECTED);
3214 menuselector++;
3215 if (outokay && inokay) {
3216 any.a_int = 4;
3217 add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
3218 "Both of the above, in first", MENU_UNSELECTED);
3220 end_menu(win, prompt);
3221 n = select_menu(win, PICK_ONE, &pick_list);
3222 destroy_nhwindow(win);
3223 if (n > 0) {
3224 n = pick_list[0].item.a_int;
3225 free((void *) pick_list);
3227 return n;
3230 /* Dumps out a container, possibly as the prelude/result of an explosion.
3231 * destroy_after trashes the container afterwards; try not to use it :P
3233 * Player is assumed to not be handling the contents directly.
3235 * Returns 1 if at least one object was present, 0 if empty.
3238 dump_container(container, destroy_after, coordx, coordy)
3239 struct obj* container;
3240 BOOLEAN_P destroy_after;
3241 int coordx, coordy;
3243 if (!isok(coordx, coordy)) {
3244 impossible("dump_container coordinates %d, %d?", coordx, coordy);
3245 coordx = u.ux;
3246 coordy = u.uy; /* fail safe */
3249 struct obj* otmp,*otmp2;
3250 int ret = 0;
3252 /* sanity check */
3253 if (!container) { return 0; }
3255 for (otmp = container->cobj; otmp; otmp = otmp2)
3257 ret = 1;
3258 otmp2 = otmp->nobj;
3259 obj_extract_self(otmp);
3260 container->owt = weight(container);
3262 /* we do need to start the timer on these */
3263 if ( (container->otyp == ICE_BOX || container->otyp == DISPERSION_BOX || container->otyp == ICE_BOX_OF_HOLDING || container->otyp == ICE_BOX_OF_WATERPROOFING || container->otyp == ICE_BOX_OF_DIGESTION) && !age_is_relative(otmp) && !is_lightsaber(otmp)) {
3264 otmp->age = monstermoves - otmp->age;
3265 otmp->icedobject = TRUE;
3266 if (otmp->otyp == CORPSE) {
3267 start_corpse_timeout(otmp);
3270 place_object(otmp,coordx,coordy);
3272 if (otmp->otyp == GOLD_PIECE) {
3273 #ifndef GOLDOBJ
3274 /*dealloc_obj(otmp);*/ /* causes panic, and besides, is it really needed??? --Amy */
3275 #endif
3276 bot(); /* update character's gold piece count immediately */
3280 if (destroy_after) {
3281 if (container->where == OBJ_INVENT) {
3282 useup(container);
3283 } else if (obj_here(container, u.ux, u.uy)) {
3284 useupf(container, container->quan);
3288 return ret;
3292 dump_container_tele(container, destroy_after, coordx, coordy)
3293 struct obj* container;
3294 BOOLEAN_P destroy_after;
3295 int coordx, coordy;
3297 if (!isok(coordx, coordy)) {
3298 impossible("dump_container coordinates %d, %d?", coordx, coordy);
3299 coordx = u.ux;
3300 coordy = u.uy; /* fail safe */
3303 struct obj* otmp,*otmp2;
3304 int ret = 0;
3306 /* sanity check */
3307 if (!container) { return 0; }
3309 for (otmp = container->cobj; otmp; otmp = otmp2)
3311 ret = 1;
3312 otmp2 = otmp->nobj;
3313 obj_extract_self(otmp);
3314 container->owt = weight(container);
3316 /* we do need to start the timer on these */
3317 if ( (container->otyp == ICE_BOX || container->otyp == DISPERSION_BOX || container->otyp == ICE_BOX_OF_HOLDING || container->otyp == ICE_BOX_OF_WATERPROOFING || container->otyp == ICE_BOX_OF_DIGESTION) && !age_is_relative(otmp) && !is_lightsaber(otmp)) {
3318 otmp->age = monstermoves - otmp->age;
3319 otmp->icedobject = TRUE;
3320 if (otmp->otyp == CORPSE) {
3321 start_corpse_timeout(otmp);
3324 place_object(otmp,coordx,coordy);
3325 rloco(otmp);
3327 if (otmp && otmp->otyp == GOLD_PIECE) {
3328 #ifndef GOLDOBJ
3329 /*dealloc_obj(otmp);*/ /* causes panic, and besides, is it really needed??? --Amy */
3330 #endif
3331 bot(); /* update character's gold piece count immediately */
3335 if (destroy_after) {
3336 if (container->where == OBJ_INVENT) {
3337 useup(container);
3338 } else if (obj_here(container, u.ux, u.uy)) {
3339 useupf(container, container->quan);
3343 return ret;
3347 dump_container_huro(container, destroy_after, coordx, coordy)
3348 struct obj* container;
3349 BOOLEAN_P destroy_after;
3350 int coordx, coordy;
3352 if (!isok(coordx, coordy)) {
3353 impossible("dump_container coordinates %d, %d?", coordx, coordy);
3354 coordx = u.ux;
3355 coordy = u.uy; /* fail safe */
3358 struct obj* otmp,*otmp2;
3359 register struct monst *offmon;
3360 int ret = 0;
3362 /* sanity check */
3363 if (!container) { return 0; }
3365 for (otmp = container->cobj; otmp; otmp = otmp2)
3367 ret = 1;
3368 otmp2 = otmp->nobj;
3369 obj_extract_self(otmp);
3370 container->owt = weight(container);
3372 /* we do need to start the timer on these */
3373 if ( (container->otyp == ICE_BOX || container->otyp == DISPERSION_BOX || container->otyp == ICE_BOX_OF_HOLDING || container->otyp == ICE_BOX_OF_WATERPROOFING || container->otyp == ICE_BOX_OF_DIGESTION) && !age_is_relative(otmp) && !is_lightsaber(otmp)) {
3374 otmp->age = monstermoves - otmp->age;
3375 otmp->icedobject = TRUE;
3376 if (otmp->otyp == CORPSE) {
3377 start_corpse_timeout(otmp);
3380 if ((offmon = makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS)) != 0) {
3381 (void) mpickobj(offmon,otmp,FALSE);
3382 mdrop_special_objs(offmon); /* don't levelport ones that have the amulet! */
3383 u_teleport_monB(offmon, FALSE);
3384 } else {
3385 place_object(otmp,coordx,coordy);
3388 if (otmp && otmp->otyp == GOLD_PIECE) {
3389 #ifndef GOLDOBJ
3390 /*dealloc_obj(otmp);*/ /* causes panic, and besides, is it really needed??? --Amy */
3391 #endif
3392 bot(); /* update character's gold piece count immediately */
3396 if (destroy_after) {
3397 if (container->where == OBJ_INVENT) {
3398 useup(container);
3399 } else if (obj_here(container, u.ux, u.uy)) {
3400 useupf(container, container->quan);
3404 return ret;
3408 dump_container_superhuro(container, destroy_after, coordx, coordy)
3409 struct obj* container;
3410 BOOLEAN_P destroy_after;
3411 int coordx, coordy;
3413 if (!isok(coordx, coordy)) {
3414 impossible("dump_container coordinates %d, %d?", coordx, coordy);
3415 coordx = u.ux;
3416 coordy = u.uy; /* fail safe */
3419 struct obj* otmp,*otmp2;
3420 register struct monst *offmon;
3421 int ret = 0;
3423 /* sanity check */
3424 if (!container) { return 0; }
3426 for (otmp = container->cobj; otmp; otmp = otmp2)
3428 ret = 1;
3429 otmp2 = otmp->nobj;
3430 obj_extract_self(otmp);
3431 container->owt = weight(container);
3433 /* we do need to start the timer on these */
3434 if ( (container->otyp == ICE_BOX || container->otyp == DISPERSION_BOX || container->otyp == ICE_BOX_OF_HOLDING || container->otyp == ICE_BOX_OF_WATERPROOFING || container->otyp == ICE_BOX_OF_DIGESTION) && !age_is_relative(otmp) && !is_lightsaber(otmp)) {
3435 otmp->age = monstermoves - otmp->age;
3436 otmp->icedobject = TRUE;
3437 if (otmp->otyp == CORPSE) {
3438 start_corpse_timeout(otmp);
3441 if ((offmon = makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS)) != 0) {
3442 (void) mpickobj(offmon,otmp,FALSE);
3443 mdrop_special_objs(offmon); /* don't levelport ones that have the amulet! */
3444 u_teleport_monC(offmon, FALSE);
3445 } else {
3446 place_object(otmp,coordx,coordy);
3449 if (otmp && otmp->otyp == GOLD_PIECE) {
3450 #ifndef GOLDOBJ
3451 /*dealloc_obj(otmp);*/ /* causes panic, and besides, is it really needed??? --Amy */
3452 #endif
3453 bot(); /* update character's gold piece count immediately */
3457 if (destroy_after) {
3458 if (container->where == OBJ_INVENT) {
3459 useup(container);
3460 } else if (obj_here(container, u.ux, u.uy)) {
3461 useupf(container, container->quan);
3465 return ret;
3468 /*pickup.c*/