Fandom

Wikihack

Source:Pickup.c

2,034pages on
this wiki
Add New Page
Talk0

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

Below is the full text to src/pickup.c from NetHack 3.4.3. To link to a particular line, write [[pickup.c#line123]], for example.

Top of file Edit

1.    /*	SCCS Id: @(#)pickup.c	3.4	2003/07/27	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
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.   #ifndef GOLDOBJ
13.   STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *,
14.   		const char *,struct obj *,BOOLEAN_P,BOOLEAN_P,int *));
15.   #else
16.   STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *,
17.   		const char *,struct obj *,BOOLEAN_P,int *));
18.   #endif
19.   STATIC_DCL void FDECL(check_here, (BOOLEAN_P));
20.   STATIC_DCL boolean FDECL(n_or_more, (struct obj *));
21.   STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *));
22.   #if 0 /* not used */
23.   STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
24.   #endif
25.   STATIC_DCL int FDECL(autopick, (struct obj*, int, menu_item **));
26.   STATIC_DCL int FDECL(count_categories, (struct obj *,int));
27.   STATIC_DCL long FDECL(carry_count,
28.   		      (struct obj *,struct obj *,long,BOOLEAN_P,int *,int *));
29.   STATIC_DCL int FDECL(lift_object, (struct obj *,struct obj *,long *,BOOLEAN_P));
30.   STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *,int));
31.   STATIC_PTR int FDECL(in_container,(struct obj *));
32.   STATIC_PTR int FDECL(ck_bag,(struct obj *));
33.   STATIC_PTR int FDECL(out_container,(struct obj *));
34.   STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *));
35.   STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
36.   STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P));
37.   STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P));
38.   STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
39.   STATIC_DCL boolean FDECL(able_to_loot, (int, int));
40.   STATIC_DCL boolean FDECL(mon_beside, (int, int));
41.   
42.   /* define for query_objlist() and autopickup() */
43.   #define FOLLOW(curr, flags) \
44.       (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
45.   
46.   /*
47.    *  How much the weight of the given container will change when the given
48.    *  object is removed from it.  This calculation must match the one used
49.    *  by weight() in mkobj.c.
50.    */
51.   #define DELTA_CWT(cont,obj)		\
52.       ((cont)->cursed ? (obj)->owt * 2 :	\
53.   		      1 + ((obj)->owt / ((cont)->blessed ? 4 : 2)))
54.   #define GOLD_WT(n)		(((n) + 50L) / 100L)
55.   /* if you can figure this out, give yourself a hearty pat on the back... */
56.   #define GOLD_CAPACITY(w,n)	(((w) * -100L) - ((n) + 50L) - 1L)
57.   
58.   static const char moderateloadmsg[] = "You have a little trouble lifting";
59.   static const char nearloadmsg[] = "You have much trouble lifting";
60.   static const char overloadmsg[] = "You have extreme difficulty lifting";
61.   

simple_look Edit

62.   /* BUG: this lets you look at cockatrice corpses while blind without
63.      touching them */
64.   /* much simpler version of the look-here code; used by query_classes() */
65.   STATIC_OVL void
66.   simple_look(otmp, here)
67.   struct obj *otmp;	/* list of objects */
68.   boolean here;		/* flag for type of obj list linkage */
69.   {
70.   	/* Neither of the first two cases is expected to happen, since
71.   	 * we're only called after multiple classes of objects have been
72.   	 * detected, hence multiple objects must be present.
73.   	 */
74.   	if (!otmp) {
75.   	    impossible("simple_look(null)");
76.   	} else if (!(here ? otmp->nexthere : otmp->nobj)) {
77.   	    pline("%s", doname(otmp));
78.   	} else {
79.   	    winid tmpwin = create_nhwindow(NHW_MENU);
80.   	    putstr(tmpwin, 0, "");
81.   	    do {
82.   		putstr(tmpwin, 0, doname(otmp));
83.   		otmp = here ? otmp->nexthere : otmp->nobj;
84.   	    } while (otmp);
85.   	    display_nhwindow(tmpwin, TRUE);
86.   	    destroy_nhwindow(tmpwin);
87.   	}
88.   }
89.   

collect_obj_classes Edit

90.   #ifndef GOLDOBJ
91.   int
92.   collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount)
93.   char ilets[];
94.   register struct obj *otmp;
95.   boolean here, incl_gold;
96.   boolean FDECL((*filter),(OBJ_P));
97.   int *itemcount;
98.   #else
99.   int
100.  collect_obj_classes(ilets, otmp, here, filter, itemcount)
101.  char ilets[];
102.  register struct obj *otmp;
103.  boolean here;
104.  boolean FDECL((*filter),(OBJ_P));
105.  int *itemcount;
106.  #endif
107.  {
108.  	register int iletct = 0;
109.  	register char c;
110.  
111.  	*itemcount = 0;
112.  #ifndef GOLDOBJ
113.  	if (incl_gold)
114.  	    ilets[iletct++] = def_oc_syms[COIN_CLASS];
115.  #endif
116.  	ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
117.  	while (otmp) {
118.  	    c = def_oc_syms[(int)otmp->oclass];
119.  	    if (!index(ilets, c) && (!filter || (*filter)(otmp)))
120.  		ilets[iletct++] = c,  ilets[iletct] = '\0';
121.  	    *itemcount += 1;
122.  	    otmp = here ? otmp->nexthere : otmp->nobj;
123.  	}
124.  
125.  	return iletct;
126.  }
127.  

query_classes Edit

128.  /*
129.   * Suppose some '?' and '!' objects are present, but '/' objects aren't:
130.   *	"a" picks all items without further prompting;
131.   *	"A" steps through all items, asking one by one;
132.   *	"?" steps through '?' items, asking, and ignores '!' ones;
133.   *	"/" becomes 'A', since no '/' present;
134.   *	"?a" or "a?" picks all '?' without further prompting;
135.   *	"/a" or "a/" becomes 'A' since there aren't any '/'
136.   *	    (bug fix:  3.1.0 thru 3.1.3 treated it as "a");
137.   *	"?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
138.   *	    (ie, treated as if it had just been "?a").
139.   */
140.  #ifndef GOLDOBJ
141.  STATIC_OVL boolean
142.  query_classes(oclasses, one_at_a_time, everything, action, objs,
143.  	      here, incl_gold, menu_on_demand)
144.  char oclasses[];
145.  boolean *one_at_a_time, *everything;
146.  const char *action;
147.  struct obj *objs;
148.  boolean here, incl_gold;
149.  int *menu_on_demand;
150.  #else
151.  STATIC_OVL boolean
152.  query_classes(oclasses, one_at_a_time, everything, action, objs,
153.  	      here, menu_on_demand)
154.  char oclasses[];
155.  boolean *one_at_a_time, *everything;
156.  const char *action;
157.  struct obj *objs;
158.  boolean here;
159.  int *menu_on_demand;
160.  #endif
161.  {
162.  	char ilets[20], inbuf[BUFSZ];
163.  	int iletct, oclassct;
164.  	boolean not_everything;
165.  	char qbuf[QBUFSZ];
166.  	boolean m_seen;
167.  	int itemcount;
168.  
169.  	oclasses[oclassct = 0] = '\0';
170.  	*one_at_a_time = *everything = m_seen = FALSE;
171.  	iletct = collect_obj_classes(ilets, objs, here,
172.  #ifndef GOLDOBJ
173.  				     incl_gold,
174.  #endif
175.  				     (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
176.  	if (iletct == 0) {
177.  		return FALSE;
178.  	} else if (iletct == 1) {
179.  		oclasses[0] = def_char_to_objclass(ilets[0]);
180.  		oclasses[1] = '\0';
181.  		if (itemcount && menu_on_demand) {
182.  			ilets[iletct++] = 'm';
183.  			*menu_on_demand = 0;
184.  			ilets[iletct] = '\0';
185.  		}
186.  	} else  {	/* more than one choice available */
187.  		const char *where = 0;
188.  		register char sym, oc_of_sym, *p;
189.  		/* additional choices */
190.  		ilets[iletct++] = ' ';
191.  		ilets[iletct++] = 'a';
192.  		ilets[iletct++] = 'A';
193.  		ilets[iletct++] = (objs == invent ? 'i' : ':');
194.  		if (menu_on_demand) {
195.  			ilets[iletct++] = 'm';
196.  			*menu_on_demand = 0;
197.  		}
198.  		ilets[iletct] = '\0';
199.  ask_again:
200.  		oclasses[oclassct = 0] = '\0';
201.  		*one_at_a_time = *everything = FALSE;
202.  		not_everything = FALSE;
203.  		Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
204.  			action, ilets);
205.  		getlin(qbuf,inbuf);
206.  		if (*inbuf == '\033') return FALSE;
207.  
208.  		for (p = inbuf; (sym = *p++); ) {
209.  		    /* new A function (selective all) added by GAN 01/09/87 */
210.  		    if (sym == ' ') continue;
211.  		    else if (sym == 'A') *one_at_a_time = TRUE;
212.  		    else if (sym == 'a') *everything = TRUE;
213.  		    else if (sym == ':') {
214.  			simple_look(objs, here);  /* dumb if objs==invent */
215.  			goto ask_again;
216.  		    } else if (sym == 'i') {
217.  			(void) display_inventory((char *)0, TRUE);
218.  			goto ask_again;
219.  		    } else if (sym == 'm') {
220.  			m_seen = TRUE;
221.  		    } else {
222.  			oc_of_sym = def_char_to_objclass(sym);
223.  			if (index(ilets,sym)) {
224.  			    add_valid_menu_class(oc_of_sym);
225.  			    oclasses[oclassct++] = oc_of_sym;
226.  			    oclasses[oclassct] = '\0';
227.  			} else {
228.  			    if (!where)
229.  				where = !strcmp(action,"pick up")  ? "here" :
230.  					!strcmp(action,"take out") ?
231.  							    "inside" : "";
232.  			    if (*where)
233.  				There("are no %c's %s.", sym, where);
234.  			    else
235.  				You("have no %c's.", sym);
236.  			    not_everything = TRUE;
237.  			}
238.  		    }
239.  		}
240.  		if (m_seen && menu_on_demand) {
241.  			*menu_on_demand = (*everything || !oclassct) ? -2 : -3;
242.  			return FALSE;
243.  		}
244.  		if (!oclassct && (!*everything || not_everything)) {
245.  		    /* didn't pick anything,
246.  		       or tried to pick something that's not present */
247.  		    *one_at_a_time = TRUE;	/* force 'A' */
248.  		    *everything = FALSE;	/* inhibit 'a' */
249.  		}
250.  	}
251.  	return TRUE;
252.  }
253.  

check_here Edit

254.  /* look at the objects at our location, unless there are too many of them */
255.  STATIC_OVL void
256.  check_here(picked_some)
257.  boolean picked_some;
258.  {
259.  	register struct obj *obj;
260.  	register int ct = 0;
261.  
262.  	/* count the objects here */
263.  	for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) {
264.  	    if (obj != uchain)
265.  		ct++;
266.  	}
267.  
268.  	/* If there are objects here, take a look. */
269.  	if (ct) {
270.  	    if (flags.run) nomul(0);
271.  	    flush_screen(1);
272.  	    (void) look_here(ct, picked_some);
273.  	} else {
274.  	    read_engr_at(u.ux,u.uy);
275.  	}
276.  }
277.  

n_or_more Edit

278.  /* Value set by query_objlist() for n_or_more(). */
279.  static long val_for_n_or_more;
280.  
281.  /* query_objlist callback: return TRUE if obj's count is >= reference value */
282.  STATIC_OVL boolean
283.  n_or_more(obj)
284.  struct obj *obj;
285.  {
286.      if (obj == uchain) return FALSE;
287.      return (obj->quan >= val_for_n_or_more);
288.  }
289.  

add_valid_menu_class Edit

290.  /* List of valid menu classes for query_objlist() and allow_category callback */
291.  static char valid_menu_classes[MAXOCLASSES + 2];
292.  
293.  void
294.  add_valid_menu_class(c)
295.  int c;
296.  {
297.  	static int vmc_count = 0;
298.  
299.  	if (c == 0)  /* reset */
300.  	  vmc_count = 0;
301.  	else
302.  	  valid_menu_classes[vmc_count++] = (char)c;
303.  	valid_menu_classes[vmc_count] = '\0';
304.  }
305.  

