1    | /*	SCCS Id: @(#)invent.c	3.3	2000/04/12	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | #include "artifact.h"
7    | 
8    | #define NOINVSYM	'#'
9    | #define CONTAINED_SYM	'>'	/* designator for inside a container */
10   | 
11   | #ifdef OVL1
12   | STATIC_DCL void NDECL(reorder_invent);
13   | STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *));
14   | STATIC_DCL void FDECL(invdisp_nothing, (const char *,const char *));
15   | STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
16   | STATIC_DCL boolean FDECL(only_here, (struct obj *));
17   | #endif /* OVL1 */
18   | STATIC_DCL void FDECL(compactify,(char *));
19   | STATIC_PTR int FDECL(ckunpaid,(struct obj *));
20   | #ifdef OVLB
21   | STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
22   | STATIC_DCL void NDECL(dounpaid);
23   | STATIC_DCL struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
24   | STATIC_DCL void FDECL(menu_identify, (int));
25   | static boolean FDECL(tool_in_use, (struct obj *));
26   | #endif /* OVLB */
27   | STATIC_DCL char FDECL(obj_to_let,(struct obj *));
28   | 
29   | #ifdef OVLB
30   | 
31   | static int lastinvnr = 51;	/* 0 ... 51 (never saved&restored) */
32   | 
33   | #ifdef WIZARD
34   | /* wizards can wish for venom, which will become an invisible inventory
35   |  * item without this.  putting it in inv_order would mean venom would
36   |  * suddenly become a choice for all the inventory-class commands, which
37   |  * would probably cause mass confusion.  the test for inventory venom
38   |  * is only WIZARD and not wizard because the wizard can leave venom lying
39   |  * around on a bones level for normal players to find.
40   |  */
41   | static char venom_inv[] = { VENOM_CLASS, 0 };	/* (constant) */
42   | #endif
43   | 
44   | void
45   | assigninvlet(otmp)
46   | register struct obj *otmp;
47   | {
48   | 	boolean inuse[52];
49   | 	register int i;
50   | 	register struct obj *obj;
51   | 
52   | 	for(i = 0; i < 52; i++) inuse[i] = FALSE;
53   | 	for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
54   | 		i = obj->invlet;
55   | 		if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
56   | 		if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
57   | 		if(i == otmp->invlet) otmp->invlet = 0;
58   | 	}
59   | 	if((i = otmp->invlet) &&
60   | 	    (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
61   | 		return;
62   | 	for(i = lastinvnr+1; i != lastinvnr; i++) {
63   | 		if(i == 52) { i = -1; continue; }
64   | 		if(!inuse[i]) break;
65   | 	}
66   | 	otmp->invlet = (inuse[i] ? NOINVSYM :
67   | 			(i < 26) ? ('a'+i) : ('A'+i-26));
68   | 	lastinvnr = i;
69   | }
70   | 
71   | #endif /* OVLB */
72   | #ifdef OVL1
73   | 
74   | /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
75   | #define inv_rank(o) ((o)->invlet ^ 040)
76   | 
77   | /* sort the inventory; used by addinv() and doorganize() */
78   | STATIC_OVL void
79   | reorder_invent()
80   | {
81   | 	struct obj *otmp, *prev, *next;
82   | 	boolean need_more_sorting;
83   | 
84   | 	do {
85   | 	    /*
86   | 	     * We expect at most one item to be out of order, so this
87   | 	     * isn't nearly as inefficient as it may first appear.
88   | 	     */
89   | 	    need_more_sorting = FALSE;
90   | 	    for (otmp = invent, prev = 0; otmp; ) {
91   | 		next = otmp->nobj;
92   | 		if (next && inv_rank(next) < inv_rank(otmp)) {
93   | 		    need_more_sorting = TRUE;
94   | 		    if (prev) prev->nobj = next;
95   | 		    else      invent = next;
96   | 		    otmp->nobj = next->nobj;
97   | 		    next->nobj = otmp;
98   | 		    prev = next;
99   | 		} else {
100  | 		    prev = otmp;
101  | 		    otmp = next;
102  | 		}
103  | 	    }
104  | 	} while (need_more_sorting);
105  | }
106  | 
107  | #undef inv_rank
108  | 
109  | /* scan a list of objects to see whether another object will merge with
110  |    one of them; used in pickup.c when all 52 inventory slots are in use,
111  |    to figure out whether another object could still be picked up */
112  | struct obj *
113  | merge_choice(objlist, obj)
114  | struct obj *objlist, *obj;
115  | {
116  | 	struct monst *shkp;
117  | 	int save_nocharge;
118  | 
119  | 	if (obj->otyp == SCR_SCARE_MONSTER)	/* punt on these */
120  | 	    return (struct obj *)0;
121  | 	/* if this is an item on the shop floor, the attributes it will
122  | 	   have when carried are different from what they are now; prevent
123  | 	   that from eliciting an incorrect result from mergable() */
124  | 	save_nocharge = obj->no_charge;
125  | 	if (objlist == invent && obj->where == OBJ_FLOOR &&
126  | 		(shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
127  | 	    if (obj->no_charge) obj->no_charge = 0;
128  | 	    /* A billable object won't have its `unpaid' bit set, so would
129  | 	       erroneously seem to be a candidate to merge with a similar
130  | 	       ordinary object.  That's no good, because once it's really
131  | 	       picked up, it won't merge after all.  It might merge with
132  | 	       another unpaid object, but we can't check that here (depends
133  | 	       too much upon shk's bill) and if it doesn't merge it would
134  | 	       end up in the '#' overflow inventory slot, so reject it now. */
135  | 	    else if (inhishop(shkp)) return (struct obj *)0;
136  | 	}
137  | 	while (objlist) {
138  | 	    if (mergable(objlist, obj)) break;
139  | 	    objlist = objlist->nobj;
140  | 	}
141  | 	obj->no_charge = save_nocharge;
142  | 	return objlist;
143  | }
144  | 
145  | /* merge obj with otmp and delete obj if types agree */
146  | int
147  | merged(potmp, pobj)
148  | struct obj **potmp, **pobj;
149  | {
150  | 	register struct obj *otmp = *potmp, *obj = *pobj;
151  | 
152  | 	if(mergable(otmp, obj)) {
153  | 		/* Approximate age: we do it this way because if we were to
154  | 		 * do it "accurately" (merge only when ages are identical)
155  | 		 * we'd wind up never merging any corpses.
156  | 		 * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
157  | 		 *
158  | 		 * Don't do the age manipulation if lit.  We would need
159  | 		 * to stop the burn on both items, then merge the age,
160  | 		 * then restart the burn.
161  | 		 */
162  | 		if (!obj->lamplit)
163  | 		    otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
164  | 			    / (otmp->quan + obj->quan);
165  | 
166  | 		otmp->quan += obj->quan;
167  | 		otmp->owt += obj->owt;
168  | 		if(!otmp->onamelth && obj->onamelth)
169  | 			otmp = *potmp = oname(otmp, ONAME(obj));
170  | 		obj_extract_self(obj);
171  | 
172  | 		/* really should merge the timeouts */
173  | 		if (obj->lamplit) obj_merge_light_sources(obj, otmp);
174  | 		if (obj->timed) obj_stop_timers(obj);	/* follows lights */
175  | 
176  | 		/* fixup for `#adjust' merging wielded darts, daggers, &c */
177  | 		if (obj->owornmask) {
178  | 			otmp->owornmask |= obj->owornmask;
179  | 			/* (it isn't necessary to "unwear" `obj' first) */
180  | 			if (carried(otmp))
181  | 			    setworn(otmp, otmp->owornmask);
182  | #if 0
183  | 			/* (this should never be necessary, since items
184  | 			    already in a monster's inventory don't ever get
185  | 			    merged into other objects [only vice versa]) */
186  | 			else if (mcarried(otmp)) {
187  | 			    if (obj == MON_WEP(otmp->ocarry))
188  | 				MON_WEP(otmp->ocarry) = otmp;
189  | 			}
190  | #endif
191  | 		}
192  | 		obfree(obj,otmp);	/* free(obj), bill->otmp */
193  | 		return(1);
194  | 	}
195  | 	return 0;
196  | }
197  | 
198  | /*
199  | Adjust hero intrinsics as if this object was being added to the hero's
200  | inventory.  Called _before_ the object has been added to the hero's
201  | inventory.
202  | 
203  | This is called when adding objects to the hero's inventory normally (via
204  | addinv) or when an object in the hero's inventory has been polymorphed
205  | in-place.
206  | 
207  | It may be valid to merge this code with with addinv_core2().
208  | */
209  | void
210  | addinv_core1(obj)
211  | struct obj *obj;
212  | {
213  | 	if (obj->oclass == GOLD_CLASS) {
214  | 		u.ugold += obj->quan;
215  | 		flags.botl = 1;
216  | 	} else if (obj->otyp == AMULET_OF_YENDOR) {
217  | 		if (u.uhave.amulet) impossible("already have amulet?");
218  | 		u.uhave.amulet = 1;
219  | 	} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
220  | 		if (u.uhave.menorah) impossible("already have candelabrum?");
221  | 		u.uhave.menorah = 1;
222  | 	} else if (obj->otyp == BELL_OF_OPENING) {
223  | 		if (u.uhave.bell) impossible("already have silver bell?");
224  | 		u.uhave.bell = 1;
225  | 	} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
226  | 		if (u.uhave.book) impossible("already have the book?");
227  | 		u.uhave.book = 1;
228  | 	} else if (obj->oartifact) {
229  | 		if (is_quest_artifact(obj)) {
230  | 		    if (u.uhave.questart)
231  | 			impossible("already have quest artifact?");
232  | 		    u.uhave.questart = 1;
233  | 		    artitouch();
234  | 		}
235  | 		set_artifact_intrinsic(obj, 1, W_ART);
236  | 	}
237  | }
238  | 
239  | /*
240  | Adjust hero intrinsics as if this object was being added to the hero's
241  | inventory.  Called _after_ the object has been added to the hero's
242  | inventory.
243  | 
244  | This is called when adding objects to the hero's inventory normally (via
245  | addinv) or when an object in the hero's inventory has been polymorphed
246  | in-place.
247  | */
248  | void
249  | addinv_core2(obj)
250  | struct obj *obj;
251  | {
252  | 	if (obj->otyp == LUCKSTONE ||
253  | 	    (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
254  | 		/* new luckstone must be in inventory by this point
255  | 		 * for correct calculation */
256  | 		set_moreluck();
257  | 	}
258  | }
259  | 
260  | /*
261  | Add obj to the hero's inventory.  Make sure the object is "free".
262  | Adjust hero attributes as necessary.
263  | */
264  | struct obj *
265  | addinv(obj)
266  | struct obj *obj;
267  | {
268  | 	struct obj *otmp, *prev;
269  | 
270  | 	if (obj->where != OBJ_FREE)
271  | 	    panic("addinv: obj not free");
272  | 
273  | 	addinv_core1(obj);
274  | 	/* if handed gold, we're done */
275  | 	if (obj->oclass == GOLD_CLASS)
276  | 	    return obj;
277  | 
278  | 	/* merge if possible; find end of chain in the process */
279  | 	for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
280  | 	    if (merged(&otmp, &obj)) {
281  | 		obj = otmp;
282  | 		goto added;
283  | 	    }
284  | 	/* didn't merge, so insert into chain */
285  | 	if (flags.invlet_constant || !prev) {
286  | 	    if (flags.invlet_constant) assigninvlet(obj);
287  | 	    obj->nobj = invent;		/* insert at beginning */
288  | 	    invent = obj;
289  | 	    if (flags.invlet_constant) reorder_invent();
290  | 	} else {
291  | 	    prev->nobj = obj;		/* insert at end */
292  | 	    obj->nobj = 0;
293  | 	}
294  | 	obj->where = OBJ_INVENT;
295  | 
296  | added:
297  | 	addinv_core2(obj);
298  | 	carry_obj_effects(obj);		/* carrying affects the obj */
299  | 	update_inventory();
300  | 	return(obj);
301  | }
302  | 
303  | /*
304  |  * Some objects are affected by being carried.
305  |  * Make those adjustments here. Called _after_ the object
306  |  * has been added to the hero's or monster's inventory,
307  |  * and after hero's intrinsics have been updated.
308  |  */
309  | void
310  | carry_obj_effects(obj)
311  | struct obj *obj;
312  | {
313  | 	/* Cursed figurines can spontaneously transform
314  | 	   when carried. */
315  | 	if (obj->otyp == FIGURINE) {
316  | 		if (obj->cursed
317  | 	    	    && obj->corpsenm != NON_PM
318  | 	    	    && !dead_species(obj->corpsenm,TRUE)) {
319  | 			attach_fig_transform_timeout(obj);
320  | 		    }
321  | 	}
322  | }
323  | 
324  | #endif /* OVL1 */
325  | #ifdef OVLB
326  | 
327  | /* Add an item to the inventory unless we're fumbling, and give a message.
328  |  * If there aren't any free inventory slots, we'll drop it instead.
329  |  * If both success and failure messages are NULL, then we're just doing the
330  |  * fumbling/slot-limit checking for a silent grab.
331  |  */
332  | struct obj *
333  | hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
334  | struct obj *obj;
335  | const char *drop_fmt, *drop_arg, *hold_msg;
336  | {
337  | 	char buf[BUFSZ];
338  | 
339  | 	if (!Blind) obj->dknown = 1;	/* maximize mergibility */
340  | 	if (Fumbling) {
341  | 		if (drop_fmt) pline(drop_fmt, drop_arg);
342  | 		dropy(obj);
343  | 	} else {
344  | 		long oquan = obj->quan;
345  | 		int prev_encumbr = near_capacity();	/* before addinv() */
346  | 		/* encumbrance only matters if it would now become worse
347  | 		   than max( current_value, stressed ) */
348  | 		if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
349  | 		if (drop_arg) {
350  | 			/* addinv() may redraw the entire inventory, overwriting
351  | 			 * drop_arg when it comes from something like doname()
352  | 			 */
353  | 			Strcpy(buf, drop_arg);
354  | 			drop_arg = buf;
355  | 		}
356  | 		obj = addinv(obj);
357  | 		if (inv_cnt() > 52
358  | 		    || ((obj->otyp != LOADSTONE || !obj->cursed)
359  | 			&& near_capacity() > prev_encumbr)) {
360  | 			if (drop_fmt) pline(drop_fmt, drop_arg);
361  | 			/* undo any merge which took place */
362  | 			if (obj->quan > oquan) {
363  | 			    struct obj *otmp = splitobj(obj, oquan);
364  | 			    /* might have merged with weapon */
365  | 			    if (obj->owornmask)
366  | 				setworn(otmp, obj->owornmask);
367  | 			}
368  | 			dropx(obj);
369  | 		} else {
370  | 			if (flags.autoquiver && !uquiver &&
371  | 			    (is_missile(obj) ||
372  | 			     (uwep && ammo_and_launcher(obj, uwep))))
373  | 			    setuqwep(obj);
374  | 			if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
375  | 		}
376  | 	}
377  | 	return obj;
378  | }
379  | 
380  | /* useup() all of an item regardless of its quantity */
381  | void
382  | useupall(obj)
383  | struct obj *obj;
384  | {
385  | 	setnotworn(obj);
386  | 	freeinv(obj);
387  | 	obfree(obj, (struct obj *)0);	/* deletes contents also */
388  | }
389  | 
390  | void
391  | useup(obj)
392  | register struct obj *obj;
393  | {
394  | 	/*  Note:  This works correctly for containers because they */
395  | 	/*	   (containers) don't merge.			    */
396  | 	if (obj->quan > 1L) {
397  | 		obj->in_use = FALSE;	/* no longer in use */
398  | 		obj->quan--;
399  | 		obj->owt = weight(obj);
400  | 		update_inventory();
401  | 	} else {
402  | 		useupall(obj);
403  | 	}
404  | }
405  | 
406  | #endif /* OVLB */
407  | #ifdef OVL3
408  | 
409  | /*
410  | Adjust hero's attributes as if this object was being removed from the
411  | hero's inventory.  This should only be called from freeinv() and
412  | where we are polymorphing an object already in the hero's inventory.
413  | 
414  | Should think of a better name...
415  | */
416  | void
417  | freeinv_core(obj)
418  | struct obj *obj;
419  | {
420  | 	if (obj->oclass == GOLD_CLASS) {
421  | 		u.ugold -= obj->quan;
422  | 		flags.botl = 1;
423  | 		return;
424  | 	} else if (obj->otyp == AMULET_OF_YENDOR) {
425  | 		if (!u.uhave.amulet) impossible("don't have amulet?");
426  | 		u.uhave.amulet = 0;
427  | 	} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
428  | 		if (!u.uhave.menorah) impossible("don't have candelabrum?");
429  | 		u.uhave.menorah = 0;
430  | 	} else if (obj->otyp == BELL_OF_OPENING) {
431  | 		if (!u.uhave.bell) impossible("don't have silver bell?");
432  | 		u.uhave.bell = 0;
433  | 	} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
434  | 		if (!u.uhave.book) impossible("don't have the book?");
435  | 		u.uhave.book = 0;
436  | 	} else if (obj->oartifact) {
437  | 		if (is_quest_artifact(obj)) {
438  | 		    if (!u.uhave.questart)
439  | 			impossible("don't have quest artifact?");
440  | 		    u.uhave.questart = 0;
441  | 		}
442  | 		set_artifact_intrinsic(obj, 0, W_ART);
443  | 	}
444  | 
445  | 	if (obj->otyp == LOADSTONE) {
446  | 		curse(obj);
447  | 	} else if (obj->otyp == LUCKSTONE ||
448  | 		    (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
449  | 		set_moreluck();
450  | 		flags.botl = 1;
451  | 	} else if (obj->otyp == FIGURINE && obj->timed) {
452  | 		(void) stop_timer(FIG_TRANSFORM, (genericptr_t) obj);
453  | 	}
454  | }
455  | 
456  | /* remove an object from the hero's inventory */
457  | void
458  | freeinv(obj)
459  | register struct obj *obj;
460  | {
461  | 	extract_nobj(obj, &invent);
462  | 	freeinv_core(obj);
463  | 	update_inventory();
464  | }
465  | 
466  | void
467  | delallobj(x, y)
468  | int x, y;
469  | {
470  | 	struct obj *otmp, *otmp2;
471  | 
472  | 	for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
473  | 		if (otmp == uball)
474  | 			unpunish();
475  | 		/* after unpunish(), or might get deallocated chain */
476  | 		otmp2 = otmp->nexthere;
477  | 		if (otmp == uchain)
478  | 			continue;
479  | 		delobj(otmp);
480  | 	}
481  | }
482  | 
483  | #endif /* OVL3 */
484  | #ifdef OVL2
485  | 
486  | /* destroy object in fobj chain (if unpaid, it remains on the bill) */
487  | void
488  | delobj(obj)
489  | register struct obj *obj;
490  | {
491  | 	boolean update_map;
492  | 
493  | 	if (obj->otyp == AMULET_OF_YENDOR ||
494  | 			obj->otyp == CANDELABRUM_OF_INVOCATION ||
495  | 			obj->otyp == BELL_OF_OPENING ||
496  | 			obj->otyp == SPE_BOOK_OF_THE_DEAD) {
497  | 		/* player might be doing something stupid, but we
498  | 		 * can't guarantee that.  assume special artifacts
499  | 		 * are indestructible via drawbridges, and exploding
500  | 		 * chests, and golem creation, and ...
501  | 		 */
502  | 		return;
503  | 	}
504  | 	update_map = (obj->where == OBJ_FLOOR);
505  | 	obj_extract_self(obj);
506  | 	if (update_map) newsym(obj->ox, obj->oy);
507  | 	obfree(obj, (struct obj *) 0);	/* frees contents also */
508  | }
509  | 
510  | #endif /* OVL2 */
511  | #ifdef OVL0
512  | 
513  | struct obj *
514  | sobj_at(n,x,y)
515  | register int n, x, y;
516  | {
517  | 	register struct obj *otmp;
518  | 
519  | 	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
520  | 		if(otmp->otyp == n)
521  | 		    return(otmp);
522  | 	return((struct obj *)0);
523  | }
524  | 
525  | #endif /* OVL0 */
526  | #ifdef OVLB
527  | 
528  | struct obj *
529  | carrying(type)
530  | register int type;
531  | {
532  | 	register struct obj *otmp;
533  | 
534  | 	for(otmp = invent; otmp; otmp = otmp->nobj)
535  | 		if(otmp->otyp == type)
536  | 			return(otmp);
537  | 	return((struct obj *) 0);
538  | }
539  | 
540  | boolean
541  | have_lizard()
542  | {
543  | 	register struct obj *otmp;
544  | 
545  | 	for(otmp = invent; otmp; otmp = otmp->nobj)
546  | 		if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
547  | 			return(TRUE);
548  | 	return(FALSE);
549  | }
550  | 
551  | struct obj *
552  | o_on(id, objchn)
553  | unsigned int id;
554  | register struct obj *objchn;
555  | {
556  | 	struct obj *temp;
557  | 
558  | 	while(objchn) {
559  | 		if(objchn->o_id == id) return(objchn);
560  | 		if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
561  | 			return temp;
562  | 		objchn = objchn->nobj;
563  | 	}
564  | 	return((struct obj *) 0);
565  | }
566  | 
567  | boolean
568  | obj_here(obj, x, y)
569  | register struct obj *obj;
570  | int x, y;
571  | {
572  | 	register struct obj *otmp;
573  | 
574  | 	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
575  | 		if(obj == otmp) return(TRUE);
576  | 	return(FALSE);
577  | }
578  | 
579  | #endif /* OVLB */
580  | #ifdef OVL2
581  | 
582  | struct obj *
583  | g_at(x,y)
584  | register int x, y;
585  | {
586  | 	register struct obj *obj = level.objects[x][y];
587  | 	while(obj) {
588  | 	    if (obj->oclass == GOLD_CLASS) return obj;
589  | 	    obj = obj->nexthere;
590  | 	}
591  | 	return((struct obj *)0);
592  | }
593  | 
594  | #endif /* OVL2 */
595  | #ifdef OVLB
596  | 
597  | /* Make a gold object from the hero's gold. */
598  | struct obj *
599  | mkgoldobj(q)
600  | register long q;
601  | {
602  | 	register struct obj *otmp;
603  | 
604  | 	otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
605  | 	u.ugold -= q;
606  | 	otmp->quan = q;
607  | 	otmp->owt = weight(otmp);
608  | 	flags.botl = 1;
609  | 	return(otmp);
610  | }
611  | 
612  | #endif /* OVLB */
613  | #ifdef OVL1
614  | 
615  | STATIC_OVL void
616  | compactify(buf)
617  | register char *buf;
618  | /* compact a string of inventory letters by dashing runs of letters */
619  | {
620  | 	register int i1 = 1, i2 = 1;
621  | 	register char ilet, ilet1, ilet2;
622  | 
623  | 	ilet2 = buf[0];
624  | 	ilet1 = buf[1];
625  | 	buf[++i2] = buf[++i1];
626  | 	ilet = buf[i1];
627  | 	while(ilet) {
628  | 		if(ilet == ilet1+1) {
629  | 			if(ilet1 == ilet2+1)
630  | 				buf[i2 - 1] = ilet1 = '-';
631  | 			else if(ilet2 == '-') {
632  | 				buf[i2 - 1] = ++ilet1;
633  | 				buf[i2] = buf[++i1];
634  | 				ilet = buf[i1];
635  | 				continue;
636  | 			}
637  | 		}
638  | 		ilet2 = ilet1;
639  | 		ilet1 = ilet;
640  | 		buf[++i2] = buf[++i1];
641  | 		ilet = buf[i1];
642  | 	}
643  | }
644  | 
645  | /*
646  |  * getobj returns:
647  |  *	struct obj *xxx:	object to do something with.
648  |  *	(struct obj *) 0	error return: no object.
649  |  *	&zeroobj		explicitly no object (as in w-).
650  |  */
651  | struct obj *
652  | getobj(let,word)
653  | register const char *let,*word;
654  | {
655  | 	register struct obj *otmp;
656  | 	register char ilet;
657  | 	char buf[BUFSZ], qbuf[QBUFSZ];
658  | 	char lets[BUFSZ], altlets[BUFSZ], *ap;
659  | 	register int foo = 0;
660  | 	register char *bp = buf;
661  | 	xchar allowcnt = 0;	/* 0, 1 or 2 */
662  | 	boolean allowgold = FALSE, usegold = FALSE;
663  | 		/* Two possibilities: they can't use gold because it's illegal,
664  | 		 * or they can't use gold because they don't have any.
665  | 		 */
666  | 	boolean allowall = FALSE;
667  | 	boolean allownone = FALSE;
668  | 	xchar foox = 0;
669  | 	long cnt;
670  | 	boolean prezero = FALSE;
671  | 	long dummymask;
672  | 
673  | 	if(*let == ALLOW_COUNT) let++, allowcnt = 1;
674  | 	if(*let == GOLD_CLASS) let++,
675  | 		usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
676  | 
677  | 	/* Equivalent of an "ugly check" for gold */
678  | 	if (usegold && !strcmp(word, "eat") && !metallivorous(youmonst.data))
679  | 		usegold = allowgold = FALSE;
680  | 
681  | 	if(*let == ALL_CLASSES) let++, allowall = TRUE;
682  | 	if(*let == ALLOW_NONE) let++, allownone = TRUE;
683  | 	/* "ugly check" for reading fortune cookies, part 1 */
684  | 	/* The normal 'ugly check' keeps the object on the inventory list.
685  | 	 * We don't want to do that for shirts/cookies, so the check for
686  | 	 * them is handled a bit differently (and also requires that we set
687  | 	 * allowall in the caller)
688  | 	 */
689  | 	if(allowall && !strcmp(word, "read")) allowall = FALSE;
690  | 
691  | 	if(allownone) *bp++ = '-';
692  | 	if(allowgold) *bp++ = def_oc_syms[GOLD_CLASS];
693  | 	if(bp > buf && bp[-1] == '-') *bp++ = ' ';
694  | 	ap = altlets;
695  | 
696  | 	ilet = 'a';
697  | 	for (otmp = invent; otmp; otmp = otmp->nobj) {
698  | 	    if (!flags.invlet_constant) otmp->invlet = ilet;	/* reassign() */
699  | 	    if (!*let || index(let, otmp->oclass)) {
700  | 		register int otyp = otmp->otyp;
701  | 		bp[foo++] = otmp->invlet;
702  | 
703  | 		/* ugly check: remove inappropriate things */
704  | 		if((!strcmp(word, "take off") &&
705  | 		    (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
706  | 		     || (otmp==uarm && uarmc)
707  | #ifdef TOURIST
708  | 		     || (otmp==uarmu && (uarm || uarmc))
709  | #endif
710  | 		    ))
711  | 		|| (!strcmp(word, "wear") &&
712  | 		     (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
713  | 							/* already worn */
714  | 		|| (!strcmp(word, "wield") &&
715  | 		    (otmp->owornmask & W_WEP))
716  | 		|| (!strcmp(word, "ready") &&
717  | 		    (otmp->owornmask & (W_WEP | W_SWAPWEP | W_QUIVER)))
718  | 		    ) {
719  | 			foo--;
720  | 			foox++;
721  | 		}
722  | 
723  | 		/* Second ugly check; unlike the first it won't trigger an
724  | 		 * "else" in "you don't have anything else to ___".
725  | 		 */
726  | 		else if ((!strcmp(word, "wear") &&
727  | 		    ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) ||
728  | 		    (otmp->oclass == TOOL_CLASS &&
729  | 		     otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES)))
730  | 		|| (!strcmp(word, "wield") &&
731  | 		    (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
732  | 		|| (!strcmp(word, "eat") && !is_edible(otmp))
733  | 		|| (!strcmp(word, "sacrifice") &&
734  | 		    (otyp != CORPSE &&
735  | 		     otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
736  | 		|| (!strcmp(word, "write with") &&
737  | 		    (otmp->oclass == TOOL_CLASS &&
738  | 		     otyp != MAGIC_MARKER && otyp != TOWEL))
739  | 		|| (!strcmp(word, "tin") &&
740  | 		    (otyp != CORPSE || !tinnable(otmp)))
741  | 		|| (!strcmp(word, "rub") &&
742  | 		    (otmp->oclass == TOOL_CLASS &&
743  | 		     otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
744  | 		     otyp != BRASS_LANTERN))
745  | 		|| ((!strcmp(word, "use or apply") ||
746  | 			!strcmp(word, "untrap with")) &&
747  | 		     /* Picks, axes, pole-weapons, bullwhips */
748  | 		    ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
749  | 		      !is_pole(otmp) && otyp != BULLWHIP)
750  | 		|| (otmp->oclass == POTION_CLASS &&
751  | 		     /* only applicable potion is oil, and it will only
752  | 			be offered as a choice when already discovered */
753  | 		     (otyp != POT_OIL || !otmp->dknown ||
754  | 		      !objects[POT_OIL].oc_name_known))))
755  | 		|| (!strcmp(word, "invoke") &&
756  | 		    (!otmp->oartifact && !objects[otyp].oc_unique &&
757  | 		     (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
758  | 		     otyp != CRYSTAL_BALL &&	/* #invoke synonym for apply */
759  | 		   /* note: presenting the possibility of invoking non-artifact
760  | 		      mirrors and/or lamps is a simply a cruel deception... */
761  | 		     otyp != MIRROR && otyp != MAGIC_LAMP &&
762  | 		     (otyp != OIL_LAMP ||	/* don't list known oil lamp */
763  | 		      (otmp->dknown && objects[OIL_LAMP].oc_name_known))))
764  | 		|| (!strcmp(word, "untrap with") &&
765  | 		    (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
766  | 		|| (!strcmp(word, "charge") && !is_chargeable(otmp))
767  | 		    )
768  | 			foo--;
769  | 		/* ugly check for unworn armor that can't be worn */
770  | 		else if (!strcmp(word, "wear") && *let == ARMOR_CLASS &&
771  | 			 !canwearobj(otmp, &dummymask, FALSE)) {
772  | 			foo--;
773  | 			allowall = TRUE;
774  | 			*ap++ = otmp->invlet;
775  | 		}
776  | 	    } else {
777  | 
778  | 		/* "ugly check" for reading fortune cookies, part 2 */
779  | 		if ((!strcmp(word, "read") &&
780  | 		    (otmp->otyp == FORTUNE_COOKIE
781  | #ifdef TOURIST
782  | 			|| otmp->otyp == T_SHIRT
783  | #endif
784  | 		    )))
785  | 			allowall = TRUE;
786  | 	    }
787  | 
788  | 	    if(ilet == 'z') ilet = 'A'; else ilet++;
789  | 	}
790  | 	bp[foo] = 0;
791  | 	if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
792  | 	Strcpy(lets, bp);	/* necessary since we destroy buf */
793  | 	if(foo > 5)			/* compactify string */
794  | 		compactify(bp);
795  | 	*ap = '\0';
796  | 
797  | 	if(!foo && !allowall && !allowgold && !allownone) {
798  | 		You("don't have anything %sto %s.",
799  | 			foox ? "else " : "", word);
800  | 		return((struct obj *)0);
801  | 	}
802  | 	for(;;) {
803  | 		cnt = 0;
804  | 		if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
805  | 		if(!buf[0]) {
806  | 			Sprintf(qbuf, "What do you want to %s? [*]", word);
807  | 		} else {
808  | 			Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
809  | 				word, buf);
810  | 		}
811  | #ifdef REDO
812  | 		if (in_doagain)
813  | 		    ilet = readchar();
814  | 		else
815  | #endif
816  | 		    ilet = yn_function(qbuf, (char *)0, '\0');
817  | 		if(ilet == '0') prezero = TRUE;
818  | 		while(digit(ilet) && allowcnt) {
819  | #ifdef REDO
820  | 			if (ilet != '?' && ilet != '*')	savech(ilet);
821  | #endif
822  | 			cnt = 10*cnt + (ilet - '0');
823  | 			allowcnt = 2;	/* signal presence of cnt */
824  | 			ilet = readchar();
825  | 		}
826  | 		if(digit(ilet)) {
827  | 			pline("No count allowed with this command.");
828  | 			continue;
829  | 		}
830  | 		if(index(quitchars,ilet)) {
831  | 		    if(flags.verbose)
832  | 			pline(Never_mind);
833  | 		    return((struct obj *)0);
834  | 		}
835  | 		if(ilet == '-') {
836  | 			return(allownone ? &zeroobj : (struct obj *) 0);
837  | 		}
838  | 		if(ilet == def_oc_syms[GOLD_CLASS]) {
839  | 			if(!usegold){
840  | 				You("cannot %s gold.", word);
841  | 				return(struct obj *)0;
842  | 			} else if (!allowgold) {
843  | 				You("are not carrying any gold.");
844  | 				return(struct obj *)0;
845  | 			}
846  | 			if(cnt == 0 && prezero) return((struct obj *)0);
847  | 			/* Historic note: early Nethack had a bug which was
848  | 			 * first reported for Larn, where trying to drop 2^32-n
849  | 			 * gold pieces was allowed, and did interesting things
850  | 			 * to your money supply.  The LRS is the tax bureau
851  | 			 * from Larn.
852  | 			 */
853  | 			if(cnt < 0) {
854  | 	pline_The("LRS would be very interested to know you have that much.");
855  | 				return(struct obj *)0;
856  | 			}
857  | 
858  | 			if(!(allowcnt == 2 && cnt < u.ugold))
859  | 				cnt = u.ugold;
860  | 			return(mkgoldobj(cnt));
861  | 		}
862  | 		if(allowcnt == 2 && !strcmp(word,"throw")) {
863  | 			/* permit counts for throwing gold, but don't accept
864  | 			 * counts for other things since the throw code will
865  | 			 * split off a single item anyway */
866  | 			allowcnt = 1;
867  | 			if(cnt == 0 && prezero) return((struct obj *)0);
868  | 			if(cnt > 1) {
869  | 			    You("can only throw one item at a time.");
870  | 			    continue;
871  | 			}
872  | 		}
873  | 		if(ilet == '?' || ilet == '*') {
874  | 		    char *allowed_choices = (ilet == '?') ? lets : (char *)0;
875  | 
876  | 		    if (ilet == '?' && !*lets && *altlets)
877  | 			allowed_choices = altlets;
878  | 		    ilet = display_inventory(allowed_choices, TRUE);
879  | 		    if(!ilet) continue;
880  | 		    if(ilet == '\033') {
881  | 			if(flags.verbose)
882  | 			    pline(Never_mind);
883  | 			return((struct obj *)0);
884  | 		    }
885  | 		    /* they typed a letter (not a space) at the prompt */
886  | 		}
887  | #ifdef REDO
888  | 		savech(ilet);
889  | #endif
890  | 		for (otmp = invent; otmp; otmp = otmp->nobj)
891  | 			if (otmp->invlet == ilet) break;
892  | 		if(!otmp) {
893  | 			You("don't have that object.");
894  | #ifdef REDO
895  | 			if (in_doagain) return((struct obj *) 0);
896  | #endif
897  | 			continue;
898  | 		} else if (cnt < 0 || otmp->quan < cnt) {
899  | 			You("don't have that many!  You have only %ld.",
900  | 			    otmp->quan);
901  | #ifdef REDO
902  | 			if (in_doagain) return((struct obj *) 0);
903  | #endif
904  | 			continue;
905  | 		}
906  | 		break;
907  | 	}
908  | 	if(!allowall && let && !index(let,otmp->oclass)) {
909  | 		pline(silly_thing_to, word);
910  | 		return((struct obj *)0);
911  | 	}
912  | 	if(allowcnt == 2) {	/* cnt given */
913  | 		if(cnt == 0) return (struct obj *)0;
914  | 		if(cnt != otmp->quan) {
915  | 			register struct obj *obj = splitobj(otmp, cnt);
916  | 		/* Very ugly kludge necessary to prevent someone from trying
917  | 		 * to drop one of several loadstones and having the loadstone
918  | 		 * now be separate.
919  | 		 */
920  | 			if (!strcmp(word, "drop") &&
921  | 			    obj->otyp == LOADSTONE && obj->cursed)
922  | 				otmp->corpsenm = obj->invlet;
923  | 			if(otmp == uwep) setuwep(obj);
924  | 			else if (otmp == uquiver) setuqwep(obj);
925  | 			if (otmp == uswapwep) setuswapwep(obj);
926  | 		}
927  | 	}
928  | 	return(otmp);
929  | }
930  | 
931  | #endif /* OVL1 */
932  | #ifdef OVLB
933  | 
934  | STATIC_PTR int
935  | ckunpaid(otmp)
936  | register struct obj *otmp;
937  | {
938  | 	return((int)(otmp->unpaid));
939  | }
940  | 
941  | boolean
942  | wearing_armor()
943  | {
944  | 	return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
945  | #ifdef TOURIST
946  | 		|| uarmu
947  | #endif
948  | 		));
949  | }
950  | 
951  | boolean
952  | is_worn(otmp)
953  | register struct obj *otmp;
954  | {
955  |     return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
956  | #ifdef STEED
957  | 			W_SADDLE |
958  | #endif
959  | 			W_WEP | W_SWAPWEP | W_QUIVER))));
960  | }
961  | 
962  | static NEARDATA const char removeables[] =
963  | 	{ ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
964  | 
965  | /* interactive version of getobj - used for Drop, Identify and */
966  | /* Takeoff (A). Return the number of times fn was called successfully */
967  | /* If combo is TRUE, we just use this to get a category list */
968  | int
969  | ggetobj(word, fn, mx, combo)
970  | const char *word;
971  | int FDECL((*fn),(OBJ_P)), mx;
972  | boolean combo;		/* combination menu flag */
973  | {
974  | 	int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0;
975  | 	boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0;
976  | 	boolean takeoff, ident, allflag, m_seen;
977  | 	int oletct, iletct, allowgold, unpaid, oc_of_sym;
978  | 	char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5];
979  | 	char buf[BUFSZ], qbuf[QBUFSZ];
980  | 
981  | 	allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;
982  | 	takeoff = ident = allflag = m_seen = FALSE;
983  | 	if(!invent && !allowgold){
984  | 		You("have nothing to %s.", word);
985  | 		return(0);
986  | 	}
987  | 	if (combo) add_valid_menu_class(0);	/* reset */
988  | 	if (!strcmp(word, "take off")) {
989  | 	    takeoff = TRUE;
990  | 	    filter = is_worn;
991  | 	} else if (!strcmp(word, "identify")) {
992  | 	    ident = TRUE;
993  | 	    filter = not_fully_identified;
994  | 	}
995  | 
996  | 	iletct = collect_obj_classes(ilets, invent,
997  | 				     FALSE, (allowgold != 0), filter);
998  | 	unpaid = count_unpaid(invent);
999  | 
1000 | 	if (ident && !iletct) {
1001 | 	    return -1;		/* no further identifications */
1002 | 	} else if (!takeoff && (unpaid || invent)) {
1003 | 	    ilets[iletct++] = ' ';
1004 | 	    if (unpaid) ilets[iletct++] = 'u';
1005 | 	    if (invent) ilets[iletct++] = 'a';
1006 | 	} else if (takeoff && invent) {
1007 | 	    ilets[iletct++] = ' ';
1008 | 	}
1009 | 	ilets[iletct++] = 'i';
1010 | 	if (!combo)
1011 | 	    ilets[iletct++] = 'm';	/* allow menu presentation on request */
1012 | 	ilets[iletct] = '\0';
1013 | 
1014 | 	for (;;) {
1015 | 	    Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
1016 | 		    word, ilets);
1017 | 	    getlin(qbuf, buf);
1018 | 	    if (buf[0] == '\033') return(0);
1019 | 	    if (index(buf, 'i')) {
1020 | 		if (display_inventory((char *)0, TRUE) == '\033') return 0;
1021 | 	    } else
1022 | 		break;
1023 | 	}
1024 | 
1025 | 	ip = buf;
1026 | 	olets[oletct = 0] = '\0';
1027 | 	while ((sym = *ip++) != '\0') {
1028 | 	    if (sym == ' ') continue;
1029 | 	    oc_of_sym = def_char_to_objclass(sym);
1030 | 	    if (takeoff && !(uwep && oc_of_sym == uwep->oclass) &&
1031 | 		    (oc_of_sym != MAXOCLASSES)) {
1032 | 		if (!index(removeables, oc_of_sym)) {
1033 | 		    pline("Not applicable.");
1034 | 		    return 0;
1035 | 		} else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1036 | 		    You("are not wearing any armor.");
1037 | 		    return 0;
1038 | 		} else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep && !uquiver) {
1039 | 		    You("are not wielding anything.");
1040 | 		    return 0;
1041 | 		} else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1042 | 		    You("are not wearing rings.");
1043 | 		    return 0;
1044 | 		} else if (oc_of_sym == AMULET_CLASS && !uamul) {
1045 | 		    You("are not wearing an amulet.");
1046 | 		    return 0;
1047 | 		} else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1048 | 		    You("are not wearing a blindfold.");
1049 | 		    return 0;
1050 | 		}
1051 | 	    }
1052 | 
1053 | 	    if (oc_of_sym == GOLD_CLASS && !combo) {
1054 | 		if (allowgold == 1)
1055 | 		    (*fn)(mkgoldobj(u.ugold));
1056 | 		else if (!u.ugold)
1057 | 		    You("have no gold.");
1058 | 		allowgold = 2;
1059 | 	    } else if (sym == 'a') {
1060 | 		allflag = TRUE;
1061 | 	    } else if (sym == 'A') {
1062 | 		/* same as the default */ ;
1063 | 	    } else if (sym == 'u' || sym == 'U') {
1064 | 		add_valid_menu_class('u');
1065 | 		ckfn = ckunpaid;
1066 | 	    } else if (sym == 'm') {
1067 | 		m_seen = TRUE;
1068 | 	    } else if (oc_of_sym == MAXOCLASSES) {
1069 | 		You("don't have any %c's.", sym);
1070 | 	    } else if (oc_of_sym != VENOM_CLASS) {	/* suppress venom */
1071 | 		if (!index(olets, oc_of_sym)) {
1072 | 		    add_valid_menu_class(oc_of_sym);
1073 | 		    olets[oletct++] = oc_of_sym;
1074 | 		    olets[oletct] = 0;
1075 | 		}
1076 | 	    }
1077 | 	}
1078 | 
1079 | 	if (m_seen)
1080 | 	    return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
1081 | 	else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
1082 | 	    return 0;
1083 | 	else if (allowgold == 2 && !oletct)
1084 | 	    return 1;	/* you dropped gold (or at least tried to) */
1085 | 	else
1086 | 	    return askchain(&invent, olets, allflag, fn, ckfn, mx, word);
1087 | }
1088 | 
1089 | /*
1090 |  * Walk through the chain starting at objchn and ask for all objects
1091 |  * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1092 |  * whether the action in question (i.e., fn) has to be performed.
1093 |  * If allflag then no questions are asked. Max gives the max nr of
1094 |  * objects to be treated. Return the number of objects treated.
1095 |  */
1096 | int
1097 | askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1098 | struct obj **objchn;
1099 | register int allflag, mx;
1100 | register const char *olets, *word;	/* olets is an Obj Class char array */
1101 | register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
1102 | {
1103 | 	register struct obj *otmp, *otmp2;
1104 | 	register char sym, ilet;
1105 | 	register int cnt = 0, dud = 0, tmp;
1106 | 	boolean takeoff, nodot, ident, ininv;
1107 | 	char qbuf[QBUFSZ];
1108 | 
1109 | 	takeoff = !strcmp(word, "take off");
1110 | 	ident = !strcmp(word, "identify");
1111 | 	nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
1112 | 		 ident || takeoff);
1113 | 	ininv = (*objchn == invent);
1114 | 	/* Changed so the askchain is interrogated in the order specified.
1115 | 	 * For example, if a person specifies =/ then first all rings will be
1116 | 	 * asked about followed by all wands -dgk
1117 | 	 */
1118 | nextclass:
1119 | 	ilet = 'a'-1;
1120 | 	if (*objchn && (*objchn)->oclass == GOLD_CLASS)
1121 | 		ilet--;		/* extra iteration */
1122 | 	for (otmp = *objchn; otmp; otmp = otmp2) {
1123 | 		if(ilet == 'z') ilet = 'A'; else ilet++;
1124 | 		otmp2 = otmp->nobj;
1125 | 		if (olets && *olets && otmp->oclass != *olets) continue;
1126 | 		if (takeoff && !is_worn(otmp)) continue;
1127 | 		if (ident && !not_fully_identified(otmp)) continue;
1128 | 		if (ckfn && !(*ckfn)(otmp)) continue;
1129 | 		if (!allflag) {
1130 | 			Strcpy(qbuf, !ininv ? doname(otmp) :
1131 | 				xprname(otmp, (char *)0, ilet, !nodot, 0L));
1132 | 			Strcat(qbuf, "?");
1133 | 			sym = (takeoff || ident || otmp->quan < 2L) ?
1134 | 				nyaq(qbuf) : nyNaq(qbuf);
1135 | 		}
1136 | 		else	sym = 'y';
1137 | 
1138 | 		if (sym == '#') {
1139 | 		 /* Number was entered; split the object unless it corresponds
1140 | 		    to 'none' or 'all'.  2 special cases: cursed loadstones and
1141 | 		    welded weapons (eg, multiple daggers) will remain as merged
1142 | 		    unit; done to avoid splitting an object that won't be
1143 | 		    droppable (even if we're picking up rather than dropping).
1144 | 		  */
1145 | 		    if (!yn_number)
1146 | 			sym = 'n';
1147 | 		    else {
1148 | 			sym = 'y';
1149 | 			if (yn_number < otmp->quan && !welded(otmp) &&
1150 | 			    (!otmp->cursed || otmp->otyp != LOADSTONE)) {
1151 | 			    struct obj *otmpx = splitobj(otmp, yn_number);
1152 | 			    if (!otmpx || otmpx->nobj != otmp2)
1153 | 				impossible("bad object split in askchain");
1154 | 			    /* assume other worn items aren't mergable */
1155 | 			    if (otmp == uwep) setuwep(otmpx);
1156 | 				if (otmp == uquiver) setuqwep(otmpx);
1157 | 				if (otmp == uswapwep) setuswapwep(otmpx);
1158 | 			}
1159 | 		    }
1160 | 		}
1161 | 		switch(sym){
1162 | 		case 'a':
1163 | 			allflag = 1;
1164 | 		case 'y':
1165 | 			tmp = (*fn)(otmp);
1166 | 			if(tmp < 0) goto ret;
1167 | 			cnt += tmp;
1168 | 			if(--mx == 0) goto ret;
1169 | 		case 'n':
1170 | 			if(nodot) dud++;
1171 | 		default:
1172 | 			break;
1173 | 		case 'q':
1174 | 			/* special case for seffects() */
1175 | 			if (ident) cnt = -1;
1176 | 			goto ret;
1177 | 		}
1178 | 	}
1179 | 	if (olets && *olets && *++olets)
1180 | 		goto nextclass;
1181 | 	if(!takeoff && (dud || cnt)) pline("That was all.");
1182 | 	else if(!dud && !cnt) pline("No applicable objects.");
1183 | ret:
1184 | 	return(cnt);
1185 | }
1186 | 
1187 | 
1188 | /*
1189 |  *	Object identification routines:
1190 |  */
1191 | 
1192 | /* make an object actually be identified; no display updating */
1193 | void
1194 | fully_identify_obj(otmp)
1195 | struct obj *otmp;
1196 | {
1197 |     makeknown(otmp->otyp);
1198 |     if (otmp->oartifact) discover_artifact((xchar)otmp->oartifact);
1199 |     otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1200 |     if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1201 | 	learn_egg_type(otmp->corpsenm);
1202 | }
1203 | 
1204 | /* ggetobj callback routine; identify an object and give immediate feedback */
1205 | int
1206 | identify(otmp)
1207 | struct obj *otmp;
1208 | {
1209 |     fully_identify_obj(otmp);
1210 |     prinv((char *)0, otmp, 0L);
1211 |     return 1;
1212 | }
1213 | 
1214 | /* menu of unidentified objects; select and identify up to id_limit of them */
1215 | STATIC_OVL void
1216 | menu_identify(id_limit)
1217 | int id_limit;
1218 | {
1219 |     menu_item *pick_list;
1220 |     int n, i, first = 1;
1221 |     char buf[BUFSZ];
1222 |     /* assumptions:  id_limit > 0 and at least one unID'd item is present */
1223 | 
1224 |     while (id_limit) {
1225 | 	Sprintf(buf, "What would you like to identify %s?",
1226 | 		first ? "first" : "next");
1227 | 	n = query_objlist(buf, invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT,
1228 | 		&pick_list, PICK_ANY, not_fully_identified);
1229 | 
1230 | 	if (n > 0) {
1231 | 	    if (n > id_limit) n = id_limit;
1232 | 	    for (i = 0; i < n; i++, id_limit--)
1233 | 		(void) identify(pick_list[i].item.a_obj);
1234 | 	    free((genericptr_t) pick_list);
1235 | 	    mark_synch(); /* Before we loop to pop open another menu */
1236 | 	} else {
1237 | 	    if (n < 0) pline("That was all.");
1238 | 	    id_limit = 0; /* Stop now */
1239 | 	}
1240 | 	first = 0;
1241 |     }
1242 | }
1243 | 
1244 | /* dialog with user to identify a given number of items; 0 means all */
1245 | void
1246 | identify_pack(id_limit)
1247 | int id_limit;
1248 | {
1249 |     struct obj *obj, *the_obj;
1250 |     int n, unid_cnt;
1251 | 
1252 |     unid_cnt = 0;
1253 |     the_obj = 0;		/* if unid_cnt ends up 1, this will be it */
1254 |     for (obj = invent; obj; obj = obj->nobj)
1255 | 	if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj;
1256 | 
1257 |     if (!unid_cnt) {
1258 | 	You("have already identified all of your possessions.");
1259 |     } else if (!id_limit) {
1260 | 	/* identify everything */
1261 | 	if (unid_cnt == 1) {
1262 | 	    (void) identify(the_obj);
1263 | 	} else {
1264 | 
1265 | 	    /* TODO:  use fully_identify_obj and cornline/menu/whatever here */
1266 | 	    for (obj = invent; obj; obj = obj->nobj)
1267 | 		if (not_fully_identified(obj)) (void) identify(obj);
1268 | 
1269 | 	}
1270 |     } else {
1271 | 	/* identify up to `id_limit' items */
1272 | 	n = 0;
1273 | 	if (flags.menu_style == MENU_TRADITIONAL)
1274 | 	    do {
1275 | 		n = ggetobj("identify", identify, id_limit, FALSE);
1276 | 		if (n < 0) break; /* quit or no eligible items */
1277 | 	    } while ((id_limit -= n) > 0);
1278 | 	if (n == 0 || n < -1)
1279 | 	    menu_identify(id_limit);
1280 |     }
1281 |     update_inventory();
1282 | }
1283 | 
1284 | #endif /* OVLB */
1285 | #ifdef OVL2
1286 | 
1287 | STATIC_OVL char
1288 | obj_to_let(obj)	/* should of course only be called for things in invent */
1289 | register struct obj *obj;
1290 | {
1291 | 	if (obj->oclass == GOLD_CLASS)
1292 | 		return GOLD_SYM;
1293 | 	if (!flags.invlet_constant) {
1294 | 		obj->invlet = NOINVSYM;
1295 | 		reassign();
1296 | 	}
1297 | 	return obj->invlet;
1298 | }
1299 | 
1300 | /*
1301 |  * Print the indicated quantity of the given object.  If quan == 0L then use
1302 |  * the current quantity.
1303 |  */
1304 | void
1305 | prinv(prefix, obj, quan)
1306 | const char *prefix;
1307 | register struct obj *obj;
1308 | long quan;
1309 | {
1310 | 	long savequan = obj->quan;
1311 | 	if (quan) obj->quan = quan;
1312 | 	if (!prefix) prefix = "";
1313 | 	pline("%s%s%s",
1314 | 	      prefix, *prefix ? " " : "",
1315 | 	      xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L));
1316 | 	if (quan) obj->quan = savequan;
1317 | }
1318 | 
1319 | #endif /* OVL2 */
1320 | #ifdef OVL1
1321 | 
1322 | char *
1323 | xprname(obj, txt, let, dot, cost)
1324 | struct obj *obj;
1325 | const char *txt;	/* text to print instead of obj */
1326 | char let;		/* inventory letter */
1327 | boolean dot;		/* append period; (dot && cost => Iu) */
1328 | long cost;		/* cost (for inventory of unpaid or expended items) */
1329 | {
1330 | #ifdef LINT	/* handle static char li[BUFSZ]; */
1331 | 	char li[BUFSZ];
1332 | #else
1333 | 	static char li[BUFSZ];
1334 | #endif
1335 | 	boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
1336 |     /*
1337 |      * If let is:
1338 |      *	*  Then obj == null and we are printing a total amount.
1339 |      *	>  Then the object is contained and doesn't have an inventory letter.
1340 |      */
1341 |     if (cost != 0 || let == '*') {
1342 | 	/* if dot is true, we're doing Iu, otherwise Ix */
1343 | 	Sprintf(li, "%c - %-45s %6ld zorkmid%s",
1344 | 		(dot && use_invlet ? obj->invlet : let),
1345 | 		(txt ? txt : doname(obj)), cost, plur(cost));
1346 |     } else if (obj->oclass == GOLD_CLASS) {
1347 | 	Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
1348 | 		(dot ? "." : ""));
1349 |     } else {
1350 | 	/* ordinary inventory display or pickup message */
1351 | 	Sprintf(li, "%c - %s%s",
1352 | 		(use_invlet ? obj->invlet : let),
1353 | 		(txt ? txt : doname(obj)), (dot ? "." : ""));
1354 |     }
1355 |     return li;
1356 | }
1357 | 
1358 | #endif /* OVL1 */
1359 | #ifdef OVLB
1360 | 
1361 | /* the 'i' command */
1362 | int
1363 | ddoinv()
1364 | {
1365 | 	(void) display_inventory((char *)0, FALSE);
1366 | 	return 0;
1367 | }
1368 | 
1369 | /*
1370 |  * find_unpaid()
1371 |  *
1372 |  * Scan the given list of objects.  If last_found is NULL, return the first
1373 |  * unpaid object found.  If last_found is not NULL, then skip over unpaid
1374 |  * objects until last_found is reached, then set last_found to NULL so the
1375 |  * next unpaid object is returned.  This routine recursively follows
1376 |  * containers.
1377 |  */
1378 | STATIC_OVL struct obj *
1379 | find_unpaid(list, last_found)
1380 |     struct obj *list, **last_found;
1381 | {
1382 |     struct obj *obj;
1383 | 
1384 |     while (list) {
1385 | 	if (list->unpaid) {
1386 | 	    if (*last_found) {
1387 | 		/* still looking for previous unpaid object */
1388 | 		if (list == *last_found)
1389 | 		    *last_found = (struct obj *) 0;
1390 | 	    } else
1391 | 		return (*last_found = list);
1392 | 	}
1393 | 	if (Has_contents(list)) {
1394 | 	    if ((obj = find_unpaid(list->cobj, last_found)) != 0)
1395 | 		return obj;
1396 | 	}
1397 | 	list = list->nobj;
1398 |     }
1399 |     return (struct obj *) 0;
1400 | }
1401 | 
1402 | /*
1403 |  * If lets == NULL or "", list all objects in the inventory.  Otherwise,
1404 |  * list all objects with object classes that match the order in lets.
1405 |  *
1406 |  * Returns the letter identifier of a selected item, or 0 if nothing
1407 |  * was selected.
1408 |  */
1409 | char
1410 | display_inventory(lets, want_reply)
1411 | register const char *lets;
1412 | boolean want_reply;
1413 | {
1414 | 	struct obj *otmp;
1415 | 	char ilet, ret;
1416 | 	char *invlet = flags.inv_order;
1417 | 	int n, classcount;
1418 | 	winid win;				/* windows being used */
1419 | 	static winid local_win = WIN_ERR;	/* window for partial menus */
1420 | 	anything any;
1421 | 	menu_item *selected;
1422 | 
1423 | 	/* overriden by global flag */
1424 | 	if (flags.perm_invent) {
1425 | 	    win = (lets && *lets) ? local_win : WIN_INVEN;
1426 | 	    /* create the first time used */
1427 | 	    if (win == WIN_ERR)
1428 | 		win = local_win = create_nhwindow(NHW_MENU);
1429 | 	} else
1430 | 	    win = WIN_INVEN;
1431 | 
1432 | 	/*
1433 | 	Exit early if no inventory -- but keep going if we are doing
1434 | 	a permanent inventory update.  We need to keep going so the
1435 | 	permanent inventory window updates itself to remove the last
1436 | 	item(s) dropped.  One down side:  the addition of the exception
1437 | 	for permanent inventory window updates _can_ pop the window
1438 | 	up when it's not displayed -- even if it's empty -- because we
1439 | 	don't know at this level if its up or not.  This may not be
1440 | 	an issue if empty checks are done before hand and the call
1441 | 	to here is short circuited away.
1442 | 	*/
1443 | 	if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
1444 | 	    pline("Not carrying anything%s.", u.ugold ? " except gold" : "");
1445 | 	    return 0;
1446 | 	}
1447 | 
1448 | 	/* oxymoron? temporarily assign permanent inventory letters */
1449 | 	if (!flags.invlet_constant) reassign();
1450 | 
1451 | 	if (lets && strlen(lets) == 1) {
1452 | 	    /* when only one item of interest, use pline instead of menus;
1453 | 	       we actually use a fake message-line menu in order to allow
1454 | 	       the user to perform selection at the --More-- prompt for tty */
1455 | 	    ret = '\0';
1456 | 	    for (otmp = invent; otmp; otmp = otmp->nobj) {
1457 | 		if (otmp->invlet == lets[0]) {
1458 | 		    ret = message_menu(lets[0],
1459 | 				  want_reply ? PICK_ONE : PICK_NONE,
1460 | 				  xprname(otmp, (char *)0, lets[0], TRUE, 0L));
1461 | 		    break;
1462 | 		}
1463 | 	    }
1464 | 	    return ret;
1465 | 	}
1466 | 
1467 | 	start_menu(win);
1468 | nextclass:
1469 | 	classcount = 0;
1470 | 	any.a_void = 0;		/* set all bits to zero */
1471 | 	for(otmp = invent; otmp; otmp = otmp->nobj) {
1472 | 		ilet = otmp->invlet;
1473 | 		if(!lets || !*lets || index(lets, ilet)) {
1474 | 			if (!flags.sortpack || otmp->oclass == *invlet) {
1475 | 			    if (flags.sortpack && !classcount) {
1476 | 				any.a_void = 0;		/* zero */
1477 | 				add_menu(win, NO_GLYPH, &any, 0, 0, ATR_INVERSE,
1478 | 				    let_to_name(*invlet, FALSE), MENU_UNSELECTED);
1479 | 				classcount++;
1480 | 			    }
1481 | 			    any.a_char = ilet;
1482 | 			    add_menu(win, obj_to_glyph(otmp),
1483 | 					&any, ilet, 0, ATR_NONE, doname(otmp),
1484 | 					MENU_UNSELECTED);
1485 | 			}
1486 | 		}
1487 | 	}
1488 | 	if (flags.sortpack) {
1489 | 		if (*++invlet) goto nextclass;
1490 | #ifdef WIZARD
1491 | 		if (--invlet != venom_inv) {
1492 | 			invlet = venom_inv;
1493 | 			goto nextclass;
1494 | 		}
1495 | #endif
1496 | 	}
1497 | 	end_menu(win, (char *) 0);
1498 | 
1499 | 	n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
1500 | 	if (n > 0) {
1501 | 	    ret = selected[0].item.a_char;
1502 | 	    free((genericptr_t)selected);
1503 | 	} else
1504 | 	    ret = !n ? '\0' : '\033';	/* cancelled */
1505 | 
1506 | 	return ret;
1507 | }
1508 | 
1509 | /*
1510 |  * Returns the number of unpaid items within the given list.  This includes
1511 |  * contained objects.
1512 |  */
1513 | int
1514 | count_unpaid(list)
1515 |     struct obj *list;
1516 | {
1517 |     int count = 0;
1518 | 
1519 |     while (list) {
1520 | 	if (list->unpaid) count++;
1521 | 	if (Has_contents(list))
1522 | 	    count += count_unpaid(list->cobj);
1523 | 	list = list->nobj;
1524 |     }
1525 |     return count;
1526 | }
1527 | 
1528 | STATIC_OVL void
1529 | dounpaid()
1530 | {
1531 |     winid win;
1532 |     struct obj *otmp, *marker;
1533 |     register char ilet;
1534 |     char *invlet = flags.inv_order;
1535 |     int classcount, count, num_so_far;
1536 |     int save_unpaid = 0;	/* lint init */
1537 |     long cost, totcost;
1538 | 
1539 |     count = count_unpaid(invent);
1540 | 
1541 |     if (count == 1) {
1542 | 	marker = (struct obj *) 0;
1543 | 	otmp = find_unpaid(invent, &marker);
1544 | 
1545 | 	/* see if the unpaid item is in the top level inventory */
1546 | 	for (marker = invent; marker; marker = marker->nobj)
1547 | 	    if (marker == otmp) break;
1548 | 
1549 | 	pline("%s", xprname(otmp, distant_name(otmp, doname),
1550 | 			    marker ? otmp->invlet : CONTAINED_SYM,
1551 | 			    TRUE, unpaid_cost(otmp)));
1552 | 	return;
1553 |     }
1554 | 
1555 |     win = create_nhwindow(NHW_MENU);
1556 |     cost = totcost = 0;
1557 |     num_so_far = 0;	/* count of # printed so far */
1558 |     if (!flags.invlet_constant) reassign();
1559 | 
1560 |     do {
1561 | 	classcount = 0;
1562 | 	for (otmp = invent; otmp; otmp = otmp->nobj) {
1563 | 	    ilet = otmp->invlet;
1564 | 	    if (otmp->unpaid) {
1565 | 		if (!flags.sortpack || otmp->oclass == *invlet) {
1566 | 		    if (flags.sortpack && !classcount) {
1567 | 			putstr(win, 0, let_to_name(*invlet, TRUE));
1568 | 			classcount++;
1569 | 		    }
1570 | 
1571 | 		    totcost += cost = unpaid_cost(otmp);
1572 | 		    /* suppress "(unpaid)" suffix */
1573 | 		    save_unpaid = otmp->unpaid;
1574 | 		    otmp->unpaid = 0;
1575 | 		    putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
1576 | 					   ilet, TRUE, cost));
1577 | 		    otmp->unpaid = save_unpaid;
1578 | 		    num_so_far++;
1579 | 		}
1580 | 	    }
1581 | 	}
1582 |     } while (flags.sortpack && (*++invlet));
1583 | 
1584 |     if (count > num_so_far) {
1585 | 	/* something unpaid is contained */
1586 | 	if (flags.sortpack)
1587 | 	    putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE));
1588 | 	/*
1589 | 	 * Search through the container objects in the inventory for
1590 | 	 * unpaid items.  The top level inventory items have already
1591 | 	 * been listed.
1592 | 	 */
1593 | 	for (otmp = invent; otmp; otmp = otmp->nobj) {
1594 | 	    if (Has_contents(otmp)) {
1595 | 		marker = (struct obj *) 0;	/* haven't found any */
1596 | 		while (find_unpaid(otmp->cobj, &marker)) {
1597 | 		    totcost += cost = unpaid_cost(marker);
1598 | 		    save_unpaid = marker->unpaid;
1599 | 		    marker->unpaid = 0;    /* suppress "(unpaid)" suffix */
1600 | 		    putstr(win, 0,
1601 | 			   xprname(marker, distant_name(marker, doname),
1602 | 				   CONTAINED_SYM, TRUE, cost));
1603 | 		    marker->unpaid = save_unpaid;
1604 | 		}
1605 | 	    }
1606 | 	}
1607 |     }
1608 | 
1609 |     putstr(win, 0, "");
1610 |     putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost));
1611 |     display_nhwindow(win, FALSE);
1612 |     destroy_nhwindow(win);
1613 | }
1614 | 
1615 | 
1616 | /* query objlist callback: return TRUE if obj type matches "this_type" */
1617 | static int this_type;
1618 | 
1619 | STATIC_OVL boolean
1620 | this_type_only(obj)
1621 |     struct obj *obj;
1622 | {
1623 |     return (obj->oclass == this_type);
1624 | }
1625 | 
1626 | /* the 'I' command */
1627 | int
1628 | dotypeinv()
1629 | {
1630 | 	char c = '\0';
1631 | 	int n, i = 0;
1632 | 	char *extra_types, types[BUFSZ];
1633 | 	int class_count, oclass, unpaid_count;
1634 | 	boolean billx = *u.ushops && doinvbill(0);
1635 | 	menu_item *pick_list;
1636 | 	boolean traditional = TRUE;
1637 | 	const char *prompt = "What type of object do you want an inventory of?";
1638 | 
1639 | 	if (!invent && !u.ugold && !billx) {
1640 | 	    You("aren't carrying anything.");
1641 | 	    return 0;
1642 | 	}
1643 | 	unpaid_count = count_unpaid(invent);
1644 | 	if (flags.menu_style != MENU_TRADITIONAL) {
1645 | 	    if (flags.menu_style == MENU_FULL ||
1646 | 				flags.menu_style == MENU_PARTIAL) {
1647 | 		traditional = FALSE;
1648 | 		i = UNPAID_TYPES;
1649 | 		if (billx) i |= BILLED_TYPES;
1650 | 		n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
1651 | 		if (!n) return 0;
1652 | 		this_type = c = pick_list[0].item.a_int;
1653 | 		free((genericptr_t) pick_list);
1654 | 	    }
1655 | 	}
1656 | 	if (traditional) {
1657 | 	    /* collect a list of classes of objects carried, for use as a prompt */
1658 | 	    types[0] = 0;
1659 | 	    class_count = collect_obj_classes(types, invent,
1660 | 					      FALSE, (u.ugold != 0),
1661 | 					      (boolean FDECL((*),(OBJ_P))) 0);
1662 | 	    if (unpaid_count) {
1663 | 		Strcat(types, "u");
1664 | 		class_count++;
1665 | 	    }
1666 | 	    if (billx) {
1667 | 		Strcat(types, "x");
1668 | 		class_count++;
1669 | 	    }
1670 | 	    /* add everything not already included; user won't see these */
1671 | 	    extra_types = eos(types);
1672 | 	    *extra_types++ = '\033';
1673 | 	    if (!unpaid_count) *extra_types++ = 'u';
1674 | 	    if (!billx) *extra_types++ = 'x';
1675 | 	    *extra_types = '\0';	/* for index() */
1676 | 	    for (i = 0; i < MAXOCLASSES; i++)
1677 | 		if (!index(types, def_oc_syms[i])) {
1678 | 		    *extra_types++ = def_oc_syms[i];
1679 | 		    *extra_types = '\0';
1680 | 		}
1681 | 
1682 | 	    if(class_count > 1) {
1683 | 		c = yn_function(prompt, types, '\0');
1684 | #ifdef REDO
1685 | 		savech(c);
1686 | #endif
1687 | 		if(c == '\0') {
1688 | 			clear_nhwindow(WIN_MESSAGE);
1689 | 			return 0;
1690 | 		}
1691 | 	    } else {
1692 | 		/* only one thing to itemize */
1693 | 		if (unpaid_count)
1694 | 		    c = 'u';
1695 | 		else if (billx)
1696 | 		    c = 'x';
1697 | 		else
1698 | 		    c = types[0];
1699 | 	    }
1700 | 	}
1701 | 	if (c == 'x') {
1702 | 	    if (billx)
1703 | 		(void) doinvbill(1);
1704 | 	    else
1705 | 		pline("No used-up objects on your shopping bill.");
1706 | 	    return 0;
1707 | 	}
1708 | 	if (c == 'u') {
1709 | 	    if (unpaid_count)
1710 | 		dounpaid();
1711 | 	    else
1712 | 		You("are not carrying any unpaid objects.");
1713 | 	    return 0;
1714 | 	}
1715 | 	if (traditional) {
1716 | 	    oclass = def_char_to_objclass(c); /* change to object class */
1717 | 	    if (oclass == GOLD_CLASS) {
1718 | 		return doprgold();
1719 | 	    } else if (index(types, c) > index(types, '\033')) {
1720 | 		You("have no such objects.");
1721 | 		return 0;
1722 | 	    }
1723 | 	    this_type = oclass;
1724 | 	}
1725 | 	if (query_objlist((char *) 0, invent,
1726 | 		    (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT,
1727 | 		    &pick_list, PICK_NONE, this_type_only) > 0)
1728 | 	    free((genericptr_t)pick_list);
1729 | 	return 0;
1730 | }
1731 | 
1732 | /* return a string describing the dungeon feature at <x,y> if there
1733 |    is one worth mentioning at that location; otherwise null */
1734 | const char *
1735 | dfeature_at(x, y, buf)
1736 | int x, y;
1737 | char *buf;
1738 | {
1739 | 	struct rm *lev = &levl[x][y];
1740 | 	int ltyp = lev->typ, cmap = -1;
1741 | 	const char *dfeature = 0;
1742 | 	static char altbuf[BUFSZ];
1743 | 
1744 | 	if (IS_DOOR(ltyp)) {
1745 | 	    switch (lev->doormask) {
1746 | 	    case D_NODOOR:	cmap = S_ndoor; break;	/* "doorway" */
1747 | 	    case D_ISOPEN:	cmap = S_vodoor; break;	/* "open door" */
1748 | 	    case D_BROKEN:	dfeature = "broken door"; break;
1749 | 	    default:	cmap = S_vcdoor; break;	/* "closed door" */
1750 | 	    }
1751 | 	    /* override door description for open drawbridge */
1752 | 	    if (is_drawbridge_wall(x, y) >= 0)
1753 | 		dfeature = "open drawbridge portcullis",  cmap = -1;
1754 | 	} else if (IS_FOUNTAIN(ltyp))
1755 | 	    cmap = S_fountain;				/* "fountain" */
1756 | 	else if (IS_THRONE(ltyp))
1757 | 	    cmap = S_throne;				/* "opulent throne" */
1758 | 	else if (is_lava(x,y))
1759 | 	    cmap = S_lava;				/* "molten lava" */
1760 | 	else if (is_ice(x,y))
1761 | 	    cmap = S_ice;				/* "ice" */
1762 | 	else if (is_pool(x,y))
1763 | 	    dfeature = "pool of water";
1764 | #ifdef SINKS
1765 | 	else if (IS_SINK(ltyp))
1766 | 	    cmap = S_sink;				/* "sink" */
1767 | #endif
1768 | 	else if (IS_ALTAR(ltyp)) {
1769 | 	    Sprintf(altbuf, "altar to %s (%s)", a_gname(),
1770 | 		    align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
1771 | 	    dfeature = altbuf;
1772 | 	} else if ((x == xupstair && y == yupstair) ||
1773 | 		 (x == sstairs.sx && y == sstairs.sy && sstairs.up))
1774 | 	    cmap = S_upstair;				/* "staircase up" */
1775 | 	else if ((x == xdnstair && y == ydnstair) ||
1776 | 		 (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
1777 | 	    cmap = S_dnstair;				/* "staircase down" */
1778 | 	else if (x == xupladder && y == yupladder)
1779 | 	    cmap = S_upladder;				/* "ladder up" */
1780 | 	else if (x == xdnladder && y == ydnladder)
1781 | 	    cmap = S_dnladder;				/* "ladder down" */
1782 | 	else if (ltyp == DRAWBRIDGE_DOWN)
1783 | 	    cmap = S_vodbridge;			/* "lowered drawbridge" */
1784 | 	else if (ltyp == DBWALL)
1785 | 	    cmap = S_vcdbridge;			/* "raised drawbridge" */
1786 | 	else if (IS_GRAVE(ltyp))
1787 | 	    cmap = S_grave;				/* "grave" */
1788 | 	else if (ltyp == TREE)
1789 | 	    cmap = S_tree;				/* "tree" */
1790 | 	else if (ltyp == IRONBARS)
1791 | 	    dfeature = "set of iron bars";
1792 | 
1793 | 	if (cmap >= 0) dfeature = defsyms[cmap].explanation;
1794 | 	if (dfeature) Strcpy(buf, dfeature);
1795 | 	return dfeature;
1796 | }
1797 | 
1798 | /* look at what is here; if there are many objects (5 or more),
1799 |    don't show them unless obj_cnt is 0 */
1800 | int
1801 | look_here(obj_cnt, picked_some)
1802 | int obj_cnt;	/* obj_cnt > 0 implies that autopickup is in progess */
1803 | boolean picked_some;
1804 | {
1805 | 	struct obj *otmp;
1806 | 	struct trap *trap;
1807 | 	const char *verb = Blind ? "feel" : "see";
1808 | 	const char *dfeature = (char *)0;
1809 | 	char fbuf[BUFSZ], fbuf2[BUFSZ];
1810 | 	winid tmpwin;
1811 | 	boolean skip_objects = (obj_cnt >= 5);
1812 | 
1813 | 	if (u.uswallow) {
1814 | 		You("%s no objects here.", verb);
1815 | 		return(!!Blind);
1816 | 	}
1817 | 	if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen)
1818 | 		There("is %s here.",
1819 | 			an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
1820 | 
1821 | 	otmp = level.objects[u.ux][u.uy];
1822 | 	dfeature = dfeature_at(u.ux, u.uy, fbuf2);
1823 | 	if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
1824 | 		dfeature = 0;
1825 | 
1826 | 	if (Blind) {
1827 | 		boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
1828 | 		You("try to feel what is %s%s.",
1829 | 		    drift ? "floating here" : "lying here on the ",
1830 | 		    drift ?	""	    : surface(u.ux, u.uy));
1831 | 		if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy)))
1832 | 			dfeature = 0;		/* ice already identifed */
1833 | 		if (!can_reach_floor()) {
1834 | 			pline("But you can't reach it!");
1835 | 			return(0);
1836 | 		}
1837 | 	}
1838 | 
1839 | 	if (dfeature)
1840 | 		Sprintf(fbuf, "There is %s here.", an(dfeature));
1841 | 
1842 | 	if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) {
1843 | 		if (dfeature) pline(fbuf);
1844 | 		read_engr_at(u.ux, u.uy); /* Eric Backus */
1845 | 		if (!skip_objects && (Blind || !dfeature))
1846 | 		    You("%s no objects here.", verb);
1847 | 		return(!!Blind);
1848 | 	}
1849 | 	/* we know there is something here */
1850 | 
1851 | 	if (skip_objects) {
1852 | 	    if (dfeature) pline(fbuf);
1853 | 	    read_engr_at(u.ux, u.uy); /* Eric Backus */
1854 | 	    There("are %s%s objects here.",
1855 | 		  (obj_cnt <= 10) ? "several" : "many",
1856 | 		  picked_some ? " more" : "");
1857 | 	} else if (!otmp->nexthere) {
1858 | 	    /* only one object */
1859 | 	    if (dfeature) pline(fbuf);
1860 | 	    read_engr_at(u.ux, u.uy); /* Eric Backus */
1861 | #ifdef INVISIBLE_OBJECTS
1862 | 	    if (otmp->oinvis && !See_invisible) verb = "feel";
1863 | #endif
1864 | 	    You("%s here %s.", verb, doname(otmp));
1865 | 	    if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
1866 | 	} else {
1867 | 	    display_nhwindow(WIN_MESSAGE, FALSE);
1868 | 	    tmpwin = create_nhwindow(NHW_MENU);
1869 | 	    if(dfeature) {
1870 | 		putstr(tmpwin, 0, fbuf);
1871 | 		putstr(tmpwin, 0, "");
1872 | 	    }
1873 | 	    putstr(tmpwin, 0, "Things that are here:");
1874 | 	    for ( ; otmp; otmp = otmp->nexthere) {
1875 | 		putstr(tmpwin, 0, doname(otmp));
1876 | 		if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
1877 | 	    }
1878 | 	    display_nhwindow(tmpwin, TRUE);
1879 | 	    destroy_nhwindow(tmpwin);
1880 | 	    read_engr_at(u.ux, u.uy); /* Eric Backus */
1881 | 	}
1882 | 	return(!!Blind);
1883 | }
1884 | 
1885 | /* explicilty look at what is here, including all objects */
1886 | int
1887 | dolook()
1888 | {
1889 | 	return look_here(0, FALSE);
1890 | }
1891 | 
1892 | void
1893 | feel_cockatrice(otmp, force_touch)
1894 | struct obj *otmp;
1895 | boolean force_touch;
1896 | {
1897 | 	char kbuf[BUFSZ];
1898 | 
1899 | 	if ((Blind || force_touch) && !uarmg && !Stone_resistance &&
1900 | 		(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))) {
1901 | 	    if(poly_when_stoned(youmonst.data))
1902 | 			You("touched the %s corpse with your bare %s.",
1903 | 				mons[otmp->corpsenm].mname, makeplural(body_part(HAND)));
1904 | 	    else
1905 | 			pline("Touching the %s corpse is a fatal mistake...",
1906 | 				mons[otmp->corpsenm].mname);
1907 | 		Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname));
1908 | 		instapetrify(kbuf);
1909 | 	}
1910 | }
1911 | 
1912 | #endif /* OVLB */
1913 | #ifdef OVL1
1914 | 
1915 | void
1916 | stackobj(obj)
1917 | struct obj *obj;
1918 | {
1919 | 	struct obj *otmp;
1920 | 
1921 | 	for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
1922 | 		if(otmp != obj && merged(&obj,&otmp))
1923 | 			break;
1924 | 	return;
1925 | }
1926 | 
1927 | STATIC_OVL boolean
1928 | mergable(otmp, obj)	/* returns TRUE if obj  & otmp can be merged */
1929 | 	register struct obj *otmp, *obj;
1930 | {
1931 | 	if (obj->otyp != otmp->otyp || obj->unpaid != otmp->unpaid ||
1932 | 	    obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
1933 | 	    (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) ||
1934 | 	    obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
1935 | 	    obj->no_charge != otmp->no_charge ||
1936 | 	    obj->obroken != otmp->obroken ||
1937 | 	    obj->otrapped != otmp->otrapped ||
1938 | 	    obj->lamplit != otmp->lamplit ||
1939 | #ifdef INVISIBLE_OBJECTS
1940 | 		obj->oinvis != otmp->oinvis ||
1941 | #endif
1942 | 	    obj->greased != otmp->greased ||
1943 | 	    obj->oeroded != otmp->oeroded ||
1944 | 	    obj->oeroded2 != otmp->oeroded2)
1945 | 	    return(FALSE);
1946 | 
1947 | 	if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
1948 | 	    (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
1949 | 	    return FALSE;
1950 | 
1951 | 	if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
1952 | 					  obj->orotten != otmp->orotten))
1953 | 	    return(FALSE);
1954 | 
1955 | 	if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
1956 | 		if (obj->corpsenm != otmp->corpsenm)
1957 | 				return FALSE;
1958 | 	}
1959 | 
1960 | 	/* hatching eggs don't merge; ditto for revivable corpses */
1961 | 	if ((obj->otyp == EGG && (obj->timed || otmp->timed)) ||
1962 | 	    (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM &&
1963 | 		mons[otmp->corpsenm].mlet == S_TROLL))
1964 | 	    return FALSE;
1965 | 
1966 | 	/* allow candle merging only if their ages are close */
1967 | 	/* see begin_burn() for a reference for the magic "25" */
1968 | 	if (Is_candle(obj) && obj->age/25 != otmp->age/25)
1969 | 	    return(FALSE);
1970 | 
1971 | 	/* burning potions of oil never merge */
1972 | 	if (obj->otyp == POT_OIL && obj->lamplit)
1973 | 	    return FALSE;
1974 | 
1975 | 	/* don't merge surcharged item with base-cost item */
1976 | 	if (obj->unpaid && !same_price(obj, otmp))
1977 | 	    return FALSE;
1978 | 
1979 | 	/* if they have names, make sure they're the same */
1980 | 	if ( (obj->onamelth != otmp->onamelth &&
1981 | 		((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
1982 | 	     ) ||
1983 | 	    (obj->onamelth && otmp->onamelth &&
1984 | 		    strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
1985 | 		return FALSE;
1986 | 
1987 | 	/* for the moment, any additional information is incompatible */
1988 | 	if (obj->oxlth || otmp->oxlth) return FALSE;
1989 | 
1990 | 	if(obj->oartifact != otmp->oartifact) return FALSE;
1991 | 
1992 | 	if(obj->known == otmp->known ||
1993 | 		!objects[otmp->otyp].oc_uses_known) {
1994 | 		return((boolean)(objects[obj->otyp].oc_merge));
1995 | 	} else return(FALSE);
1996 | }
1997 | 
1998 | int
1999 | doprgold()
2000 | {
2001 | 	/* the messages used to refer to "carrying gold", but that didn't
2002 | 	   take containers into account */
2003 | 	if(!u.ugold)
2004 | 	    Your("wallet is empty.");
2005 | 	else
2006 | 	    Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold));
2007 | 	shopper_financial_report();
2008 | 	return 0;
2009 | }
2010 | 
2011 | #endif /* OVL1 */
2012 | #ifdef OVLB
2013 | 
2014 | int
2015 | doprwep()
2016 | {
2017 |     if (!uwep) {
2018 | 	You("are empty %s.", body_part(HANDED));
2019 |     } else {
2020 | 	prinv((char *)0, uwep, 0L);
2021 | 	if (u.twoweap) prinv((char *)0, uswapwep, 0L);
2022 |     }
2023 |     return 0;
2024 | }
2025 | 
2026 | int
2027 | doprarm()
2028 | {
2029 | 	if(!wearing_armor())
2030 | 		You("are not wearing any armor.");
2031 | 	else {
2032 | #ifdef TOURIST
2033 | 		char lets[8];
2034 | #else
2035 | 		char lets[7];
2036 | #endif
2037 | 		register int ct = 0;
2038 | 
2039 | #ifdef TOURIST
2040 | 		if(uarmu) lets[ct++] = obj_to_let(uarmu);
2041 | #endif
2042 | 		if(uarm) lets[ct++] = obj_to_let(uarm);
2043 | 		if(uarmc) lets[ct++] = obj_to_let(uarmc);
2044 | 		if(uarmh) lets[ct++] = obj_to_let(uarmh);
2045 | 		if(uarms) lets[ct++] = obj_to_let(uarms);
2046 | 		if(uarmg) lets[ct++] = obj_to_let(uarmg);
2047 | 		if(uarmf) lets[ct++] = obj_to_let(uarmf);
2048 | 		lets[ct] = 0;
2049 | 		(void) display_inventory(lets, FALSE);
2050 | 	}
2051 | 	return 0;
2052 | }
2053 | 
2054 | int
2055 | doprring()
2056 | {
2057 | 	if(!uleft && !uright)
2058 | 		You("are not wearing any rings.");
2059 | 	else {
2060 | 		char lets[3];
2061 | 		register int ct = 0;
2062 | 
2063 | 		if(uleft) lets[ct++] = obj_to_let(uleft);
2064 | 		if(uright) lets[ct++] = obj_to_let(uright);
2065 | 		lets[ct] = 0;
2066 | 		(void) display_inventory(lets, FALSE);
2067 | 	}
2068 | 	return 0;
2069 | }
2070 | 
2071 | int
2072 | dopramulet()
2073 | {
2074 | 	if (!uamul)
2075 | 		You("are not wearing an amulet.");
2076 | 	else
2077 | 		prinv((char *)0, uamul, 0L);
2078 | 	return 0;
2079 | }
2080 | 
2081 | static boolean
2082 | tool_in_use(obj)
2083 | struct obj *obj;
2084 | {
2085 | 	if ((obj->owornmask & (W_TOOL
2086 | #ifdef STEED
2087 | 			| W_SADDLE
2088 | #endif
2089 | 			)) != 0L) return TRUE;
2090 | 	if (obj->oclass != TOOL_CLASS) return FALSE;
2091 | 	return (boolean)(obj == uwep || obj->lamplit ||
2092 | 				(obj->otyp == LEASH && obj->leashmon));
2093 | }
2094 | 
2095 | int
2096 | doprtool()
2097 | {
2098 | 	struct obj *otmp;
2099 | 	int ct = 0;
2100 | 	char lets[52+1];
2101 | 
2102 | 	for (otmp = invent; otmp; otmp = otmp->nobj)
2103 | 	    if (tool_in_use(otmp))
2104 | 		lets[ct++] = obj_to_let(otmp);
2105 | 	lets[ct] = '\0';
2106 | 	if (!ct) You("are not using any tools.");
2107 | 	else (void) display_inventory(lets, FALSE);
2108 | 	return 0;
2109 | }
2110 | 
2111 | /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
2112 |    show inventory of all currently wielded, worn, or used objects */
2113 | int
2114 | doprinuse()
2115 | {
2116 | 	struct obj *otmp;
2117 | 	int ct = 0;
2118 | 	char lets[52+1];
2119 | 
2120 | 	for (otmp = invent; otmp; otmp = otmp->nobj)
2121 | 	    if (is_worn(otmp) || tool_in_use(otmp))
2122 | 		lets[ct++] = obj_to_let(otmp);
2123 | 	lets[ct] = '\0';
2124 | 	if (!ct) You("are not wearing or wielding anything.");
2125 | 	else (void) display_inventory(lets, FALSE);
2126 | 	return 0;
2127 | }
2128 | 
2129 | /*
2130 |  * uses up an object that's on the floor, charging for it as necessary
2131 |  */
2132 | void
2133 | useupf(obj, numused)
2134 | register struct obj *obj;
2135 | long numused;
2136 | {
2137 | 	register struct obj *otmp;
2138 | 
2139 | 	/* burn_floor_paper() keeps an object pointer that it tries to
2140 | 	 * useupf() multiple times, so obj must survive if plural */
2141 | 	if (obj->quan > numused)
2142 | 		otmp = splitobj(obj, obj->quan - numused);
2143 | 	else
2144 | 		otmp = obj;
2145 | 	if(costly_spot(otmp->ox, otmp->oy)) {
2146 | 	    if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
2147 | 	        addtobill(otmp, FALSE, FALSE, FALSE);
2148 | 	    else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
2149 | 	}
2150 | 	delobj(otmp);
2151 | }
2152 | 
2153 | #endif /* OVLB */
2154 | 
2155 | 
2156 | #ifdef OVL1
2157 | 
2158 | /*
2159 |  * Conversion from a class to a string for printing.
2160 |  * This must match the object class order.
2161 |  */
2162 | STATIC_VAR NEARDATA const char *names[] = { 0,
2163 | 	"Illegal objects", "Weapons", "Armor", "Rings", "Amulets",
2164 | 	"Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks",
2165 | 	"Wands", "Coins", "Gems", "Boulders/Statues", "Iron balls",
2166 | 	"Chains", "Venoms"
2167 | };
2168 | 
2169 | static NEARDATA const char oth_symbols[] = {
2170 | 	CONTAINED_SYM,
2171 | 	'\0'
2172 | };
2173 | 
2174 | static NEARDATA const char *oth_names[] = {
2175 | 	"Bagged/Boxed items"
2176 | };
2177 | 
2178 | static NEARDATA char *invbuf = (char *)0;
2179 | static NEARDATA unsigned invbufsiz = 0;
2180 | 
2181 | char *
2182 | let_to_name(let,unpaid)
2183 | char let;
2184 | boolean unpaid;
2185 | {
2186 | 	const char *class_name;
2187 | 	const char *pos;
2188 | 	int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
2189 | 	unsigned len;
2190 | 
2191 | 	if (oclass)
2192 | 	    class_name = names[oclass];
2193 | 	else if ((pos = index(oth_symbols, let)) != 0)
2194 | 	    class_name = oth_names[pos - oth_symbols];
2195 | 	else
2196 | 	    class_name = names[0];
2197 | 
2198 | 	len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "");
2199 | 	if (len > invbufsiz) {
2200 | 	    if (invbuf) free((genericptr_t)invbuf);
2201 | 	    invbufsiz = len + 10; /* add slop to reduce incremental realloc */
2202 | 	    invbuf = (char *) alloc(invbufsiz);
2203 | 	}
2204 | 	if (unpaid)
2205 | 	    Strcat(strcpy(invbuf, "Unpaid "), class_name);
2206 | 	else
2207 | 	    Strcpy(invbuf, class_name);
2208 | 	return invbuf;
2209 | }
2210 | 
2211 | void
2212 | free_invbuf()
2213 | {
2214 | 	if (invbuf) free((genericptr_t)invbuf),  invbuf = (char *)0;
2215 | 	invbufsiz = 0;
2216 | }
2217 | 
2218 | #endif /* OVL1 */
2219 | #ifdef OVLB
2220 | 
2221 | void
2222 | reassign()
2223 | {
2224 | 	register int i;
2225 | 	register struct obj *obj;
2226 | 
2227 | 	for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
2228 | 		obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
2229 | 	lastinvnr = i;
2230 | }
2231 | 
2232 | #endif /* OVLB */
2233 | #ifdef OVL1
2234 | 
2235 | int
2236 | doorganize()	/* inventory organizer by Del Lamb */
2237 | {
2238 | 	struct obj *obj, *otmp;
2239 | 	register int ix, cur;
2240 | 	register char let;
2241 | 	char alphabet[52+1], buf[52+1];
2242 | 	char qbuf[QBUFSZ];
2243 | 	char allowall[2];
2244 | 	const char *adj_type;
2245 | 
2246 | 	if (!flags.invlet_constant) reassign();
2247 | 	/* get a pointer to the object the user wants to organize */
2248 | 	allowall[0] = ALL_CLASSES; allowall[1] = '\0';
2249 | 	if (!(obj = getobj(allowall,"adjust"))) return(0);
2250 | 
2251 | 	/* initialize the list with all upper and lower case letters */
2252 | 	for (let = 'a', ix = 0;  let <= 'z';) alphabet[ix++] = let++;
2253 | 	for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
2254 | 	alphabet[52] = 0;
2255 | 
2256 | 	/* blank out all the letters currently in use in the inventory */
2257 | 	/* except those that will be merged with the selected object   */
2258 | 	for (otmp = invent; otmp; otmp = otmp->nobj)
2259 | 		if (otmp != obj && !mergable(otmp,obj)) {
2260 | 			if (otmp->invlet <= 'Z')
2261 | 				alphabet[(otmp->invlet) - 'A' + 26] = ' ';
2262 | 			else	alphabet[(otmp->invlet) - 'a']	    = ' ';
2263 | 		}
2264 | 
2265 | 	/* compact the list by removing all the blanks */
2266 | 	for (ix = cur = 0; ix <= 52; ix++)
2267 | 		if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];
2268 | 
2269 | 	/* and by dashing runs of letters */
2270 | 	if(cur > 5) compactify(buf);
2271 | 
2272 | 	/* get new letter to use as inventory letter */
2273 | 	for (;;) {
2274 | 		Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
2275 | 		let = yn_function(qbuf, (char *)0, '\0');
2276 | 		if(index(quitchars,let)) {
2277 | 			pline(Never_mind);
2278 | 			return(0);
2279 | 		}
2280 | 		if (let == '@' || !letter(let))
2281 | 			pline("Select an inventory slot letter.");
2282 | 		else
2283 | 			break;
2284 | 	}
2285 | 
2286 | 	/* change the inventory and print the resulting item */
2287 | 	adj_type = "Moving:";
2288 | 
2289 | 	/*
2290 | 	 * don't use freeinv/addinv to avoid double-touching artifacts,
2291 | 	 * dousing lamps, losing luck, cursing loadstone, etc.
2292 | 	 */
2293 | 	extract_nobj(obj, &invent);
2294 | 
2295 | 	for (otmp = invent; otmp;)
2296 | 		if (merged(&otmp,&obj)) {
2297 | 			adj_type = "Merging:";
2298 | 			obj = otmp;
2299 | 			otmp = otmp->nobj;
2300 | 			extract_nobj(obj, &invent);
2301 | 		} else {
2302 | 			if (otmp->invlet == let) {
2303 | 				adj_type = "Swapping:";
2304 | 				otmp->invlet = obj->invlet;
2305 | 			}
2306 | 			otmp = otmp->nobj;
2307 | 		}
2308 | 
2309 | 	/* inline addinv (assuming flags.invlet_constant and !merged) */
2310 | 	obj->invlet = let;
2311 | 	obj->nobj = invent; /* insert at beginning */
2312 | 	obj->where = OBJ_INVENT;
2313 | 	invent = obj;
2314 | 	reorder_invent();
2315 | 
2316 | 	prinv(adj_type, obj, 0L);
2317 | 	update_inventory();
2318 | 	return(0);
2319 | }
2320 | 
2321 | /* common to display_minventory and display_cinventory */
2322 | STATIC_OVL void
2323 | invdisp_nothing(hdr, txt)
2324 | const char *hdr, *txt;
2325 | {
2326 | 	winid win;
2327 | 	anything any;
2328 | 	menu_item *selected;
2329 | 
2330 | 	any.a_void = 0;
2331 | 	win = create_nhwindow(NHW_MENU);
2332 | 	start_menu(win);
2333 | 	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_INVERSE, hdr, MENU_UNSELECTED);
2334 | 	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2335 | 	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
2336 | 	end_menu(win, (char *)0);
2337 | 	if (select_menu(win, PICK_NONE, &selected) > 0)
2338 | 	    free((genericptr_t)selected);
2339 | 	destroy_nhwindow(win);
2340 | 	return;
2341 | }
2342 | 
2343 | /* query_objlist callback: return things that could possibly be worn/wielded */
2344 | STATIC_OVL boolean
2345 | worn_wield_only(obj)
2346 | struct obj *obj;
2347 | {
2348 |     return (obj->oclass == WEAPON_CLASS
2349 | 		|| obj->oclass == ARMOR_CLASS
2350 | 		|| obj->oclass == AMULET_CLASS
2351 | 		|| obj->oclass == RING_CLASS
2352 | 		|| obj->oclass == TOOL_CLASS);
2353 | }
2354 | 
2355 | /*
2356 |  * Display a monster's inventory.
2357 |  * Returns a pointer to the object from the monster's inventory selected
2358 |  * or NULL if nothing was selected.
2359 |  *
2360 |  * By default, only worn and wielded items are displayed.  The caller
2361 |  * can pick one.  Modifier flags are:
2362 |  *
2363 |  *	MINV_NOLET	- nothing selectable
2364 |  *	MINV_ALL	- display all inventory
2365 |  */
2366 | struct obj *
2367 | display_minventory(mon, dflags)
2368 | register struct monst *mon;
2369 | int dflags;
2370 | {
2371 | 	struct obj *ret, m_gold;
2372 | 	char tmp[QBUFSZ];
2373 | 	int n;
2374 | 	menu_item *selected = 0;
2375 | 	int do_all = (dflags & MINV_ALL) != 0,
2376 | 	    do_gold = (do_all && mon->mgold);
2377 | 
2378 | 	Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)),
2379 | 		do_all ? "possessions" : "armament");
2380 | 
2381 | 	if (do_all ? (mon->minvent || mon->mgold)
2382 | 		   : (mon->misc_worn_check || MON_WEP(mon))) {
2383 | 	    /* Fool the 'weapon in hand' routine into
2384 | 	     * displaying 'weapon in claw', etc. properly.
2385 | 	     */
2386 | 	    youmonst.data = mon->data;
2387 | 
2388 | 	    if (do_gold) {
2389 | 		/*
2390 | 		 * Make temporary gold object and insert at the head of
2391 | 		 * the mon's inventory.  We can get away with using a
2392 | 		 * stack variable object because monsters don't carry
2393 | 		 * gold in their inventory, so it won't merge.
2394 | 		 */
2395 | 		m_gold = zeroobj;
2396 | 		m_gold.otyp = GOLD_PIECE;  m_gold.oclass = GOLD_CLASS;
2397 | 		m_gold.quan = mon->mgold;  m_gold.dknown = 1;
2398 | 		m_gold.where = OBJ_FREE;
2399 | 		/* we had better not merge and free this object... */
2400 | 		if (add_to_minv(mon, &m_gold))
2401 | 		    panic("display_minventory: static object freed.");
2402 | 	    }
2403 | 
2404 | 	    n = query_objlist(tmp, mon->minvent, INVORDER_SORT, &selected,
2405 | 			(dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
2406 | 			do_all ? allow_all : worn_wield_only);
2407 | 
2408 | 	    if (do_gold) obj_extract_self(&m_gold);
2409 | 
2410 | 	    set_uasmon();
2411 | 	} else {
2412 | 	    invdisp_nothing(tmp, "(none)");
2413 | 	    n = 0;
2414 | 	}
2415 | 
2416 | 	if (n > 0) {
2417 | 	    ret = selected[0].item.a_obj;
2418 | 	    free((genericptr_t)selected);
2419 | 	    /*
2420 | 	     * Unfortunately, we can't return a pointer to our temporary
2421 | 	     * gold object.  We'll have to work out a scheme where this
2422 | 	     * can happen.  Maybe even put gold in the inventory list...
2423 | 	     */
2424 | 	    if (ret == &m_gold) ret = (struct obj *) 0;
2425 | 	} else
2426 | 	    ret = (struct obj *) 0;
2427 | 	return ret;
2428 | }
2429 | 
2430 | /*
2431 |  * Display the contents of a container in inventory style.
2432 |  * Currently, this is only used for statues, via wand of probing.
2433 |  */
2434 | struct obj *
2435 | display_cinventory(obj)
2436 | register struct obj *obj;
2437 | {
2438 | 	struct obj *ret;
2439 | 	char tmp[QBUFSZ];
2440 | 	int n;
2441 | 	menu_item *selected = 0;
2442 | 
2443 | 	Sprintf(tmp,"Contents of %s:", doname(obj));
2444 | 
2445 | 	if (obj->cobj) {
2446 | 	    n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected,
2447 | 			    PICK_NONE, allow_all);
2448 | 	} else {
2449 | 	    invdisp_nothing(tmp, "(empty)");
2450 | 	    n = 0;
2451 | 	}
2452 | 	if (n > 0) {
2453 | 	    ret = selected[0].item.a_obj;
2454 | 	    free((genericptr_t)selected);
2455 | 	} else
2456 | 	    ret = (struct obj *) 0;
2457 | 	return ret;
2458 | }
2459 | 
2460 | /* query objlist callback: return TRUE if obj is at given location */
2461 | static coord only;
2462 | 
2463 | STATIC_OVL boolean
2464 | only_here(obj)
2465 |     struct obj *obj;
2466 | {
2467 |     return (obj->ox == only.x && obj->oy == only.y);
2468 | }
2469 | 
2470 | /*
2471 |  * Display a list of buried items in inventory style.  Return a non-zero
2472 |  * value if there were items at that spot.
2473 |  *
2474 |  * Currently, this is only used with a wand of probing zapped downwards.
2475 |  */
2476 | int
2477 | display_binventory(x, y, as_if_seen)
2478 | int x, y;
2479 | boolean as_if_seen;
2480 | {
2481 | 	struct obj *obj;
2482 | 	menu_item *selected = 0;
2483 | 	int n;
2484 | 
2485 | 	/* count # of objects here */
2486 | 	for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
2487 | 	    if (obj->ox == x && obj->oy == y) {
2488 | 		if (as_if_seen) obj->dknown = 1;
2489 | 		n++;
2490 | 	    }
2491 | 
2492 | 	if (n) {
2493 | 	    only.x = x;
2494 | 	    only.y = y;
2495 | 	    if (query_objlist("Things that are buried here:",
2496 | 			      level.buriedobjlist, INVORDER_SORT,
2497 | 			      &selected, PICK_NONE, only_here) > 0)
2498 | 		free((genericptr_t)selected);
2499 | 	    only.x = only.y = 0;
2500 | 	}
2501 | 	return n;
2502 | }
2503 | 
2504 | #endif /* OVL1 */
2505 | 
2506 | /*invent.c*/