1 /*	SCCS Id: @(#)pickup.c	3.3	2000/03/01	*/
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /*
6  *	Contains code for picking objects up, and container use.
7  */
8 
9 #include "hack.h"
10 
11 STATIC_DCL void FDECL(simple_look, (struct obj *,BOOLEAN_P));
12 STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *,
13 		const char *,struct obj *,BOOLEAN_P,BOOLEAN_P,int *));
14 STATIC_DCL void FDECL(check_here, (BOOLEAN_P));
15 STATIC_DCL boolean FDECL(n_or_more, (struct obj *));
16 STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *));
17 #if 0 /* not used */
18 STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
19 #endif
20 STATIC_DCL int FDECL(autopick, (struct obj*, int, menu_item **));
21 STATIC_DCL int FDECL(count_categories, (struct obj *,int));
22 STATIC_DCL long FDECL(carry_count,
23 		      (struct obj *,struct obj *,long,BOOLEAN_P,int *,int *));
24 STATIC_DCL int FDECL(lift_object, (struct obj *,struct obj *,long *,BOOLEAN_P));
25 STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *,int));
26 STATIC_PTR int FDECL(in_container,(struct obj *));
27 STATIC_PTR int FDECL(ck_bag,(struct obj *));
28 STATIC_PTR int FDECL(out_container,(struct obj *));
29 STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P));
30 STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *));
31 STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
32 STATIC_DCL boolean FDECL(able_to_loot, (int, int));
33 STATIC_DCL boolean FDECL(mon_beside, (int, int));
34 
35 /* define for query_objlist() and autopickup() */
36 #define FOLLOW(curr, flags) \
37     (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
38 
39 /*
40  *  How much the weight of the given container will change when the given
41  *  object is removed from it.  This calculation must match the one used
42  *  by weight() in mkobj.c.
43  */
44 #define DELTA_CWT(cont,obj)		\
45     ((cont)->cursed ? (obj)->owt * 2 :	\
46 		      1 + ((obj)->owt / ((cont)->blessed ? 4 : 2)))
47 #define GOLD_WT(n)		(((n) + 50L) / 100L)
48 /* if you can figure this out, give yourself a hearty pat on the back... */
49 #define GOLD_CAPACITY(w,n)	(((w) * -100L) - ((n) + 50L) - 1L)
50 
51 static const char moderateloadmsg[] = "You have a little trouble lifting";
52 static const char nearloadmsg[] = "You have much trouble lifting";
53 static const char overloadmsg[] = "You have extreme difficulty lifting";
54 
55 /* BUG: this lets you look at cockatrice corpses while blind without
56    touching them */
57 /* much simpler version of the look-here code; used by query_classes() */
58 STATIC_OVL void
simple_look(otmp,here)59 simple_look(otmp, here)
60 struct obj *otmp;	/* list of objects */
61 boolean here;		/* flag for type of obj list linkage */
62 {
63 	/* Neither of the first two cases is expected to happen, since
64 	 * we're only called after multiple classes of objects have been
65 	 * detected, hence multiple objects must be present.
66 	 */
67 	if (!otmp) {
68 	    impossible("simple_look(null)");
69 	} else if (!(here ? otmp->nexthere : otmp->nobj)) {
70 	    pline("%s", doname(otmp));
71 	} else {
72 	    winid tmpwin = create_nhwindow(NHW_MENU);
73 	    putstr(tmpwin, 0, "");
74 	    do {
75 		putstr(tmpwin, 0, doname(otmp));
76 		otmp = here ? otmp->nexthere : otmp->nobj;
77 	    } while (otmp);
78 	    display_nhwindow(tmpwin, TRUE);
79 	    destroy_nhwindow(tmpwin);
80 	}
81 }
82 
83 int
collect_obj_classes(ilets,otmp,here,incl_gold,filter)84 collect_obj_classes(ilets, otmp, here, incl_gold, filter)
85 char ilets[];
86 register struct obj *otmp;
87 boolean here, incl_gold;
88 boolean FDECL((*filter),(OBJ_P));
89 {
90 	register int iletct = 0;
91 	register char c;
92 
93 	if (incl_gold)
94 	    ilets[iletct++] = def_oc_syms[GOLD_CLASS];
95 	ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
96 	while (otmp) {
97 	    c = def_oc_syms[(int)otmp->oclass];
98 	    if (!index(ilets, c) && (!filter || (*filter)(otmp)))
99 		ilets[iletct++] = c,  ilets[iletct] = '\0';
100 	    otmp = here ? otmp->nexthere : otmp->nobj;
101 	}
102 
103 	return iletct;
104 }
105 
106 /*
107  * Suppose some '?' and '!' objects are present, but '/' objects aren't:
108  *	"a" picks all items without further prompting;
109  *	"A" steps through all items, asking one by one;
110  *	"?" steps through '?' items, asking, and ignores '!' ones;
111  *	"/" becomes 'A', since no '/' present;
112  *	"?a" or "a?" picks all '?' without further prompting;
113  *	"/a" or "a/" becomes 'A' since there aren't any '/'
114  *	    (bug fix:  3.1.0 thru 3.1.3 treated it as "a");
115  *	"?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
116  *	    (ie, treated as if it had just been "?a").
117  */
118 STATIC_OVL boolean
query_classes(oclasses,one_at_a_time,everything,action,objs,here,incl_gold,menu_on_demand)119 query_classes(oclasses, one_at_a_time, everything, action, objs,
120 	      here, incl_gold, menu_on_demand)
121 char oclasses[];
122 boolean *one_at_a_time, *everything;
123 const char *action;
124 struct obj *objs;
125 boolean here, incl_gold;
126 int *menu_on_demand;
127 {
128 	char ilets[20], inbuf[BUFSZ];
129 	int iletct, oclassct;
130 	boolean not_everything;
131 	char qbuf[QBUFSZ];
132 	boolean m_seen;
133 
134 	oclasses[oclassct = 0] = '\0';
135 	*one_at_a_time = *everything = m_seen = FALSE;
136 	iletct = collect_obj_classes(ilets, objs, here, incl_gold,
137 				     (boolean FDECL((*),(OBJ_P))) 0);
138 	if (iletct == 0) {
139 		return FALSE;
140 	} else if (iletct == 1) {
141 		oclasses[0] = def_char_to_objclass(ilets[0]);
142 		oclasses[1] = '\0';
143 	} else  {	/* more than one choice available */
144 		const char *where = 0;
145 		register char sym, oc_of_sym, *p;
146 		/* additional choices */
147 		ilets[iletct++] = ' ';
148 		ilets[iletct++] = 'a';
149 		ilets[iletct++] = 'A';
150 		ilets[iletct++] = (objs == invent ? 'i' : ':');
151 		if (menu_on_demand) {
152 			ilets[iletct++] = 'm';
153 			*menu_on_demand = 0;
154 		}
155 		ilets[iletct] = '\0';
156 ask_again:
157 		oclasses[oclassct = 0] = '\0';
158 		*one_at_a_time = *everything = FALSE;
159 		not_everything = FALSE;
160 		Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
161 			action, ilets);
162 		getlin(qbuf,inbuf);
163 		if (*inbuf == '\033') return FALSE;
164 
165 		for (p = inbuf; (sym = *p++); ) {
166 		    /* new A function (selective all) added by GAN 01/09/87 */
167 		    if (sym == ' ') continue;
168 		    else if (sym == 'A') *one_at_a_time = TRUE;
169 		    else if (sym == 'a') *everything = TRUE;
170 		    else if (sym == ':') {
171 			simple_look(objs, here);  /* dumb if objs==invent */
172 			goto ask_again;
173 		    } else if (sym == 'i') {
174 			(void) display_inventory((char *)0, TRUE);
175 			goto ask_again;
176 		    } else if (sym == 'm') {
177 			m_seen = TRUE;
178 		    } else {
179 			oc_of_sym = def_char_to_objclass(sym);
180 			if (index(ilets,sym)) {
181 			    add_valid_menu_class(oc_of_sym);
182 			    oclasses[oclassct++] = oc_of_sym;
183 			    oclasses[oclassct] = '\0';
184 			} else {
185 			    if (!where)
186 				where = !strcmp(action,"pick up")  ? "here" :
187 					!strcmp(action,"take out") ?
188 							    "inside" : "";
189 			    if (*where)
190 				There("are no %c's %s.", sym, where);
191 			    else
192 				You("have no %c's.", sym);
193 			    not_everything = TRUE;
194 			}
195 		    }
196 		}
197 		if (m_seen && menu_on_demand) {
198 			*menu_on_demand = (*everything || !oclassct) ? -2 : -3;
199 			return FALSE;
200 		}
201 		if (!oclassct && (!*everything || not_everything)) {
202 		    /* didn't pick anything,
203 		       or tried to pick something that's not present */
204 		    *one_at_a_time = TRUE;	/* force 'A' */
205 		    *everything = FALSE;	/* inhibit 'a' */
206 		}
207 	}
208 	return TRUE;
209 }
210 
211 /* look at the objects at our location, unless there are too many of them */
212 STATIC_OVL void
check_here(picked_some)213 check_here(picked_some)
214 boolean picked_some;
215 {
216 	register struct obj *obj;
217 	register int ct = 0;
218 
219 	/* count the objects here */
220 	for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) {
221 	    if (obj != uchain)
222 		ct++;
223 	}
224 
225 	/* If there are objects here, take a look. */
226 	if (ct) {
227 	    if (flags.run) nomul(0);
228 	    flush_screen(1);
229 	    (void) look_here(ct, picked_some);
230 	} else {
231 	    read_engr_at(u.ux,u.uy);
232 	}
233 }
234 
235 /* Value set by query_objlist() for n_or_more(). */
236 static long val_for_n_or_more;
237 
238 /* query_objlist callback: return TRUE if obj's count is >= reference value */
239 STATIC_OVL boolean
n_or_more(obj)240 n_or_more(obj)
241 struct obj *obj;
242 {
243     if (obj == uchain) return FALSE;
244     return (obj->quan >= val_for_n_or_more);
245 }
246 
247 /* List of valid menu classes for query_objlist() and allow_category callback */
248 static char valid_menu_classes[MAXOCLASSES + 2];
249 
250 void
add_valid_menu_class(c)251 add_valid_menu_class(c)
252 int c;
253 {
254 	static int vmc_count = 0;
255 
256 	if (c == 0)  /* reset */
257 	  vmc_count = 0;
258 	else
259 	  valid_menu_classes[vmc_count++] = (char)c;
260 	valid_menu_classes[vmc_count] = '\0';
261 }
262 
263 /* query_objlist callback: return TRUE if not uchain */
264 STATIC_OVL boolean
all_but_uchain(obj)265 all_but_uchain(obj)
266 struct obj *obj;
267 {
268     return (obj != uchain);
269 }
270 
271 /* query_objlist callback: return TRUE */
272 /*ARGSUSED*/
273 boolean
allow_all(obj)274 allow_all(obj)
275 struct obj *obj;
276 {
277     return TRUE;
278 }
279 
280 boolean
allow_category(obj)281 allow_category(obj)
282 struct obj *obj;
283 {
284     if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
285 	(index(valid_menu_classes, obj->oclass) != (char *)0))
286 	return TRUE;
287     else
288 	return FALSE;
289 }
290 
291 #if 0 /* not used */
292 /* query_objlist callback: return TRUE if valid category (class), no uchain */
293 STATIC_OVL boolean
294 allow_cat_no_uchain(obj)
295 struct obj *obj;
296 {
297     if ((obj != uchain) &&
298 	(((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
299 	(index(valid_menu_classes, obj->oclass) != (char *)0)))
300 	return TRUE;
301     else
302 	return FALSE;
303 }
304 #endif
305 
306 /* query_objlist callback: return TRUE if valid class and worn */
307 boolean
is_worn_by_type(otmp)308 is_worn_by_type(otmp)
309 register struct obj *otmp;
310 {
311 	return((boolean)(!!(otmp->owornmask &
312 			(W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER)))
313 	        && (index(valid_menu_classes, otmp->oclass) != (char *)0));
314 }
315 
316 /*
317  * Have the hero pick things from the ground.
318  *
319  * Arg what:
320  *	>0  autopickup
321  *	=0  interactive
322  *	<0  pickup count of something
323  *
324  * Returns 1 if tried to pick something up, whether
325  * or not it succeeded.
326  */
327 int
pickup(what)328 pickup(what)
329 int what;		/* should be a long */
330 {
331 	int i, n, res, count, n_tried = 0, n_picked = 0;
332 	menu_item *pick_list = (menu_item *) 0;
333 	boolean autopickup = what > 0;
334 
335 	if (what < 0)		/* pick N of something */
336 	    count = -what;
337 	else			/* pick anything */
338 	    count = 0;
339 
340 	/* no auto-pick if no-pick move, nothing there, or in a pool */
341 	if (autopickup && (flags.nopick || !OBJ_AT(u.ux, u.uy) ||
342 			(is_pool(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) {
343 	    read_engr_at(u.ux, u.uy);
344 	    return (0);
345 	}
346 
347 	/* no pickup if levitating & not on air or water level */
348 	if (!can_reach_floor()) {
349 	    if ((multi && !flags.run) || (autopickup && !flags.pickup))
350 		read_engr_at(u.ux, u.uy);
351 	    return (0);
352 	}
353 
354 	/* multi && !flags.run means they are in the middle of some other
355 	 * action, or possibly paralyzed, sleeping, etc.... and they just
356 	 * teleported onto the object.  They shouldn't pick it up.
357 	 */
358 	if ((multi && !flags.run) || (autopickup && !flags.pickup)) {
359 	    check_here(FALSE);
360 	    return (0);
361 	}
362 
363 	if (notake(youmonst.data)) {
364 	    if (!autopickup)
365 		You("are physically incapable of picking anything up.");
366 	    else
367 		check_here(FALSE);
368 	    return (0);
369 	}
370 
371 	/* if there's anything here, stop running */
372 	if (OBJ_AT(u.ux,u.uy) && flags.run && !flags.nopick) nomul(0);
373 
374 	add_valid_menu_class(0);	/* reset */
375 	/*
376 	 * Start the actual pickup process.  This is split into two main
377 	 * sections, the newer menu and the older "traditional" methods.
378 	 * Automatic pickup has been split into its own menu-style routine
379 	 * to make things less confusing.
380 	 */
381 	if (autopickup) {
382 	    n = autopick(level.objects[u.ux][u.uy], BY_NEXTHERE, &pick_list);
383 	    goto menu_pickup;
384 	}
385 
386 	if (flags.menu_style != MENU_TRADITIONAL) {
387 	    /* use menus exclusively */
388 
389 	    if (count) {	/* looking for N of something */
390 		char buf[QBUFSZ];
391 		Sprintf(buf, "Pick %d of what?", count);
392 		val_for_n_or_more = count;	/* set up callback selector */
393 		n = query_objlist(buf, level.objects[u.ux][u.uy],
394 			    BY_NEXTHERE|AUTOSELECT_SINGLE|INVORDER_SORT,
395 			    &pick_list, PICK_ONE, n_or_more);
396 		/* correct counts, if any given */
397 		for (i = 0; i < n; i++)
398 		    pick_list[i].count = count;
399 	    } else {
400 		n = query_objlist("Pick up what?", level.objects[u.ux][u.uy],
401 			    BY_NEXTHERE|AUTOSELECT_SINGLE|INVORDER_SORT,
402 			    &pick_list, PICK_ANY, all_but_uchain);
403 	    }
404 menu_pickup:
405 	    n_tried = n;
406 	    for (n_picked = i = 0 ; i < n; i++) {
407 		res = pickup_object(pick_list[i].item.a_obj,pick_list[i].count,
408 					FALSE);
409 		if (res < 0) break;	/* can't continue */
410 		n_picked += res;
411 	    }
412 	    if (pick_list) free((genericptr_t)pick_list);
413 
414 	} else {
415 	    /* old style interface */
416 	    int ct = 0;
417 	    long lcount;
418 	    boolean all_of_a_type, selective;
419 	    char oclasses[MAXOCLASSES];
420 	    struct obj *obj, *obj2;
421 
422 	    oclasses[0] = '\0';		/* types to consider (empty for all) */
423 	    all_of_a_type = TRUE;	/* take all of considered types */
424 	    selective = FALSE;		/* ask for each item */
425 
426 	    /* check for more than one object */
427 	    for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
428 		ct++;
429 
430 	    if (ct == 1 && count) {
431 		/* if only one thing, then pick it */
432 		obj = level.objects[u.ux][u.uy];
433 		lcount = min(obj->quan, (long)count);
434 		n_tried++;
435 		if (pickup_object(obj, lcount, FALSE) > 0)
436 		    n_picked++;	/* picked something */
437 		goto end_query;
438 
439 	    } else if (ct >= 2) {
440 		int via_menu = 0;
441 
442 		There("are %s objects here.",
443 		      (ct <= 10) ? "several" : "many");
444 		if (!query_classes(oclasses, &selective, &all_of_a_type,
445 				   "pick up", level.objects[u.ux][u.uy],
446 				   TRUE, FALSE, &via_menu)) {
447 		    if (!via_menu) return (0);
448 		    n = query_objlist("Pick up what?",
449 				  level.objects[u.ux][u.uy],
450 				  BY_NEXTHERE|(selective ? 0 : INVORDER_SORT),
451 				  &pick_list, PICK_ANY,
452 				  via_menu == -2 ? allow_all : allow_category);
453 		    goto menu_pickup;
454 		}
455 	    }
456 
457 	    for (obj = level.objects[u.ux][u.uy]; obj; obj = obj2) {
458 		obj2 = obj->nexthere;	/* perhaps obj will be picked up */
459 		lcount = -1L;
460 
461 		if (!selective && oclasses[0] && !index(oclasses,obj->oclass))
462 		    continue;
463 
464 		if (!all_of_a_type) {
465 		    char qbuf[QBUFSZ];
466 		    Sprintf(qbuf, "Pick up %s?", doname(obj));
467 		    switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
468 		    case 'q': goto end_query;	/* out 2 levels */
469 		    case 'n': continue;
470 		    case 'a':
471 			all_of_a_type = TRUE;
472 			if (selective) {
473 			    selective = FALSE;
474 			    oclasses[0] = obj->oclass;
475 			    oclasses[1] = '\0';
476 			}
477 			break;
478 		    case '#':	/* count was entered */
479 			if (!yn_number) continue; /* 0 count => No */
480 			lcount = (long) yn_number;
481 			if (lcount > obj->quan) lcount = obj->quan;
482 			/* fall thru */
483 		    default:	/* 'y' */
484 			break;
485 		    }
486 		}
487 		if (lcount == -1L) lcount = obj->quan;
488 
489 		n_tried++;
490 		if ((res = pickup_object(obj, lcount, FALSE)) < 0) break;
491 		n_picked += res;
492 	    }
493 end_query:
494 	    ;	/* semicolon needed by brain-damaged compilers */
495 	}
496 
497 	/* position may need updating (invisible hero) */
498 	if (n_picked) newsym(u.ux,u.uy);
499 
500 	/* see whether there's anything else here, after auto-pickup is done */
501 	if (autopickup) check_here(n_picked > 0);
502 	return (n_tried > 0);
503 }
504 
505 /*
506  * Pick from the given list using flags.pickup_types.  Return the number
507  * of items picked (not counts).  Create an array that returns pointers
508  * and counts of the items to be picked up.  If the number of items
509  * picked is zero, the pickup list is left alone.  The caller of this
510  * function must free the pickup list.
511  */
512 STATIC_OVL int
autopick(olist,follow,pick_list)513 autopick(olist, follow, pick_list)
514 struct obj *olist;	/* the object list */
515 int follow;		/* how to follow the object list */
516 menu_item **pick_list;	/* list of objects and counts to pick up */
517 {
518 	menu_item *pi;	/* pick item */
519 	struct obj *curr;
520 	int n;
521 	const char *otypes = flags.pickup_types;
522 
523 	/* first count the number of eligible items */
524 	for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
525 	    if (!*otypes || index(otypes, curr->oclass))
526 		n++;
527 
528 	if (n) {
529 	    *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n);
530 	    for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
531 		if (!*otypes || index(otypes, curr->oclass)) {
532 		    pi[n].item.a_obj = curr;
533 		    pi[n].count = curr->quan;
534 		    n++;
535 		}
536 	}
537 	return n;
538 }
539 
540 
541 /*
542  * Put up a menu using the given object list.  Only those objects on the
543  * list that meet the approval of the allow function are displayed.  Return
544  * a count of the number of items selected, as well as an allocated array of
545  * menu_items, containing pointers to the objects selected and counts.  The
546  * returned counts are guaranteed to be in bounds and non-zero.
547  *
548  * Query flags:
549  *	BY_NEXTHERE	  - Follow object list via nexthere instead of nobj.
550  *	AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
551  *			    use it.
552  *	USE_INVLET	  - Use object's invlet.
553  *	INVORDER_SORT	  - Use hero's pack order.
554  *	SIGNAL_NOMENU	  - Return -1 rather than 0 if nothing passes "allow".
555  */
556 int
query_objlist(qstr,olist,qflags,pick_list,how,allow)557 query_objlist(qstr, olist, qflags, pick_list, how, allow)
558 const char *qstr;		/* query string */
559 struct obj *olist;		/* the list to pick from */
560 int qflags;			/* options to control the query */
561 menu_item **pick_list;		/* return list of items picked */
562 int how;			/* type of query */
563 boolean FDECL((*allow), (OBJ_P));/* allow function */
564 {
565 	int n;
566 	winid win;
567 	struct obj *curr, *last;
568 	char *pack;
569 	anything any;
570 	boolean printed_type_name;
571 
572 	*pick_list = (menu_item *) 0;
573 	if (!olist) return 0;
574 
575 	/* count the number of items allowed */
576 	for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags))
577 	    if ((*allow)(curr)) {
578 		last = curr;
579 		n++;
580 	    }
581 
582 	if (n == 0)	/* nothing to pick here */
583 	    return (qflags & SIGNAL_NOMENU) ? -1 : 0;
584 
585 	if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
586 	    *pick_list = (menu_item *) alloc(sizeof(menu_item));
587 	    (*pick_list)->item.a_obj = last;
588 	    (*pick_list)->count = last->quan;
589 	    return 1;
590 	}
591 
592 	win = create_nhwindow(NHW_MENU);
593 	start_menu(win);
594 	any.a_obj = (struct obj *) 0;
595 
596 	/*
597 	 * Run through the list and add the objects to the menu.  If
598 	 * INVORDER_SORT is set, we'll run through the list once for
599 	 * each type so we can group them.  The allow function will only
600 	 * be called once per object in the list.
601 	 */
602 	pack = flags.inv_order;
603 	do {
604 	    printed_type_name = FALSE;
605 	    for (curr = olist; curr; curr = FOLLOW(curr, qflags))
606 		if ((!(qflags & INVORDER_SORT) || curr->oclass == *pack)
607 							&& (*allow)(curr)) {
608 
609 		    /* if sorting, print type name (once only) */
610 		    if (qflags & INVORDER_SORT && !printed_type_name) {
611 			any.a_obj = (struct obj *) 0;
612 			add_menu(win, NO_GLYPH, &any, 0, 0, ATR_INVERSE,
613 					let_to_name(*pack, FALSE), MENU_UNSELECTED);
614 			printed_type_name = TRUE;
615 		    }
616 
617 		    any.a_obj = curr;
618 		    add_menu(win, obj_to_glyph(curr), &any,
619 			    qflags & USE_INVLET ? curr->invlet : 0,
620 			    def_oc_syms[(int)objects[curr->otyp].oc_class],
621 			    ATR_NONE, doname(curr), MENU_UNSELECTED);
622 		}
623 	    pack++;
624 	} while (qflags & INVORDER_SORT && *pack);
625 
626 	end_menu(win, qstr);
627 	n = select_menu(win, how, pick_list);
628 	destroy_nhwindow(win);
629 
630 	if (n > 0) {
631 	    menu_item *mi;
632 	    int i;
633 
634 	    /* fix up counts:  -1 means no count used => pick all */
635 	    for (i = 0, mi = *pick_list; i < n; i++, mi++)
636 		if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
637 		    mi->count = mi->item.a_obj->quan;
638 	} else if (n < 0) {
639 	    n = 0;	/* caller's don't expect -1 */
640 	}
641 	return n;
642 }
643 
644 /*
645  * allow menu-based category (class) selection (for Drop,take off etc.)
646  *
647  */
648 int
query_category(qstr,olist,qflags,pick_list,how)649 query_category(qstr, olist, qflags, pick_list, how)
650 const char *qstr;		/* query string */
651 struct obj *olist;		/* the list to pick from */
652 int qflags;			/* behaviour modification flags */
653 menu_item **pick_list;		/* return list of items picked */
654 int how;			/* type of query */
655 {
656 	int n;
657 	winid win;
658 	struct obj *curr;
659 	char *pack;
660 	anything any;
661 	boolean collected_type_name;
662 	char invlet;
663 	int ccount;
664 	boolean do_unpaid = FALSE;
665 
666 	*pick_list = (menu_item *) 0;
667 	if (!olist) return 0;
668 	if ((qflags & UNPAID_TYPES) && count_unpaid(olist)) do_unpaid = TRUE;
669 
670 	ccount = count_categories(olist, qflags);
671 	/* no point in actually showing a menu for a single category */
672 	if (ccount == 1 && !do_unpaid && !(qflags & BILLED_TYPES)) {
673 	    for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
674 		if ((qflags & WORN_TYPES) &&
675 		    !(curr->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL|W_WEP|W_SWAPWEP|W_QUIVER)))
676 		    continue;
677 		break;
678 	    }
679 	    if (curr) {
680 		*pick_list = (menu_item *) alloc(sizeof(menu_item));
681 		(*pick_list)->item.a_int = curr->oclass;
682 		return 1;
683 	    } else {
684 #ifdef DEBUG
685 		impossible("query_category: no single object match");
686 #endif
687 	    }
688 	    return 0;
689 	}
690 
691 	win = create_nhwindow(NHW_MENU);
692 	start_menu(win);
693 	pack = flags.inv_order;
694 	if ((qflags & ALL_TYPES) && (ccount > 1)) {
695 		invlet = 'a';
696 		any.a_void = 0;
697 		any.a_int = ALL_TYPES_SELECTED;
698 		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
699 		       (qflags & WORN_TYPES) ? "All worn types" : "All types",
700 			MENU_UNSELECTED);
701 		invlet = 'b';
702 	} else
703 		invlet = 'a';
704 	do {
705 	    collected_type_name = FALSE;
706 	    for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
707 		if (curr->oclass == *pack) {
708 		   if ((qflags & WORN_TYPES) &&
709 		   		!(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
710 		    	W_WEP | W_SWAPWEP | W_QUIVER)))
711 			 continue;
712 		   if (!collected_type_name) {
713 			any.a_void = 0;
714 			any.a_int = curr->oclass;
715 			add_menu(win, NO_GLYPH, &any, invlet++,
716 				def_oc_syms[(int)objects[curr->otyp].oc_class],
717 				ATR_NONE, let_to_name(*pack, FALSE),
718 				MENU_UNSELECTED);
719 			collected_type_name = TRUE;
720 		   }
721 		}
722 	    }
723 	    pack++;
724 	    if (invlet >= 'u') {
725 		impossible("query_category: too many categories");
726 		return 0;
727 	    }
728 	} while (*pack);
729 	/* unpaid items if there are any */
730 	if (do_unpaid) {
731 		invlet = 'u';
732 		any.a_void = 0;
733 		any.a_int = 'u';
734 		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
735 			"Unpaid items", MENU_UNSELECTED);
736 	}
737 	/* billed items: checked by caller, so always include if BILLED_TYPES */
738 	if (qflags & BILLED_TYPES) {
739 		invlet = 'x';
740 		any.a_void = 0;
741 		any.a_int = 'x';
742 		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
743 			 "Unpaid items already used up", MENU_UNSELECTED);
744 	}
745 	if (qflags & CHOOSE_ALL) {
746 		invlet = 'A';
747 		any.a_void = 0;
748 		any.a_int = 'A';
749 		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
750 			(qflags & WORN_TYPES) ?
751 			"Auto-select every item being worn" :
752 			"Auto-select every item", MENU_UNSELECTED);
753 	}
754 	end_menu(win, qstr);
755 	n = select_menu(win, how, pick_list);
756 	destroy_nhwindow(win);
757 	if (n < 0)
758 	    n = 0;	/* caller's don't expect -1 */
759 	return n;
760 }
761 
762 STATIC_OVL int
count_categories(olist,qflags)763 count_categories(olist, qflags)
764 struct obj *olist;
765 int qflags;
766 {
767 	char *pack;
768 	boolean counted_category;
769 	int ccount = 0;
770 	struct obj *curr;
771 
772 	pack = flags.inv_order;
773 	do {
774 	    counted_category = FALSE;
775 	    for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
776 		if (curr->oclass == *pack) {
777 		   if ((qflags & WORN_TYPES) &&
778 		    	!(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
779 		    	W_WEP | W_SWAPWEP | W_QUIVER)))
780 			 continue;
781 		   if (!counted_category) {
782 			ccount++;
783 			counted_category = TRUE;
784 		   }
785 		}
786 	    }
787 	    pack++;
788 	} while (*pack);
789 	return ccount;
790 }
791 
792 /* could we carry `obj'? if not, could we carry some of it/them? */
793 STATIC_OVL
carry_count(obj,container,count,telekinesis,wt_before,wt_after)794 long carry_count(obj, container, count, telekinesis, wt_before, wt_after)
795 struct obj *obj, *container;	/* object to pick up, bag it's coming out of */
796 long count;
797 boolean telekinesis;
798 int *wt_before, *wt_after;
799 {
800     boolean adjust_wt = container && carried(container),
801 	    is_gold = obj->oclass == GOLD_CLASS;
802     int wt, iw, ow, oow;
803     long qq, savequan;
804     unsigned saveowt;
805     const char *verb, *prefx1, *prefx2, *suffx;
806     char obj_nambuf[BUFSZ], where[BUFSZ];
807 
808     savequan = obj->quan;
809     saveowt = obj->owt;
810     iw = max_capacity();
811     if (count != savequan) {
812 	obj->quan = count;
813 	obj->owt = (unsigned)weight(obj);
814     }
815     wt = iw + (int)obj->owt;
816     if (adjust_wt)
817 	wt -= (container->otyp == BAG_OF_HOLDING) ?
818 		(int)DELTA_CWT(container, obj) : (int)obj->owt;
819     if (is_gold)	/* merged gold might affect cumulative weight */
820 	wt -= (GOLD_WT(u.ugold) + GOLD_WT(count) - GOLD_WT(u.ugold + count));
821     if (count != savequan) {
822 	obj->quan = savequan;
823 	obj->owt = saveowt;
824     }
825     *wt_before = iw;
826     *wt_after  = wt;
827     if (wt < 0)
828 	return count;
829 
830     /* see how many we can lift */
831     if (is_gold) {
832 	iw -= (int)GOLD_WT(u.ugold);
833 	if (!adjust_wt) {
834 	    qq = GOLD_CAPACITY((long)iw, u.ugold);
835 	} else {
836 	    oow = 0;
837 	    qq = 50L - (u.ugold % 100L) - 1L;
838 	    if (qq < 0L) qq += 100L;
839 	    for ( ; qq <= count; qq += 100L) {
840 		obj->quan = qq;
841 		obj->owt = (unsigned)GOLD_WT(qq);
842 		ow = (int)GOLD_WT(u.ugold + qq);
843 		ow -= (container->otyp == BAG_OF_HOLDING) ?
844 			(int)DELTA_CWT(container, obj) : (int)obj->owt;
845 		if (iw + ow >= 0) break;
846 		oow = ow;
847 	    }
848 	    iw -= oow;
849 	    qq -= 100L;
850 	}
851 	if (qq < 0L) qq = 0L;
852 	else if (qq > count) qq = count;
853 	wt = iw + (int)GOLD_WT(u.ugold + qq);
854     } else if (count > 1 || count < obj->quan) {
855 	/*
856 	 * Ugh. Calc num to lift by changing the quan of of the
857 	 * object and calling weight.
858 	 *
859 	 * This works for containers only because containers
860 	 * don't merge.		-dean
861 	 */
862 	for (qq = 1L; qq <= count; qq++) {
863 	    obj->quan = qq;
864 	    obj->owt = (unsigned)(ow = weight(obj));
865 	    if (adjust_wt)
866 		ow -= (container->otyp == BAG_OF_HOLDING) ?
867 			(int)DELTA_CWT(container, obj) : (int)obj->owt;
868 	    if (iw + ow >= 0)
869 		break;
870 	    wt = iw + ow;
871 	}
872 	--qq;
873     } else {
874 	/* there's only one, and we can't lift it */
875 	qq = 0L;
876     }
877     obj->quan = savequan;
878     obj->owt = saveowt;
879 
880     if (qq < count) {
881 	/* some message will be given */
882 	Strcpy(obj_nambuf, doname(obj));
883 	if (container) {
884 	    Sprintf(where, "in %s", the(xname(container)));
885 	    verb = "carry";
886 	} else {
887 	    Strcpy(where, "lying here");
888 	    verb = telekinesis ? "acquire" : "lift";
889 	}
890     } else {
891 	/* lint supppression */
892 	*obj_nambuf = *where = '\0';
893 	verb = "";
894     }
895     /* we can carry qq of them */
896     if (qq > 0) {
897 	if (qq < count)
898 	    You("can only %s %s of the %s %s.",
899 		verb, (qq == 1L) ? "one" : "some", obj_nambuf, where);
900 	*wt_after = wt;
901 	return qq;
902     }
903 
904     if (!container) Strcpy(where, "here");  /* slightly shorter form */
905     if (invent || u.ugold) {
906 	prefx1 = "you cannot ";
907 	prefx2 = "";
908 	suffx  = " any more";
909     } else {
910 	prefx1 = (obj->quan == 1L) ? "it " : "even one ";
911 	prefx2 = "is too heavy for you to ";
912 	suffx  = "";
913     }
914     There("%s %s %s, but %s%s%s%s.",
915 	  (obj->quan == 1L) ? "is" : "are", obj_nambuf, where,
916 	  prefx1, prefx2, verb, suffx);
917 
918  /* *wt_after = iw; */
919     return 0L;
920 }
921 
922 /* determine whether character is able and player is willing to carry `obj' */
923 STATIC_OVL
lift_object(obj,container,cnt_p,telekinesis)924 int lift_object(obj, container, cnt_p, telekinesis)
925 struct obj *obj, *container;	/* object to pick up, bag it's coming out of */
926 long *cnt_p;
927 boolean telekinesis;
928 {
929     int result, old_wt, new_wt, prev_encumbr, next_encumbr;
930 
931 
932     if (obj->otyp == BOULDER && In_sokoban(&u.uz)) {
933 	You("cannot get your %s around this %s.",
934 			body_part(HAND), xname(obj));
935 	return -1;
936     }
937     if (obj->otyp == LOADSTONE ||
938 	    (obj->otyp == BOULDER && throws_rocks(youmonst.data)))
939 	return 1;		/* lift regardless of current situation */
940 
941     *cnt_p = carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt);
942     if (*cnt_p < 1L) {
943 	result = -1;	/* nothing lifted */
944     } else if (obj->oclass != GOLD_CLASS && inv_cnt() >= 52 &&
945 		!merge_choice(invent, obj)) {
946 	Your("knapsack cannot accommodate any more items.");
947 	result = -1;	/* nothing lifted */
948     } else {
949 	result = 1;
950 	prev_encumbr = near_capacity();
951 	if (prev_encumbr < flags.pickup_burden)
952 		prev_encumbr = flags.pickup_burden;
953 	next_encumbr = calc_capacity(new_wt - old_wt);
954 	if (next_encumbr > prev_encumbr) {
955 	    if (telekinesis) {
956 		result = 0;	/* don't lift */
957 	    } else {
958 		char qbuf[QBUFSZ];
959 		long savequan = obj->quan;
960 
961 		obj->quan = *cnt_p;
962 		Sprintf(qbuf, "%s %s.  Continue?",
963 			(next_encumbr > HVY_ENCUMBER) ? overloadmsg :
964 			(next_encumbr > MOD_ENCUMBER) ? nearloadmsg :
965 			moderateloadmsg, doname(obj));
966 		obj->quan = savequan;
967 		switch (ynq(qbuf)) {
968 		case 'q':  result = -1; break;
969 		case 'n':  result =  0; break;
970 		default:   break;	/* 'y' => result == 1 */
971 		}
972 	    }
973 	}
974     }
975 
976     if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container)
977 	obj->spe = 0;
978     return result;
979 }
980 
981 /*
982  * Pick up <count> of obj from the ground and add it to the hero's inventory.
983  * Returns -1 if caller should break out of its loop, 0 if nothing picked
984  * up, 1 if otherwise.
985  */
986 int
pickup_object(obj,count,telekinesis)987 pickup_object(obj, count, telekinesis)
988 struct obj *obj;
989 long count;
990 boolean telekinesis;	/* not picking it up directly by hand */
991 {
992 	int res, nearload;
993 	const char *where = (obj->ox == u.ux && obj->oy == u.uy) ?
994 			    "here" : "there";
995 
996 	if (obj->quan < count) {
997 	    impossible("pickup_object: count %ld > quan %ld?",
998 		count, obj->quan);
999 	    return 0;
1000 	}
1001 
1002 	/* In case of auto-pickup, where we haven't had a chance
1003 	   to look at it yet; affects docall(SCR_SCARE_MONSTER). */
1004 	if (!Blind)
1005 #ifdef INVISIBLE_OBJECTS
1006 		if (!obj->oinvis || See_invisible)
1007 #endif
1008 		obj->dknown = 1;
1009 
1010 	if (obj == uchain) {    /* do not pick up attached chain */
1011 	    return 0;
1012 	} else if (obj->oartifact && !touch_artifact(obj,&youmonst)) {
1013 	    return 0;
1014 	} else if (obj->oclass == GOLD_CLASS) {
1015 	    /* Special consideration for gold pieces... */
1016 	    long iw = (long)max_capacity() - GOLD_WT(u.ugold);
1017 	    long gold_capacity = GOLD_CAPACITY(iw, u.ugold);
1018 
1019 	    if (gold_capacity <= 0L) {
1020 		pline(
1021 	       "There %s %ld gold piece%s %s, but you cannot carry any more.",
1022 		      (obj->quan == 1L) ? "is" : "are",
1023 		      obj->quan, plur(obj->quan), where);
1024 		return 0;
1025 	    } else if (gold_capacity < count) {
1026 		You("can only %s %s of the %ld gold pieces lying %s.",
1027 		    telekinesis ? "acquire" : "carry",
1028 		    gold_capacity == 1L ? "one" : "some", obj->quan, where);
1029 		pline("%s %ld gold piece%s.",
1030 		    nearloadmsg, gold_capacity, plur(gold_capacity));
1031 		u.ugold += gold_capacity;
1032 		obj->quan -= gold_capacity;
1033 		costly_gold(obj->ox, obj->oy, gold_capacity);
1034 	    } else {
1035 		u.ugold += count;
1036 		if ((nearload = near_capacity()) != 0)
1037 		    pline("%s %ld gold piece%s.",
1038 			  nearload < MOD_ENCUMBER ?
1039 			  moderateloadmsg : nearloadmsg,
1040 			  count, plur(count));
1041 		else
1042 		    prinv((char *) 0, obj, count);
1043 		costly_gold(obj->ox, obj->oy, count);
1044 		if (count == obj->quan)
1045 		    delobj(obj);
1046 		else
1047 		    obj->quan -= count;
1048 	    }
1049 	    flags.botl = 1;
1050 	    if (flags.run) nomul(0);
1051 	    return 1;
1052 	} else if (obj->otyp == CORPSE) {
1053 		if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg
1054 				&& !Stone_resistance && !telekinesis) {
1055 		if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1056 		    display_nhwindow(WIN_MESSAGE, FALSE);
1057 		else {
1058 			char kbuf[BUFSZ];
1059 
1060 			pline("Touching %s corpse is a fatal mistake.",
1061 					an(mons[obj->corpsenm].mname));
1062 			Sprintf(kbuf, "%s corpse", an(mons[obj->corpsenm].mname));
1063 			instapetrify(kbuf);
1064 		    return -1;
1065 		}
1066 	    } else if (is_rider(&mons[obj->corpsenm])) {
1067 		pline("At your %s, the corpse suddenly moves...",
1068 			telekinesis ? "attempted acquisition" : "touch");
1069 		(void) revive_corpse(obj);
1070 		exercise(A_WIS, FALSE);
1071 		return -1;
1072 	    }
1073 	} else  if (obj->otyp == SCR_SCARE_MONSTER) {
1074 	    if (obj->blessed) obj->blessed = 0;
1075 	    else if (!obj->spe && !obj->cursed) obj->spe = 1;
1076 	    else {
1077 		pline_The("scroll%s turn%s to dust as you %s %s up.",
1078 			plur(obj->quan), (obj->quan == 1L) ? "s" : "",
1079 			telekinesis ? "raise" : "pick",
1080 			(obj->quan == 1L) ? "it" : "them");
1081 		if (!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
1082 				    !(objects[SCR_SCARE_MONSTER].oc_uname))
1083 		    docall(obj);
1084 		useupf(obj, obj->quan);
1085 		return 1;	/* tried to pick something up and failed, but
1086 				   don't want to terminate pickup loop yet   */
1087 	    }
1088 	}
1089 
1090 	if ((res = lift_object(obj, (struct obj *)0, &count, telekinesis)) <= 0)
1091 	    return res;
1092 
1093 	if (obj->quan != count && obj->otyp != LOADSTONE)
1094 	    (void) splitobj(obj, count);
1095 
1096 	obj = pick_obj(obj);
1097 
1098 	if (uwep && uwep == obj) mrg_to_wielded = TRUE;
1099 	nearload = near_capacity();
1100 	prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0, obj, count);
1101 	mrg_to_wielded = FALSE;
1102 	return 1;
1103 }
1104 
1105 /*
1106  * Do the actual work of picking otmp from the floor and putting
1107  * it in the hero's inventory.  Take care of billing.  Return a
1108  * pointer to the object where otmp ends up.  This may be different
1109  * from otmp because of merging.
1110  *
1111  * Gold never reaches this routine.
1112  */
1113 struct obj *
pick_obj(otmp)1114 pick_obj(otmp)
1115 register struct obj *otmp;
1116 {
1117 	obj_extract_self(otmp);
1118 	if (*u.ushops && costly_spot(u.ux, u.uy) &&
1119 	    otmp != uball)     /* don't charge for this - kd, 1/17/90 */
1120 	   /* sets obj->unpaid if necessary */
1121 	    addtobill(otmp, TRUE, FALSE, FALSE);
1122 	if(Invisible) newsym(u.ux,u.uy);
1123 	return(addinv(otmp));    /* might merge it with other objects */
1124 }
1125 
1126 /*
1127  * prints a message if encumbrance changed since the last check and
1128  * returns the new encumbrance value (from near_capacity()).
1129  */
1130 int
encumber_msg()1131 encumber_msg()
1132 {
1133     static int oldcap = UNENCUMBERED;
1134     int newcap = near_capacity();
1135 
1136     if(oldcap < newcap) {
1137 	switch(newcap) {
1138 	case 1: Your("movements are slowed slightly because of your load.");
1139 		break;
1140 	case 2: You("rebalance your load.  Movement is difficult.");
1141 		break;
1142 	case 3: You("stagger under your heavy load.  Movement is very hard.");
1143 		break;
1144 	default: You("%s move a handspan with this load!",
1145 		     newcap == 4 ? "can barely" : "can't even");
1146 		break;
1147 	}
1148 	flags.botl = 1;
1149     } else if(oldcap > newcap) {
1150 	switch(newcap) {
1151 	case 0: Your("movements are now unencumbered.");
1152 		break;
1153 	case 1: Your("movements are only slowed slightly by your load.");
1154 		break;
1155 	case 2: You("rebalance your load.  Movement is still difficult.");
1156 		break;
1157 	case 3: You("stagger under your load.  Movement is still very hard.");
1158 		break;
1159 	}
1160 	flags.botl = 1;
1161     }
1162 
1163     oldcap = newcap;
1164     return (newcap);
1165 }
1166 
1167 /* Is there a container at x,y. Optional: return count of containers at x,y */
1168 STATIC_OVL int
container_at(x,y,countem)1169 container_at(x, y, countem)
1170 int x,y;
1171 boolean countem;
1172 {
1173 	struct obj *cobj, *nobj;
1174 	int container_count = 0;
1175 
1176 	for(cobj = level.objects[x][y]; cobj; cobj = nobj) {
1177 		nobj = cobj->nexthere;
1178 		if(Is_container(cobj)) {
1179 			container_count++;
1180 			if (!countem) break;
1181 		}
1182 	}
1183 	return container_count;
1184 }
1185 
1186 STATIC_OVL boolean
able_to_loot(x,y)1187 able_to_loot(x, y)
1188 int x, y;
1189 {
1190 	if (!can_reach_floor()) {
1191 #ifdef STEED
1192 		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
1193 			You("aren't skilled enough to reach from %s.",
1194 				mon_nam(u.usteed));
1195 		else
1196 #endif
1197 			You("cannot reach the %s.", surface(x, y));
1198 		return FALSE;
1199 	} else if (is_pool(x, y) || is_lava(x, y)) {
1200 		/* at present, can't loot in water even when Underwater */
1201 		You("cannot loot things that are deep in the %s.",
1202 		    is_lava(x, y) ? "lava" : "water");
1203 		return FALSE;
1204 	} else if (nolimbs(youmonst.data)) {
1205 		pline("Without limbs, you cannot loot anything.");
1206 		return FALSE;
1207 	}
1208 	return TRUE;
1209 }
1210 
1211 STATIC_OVL
mon_beside(x,y)1212 boolean mon_beside(x,y)
1213 int x, y;
1214 {
1215 	int i,j,nx,ny;
1216 	for(i = -1; i <= 1; i++)
1217 	    for(j = -1; j <= 1; j++) {
1218 	    	nx = x + i;
1219 	    	ny = y + j;
1220 		if(isok(nx, ny) && MON_AT(nx, ny))
1221 			return TRUE;
1222 	    }
1223 	return FALSE;
1224 }
1225 
1226 int
doloot()1227 doloot()	/* loot a container on the floor. */
1228 {
1229     register struct obj *cobj, *nobj;
1230     register int c = -1;
1231     int timepassed = 0;
1232     int x,y;
1233     boolean underfoot = TRUE;
1234     const char *dont_find_anything = "don't find anything";
1235     struct monst *mtmp;
1236     char qbuf[QBUFSZ];
1237 #ifdef STEED
1238     struct obj *otmp;
1239     boolean saddled_there = FALSE;
1240     boolean got_saddle = FALSE;
1241 #endif
1242 
1243     if (check_capacity((char *)0)) {
1244 	/* "Can't do that while carrying so much stuff." */
1245 	return 0;
1246     }
1247     x = u.ux; y = u.uy;
1248 
1249 lootcont:
1250 
1251     if (container_at(x, y, FALSE)) {
1252 	if (!able_to_loot(x, y)) return 0;
1253 	for (cobj = level.objects[x][y]; cobj; cobj = nobj) {
1254 	    nobj = cobj->nexthere;
1255 
1256 	    if (Is_container(cobj)) {
1257 		Sprintf(qbuf, "There is %s here, loot it?", doname(cobj));
1258 		c = ynq(qbuf);
1259 		if (c == 'q') return (timepassed);
1260 		if (c == 'n') continue;
1261 
1262 		if (cobj->olocked) {
1263 		    pline("Hmmm, it seems to be locked.");
1264 		    continue;
1265 		}
1266 		if (cobj->otyp == BAG_OF_TRICKS) {
1267 		    You("carefully open the bag...");
1268 		    pline("It develops a huge set of teeth and bites you!");
1269 		    c = rnd(10);
1270 		    if (Half_physical_damage) c = (c+1) / 2;
1271 		    losehp(c, "carnivorous bag", KILLED_BY_AN);
1272 		    makeknown(BAG_OF_TRICKS);
1273 		    timepassed = 1;
1274 		    continue;
1275 		}
1276 
1277 		You("carefully open %s...", the(xname(cobj)));
1278 		timepassed |= use_container(cobj, 0);
1279 		if (multi < 0) return 1;		/* chest trap */
1280 	    }
1281 	}
1282     } else if (Confusion) {
1283 	if (u.ugold){
1284 	    long contribution = rnd((int)min(LARGEST_INT,u.ugold));
1285 	    struct obj *goldob = mkgoldobj(contribution);
1286 	    if (IS_THRONE(levl[u.ux][u.uy].typ)){
1287 		struct obj *coffers;
1288 		int pass;
1289 		/* find the original coffers chest, or any chest */
1290 		for (pass = 2; pass > -1; pass -= 2)
1291 		    for (coffers = fobj; coffers; coffers = coffers->nobj)
1292 			if (coffers->otyp == CHEST && coffers->spe == pass)
1293 			    goto gotit;	/* two level break */
1294 gotit:
1295 		if (coffers){
1296 		    struct obj *tmp;
1297 	    verbalize("Thank you for your contribution to reduce the debt.");
1298 		    for (tmp = coffers->cobj; tmp; tmp = tmp->nobj)
1299 			if (tmp->otyp == goldob->otyp) break;
1300 
1301 		    if (tmp) {
1302 			tmp->quan += goldob->quan;
1303 			delobj(goldob);
1304 		    } else {
1305 			add_to_container(coffers, goldob);
1306 		    }
1307 		} else {
1308 		    struct monst *mon = makemon(courtmon(),
1309 					    u.ux, u.uy, NO_MM_FLAGS);
1310 		    if (mon) {
1311 			mon->mgold += goldob->quan;
1312 			delobj(goldob);
1313 			pline("The exchequer accepts your contribution.");
1314 		    } else {
1315 			dropx(goldob);
1316 		    }
1317 		}
1318 	    } else {
1319 		dropx(goldob);
1320 		pline("Ok, now there is loot here.");
1321 	    }
1322 	}
1323     } else if (IS_GRAVE(levl[x][y].typ)) {
1324 	You("need to dig up the grave to effectively loot it...");
1325     }
1326     /*
1327      * 3.3.1 introduced directional looting for some things.
1328      */
1329     if (c != 'y' && mon_beside(u.ux, u.uy)) {
1330 	if (!getdir("Loot in what direction?")) {
1331 	    pline(Never_mind);
1332 	    return(0);
1333 	}
1334 	x = u.ux + u.dx;
1335 	y = u.uy + u.dy;
1336 	if (x == u.ux && y == u.uy) {
1337 	    underfoot = TRUE;
1338 	    if (container_at(x, y, FALSE))
1339 		goto lootcont;
1340 	} else
1341 	    underfoot = FALSE;
1342 	if (u.dz < 0) {
1343 	    You("%s to loot on the %s.", dont_find_anything,
1344 		ceiling(x, y));
1345 	    timepassed = 1;
1346 	    return timepassed;
1347 	}
1348 	mtmp = m_at(x, y);
1349 #ifdef STEED
1350 	/* 3.3.1 introduced the ability to remove saddle from a steed */
1351 	if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
1352 	    long unwornmask;
1353 	    saddled_there = TRUE;
1354 	    Sprintf(qbuf, "Do you want to remove the saddle from %s?",
1355 		x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE));
1356 	    if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
1357 		if (nolimbs(youmonst.data)) {
1358 		    You_cant("do that without limbs."); /* not body_part(HAND) */
1359 		    return (0);
1360 		}
1361 		if (otmp->cursed) {
1362 		    You("can't. The saddle seems to be stuck to %s.",
1363 			x_monnam(mtmp, ARTICLE_THE, (char *)0,
1364 				SUPPRESS_SADDLE, FALSE));
1365 
1366 		    /* the attempt costs you time */
1367 			return (1);
1368 		}
1369 		obj_extract_self(otmp);
1370 		if ((unwornmask = otmp->owornmask) != 0L) {
1371 		    mtmp->misc_worn_check &= ~unwornmask;
1372 		    otmp->owornmask = 0L;
1373 		    update_mon_intrinsics(mtmp, otmp, FALSE);
1374 		}
1375 		otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
1376 					(const char *)0);
1377 		timepassed = rnd(3);
1378 		got_saddle = TRUE;
1379 	    } else if (c == 'q') {
1380 		return (0);
1381 	    }
1382 	}
1383 # if 0
1384 	/* Loot your steed, even if you can't reach the floor */
1385 	if (u.usteed) {
1386 	    Sprintf(qbuf, "Do you want to loot %s inventory?",
1387 			s_suffix(x_monnam(u.usteed, ARTICLE_YOUR,
1388 				(char *)0, SUPPRESS_SADDLE, FALSE)));
1389 	    switch (c = ynq(qbuf)) {
1390 		case 'y':
1391 		    if (!u.usteed->minvent) {
1392 			impossible("no saddle?");
1393 			break;
1394 		    }
1395 		    /* TO DO: get and put things into the inventory */
1396 		    You("peek at %s inventory...",
1397 			s_suffix(x_monnam(u.usteed, ARTICLE_YOUR,
1398 				(char *)0, SUPPRESS_SADDLE, FALSE)));
1399 		    (void) display_minventory(u.usteed, MINV_ALL);
1400 		    timepassed = 1;
1401 		    break;
1402 		case 'n':
1403 		    break;
1404 		case 'q':
1405 		    return (0);
1406 	    }
1407 	}
1408 # endif
1409 #endif	/* STEED */
1410 
1411 	/* Preserve pre-3.3.1 behaviour for containers.
1412 	 * Adjust this if-block to allow container looting
1413 	 * from one square away to change that in the future.
1414 	 */
1415 	if (!underfoot) {
1416 	    if (container_at(x, y, FALSE)) {
1417 		if (mtmp) {
1418 		    You("can't loot anything %sthere with %s in the way.",
1419 #ifdef STEED
1420 			    saddled_there ? "else " :
1421 #endif
1422 			    "", mon_nam(mtmp));
1423 		    return timepassed;
1424 		} else {
1425 		    You("have to be at a container to loot it.");
1426 		}
1427 	    } else {
1428 		You("%s %sthere to loot.", dont_find_anything,
1429 #ifdef STEED
1430 			(saddled_there || got_saddle) ? "else " :
1431 #endif
1432 			"");
1433 		return timepassed;
1434 	    }
1435 	}
1436     } else if (c != 'y' && c != 'n') {
1437 	You("%s %s to loot.", dont_find_anything,
1438 		    underfoot ? "here" : "there");
1439     }
1440     return (timepassed);
1441 }
1442 
1443 /*
1444  * Decide whether an object being placed into a magic bag will cause
1445  * it to explode.  If the object is a bag itself, check recursively.
1446  */
1447 STATIC_OVL boolean
mbag_explodes(obj,depthin)1448 mbag_explodes(obj, depthin)
1449     struct obj *obj;
1450     int depthin;
1451 {
1452     /* these won't cause an explosion when they're empty */
1453     if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS) &&
1454 	    obj->spe <= 0)
1455 	return FALSE;
1456 
1457     /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
1458     if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION) &&
1459 	(rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
1460 	return TRUE;
1461     else if (Has_contents(obj)) {
1462 	struct obj *otmp;
1463 
1464 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
1465 	    if (mbag_explodes(otmp, depthin+1)) return TRUE;
1466     }
1467     return FALSE;
1468 }
1469 
1470 /* A variable set in use_container(), to be used by the callback routines   */
1471 /* in_container(), and out_container() from askchain() and use_container(). */
1472 static NEARDATA struct obj *current_container;
1473 #define Icebox (current_container->otyp == ICE_BOX)
1474 
1475 /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
1476 STATIC_PTR int
in_container(obj)1477 in_container(obj)
1478 register struct obj *obj;
1479 {
1480 	register struct obj *gold;
1481 	boolean is_gold = (obj->oclass == GOLD_CLASS);
1482 	boolean floor_container = !carried(current_container);
1483 	char buf[BUFSZ];
1484 
1485 	if (!current_container) {
1486 		impossible("<in> no current_container?");
1487 		return 0;
1488 	} else if (obj == uball || obj == uchain) {
1489 		You("must be kidding.");
1490 		return 0;
1491 	} else if (obj == current_container) {
1492 		pline("That would be an interesting topological exercise.");
1493 		return 0;
1494 	} else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
1495 		Norep("You cannot %s %s you are wearing.",
1496 			Icebox ? "refrigerate" : "stash", something);
1497 		return 0;
1498 	} else if ((obj->otyp == LOADSTONE) && obj->cursed) {
1499 		obj->bknown = 1;
1500 	      pline_The("stone%s won't leave your person.", plur(obj->quan));
1501 		return 0;
1502 	} else if (obj->otyp == AMULET_OF_YENDOR ||
1503 		   obj->otyp == CANDELABRUM_OF_INVOCATION ||
1504 		   obj->otyp == BELL_OF_OPENING ||
1505 		   obj->otyp == SPE_BOOK_OF_THE_DEAD) {
1506 	/* Prohibit Amulets in containers; if you allow it, monsters can't
1507 	 * steal them.  It also becomes a pain to check to see if someone
1508 	 * has the Amulet.  Ditto for the Candelabrum, the Bell and the Book.
1509 	 */
1510 	    pline("%s cannot be confined in such trappings.", The(xname(obj)));
1511 	    return 0;
1512 	} else if (obj->otyp == LEASH && obj->leashmon != 0) {
1513 		pline("%s is attached to your pet.", The(xname(obj)));
1514 		return 0;
1515 	} else if (obj == uwep) {
1516 		if (welded(obj)) {
1517 			weldmsg(obj);
1518 			return 0;
1519 		}
1520 		setuwep((struct obj *) 0);
1521 		if (uwep) return 0;	/* unwielded, died, rewielded */
1522 	} else if (obj == uswapwep) {
1523 		setuswapwep((struct obj *) 0);
1524 		if (uswapwep) return 0;     /* unwielded, died, rewielded */
1525 	} else if (obj == uquiver) {
1526 		setuqwep((struct obj *) 0);
1527 		if (uquiver) return 0;     /* unwielded, died, rewielded */
1528 	}
1529 
1530 	/* boxes, boulders, and big statues can't fit into any container */
1531 	if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER ||
1532 		(obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) {
1533 		/*
1534 		 *  xname() uses a static result array.  Save obj's name
1535 		 *  before current_container's name is computed.  Don't
1536 		 *  use the result of strcpy() within You() --- the order
1537 		 *  of evaluation of the parameters is undefined.
1538 		 */
1539 		Strcpy(buf, the(xname(obj)));
1540 		You("cannot fit %s into %s.", buf,
1541 		    the(xname(current_container)));
1542 		return 0;
1543 	}
1544 
1545 	freeinv(obj);
1546 
1547 	if (is_gold) {	/* look for other money to merge within the container */
1548 		for (gold = current_container->cobj; gold; gold = gold->nobj)
1549 			if (gold->otyp == obj->otyp) break;
1550 	} else
1551 		gold = 0;
1552 
1553 	if (gold) {
1554 		gold->quan += obj->quan;
1555 	} else {
1556 		add_to_container(current_container, obj);
1557 	}
1558 
1559 	current_container->owt = weight(current_container);
1560 
1561 	Strcpy(buf, the(xname(current_container)));
1562 	You("put %s into %s.", doname(obj), buf);
1563 
1564 	if (obj_is_burning(obj))	/* this used to be part of freeinv() */
1565 		(void) snuff_lit(obj);
1566 
1567 	if (floor_container && costly_spot(u.ux, u.uy)) {
1568 		sellobj_state(TRUE);
1569 		sellobj(obj, u.ux, u.uy);
1570 		sellobj_state(FALSE);
1571 	}
1572 	if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN
1573 			&& !Is_candle(obj)) {
1574 		obj->age = monstermoves - obj->age; /* actual age */
1575 		/* stop any corpse timeouts when frozen */
1576 		if (obj->otyp == CORPSE && obj->timed) {
1577 			(void) stop_timer(ROT_CORPSE, (genericptr_t)obj);
1578 			(void) stop_timer(REVIVE_MON, (genericptr_t)obj);
1579 		}
1580 	}
1581 
1582 	else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
1583 		You("are blasted by a magical explosion!");
1584 
1585 		/* the !floor_container case is taken care of */
1586 		if(*u.ushops && costly_spot(u.ux, u.uy) && floor_container) {
1587 		    register struct monst *shkp;
1588 
1589 		    if ((shkp = shop_keeper(*u.ushops)) != 0)
1590 			(void)stolen_value(current_container, u.ux, u.uy,
1591 					   (boolean)shkp->mpeaceful, FALSE);
1592 		}
1593 		delete_contents(current_container);
1594 		if (!floor_container)
1595 			useup(current_container);
1596 		else if (obj_here(current_container, u.ux, u.uy))
1597 			useupf(current_container, obj->quan);
1598 		else
1599 			panic("in_container:  bag not found.");
1600 
1601 		losehp(d(6,6),"magical explosion", KILLED_BY_AN);
1602 		current_container = 0;	/* baggone = TRUE; */
1603 	}
1604 
1605 	if (is_gold) {
1606 		if (gold) dealloc_obj(obj);
1607 		bot();	/* update character's gold piece count immediately */
1608 	}
1609 
1610 	return(current_container ? 1 : -1);
1611 }
1612 
1613 STATIC_PTR int
ck_bag(obj)1614 ck_bag(obj)
1615 struct obj *obj;
1616 {
1617 	return current_container && obj != current_container;
1618 }
1619 
1620 /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
1621 STATIC_PTR int
out_container(obj)1622 out_container(obj)
1623 register struct obj *obj;
1624 {
1625 	register struct obj *otmp;
1626 	boolean is_gold = (obj->oclass == GOLD_CLASS);
1627 	int res, loadlev;
1628 	long count;
1629 
1630 	if (!current_container) {
1631 		impossible("<out> no current_container?");
1632 		return -1;
1633 	} else if (is_gold) {
1634 		obj->owt = weight(obj);
1635 	}
1636 
1637 	if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0;
1638 
1639 	count = obj->quan;
1640 	if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0)
1641 	    return res;
1642 
1643 	if (obj->quan != count && obj->otyp != LOADSTONE)
1644 	    (void) splitobj(obj, count);
1645 
1646 	/* Remove the object from the list. */
1647 	obj_extract_self(obj);
1648 	current_container->owt = weight(current_container);
1649 
1650 	if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN
1651 			&& !Is_candle(obj)) {
1652 		obj->age = monstermoves - obj->age; /* actual age */
1653 		if (obj->otyp == CORPSE)
1654 			start_corpse_timeout(obj);
1655 	}
1656 	/* simulated point of time */
1657 
1658 	if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops))
1659 		verbalize("You sneaky cad! Get out of here with that pick!");
1660 	if(!obj->unpaid && !carried(current_container) &&
1661 	     costly_spot(current_container->ox, current_container->oy)) {
1662 
1663 		obj->ox = current_container->ox;
1664 		obj->oy = current_container->oy;
1665 		addtobill(obj, FALSE, FALSE, FALSE);
1666 	}
1667 
1668 	otmp = addinv(obj);
1669 	loadlev = near_capacity();
1670 	prinv(loadlev ?
1671 	      (loadlev < MOD_ENCUMBER ?
1672 	       "You have a little trouble removing" :
1673 	       "You have much trouble removing") : (char *)0,
1674 	      otmp, count);
1675 
1676 	if (is_gold) {
1677 		dealloc_obj(obj);
1678 		bot();	/* update character's gold piece count immediately */
1679 	}
1680 	return 1;
1681 }
1682 
1683 #undef Icebox
1684 
1685 int
use_container(obj,held)1686 use_container(obj, held)
1687 register struct obj *obj;
1688 register int held;
1689 {
1690 	struct obj *curr, *otmp, *u_gold = (struct obj *)0;
1691 	struct monst *shkp;
1692 	boolean one_by_one, allflag, loot_out = FALSE, loot_in = FALSE;
1693 	char select[MAXOCLASSES+1];
1694 	char qbuf[QBUFSZ];
1695 	long loss = 0L;
1696 	int cnt = 0, used = 0, lcnt = 0,
1697 	    menu_on_request;
1698 
1699 	if (obj->olocked) {
1700 	    pline("%s seems to be locked.", The(xname(obj)));
1701 	    if (held) You("must put it down to unlock.");
1702 	    return 0;
1703 	} else if (obj->otrapped) {
1704 	    if (held) You("open %s...", the(xname(obj)));
1705 	    (void) chest_trap(obj, HAND, FALSE);
1706 	    /* even if the trap fails, you've used up this turn */
1707 	    if (multi >= 0) {	/* in case we didn't become paralyzed */
1708 		nomul(-1);
1709 		nomovemsg = "";
1710 	    }
1711 	    return 1;
1712 	}
1713 	current_container = obj;	/* for use by in/out_container */
1714 
1715 	if (obj->spe == 1) {
1716 	    static NEARDATA const char sc[] = "Schroedinger's Cat";
1717 	    struct obj *ocat;
1718 	    struct monst *cat;
1719 
1720 	    obj->spe = 0;		/* obj->owt will be updated below */
1721 	    /* this isn't really right, since any form of observation
1722 	       (telepathic or monster/object/food detection) ought to
1723 	       force the determination of alive vs dead state; but basing
1724 	       it just on opening the box is much simpler to cope with */
1725 	    cat = rn2(2) ? makemon(&mons[PM_HOUSECAT],
1726 				   obj->ox, obj->oy, NO_MINVENT) : 0;
1727 	    if (cat) {
1728 		cat->mpeaceful = 1;
1729 		set_malign(cat);
1730 		if (Blind)
1731 		    You("think %s brushed your %s.", something,
1732 			body_part(FOOT));
1733 		else
1734 		    pline("%s inside the box is still alive!", Monnam(cat));
1735 		(void) christen_monst(cat, sc);
1736 	    } else {
1737 		ocat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
1738 				       obj->ox, obj->oy, sc);
1739 		if (ocat) {
1740 		    obj_extract_self(ocat);
1741 		    add_to_container(obj, ocat);  /* weight handled below */
1742 		}
1743 		pline_The("%s inside the box is dead!",
1744 		    Hallucination ? rndmonnam() : "housecat");
1745 	    }
1746 	    used = 1;
1747 	}
1748 	/* Count the number of contained objects. Sometimes toss objects if */
1749 	/* a cursed magic bag.						    */
1750 	for (curr = obj->cobj; curr; curr = otmp) {
1751 	    otmp = curr->nobj;
1752 	    if (Is_mbag(obj) && obj->cursed && !rn2(13)) {
1753 		if (curr->dknown)
1754 		    pline("%s to have vanished!", The(aobjnam(curr,"seem")));
1755 		else
1756 		    You("%s %s disappear.", Blind ? "notice" : "see",
1757 							doname(curr));
1758 		obj_extract_self(curr);
1759 		if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) {
1760 		    if(held) {
1761 			if(curr->unpaid)
1762 			    loss += stolen_value(curr, u.ux, u.uy,
1763 					     (boolean)shkp->mpeaceful, TRUE);
1764 			lcnt++;
1765 		    } else if(costly_spot(u.ux, u.uy)) {
1766 			loss += stolen_value(curr, u.ux, u.uy,
1767 					     (boolean)shkp->mpeaceful, TRUE);
1768 			lcnt++;
1769 		    }
1770 		}
1771 		/* obfree() will free all contained objects */
1772 		obfree(curr, (struct obj *) 0);
1773 		used = 1;
1774 	    } else {
1775 		cnt++;
1776 	    }
1777 	}
1778 
1779 	if (cnt && loss)
1780 	    You("owe %ld zorkmids for lost item%s.",
1781 		loss, lcnt > 1 ? "s" : "");
1782 
1783 	obj->owt = weight(obj);
1784 
1785 	if (!cnt) {
1786 	    pline("%s is empty.", Yname2(obj));
1787 	} else {
1788 	    Sprintf(qbuf, "Do you want to take %s out of %s?",
1789 		    something, yname(obj));
1790 	    if (flags.menu_style != MENU_TRADITIONAL) {
1791 		if (flags.menu_style == MENU_FULL) {
1792 		    int t = in_or_out_menu("Do what?", current_container);
1793 		    if (t <= 0) return 0;
1794 		    loot_out = (t & 0x01) != 0;
1795 		    loot_in  = (t & 0x02) != 0;
1796 		} else {	/* MENU_COMBINATION or MENU_PARTIAL */
1797 		    loot_out = (yn_function(qbuf, "ynq", 'n') == 'y');
1798 		}
1799 		if (loot_out) {
1800 		    add_valid_menu_class(0);	/* reset */
1801 		    used |= menu_loot(0, current_container, FALSE) > 0;
1802 		}
1803 	    } else {
1804 		/* traditional code */
1805 ask_again2:
1806 		menu_on_request = 0;
1807 		add_valid_menu_class(0);	/* reset */
1808 		switch (yn_function(qbuf, ":ynq", 'n')) {
1809 		case ':':
1810 		    container_contents(current_container, FALSE, FALSE);
1811 		    goto ask_again2;
1812 		case 'y':
1813 		    if (query_classes(select, &one_by_one, &allflag,
1814 				      "take out", current_container->cobj,
1815 				      FALSE, FALSE, &menu_on_request)) {
1816 			if (askchain((struct obj **)&current_container->cobj,
1817 				     (one_by_one ? (char *)0 : select),
1818 				     allflag, out_container,
1819 				     (int FDECL((*),(OBJ_P)))0,
1820 				     0, "nodot"))
1821 			    used = 1;
1822 		    } else if (menu_on_request < 0) {
1823 			used |= menu_loot(menu_on_request,
1824 					  current_container, FALSE) > 0;
1825 		    }
1826 		    /*FALLTHRU*/
1827 		case 'n':
1828 		    break;
1829 		case 'q':
1830 		default:
1831 		    return used;
1832 		}
1833 	    }
1834 	}
1835 
1836 	if (!invent && u.ugold == 0) {
1837 	    /* nothing to put in, but some feedback is necessary */
1838 	    You("don't have anything to put in.");
1839 	    return used;
1840 	}
1841 	if (flags.menu_style != MENU_FULL || !cnt) {
1842 	    loot_in = (yn_function("Do you wish to put something in?",
1843 				   ynqchars, 'n') == 'y');
1844 	}
1845 	/*
1846 	 * Gone: being nice about only selecting food if we know we are
1847 	 * putting things in an ice chest.
1848 	 */
1849 	if (loot_in) {
1850 	    if (u.ugold) {
1851 		/*
1852 		 * Hack: gold is not in the inventory, so make a gold object
1853 		 * and put it at the head of the inventory list.
1854 		 */
1855 		u_gold = mkgoldobj(u.ugold);	/* removes from u.ugold */
1856 		u.ugold = u_gold->quan;		/* put the gold back */
1857 		assigninvlet(u_gold);		/* might end up as NOINVSYM */
1858 		u_gold->nobj = invent;
1859 		invent = u_gold;
1860 	    }
1861 	    add_valid_menu_class(0);	  /* reset */
1862 	    if (flags.menu_style != MENU_TRADITIONAL) {
1863 		used |= menu_loot(0, current_container, TRUE) > 0;
1864 	    } else {
1865 		/* traditional code */
1866 		menu_on_request = 0;
1867 		if (query_classes(select, &one_by_one, &allflag, "put in",
1868 				   invent, FALSE, (u.ugold != 0L),
1869 				   &menu_on_request)) {
1870 		    (void) askchain((struct obj **)&invent,
1871 				    (one_by_one ? (char *)0 : select), allflag,
1872 				    in_container, ck_bag, 0, "nodot");
1873 		    used = 1;
1874 		} else if (menu_on_request < 0) {
1875 		    used |= menu_loot(menu_on_request,
1876 				      current_container, TRUE) > 0;
1877 		}
1878 	    }
1879 	}
1880 
1881 	if (u_gold && invent && invent->oclass == GOLD_CLASS) {
1882 	    /* didn't stash [all of] it */
1883 	    u_gold = invent;
1884 	    invent = u_gold->nobj;
1885 	    dealloc_obj(u_gold);
1886 	}
1887 
1888 	return used;
1889 }
1890 
1891 /* Loot a container (take things out, put things in), using a menu. */
1892 STATIC_OVL int
menu_loot(retry,container,put_in)1893 menu_loot(retry, container, put_in)
1894 int retry;
1895 struct obj *container;
1896 boolean put_in;
1897 {
1898     int n, i, n_looted = 0;
1899     boolean all_categories = TRUE, loot_everything = FALSE;
1900     char buf[BUFSZ];
1901     const char *takeout = "Take out", *putin = "Put in";
1902     struct obj *otmp, *otmp2;
1903     menu_item *pick_list;
1904     int mflags, res;
1905     long count;
1906 
1907     if (retry) {
1908 	all_categories = (retry == -2);
1909     } else if (flags.menu_style == MENU_FULL) {
1910 	all_categories = FALSE;
1911 	Sprintf(buf,"%s what type of objects?", put_in ? putin : takeout);
1912 	mflags = put_in ? ALL_TYPES : ALL_TYPES|CHOOSE_ALL;
1913 	n = query_category(buf, put_in ? invent : container->cobj,
1914 			   mflags, &pick_list, PICK_ANY);
1915 	if (!n) return 0;
1916 	for (i = 0; i < n; i++) {
1917 	    if (pick_list[i].item.a_int == 'A')
1918 		loot_everything = TRUE;
1919 	    else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
1920 		all_categories = TRUE;
1921 	    else
1922 		add_valid_menu_class(pick_list[i].item.a_int);
1923 	}
1924 	free((genericptr_t) pick_list);
1925     }
1926 
1927     if (loot_everything) {
1928 	for (otmp = container->cobj; otmp; otmp = otmp2) {
1929 	    otmp2 = otmp->nobj;
1930 	    res = out_container(otmp);
1931 	    if (res < 0) break;
1932 	}
1933     } else {
1934 	mflags = INVORDER_SORT;
1935 	if (put_in && flags.invlet_constant) mflags |= USE_INVLET;
1936 	Sprintf(buf,"%s what?", put_in ? putin : takeout);
1937 	n = query_objlist(buf, put_in ? invent : container->cobj,
1938 			  mflags, &pick_list, PICK_ANY,
1939 			  all_categories ? allow_all : allow_category);
1940 	if (n) {
1941 		n_looted = n;
1942 		for (i = 0; i < n; i++) {
1943 		    otmp = pick_list[i].item.a_obj;
1944 		    count = pick_list[i].count;
1945 		    if (count > 0 && count < otmp->quan) {
1946 			otmp2 = splitobj(otmp, count);
1947 			/* special split case also handled by askchain() */
1948 			if (otmp == uwep) setuwep(otmp2);
1949 			if (otmp == uquiver) setuqwep(otmp2);
1950 			if (otmp == uswapwep) setuswapwep(otmp2);
1951 		    }
1952 		    res = put_in ? in_container(otmp) : out_container(otmp);
1953 		    if (res < 0)
1954 			break;
1955 		}
1956 		free((genericptr_t)pick_list);
1957 	}
1958     }
1959     return n_looted;
1960 }
1961 
1962 STATIC_OVL int
in_or_out_menu(prompt,obj)1963 in_or_out_menu(prompt, obj)
1964 const char *prompt;
1965 struct obj *obj;
1966 {
1967     winid win;
1968     anything any;
1969     menu_item *pick_list;
1970     char buf[BUFSZ];
1971     int n;
1972 
1973     any.a_void = 0;
1974     win = create_nhwindow(NHW_MENU);
1975     start_menu(win);
1976     any.a_int = 1;
1977     Sprintf(buf,"Take %s out of %s", something, the(xname(obj)));
1978     add_menu(win, NO_GLYPH, &any, 'a', 0, ATR_NONE, buf, MENU_UNSELECTED);
1979     any.a_int = 2;
1980     Sprintf(buf,"Put %s into %s", something, the(xname(obj)));
1981     add_menu(win, NO_GLYPH, &any, 'b', 0, ATR_NONE, buf, MENU_UNSELECTED);
1982     any.a_int = 3;
1983     add_menu(win, NO_GLYPH, &any, 'c', 0, ATR_NONE,
1984 		"Both of the above", MENU_UNSELECTED);
1985     end_menu(win, prompt);
1986     n = select_menu(win, PICK_ONE, &pick_list);
1987     destroy_nhwindow(win);
1988     if (n > 0) {
1989 	n = pick_list[0].item.a_int;
1990 	free((genericptr_t) pick_list);
1991     }
1992     return n;
1993 }
1994 
1995 /*pickup.c*/
1996