all_but_uchain Edit

306.  /* query_objlist callback: return TRUE if not uchain */
307.  STATIC_OVL boolean
308.  all_but_uchain(obj)
309.  struct obj *obj;
310.  {
311.      return (obj != uchain);
312.  }
313.  

allow_all Edit

314.  /* query_objlist callback: return TRUE */
315.  /*ARGSUSED*/
316.  boolean
317.  allow_all(obj)
318.  struct obj *obj;
319.  {
320.      return TRUE;
321.  }
322.  

allow_category Edit

323.  boolean
324.  allow_category(obj)
325.  struct obj *obj;
326.  {
327.      if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
328.      if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
329.  	(index(valid_menu_classes, obj->oclass) != (char *)0))
330.  	return TRUE;
331.      else if (((index(valid_menu_classes,'U') != (char *)0) &&
332.  	(obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed)))
333.  	return TRUE;
334.      else if (((index(valid_menu_classes,'B') != (char *)0) &&
335.  	(obj->oclass != COIN_CLASS && obj->bknown && obj->blessed)))
336.  	return TRUE;
337.      else if (((index(valid_menu_classes,'C') != (char *)0) &&
338.  	(obj->oclass != COIN_CLASS && obj->bknown && obj->cursed)))
339.  	return TRUE;
340.      else if (((index(valid_menu_classes,'X') != (char *)0) &&
341.  	(obj->oclass != COIN_CLASS && !obj->bknown)))
342.  	return TRUE;
343.      else
344.  	return FALSE;
345.  }
346.  

allow_cat_no_uchain Edit

347.  #if 0 /* not used */
348.  /* query_objlist callback: return TRUE if valid category (class), no uchain */
349.  STATIC_OVL boolean
350.  allow_cat_no_uchain(obj)
351.  struct obj *obj;
352.  {
353.      if ((obj != uchain) &&
354.  	(((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) ||
355.  	(index(valid_menu_classes, obj->oclass) != (char *)0)))
356.  	return TRUE;
357.      else
358.  	return FALSE;
359.  }
360.  #endif
361.  

is_worn_by_type Edit

362.  /* query_objlist callback: return TRUE if valid class and worn */
363.  boolean
364.  is_worn_by_type(otmp)
365.  register struct obj *otmp;
366.  {
367.  	return((boolean)(!!(otmp->owornmask &
368.  			(W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER)))
369.  	        && (index(valid_menu_classes, otmp->oclass) != (char *)0));
370.  }
371.  

pickup Edit

372.  /*
373.   * Have the hero pick things from the ground
374.   * or a monster's inventory if swallowed.
375.   *
376.   * Arg what:
377.   *	>0  autopickup
378.   *	=0  interactive
379.   *	<0  pickup count of something
380.   *
381.   * Returns 1 if tried to pick something up, whether
382.   * or not it succeeded.
383.   */
384.  int
385.  pickup(what)
386.  int what;		/* should be a long */
387.  {
388.  	int i, n, res, count, n_tried = 0, n_picked = 0;
389.  	menu_item *pick_list = (menu_item *) 0;
390.  	boolean autopickup = what > 0;
391.  	struct obj *objchain;
392.  	int traverse_how;
393.  
394.  	if (what < 0)		/* pick N of something */
395.  	    count = -what;
396.  	else			/* pick anything */
397.  	    count = 0;
398.  
399.  	if (!u.uswallow) {
400.  		struct trap *ttmp = t_at(u.ux, u.uy);
401.  		/* no auto-pick if no-pick move, nothing there, or in a pool */
402.  		if (autopickup && (flags.nopick || !OBJ_AT(u.ux, u.uy) ||
403.  			(is_pool(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) {
404.  			read_engr_at(u.ux, u.uy);
405.  			return (0);
406.  		}
407.  
408.  		/* no pickup if levitating & not on air or water level */
409.  		if (!can_reach_floor()) {
410.  		    if ((multi && !flags.run) || (autopickup && !flags.pickup))
411.  			read_engr_at(u.ux, u.uy);
412.  		    return (0);
413.  		}
414.  		if (ttmp && ttmp->tseen) {
415.  		    /* Allow pickup from holes and trap doors that you escaped
416.  		     * from because that stuff is teetering on the edge just
417.  		     * like you, but not pits, because there is an elevation
418.  		     * discrepancy with stuff in pits.
419.  		     */
420.  		    if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) &&
421.  			(!u.utrap || (u.utrap && u.utraptype != TT_PIT))) {
422.  			read_engr_at(u.ux, u.uy);
423.  			return(0);
424.  		    }
425.  		}
426.  		/* multi && !flags.run means they are in the middle of some other
427.  		 * action, or possibly paralyzed, sleeping, etc.... and they just
428.  		 * teleported onto the object.  They shouldn't pick it up.
429.  		 */
430.  		if ((multi && !flags.run) || (autopickup && !flags.pickup)) {
431.  		    check_here(FALSE);
432.  		    return (0);
433.  		}
434.  		if (notake(youmonst.data)) {
435.  		    if (!autopickup)
436.  			You("are physically incapable of picking anything up.");
437.  		    else
438.  			check_here(FALSE);
439.  		    return (0);
440.  		}
441.  
442.  		/* if there's anything here, stop running */
443.  		if (OBJ_AT(u.ux,u.uy) && flags.run && flags.run != 8 && !flags.nopick) nomul(0);
444.  	}
445.  
446.  	add_valid_menu_class(0);	/* reset */
447.  	if (!u.uswallow) {
448.  		objchain = level.objects[u.ux][u.uy];
449.  		traverse_how = BY_NEXTHERE;
450.  	} else {
451.  		objchain = u.ustuck->minvent;
452.  		traverse_how = 0;	/* nobj */
453.  	}
454.  	/*
455.  	 * Start the actual pickup process.  This is split into two main
456.  	 * sections, the newer menu and the older "traditional" methods.
457.  	 * Automatic pickup has been split into its own menu-style routine
458.  	 * to make things less confusing.
459.  	 */
460.  	if (autopickup) {
461.  	    n = autopick(objchain, traverse_how, &pick_list);
462.  	    goto menu_pickup;
463.  	}
464.  
465.  	if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) {
466.  
467.  	    /* use menus exclusively */
468.  	    if (count) {	/* looking for N of something */
469.  		char buf[QBUFSZ];
470.  		Sprintf(buf, "Pick %d of what?", count);
471.  		val_for_n_or_more = count;	/* set up callback selector */
472.  		n = query_objlist(buf, objchain,
473.  			    traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT,
474.  			    &pick_list, PICK_ONE, n_or_more);
475.  		/* correct counts, if any given */
476.  		for (i = 0; i < n; i++)
477.  		    pick_list[i].count = count;
478.  	    } else {
479.  		n = query_objlist("Pick up what?", objchain,
480.  			traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT|FEEL_COCKATRICE,
481.  			&pick_list, PICK_ANY, all_but_uchain);
482.  	    }
483.  menu_pickup:
484.  	    n_tried = n;
485.  	    for (n_picked = i = 0 ; i < n; i++) {
486.  		res = pickup_object(pick_list[i].item.a_obj,pick_list[i].count,
487.  					FALSE);
488.  		if (res < 0) break;	/* can't continue */
489.  		n_picked += res;
490.  	    }
491.  	    if (pick_list) free((genericptr_t)pick_list);
492.  
493.  	} else {
494.  	    /* old style interface */
495.  	    int ct = 0;
496.  	    long lcount;
497.  	    boolean all_of_a_type, selective;
498.  	    char oclasses[MAXOCLASSES];
499.  	    struct obj *obj, *obj2;
500.  
501.  	    oclasses[0] = '\0';		/* types to consider (empty for all) */
502.  	    all_of_a_type = TRUE;	/* take all of considered types */
503.  	    selective = FALSE;		/* ask for each item */
504.  
505.  	    /* check for more than one object */
506.  	    for (obj = objchain;
507.  		  obj; obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj)
508.  		ct++;
509.  
510.  	    if (ct == 1 && count) {
511.  		/* if only one thing, then pick it */
512.  		obj = objchain;
513.  		lcount = min(obj->quan, (long)count);
514.  		n_tried++;
515.  		if (pickup_object(obj, lcount, FALSE) > 0)
516.  		    n_picked++;	/* picked something */
517.  		goto end_query;
518.  
519.  	    } else if (ct >= 2) {
520.  		int via_menu = 0;
521.  
522.  		There("are %s objects here.",
523.  		      (ct <= 10) ? "several" : "many");
524.  		if (!query_classes(oclasses, &selective, &all_of_a_type,
525.  				   "pick up", objchain,
526.  				   traverse_how == BY_NEXTHERE,
527.  #ifndef GOLDOBJ
528.  				   FALSE,
529.  #endif
530.  				   &via_menu)) {
531.  		    if (!via_menu) return (0);
532.  		    n = query_objlist("Pick up what?",
533.  				  objchain,
534.  				  traverse_how|(selective ? 0 : INVORDER_SORT),
535.  				  &pick_list, PICK_ANY,
536.  				  via_menu == -2 ? allow_all : allow_category);
537.  		    goto menu_pickup;
538.  		}
539.  	    }
540.  
541.  	    for (obj = objchain; obj; obj = obj2) {
542.  		if (traverse_how == BY_NEXTHERE)
543.  			obj2 = obj->nexthere;	/* perhaps obj will be picked up */
544.  		else
545.  			obj2 = obj->nobj;
546.  		lcount = -1L;
547.  
548.  		if (!selective && oclasses[0] && !index(oclasses,obj->oclass))
549.  		    continue;
550.  
551.  		if (!all_of_a_type) {
552.  		    char qbuf[BUFSZ];
553.  		    Sprintf(qbuf, "Pick up %s?",
554.  			safe_qbuf("", sizeof("Pick up ?"), doname(obj),
555.  					an(simple_typename(obj->otyp)), "something"));
556.  		    switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
557.  		    case 'q': goto end_query;	/* out 2 levels */
558.  		    case 'n': continue;
559.  		    case 'a':
560.  			all_of_a_type = TRUE;
561.  			if (selective) {
562.  			    selective = FALSE;
563.  			    oclasses[0] = obj->oclass;
564.  			    oclasses[1] = '\0';
565.  			}
566.  			break;
567.  		    case '#':	/* count was entered */
568.  			if (!yn_number) continue; /* 0 count => No */
569.  			lcount = (long) yn_number;
570.  			if (lcount > obj->quan) lcount = obj->quan;
571.  			/* fall thru */
572.  		    default:	/* 'y' */
573.  			break;
574.  		    }
575.  		}
576.  		if (lcount == -1L) lcount = obj->quan;
577.  
578.  		n_tried++;
579.  		if ((res = pickup_object(obj, lcount, FALSE)) < 0) break;
580.  		n_picked += res;
581.  	    }
582.  end_query:
583.  	    ;	/* semicolon needed by brain-damaged compilers */
584.  	}
585.  
586.  	if (!u.uswallow) {
587.  		if (!OBJ_AT(u.ux,u.uy)) u.uundetected = 0;
588.  
589.  		/* position may need updating (invisible hero) */
590.  		if (n_picked) newsym(u.ux,u.uy);
591.  
592.  		/* see whether there's anything else here, after auto-pickup is done */
593.  		if (autopickup) check_here(n_picked > 0);
594.  	}
595.  	return (n_tried > 0);
596.  }
597.  

is_autopickup_exception Edit

598.  #ifdef AUTOPICKUP_EXCEPTIONS
599.  boolean
600.  is_autopickup_exception(obj, grab)
601.  struct obj *obj;
602.  boolean grab;	 /* forced pickup, rather than forced leave behind? */
603.  {
604.  	/*
605.  	 *  Does the text description of this match an exception?
606.  	 */
607.  	char *objdesc = makesingular(doname(obj));
608.  	struct autopickup_exception *ape = (grab) ?
609.  					iflags.autopickup_exceptions[AP_GRAB] :
610.  					iflags.autopickup_exceptions[AP_LEAVE];
611.  	while (ape) {
612.  		if (pmatch(ape->pattern, objdesc)) return TRUE;
613.  		ape = ape->next;
614.  	}
615.  	return FALSE;
616.  }
617.  #endif /* AUTOPICKUP_EXCEPTIONS */
618.  

autopick Edit

