xref: /csrg-svn/games/hack/hack.invent.c (revision 57827)
141238Sbostic /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
241238Sbostic /* hack.invent.c - version 1.0.3 */
341238Sbostic 
441238Sbostic #include	"hack.h"
541238Sbostic #include	<stdio.h>
641238Sbostic extern struct obj *splitobj();
741238Sbostic extern struct obj zeroobj;
841238Sbostic extern char morc;
941238Sbostic extern char quitchars[];
10*57827Storek static char *xprname();
1141238Sbostic 
1241238Sbostic #ifndef NOWORM
1341238Sbostic #include	"def.wseg.h"
1441238Sbostic extern struct wseg *wsegs[32];
1541238Sbostic #endif NOWORM
1641238Sbostic 
1741238Sbostic #define	NOINVSYM	'#'
1841238Sbostic 
1941238Sbostic static int lastinvnr = 51;	/* 0 ... 51 */
2041238Sbostic static
assigninvlet(otmp)2141238Sbostic assigninvlet(otmp)
2241238Sbostic register struct obj *otmp;
2341238Sbostic {
2441238Sbostic 	boolean inuse[52];
2541238Sbostic 	register int i;
2641238Sbostic 	register struct obj *obj;
2741238Sbostic 
2841238Sbostic 	for(i = 0; i < 52; i++) inuse[i] = FALSE;
2941238Sbostic 	for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
3041238Sbostic 		i = obj->invlet;
3141238Sbostic 		if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
3241238Sbostic 		if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
3341238Sbostic 		if(i == otmp->invlet) otmp->invlet = 0;
3441238Sbostic 	}
3541238Sbostic 	if((i = otmp->invlet) &&
3641238Sbostic 	    (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
3741238Sbostic 		return;
3841238Sbostic 	for(i = lastinvnr+1; i != lastinvnr; i++) {
3941238Sbostic 		if(i == 52) { i = -1; continue; }
4041238Sbostic 		if(!inuse[i]) break;
4141238Sbostic 	}
4241238Sbostic 	otmp->invlet = (inuse[i] ? NOINVSYM :
4341238Sbostic 			(i < 26) ? ('a'+i) : ('A'+i-26));
4441238Sbostic 	lastinvnr = i;
4541238Sbostic }
4641238Sbostic 
4741238Sbostic struct obj *
addinv(obj)4841238Sbostic addinv(obj)
4941238Sbostic register struct obj *obj;
5041238Sbostic {
5141238Sbostic 	register struct obj *otmp;
5241238Sbostic 
5341238Sbostic 	/* merge or attach to end of chain */
5441238Sbostic 	if(!invent) {
5541238Sbostic 		invent = obj;
5641238Sbostic 		otmp = 0;
5741238Sbostic 	} else
5841238Sbostic 	for(otmp = invent; /* otmp */; otmp = otmp->nobj) {
5941238Sbostic 		if(merged(otmp, obj, 0))
6041238Sbostic 			return(otmp);
6141238Sbostic 		if(!otmp->nobj) {
6241238Sbostic 			otmp->nobj = obj;
6341238Sbostic 			break;
6441238Sbostic 		}
6541238Sbostic 	}
6641238Sbostic 	obj->nobj = 0;
6741238Sbostic 
6841238Sbostic 	if(flags.invlet_constant) {
6941238Sbostic 		assigninvlet(obj);
7041238Sbostic 		/*
7141238Sbostic 		 * The ordering of the chain is nowhere significant
7241238Sbostic 		 * so in case you prefer some other order than the
7341238Sbostic 		 * historical one, change the code below.
7441238Sbostic 		 */
7541238Sbostic 		if(otmp) {	/* find proper place in chain */
7641238Sbostic 			otmp->nobj = 0;
7741238Sbostic 			if((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
7841238Sbostic 				obj->nobj = invent;
7941238Sbostic 				invent = obj;
8041238Sbostic 			} else
8141238Sbostic 			for(otmp = invent; ; otmp = otmp->nobj) {
8241238Sbostic 			    if(!otmp->nobj ||
8341238Sbostic 				(otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)){
8441238Sbostic 				obj->nobj = otmp->nobj;
8541238Sbostic 				otmp->nobj = obj;
8641238Sbostic 				break;
8741238Sbostic 			    }
8841238Sbostic 			}
8941238Sbostic 		}
9041238Sbostic 	}
9141238Sbostic 
9241238Sbostic 	return(obj);
9341238Sbostic }
9441238Sbostic 
useup(obj)9541238Sbostic useup(obj)
9641238Sbostic register struct obj *obj;
9741238Sbostic {
9841238Sbostic 	if(obj->quan > 1){
9941238Sbostic 		obj->quan--;
10041238Sbostic 		obj->owt = weight(obj);
10141238Sbostic 	} else {
10241238Sbostic 		setnotworn(obj);
10341238Sbostic 		freeinv(obj);
10441238Sbostic 		obfree(obj, (struct obj *) 0);
10541238Sbostic 	}
10641238Sbostic }
10741238Sbostic 
freeinv(obj)10841238Sbostic freeinv(obj)
10941238Sbostic register struct obj *obj;
11041238Sbostic {
11141238Sbostic 	register struct obj *otmp;
11241238Sbostic 
11341238Sbostic 	if(obj == invent)
11441238Sbostic 		invent = invent->nobj;
11541238Sbostic 	else {
11641238Sbostic 		for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
11741238Sbostic 			if(!otmp->nobj) panic("freeinv");
11841238Sbostic 		otmp->nobj = obj->nobj;
11941238Sbostic 	}
12041238Sbostic }
12141238Sbostic 
12241238Sbostic /* destroy object in fobj chain (if unpaid, it remains on the bill) */
delobj(obj)12341238Sbostic delobj(obj) register struct obj *obj; {
12441238Sbostic 	freeobj(obj);
12541238Sbostic 	unpobj(obj);
12641238Sbostic 	obfree(obj, (struct obj *) 0);
12741238Sbostic }
12841238Sbostic 
12941238Sbostic /* unlink obj from chain starting with fobj */
freeobj(obj)13041238Sbostic freeobj(obj) register struct obj *obj; {
13141238Sbostic 	register struct obj *otmp;
13241238Sbostic 
13341238Sbostic 	if(obj == fobj) fobj = fobj->nobj;
13441238Sbostic 	else {
13541238Sbostic 		for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
13641238Sbostic 			if(!otmp) panic("error in freeobj");
13741238Sbostic 		otmp->nobj = obj->nobj;
13841238Sbostic 	}
13941238Sbostic }
14041238Sbostic 
14141238Sbostic /* Note: freegold throws away its argument! */
freegold(gold)14241238Sbostic freegold(gold) register struct gold *gold; {
14341238Sbostic 	register struct gold *gtmp;
14441238Sbostic 
14541238Sbostic 	if(gold == fgold) fgold = gold->ngold;
14641238Sbostic 	else {
14741238Sbostic 		for(gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
14841238Sbostic 			if(!gtmp) panic("error in freegold");
14941238Sbostic 		gtmp->ngold = gold->ngold;
15041238Sbostic 	}
15141238Sbostic 	free((char *) gold);
15241238Sbostic }
15341238Sbostic 
deltrap(trap)15441238Sbostic deltrap(trap)
15541238Sbostic register struct trap *trap;
15641238Sbostic {
15741238Sbostic 	register struct trap *ttmp;
15841238Sbostic 
15941238Sbostic 	if(trap == ftrap)
16041238Sbostic 		ftrap = ftrap->ntrap;
16141238Sbostic 	else {
16241238Sbostic 		for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
16341238Sbostic 		ttmp->ntrap = trap->ntrap;
16441238Sbostic 	}
16541238Sbostic 	free((char *) trap);
16641238Sbostic }
16741238Sbostic 
16841238Sbostic struct wseg *m_atseg;
16941238Sbostic 
17041238Sbostic struct monst *
m_at(x,y)17141238Sbostic m_at(x,y)
17241238Sbostic register x,y;
17341238Sbostic {
17441238Sbostic 	register struct monst *mtmp;
17541238Sbostic #ifndef NOWORM
17641238Sbostic 	register struct wseg *wtmp;
17741238Sbostic #endif NOWORM
17841238Sbostic 
17941238Sbostic 	m_atseg = 0;
18041238Sbostic 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
18141238Sbostic 		if(mtmp->mx == x && mtmp->my == y)
18241238Sbostic 			return(mtmp);
18341238Sbostic #ifndef NOWORM
18441238Sbostic 		if(mtmp->wormno){
18541238Sbostic 		    for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
18641238Sbostic 		    if(wtmp->wx == x && wtmp->wy == y){
18741238Sbostic 			m_atseg = wtmp;
18841238Sbostic 			return(mtmp);
18941238Sbostic 		    }
19041238Sbostic 		}
19141238Sbostic #endif NOWORM
19241238Sbostic 	}
19341238Sbostic 	return(0);
19441238Sbostic }
19541238Sbostic 
19641238Sbostic struct obj *
o_at(x,y)19741238Sbostic o_at(x,y)
19841238Sbostic register x,y;
19941238Sbostic {
20041238Sbostic 	register struct obj *otmp;
20141238Sbostic 
20241238Sbostic 	for(otmp = fobj; otmp; otmp = otmp->nobj)
20341238Sbostic 		if(otmp->ox == x && otmp->oy == y) return(otmp);
20441238Sbostic 	return(0);
20541238Sbostic }
20641238Sbostic 
20741238Sbostic struct obj *
sobj_at(n,x,y)20841238Sbostic sobj_at(n,x,y)
20941238Sbostic register n,x,y;
21041238Sbostic {
21141238Sbostic 	register struct obj *otmp;
21241238Sbostic 
21341238Sbostic 	for(otmp = fobj; otmp; otmp = otmp->nobj)
21441238Sbostic 		if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
21541238Sbostic 			return(otmp);
21641238Sbostic 	return(0);
21741238Sbostic }
21841238Sbostic 
carried(obj)21941238Sbostic carried(obj) register struct obj *obj; {
22041238Sbostic register struct obj *otmp;
22141238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj)
22241238Sbostic 		if(otmp == obj) return(1);
22341238Sbostic 	return(0);
22441238Sbostic }
22541238Sbostic 
carrying(type)22641238Sbostic carrying(type)
22741238Sbostic register int type;
22841238Sbostic {
22941238Sbostic 	register struct obj *otmp;
23041238Sbostic 
23141238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj)
23241238Sbostic 		if(otmp->otyp == type)
23341238Sbostic 			return(TRUE);
23441238Sbostic 	return(FALSE);
23541238Sbostic }
23641238Sbostic 
23741238Sbostic struct obj *
o_on(id,objchn)23841238Sbostic o_on(id, objchn) unsigned int id; register struct obj *objchn; {
23941238Sbostic 	while(objchn) {
24041238Sbostic 		if(objchn->o_id == id) return(objchn);
24141238Sbostic 		objchn = objchn->nobj;
24241238Sbostic 	}
24341238Sbostic 	return((struct obj *) 0);
24441238Sbostic }
24541238Sbostic 
24641238Sbostic struct trap *
t_at(x,y)24741238Sbostic t_at(x,y)
24841238Sbostic register x,y;
24941238Sbostic {
25041238Sbostic 	register struct trap *trap = ftrap;
25141238Sbostic 	while(trap) {
25241238Sbostic 		if(trap->tx == x && trap->ty == y) return(trap);
25341238Sbostic 		trap = trap->ntrap;
25441238Sbostic 	}
25541238Sbostic 	return(0);
25641238Sbostic }
25741238Sbostic 
25841238Sbostic struct gold *
g_at(x,y)25941238Sbostic g_at(x,y)
26041238Sbostic register x,y;
26141238Sbostic {
26241238Sbostic 	register struct gold *gold = fgold;
26341238Sbostic 	while(gold) {
26441238Sbostic 		if(gold->gx == x && gold->gy == y) return(gold);
26541238Sbostic 		gold = gold->ngold;
26641238Sbostic 	}
26741238Sbostic 	return(0);
26841238Sbostic }
26941238Sbostic 
27041238Sbostic /* make dummy object structure containing gold - for temporary use only */
27141238Sbostic struct obj *
mkgoldobj(q)27241238Sbostic mkgoldobj(q)
27341238Sbostic register long q;
27441238Sbostic {
27541238Sbostic 	register struct obj *otmp;
27641238Sbostic 
27741238Sbostic 	otmp = newobj(0);
27841238Sbostic 	/* should set o_id etc. but otmp will be freed soon */
27941238Sbostic 	otmp->olet = '$';
28041238Sbostic 	u.ugold -= q;
28141238Sbostic 	OGOLD(otmp) = q;
28241238Sbostic 	flags.botl = 1;
28341238Sbostic 	return(otmp);
28441238Sbostic }
28541238Sbostic 
28641238Sbostic /*
28741238Sbostic  * getobj returns:
28841238Sbostic  *	struct obj *xxx:	object to do something with.
28941238Sbostic  *	(struct obj *) 0	error return: no object.
29041238Sbostic  *	&zeroobj		explicitly no object (as in w-).
29141238Sbostic  */
29241238Sbostic struct obj *
getobj(let,word)29341238Sbostic getobj(let,word)
29441238Sbostic register char *let,*word;
29541238Sbostic {
29641238Sbostic 	register struct obj *otmp;
29741238Sbostic 	register char ilet,ilet1,ilet2;
29841238Sbostic 	char buf[BUFSZ];
29941238Sbostic 	char lets[BUFSZ];
30041238Sbostic 	register int foo = 0, foo2;
30141238Sbostic 	register char *bp = buf;
30241238Sbostic 	xchar allowcnt = 0;	/* 0, 1 or 2 */
30341238Sbostic 	boolean allowgold = FALSE;
30441238Sbostic 	boolean allowall = FALSE;
30541238Sbostic 	boolean allownone = FALSE;
30641238Sbostic 	xchar foox = 0;
30741238Sbostic 	long cnt;
30841238Sbostic 
30941238Sbostic 	if(*let == '0') let++, allowcnt = 1;
31041238Sbostic 	if(*let == '$') let++, allowgold = TRUE;
31141238Sbostic 	if(*let == '#') let++, allowall = TRUE;
31241238Sbostic 	if(*let == '-') let++, allownone = TRUE;
31341238Sbostic 	if(allownone) *bp++ = '-';
31441238Sbostic 	if(allowgold) *bp++ = '$';
31541238Sbostic 	if(bp > buf && bp[-1] == '-') *bp++ = ' ';
31641238Sbostic 
31741238Sbostic 	ilet = 'a';
31841238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj){
31941238Sbostic 	    if(!*let || index(let, otmp->olet)) {
32041238Sbostic 		bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
32141238Sbostic 
32241238Sbostic 		/* ugly check: remove inappropriate things */
32341238Sbostic 		if((!strcmp(word, "take off") &&
32441238Sbostic 		    !(otmp->owornmask & (W_ARMOR - W_ARM2)))
32541238Sbostic 		|| (!strcmp(word, "wear") &&
32641238Sbostic 		    (otmp->owornmask & (W_ARMOR | W_RING)))
32741238Sbostic 		|| (!strcmp(word, "wield") &&
32841238Sbostic 		    (otmp->owornmask & W_WEP))) {
32941238Sbostic 			foo--;
33041238Sbostic 			foox++;
33141238Sbostic 		}
33241238Sbostic 	    }
33341238Sbostic 	    if(ilet == 'z') ilet = 'A'; else ilet++;
33441238Sbostic 	}
33541238Sbostic 	bp[foo] = 0;
33641238Sbostic 	if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
33741238Sbostic 	(void) strcpy(lets, bp);	/* necessary since we destroy buf */
33841238Sbostic 	if(foo > 5) {			/* compactify string */
33941238Sbostic 		foo = foo2 = 1;
34041238Sbostic 		ilet2 = bp[0];
34141238Sbostic 		ilet1 = bp[1];
34241238Sbostic 		while(ilet = bp[++foo2] = bp[++foo]){
34341238Sbostic 			if(ilet == ilet1+1){
34441238Sbostic 				if(ilet1 == ilet2+1)
34541238Sbostic 					bp[foo2 - 1] = ilet1 = '-';
34641238Sbostic 				else if(ilet2 == '-') {
34741238Sbostic 					bp[--foo2] = ++ilet1;
34841238Sbostic 					continue;
34941238Sbostic 				}
35041238Sbostic 			}
35141238Sbostic 			ilet2 = ilet1;
35241238Sbostic 			ilet1 = ilet;
35341238Sbostic 		}
35441238Sbostic 	}
35541238Sbostic 	if(!foo && !allowall && !allowgold && !allownone) {
35641238Sbostic 		pline("You don't have anything %sto %s.",
35741238Sbostic 			foox ? "else " : "", word);
35841238Sbostic 		return(0);
35941238Sbostic 	}
36041238Sbostic 	for(;;) {
36141238Sbostic 		if(!buf[0])
36241238Sbostic 			pline("What do you want to %s [*]? ", word);
36341238Sbostic 		else
36441238Sbostic 			pline("What do you want to %s [%s or ?*]? ",
36541238Sbostic 				word, buf);
36641238Sbostic 
36741238Sbostic 		cnt = 0;
36841238Sbostic 		ilet = readchar();
36941238Sbostic 		while(digit(ilet) && allowcnt) {
37041238Sbostic 			if (cnt < 100000000)
37141238Sbostic 			    cnt = 10*cnt + (ilet - '0');
37241238Sbostic 			else
37341238Sbostic 			    cnt = 999999999;
37441238Sbostic 			allowcnt = 2;	/* signal presence of cnt */
37541238Sbostic 			ilet = readchar();
37641238Sbostic 		}
37741238Sbostic 		if(digit(ilet)) {
37841238Sbostic 			pline("No count allowed with this command.");
37941238Sbostic 			continue;
38041238Sbostic 		}
38141238Sbostic 		if(index(quitchars,ilet))
38241238Sbostic 			return((struct obj *)0);
38341238Sbostic 		if(ilet == '-') {
38441238Sbostic 			return(allownone ? &zeroobj : (struct obj *) 0);
38541238Sbostic 		}
38641238Sbostic 		if(ilet == '$') {
38741238Sbostic 			if(!allowgold){
38841238Sbostic 				pline("You cannot %s gold.", word);
38941238Sbostic 				continue;
39041238Sbostic 			}
39141238Sbostic 			if(!(allowcnt == 2 && cnt < u.ugold))
39241238Sbostic 				cnt = u.ugold;
39341238Sbostic 			return(mkgoldobj(cnt));
39441238Sbostic 		}
39541238Sbostic 		if(ilet == '?') {
39641238Sbostic 			doinv(lets);
39741238Sbostic 			if(!(ilet = morc)) continue;
39841238Sbostic 			/* he typed a letter (not a space) to more() */
39941238Sbostic 		} else if(ilet == '*') {
40041238Sbostic 			doinv((char *) 0);
40141238Sbostic 			if(!(ilet = morc)) continue;
40241238Sbostic 			/* ... */
40341238Sbostic 		}
40441238Sbostic 		if(flags.invlet_constant) {
40541238Sbostic 			for(otmp = invent; otmp; otmp = otmp->nobj)
40641238Sbostic 				if(otmp->invlet == ilet) break;
40741238Sbostic 		} else {
40841238Sbostic 			if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
40941238Sbostic 			ilet -= 'a';
41041238Sbostic 			for(otmp = invent; otmp && ilet;
41141238Sbostic 					ilet--, otmp = otmp->nobj) ;
41241238Sbostic 		}
41341238Sbostic 		if(!otmp) {
41441238Sbostic 			pline("You don't have that object.");
41541238Sbostic 			continue;
41641238Sbostic 		}
41741238Sbostic 		if(cnt < 0 || otmp->quan < cnt) {
41841238Sbostic 			pline("You don't have that many! [You have %u]"
41941238Sbostic 			, otmp->quan);
42041238Sbostic 			continue;
42141238Sbostic 		}
42241238Sbostic 		break;
42341238Sbostic 	}
42441238Sbostic 	if(!allowall && let && !index(let,otmp->olet)) {
42541238Sbostic 		pline("That is a silly thing to %s.",word);
42641238Sbostic 		return(0);
42741238Sbostic 	}
42841238Sbostic 	if(allowcnt == 2) {	/* cnt given */
42941238Sbostic 		if(cnt == 0) return(0);
43041238Sbostic 		if(cnt != otmp->quan) {
43141238Sbostic 			register struct obj *obj;
43241238Sbostic 			obj = splitobj(otmp, (int) cnt);
43341238Sbostic 			if(otmp == uwep) setuwep(obj);
43441238Sbostic 		}
43541238Sbostic 	}
43641238Sbostic 	return(otmp);
43741238Sbostic }
43841238Sbostic 
ckunpaid(otmp)43941238Sbostic ckunpaid(otmp) register struct obj *otmp; {
44041238Sbostic 	return( otmp->unpaid );
44141238Sbostic }
44241238Sbostic 
44341238Sbostic /* interactive version of getobj - used for Drop and Identify */
44441238Sbostic /* return the number of times fn was called successfully */
ggetobj(word,fn,max)44541238Sbostic ggetobj(word, fn, max)
44641238Sbostic char *word;
44741238Sbostic int (*fn)(),  max;
44841238Sbostic {
44941238Sbostic char buf[BUFSZ];
45041238Sbostic register char *ip;
45141238Sbostic register char sym;
45241238Sbostic register int oletct = 0, iletct = 0;
45341238Sbostic register boolean allflag = FALSE;
45441238Sbostic char olets[20], ilets[20];
45541238Sbostic int (*ckfn)() = (int (*)()) 0;
45641238Sbostic xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;	/* BAH */
45741238Sbostic 	if(!invent && !allowgold){
45841238Sbostic 		pline("You have nothing to %s.", word);
45941238Sbostic 		return(0);
46041238Sbostic 	} else {
46141238Sbostic 		register struct obj *otmp = invent;
46241238Sbostic 		register int uflg = 0;
46341238Sbostic 
46441238Sbostic 		if(allowgold) ilets[iletct++] = '$';
46541238Sbostic 		ilets[iletct] = 0;
46641238Sbostic 		while(otmp) {
46741238Sbostic 			if(!index(ilets, otmp->olet)){
46841238Sbostic 				ilets[iletct++] = otmp->olet;
46941238Sbostic 				ilets[iletct] = 0;
47041238Sbostic 			}
47141238Sbostic 			if(otmp->unpaid) uflg = 1;
47241238Sbostic 			otmp = otmp->nobj;
47341238Sbostic 		}
47441238Sbostic 		ilets[iletct++] = ' ';
47541238Sbostic 		if(uflg) ilets[iletct++] = 'u';
47641238Sbostic 		if(invent) ilets[iletct++] = 'a';
47741238Sbostic 		ilets[iletct] = 0;
47841238Sbostic 	}
47941238Sbostic 	pline("What kinds of thing do you want to %s? [%s] ",
48041238Sbostic 		word, ilets);
48141238Sbostic 	getlin(buf);
48241238Sbostic 	if(buf[0] == '\033') {
48341238Sbostic 		clrlin();
48441238Sbostic 		return(0);
48541238Sbostic 	}
48641238Sbostic 	ip = buf;
48741238Sbostic 	olets[0] = 0;
48841238Sbostic 	while(sym = *ip++){
48941238Sbostic 		if(sym == ' ') continue;
49041238Sbostic 		if(sym == '$') {
49141238Sbostic 			if(allowgold == 1)
49241238Sbostic 				(*fn)(mkgoldobj(u.ugold));
49341238Sbostic 			else if(!u.ugold)
49441238Sbostic 				pline("You have no gold.");
49541238Sbostic 			allowgold = 2;
49641238Sbostic 		} else
49741238Sbostic 		if(sym == 'a' || sym == 'A') allflag = TRUE; else
49841238Sbostic 		if(sym == 'u' || sym == 'U') ckfn = ckunpaid; else
49941238Sbostic 		if(index("!%?[()=*/\"0", sym)){
50041238Sbostic 			if(!index(olets, sym)){
50141238Sbostic 				olets[oletct++] = sym;
50241238Sbostic 				olets[oletct] = 0;
50341238Sbostic 			}
50441238Sbostic 		}
50541238Sbostic 		else pline("You don't have any %c's.", sym);
50641238Sbostic 	}
50741238Sbostic 	if(allowgold == 2 && !oletct)
50841238Sbostic 		return(1);	/* he dropped gold (or at least tried to) */
50941238Sbostic 	else
51041238Sbostic 		return(askchain(invent, olets, allflag, fn, ckfn, max));
51141238Sbostic }
51241238Sbostic 
51341238Sbostic /*
51441238Sbostic  * Walk through the chain starting at objchn and ask for all objects
51541238Sbostic  * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
51641238Sbostic  * whether the action in question (i.e., fn) has to be performed.
51741238Sbostic  * If allflag then no questions are asked. Max gives the max nr of
51841238Sbostic  * objects to be treated. Return the number of objects treated.
51941238Sbostic  */
52041238Sbostic askchain(objchn, olets, allflag, fn, ckfn, max)
52141238Sbostic struct obj *objchn;
52241238Sbostic register char *olets;
52341238Sbostic int allflag;
52441238Sbostic int (*fn)(), (*ckfn)();
52541238Sbostic int max;
52641238Sbostic {
52741238Sbostic register struct obj *otmp, *otmp2;
52841238Sbostic register char sym, ilet;
52941238Sbostic register int cnt = 0;
53041238Sbostic 	ilet = 'a'-1;
53141238Sbostic 	for(otmp = objchn; otmp; otmp = otmp2){
53241238Sbostic 		if(ilet == 'z') ilet = 'A'; else ilet++;
53341238Sbostic 		otmp2 = otmp->nobj;
53441238Sbostic 		if(olets && *olets && !index(olets, otmp->olet)) continue;
53541238Sbostic 		if(ckfn && !(*ckfn)(otmp)) continue;
53641238Sbostic 		if(!allflag) {
53741238Sbostic 			pline(xprname(otmp, ilet));
53841238Sbostic 			addtopl(" [nyaq]? ");
53941238Sbostic 			sym = readchar();
54041238Sbostic 		}
54141238Sbostic 		else	sym = 'y';
54241238Sbostic 
54341238Sbostic 		switch(sym){
54441238Sbostic 		case 'a':
54541238Sbostic 			allflag = 1;
54641238Sbostic 		case 'y':
54741238Sbostic 			cnt += (*fn)(otmp);
54841238Sbostic 			if(--max == 0) goto ret;
54941238Sbostic 		case 'n':
55041238Sbostic 		default:
55141238Sbostic 			break;
55241238Sbostic 		case 'q':
55341238Sbostic 			goto ret;
55441238Sbostic 		}
55541238Sbostic 	}
55641238Sbostic 	pline(cnt ? "That was all." : "No applicable objects.");
55741238Sbostic ret:
55841238Sbostic 	return(cnt);
55941238Sbostic }
56041238Sbostic 
obj_to_let(obj)56141238Sbostic obj_to_let(obj)	/* should of course only be called for things in invent */
56241238Sbostic register struct obj *obj;
56341238Sbostic {
56441238Sbostic 	register struct obj *otmp;
56541238Sbostic 	register char ilet;
56641238Sbostic 
56741238Sbostic 	if(flags.invlet_constant)
56841238Sbostic 		return(obj->invlet);
56941238Sbostic 	ilet = 'a';
57041238Sbostic 	for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
57141238Sbostic 		if(++ilet > 'z') ilet = 'A';
57241238Sbostic 	return(otmp ? ilet : NOINVSYM);
57341238Sbostic }
57441238Sbostic 
prinv(obj)57541238Sbostic prinv(obj)
57641238Sbostic register struct obj *obj;
57741238Sbostic {
57841238Sbostic 	pline(xprname(obj, obj_to_let(obj)));
57941238Sbostic }
58041238Sbostic 
58141238Sbostic static char *
xprname(obj,let)58241238Sbostic xprname(obj,let)
58341238Sbostic register struct obj *obj;
58441238Sbostic register char let;
58541238Sbostic {
58641238Sbostic 	static char li[BUFSZ];
58741238Sbostic 
58841238Sbostic 	(void) sprintf(li, "%c - %s.",
58941238Sbostic 		flags.invlet_constant ? obj->invlet : let,
59041238Sbostic 		doname(obj));
59141238Sbostic 	return(li);
59241238Sbostic }
59341238Sbostic 
ddoinv()59441238Sbostic ddoinv()
59541238Sbostic {
59641238Sbostic 	doinv((char *) 0);
59741238Sbostic 	return(0);
59841238Sbostic }
59941238Sbostic 
60041238Sbostic /* called with 0 or "": all objects in inventory */
60141238Sbostic /* otherwise: all objects with (serial) letter in lets */
doinv(lets)60241238Sbostic doinv(lets)
60341238Sbostic register char *lets;
60441238Sbostic {
60541238Sbostic 	register struct obj *otmp;
60641238Sbostic 	register char ilet;
60741238Sbostic 	int ct = 0;
60841238Sbostic 	char any[BUFSZ];
60941238Sbostic 
61041238Sbostic 	morc = 0;		/* just to be sure */
61141238Sbostic 
61241238Sbostic 	if(!invent){
61341238Sbostic 		pline("Not carrying anything.");
61441238Sbostic 		return;
61541238Sbostic 	}
61641238Sbostic 
61741238Sbostic 	cornline(0, (char *) 0);
61841238Sbostic 	ilet = 'a';
61941238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj) {
62041238Sbostic 	    if(flags.invlet_constant) ilet = otmp->invlet;
62141238Sbostic 	    if(!lets || !*lets || index(lets, ilet)) {
62241238Sbostic 		    cornline(1, xprname(otmp, ilet));
62341238Sbostic 		    any[ct++] = ilet;
62441238Sbostic 	    }
62541238Sbostic 	    if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
62641238Sbostic 	}
62741238Sbostic 	any[ct] = 0;
62841238Sbostic 	cornline(2, any);
62941238Sbostic }
63041238Sbostic 
dotypeinv()63141238Sbostic dotypeinv ()				/* free after Robert Viduya */
63241238Sbostic /* Changed to one type only, so he doesnt have to type cr */
63341238Sbostic {
63441238Sbostic     char c, ilet;
63541238Sbostic     char stuff[BUFSZ];
63641238Sbostic     register int stct;
63741238Sbostic     register struct obj *otmp;
63841238Sbostic     boolean billx = inshop() && doinvbill(0);
63941238Sbostic     boolean unpd = FALSE;
64041238Sbostic 
64141238Sbostic 	if (!invent && !u.ugold && !billx) {
64241238Sbostic 	    pline ("You aren't carrying anything.");
64341238Sbostic 	    return(0);
64441238Sbostic 	}
64541238Sbostic 
64641238Sbostic 	stct = 0;
64741238Sbostic 	if(u.ugold) stuff[stct++] = '$';
64841238Sbostic 	stuff[stct] = 0;
64941238Sbostic 	for(otmp = invent; otmp; otmp = otmp->nobj) {
65041238Sbostic 	    if (!index (stuff, otmp->olet)) {
65141238Sbostic 		stuff[stct++] = otmp->olet;
65241238Sbostic 		stuff[stct] = 0;
65341238Sbostic 	    }
65441238Sbostic 	    if(otmp->unpaid)
65541238Sbostic 		unpd = TRUE;
65641238Sbostic 	}
65741238Sbostic 	if(unpd) stuff[stct++] = 'u';
65841238Sbostic 	if(billx) stuff[stct++] = 'x';
65941238Sbostic 	stuff[stct] = 0;
66041238Sbostic 
66141238Sbostic 	if(stct > 1) {
66241238Sbostic 	    pline ("What type of object [%s] do you want an inventory of? ",
66341238Sbostic 		stuff);
66441238Sbostic 	    c = readchar();
66541238Sbostic 	    if(index(quitchars,c)) return(0);
66641238Sbostic 	} else
66741238Sbostic 	    c = stuff[0];
66841238Sbostic 
66941238Sbostic 	if(c == '$')
67041238Sbostic 	    return(doprgold());
67141238Sbostic 
67241238Sbostic 	if(c == 'x' || c == 'X') {
67341238Sbostic 	    if(billx)
67441238Sbostic 		(void) doinvbill(1);
67541238Sbostic 	    else
67641238Sbostic 		pline("No used-up objects on the shopping bill.");
67741238Sbostic 	    return(0);
67841238Sbostic 	}
67941238Sbostic 
68041238Sbostic 	if((c == 'u' || c == 'U') && !unpd) {
68141238Sbostic 		pline("You are not carrying any unpaid objects.");
68241238Sbostic 		return(0);
68341238Sbostic 	}
68441238Sbostic 
68541238Sbostic 	stct = 0;
68641238Sbostic 	ilet = 'a';
68741238Sbostic 	for (otmp = invent; otmp; otmp = otmp -> nobj) {
68841238Sbostic 	    if(flags.invlet_constant) ilet = otmp->invlet;
68941238Sbostic 	    if (c == otmp -> olet || (c == 'u' && otmp -> unpaid))
69041238Sbostic 		stuff[stct++] = ilet;
69141238Sbostic 	    if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
69241238Sbostic 	}
69341238Sbostic 	stuff[stct] = '\0';
69441238Sbostic 	if(stct == 0)
69541238Sbostic 		pline("You have no such objects.");
69641238Sbostic 	else
69741238Sbostic 		doinv (stuff);
69841238Sbostic 
69941238Sbostic 	return(0);
70041238Sbostic }
70141238Sbostic 
70241238Sbostic /* look at what is here */
dolook()70341238Sbostic dolook() {
70441238Sbostic     register struct obj *otmp, *otmp0;
70541238Sbostic     register struct gold *gold;
70641238Sbostic     char *verb = Blind ? "feel" : "see";
70741238Sbostic     int	ct = 0;
70841238Sbostic 
70941238Sbostic     if(!u.uswallow) {
71041238Sbostic 	if(Blind) {
71141238Sbostic 	    pline("You try to feel what is lying here on the floor.");
71241238Sbostic 	    if(Levitation) {				/* ab@unido */
71341238Sbostic 		pline("You cannot reach the floor!");
71441238Sbostic 		return(1);
71541238Sbostic 	    }
71641238Sbostic 	}
71741238Sbostic 	otmp0 = o_at(u.ux, u.uy);
71841238Sbostic 	gold = g_at(u.ux, u.uy);
71941238Sbostic     }
72041238Sbostic 
72141238Sbostic     if(u.uswallow || (!otmp0 && !gold)) {
72241238Sbostic 	pline("You %s no objects here.", verb);
72341238Sbostic 	return(!!Blind);
72441238Sbostic     }
72541238Sbostic 
72641238Sbostic     cornline(0, "Things that are here:");
72741238Sbostic     for(otmp = otmp0; otmp; otmp = otmp->nobj) {
72841238Sbostic 	if(otmp->ox == u.ux && otmp->oy == u.uy) {
72941238Sbostic 	    ct++;
73041238Sbostic 	    cornline(1, doname(otmp));
73141238Sbostic 	    if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
73241238Sbostic 		pline("Touching the dead cockatrice is a fatal mistake ...");
73341238Sbostic 		pline("You die ...");
73441238Sbostic 		killer = "dead cockatrice";
73541238Sbostic 		done("died");
73641238Sbostic 	    }
73741238Sbostic 	}
73841238Sbostic     }
73941238Sbostic 
74041238Sbostic     if(gold) {
74141238Sbostic 	char gbuf[30];
74241238Sbostic 
74341238Sbostic 	(void) sprintf(gbuf, "%ld gold piece%s",
74441238Sbostic 		gold->amount, plur(gold->amount));
74541238Sbostic 	if(!ct++)
74641238Sbostic 	    pline("You %s here %s.", verb, gbuf);
74741238Sbostic 	else
74841238Sbostic 	    cornline(1, gbuf);
74941238Sbostic     }
75041238Sbostic 
75141238Sbostic     if(ct == 1 && !gold) {
75241238Sbostic 	pline("You %s here %s.", verb, doname(otmp0));
75341238Sbostic 	cornline(3, (char *) 0);
75441238Sbostic     }
75541238Sbostic     if(ct > 1)
75641238Sbostic 	cornline(2, (char *) 0);
75741238Sbostic     return(!!Blind);
75841238Sbostic }
75941238Sbostic 
stackobj(obj)76041238Sbostic stackobj(obj) register struct obj *obj; {
76141238Sbostic register struct obj *otmp = fobj;
76241238Sbostic 	for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
76341238Sbostic 	if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
76441238Sbostic 		merged(obj,otmp,1))
76541238Sbostic 			return;
76641238Sbostic }
76741238Sbostic 
76841238Sbostic /* merge obj with otmp and delete obj if types agree */
merged(otmp,obj,lose)76941238Sbostic merged(otmp,obj,lose) register struct obj *otmp, *obj; {
77041238Sbostic 	if(obj->otyp == otmp->otyp &&
77141238Sbostic 	  obj->unpaid == otmp->unpaid &&
77241238Sbostic 	  obj->spe == otmp->spe &&
77341238Sbostic 	  obj->dknown == otmp->dknown &&
77441238Sbostic 	  obj->cursed == otmp->cursed &&
77541238Sbostic 	  (index("%*?!", obj->olet) ||
77641238Sbostic 	    (obj->known == otmp->known &&
77741238Sbostic 		(obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
77841238Sbostic 		otmp->quan += obj->quan;
77941238Sbostic 		otmp->owt += obj->owt;
78041238Sbostic 		if(lose) freeobj(obj);
78141238Sbostic 		obfree(obj,otmp);	/* free(obj), bill->otmp */
78241238Sbostic 		return(1);
78341238Sbostic 	} else	return(0);
78441238Sbostic }
78541238Sbostic 
78641238Sbostic /*
78741238Sbostic  * Gold is no longer displayed; in fact, when you have a lot of money,
78841238Sbostic  * it may take a while before you have counted it all.
78941238Sbostic  * [Bug: d$ and pickup still tell you how much it was.]
79041238Sbostic  */
79141238Sbostic extern int (*occupation)();
79241238Sbostic extern char *occtxt;
79341238Sbostic static long goldcounted;
79441238Sbostic 
countgold()79541238Sbostic countgold(){
79641238Sbostic 	if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) {
79741238Sbostic 		long eps = 0;
79841238Sbostic 		if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1));
79941238Sbostic 		pline("You probably have about %ld gold pieces.",
80041238Sbostic 			u.ugold + eps);
80141238Sbostic 		return(0);	/* done */
80241238Sbostic 	}
80341238Sbostic 	return(1);		/* continue */
80441238Sbostic }
80541238Sbostic 
doprgold()80641238Sbostic doprgold(){
80741238Sbostic 	if(!u.ugold)
80841238Sbostic 		pline("You do not carry any gold.");
80941238Sbostic 	else if(u.ugold <= 500)
81041238Sbostic 		pline("You are carrying %ld gold pieces.", u.ugold);
81141238Sbostic 	else {
81241238Sbostic 		pline("You sit down in order to count your gold pieces.");
81341238Sbostic 		goldcounted = 500;
81441238Sbostic 		occupation = countgold;
81541238Sbostic 		occtxt = "counting your gold";
81641238Sbostic 	}
81741238Sbostic 	return(1);
81841238Sbostic }
81941238Sbostic 
82041238Sbostic /* --- end of gold counting section --- */
82141238Sbostic 
doprwep()82241238Sbostic doprwep(){
82341238Sbostic 	if(!uwep) pline("You are empty handed.");
82441238Sbostic 	else prinv(uwep);
82541238Sbostic 	return(0);
82641238Sbostic }
82741238Sbostic 
doprarm()82841238Sbostic doprarm(){
82941238Sbostic 	if(!uarm && !uarmg && !uarms && !uarmh)
83041238Sbostic 		pline("You are not wearing any armor.");
83141238Sbostic 	else {
83241238Sbostic 		char lets[6];
83341238Sbostic 		register int ct = 0;
83441238Sbostic 
83541238Sbostic 		if(uarm) lets[ct++] = obj_to_let(uarm);
83641238Sbostic 		if(uarm2) lets[ct++] = obj_to_let(uarm2);
83741238Sbostic 		if(uarmh) lets[ct++] = obj_to_let(uarmh);
83841238Sbostic 		if(uarms) lets[ct++] = obj_to_let(uarms);
83941238Sbostic 		if(uarmg) lets[ct++] = obj_to_let(uarmg);
84041238Sbostic 		lets[ct] = 0;
84141238Sbostic 		doinv(lets);
84241238Sbostic 	}
84341238Sbostic 	return(0);
84441238Sbostic }
84541238Sbostic 
doprring()84641238Sbostic doprring(){
84741238Sbostic 	if(!uleft && !uright)
84841238Sbostic 		pline("You are not wearing any rings.");
84941238Sbostic 	else {
85041238Sbostic 		char lets[3];
85141238Sbostic 		register int ct = 0;
85241238Sbostic 
85341238Sbostic 		if(uleft) lets[ct++] = obj_to_let(uleft);
85441238Sbostic 		if(uright) lets[ct++] = obj_to_let(uright);
85541238Sbostic 		lets[ct] = 0;
85641238Sbostic 		doinv(lets);
85741238Sbostic 	}
85841238Sbostic 	return(0);
85941238Sbostic }
86041238Sbostic 
digit(c)86141238Sbostic digit(c) char c; {
86241238Sbostic 	return(c >= '0' && c <= '9');
86341238Sbostic }
864