xref: /csrg-svn/games/hack/hack.invent.c (revision 41238)
1*41238Sbostic /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2*41238Sbostic /* hack.invent.c - version 1.0.3 */
3*41238Sbostic 
4*41238Sbostic #include	"hack.h"
5*41238Sbostic #include	<stdio.h>
6*41238Sbostic extern struct obj *splitobj();
7*41238Sbostic extern struct obj zeroobj;
8*41238Sbostic extern char morc;
9*41238Sbostic extern char quitchars[];
10*41238Sbostic char *xprname();
11*41238Sbostic 
12*41238Sbostic #ifndef NOWORM
13*41238Sbostic #include	"def.wseg.h"
14*41238Sbostic extern struct wseg *wsegs[32];
15*41238Sbostic #endif NOWORM
16*41238Sbostic 
17*41238Sbostic #define	NOINVSYM	'#'
18*41238Sbostic 
19*41238Sbostic static int lastinvnr = 51;	/* 0 ... 51 */
20*41238Sbostic static
21*41238Sbostic assigninvlet(otmp)
22*41238Sbostic register struct obj *otmp;
23*41238Sbostic {
24*41238Sbostic 	boolean inuse[52];
25*41238Sbostic 	register int i;
26*41238Sbostic 	register struct obj *obj;
27*41238Sbostic 
28*41238Sbostic 	for(i = 0; i < 52; i++) inuse[i] = FALSE;
29*41238Sbostic 	for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
30*41238Sbostic 		i = obj->invlet;
31*41238Sbostic 		if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
32*41238Sbostic 		if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
33*41238Sbostic 		if(i == otmp->invlet) otmp->invlet = 0;
34*41238Sbostic 	}
35*41238Sbostic 	if((i = otmp->invlet) &&
36*41238Sbostic 	    (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
37*41238Sbostic 		return;
38*41238Sbostic 	for(i = lastinvnr+1; i != lastinvnr; i++) {
39*41238Sbostic 		if(i == 52) { i = -1; continue; }
40*41238Sbostic 		if(!inuse[i]) break;
41*41238Sbostic 	}
42*41238Sbostic 	otmp->invlet = (inuse[i] ? NOINVSYM :
43*41238Sbostic 			(i < 26) ? ('a'+i) : ('A'+i-26));
44*41238Sbostic 	lastinvnr = i;
45*41238Sbostic }
46*41238Sbostic 
47*41238Sbostic struct obj *
48*41238Sbostic addinv(obj)
49*41238Sbostic register struct obj *obj;
50*41238Sbostic {
51*41238Sbostic 	register struct obj *otmp;
52*41238Sbostic 
53*41238Sbostic 	/* merge or attach to end of chain */
54*41238Sbostic 	if(!invent) {
55*41238Sbostic 		invent = obj;
56*41238Sbostic 		otmp = 0;
57*41238Sbostic 	} else
58*41238Sbostic 	for(otmp = invent; /* otmp */; otmp = otmp->nobj) {
59*41238Sbostic 		if(merged(otmp, obj, 0))
60*41238Sbostic 			return(otmp);
61*41238Sbostic 		if(!otmp->nobj) {
62*41238Sbostic 			otmp->nobj = obj;
63*41238Sbostic 			break;
64*41238Sbostic 		}
65*41238Sbostic 	}
66*41238Sbostic 	obj->nobj = 0;
67*41238Sbostic 
68*41238Sbostic 	if(flags.invlet_constant) {
69*41238Sbostic 		assigninvlet(obj);
70*41238Sbostic 		/*
71*41238Sbostic 		 * The ordering of the chain is nowhere significant
72*41238Sbostic 		 * so in case you prefer some other order than the
73*41238Sbostic 		 * historical one, change the code below.
74*41238Sbostic 		 */
75*41238Sbostic 		if(otmp) {	/* find proper place in chain */
76*41238Sbostic 			otmp->nobj = 0;
77*41238Sbostic 			if((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
78*41238Sbostic 				obj->nobj = invent;
79*41238Sbostic 				invent = obj;
80*41238Sbostic 			} else
81*41238Sbostic 			for(otmp = invent; ; otmp = otmp->nobj) {
82*41238Sbostic 			    if(!otmp->nobj ||
83*41238Sbostic 				(otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)){
84*41238Sbostic 				obj->nobj = otmp->nobj;
85*41238Sbostic 				otmp->nobj = obj;
86*41238Sbostic 				break;
87*41238Sbostic 			    }
88*41238Sbostic 			}
89*41238Sbostic 		}
90*41238Sbostic 	}
91*41238Sbostic 
92*41238Sbostic 	return(obj);
93*41238Sbostic }
94*41238Sbostic 
95*41238Sbostic useup(obj)
96*41238Sbostic register struct obj *obj;
97*41238Sbostic {
98*41238Sbostic 	if(obj->quan > 1){
99*41238Sbostic 		obj->quan--;
100*41238Sbostic 		obj->owt = weight(obj);
101*41238Sbostic 	} else {
102*41238Sbostic 		setnotworn(obj);
103*41238Sbostic 		freeinv(obj);
104*41238Sbostic 		obfree(obj, (struct obj *) 0);
105*41238Sbostic 	}
106*41238Sbostic }
107*41238Sbostic 
108*41238Sbostic freeinv(obj)
109*41238Sbostic register struct obj *obj;
110*41238Sbostic {
111*41238Sbostic 	register struct obj *otmp;
112*41238Sbostic 
113*41238Sbostic 	if(obj == invent)
114*41238Sbostic 		invent = invent->nobj;
115*41238Sbostic 	else {
116*41238Sbostic 		for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
117*41238Sbostic 			if(!otmp->nobj) panic("freeinv");
118*41238Sbostic 		otmp->nobj = obj->nobj;
119*41238Sbostic 	}
120*41238Sbostic }
121*41238Sbostic 
122*41238Sbostic /* destroy object in fobj chain (if unpaid, it remains on the bill) */
123*41238Sbostic delobj(obj) register struct obj *obj; {
124*41238Sbostic 	freeobj(obj);
125*41238Sbostic 	unpobj(obj);
126*41238Sbostic 	obfree(obj, (struct obj *) 0);
127*41238Sbostic }
128*41238Sbostic 
129*41238Sbostic /* unlink obj from chain starting with fobj */
130*41238Sbostic freeobj(obj) register struct obj *obj; {
131*41238Sbostic 	register struct obj *otmp;
132*41238Sbostic 
133*41238Sbostic 	if(obj == fobj) fobj = fobj->nobj;
134*41238Sbostic 	else {
135*41238Sbostic 		for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
136*41238Sbostic 			if(!otmp) panic("error in freeobj");
137*41238Sbostic 		otmp->nobj = obj->nobj;
138*41238Sbostic 	}
139*41238Sbostic }
140*41238Sbostic 
141*41238Sbostic /* Note: freegold throws away its argument! */
142*41238Sbostic freegold(gold) register struct gold *gold; {
143*41238Sbostic 	register struct gold *gtmp;
144*41238Sbostic 
145*41238Sbostic 	if(gold == fgold) fgold = gold->ngold;
146*41238Sbostic 	else {
147*41238Sbostic 		for(gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
148*41238Sbostic 			if(!gtmp) panic("error in freegold");
149*41238Sbostic 		gtmp->ngold = gold->ngold;
150*41238Sbostic 	}
151*41238Sbostic 	free((char *) gold);
152*41238Sbostic }
153*41238Sbostic 
154*41238Sbostic deltrap(trap)
155*41238Sbostic register struct trap *trap;
156*41238Sbostic {
157*41238Sbostic 	register struct trap *ttmp;
158*41238Sbostic 
159*41238Sbostic 	if(trap == ftrap)
160*41238Sbostic 		ftrap = ftrap->ntrap;
161*41238Sbostic 	else {
162*41238Sbostic 		for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
163*41238Sbostic 		ttmp->ntrap = trap->ntrap;
164*41238Sbostic 	}
165*41238Sbostic 	free((char *) trap);
166*41238Sbostic }
167*41238Sbostic 
168*41238Sbostic struct wseg *m_atseg;
169*41238Sbostic 
170*41238Sbostic struct monst *
171*41238Sbostic m_at(x,y)
172*41238Sbostic register x,y;
173*41238Sbostic {
174*41238Sbostic 	register struct monst *mtmp;
175*41238Sbostic #ifndef NOWORM
176*41238Sbostic 	register struct wseg *wtmp;
177*41238Sbostic #endif NOWORM
178*41238Sbostic 
179*41238Sbostic 	m_atseg = 0;
180*41238Sbostic 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
181*41238Sbostic 		if(mtmp->mx == x && mtmp->my == y)
182*41238Sbostic 			return(mtmp);
183*41238Sbostic #ifndef NOWORM
184*41238Sbostic 		if(mtmp->wormno){
185*41238Sbostic 		    for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
186*41238Sbostic 		    if(wtmp->wx == x && wtmp->wy == y){
187*41238Sbostic 			m_atseg = wtmp;
188*41238Sbostic 			return(mtmp);
189*41238Sbostic 		    }
190*41238Sbostic 		}
191*41238Sbostic #endif NOWORM
192*41238Sbostic 	}
193*41238Sbostic 	return(0);
194*41238Sbostic }
195*41238Sbostic 
196*41238Sbostic struct obj *
197*41238Sbostic o_at(x,y)
198*41238Sbostic register x,y;
199*41238Sbostic {
200*41238Sbostic 	register struct obj *otmp;
201*41238Sbostic 
202*41238Sbostic 	for(otmp = fobj; otmp; otmp = otmp->nobj)
203*41238Sbostic 		if(otmp->ox == x && otmp->oy == y) return(otmp);
204*41238Sbostic 	return(0);
205*41238Sbostic }
206*41238Sbostic 
207*41238Sbostic struct obj *
208*41238Sbostic sobj_at(n,x,y)
209*41238Sbostic register n,x,y;
210*41238Sbostic {
211*41238Sbostic 	register struct obj *otmp;
212*41238Sbostic 
213*41238Sbostic 	for(otmp = fobj; otmp; otmp = otmp->nobj)
214*41238Sbostic 		if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
215*41238Sbostic 			return(otmp);
216*41238Sbostic 	return(0);
217*41238Sbostic }
218*41238Sbostic 
219*41238Sbostic carried(obj) register struct obj *obj; {
220*41238Sbostic register struct obj *otmp;
221*41238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj)
222*41238Sbostic 		if(otmp == obj) return(1);
223*41238Sbostic 	return(0);
224*41238Sbostic }
225*41238Sbostic 
226*41238Sbostic carrying(type)
227*41238Sbostic register int type;
228*41238Sbostic {
229*41238Sbostic 	register struct obj *otmp;
230*41238Sbostic 
231*41238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj)
232*41238Sbostic 		if(otmp->otyp == type)
233*41238Sbostic 			return(TRUE);
234*41238Sbostic 	return(FALSE);
235*41238Sbostic }
236*41238Sbostic 
237*41238Sbostic struct obj *
238*41238Sbostic o_on(id, objchn) unsigned int id; register struct obj *objchn; {
239*41238Sbostic 	while(objchn) {
240*41238Sbostic 		if(objchn->o_id == id) return(objchn);
241*41238Sbostic 		objchn = objchn->nobj;
242*41238Sbostic 	}
243*41238Sbostic 	return((struct obj *) 0);
244*41238Sbostic }
245*41238Sbostic 
246*41238Sbostic struct trap *
247*41238Sbostic t_at(x,y)
248*41238Sbostic register x,y;
249*41238Sbostic {
250*41238Sbostic 	register struct trap *trap = ftrap;
251*41238Sbostic 	while(trap) {
252*41238Sbostic 		if(trap->tx == x && trap->ty == y) return(trap);
253*41238Sbostic 		trap = trap->ntrap;
254*41238Sbostic 	}
255*41238Sbostic 	return(0);
256*41238Sbostic }
257*41238Sbostic 
258*41238Sbostic struct gold *
259*41238Sbostic g_at(x,y)
260*41238Sbostic register x,y;
261*41238Sbostic {
262*41238Sbostic 	register struct gold *gold = fgold;
263*41238Sbostic 	while(gold) {
264*41238Sbostic 		if(gold->gx == x && gold->gy == y) return(gold);
265*41238Sbostic 		gold = gold->ngold;
266*41238Sbostic 	}
267*41238Sbostic 	return(0);
268*41238Sbostic }
269*41238Sbostic 
270*41238Sbostic /* make dummy object structure containing gold - for temporary use only */
271*41238Sbostic struct obj *
272*41238Sbostic mkgoldobj(q)
273*41238Sbostic register long q;
274*41238Sbostic {
275*41238Sbostic 	register struct obj *otmp;
276*41238Sbostic 
277*41238Sbostic 	otmp = newobj(0);
278*41238Sbostic 	/* should set o_id etc. but otmp will be freed soon */
279*41238Sbostic 	otmp->olet = '$';
280*41238Sbostic 	u.ugold -= q;
281*41238Sbostic 	OGOLD(otmp) = q;
282*41238Sbostic 	flags.botl = 1;
283*41238Sbostic 	return(otmp);
284*41238Sbostic }
285*41238Sbostic 
286*41238Sbostic /*
287*41238Sbostic  * getobj returns:
288*41238Sbostic  *	struct obj *xxx:	object to do something with.
289*41238Sbostic  *	(struct obj *) 0	error return: no object.
290*41238Sbostic  *	&zeroobj		explicitly no object (as in w-).
291*41238Sbostic  */
292*41238Sbostic struct obj *
293*41238Sbostic getobj(let,word)
294*41238Sbostic register char *let,*word;
295*41238Sbostic {
296*41238Sbostic 	register struct obj *otmp;
297*41238Sbostic 	register char ilet,ilet1,ilet2;
298*41238Sbostic 	char buf[BUFSZ];
299*41238Sbostic 	char lets[BUFSZ];
300*41238Sbostic 	register int foo = 0, foo2;
301*41238Sbostic 	register char *bp = buf;
302*41238Sbostic 	xchar allowcnt = 0;	/* 0, 1 or 2 */
303*41238Sbostic 	boolean allowgold = FALSE;
304*41238Sbostic 	boolean allowall = FALSE;
305*41238Sbostic 	boolean allownone = FALSE;
306*41238Sbostic 	xchar foox = 0;
307*41238Sbostic 	long cnt;
308*41238Sbostic 
309*41238Sbostic 	if(*let == '0') let++, allowcnt = 1;
310*41238Sbostic 	if(*let == '$') let++, allowgold = TRUE;
311*41238Sbostic 	if(*let == '#') let++, allowall = TRUE;
312*41238Sbostic 	if(*let == '-') let++, allownone = TRUE;
313*41238Sbostic 	if(allownone) *bp++ = '-';
314*41238Sbostic 	if(allowgold) *bp++ = '$';
315*41238Sbostic 	if(bp > buf && bp[-1] == '-') *bp++ = ' ';
316*41238Sbostic 
317*41238Sbostic 	ilet = 'a';
318*41238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj){
319*41238Sbostic 	    if(!*let || index(let, otmp->olet)) {
320*41238Sbostic 		bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
321*41238Sbostic 
322*41238Sbostic 		/* ugly check: remove inappropriate things */
323*41238Sbostic 		if((!strcmp(word, "take off") &&
324*41238Sbostic 		    !(otmp->owornmask & (W_ARMOR - W_ARM2)))
325*41238Sbostic 		|| (!strcmp(word, "wear") &&
326*41238Sbostic 		    (otmp->owornmask & (W_ARMOR | W_RING)))
327*41238Sbostic 		|| (!strcmp(word, "wield") &&
328*41238Sbostic 		    (otmp->owornmask & W_WEP))) {
329*41238Sbostic 			foo--;
330*41238Sbostic 			foox++;
331*41238Sbostic 		}
332*41238Sbostic 	    }
333*41238Sbostic 	    if(ilet == 'z') ilet = 'A'; else ilet++;
334*41238Sbostic 	}
335*41238Sbostic 	bp[foo] = 0;
336*41238Sbostic 	if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
337*41238Sbostic 	(void) strcpy(lets, bp);	/* necessary since we destroy buf */
338*41238Sbostic 	if(foo > 5) {			/* compactify string */
339*41238Sbostic 		foo = foo2 = 1;
340*41238Sbostic 		ilet2 = bp[0];
341*41238Sbostic 		ilet1 = bp[1];
342*41238Sbostic 		while(ilet = bp[++foo2] = bp[++foo]){
343*41238Sbostic 			if(ilet == ilet1+1){
344*41238Sbostic 				if(ilet1 == ilet2+1)
345*41238Sbostic 					bp[foo2 - 1] = ilet1 = '-';
346*41238Sbostic 				else if(ilet2 == '-') {
347*41238Sbostic 					bp[--foo2] = ++ilet1;
348*41238Sbostic 					continue;
349*41238Sbostic 				}
350*41238Sbostic 			}
351*41238Sbostic 			ilet2 = ilet1;
352*41238Sbostic 			ilet1 = ilet;
353*41238Sbostic 		}
354*41238Sbostic 	}
355*41238Sbostic 	if(!foo && !allowall && !allowgold && !allownone) {
356*41238Sbostic 		pline("You don't have anything %sto %s.",
357*41238Sbostic 			foox ? "else " : "", word);
358*41238Sbostic 		return(0);
359*41238Sbostic 	}
360*41238Sbostic 	for(;;) {
361*41238Sbostic 		if(!buf[0])
362*41238Sbostic 			pline("What do you want to %s [*]? ", word);
363*41238Sbostic 		else
364*41238Sbostic 			pline("What do you want to %s [%s or ?*]? ",
365*41238Sbostic 				word, buf);
366*41238Sbostic 
367*41238Sbostic 		cnt = 0;
368*41238Sbostic 		ilet = readchar();
369*41238Sbostic 		while(digit(ilet) && allowcnt) {
370*41238Sbostic 			if (cnt < 100000000)
371*41238Sbostic 			    cnt = 10*cnt + (ilet - '0');
372*41238Sbostic 			else
373*41238Sbostic 			    cnt = 999999999;
374*41238Sbostic 			allowcnt = 2;	/* signal presence of cnt */
375*41238Sbostic 			ilet = readchar();
376*41238Sbostic 		}
377*41238Sbostic 		if(digit(ilet)) {
378*41238Sbostic 			pline("No count allowed with this command.");
379*41238Sbostic 			continue;
380*41238Sbostic 		}
381*41238Sbostic 		if(index(quitchars,ilet))
382*41238Sbostic 			return((struct obj *)0);
383*41238Sbostic 		if(ilet == '-') {
384*41238Sbostic 			return(allownone ? &zeroobj : (struct obj *) 0);
385*41238Sbostic 		}
386*41238Sbostic 		if(ilet == '$') {
387*41238Sbostic 			if(!allowgold){
388*41238Sbostic 				pline("You cannot %s gold.", word);
389*41238Sbostic 				continue;
390*41238Sbostic 			}
391*41238Sbostic 			if(!(allowcnt == 2 && cnt < u.ugold))
392*41238Sbostic 				cnt = u.ugold;
393*41238Sbostic 			return(mkgoldobj(cnt));
394*41238Sbostic 		}
395*41238Sbostic 		if(ilet == '?') {
396*41238Sbostic 			doinv(lets);
397*41238Sbostic 			if(!(ilet = morc)) continue;
398*41238Sbostic 			/* he typed a letter (not a space) to more() */
399*41238Sbostic 		} else if(ilet == '*') {
400*41238Sbostic 			doinv((char *) 0);
401*41238Sbostic 			if(!(ilet = morc)) continue;
402*41238Sbostic 			/* ... */
403*41238Sbostic 		}
404*41238Sbostic 		if(flags.invlet_constant) {
405*41238Sbostic 			for(otmp = invent; otmp; otmp = otmp->nobj)
406*41238Sbostic 				if(otmp->invlet == ilet) break;
407*41238Sbostic 		} else {
408*41238Sbostic 			if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
409*41238Sbostic 			ilet -= 'a';
410*41238Sbostic 			for(otmp = invent; otmp && ilet;
411*41238Sbostic 					ilet--, otmp = otmp->nobj) ;
412*41238Sbostic 		}
413*41238Sbostic 		if(!otmp) {
414*41238Sbostic 			pline("You don't have that object.");
415*41238Sbostic 			continue;
416*41238Sbostic 		}
417*41238Sbostic 		if(cnt < 0 || otmp->quan < cnt) {
418*41238Sbostic 			pline("You don't have that many! [You have %u]"
419*41238Sbostic 			, otmp->quan);
420*41238Sbostic 			continue;
421*41238Sbostic 		}
422*41238Sbostic 		break;
423*41238Sbostic 	}
424*41238Sbostic 	if(!allowall && let && !index(let,otmp->olet)) {
425*41238Sbostic 		pline("That is a silly thing to %s.",word);
426*41238Sbostic 		return(0);
427*41238Sbostic 	}
428*41238Sbostic 	if(allowcnt == 2) {	/* cnt given */
429*41238Sbostic 		if(cnt == 0) return(0);
430*41238Sbostic 		if(cnt != otmp->quan) {
431*41238Sbostic 			register struct obj *obj;
432*41238Sbostic 			obj = splitobj(otmp, (int) cnt);
433*41238Sbostic 			if(otmp == uwep) setuwep(obj);
434*41238Sbostic 		}
435*41238Sbostic 	}
436*41238Sbostic 	return(otmp);
437*41238Sbostic }
438*41238Sbostic 
439*41238Sbostic ckunpaid(otmp) register struct obj *otmp; {
440*41238Sbostic 	return( otmp->unpaid );
441*41238Sbostic }
442*41238Sbostic 
443*41238Sbostic /* interactive version of getobj - used for Drop and Identify */
444*41238Sbostic /* return the number of times fn was called successfully */
445*41238Sbostic ggetobj(word, fn, max)
446*41238Sbostic char *word;
447*41238Sbostic int (*fn)(),  max;
448*41238Sbostic {
449*41238Sbostic char buf[BUFSZ];
450*41238Sbostic register char *ip;
451*41238Sbostic register char sym;
452*41238Sbostic register int oletct = 0, iletct = 0;
453*41238Sbostic register boolean allflag = FALSE;
454*41238Sbostic char olets[20], ilets[20];
455*41238Sbostic int (*ckfn)() = (int (*)()) 0;
456*41238Sbostic xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;	/* BAH */
457*41238Sbostic 	if(!invent && !allowgold){
458*41238Sbostic 		pline("You have nothing to %s.", word);
459*41238Sbostic 		return(0);
460*41238Sbostic 	} else {
461*41238Sbostic 		register struct obj *otmp = invent;
462*41238Sbostic 		register int uflg = 0;
463*41238Sbostic 
464*41238Sbostic 		if(allowgold) ilets[iletct++] = '$';
465*41238Sbostic 		ilets[iletct] = 0;
466*41238Sbostic 		while(otmp) {
467*41238Sbostic 			if(!index(ilets, otmp->olet)){
468*41238Sbostic 				ilets[iletct++] = otmp->olet;
469*41238Sbostic 				ilets[iletct] = 0;
470*41238Sbostic 			}
471*41238Sbostic 			if(otmp->unpaid) uflg = 1;
472*41238Sbostic 			otmp = otmp->nobj;
473*41238Sbostic 		}
474*41238Sbostic 		ilets[iletct++] = ' ';
475*41238Sbostic 		if(uflg) ilets[iletct++] = 'u';
476*41238Sbostic 		if(invent) ilets[iletct++] = 'a';
477*41238Sbostic 		ilets[iletct] = 0;
478*41238Sbostic 	}
479*41238Sbostic 	pline("What kinds of thing do you want to %s? [%s] ",
480*41238Sbostic 		word, ilets);
481*41238Sbostic 	getlin(buf);
482*41238Sbostic 	if(buf[0] == '\033') {
483*41238Sbostic 		clrlin();
484*41238Sbostic 		return(0);
485*41238Sbostic 	}
486*41238Sbostic 	ip = buf;
487*41238Sbostic 	olets[0] = 0;
488*41238Sbostic 	while(sym = *ip++){
489*41238Sbostic 		if(sym == ' ') continue;
490*41238Sbostic 		if(sym == '$') {
491*41238Sbostic 			if(allowgold == 1)
492*41238Sbostic 				(*fn)(mkgoldobj(u.ugold));
493*41238Sbostic 			else if(!u.ugold)
494*41238Sbostic 				pline("You have no gold.");
495*41238Sbostic 			allowgold = 2;
496*41238Sbostic 		} else
497*41238Sbostic 		if(sym == 'a' || sym == 'A') allflag = TRUE; else
498*41238Sbostic 		if(sym == 'u' || sym == 'U') ckfn = ckunpaid; else
499*41238Sbostic 		if(index("!%?[()=*/\"0", sym)){
500*41238Sbostic 			if(!index(olets, sym)){
501*41238Sbostic 				olets[oletct++] = sym;
502*41238Sbostic 				olets[oletct] = 0;
503*41238Sbostic 			}
504*41238Sbostic 		}
505*41238Sbostic 		else pline("You don't have any %c's.", sym);
506*41238Sbostic 	}
507*41238Sbostic 	if(allowgold == 2 && !oletct)
508*41238Sbostic 		return(1);	/* he dropped gold (or at least tried to) */
509*41238Sbostic 	else
510*41238Sbostic 		return(askchain(invent, olets, allflag, fn, ckfn, max));
511*41238Sbostic }
512*41238Sbostic 
513*41238Sbostic /*
514*41238Sbostic  * Walk through the chain starting at objchn and ask for all objects
515*41238Sbostic  * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
516*41238Sbostic  * whether the action in question (i.e., fn) has to be performed.
517*41238Sbostic  * If allflag then no questions are asked. Max gives the max nr of
518*41238Sbostic  * objects to be treated. Return the number of objects treated.
519*41238Sbostic  */
520*41238Sbostic askchain(objchn, olets, allflag, fn, ckfn, max)
521*41238Sbostic struct obj *objchn;
522*41238Sbostic register char *olets;
523*41238Sbostic int allflag;
524*41238Sbostic int (*fn)(), (*ckfn)();
525*41238Sbostic int max;
526*41238Sbostic {
527*41238Sbostic register struct obj *otmp, *otmp2;
528*41238Sbostic register char sym, ilet;
529*41238Sbostic register int cnt = 0;
530*41238Sbostic 	ilet = 'a'-1;
531*41238Sbostic 	for(otmp = objchn; otmp; otmp = otmp2){
532*41238Sbostic 		if(ilet == 'z') ilet = 'A'; else ilet++;
533*41238Sbostic 		otmp2 = otmp->nobj;
534*41238Sbostic 		if(olets && *olets && !index(olets, otmp->olet)) continue;
535*41238Sbostic 		if(ckfn && !(*ckfn)(otmp)) continue;
536*41238Sbostic 		if(!allflag) {
537*41238Sbostic 			pline(xprname(otmp, ilet));
538*41238Sbostic 			addtopl(" [nyaq]? ");
539*41238Sbostic 			sym = readchar();
540*41238Sbostic 		}
541*41238Sbostic 		else	sym = 'y';
542*41238Sbostic 
543*41238Sbostic 		switch(sym){
544*41238Sbostic 		case 'a':
545*41238Sbostic 			allflag = 1;
546*41238Sbostic 		case 'y':
547*41238Sbostic 			cnt += (*fn)(otmp);
548*41238Sbostic 			if(--max == 0) goto ret;
549*41238Sbostic 		case 'n':
550*41238Sbostic 		default:
551*41238Sbostic 			break;
552*41238Sbostic 		case 'q':
553*41238Sbostic 			goto ret;
554*41238Sbostic 		}
555*41238Sbostic 	}
556*41238Sbostic 	pline(cnt ? "That was all." : "No applicable objects.");
557*41238Sbostic ret:
558*41238Sbostic 	return(cnt);
559*41238Sbostic }
560*41238Sbostic 
561*41238Sbostic obj_to_let(obj)	/* should of course only be called for things in invent */
562*41238Sbostic register struct obj *obj;
563*41238Sbostic {
564*41238Sbostic 	register struct obj *otmp;
565*41238Sbostic 	register char ilet;
566*41238Sbostic 
567*41238Sbostic 	if(flags.invlet_constant)
568*41238Sbostic 		return(obj->invlet);
569*41238Sbostic 	ilet = 'a';
570*41238Sbostic 	for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
571*41238Sbostic 		if(++ilet > 'z') ilet = 'A';
572*41238Sbostic 	return(otmp ? ilet : NOINVSYM);
573*41238Sbostic }
574*41238Sbostic 
575*41238Sbostic prinv(obj)
576*41238Sbostic register struct obj *obj;
577*41238Sbostic {
578*41238Sbostic 	pline(xprname(obj, obj_to_let(obj)));
579*41238Sbostic }
580*41238Sbostic 
581*41238Sbostic static char *
582*41238Sbostic xprname(obj,let)
583*41238Sbostic register struct obj *obj;
584*41238Sbostic register char let;
585*41238Sbostic {
586*41238Sbostic 	static char li[BUFSZ];
587*41238Sbostic 
588*41238Sbostic 	(void) sprintf(li, "%c - %s.",
589*41238Sbostic 		flags.invlet_constant ? obj->invlet : let,
590*41238Sbostic 		doname(obj));
591*41238Sbostic 	return(li);
592*41238Sbostic }
593*41238Sbostic 
594*41238Sbostic ddoinv()
595*41238Sbostic {
596*41238Sbostic 	doinv((char *) 0);
597*41238Sbostic 	return(0);
598*41238Sbostic }
599*41238Sbostic 
600*41238Sbostic /* called with 0 or "": all objects in inventory */
601*41238Sbostic /* otherwise: all objects with (serial) letter in lets */
602*41238Sbostic doinv(lets)
603*41238Sbostic register char *lets;
604*41238Sbostic {
605*41238Sbostic 	register struct obj *otmp;
606*41238Sbostic 	register char ilet;
607*41238Sbostic 	int ct = 0;
608*41238Sbostic 	char any[BUFSZ];
609*41238Sbostic 
610*41238Sbostic 	morc = 0;		/* just to be sure */
611*41238Sbostic 
612*41238Sbostic 	if(!invent){
613*41238Sbostic 		pline("Not carrying anything.");
614*41238Sbostic 		return;
615*41238Sbostic 	}
616*41238Sbostic 
617*41238Sbostic 	cornline(0, (char *) 0);
618*41238Sbostic 	ilet = 'a';
619*41238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj) {
620*41238Sbostic 	    if(flags.invlet_constant) ilet = otmp->invlet;
621*41238Sbostic 	    if(!lets || !*lets || index(lets, ilet)) {
622*41238Sbostic 		    cornline(1, xprname(otmp, ilet));
623*41238Sbostic 		    any[ct++] = ilet;
624*41238Sbostic 	    }
625*41238Sbostic 	    if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
626*41238Sbostic 	}
627*41238Sbostic 	any[ct] = 0;
628*41238Sbostic 	cornline(2, any);
629*41238Sbostic }
630*41238Sbostic 
631*41238Sbostic dotypeinv ()				/* free after Robert Viduya */
632*41238Sbostic /* Changed to one type only, so he doesnt have to type cr */
633*41238Sbostic {
634*41238Sbostic     char c, ilet;
635*41238Sbostic     char stuff[BUFSZ];
636*41238Sbostic     register int stct;
637*41238Sbostic     register struct obj *otmp;
638*41238Sbostic     boolean billx = inshop() && doinvbill(0);
639*41238Sbostic     boolean unpd = FALSE;
640*41238Sbostic 
641*41238Sbostic 	if (!invent && !u.ugold && !billx) {
642*41238Sbostic 	    pline ("You aren't carrying anything.");
643*41238Sbostic 	    return(0);
644*41238Sbostic 	}
645*41238Sbostic 
646*41238Sbostic 	stct = 0;
647*41238Sbostic 	if(u.ugold) stuff[stct++] = '$';
648*41238Sbostic 	stuff[stct] = 0;
649*41238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj) {
650*41238Sbostic 	    if (!index (stuff, otmp->olet)) {
651*41238Sbostic 		stuff[stct++] = otmp->olet;
652*41238Sbostic 		stuff[stct] = 0;
653*41238Sbostic 	    }
654*41238Sbostic 	    if(otmp->unpaid)
655*41238Sbostic 		unpd = TRUE;
656*41238Sbostic 	}
657*41238Sbostic 	if(unpd) stuff[stct++] = 'u';
658*41238Sbostic 	if(billx) stuff[stct++] = 'x';
659*41238Sbostic 	stuff[stct] = 0;
660*41238Sbostic 
661*41238Sbostic 	if(stct > 1) {
662*41238Sbostic 	    pline ("What type of object [%s] do you want an inventory of? ",
663*41238Sbostic 		stuff);
664*41238Sbostic 	    c = readchar();
665*41238Sbostic 	    if(index(quitchars,c)) return(0);
666*41238Sbostic 	} else
667*41238Sbostic 	    c = stuff[0];
668*41238Sbostic 
669*41238Sbostic 	if(c == '$')
670*41238Sbostic 	    return(doprgold());
671*41238Sbostic 
672*41238Sbostic 	if(c == 'x' || c == 'X') {
673*41238Sbostic 	    if(billx)
674*41238Sbostic 		(void) doinvbill(1);
675*41238Sbostic 	    else
676*41238Sbostic 		pline("No used-up objects on the shopping bill.");
677*41238Sbostic 	    return(0);
678*41238Sbostic 	}
679*41238Sbostic 
680*41238Sbostic 	if((c == 'u' || c == 'U') && !unpd) {
681*41238Sbostic 		pline("You are not carrying any unpaid objects.");
682*41238Sbostic 		return(0);
683*41238Sbostic 	}
684*41238Sbostic 
685*41238Sbostic 	stct = 0;
686*41238Sbostic 	ilet = 'a';
687*41238Sbostic 	for (otmp = invent; otmp; otmp = otmp -> nobj) {
688*41238Sbostic 	    if(flags.invlet_constant) ilet = otmp->invlet;
689*41238Sbostic 	    if (c == otmp -> olet || (c == 'u' && otmp -> unpaid))
690*41238Sbostic 		stuff[stct++] = ilet;
691*41238Sbostic 	    if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
692*41238Sbostic 	}
693*41238Sbostic 	stuff[stct] = '\0';
694*41238Sbostic 	if(stct == 0)
695*41238Sbostic 		pline("You have no such objects.");
696*41238Sbostic 	else
697*41238Sbostic 		doinv (stuff);
698*41238Sbostic 
699*41238Sbostic 	return(0);
700*41238Sbostic }
701*41238Sbostic 
702*41238Sbostic /* look at what is here */
703*41238Sbostic dolook() {
704*41238Sbostic     register struct obj *otmp, *otmp0;
705*41238Sbostic     register struct gold *gold;
706*41238Sbostic     char *verb = Blind ? "feel" : "see";
707*41238Sbostic     int	ct = 0;
708*41238Sbostic 
709*41238Sbostic     if(!u.uswallow) {
710*41238Sbostic 	if(Blind) {
711*41238Sbostic 	    pline("You try to feel what is lying here on the floor.");
712*41238Sbostic 	    if(Levitation) {				/* ab@unido */
713*41238Sbostic 		pline("You cannot reach the floor!");
714*41238Sbostic 		return(1);
715*41238Sbostic 	    }
716*41238Sbostic 	}
717*41238Sbostic 	otmp0 = o_at(u.ux, u.uy);
718*41238Sbostic 	gold = g_at(u.ux, u.uy);
719*41238Sbostic     }
720*41238Sbostic 
721*41238Sbostic     if(u.uswallow || (!otmp0 && !gold)) {
722*41238Sbostic 	pline("You %s no objects here.", verb);
723*41238Sbostic 	return(!!Blind);
724*41238Sbostic     }
725*41238Sbostic 
726*41238Sbostic     cornline(0, "Things that are here:");
727*41238Sbostic     for(otmp = otmp0; otmp; otmp = otmp->nobj) {
728*41238Sbostic 	if(otmp->ox == u.ux && otmp->oy == u.uy) {
729*41238Sbostic 	    ct++;
730*41238Sbostic 	    cornline(1, doname(otmp));
731*41238Sbostic 	    if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
732*41238Sbostic 		pline("Touching the dead cockatrice is a fatal mistake ...");
733*41238Sbostic 		pline("You die ...");
734*41238Sbostic 		killer = "dead cockatrice";
735*41238Sbostic 		done("died");
736*41238Sbostic 	    }
737*41238Sbostic 	}
738*41238Sbostic     }
739*41238Sbostic 
740*41238Sbostic     if(gold) {
741*41238Sbostic 	char gbuf[30];
742*41238Sbostic 
743*41238Sbostic 	(void) sprintf(gbuf, "%ld gold piece%s",
744*41238Sbostic 		gold->amount, plur(gold->amount));
745*41238Sbostic 	if(!ct++)
746*41238Sbostic 	    pline("You %s here %s.", verb, gbuf);
747*41238Sbostic 	else
748*41238Sbostic 	    cornline(1, gbuf);
749*41238Sbostic     }
750*41238Sbostic 
751*41238Sbostic     if(ct == 1 && !gold) {
752*41238Sbostic 	pline("You %s here %s.", verb, doname(otmp0));
753*41238Sbostic 	cornline(3, (char *) 0);
754*41238Sbostic     }
755*41238Sbostic     if(ct > 1)
756*41238Sbostic 	cornline(2, (char *) 0);
757*41238Sbostic     return(!!Blind);
758*41238Sbostic }
759*41238Sbostic 
760*41238Sbostic stackobj(obj) register struct obj *obj; {
761*41238Sbostic register struct obj *otmp = fobj;
762*41238Sbostic 	for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
763*41238Sbostic 	if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
764*41238Sbostic 		merged(obj,otmp,1))
765*41238Sbostic 			return;
766*41238Sbostic }
767*41238Sbostic 
768*41238Sbostic /* merge obj with otmp and delete obj if types agree */
769*41238Sbostic merged(otmp,obj,lose) register struct obj *otmp, *obj; {
770*41238Sbostic 	if(obj->otyp == otmp->otyp &&
771*41238Sbostic 	  obj->unpaid == otmp->unpaid &&
772*41238Sbostic 	  obj->spe == otmp->spe &&
773*41238Sbostic 	  obj->dknown == otmp->dknown &&
774*41238Sbostic 	  obj->cursed == otmp->cursed &&
775*41238Sbostic 	  (index("%*?!", obj->olet) ||
776*41238Sbostic 	    (obj->known == otmp->known &&
777*41238Sbostic 		(obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
778*41238Sbostic 		otmp->quan += obj->quan;
779*41238Sbostic 		otmp->owt += obj->owt;
780*41238Sbostic 		if(lose) freeobj(obj);
781*41238Sbostic 		obfree(obj,otmp);	/* free(obj), bill->otmp */
782*41238Sbostic 		return(1);
783*41238Sbostic 	} else	return(0);
784*41238Sbostic }
785*41238Sbostic 
786*41238Sbostic /*
787*41238Sbostic  * Gold is no longer displayed; in fact, when you have a lot of money,
788*41238Sbostic  * it may take a while before you have counted it all.
789*41238Sbostic  * [Bug: d$ and pickup still tell you how much it was.]
790*41238Sbostic  */
791*41238Sbostic extern int (*occupation)();
792*41238Sbostic extern char *occtxt;
793*41238Sbostic static long goldcounted;
794*41238Sbostic 
795*41238Sbostic countgold(){
796*41238Sbostic 	if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) {
797*41238Sbostic 		long eps = 0;
798*41238Sbostic 		if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1));
799*41238Sbostic 		pline("You probably have about %ld gold pieces.",
800*41238Sbostic 			u.ugold + eps);
801*41238Sbostic 		return(0);	/* done */
802*41238Sbostic 	}
803*41238Sbostic 	return(1);		/* continue */
804*41238Sbostic }
805*41238Sbostic 
806*41238Sbostic doprgold(){
807*41238Sbostic 	if(!u.ugold)
808*41238Sbostic 		pline("You do not carry any gold.");
809*41238Sbostic 	else if(u.ugold <= 500)
810*41238Sbostic 		pline("You are carrying %ld gold pieces.", u.ugold);
811*41238Sbostic 	else {
812*41238Sbostic 		pline("You sit down in order to count your gold pieces.");
813*41238Sbostic 		goldcounted = 500;
814*41238Sbostic 		occupation = countgold;
815*41238Sbostic 		occtxt = "counting your gold";
816*41238Sbostic 	}
817*41238Sbostic 	return(1);
818*41238Sbostic }
819*41238Sbostic 
820*41238Sbostic /* --- end of gold counting section --- */
821*41238Sbostic 
822*41238Sbostic doprwep(){
823*41238Sbostic 	if(!uwep) pline("You are empty handed.");
824*41238Sbostic 	else prinv(uwep);
825*41238Sbostic 	return(0);
826*41238Sbostic }
827*41238Sbostic 
828*41238Sbostic doprarm(){
829*41238Sbostic 	if(!uarm && !uarmg && !uarms && !uarmh)
830*41238Sbostic 		pline("You are not wearing any armor.");
831*41238Sbostic 	else {
832*41238Sbostic 		char lets[6];
833*41238Sbostic 		register int ct = 0;
834*41238Sbostic 
835*41238Sbostic 		if(uarm) lets[ct++] = obj_to_let(uarm);
836*41238Sbostic 		if(uarm2) lets[ct++] = obj_to_let(uarm2);
837*41238Sbostic 		if(uarmh) lets[ct++] = obj_to_let(uarmh);
838*41238Sbostic 		if(uarms) lets[ct++] = obj_to_let(uarms);
839*41238Sbostic 		if(uarmg) lets[ct++] = obj_to_let(uarmg);
840*41238Sbostic 		lets[ct] = 0;
841*41238Sbostic 		doinv(lets);
842*41238Sbostic 	}
843*41238Sbostic 	return(0);
844*41238Sbostic }
845*41238Sbostic 
846*41238Sbostic doprring(){
847*41238Sbostic 	if(!uleft && !uright)
848*41238Sbostic 		pline("You are not wearing any rings.");
849*41238Sbostic 	else {
850*41238Sbostic 		char lets[3];
851*41238Sbostic 		register int ct = 0;
852*41238Sbostic 
853*41238Sbostic 		if(uleft) lets[ct++] = obj_to_let(uleft);
854*41238Sbostic 		if(uright) lets[ct++] = obj_to_let(uright);
855*41238Sbostic 		lets[ct] = 0;
856*41238Sbostic 		doinv(lets);
857*41238Sbostic 	}
858*41238Sbostic 	return(0);
859*41238Sbostic }
860*41238Sbostic 
861*41238Sbostic digit(c) char c; {
862*41238Sbostic 	return(c >= '0' && c <= '9');
863*41238Sbostic }
864