619.  /*
620.   * Pick from the given list using flags.pickup_types.  Return the number
621.   * of items picked (not counts).  Create an array that returns pointers
622.   * and counts of the items to be picked up.  If the number of items
623.   * picked is zero, the pickup list is left alone.  The caller of this
624.   * function must free the pickup list.
625.   */
626.  STATIC_OVL int
627.  autopick(olist, follow, pick_list)
628.  struct obj *olist;	/* the object list */
629.  int follow;		/* how to follow the object list */
630.  menu_item **pick_list;	/* list of objects and counts to pick up */
631.  {
632.  	menu_item *pi;	/* pick item */
633.  	struct obj *curr;
634.  	int n;
635.  	const char *otypes = flags.pickup_types;
636.  
637.  	/* first count the number of eligible items */
638.  	for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
639.  
640.  
641.  #ifndef AUTOPICKUP_EXCEPTIONS
642.  	    if (!*otypes || index(otypes, curr->oclass))
643.  #else
644.  	    if ((!*otypes || index(otypes, curr->oclass) ||
645.  		 is_autopickup_exception(curr, TRUE)) &&
646.  	    	 !is_autopickup_exception(curr, FALSE))
647.  #endif
648.  		n++;
649.  
650.  	if (n) {
651.  	    *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n);
652.  	    for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
653.  #ifndef AUTOPICKUP_EXCEPTIONS
654.  		if (!*otypes || index(otypes, curr->oclass)) {
655.  #else
656.  	    if ((!*otypes || index(otypes, curr->oclass) ||
657.  		 is_autopickup_exception(curr, TRUE)) &&
658.  	    	 !is_autopickup_exception(curr, FALSE)) {
659.  #endif
660.  		    pi[n].item.a_obj = curr;
661.  		    pi[n].count = curr->quan;
662.  		    n++;
663.  		}
664.  	}
665.  	return n;
666.  }
667.  
668.  

query_objlist Edit

669.  /*
670.   * Put up a menu using the given object list.  Only those objects on the
671.   * list that meet the approval of the allow function are displayed.  Return
672.   * a count of the number of items selected, as well as an allocated array of
673.   * menu_items, containing pointers to the objects selected and counts.  The
674.   * returned counts are guaranteed to be in bounds and non-zero.
675.   *
676.   * Query flags:
677.   *	BY_NEXTHERE	  - Follow object list via nexthere instead of nobj.
678.   *	AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
679.   *			    use it.
680.   *	USE_INVLET	  - Use object's invlet.
681.   *	INVORDER_SORT	  - Use hero's pack order.
682.   *	SIGNAL_NOMENU	  - Return -1 rather than 0 if nothing passes "allow".
683.   */
684.  int
685.  query_objlist(qstr, olist, qflags, pick_list, how, allow)
686.  const char *qstr;		/* query string */
687.  struct obj *olist;		/* the list to pick from */
688.  int qflags;			/* options to control the query */
689.  menu_item **pick_list;		/* return list of items picked */
690.  int how;			/* type of query */
691.  boolean FDECL((*allow), (OBJ_P));/* allow function */
692.  {
693.  	int n;
694.  	winid win;
695.  	struct obj *curr, *last;
696.  	char *pack;
697.  	anything any;
698.  	boolean printed_type_name;
699.  
700.  	*pick_list = (menu_item *) 0;
701.  	if (!olist) return 0;
702.  
703.  	/* count the number of items allowed */
704.  	for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags))
705.  	    if ((*allow)(curr)) {
706.  		last = curr;
707.  		n++;
708.  	    }
709.  
710.  	if (n == 0)	/* nothing to pick here */
711.  	    return (qflags & SIGNAL_NOMENU) ? -1 : 0;
712.  
713.  	if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
714.  	    *pick_list = (menu_item *) alloc(sizeof(menu_item));
715.  	    (*pick_list)->item.a_obj = last;
716.  	    (*pick_list)->count = last->quan;
717.  	    return 1;
718.  	}
719.  
720.  	win = create_nhwindow(NHW_MENU);
721.  	start_menu(win);
722.  	any.a_obj = (struct obj *) 0;
723.  
724.  	/*
725.  	 * Run through the list and add the objects to the menu.  If
726.  	 * INVORDER_SORT is set, we'll run through the list once for
727.  	 * each type so we can group them.  The allow function will only
728.  	 * be called once per object in the list.
729.  	 */
730.  	pack = flags.inv_order;
731.  	do {
732.  	    printed_type_name = FALSE;
733.  	    for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
734.  		if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE &&
735.  		     will_feel_cockatrice(curr, FALSE)) {
736.  			destroy_nhwindow(win);	/* stop the menu and revert */
737.  			(void) look_here(0, FALSE);
738.  			return 0;
739.  		}
740.  		if ((!(qflags & INVORDER_SORT) || curr->oclass == *pack)
741.  							&& (*allow)(curr)) {
742.  
743.  		    /* if sorting, print type name (once only) */
744.  		    if (qflags & INVORDER_SORT && !printed_type_name) {
745.  			any.a_obj = (struct obj *) 0;
746.  			add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
747.  					let_to_name(*pack, FALSE), MENU_UNSELECTED);
748.  			printed_type_name = TRUE;
749.  		    }
750.  
751.  		    any.a_obj = curr;
752.  		    add_menu(win, obj_to_glyph(curr), &any,
753.  			    qflags & USE_INVLET ? curr->invlet : 0,
754.  			    def_oc_syms[(int)objects[curr->otyp].oc_class],
755.  			    ATR_NONE, doname(curr), MENU_UNSELECTED);
756.  		}
757.  	    }
758.  	    pack++;
759.  	} while (qflags & INVORDER_SORT && *pack);
760.  
761.  	end_menu(win, qstr);
762.  	n = select_menu(win, how, pick_list);
763.  	destroy_nhwindow(win);
764.  
765.  	if (n > 0) {
766.  	    menu_item *mi;
767.  	    int i;
768.  
769.  	    /* fix up counts:  -1 means no count used => pick all */
770.  	    for (i = 0, mi = *pick_list; i < n; i++, mi++)
771.  		if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
772.  		    mi->count = mi->item.a_obj->quan;
773.  	} else if (n < 0) {
774.  	    n = 0;	/* caller's don't expect -1 */
775.  	}
776.  	return n;
777.  }
778.  

query_category Edit

779.  /*
780.   * allow menu-based category (class) selection (for Drop,take off etc.)
781.   *
782.   */
783.  int
784.  query_category(qstr, olist, qflags, pick_list, how)
785.  const char *qstr;		/* query string */
786.  struct obj *olist;		/* the list to pick from */
787.  int qflags;			/* behaviour modification flags */
788.  menu_item **pick_list;		/* return list of items picked */
789.  int how;			/* type of query */
790.  {
791.  	int n;
792.  	winid win;
793.  	struct obj *curr;
794.  	char *pack;
795.  	anything any;
796.  	boolean collected_type_name;
797.  	char invlet;
798.  	int ccount;
799.  	boolean do_unpaid = FALSE;
800.  	boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
801.  	    do_buc_unknown = FALSE;
802.  	int num_buc_types = 0;
803.  
804.  	*pick_list = (menu_item *) 0;
805.  	if (!olist) return 0;
806.  	if ((qflags & UNPAID_TYPES) && count_unpaid(olist)) do_unpaid = TRUE;
807.  	if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) {
808.  	    do_blessed = TRUE;
809.  	    num_buc_types++;
810.  	}
811.  	if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) {
812.  	    do_cursed = TRUE;
813.  	    num_buc_types++;
814.  	}
815.  	if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) {
816.  	    do_uncursed = TRUE;
817.  	    num_buc_types++;
818.  	}
819.  	if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) {
820.  	    do_buc_unknown = TRUE;
821.  	    num_buc_types++;
822.  	}
823.  
824.  	ccount = count_categories(olist, qflags);
825.  	/* no point in actually showing a menu for a single category */
826.  	if (ccount == 1 && !do_unpaid && num_buc_types <= 1 && !(qflags & BILLED_TYPES)) {
827.  	    for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
828.  		if ((qflags & WORN_TYPES) &&
829.  		    !(curr->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL|W_WEP|W_SWAPWEP|W_QUIVER)))
830.  		    continue;
831.  		break;
832.  	    }
833.  	    if (curr) {
834.  		*pick_list = (menu_item *) alloc(sizeof(menu_item));
835.  		(*pick_list)->item.a_int = curr->oclass;
836.  		return 1;
837.  	    } else {
838.  #ifdef DEBUG
839.  		impossible("query_category: no single object match");
840.  #endif
841.  	    }
842.  	    return 0;
843.  	}
844.  
845.  	win = create_nhwindow(NHW_MENU);
846.  	start_menu(win);
847.  	pack = flags.inv_order;
848.  	if ((qflags & ALL_TYPES) && (ccount > 1)) {
849.  		invlet = 'a';
850.  		any.a_void = 0;
851.  		any.a_int = ALL_TYPES_SELECTED;
852.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
853.  		       (qflags & WORN_TYPES) ? "All worn types" : "All types",
854.  			MENU_UNSELECTED);
855.  		invlet = 'b';
856.  	} else
857.  		invlet = 'a';
858.  	do {
859.  	    collected_type_name = FALSE;
860.  	    for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
861.  		if (curr->oclass == *pack) {
862.  		   if ((qflags & WORN_TYPES) &&
863.  		   		!(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
864.  		    	W_WEP | W_SWAPWEP | W_QUIVER)))
865.  			 continue;
866.  		   if (!collected_type_name) {
867.  			any.a_void = 0;
868.  			any.a_int = curr->oclass;
869.  			add_menu(win, NO_GLYPH, &any, invlet++,
870.  				def_oc_syms[(int)objects[curr->otyp].oc_class],
871.  				ATR_NONE, let_to_name(*pack, FALSE),
872.  				MENU_UNSELECTED);
873.  			collected_type_name = TRUE;
874.  		   }
875.  		}
876.  	    }
877.  	    pack++;
878.  	    if (invlet >= 'u') {
879.  		impossible("query_category: too many categories");
880.  		return 0;
881.  	    }
882.  	} while (*pack);
883.  	/* unpaid items if there are any */
884.  	if (do_unpaid) {
885.  		invlet = 'u';
886.  		any.a_void = 0;
887.  		any.a_int = 'u';
888.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
889.  			"Unpaid items", MENU_UNSELECTED);
890.  	}
891.  	/* billed items: checked by caller, so always include if BILLED_TYPES */
892.  	if (qflags & BILLED_TYPES) {
893.  		invlet = 'x';
894.  		any.a_void = 0;
895.  		any.a_int = 'x';
896.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
897.  			 "Unpaid items already used up", MENU_UNSELECTED);
898.  	}
899.  	if (qflags & CHOOSE_ALL) {
900.  		invlet = 'A';
901.  		any.a_void = 0;
902.  		any.a_int = 'A';
903.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
904.  			(qflags & WORN_TYPES) ?
905.  			"Auto-select every item being worn" :
906.  			"Auto-select every item", MENU_UNSELECTED);
907.  	}
908.  	/* items with b/u/c/unknown if there are any */
909.  	if (do_blessed) {
910.  		invlet = 'B';
911.  		any.a_void = 0;
912.  		any.a_int = 'B';
913.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
914.  			"Items known to be Blessed", MENU_UNSELECTED);
915.  	}
916.  	if (do_cursed) {
917.  		invlet = 'C';
918.  		any.a_void = 0;
919.  		any.a_int = 'C';
920.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
921.  			"Items known to be Cursed", MENU_UNSELECTED);
922.  	}
923.  	if (do_uncursed) {
924.  		invlet = 'U';
925.  		any.a_void = 0;
926.  		any.a_int = 'U';
927.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
928.  			"Items known to be Uncursed", MENU_UNSELECTED);
929.  	}
930.  	if (do_buc_unknown) {
931.  		invlet = 'X';
932.  		any.a_void = 0;
933.  		any.a_int = 'X';
934.  		add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
935.  			"Items of unknown B/C/U status",
936.  			MENU_UNSELECTED);
937.  	}
938.  	end_menu(win, qstr);
939.  	n = select_menu(win, how, pick_list);
940.  	destroy_nhwindow(win);
941.  	if (n < 0)
942.  	    n = 0;	/* caller's don't expect -1 */
943.  	return n;
944.  }
945.  

