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
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
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
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
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
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
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
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
274  | allow_all(obj)
275  | struct obj *obj;
276  | {
277  |     return TRUE;
278  | }
279  | 
280  | boolean
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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*/