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