count_categories Edit

946.  STATIC_OVL int
947.  count_categories(olist, qflags)
948.  struct obj *olist;
949.  int qflags;
950.  {
951.  	char *pack;
952.  	boolean counted_category;
953.  	int ccount = 0;
954.  	struct obj *curr;
955.  
956.  	pack = flags.inv_order;
957.  	do {
958.  	    counted_category = FALSE;
959.  	    for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
960.  		if (curr->oclass == *pack) {
961.  		   if ((qflags & WORN_TYPES) &&
962.  		    	!(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
963.  		    	W_WEP | W_SWAPWEP | W_QUIVER)))
964.  			 continue;
965.  		   if (!counted_category) {
966.  			ccount++;
967.  			counted_category = TRUE;
968.  		   }
969.  		}
970.  	    }
971.  	    pack++;
972.  	} while (*pack);
973.  	return ccount;
974.  }
975.  

carry_count Edit

976.  /* could we carry `obj'? if not, could we carry some of it/them? */
977.  STATIC_OVL long
978.  carry_count(obj, container, count, telekinesis, wt_before, wt_after)
979.  struct obj *obj, *container;	/* object to pick up, bag it's coming out of */
980.  long count;
981.  boolean telekinesis;
982.  int *wt_before, *wt_after;
983.  {
984.      boolean adjust_wt = container && carried(container),
985.  	    is_gold = obj->oclass == COIN_CLASS;
986.      int wt, iw, ow, oow;
987.      long qq, savequan;
988.  #ifdef GOLDOBJ
989.      long umoney = money_cnt(invent);
990.  #endif
991.      unsigned saveowt;
992.      const char *verb, *prefx1, *prefx2, *suffx;
993.      char obj_nambuf[BUFSZ], where[BUFSZ];
994.  
995.      savequan = obj->quan;
996.      saveowt = obj->owt;
997.  
998.      iw = max_capacity();
999.  
1000.     if (count != savequan) {
1001. 	obj->quan = count;
1002. 	obj->owt = (unsigned)weight(obj);
1003.     }
1004.     wt = iw + (int)obj->owt;
1005.     if (adjust_wt)
1006. 	wt -= (container->otyp == BAG_OF_HOLDING) ?
1007. 		(int)DELTA_CWT(container, obj) : (int)obj->owt;
1008. #ifndef GOLDOBJ
1009.     if (is_gold)	/* merged gold might affect cumulative weight */
1010. 	wt -= (GOLD_WT(u.ugold) + GOLD_WT(count) - GOLD_WT(u.ugold + count));
1011. #else
1012.     /* This will go with silver+copper & new gold weight */
1013.     if (is_gold)	/* merged gold might affect cumulative weight */
1014. 	wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count));
1015. #endif
1016.     if (count != savequan) {
1017. 	obj->quan = savequan;
1018. 	obj->owt = saveowt;
1019.     }
1020.     *wt_before = iw;
1021.     *wt_after  = wt;
1022. 
1023.     if (wt < 0)
1024. 	return count;
1025. 
1026.     /* see how many we can lift */
1027.     if (is_gold) {
1028. #ifndef GOLDOBJ
1029. 	iw -= (int)GOLD_WT(u.ugold);
1030. 	if (!adjust_wt) {
1031. 	    qq = GOLD_CAPACITY((long)iw, u.ugold);
1032. 	} else {
1033. 	    oow = 0;
1034. 	    qq = 50L - (u.ugold % 100L) - 1L;
1035. #else
1036. 	iw -= (int)GOLD_WT(umoney);
1037. 	if (!adjust_wt) {
1038. 	    qq = GOLD_CAPACITY((long)iw, umoney);
1039. 	} else {
1040. 	    oow = 0;
1041. 	    qq = 50L - (umoney % 100L) - 1L;
1042. #endif
1043. 	    if (qq < 0L) qq += 100L;
1044. 	    for ( ; qq <= count; qq += 100L) {
1045. 		obj->quan = qq;
1046. 		obj->owt = (unsigned)GOLD_WT(qq);
1047. #ifndef GOLDOBJ
1048. 		ow = (int)GOLD_WT(u.ugold + qq);
1049. #else
1050. 		ow = (int)GOLD_WT(umoney + qq);
1051. #endif
1052. 		ow -= (container->otyp == BAG_OF_HOLDING) ?
1053. 			(int)DELTA_CWT(container, obj) : (int)obj->owt;
1054. 		if (iw + ow >= 0) break;
1055. 		oow = ow;
1056. 	    }
1057. 	    iw -= oow;
1058. 	    qq -= 100L;
1059. 	}
1060. 	if (qq < 0L) qq = 0L;
1061. 	else if (qq > count) qq = count;
1062. #ifndef GOLDOBJ
1063. 	wt = iw + (int)GOLD_WT(u.ugold + qq);
1064. #else
1065. 	wt = iw + (int)GOLD_WT(umoney + qq);
1066. #endif
1067.     } else if (count > 1 || count < obj->quan) {
1068. 	/*
1069. 	 * Ugh. Calc num to lift by changing the quan of of the
1070. 	 * object and calling weight.
1071. 	 *
1072. 	 * This works for containers only because containers
1073. 	 * don't merge.		-dean
1074. 	 */
1075. 	for (qq = 1L; qq <= count; qq++) {
1076. 	    obj->quan = qq;
1077. 	    obj->owt = (unsigned)(ow = weight(obj));
1078. 	    if (adjust_wt)
1079. 		ow -= (container->otyp == BAG_OF_HOLDING) ?
1080. 			(int)DELTA_CWT(container, obj) : (int)obj->owt;
1081. 	    if (iw + ow >= 0)
1082. 		break;
1083. 	    wt = iw + ow;
1084. 	}
1085. 	--qq;
1086.     } else {
1087. 	/* there's only one, and we can't lift it */
1088. 	qq = 0L;
1089.     }
1090.     obj->quan = savequan;
1091.     obj->owt = saveowt;
1092. 
1093.     if (qq < count) {
1094. 	/* some message will be given */
1095. 	Strcpy(obj_nambuf, doname(obj));
1096. 	if (container) {
1097. 	    Sprintf(where, "in %s", the(xname(container)));
1098. 	    verb = "carry";
1099. 	} else {
1100. 	    Strcpy(where, "lying here");
1101. 	    verb = telekinesis ? "acquire" : "lift";
1102. 	}
1103.     } else {
1104. 	/* lint supppression */
1105. 	*obj_nambuf = *where = '\0';
1106. 	verb = "";
1107.     }
1108.     /* we can carry qq of them */
1109.     if (qq > 0) {
1110. 	if (qq < count)
1111. 	    You("can only %s %s of the %s %s.",
1112. 		verb, (qq == 1L) ? "one" : "some", obj_nambuf, where);
1113. 	*wt_after = wt;
1114. 	return qq;
1115.     }
1116. 
1117.     if (!container) Strcpy(where, "here");  /* slightly shorter form */
1118. #ifndef GOLDOBJ
1119.     if (invent || u.ugold) {
1120. #else
1121.     if (invent || umoney) {
1122. #endif
1123. 	prefx1 = "you cannot ";
1124. 	prefx2 = "";
1125. 	suffx  = " any more";
1126.     } else {
1127. 	prefx1 = (obj->quan == 1L) ? "it " : "even one ";
1128. 	prefx2 = "is too heavy for you to ";
1129. 	suffx  = "";
1130.     }
1131.     There("%s %s %s, but %s%s%s%s.",
1132. 	  otense(obj, "are"), obj_nambuf, where,
1133. 	  prefx1, prefx2, verb, suffx);
1134. 
1135.  /* *wt_after = iw; */
1136.     return 0L;
1137. }
1138. 

lift_object Edit

1139. /* determine whether character is able and player is willing to carry `obj' */
1140. STATIC_OVL
1141. int 
1142. lift_object(obj, container, cnt_p, telekinesis)
1143. struct obj *obj, *container;	/* object to pick up, bag it's coming out of */
1144. long *cnt_p;
1145. boolean telekinesis;
1146. {
1147.     int result, old_wt, new_wt, prev_encumbr, next_encumbr;
1148. 
1149.     if (obj->otyp == BOULDER && In_sokoban(&u.uz)) {
1150. 	You("cannot get your %s around this %s.",
1151. 			body_part(HAND), xname(obj));
1152. 	return -1;
1153.     }
1154.     if (obj->otyp == LOADSTONE ||
1155. 	    (obj->otyp == BOULDER && throws_rocks(youmonst.data)))
1156. 	return 1;		/* lift regardless of current situation */
1157. 
1158.     *cnt_p = carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt);
1159.     if (*cnt_p < 1L) {
1160. 	result = -1;	/* nothing lifted */
1161. #ifndef GOLDOBJ
1162.     } else if (obj->oclass != COIN_CLASS && inv_cnt() >= 52 &&
1163. 		!merge_choice(invent, obj)) {
1164. #else
1165.     } else if (inv_cnt() >= 52 && !merge_choice(invent, obj)) {
1166. #endif
1167. 	Your("knapsack cannot accommodate any more items.");
1168. 	result = -1;	/* nothing lifted */
1169.     } else {
1170. 	result = 1;
1171. 	prev_encumbr = near_capacity();
1172. 	if (prev_encumbr < flags.pickup_burden)
1173. 		prev_encumbr = flags.pickup_burden;
1174. 	next_encumbr = calc_capacity(new_wt - old_wt);
1175. 	if (next_encumbr > prev_encumbr) {
1176. 	    if (telekinesis) {
1177. 		result = 0;	/* don't lift */
1178. 	    } else {
1179. 		char qbuf[BUFSZ];
1180. 		long savequan = obj->quan;
1181. 
1182. 		obj->quan = *cnt_p;
1183. 		Strcpy(qbuf,
1184. 			(next_encumbr > HVY_ENCUMBER) ? overloadmsg :
1185. 			(next_encumbr > MOD_ENCUMBER) ? nearloadmsg :
1186. 			moderateloadmsg);
1187. 		Sprintf(eos(qbuf), " %s. Continue?",
1188. 			safe_qbuf(qbuf, sizeof(" . Continue?"),
1189. 				doname(obj), an(simple_typename(obj->otyp)), "something"));
1190. 		obj->quan = savequan;
1191. 		switch (ynq(qbuf)) {
1192. 		case 'q':  result = -1; break;
1193. 		case 'n':  result =  0; break;
1194. 		default:   break;	/* 'y' => result == 1 */
1195. 		}
1196. 		clear_nhwindow(WIN_MESSAGE);
1197. 	    }
1198. 	}
1199.     }
1200. 
1201.     if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container)
1202. 	obj->spe = 0;
1203.     return result;
1204. }
1205. 

safe_qbuf Edit

1206. /* To prevent qbuf overflow in prompts use planA only
1207.  * if it fits, or planB if PlanA doesn't fit,
1208.  * finally using the fallback as a last resort.
1209.  * last_restort is expected to be very short.
1210.  */
1211. const char *
1212. safe_qbuf(qbuf, padlength, planA, planB, last_resort)
1213. const char *qbuf, *planA, *planB, *last_resort;
1214. unsigned padlength;
1215. {
1216. 	/* convert size_t (or int for ancient systems) to ordinary unsigned */
1217. 	unsigned len_qbuf = (unsigned)strlen(qbuf),
1218. 	         len_planA = (unsigned)strlen(planA),
1219. 	         len_planB = (unsigned)strlen(planB),
1220. 	         len_lastR = (unsigned)strlen(last_resort);
1221. 	unsigned textleft = QBUFSZ - (len_qbuf + padlength);
1222. 
1223. 	if (len_lastR >= textleft) {
1224. 	    impossible("safe_qbuf: last_resort too large at %u characters.",
1225. 		       len_lastR);
1226. 	    return "";
1227. 	}
1228. 	return (len_planA < textleft) ? planA :
1229. 		    (len_planB < textleft) ? planB : last_resort;
1230. }
1231. 

pickup_object Edit

1232. /*
1233.  * Pick up <count> of obj from the ground and add it to the hero's inventory.
1234.  * Returns -1 if caller should break out of its loop, 0 if nothing picked
1235.  * up, 1 if otherwise.
1236.  */
1237. int
1238. pickup_object(obj, count, telekinesis)
1239. struct obj *obj;
1240. long count;
1241. boolean telekinesis;	/* not picking it up directly by hand */
1242. {
1243. 	int res, nearload;
1244. #ifndef GOLDOBJ
1245. 	const char *where = (obj->ox == u.ux && obj->oy == u.uy) ?
1246. 			    "here" : "there";
1247. #endif
1248. 
1249. 	if (obj->quan < count) {
1250. 	    impossible("pickup_object: count %ld > quan %ld?",
1251. 		count, obj->quan);
1252. 	    return 0;
1253. 	}
1254. 
1255. 	/* In case of auto-pickup, where we haven't had a chance
1256. 	   to look at it yet; affects docall(SCR_SCARE_MONSTER). */
1257. 	if (!Blind)
1258. #ifdef INVISIBLE_OBJECTS
1259. 		if (!obj->oinvis || See_invisible)
1260. #endif
1261. 		obj->dknown = 1;
1262. 
1263. 	if (obj == uchain) {    /* do not pick up attached chain */
1264. 	    return 0;
1265. 	} else if (obj->oartifact && !touch_artifact(obj,&youmonst)) {
1266. 	    return 0;
1267. #ifndef GOLDOBJ
1268. 	} else if (obj->oclass == COIN_CLASS) {
1269. 	    /* Special consideration for gold pieces... */
1270. 	    long iw = (long)max_capacity() - GOLD_WT(u.ugold);
1271. 	    long gold_capacity = GOLD_CAPACITY(iw, u.ugold);
1272. 
1273. 	    if (gold_capacity <= 0L) {
1274. 		pline(
1275. 	       "There %s %ld gold piece%s %s, but you cannot carry any more.",
1276. 		      otense(obj, "are"),
1277. 		      obj->quan, plur(obj->quan), where);
1278. 		return 0;
1279. 	    } else if (gold_capacity < count) {
1280. 		You("can only %s %s of the %ld gold pieces lying %s.",
1281. 		    telekinesis ? "acquire" : "carry",
1282. 		    gold_capacity == 1L ? "one" : "some", obj->quan, where);
1283. 		pline("%s %ld gold piece%s.",
1284. 		    nearloadmsg, gold_capacity, plur(gold_capacity));
1285. 		u.ugold += gold_capacity;
1286. 		obj->quan -= gold_capacity;
1287. 		costly_gold(obj->ox, obj->oy, gold_capacity);
1288. 	    } else {
1289. 		u.ugold += count;
1290. 		if ((nearload = near_capacity()) != 0)
1291. 		    pline("%s %ld gold piece%s.",
1292. 			  nearload < MOD_ENCUMBER ?
1293. 			  moderateloadmsg : nearloadmsg,
1294. 			  count, plur(count));
1295. 		else
1296. 		    prinv((char *) 0, obj, count);
1297. 		costly_gold(obj->ox, obj->oy, count);
1298. 		if (count == obj->quan)
1299. 		    delobj(obj);
1300. 		else
1301. 		    obj->quan -= count;
1302. 	    }
1303. 	    flags.botl = 1;
1304. 	    if (flags.run) nomul(0);
1305. 	    return 1;
1306. #endif
1307. 	} else if (obj->otyp == CORPSE) {
1308. 	    if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg
1309. 				&& !Stone_resistance && !telekinesis) {
1310. 		if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1311. 		    display_nhwindow(WIN_MESSAGE, FALSE);
1312. 		else {
1313. 			char kbuf[BUFSZ];
1314. 
1315. 			Strcpy(kbuf, an(corpse_xname(obj, TRUE)));
1316. 			pline("Touching %s is a fatal mistake.", kbuf);
1317. 			instapetrify(kbuf);
1318. 		    return -1;
1319. 		}
1320. 	    } else if (is_rider(&mons[obj->corpsenm])) {
1321. 		pline("At your %s, the corpse suddenly moves...",
1322. 			telekinesis ? "attempted acquisition" : "touch");
1323. 		(void) revive_corpse(obj);
1324. 		exercise(A_WIS, FALSE);
1325. 		return -1;
1326. 	    }
1327. 	} else  if (obj->otyp == SCR_SCARE_MONSTER) {
1328. 	    if (obj->blessed) obj->blessed = 0;
1329. 	    else if (!obj->spe && !obj->cursed) obj->spe = 1;
1330. 	    else {
1331. 		pline_The("scroll%s %s to dust as you %s %s up.",
1332. 			plur(obj->quan), otense(obj, "turn"),
1333. 			telekinesis ? "raise" : "pick",
1334. 			(obj->quan == 1L) ? "it" : "them");
1335. 		if (!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
1336. 				    !(objects[SCR_SCARE_MONSTER].oc_uname))
1337. 		    docall(obj);
1338. 		useupf(obj, obj->quan);
1339. 		return 1;	/* tried to pick something up and failed, but
1340. 				   don't want to terminate pickup loop yet   */
1341. 	    }
1342. 	}
1343. 
1344. 	if ((res = lift_object(obj, (struct obj *)0, &count, telekinesis)) <= 0)
1345. 	    return res;
1346. 
1347. #ifdef GOLDOBJ
1348.         /* Whats left of the special case for gold :-) */
1349. 	if (obj->oclass == COIN_CLASS) flags.botl = 1;
1350. #endif
1351. 	if (obj->quan != count && obj->otyp != LOADSTONE)
1352. 	    obj = splitobj(obj, count);
1353. 
1354. 	obj = pick_obj(obj);
1355. 
1356. 	if (uwep && uwep == obj) mrg_to_wielded = TRUE;
1357. 	nearload = near_capacity();
1358. 	prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0,
1359. 	      obj, count);
1360. 	mrg_to_wielded = FALSE;
1361. 	return 1;
1362. }
1363. 

pick_obj Edit

1364. /*
1365.  * Do the actual work of picking otmp from the floor or monster's interior
1366.  * and putting it in the hero's inventory.  Take care of billing.  Return a
1367.  * pointer to the object where otmp ends up.  This may be different
1368.  * from otmp because of merging.
1369.  *
1370.  * Gold never reaches this routine unless GOLDOBJ is defined.
1371.  */
1372. struct obj *
1373. pick_obj(otmp)
1374. struct obj *otmp;
1375. {
1376. 	obj_extract_self(otmp);
1377. 	if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
1378. 	    char saveushops[5], fakeshop[2];
1379. 
1380. 	    /* addtobill cares about your location rather than the object's;
1381. 	       usually they'll be the same, but not when using telekinesis
1382. 	       (if ever implemented) or a grappling hook */
1383. 	    Strcpy(saveushops, u.ushops);
1384. 	    fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE);
1385. 	    fakeshop[1] = '\0';
1386. 	    Strcpy(u.ushops, fakeshop);
1387. 	    /* sets obj->unpaid if necessary */
1388. 	    addtobill(otmp, TRUE, FALSE, FALSE);
1389. 	    Strcpy(u.ushops, saveushops);
1390. 	    /* if you're outside the shop, make shk notice */
1391. 	    if (!index(u.ushops, *fakeshop))
1392. 		remote_burglary(otmp->ox, otmp->oy);
1393. 	}
1394. 	if (otmp->no_charge)	/* only applies to objects outside invent */
1395. 	    otmp->no_charge = 0;
1396. 	newsym(otmp->ox, otmp->oy);
1397. 	return addinv(otmp);	/* might merge it with other objects */
1398. }
1399. 

encumber_msg Edit

1400. /*
1401.  * prints a message if encumbrance changed since the last check and
1402.  * returns the new encumbrance value (from near_capacity()).
1403.  */
1404. int
1405. encumber_msg()
1406. {
1407.     static int oldcap = UNENCUMBERED;
1408.     int newcap = near_capacity();
1409. 
1410.     if(oldcap < newcap) {
1411. 	switch(newcap) {
1412. 	case 1: Your("movements are slowed slightly because of your load.");
1413. 		break;
1414. 	case 2: You("rebalance your load.  Movement is difficult.");
1415. 		break;
1416. 	case 3: You("%s under your heavy load.  Movement is very hard.",
1417. 		    stagger(youmonst.data, "stagger"));
1418. 		break;
1419. 	default: You("%s move a handspan with this load!",
1420. 		     newcap == 4 ? "can barely" : "can't even");
1421. 		break;
1422. 	}
1423. 	flags.botl = 1;
1424.     } else if(oldcap > newcap) {
1425. 	switch(newcap) {
1426. 	case 0: Your("movements are now unencumbered.");
1427. 		break;
1428. 	case 1: Your("movements are only slowed slightly by your load.");
1429. 		break;
1430. 	case 2: You("rebalance your load.  Movement is still difficult.");
1431. 		break;
1432. 	case 3: You("%s under your load.  Movement is still very hard.",
1433. 		    stagger(youmonst.data, "stagger"));
1434. 		break;
1435. 	}
1436. 	flags.botl = 1;
1437.     }
1438. 
1439.     oldcap = newcap;
1440.     return (newcap);
1441. }
1442. 

container_at Edit

1443. /* Is there a container at x,y. Optional: return count of containers at x,y */
1444. STATIC_OVL int
1445. container_at(x, y, countem)
1446. int x,y;
1447. boolean countem;
1448. {
1449. 	struct obj *cobj, *nobj;
1450. 	int container_count = 0;
1451. 	
1452. 	for(cobj = level.objects[x][y]; cobj; cobj = nobj) {
1453. 		nobj = cobj->nexthere;
1454. 		if(Is_container(cobj)) {
1455. 			container_count++;
1456. 			if (!countem) break;
1457. 		}
1458. 	}
1459. 	return container_count;
1460. }
1461. 

able_to_loot Edit

1462. STATIC_OVL boolean
1463. able_to_loot(x, y)
1464. int x, y;
1465. {
1466. 	if (!can_reach_floor()) {
1467. #ifdef STEED
1468. 		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
1469. 			rider_cant_reach(); /* not skilled enough to reach */
1470. 		else
1471. #endif
1472. 			You("cannot reach the %s.", surface(x, y));
1473. 		return FALSE;
1474. 	} else if (is_pool(x, y) || is_lava(x, y)) {
1475. 		/* at present, can't loot in water even when Underwater */
1476. 		You("cannot loot things that are deep in the %s.",
1477. 		    is_lava(x, y) ? "lava" : "water");
1478. 		return FALSE;
1479. 	} else if (nolimbs(youmonst.data)) {
1480. 		pline("Without limbs, you cannot loot anything.");
1481. 		return FALSE;
1482. 	} else if (!freehand()) {
1483. 		pline("Without a free %s, you cannot loot anything.",
1484. 			body_part(HAND));
1485. 		return FALSE;
1486. 	}
1487. 	return TRUE;
1488. }
1489. 

mon_beside Edit

1490. STATIC_OVL boolean
1491. mon_beside(x,y)
1492. int x, y;
1493. {
1494. 	int i,j,nx,ny;
1495. 	for(i = -1; i <= 1; i++)
1496. 	    for(j = -1; j <= 1; j++) {
1497. 	    	nx = x + i;
1498. 	    	ny = y + j;
1499. 		if(isok(nx, ny) && MON_AT(nx, ny))
1500. 			return TRUE;
1501. 	    }
1502. 	return FALSE;
1503. }
1504. 

doloot Edit

1505. int
1506. doloot()	/* loot a container on the floor or loot saddle from mon. */
1507. {
1508.     register struct obj *cobj, *nobj;
1509.     register int c = -1;
1510.     int timepassed = 0;
1511.     coord cc;
1512.     boolean underfoot = TRUE;
1513.     const char *dont_find_anything = "don't find anything";
1514.     struct monst *mtmp;
1515.     char qbuf[BUFSZ];
1516.     int prev_inquiry = 0;
1517.     boolean prev_loot = FALSE;
1518. 
1519.     if (check_capacity((char *)0)) {
1520. 	/* "Can't do that while carrying so much stuff." */
1521. 	return 0;
1522.     }
1523.     if (nohands(youmonst.data)) {
1524. 	You("have no hands!");	/* not `body_part(HAND)' */
1525. 	return 0;
1526.     }
1527.     cc.x = u.ux; cc.y = u.uy;
1528. 
1529. lootcont:
1530. 
1531.     if (container_at(cc.x, cc.y, FALSE)) {
1532. 	boolean any = FALSE;
1533. 
1534. 	if (!able_to_loot(cc.x, cc.y)) return 0;
1535. 	for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
1536. 	    nobj = cobj->nexthere;
1537. 
1538. 	    if (Is_container(cobj)) {
1539. 		Sprintf(qbuf, "There is %s here, loot it?",
1540. 			safe_qbuf("", sizeof("There is  here, loot it?"),
1541. 			     doname(cobj), an(simple_typename(cobj->otyp)),
1542. 			     "a container"));
1543. 		c = ynq(qbuf);
1544. 		if (c == 'q') return (timepassed);
1545. 		if (c == 'n') continue;
1546. 		any = TRUE;
1547. 
1548. 		if (cobj->olocked) {
1549. 		    pline("Hmmm, it seems to be locked.");
1550. 		    continue;
1551. 		}
1552. 		if (cobj->otyp == BAG_OF_TRICKS) {
1553. 		    int tmp;
1554. 		    You("carefully open the bag...");
1555. 		    pline("It develops a huge set of teeth and bites you!");
1556. 		    tmp = rnd(10);
1557. 		    if (Half_physical_damage) tmp = (tmp+1) / 2;
1558. 		    losehp(tmp, "carnivorous bag", KILLED_BY_AN);
1559. 		    makeknown(BAG_OF_TRICKS);
1560. 		    timepassed = 1;
1561. 		    continue;
1562. 		}
1563. 
1564. 		You("carefully open %s...", the(xname(cobj)));
1565. 		timepassed |= use_container(cobj, 0);
1566. 		if (multi < 0) return 1;		/* chest trap */
1567. 	    }
1568. 	}
1569. 	if (any) c = 'y';
1570.     } else if (Confusion) {
1571. #ifndef GOLDOBJ
1572. 	if (u.ugold){
1573. 	    long contribution = rnd((int)min(LARGEST_INT,u.ugold));
1574. 	    struct obj *goldob = mkgoldobj(contribution);
1575. #else
1576. 	struct obj *goldob;
1577. 	/* Find a money object to mess with */
1578. 	for (goldob = invent; goldob; goldob = goldob->nobj) {
1579. 	    if (goldob->oclass == COIN_CLASS) break;
1580. 	}
1581. 	if (goldob){
1582. 	    long contribution = rnd((int)min(LARGEST_INT, goldob->quan));
1583. 	    if (contribution < goldob->quan)
1584. 		goldob = splitobj(goldob, contribution);
1585. 	    freeinv(goldob);
1586. #endif
1587. 	    if (IS_THRONE(levl[u.ux][u.uy].typ)){
1588. 		struct obj *coffers;
1589. 		int pass;
1590. 		/* find the original coffers chest, or any chest */
1591. 		for (pass = 2; pass > -1; pass -= 2)
1592. 		    for (coffers = fobj; coffers; coffers = coffers->nobj)
1593. 			if (coffers->otyp == CHEST && coffers->spe == pass)
1594. 			    goto gotit;	/* two level break */
1595. gotit:
1596. 		if (coffers) {
1597. 	    verbalize("Thank you for your contribution to reduce the debt.");
1598. 		    (void) add_to_container(coffers, goldob);
1599. 		    coffers->owt = weight(coffers);
1600. 		} else {
1601. 		    struct monst *mon = makemon(courtmon(),
1602. 					    u.ux, u.uy, NO_MM_FLAGS);
1603. 		    if (mon) {
1604. #ifndef GOLDOBJ
1605. 			mon->mgold += goldob->quan;
1606. 			delobj(goldob);
1607. 			pline("The exchequer accepts your contribution.");
1608. 		    } else {
1609. 			dropx(goldob);
1610. 		    }
1611. 		}
1612. 	    } else {
1613. 		dropx(goldob);
1614. #else
1615. 			add_to_minv(mon, goldob);
1616. 			pline("The exchequer accepts your contribution.");
1617. 		    } else {
1618. 			dropy(goldob);
1619. 		    }
1620. 		}
1621. 	    } else {
1622. 		dropy(goldob);
1623. #endif
1624. 		pline("Ok, now there is loot here.");
1625. 	    }
1626. 	}
1627.     } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
1628. 	You("need to dig up the grave to effectively loot it...");
1629.     }
1630.     /*
1631.      * 3.3.1 introduced directional looting for some things.
1632.      */
1633.     if (c != 'y' && mon_beside(u.ux, u.uy)) {
1634. 	if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location",
1635. 			u.ux, u.uy, &cc)) return 0;
1636. 	if (cc.x == u.ux && cc.y == u.uy) {
1637. 	    underfoot = TRUE;
1638. 	    if (container_at(cc.x, cc.y, FALSE))
1639. 		goto lootcont;
1640. 	} else
1641. 	    underfoot = FALSE;
1642. 	if (u.dz < 0) {
1643. 	    You("%s to loot on the %s.", dont_find_anything,
1644. 		ceiling(cc.x, cc.y));
1645. 	    timepassed = 1;
1646. 	    return timepassed;
1647. 	}
1648. 	mtmp = m_at(cc.x, cc.y);
1649. 	if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot);
1650. 
1651. 	/* Preserve pre-3.3.1 behaviour for containers.
1652. 	 * Adjust this if-block to allow container looting
1653. 	 * from one square away to change that in the future.
1654. 	 */
1655. 	if (!underfoot) {
1656. 	    if (container_at(cc.x, cc.y, FALSE)) {
1657. 		if (mtmp) {
1658. 		    You_cant("loot anything %sthere with %s in the way.",
1659. 			    prev_inquiry ? "else " : "", mon_nam(mtmp));
1660. 		    return timepassed;
1661. 		} else {
1662. 		    You("have to be at a container to loot it.");
1663. 		}
1664. 	    } else {
1665. 		You("%s %sthere to loot.", dont_find_anything,
1666. 			(prev_inquiry || prev_loot) ? "else " : "");
1667. 		return timepassed;
1668. 	    }
1669. 	}
1670.     } else if (c != 'y' && c != 'n') {
1671. 	You("%s %s to loot.", dont_find_anything,
1672. 		    underfoot ? "here" : "there");
1673.     }
1674.     return (timepassed);
1675. }
1676. 

loot_mon Edit

1677. /* loot_mon() returns amount of time passed.
1678.  */
1679. int
1680. loot_mon(mtmp, passed_info, prev_loot)
1681. struct monst *mtmp;
1682. int *passed_info;
1683. boolean *prev_loot;
1684. {
1685.     int c = -1;
1686.     int timepassed = 0;
1687. #ifdef STEED
1688.     struct obj *otmp;
1689.     char qbuf[QBUFSZ];
1690. 
1691.     /* 3.3.1 introduced the ability to remove saddle from a steed             */
1692.     /* 	*passed_info is set to TRUE if a loot query was given.               */
1693.     /*	*prev_loot is set to TRUE if something was actually acquired in here. */
1694.     if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
1695. 	long unwornmask;
1696. 	if (passed_info) *passed_info = 1;
1697. 	Sprintf(qbuf, "Do you want to remove the saddle from %s?",
1698. 		x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE));
1699. 	if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
1700. 		if (nolimbs(youmonst.data)) {
1701. 		    You_cant("do that without limbs."); /* not body_part(HAND) */
1702. 		    return (0);
1703. 		}
1704. 		if (otmp->cursed) {
1705. 		    You("can't. The saddle seems to be stuck to %s.",
1706. 			x_monnam(mtmp, ARTICLE_THE, (char *)0,
1707. 				SUPPRESS_SADDLE, FALSE));
1708. 			    
1709. 		    /* the attempt costs you time */
1710. 			return (1);
1711. 		}
1712. 		obj_extract_self(otmp);
1713. 		if ((unwornmask = otmp->owornmask) != 0L) {
1714. 		    mtmp->misc_worn_check &= ~unwornmask;
1715. 		    otmp->owornmask = 0L;
1716. 		    update_mon_intrinsics(mtmp, otmp, FALSE, FALSE);
1717. 		}
1718. 		otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
1719. 					(const char *)0);
1720. 		timepassed = rnd(3);
1721. 		if (prev_loot) *prev_loot = TRUE;
1722. 	} else if (c == 'q') {
1723. 		return (0);
1724. 	}
1725.     }
1726. #endif	/* STEED */
1727.     /* 3.4.0 introduced the ability to pick things up from within swallower's stomach */
1728.     if (u.uswallow) {
1729. 	int count = passed_info ? *passed_info : 0;
1730. 	timepassed = pickup(count);
1731.     }
1732.     return timepassed;
1733. }
1734. 

mbag_explodes Edit

1735. /*
1736.  * Decide whether an object being placed into a magic bag will cause
1737.  * it to explode.  If the object is a bag itself, check recursively.
1738.  */
1739. STATIC_OVL boolean
1740. mbag_explodes(obj, depthin)
1741.     struct obj *obj;
1742.     int depthin;
1743. {
1744.     /* these won't cause an explosion when they're empty */
1745.     if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS) &&
1746. 	    obj->spe <= 0)
1747. 	return FALSE;
1748. 
1749.     /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
1750.     if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION) &&
1751. 	(rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
1752. 	return TRUE;
1753.     else if (Has_contents(obj)) {
1754. 	struct obj *otmp;
1755. 
1756. 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
1757. 	    if (mbag_explodes(otmp, depthin+1)) return TRUE;
1758.     }
1759.     return FALSE;
1760. }
1761. 

in_container Edit

1762. /* A variable set in use_container(), to be used by the callback routines   */
1763. /* in_container(), and out_container() from askchain() and use_container(). */
1764. static NEARDATA struct obj *current_container;
1765. #define Icebox (current_container->otyp == ICE_BOX)
1766. 
1767. /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
1768. STATIC_PTR int
1769. in_container(obj)
1770. register struct obj *obj;
1771. {
1772. 	boolean floor_container = !carried(current_container);
1773. 	boolean was_unpaid = FALSE;
1774. 	char buf[BUFSZ];
1775. 
1776. 	if (!current_container) {
1777. 		impossible("<in> no current_container?");
1778. 		return 0;
1779. 	} else if (obj == uball || obj == uchain) {
1780. 		You("must be kidding.");
1781. 		return 0;
1782. 	} else if (obj == current_container) {
1783. 		pline("That would be an interesting topological exercise.");
1784. 		return 0;
1785. 	} else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
1786. 		Norep("You cannot %s %s you are wearing.",
1787. 			Icebox ? "refrigerate" : "stash", something);
1788. 		return 0;
1789. 	} else if ((obj->otyp == LOADSTONE) && obj->cursed) {
1790. 		obj->bknown = 1;
1791. 	      pline_The("stone%s won't leave your person.", plur(obj->quan));
1792. 		return 0;
1793. 	} else if (obj->otyp == AMULET_OF_YENDOR ||
1794. 		   obj->otyp == CANDELABRUM_OF_INVOCATION ||
1795. 		   obj->otyp == BELL_OF_OPENING ||
1796. 		   obj->otyp == SPE_BOOK_OF_THE_DEAD) {
1797. 	/* Prohibit Amulets in containers; if you allow it, monsters can't
1798. 	 * steal them.  It also becomes a pain to check to see if someone
1799. 	 * has the Amulet.  Ditto for the Candelabrum, the Bell and the Book.
1800. 	 */
1801. 	    pline("%s cannot be confined in such trappings.", The(xname(obj)));
1802. 	    return 0;
1803. 	} else if (obj->otyp == LEASH && obj->leashmon != 0) {
1804. 		pline("%s attached to your pet.", Tobjnam(obj, "are"));
1805. 		return 0;
1806. 	} else if (obj == uwep) {
1807. 		if (welded(obj)) {
1808. 			weldmsg(obj);
1809. 			return 0;
1810. 		}
1811. 		setuwep((struct obj *) 0);
1812. 		if (uwep) return 0;	/* unwielded, died, rewielded */
1813. 	} else if (obj == uswapwep) {
1814. 		setuswapwep((struct obj *) 0);
1815. 		if (uswapwep) return 0;     /* unwielded, died, rewielded */
1816. 	} else if (obj == uquiver) {
1817. 		setuqwep((struct obj *) 0);
1818. 		if (uquiver) return 0;     /* unwielded, died, rewielded */
1819. 	}
1820. 
1821. 	if (obj->otyp == CORPSE) {
1822. 	    if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg
1823. 		 && !Stone_resistance) {
1824. 		if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1825. 		    display_nhwindow(WIN_MESSAGE, FALSE);
1826. 		else {
1827. 		    char kbuf[BUFSZ];
1828. 
1829. 		    Strcpy(kbuf, an(corpse_xname(obj, TRUE)));
1830. 		    pline("Touching %s is a fatal mistake.", kbuf);
1831. 		    instapetrify(kbuf);
1832. 		    return -1;
1833. 		}
1834. 	    }
1835. 	}
1836. 
1837. 	/* boxes, boulders, and big statues can't fit into any container */
1838. 	if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER ||
1839. 		(obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) {
1840. 		/*
1841. 		 *  xname() uses a static result array.  Save obj's name
1842. 		 *  before current_container's name is computed.  Don't
1843. 		 *  use the result of strcpy() within You() --- the order
1844. 		 *  of evaluation of the parameters is undefined.
1845. 		 */
1846. 		Strcpy(buf, the(xname(obj)));
1847. 		You("cannot fit %s into %s.", buf,
1848. 		    the(xname(current_container)));
1849. 		return 0;
1850. 	}
1851. 
1852. 	freeinv(obj);
1853. 
1854. 	if (obj_is_burning(obj))	/* this used to be part of freeinv() */
1855. 		(void) snuff_lit(obj);
1856. 
1857. 	if (floor_container && costly_spot(u.ux, u.uy)) {
1858. 	    if (current_container->no_charge && !obj->unpaid) {
1859. 		/* don't sell when putting the item into your own container */
1860. 		obj->no_charge = 1;
1861. 	    } else if (obj->oclass != COIN_CLASS) {
1862. 		/* sellobj() will take an unpaid item off the shop bill
1863. 		 * note: coins are handled later */
1864. 		was_unpaid = obj->unpaid ? TRUE : FALSE;
1865. 		sellobj_state(SELL_DELIBERATE);
1866. 		sellobj(obj, u.ux, u.uy);
1867. 		sellobj_state(SELL_NORMAL);
1868. 	    }
1869. 	}
1870. 	if (Icebox && !age_is_relative(obj)) {
1871. 		obj->age = monstermoves - obj->age; /* actual age */
1872. 		/* stop any corpse timeouts when frozen */
1873. 		if (obj->otyp == CORPSE && obj->timed) {
1874. 			long rot_alarm = stop_timer(ROT_CORPSE, (genericptr_t)obj);
1875. 			(void) stop_timer(REVIVE_MON, (genericptr_t)obj);
1876. 			/* mark a non-reviving corpse as such */
1877. 			if (rot_alarm) obj->norevive = 1;
1878. 		}
1879. 	} else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
1880. 		/* explicitly mention what item is triggering the explosion */
1881. 		pline(
1882. 	      "As you put %s inside, you are blasted by a magical explosion!",
1883. 		      doname(obj));
1884. 		/* did not actually insert obj yet */
1885. 		if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE);
1886. 		obfree(obj, (struct obj *)0);
1887. 		delete_contents(current_container);
1888. 		if (!floor_container)
1889. 			useup(current_container);
1890. 		else if (obj_here(current_container, u.ux, u.uy))
1891. 			useupf(current_container, obj->quan);
1892. 		else
1893. 			panic("in_container:  bag not found.");
1894. 
1895. 		losehp(d(6,6),"magical explosion", KILLED_BY_AN);
1896. 		current_container = 0;	/* baggone = TRUE; */
1897. 	}
1898. 
1899. 	if (current_container) {
1900. 	    Strcpy(buf, the(xname(current_container)));
1901. 	    You("put %s into %s.", doname(obj), buf);
1902. 
1903. 	    /* gold in container always needs to be added to credit */
1904. 	    if (floor_container && obj->oclass == COIN_CLASS)
1905. 		sellobj(obj, current_container->ox, current_container->oy);
1906. 	    (void) add_to_container(current_container, obj);
1907. 	    current_container->owt = weight(current_container);
1908. 	}
1909. 	/* gold needs this, and freeinv() many lines above may cause
1910. 	 * the encumbrance to disappear from the status, so just always
1911. 	 * update status immediately.
1912. 	 */
1913. 	bot();
1914. 
1915. 	return(current_container ? 1 : -1);
1916. }
1917. 

ck_bag Edit

1918. STATIC_PTR int
1919. ck_bag(obj)
1920. struct obj *obj;
1921. {
1922. 	return current_container && obj != current_container;
1923. }
1924. 

out_container Edit

1925. /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
1926. STATIC_PTR int
1927. out_container(obj)
1928. register struct obj *obj;
1929. {
1930. 	register struct obj *otmp;
1931. 	boolean is_gold = (obj->oclass == COIN_CLASS);
1932. 	int res, loadlev;
1933. 	long count;
1934. 
1935. 	if (!current_container) {
1936. 		impossible("<out> no current_container?");
1937. 		return -1;
1938. 	} else if (is_gold) {
1939. 		obj->owt = weight(obj);
1940. 	}
1941. 
1942. 	if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0;
1943. 
1944. 	if (obj->otyp == CORPSE) {
1945. 	    if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg
1946. 		 && !Stone_resistance) {
1947. 		if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1948. 		    display_nhwindow(WIN_MESSAGE, FALSE);
1949. 		else {
1950. 		    char kbuf[BUFSZ];
1951. 
1952. 		    Strcpy(kbuf, an(corpse_xname(obj, TRUE)));
1953. 		    pline("Touching %s is a fatal mistake.", kbuf);
1954. 		    instapetrify(kbuf);
1955. 		    return -1;
1956. 		}
1957. 	    }
1958. 	}
1959. 
1960. 	count = obj->quan;
1961. 	if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0)
1962. 	    return res;
1963. 
1964. 	if (obj->quan != count && obj->otyp != LOADSTONE)
1965. 	    obj = splitobj(obj, count);
1966. 
1967. 	/* Remove the object from the list. */
1968. 	obj_extract_self(obj);
1969. 	current_container->owt = weight(current_container);
1970. 
1971. 	if (Icebox && !age_is_relative(obj)) {
1972. 		obj->age = monstermoves - obj->age; /* actual age */
1973. 		if (obj->otyp == CORPSE)
1974. 			start_corpse_timeout(obj);
1975. 	}
1976. 	/* simulated point of time */
1977. 
1978. 	if(!obj->unpaid && !carried(current_container) &&
1979. 	     costly_spot(current_container->ox, current_container->oy)) {
1980. 		obj->ox = current_container->ox;
1981. 		obj->oy = current_container->oy;
1982. 		addtobill(obj, FALSE, FALSE, FALSE);
1983. 	}
1984. 	if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops))
1985. 		verbalize("You sneaky cad! Get out of here with that pick!");
1986. 
1987. 	otmp = addinv(obj);
1988. 	loadlev = near_capacity();
1989. 	prinv(loadlev ?
1990. 	      (loadlev < MOD_ENCUMBER ?
1991. 	       "You have a little trouble removing" :
1992. 	       "You have much trouble removing") : (char *)0,
1993. 	      otmp, count);
1994. 
1995. 	if (is_gold) {
1996. #ifndef GOLDOBJ
1997. 		dealloc_obj(obj);
1998. #endif
1999. 		bot();	/* update character's gold piece count immediately */
2000. 	}
2001. 	return 1;
2002. }
2003. 

mbag_item_gone Edit

2004. /* an object inside a cursed bag of holding is being destroyed */
2005. STATIC_OVL long
2006. mbag_item_gone(held, item)
2007. int held;
2008. struct obj *item;
2009. {
2010.     struct monst *shkp;
2011.     long loss = 0L;
2012. 
2013.     if (item->dknown)
2014. 	pline("%s %s vanished!", Doname2(item), otense(item, "have"));
2015.     else
2016. 	You("%s %s disappear!", Blind ? "notice" : "see", doname(item));
2017. 
2018.     if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) {
2019. 	if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy))
2020. 	    loss = stolen_value(item, u.ux, u.uy,
2021. 				(boolean)shkp->mpeaceful, TRUE);
2022.     }
2023.     obfree(item, (struct obj *) 0);
2024.     return loss;
2025. }
2026. 

observe_quantum_cat Edit

2027. STATIC_OVL void
2028. observe_quantum_cat(box)
2029. struct obj *box;
2030. {
2031.     static NEARDATA const char sc[] = "Schroedinger's Cat";
2032.     struct obj *deadcat;
2033.     struct monst *livecat;
2034.     xchar ox, oy;
2035. 
2036.     box->spe = 0;		/* box->owt will be updated below */
2037.     if (get_obj_location(box, &ox, &oy, 0))
2038. 	box->ox = ox, box->oy = oy;	/* in case it's being carried */
2039. 
2040.     /* this isn't really right, since any form of observation
2041.        (telepathic or monster/object/food detection) ought to
2042.        force the determination of alive vs dead state; but basing
2043.        it just on opening the box is much simpler to cope with */
2044.     livecat = rn2(2) ? makemon(&mons[PM_HOUSECAT],
2045. 			       box->ox, box->oy, NO_MINVENT) : 0;
2046.     if (livecat) {
2047. 	livecat->mpeaceful = 1;
2048. 	set_malign(livecat);
2049. 	if (!canspotmon(livecat))
2050. 	    You("think %s brushed your %s.", something, body_part(FOOT));
2051. 	else
2052. 	    pline("%s inside the box is still alive!", Monnam(livecat));
2053. 	(void) christen_monst(livecat, sc);
2054.     } else {
2055. 	deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
2056. 				  box->ox, box->oy, sc);
2057. 	if (deadcat) {
2058. 	    obj_extract_self(deadcat);
2059. 	    (void) add_to_container(box, deadcat);
2060. 	}
2061. 	pline_The("%s inside the box is dead!",
2062. 	    Hallucination ? rndmonnam() : "housecat");
2063.     }
2064.     box->owt = weight(box);
2065.     return;
2066. }
2067. 
2068. #undef Icebox
2069. 

use_container Edit

2070. int
2071. use_container(obj, held)
2072. register struct obj *obj;
2073. register int held;
2074. {
2075. 	struct obj *curr, *otmp;
2076. #ifndef GOLDOBJ
2077. 	struct obj *u_gold = (struct obj *)0;
2078. #endif
2079. 	boolean one_by_one, allflag, quantum_cat = FALSE,
2080. 		loot_out = FALSE, loot_in = FALSE;
2081. 	char select[MAXOCLASSES+1];
2082. 	char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ];
2083. 	long loss = 0L;
2084. 	int cnt = 0, used = 0,
2085. 	    menu_on_request;
2086. 
2087. 	emptymsg[0] = '\0';
2088. 	if (nohands(youmonst.data)) {
2089. 		You("have no hands!");	/* not `body_part(HAND)' */
2090. 		return 0;
2091. 	} else if (!freehand()) {
2092. 		You("have no free %s.", body_part(HAND));
2093. 		return 0;
2094. 	}
2095. 	if (obj->olocked) {
2096. 	    pline("%s to be locked.", Tobjnam(obj, "seem"));
2097. 	    if (held) You("must put it down to unlock.");
2098. 	    return 0;
2099. 	} else if (obj->otrapped) {
2100. 	    if (held) You("open %s...", the(xname(obj)));
2101. 	    (void) chest_trap(obj, HAND, FALSE);
2102. 	    /* even if the trap fails, you've used up this turn */
2103. 	    if (multi >= 0) {	/* in case we didn't become paralyzed */
2104. 		nomul(-1);
2105. 		nomovemsg = "";
2106. 	    }
2107. 	    return 1;
2108. 	}
2109. 	current_container = obj;	/* for use by in/out_container */
2110. 
2111. 	if (obj->spe == 1) {
2112. 	    observe_quantum_cat(obj);
2113. 	    used = 1;
2114. 	    quantum_cat = TRUE;	/* for adjusting "it's empty" message */
2115. 	}
2116. 	/* Count the number of contained objects. Sometimes toss objects if */
2117. 	/* a cursed magic bag.						    */
2118. 	for (curr = obj->cobj; curr; curr = otmp) {
2119. 	    otmp = curr->nobj;
2120. 	    if (Is_mbag(obj) && obj->cursed && !rn2(13)) {
2121. 		obj_extract_self(curr);
2122. 		loss += mbag_item_gone(held, curr);
2123. 		used = 1;
2124. 	    } else {
2125. 		cnt++;
2126. 	    }
2127. 	}
2128. 
2129. 	if (loss)	/* magic bag lost some shop goods */
2130. 	    You("owe %ld %s for lost merchandise.", loss, currency(loss));
2131. 	obj->owt = weight(obj);	/* in case any items were lost */
2132. 
2133. 	if (!cnt)
2134. 	    Sprintf(emptymsg, "%s is %sempty.", Yname2(obj),
2135. 		    quantum_cat ? "now " : "");
2136. 
2137. 	if (cnt || flags.menu_style == MENU_FULL) {
2138. 	    Strcpy(qbuf, "Do you want to take something out of ");
2139. 	    Sprintf(eos(qbuf), "%s?",
2140. 		    safe_qbuf(qbuf, 1, yname(obj), ysimple_name(obj), "it"));
2141. 	    if (flags.menu_style != MENU_TRADITIONAL) {
2142. 		if (flags.menu_style == MENU_FULL) {
2143. 		    int t;
2144. 		    char menuprompt[BUFSZ];
2145. 		    boolean outokay = (cnt != 0);
2146. #ifndef GOLDOBJ
2147. 		    boolean inokay = (invent != 0) || (u.ugold != 0);
2148. #else
2149. 		    boolean inokay = (invent != 0);
2150. #endif
2151. 		    if (!outokay && !inokay) {
2152. 			pline("%s", emptymsg);
2153. 			You("don't have anything to put in.");
2154. 			return used;
2155. 		    }
2156. 		    menuprompt[0] = '\0';
2157. 		    if (!cnt) Sprintf(menuprompt, "%s ", emptymsg);
2158. 		    Strcat(menuprompt, "Do what?");
2159. 		    t = in_or_out_menu(menuprompt, current_container, outokay, inokay);
2160. 		    if (t <= 0) return 0;
2161. 		    loot_out = (t & 0x01) != 0;
2162. 		    loot_in  = (t & 0x02) != 0;
2163. 		} else {	/* MENU_COMBINATION or MENU_PARTIAL */
2164. 		    loot_out = (yn_function(qbuf, "ynq", 'n') == 'y');
2165. 		}
2166. 		if (loot_out) {
2167. 		    add_valid_menu_class(0);	/* reset */
2168. 		    used |= menu_loot(0, current_container, FALSE) > 0;
2169. 		}
2170. 	    } else {
2171. 		/* traditional code */
2172. ask_again2:
2173. 		menu_on_request = 0;
2174. 		add_valid_menu_class(0);	/* reset */
2175. 		Strcpy(pbuf, ":ynq");
2176. 		if (cnt) Strcat(pbuf, "m");
2177. 		switch (yn_function(qbuf, pbuf, 'n')) {
2178. 		case ':':
2179. 		    container_contents(current_container, FALSE, FALSE);
2180. 		    goto ask_again2;
2181. 		case 'y':
2182. 		    if (query_classes(select, &one_by_one, &allflag,
2183. 				      "take out", current_container->cobj,
2184. 				      FALSE,
2185. #ifndef GOLDOBJ
2186. 				      FALSE,
2187. #endif
2188. 				      &menu_on_request)) {
2189. 			if (askchain((struct obj **)&current_container->cobj,
2190. 				     (one_by_one ? (char *)0 : select),
2191. 				     allflag, out_container,
2192. 				     (int FDECL((*),(OBJ_P)))0,
2193. 				     0, "nodot"))
2194. 			    used = 1;
2195. 		    } else if (menu_on_request < 0) {
2196. 			used |= menu_loot(menu_on_request,
2197. 					  current_container, FALSE) > 0;
2198. 		    }
2199. 		    /*FALLTHRU*/
2200. 		case 'n':
2201. 		    break;
2202. 		case 'm':
2203. 		    menu_on_request = -2; /* triggers ALL_CLASSES */
2204. 		    used |= menu_loot(menu_on_request, current_container, FALSE) > 0;
2205. 		    break;
2206. 		case 'q':
2207. 		default:
2208. 		    return used;
2209. 		}
2210. 	    }
2211. 	} else {
2212. 	    pline("%s", emptymsg);		/* <whatever> is empty. */
2213. 	}
2214. 
2215. #ifndef GOLDOBJ
2216. 	if (!invent && u.ugold == 0) {
2217. #else
2218. 	if (!invent) {
2219. #endif
2220. 	    /* nothing to put in, but some feedback is necessary */
2221. 	    You("don't have anything to put in.");
2222. 	    return used;
2223. 	}
2224. 	if (flags.menu_style != MENU_FULL) {
2225. 	    Sprintf(qbuf, "Do you wish to put %s in?", something);
2226. 	    Strcpy(pbuf, ynqchars);
2227. 	    if (flags.menu_style == MENU_TRADITIONAL && invent && inv_cnt() > 0)
2228. 		Strcat(pbuf, "m");
2229. 	    switch (yn_function(qbuf, pbuf, 'n')) {
2230. 		case 'y':
2231. 		    loot_in = TRUE;
2232. 		    break;
2233. 		case 'n':
2234. 		    break;
2235. 		case 'm':
2236. 		    add_valid_menu_class(0);	  /* reset */
2237. 		    menu_on_request = -2; /* triggers ALL_CLASSES */
2238. 		    used |= menu_loot(menu_on_request, current_container, TRUE) > 0;
2239. 		    break;
2240. 		case 'q':
2241. 		default:
2242. 		    return used;
2243. 	    }
2244. 	}
2245. 	/*
2246. 	 * Gone: being nice about only selecting food if we know we are
2247. 	 * putting things in an ice chest.
2248. 	 */
2249. 	if (loot_in) {
2250. #ifndef GOLDOBJ
2251. 	    if (u.ugold) {
2252. 		/*
2253. 		 * Hack: gold is not in the inventory, so make a gold object
2254. 		 * and put it at the head of the inventory list.
2255. 		 */
2256. 		u_gold = mkgoldobj(u.ugold);	/* removes from u.ugold */
2257. 		u_gold->in_use = TRUE;
2258. 		u.ugold = u_gold->quan;		/* put the gold back */
2259. 		assigninvlet(u_gold);		/* might end up as NOINVSYM */
2260. 		u_gold->nobj = invent;
2261. 		invent = u_gold;
2262. 	    }
2263. #endif
2264. 	    add_valid_menu_class(0);	  /* reset */
2265. 	    if (flags.menu_style != MENU_TRADITIONAL) {
2266. 		used |= menu_loot(0, current_container, TRUE) > 0;
2267. 	    } else {
2268. 		/* traditional code */
2269. 		menu_on_request = 0;
2270. 		if (query_classes(select, &one_by_one, &allflag, "put in",
2271. 				   invent, FALSE,
2272. #ifndef GOLDOBJ
2273. 				   (u.ugold != 0L),
2274. #endif
2275. 				   &menu_on_request)) {
2276. 		    (void) askchain((struct obj **)&invent,
2277. 				    (one_by_one ? (char *)0 : select), allflag,
2278. 				    in_container, ck_bag, 0, "nodot");
2279. 		    used = 1;
2280. 		} else if (menu_on_request < 0) {
2281. 		    used |= menu_loot(menu_on_request,
2282. 				      current_container, TRUE) > 0;
2283. 		}
2284. 	    }
2285. 	}
2286. 
2287. #ifndef GOLDOBJ
2288. 	if (u_gold && invent && invent->oclass == COIN_CLASS) {
2289. 	    /* didn't stash [all of] it */
2290. 	    u_gold = invent;
2291. 	    invent = u_gold->nobj;
2292. 	    u_gold->in_use = FALSE;
2293. 	    dealloc_obj(u_gold);
2294. 	}
2295. #endif
2296. 	return used;
2297. }
2298. 

menu_loot Edit

2299. /* Loot a container (take things out, put things in), using a menu. */
2300. STATIC_OVL int
2301. menu_loot(retry, container, put_in)
2302. int retry;
2303. struct obj *container;
2304. boolean put_in;
2305. {
2306.     int n, i, n_looted = 0;
2307.     boolean all_categories = TRUE, loot_everything = FALSE;
2308.     char buf[BUFSZ];
2309.     const char *takeout = "Take out", *putin = "Put in";
2310.     struct obj *otmp, *otmp2;
2311.     menu_item *pick_list;
2312.     int mflags, res;
2313.     long count;
2314. 
2315.     if (retry) {
2316. 	all_categories = (retry == -2);
2317.     } else if (flags.menu_style == MENU_FULL) {
2318. 	all_categories = FALSE;
2319. 	Sprintf(buf,"%s what type of objects?", put_in ? putin : takeout);
2320. 	mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN :
2321. 		          ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
2322. 	n = query_category(buf, put_in ? invent : container->cobj,
2323. 			   mflags, &pick_list, PICK_ANY);
2324. 	if (!n) return 0;
2325. 	for (i = 0; i < n; i++) {
2326. 	    if (pick_list[i].item.a_int == 'A')
2327. 		loot_everything = TRUE;
2328. 	    else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
2329. 		all_categories = TRUE;
2330. 	    else
2331. 		add_valid_menu_class(pick_list[i].item.a_int);
2332. 	}
2333. 	free((genericptr_t) pick_list);
2334.     }
2335. 
2336.     if (loot_everything) {
2337. 	for (otmp = container->cobj; otmp; otmp = otmp2) {
2338. 	    otmp2 = otmp->nobj;
2339. 	    res = out_container(otmp);
2340. 	    if (res < 0) break;
2341. 	}
2342.     } else {
2343. 	mflags = INVORDER_SORT;
2344. 	if (put_in && flags.invlet_constant) mflags |= USE_INVLET;
2345. 	Sprintf(buf,"%s what?", put_in ? putin : takeout);
2346. 	n = query_objlist(buf, put_in ? invent : container->cobj,
2347. 			  mflags, &pick_list, PICK_ANY,
2348. 			  all_categories ? allow_all : allow_category);
2349. 	if (n) {
2350. 		n_looted = n;
2351. 		for (i = 0; i < n; i++) {
2352. 		    otmp = pick_list[i].item.a_obj;
2353. 		    count = pick_list[i].count;
2354. 		    if (count > 0 && count < otmp->quan) {
2355. 			otmp = splitobj(otmp, count);
2356. 			/* special split case also handled by askchain() */
2357. 		    }
2358. 		    res = put_in ? in_container(otmp) : out_container(otmp);
2359. 		    if (res < 0) {
2360. 			if (otmp != pick_list[i].item.a_obj) {
2361. 			    /* split occurred, merge again */
2362. 			    (void) merged(&pick_list[i].item.a_obj, &otmp);
2363. 			}
2364. 			break;
2365. 		    }
2366. 		}
2367. 		free((genericptr_t)pick_list);
2368. 	}
2369.     }
2370.     return n_looted;
2371. }
2372. 

in_or_out_menu Edit

2373. STATIC_OVL int
2374. in_or_out_menu(prompt, obj, outokay, inokay)
2375. const char *prompt;
2376. struct obj *obj;
2377. boolean outokay, inokay;
2378. {
2379.     winid win;
2380.     anything any;
2381.     menu_item *pick_list;
2382.     char buf[BUFSZ];
2383.     int n;
2384.     const char *menuselector = iflags.lootabc ? "abc" : "oib";
2385. 
2386.     any.a_void = 0;
2387.     win = create_nhwindow(NHW_MENU);
2388.     start_menu(win);
2389.     if (outokay) {
2390. 	any.a_int = 1;
2391. 	Sprintf(buf,"Take %s out of %s", something, the(xname(obj)));
2392. 	add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
2393. 			buf, MENU_UNSELECTED);
2394.     }
2395.     menuselector++;
2396.     if (inokay) {
2397. 	any.a_int = 2;
2398. 	Sprintf(buf,"Put %s into %s", something, the(xname(obj)));
2399. 	add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED);
2400.     }
2401.     menuselector++;
2402.     if (outokay && inokay) {
2403. 	any.a_int = 3;
2404. 	add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE,
2405. 			"Both of the above", MENU_UNSELECTED);
2406.     }
2407.     end_menu(win, prompt);
2408.     n = select_menu(win, PICK_ONE, &pick_list);
2409.     destroy_nhwindow(win);
2410.     if (n > 0) {
2411. 	n = pick_list[0].item.a_int;
2412. 	free((genericptr_t) pick_list);
2413.     }
2414.     return n;
2415. }
2416. 
2417. /*pickup.c*/

Also on Fandom

Random Wiki