xref: /netbsd-src/games/hack/hack.invent.c (revision d5b021c7edb8313eee3804ec3819b28abef1d1a0)
1*d5b021c7Sdholland /*	$NetBSD: hack.invent.c,v 1.18 2011/08/07 06:03:45 dholland Exp $	*/
23ea4a95cSchristos 
302ded532Smycroft /*
41c7f94e5Sjsm  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
51c7f94e5Sjsm  * Amsterdam
61c7f94e5Sjsm  * All rights reserved.
71c7f94e5Sjsm  *
81c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
91c7f94e5Sjsm  * modification, are permitted provided that the following conditions are
101c7f94e5Sjsm  * met:
111c7f94e5Sjsm  *
121c7f94e5Sjsm  * - Redistributions of source code must retain the above copyright notice,
131c7f94e5Sjsm  * this list of conditions and the following disclaimer.
141c7f94e5Sjsm  *
151c7f94e5Sjsm  * - Redistributions in binary form must reproduce the above copyright
161c7f94e5Sjsm  * notice, this list of conditions and the following disclaimer in the
171c7f94e5Sjsm  * documentation and/or other materials provided with the distribution.
181c7f94e5Sjsm  *
191c7f94e5Sjsm  * - Neither the name of the Stichting Centrum voor Wiskunde en
201c7f94e5Sjsm  * Informatica, nor the names of its contributors may be used to endorse or
211c7f94e5Sjsm  * promote products derived from this software without specific prior
221c7f94e5Sjsm  * written permission.
231c7f94e5Sjsm  *
241c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
251c7f94e5Sjsm  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
261c7f94e5Sjsm  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
271c7f94e5Sjsm  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
281c7f94e5Sjsm  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
291c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
301c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
311c7f94e5Sjsm  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
321c7f94e5Sjsm  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
331c7f94e5Sjsm  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
341c7f94e5Sjsm  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
351c7f94e5Sjsm  */
361c7f94e5Sjsm 
371c7f94e5Sjsm /*
381c7f94e5Sjsm  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
391c7f94e5Sjsm  * All rights reserved.
401c7f94e5Sjsm  *
411c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
421c7f94e5Sjsm  * modification, are permitted provided that the following conditions
431c7f94e5Sjsm  * are met:
441c7f94e5Sjsm  * 1. Redistributions of source code must retain the above copyright
451c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer.
461c7f94e5Sjsm  * 2. Redistributions in binary form must reproduce the above copyright
471c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer in the
481c7f94e5Sjsm  *    documentation and/or other materials provided with the distribution.
491c7f94e5Sjsm  * 3. The name of the author may not be used to endorse or promote products
501c7f94e5Sjsm  *    derived from this software without specific prior written permission.
511c7f94e5Sjsm  *
521c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
531c7f94e5Sjsm  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
541c7f94e5Sjsm  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
551c7f94e5Sjsm  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
561c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
571c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
581c7f94e5Sjsm  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
591c7f94e5Sjsm  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
601c7f94e5Sjsm  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
611c7f94e5Sjsm  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6202ded532Smycroft  */
6302ded532Smycroft 
643ea4a95cSchristos #include <sys/cdefs.h>
6502ded532Smycroft #ifndef lint
66*d5b021c7Sdholland __RCSID("$NetBSD: hack.invent.c,v 1.18 2011/08/07 06:03:45 dholland Exp $");
6702ded532Smycroft #endif				/* not lint */
6861f28255Scgd 
69165c915bSdholland #include <assert.h>
703ea4a95cSchristos #include <stdlib.h>
7161f28255Scgd #include "hack.h"
723ea4a95cSchristos #include "extern.h"
7361f28255Scgd 
7461f28255Scgd #ifndef NOWORM
7561f28255Scgd #include	"def.wseg.h"
763ea4a95cSchristos #endif	/* NOWORM */
7761f28255Scgd 
7861f28255Scgd #define	NOINVSYM	'#'
7961f28255Scgd 
8061f28255Scgd static int      lastinvnr = 51;	/* 0 ... 51 */
813ea4a95cSchristos 
82cb5fd834Sjsm static char *xprname(struct obj *, char);
832c0ecb1aSdholland static void doinv(const char *);
849b92b189Sdholland static int merged(struct obj *, struct obj *, int);
853ea4a95cSchristos 
863ea4a95cSchristos static void
assigninvlet(struct obj * otmp)871fa8a9a6Sdholland assigninvlet(struct obj *otmp)
8861f28255Scgd {
8961f28255Scgd 	boolean         inuse[52];
903ea4a95cSchristos 	int             i;
913ea4a95cSchristos 	struct obj     *obj;
9261f28255Scgd 
933ea4a95cSchristos 	for (i = 0; i < 52; i++)
943ea4a95cSchristos 		inuse[i] = FALSE;
953ea4a95cSchristos 	for (obj = invent; obj; obj = obj->nobj)
963ea4a95cSchristos 		if (obj != otmp) {
9761f28255Scgd 			i = obj->invlet;
983ea4a95cSchristos 			if ('a' <= i && i <= 'z')
993ea4a95cSchristos 				inuse[i - 'a'] = TRUE;
1003ea4a95cSchristos 			else if ('A' <= i && i <= 'Z')
1013ea4a95cSchristos 				inuse[i - 'A' + 26] = TRUE;
1023ea4a95cSchristos 			if (i == otmp->invlet)
1033ea4a95cSchristos 				otmp->invlet = 0;
10461f28255Scgd 		}
10561f28255Scgd 	if ((i = otmp->invlet) &&
10661f28255Scgd 	    (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
10761f28255Scgd 		return;
10861f28255Scgd 	for (i = lastinvnr + 1; i != lastinvnr; i++) {
1093ea4a95cSchristos 		if (i == 52) {
1103ea4a95cSchristos 			i = -1;
1113ea4a95cSchristos 			continue;
1123ea4a95cSchristos 		}
1133ea4a95cSchristos 		if (!inuse[i])
1143ea4a95cSchristos 			break;
11561f28255Scgd 	}
11661f28255Scgd 	otmp->invlet = (inuse[i] ? NOINVSYM :
11761f28255Scgd 			(i < 26) ? ('a' + i) : ('A' + i - 26));
11861f28255Scgd 	lastinvnr = i;
11961f28255Scgd }
12061f28255Scgd 
12161f28255Scgd struct obj     *
addinv(struct obj * obj)1221fa8a9a6Sdholland addinv(struct obj *obj)
12361f28255Scgd {
1243ea4a95cSchristos 	struct obj     *otmp;
12561f28255Scgd 
12661f28255Scgd 	/* merge or attach to end of chain */
12761f28255Scgd 	if (!invent) {
12861f28255Scgd 		invent = obj;
12961f28255Scgd 		otmp = 0;
13061f28255Scgd 	} else
13161f28255Scgd 		for (otmp = invent; /* otmp */ ; otmp = otmp->nobj) {
13261f28255Scgd 			if (merged(otmp, obj, 0))
13361f28255Scgd 				return (otmp);
13461f28255Scgd 			if (!otmp->nobj) {
13561f28255Scgd 				otmp->nobj = obj;
13661f28255Scgd 				break;
13761f28255Scgd 			}
13861f28255Scgd 		}
13961f28255Scgd 	obj->nobj = 0;
14061f28255Scgd 
14161f28255Scgd 	if (flags.invlet_constant) {
14261f28255Scgd 		assigninvlet(obj);
14361f28255Scgd 		/*
14461f28255Scgd 		 * The ordering of the chain is nowhere significant
14561f28255Scgd 		 * so in case you prefer some other order than the
14661f28255Scgd 		 * historical one, change the code below.
14761f28255Scgd 		 */
14861f28255Scgd 		if (otmp) {	/* find proper place in chain */
14961f28255Scgd 			otmp->nobj = 0;
15061f28255Scgd 			if ((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
15161f28255Scgd 				obj->nobj = invent;
15261f28255Scgd 				invent = obj;
15361f28255Scgd 			} else
15461f28255Scgd 				for (otmp = invent;; otmp = otmp->nobj) {
15561f28255Scgd 					if (!otmp->nobj ||
15661f28255Scgd 					    (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)) {
15761f28255Scgd 						obj->nobj = otmp->nobj;
15861f28255Scgd 						otmp->nobj = obj;
15961f28255Scgd 						break;
16061f28255Scgd 					}
16161f28255Scgd 				}
16261f28255Scgd 		}
16361f28255Scgd 	}
16461f28255Scgd 	return (obj);
16561f28255Scgd }
16661f28255Scgd 
1673ea4a95cSchristos void
useup(struct obj * obj)1681fa8a9a6Sdholland useup(struct obj *obj)
16961f28255Scgd {
17061f28255Scgd 	if (obj->quan > 1) {
17161f28255Scgd 		obj->quan--;
17261f28255Scgd 		obj->owt = weight(obj);
17361f28255Scgd 	} else {
17461f28255Scgd 		setnotworn(obj);
17561f28255Scgd 		freeinv(obj);
17661f28255Scgd 		obfree(obj, (struct obj *) 0);
17761f28255Scgd 	}
17861f28255Scgd }
17961f28255Scgd 
1803ea4a95cSchristos void
freeinv(struct obj * obj)1811fa8a9a6Sdholland freeinv(struct obj *obj)
18261f28255Scgd {
1833ea4a95cSchristos 	struct obj     *otmp;
18461f28255Scgd 
18561f28255Scgd 	if (obj == invent)
18661f28255Scgd 		invent = invent->nobj;
18761f28255Scgd 	else {
18861f28255Scgd 		for (otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
1893ea4a95cSchristos 			if (!otmp->nobj)
1903ea4a95cSchristos 				panic("freeinv");
19161f28255Scgd 		otmp->nobj = obj->nobj;
19261f28255Scgd 	}
19361f28255Scgd }
19461f28255Scgd 
19561f28255Scgd /* destroy object in fobj chain (if unpaid, it remains on the bill) */
1963ea4a95cSchristos void
delobj(struct obj * obj)1971fa8a9a6Sdholland delobj(struct obj *obj)
1983ea4a95cSchristos {
19961f28255Scgd 	freeobj(obj);
20061f28255Scgd 	unpobj(obj);
20161f28255Scgd 	obfree(obj, (struct obj *) 0);
20261f28255Scgd }
20361f28255Scgd 
20461f28255Scgd /* unlink obj from chain starting with fobj */
2053ea4a95cSchristos void
freeobj(struct obj * obj)2061fa8a9a6Sdholland freeobj(struct obj *obj)
2073ea4a95cSchristos {
2083ea4a95cSchristos 	struct obj     *otmp;
20961f28255Scgd 
2103ea4a95cSchristos 	if (obj == fobj)
2113ea4a95cSchristos 		fobj = fobj->nobj;
21261f28255Scgd 	else {
21383f277c4Sjnemeth 		otmp = fobj;
21483f277c4Sjnemeth 		while (otmp->nobj != obj) {
21583f277c4Sjnemeth 			if (otmp->nobj == NULL)
2163ea4a95cSchristos 				panic("error in freeobj");
21783f277c4Sjnemeth 			otmp = otmp->nobj;
21883f277c4Sjnemeth 		}
21961f28255Scgd 		otmp->nobj = obj->nobj;
22061f28255Scgd 	}
22161f28255Scgd }
22261f28255Scgd 
22361f28255Scgd /* Note: freegold throws away its argument! */
2243ea4a95cSchristos void
freegold(struct gold * gold)2251fa8a9a6Sdholland freegold(struct gold *gold)
2263ea4a95cSchristos {
2273ea4a95cSchristos 	struct gold    *gtmp;
22861f28255Scgd 
2293ea4a95cSchristos 	if (gold == fgold)
2303ea4a95cSchristos 		fgold = gold->ngold;
23161f28255Scgd 	else {
23283f277c4Sjnemeth 		gtmp = fgold;
23383f277c4Sjnemeth 		while (gtmp->ngold != gold) {
23483f277c4Sjnemeth 			if (gtmp->ngold == NULL)
2353ea4a95cSchristos 				panic("error in freegold");
23683f277c4Sjnemeth 			gtmp = gtmp->ngold;
23783f277c4Sjnemeth 		}
23861f28255Scgd 		gtmp->ngold = gold->ngold;
23961f28255Scgd 	}
2408e73b3adSdholland 	free(gold);
24161f28255Scgd }
24261f28255Scgd 
2433ea4a95cSchristos void
deltrap(struct trap * trap)2441fa8a9a6Sdholland deltrap(struct trap *trap)
24561f28255Scgd {
2463ea4a95cSchristos 	struct trap    *ttmp;
24761f28255Scgd 
24861f28255Scgd 	if (trap == ftrap)
24961f28255Scgd 		ftrap = ftrap->ntrap;
25061f28255Scgd 	else {
25161f28255Scgd 		for (ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap);
25261f28255Scgd 		ttmp->ntrap = trap->ntrap;
25361f28255Scgd 	}
2548e73b3adSdholland 	free(trap);
25561f28255Scgd }
25661f28255Scgd 
25761f28255Scgd struct wseg    *m_atseg;
25861f28255Scgd 
25961f28255Scgd struct monst   *
m_at(int x,int y)2601fa8a9a6Sdholland m_at(int x, int y)
26161f28255Scgd {
2623ea4a95cSchristos 	struct monst   *mtmp;
26361f28255Scgd #ifndef NOWORM
2643ea4a95cSchristos 	struct wseg    *wtmp;
2653ea4a95cSchristos #endif	/* NOWORM */
26661f28255Scgd 
26761f28255Scgd 	m_atseg = 0;
26861f28255Scgd 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
26961f28255Scgd 		if (mtmp->mx == x && mtmp->my == y)
27061f28255Scgd 			return (mtmp);
27161f28255Scgd #ifndef NOWORM
27261f28255Scgd 		if (mtmp->wormno) {
27361f28255Scgd 			for (wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
27461f28255Scgd 				if (wtmp->wx == x && wtmp->wy == y) {
27561f28255Scgd 					m_atseg = wtmp;
27661f28255Scgd 					return (mtmp);
27761f28255Scgd 				}
27861f28255Scgd 		}
2793ea4a95cSchristos #endif	/* NOWORM */
28061f28255Scgd 	}
28161f28255Scgd 	return (0);
28261f28255Scgd }
28361f28255Scgd 
28461f28255Scgd struct obj     *
o_at(int x,int y)2851fa8a9a6Sdholland o_at(int x, int y)
28661f28255Scgd {
2873ea4a95cSchristos 	struct obj     *otmp;
28861f28255Scgd 
28961f28255Scgd 	for (otmp = fobj; otmp; otmp = otmp->nobj)
2903ea4a95cSchristos 		if (otmp->ox == x && otmp->oy == y)
2913ea4a95cSchristos 			return (otmp);
29261f28255Scgd 	return (0);
29361f28255Scgd }
29461f28255Scgd 
29561f28255Scgd struct obj     *
sobj_at(int n,int x,int y)2961fa8a9a6Sdholland sobj_at(int n, int x, int y)
29761f28255Scgd {
2983ea4a95cSchristos 	struct obj     *otmp;
29961f28255Scgd 
30061f28255Scgd 	for (otmp = fobj; otmp; otmp = otmp->nobj)
30161f28255Scgd 		if (otmp->ox == x && otmp->oy == y && otmp->otyp == n)
30261f28255Scgd 			return (otmp);
30361f28255Scgd 	return (0);
30461f28255Scgd }
30561f28255Scgd 
3063ea4a95cSchristos int
carried(struct obj * obj)3071fa8a9a6Sdholland carried(struct obj *obj)
3083ea4a95cSchristos {
3093ea4a95cSchristos 	struct obj     *otmp;
31061f28255Scgd 	for (otmp = invent; otmp; otmp = otmp->nobj)
3113ea4a95cSchristos 		if (otmp == obj)
3123ea4a95cSchristos 			return (1);
31361f28255Scgd 	return (0);
31461f28255Scgd }
31561f28255Scgd 
3163ea4a95cSchristos int
carrying(int type)3171fa8a9a6Sdholland carrying(int type)
31861f28255Scgd {
3193ea4a95cSchristos 	struct obj     *otmp;
32061f28255Scgd 
32161f28255Scgd 	for (otmp = invent; otmp; otmp = otmp->nobj)
32261f28255Scgd 		if (otmp->otyp == type)
32361f28255Scgd 			return (TRUE);
32461f28255Scgd 	return (FALSE);
32561f28255Scgd }
32661f28255Scgd 
32761f28255Scgd struct obj     *
o_on(unsigned int id,struct obj * objchn)3281fa8a9a6Sdholland o_on(unsigned int id, struct obj *objchn)
3293ea4a95cSchristos {
33061f28255Scgd 	while (objchn) {
3313ea4a95cSchristos 		if (objchn->o_id == id)
3323ea4a95cSchristos 			return (objchn);
33361f28255Scgd 		objchn = objchn->nobj;
33461f28255Scgd 	}
33561f28255Scgd 	return ((struct obj *) 0);
33661f28255Scgd }
33761f28255Scgd 
33861f28255Scgd struct trap    *
t_at(int x,int y)3391fa8a9a6Sdholland t_at(int x, int y)
34061f28255Scgd {
3413ea4a95cSchristos 	struct trap    *trap = ftrap;
34261f28255Scgd 	while (trap) {
3433ea4a95cSchristos 		if (trap->tx == x && trap->ty == y)
3443ea4a95cSchristos 			return (trap);
34561f28255Scgd 		trap = trap->ntrap;
34661f28255Scgd 	}
34761f28255Scgd 	return (0);
34861f28255Scgd }
34961f28255Scgd 
35061f28255Scgd struct gold    *
g_at(int x,int y)3511fa8a9a6Sdholland g_at(int x, int y)
35261f28255Scgd {
3533ea4a95cSchristos 	struct gold    *gold = fgold;
35461f28255Scgd 	while (gold) {
3553ea4a95cSchristos 		if (gold->gx == x && gold->gy == y)
3563ea4a95cSchristos 			return (gold);
35761f28255Scgd 		gold = gold->ngold;
35861f28255Scgd 	}
35961f28255Scgd 	return (0);
36061f28255Scgd }
36161f28255Scgd 
36261f28255Scgd /* make dummy object structure containing gold - for temporary use only */
3639b92b189Sdholland static struct obj *
mkgoldobj(long q)3641fa8a9a6Sdholland mkgoldobj(long q)
36561f28255Scgd {
3663ea4a95cSchristos 	struct obj     *otmp;
36761f28255Scgd 
36861f28255Scgd 	otmp = newobj(0);
36961f28255Scgd 	/* should set o_id etc. but otmp will be freed soon */
37061f28255Scgd 	otmp->olet = '$';
37161f28255Scgd 	u.ugold -= q;
37261f28255Scgd 	OGOLD(otmp) = q;
37361f28255Scgd 	flags.botl = 1;
37461f28255Scgd 	return (otmp);
37561f28255Scgd }
37661f28255Scgd 
37761f28255Scgd /*
37861f28255Scgd  * getobj returns:
37961f28255Scgd  *	struct obj *xxx:	object to do something with.
38061f28255Scgd  *	(struct obj *) 0	error return: no object.
38161f28255Scgd  *	&zeroobj		explicitly no object (as in w-).
38261f28255Scgd  */
38361f28255Scgd struct obj     *
getobj(const char * let,const char * word)3841fa8a9a6Sdholland getobj(const char *let, const char *word)
38561f28255Scgd {
3863ea4a95cSchristos 	struct obj     *otmp;
3873ea4a95cSchristos 	char            ilet, ilet1, ilet2;
38861f28255Scgd 	char            buf[BUFSZ];
38961f28255Scgd 	char            lets[BUFSZ];
3903ea4a95cSchristos 	int             foo = 0, foo2;
3913ea4a95cSchristos 	char           *bp = buf;
39261f28255Scgd 	xchar           allowcnt = 0;	/* 0, 1 or 2 */
39361f28255Scgd 	boolean         allowgold = FALSE;
39461f28255Scgd 	boolean         allowall = FALSE;
39561f28255Scgd 	boolean         allownone = FALSE;
39661f28255Scgd 	xchar           foox = 0;
39761f28255Scgd 	long            cnt;
39861f28255Scgd 
3993ea4a95cSchristos 	if (*let == '0')
4003ea4a95cSchristos 		let++, allowcnt = 1;
4013ea4a95cSchristos 	if (*let == '$')
4023ea4a95cSchristos 		let++, allowgold = TRUE;
4033ea4a95cSchristos 	if (*let == '#')
4043ea4a95cSchristos 		let++, allowall = TRUE;
4053ea4a95cSchristos 	if (*let == '-')
4063ea4a95cSchristos 		let++, allownone = TRUE;
4073ea4a95cSchristos 	if (allownone)
4083ea4a95cSchristos 		*bp++ = '-';
4093ea4a95cSchristos 	if (allowgold)
4103ea4a95cSchristos 		*bp++ = '$';
4113ea4a95cSchristos 	if (bp > buf && bp[-1] == '-')
4123ea4a95cSchristos 		*bp++ = ' ';
41361f28255Scgd 
41461f28255Scgd 	ilet = 'a';
41561f28255Scgd 	for (otmp = invent; otmp; otmp = otmp->nobj) {
4163ea4a95cSchristos 		if (!*let || strchr(let, otmp->olet)) {
41761f28255Scgd 			bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
41861f28255Scgd 
41961f28255Scgd 			/* ugly check: remove inappropriate things */
42061f28255Scgd 			if ((!strcmp(word, "take off") &&
42161f28255Scgd 			     !(otmp->owornmask & (W_ARMOR - W_ARM2)))
42261f28255Scgd 			    || (!strcmp(word, "wear") &&
42361f28255Scgd 				(otmp->owornmask & (W_ARMOR | W_RING)))
42461f28255Scgd 			    || (!strcmp(word, "wield") &&
42561f28255Scgd 				(otmp->owornmask & W_WEP))) {
42661f28255Scgd 				foo--;
42761f28255Scgd 				foox++;
42861f28255Scgd 			}
42961f28255Scgd 		}
4303ea4a95cSchristos 		if (ilet == 'z')
4313ea4a95cSchristos 			ilet = 'A';
4323ea4a95cSchristos 		else
4333ea4a95cSchristos 			ilet++;
43461f28255Scgd 	}
43561f28255Scgd 	bp[foo] = 0;
4363ea4a95cSchristos 	if (foo == 0 && bp > buf && bp[-1] == ' ')
4373ea4a95cSchristos 		*--bp = 0;
43861f28255Scgd 	(void) strcpy(lets, bp);/* necessary since we destroy buf */
43961f28255Scgd 	if (foo > 5) {		/* compactify string */
44061f28255Scgd 		foo = foo2 = 1;
44161f28255Scgd 		ilet2 = bp[0];
44261f28255Scgd 		ilet1 = bp[1];
4433ea4a95cSchristos 		while ((ilet = bp[++foo2] = bp[++foo]) != '\0') {
44461f28255Scgd 			if (ilet == ilet1 + 1) {
44561f28255Scgd 				if (ilet1 == ilet2 + 1)
44661f28255Scgd 					bp[foo2 - 1] = ilet1 = '-';
44761f28255Scgd 				else if (ilet2 == '-') {
44861f28255Scgd 					bp[--foo2] = ++ilet1;
44961f28255Scgd 					continue;
45061f28255Scgd 				}
45161f28255Scgd 			}
45261f28255Scgd 			ilet2 = ilet1;
45361f28255Scgd 			ilet1 = ilet;
45461f28255Scgd 		}
45561f28255Scgd 	}
45661f28255Scgd 	if (!foo && !allowall && !allowgold && !allownone) {
45761f28255Scgd 		pline("You don't have anything %sto %s.",
45861f28255Scgd 		      foox ? "else " : "", word);
45961f28255Scgd 		return (0);
46061f28255Scgd 	}
46161f28255Scgd 	for (;;) {
46261f28255Scgd 		if (!buf[0])
46361f28255Scgd 			pline("What do you want to %s [*]? ", word);
46461f28255Scgd 		else
46561f28255Scgd 			pline("What do you want to %s [%s or ?*]? ",
46661f28255Scgd 			      word, buf);
46761f28255Scgd 
46861f28255Scgd 		cnt = 0;
46961f28255Scgd 		ilet = readchar();
47061f28255Scgd 		while (digit(ilet) && allowcnt) {
47161f28255Scgd 			if (cnt < 100000000)
47261f28255Scgd 				cnt = 10 * cnt + (ilet - '0');
47361f28255Scgd 			else
47461f28255Scgd 				cnt = 999999999;
47561f28255Scgd 			allowcnt = 2;	/* signal presence of cnt */
47661f28255Scgd 			ilet = readchar();
47761f28255Scgd 		}
47861f28255Scgd 		if (digit(ilet)) {
47961f28255Scgd 			pline("No count allowed with this command.");
48061f28255Scgd 			continue;
48161f28255Scgd 		}
4823ea4a95cSchristos 		if (strchr(quitchars, ilet))
48361f28255Scgd 			return ((struct obj *) 0);
48461f28255Scgd 		if (ilet == '-') {
48561f28255Scgd 			return (allownone ? &zeroobj : (struct obj *) 0);
48661f28255Scgd 		}
48761f28255Scgd 		if (ilet == '$') {
48861f28255Scgd 			if (!allowgold) {
48961f28255Scgd 				pline("You cannot %s gold.", word);
49061f28255Scgd 				continue;
49161f28255Scgd 			}
49261f28255Scgd 			if (!(allowcnt == 2 && cnt < u.ugold))
49361f28255Scgd 				cnt = u.ugold;
49461f28255Scgd 			return (mkgoldobj(cnt));
49561f28255Scgd 		}
49661f28255Scgd 		if (ilet == '?') {
49761f28255Scgd 			doinv(lets);
4983ea4a95cSchristos 			if (!(ilet = morc))
4993ea4a95cSchristos 				continue;
50061f28255Scgd 			/* he typed a letter (not a space) to more() */
50161f28255Scgd 		} else if (ilet == '*') {
5022c0ecb1aSdholland 			doinv(NULL);
5033ea4a95cSchristos 			if (!(ilet = morc))
5043ea4a95cSchristos 				continue;
50561f28255Scgd 			/* ... */
50661f28255Scgd 		}
50761f28255Scgd 		if (flags.invlet_constant) {
50861f28255Scgd 			for (otmp = invent; otmp; otmp = otmp->nobj)
5093ea4a95cSchristos 				if (otmp->invlet == ilet)
5103ea4a95cSchristos 					break;
51161f28255Scgd 		} else {
5123ea4a95cSchristos 			if (ilet >= 'A' && ilet <= 'Z')
5133ea4a95cSchristos 				ilet += 'z' - 'A' + 1;
51461f28255Scgd 			ilet -= 'a';
51561f28255Scgd 			for (otmp = invent; otmp && ilet;
51661f28255Scgd 			     ilet--, otmp = otmp->nobj);
51761f28255Scgd 		}
51861f28255Scgd 		if (!otmp) {
51961f28255Scgd 			pline("You don't have that object.");
52061f28255Scgd 			continue;
52161f28255Scgd 		}
52261f28255Scgd 		if (cnt < 0 || otmp->quan < cnt) {
52361f28255Scgd 			pline("You don't have that many! [You have %u]"
52461f28255Scgd 			      ,otmp->quan);
52561f28255Scgd 			continue;
52661f28255Scgd 		}
52761f28255Scgd 		break;
52861f28255Scgd 	}
5293ea4a95cSchristos 	if (!allowall && let && !strchr(let, otmp->olet)) {
53061f28255Scgd 		pline("That is a silly thing to %s.", word);
53161f28255Scgd 		return (0);
53261f28255Scgd 	}
53361f28255Scgd 	if (allowcnt == 2) {	/* cnt given */
5343ea4a95cSchristos 		if (cnt == 0)
5353ea4a95cSchristos 			return (0);
53661f28255Scgd 		if (cnt != otmp->quan) {
5373ea4a95cSchristos 			struct obj     *obj;
53861f28255Scgd 			obj = splitobj(otmp, (int) cnt);
5393ea4a95cSchristos 			if (otmp == uwep)
5403ea4a95cSchristos 				setuwep(obj);
54161f28255Scgd 		}
54261f28255Scgd 	}
54361f28255Scgd 	return (otmp);
54461f28255Scgd }
54561f28255Scgd 
5469b92b189Sdholland static int
ckunpaid(struct obj * otmp)5471fa8a9a6Sdholland ckunpaid(struct obj *otmp)
5483ea4a95cSchristos {
54961f28255Scgd 	return (otmp->unpaid);
55061f28255Scgd }
55161f28255Scgd 
55261f28255Scgd /* interactive version of getobj - used for Drop and Identify */
55361f28255Scgd /* return the number of times fn was called successfully */
5543ea4a95cSchristos int
ggetobj(const char * word,int (* fn)(struct obj *),int max)5551fa8a9a6Sdholland ggetobj(const char *word, int (*fn)(struct obj *), int max)
55661f28255Scgd {
55761f28255Scgd 	char            buf[BUFSZ];
5583ea4a95cSchristos 	char           *ip;
5593ea4a95cSchristos 	char            sym;
560165c915bSdholland 	unsigned        oletct = 0, iletct = 0;
5613ea4a95cSchristos 	boolean         allflag = FALSE;
56261f28255Scgd 	char            olets[20], ilets[20];
563cb5fd834Sjsm 	int           (*ckfn)(struct obj *) =
564cb5fd834Sjsm 	    (int (*)(struct obj *)) 0;
56561f28255Scgd 	xchar           allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;	/* BAH */
56661f28255Scgd 	if (!invent && !allowgold) {
56761f28255Scgd 		pline("You have nothing to %s.", word);
56861f28255Scgd 		return (0);
56961f28255Scgd 	} else {
5703ea4a95cSchristos 		struct obj     *otmp = invent;
5713ea4a95cSchristos 		int             uflg = 0;
57261f28255Scgd 
5733ea4a95cSchristos 		if (allowgold)
5743ea4a95cSchristos 			ilets[iletct++] = '$';
57561f28255Scgd 		ilets[iletct] = 0;
57661f28255Scgd 		while (otmp) {
5773ea4a95cSchristos 			if (!strchr(ilets, otmp->olet)) {
57861f28255Scgd 				ilets[iletct++] = otmp->olet;
57961f28255Scgd 				ilets[iletct] = 0;
58061f28255Scgd 			}
5813ea4a95cSchristos 			if (otmp->unpaid)
5823ea4a95cSchristos 				uflg = 1;
58361f28255Scgd 			otmp = otmp->nobj;
58461f28255Scgd 		}
58561f28255Scgd 		ilets[iletct++] = ' ';
5863ea4a95cSchristos 		if (uflg)
5873ea4a95cSchristos 			ilets[iletct++] = 'u';
5883ea4a95cSchristos 		if (invent)
5893ea4a95cSchristos 			ilets[iletct++] = 'a';
59061f28255Scgd 		ilets[iletct] = 0;
591165c915bSdholland 		assert(iletct < sizeof(ilets));
59261f28255Scgd 	}
59361f28255Scgd 	pline("What kinds of thing do you want to %s? [%s] ",
59461f28255Scgd 	      word, ilets);
59561f28255Scgd 	getlin(buf);
59661f28255Scgd 	if (buf[0] == '\033') {
59761f28255Scgd 		clrlin();
59861f28255Scgd 		return (0);
59961f28255Scgd 	}
60061f28255Scgd 	ip = buf;
60161f28255Scgd 	olets[0] = 0;
6023ea4a95cSchristos 	while ((sym = *ip++) != '\0') {
6033ea4a95cSchristos 		if (sym == ' ')
6043ea4a95cSchristos 			continue;
60561f28255Scgd 		if (sym == '$') {
60661f28255Scgd 			if (allowgold == 1)
60761f28255Scgd 				(*fn) (mkgoldobj(u.ugold));
60861f28255Scgd 			else if (!u.ugold)
60961f28255Scgd 				pline("You have no gold.");
61061f28255Scgd 			allowgold = 2;
6113ea4a95cSchristos 		} else if (sym == 'a' || sym == 'A')
6123ea4a95cSchristos 			allflag = TRUE;
6133ea4a95cSchristos 		else if (sym == 'u' || sym == 'U')
6143ea4a95cSchristos 			ckfn = ckunpaid;
6153ea4a95cSchristos 		else if (strchr("!%?[()=*/\"0", sym)) {
6163ea4a95cSchristos 			if (!strchr(olets, sym)) {
61761f28255Scgd 				olets[oletct++] = sym;
61861f28255Scgd 				olets[oletct] = 0;
61961f28255Scgd 			}
620165c915bSdholland 			assert(oletct < sizeof(olets));
6213ea4a95cSchristos 		} else
6223ea4a95cSchristos 			pline("You don't have any %c's.", sym);
62361f28255Scgd 	}
62461f28255Scgd 	if (allowgold == 2 && !oletct)
62561f28255Scgd 		return (1);	/* he dropped gold (or at least tried to) */
62661f28255Scgd 	else
62761f28255Scgd 		return (askchain(invent, olets, allflag, fn, ckfn, max));
62861f28255Scgd }
62961f28255Scgd 
63061f28255Scgd /*
63161f28255Scgd  * Walk through the chain starting at objchn and ask for all objects
63261f28255Scgd  * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
63361f28255Scgd  * whether the action in question (i.e., fn) has to be performed.
63461f28255Scgd  * If allflag then no questions are asked. Max gives the max nr of
63561f28255Scgd  * objects to be treated. Return the number of objects treated.
63661f28255Scgd  */
6373ea4a95cSchristos int
askchain(struct obj * objchn,char * olets,int allflag,int (* fn)(struct obj *),int (* ckfn)(struct obj *),int max)6381fa8a9a6Sdholland askchain(struct obj *objchn, char *olets, int allflag,
6391fa8a9a6Sdholland 	int (*fn)(struct obj *),
6401fa8a9a6Sdholland 	int (*ckfn)(struct obj *),
6411fa8a9a6Sdholland 	int max)
64261f28255Scgd {
6433ea4a95cSchristos 	struct obj     *otmp, *otmp2;
6443ea4a95cSchristos 	char            sym, ilet;
6453ea4a95cSchristos 	int             cnt = 0;
64661f28255Scgd 	ilet = 'a' - 1;
64761f28255Scgd 	for (otmp = objchn; otmp; otmp = otmp2) {
6483ea4a95cSchristos 		if (ilet == 'z')
6493ea4a95cSchristos 			ilet = 'A';
6503ea4a95cSchristos 		else
6513ea4a95cSchristos 			ilet++;
65261f28255Scgd 		otmp2 = otmp->nobj;
6533ea4a95cSchristos 		if (olets && *olets && !strchr(olets, otmp->olet))
6543ea4a95cSchristos 			continue;
6553ea4a95cSchristos 		if (ckfn && !(*ckfn) (otmp))
6563ea4a95cSchristos 			continue;
65761f28255Scgd 		if (!allflag) {
65857c13365Sjoerg 			pline("%s", xprname(otmp, ilet));
65961f28255Scgd 			addtopl(" [nyaq]? ");
66061f28255Scgd 			sym = readchar();
6613ea4a95cSchristos 		} else
6623ea4a95cSchristos 			sym = 'y';
66361f28255Scgd 
66461f28255Scgd 		switch (sym) {
66561f28255Scgd 		case 'a':
66661f28255Scgd 			allflag = 1;
667*d5b021c7Sdholland 			/* FALLTHROUGH */
66861f28255Scgd 		case 'y':
66961f28255Scgd 			cnt += (*fn) (otmp);
6703ea4a95cSchristos 			if (--max == 0)
6713ea4a95cSchristos 				goto ret;
672*d5b021c7Sdholland 			break;
67361f28255Scgd 		case 'n':
67461f28255Scgd 		default:
67561f28255Scgd 			break;
67661f28255Scgd 		case 'q':
67761f28255Scgd 			goto ret;
67861f28255Scgd 		}
67961f28255Scgd 	}
68061f28255Scgd 	pline(cnt ? "That was all." : "No applicable objects.");
68161f28255Scgd ret:
68261f28255Scgd 	return (cnt);
68361f28255Scgd }
68461f28255Scgd 
6851fa8a9a6Sdholland /* should of course only be called for things in invent */
6869b92b189Sdholland static char
obj_to_let(struct obj * obj)6871fa8a9a6Sdholland obj_to_let(struct obj *obj)
68861f28255Scgd {
6893ea4a95cSchristos 	struct obj     *otmp;
6903ea4a95cSchristos 	char            ilet;
69161f28255Scgd 
69261f28255Scgd 	if (flags.invlet_constant)
69361f28255Scgd 		return (obj->invlet);
69461f28255Scgd 	ilet = 'a';
69561f28255Scgd 	for (otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
6963ea4a95cSchristos 		if (++ilet > 'z')
6973ea4a95cSchristos 			ilet = 'A';
69861f28255Scgd 	return (otmp ? ilet : NOINVSYM);
69961f28255Scgd }
70061f28255Scgd 
7013ea4a95cSchristos void
prinv(struct obj * obj)7021fa8a9a6Sdholland prinv(struct obj *obj)
70361f28255Scgd {
70457c13365Sjoerg 	pline("%s", xprname(obj, obj_to_let(obj)));
70561f28255Scgd }
70661f28255Scgd 
70761f28255Scgd static char *
xprname(struct obj * obj,char let)7081fa8a9a6Sdholland xprname(struct obj *obj, char let)
70961f28255Scgd {
71061f28255Scgd 	static char     li[BUFSZ];
71161f28255Scgd 
712907fca1bSdholland 	(void) snprintf(li, sizeof(li), "%c - %s.",
71361f28255Scgd 		       flags.invlet_constant ? obj->invlet : let,
71461f28255Scgd 		       doname(obj));
71561f28255Scgd 	return (li);
71661f28255Scgd }
71761f28255Scgd 
7183ea4a95cSchristos int
ddoinv(void)7191fa8a9a6Sdholland ddoinv(void)
72061f28255Scgd {
7212c0ecb1aSdholland 	doinv(NULL);
72261f28255Scgd 	return (0);
72361f28255Scgd }
72461f28255Scgd 
72561f28255Scgd /* called with 0 or "": all objects in inventory */
72661f28255Scgd /* otherwise: all objects with (serial) letter in lets */
7279b92b189Sdholland static void
doinv(const char * lets)7282c0ecb1aSdholland doinv(const char *lets)
72961f28255Scgd {
7303ea4a95cSchristos 	struct obj     *otmp;
7313ea4a95cSchristos 	char            ilet;
732165c915bSdholland 	unsigned        ct = 0;
73361f28255Scgd 	char            any[BUFSZ];
73461f28255Scgd 
73561f28255Scgd 	morc = 0;		/* just to be sure */
73661f28255Scgd 
73761f28255Scgd 	if (!invent) {
73861f28255Scgd 		pline("Not carrying anything.");
73961f28255Scgd 		return;
74061f28255Scgd 	}
7412c0ecb1aSdholland 	cornline(0, NULL);
74261f28255Scgd 	ilet = 'a';
74361f28255Scgd 	for (otmp = invent; otmp; otmp = otmp->nobj) {
7443ea4a95cSchristos 		if (flags.invlet_constant)
7453ea4a95cSchristos 			ilet = otmp->invlet;
7463ea4a95cSchristos 		if (!lets || !*lets || strchr(lets, ilet)) {
74761f28255Scgd 			cornline(1, xprname(otmp, ilet));
74861f28255Scgd 			any[ct++] = ilet;
74961f28255Scgd 		}
7503ea4a95cSchristos 		if (!flags.invlet_constant)
7513ea4a95cSchristos 			if (++ilet > 'z')
7523ea4a95cSchristos 				ilet = 'A';
75361f28255Scgd 	}
75461f28255Scgd 	any[ct] = 0;
755165c915bSdholland 	assert(ct < sizeof(any));
75661f28255Scgd 	cornline(2, any);
75761f28255Scgd }
75861f28255Scgd 
7593ea4a95cSchristos int
dotypeinv(void)7601fa8a9a6Sdholland dotypeinv(void)
7613ea4a95cSchristos {				/* free after Robert Viduya */
76261f28255Scgd 	/* Changed to one type only, so he doesnt have to type cr */
76361f28255Scgd 	char            c, ilet;
76461f28255Scgd 	char            stuff[BUFSZ];
765165c915bSdholland 	unsigned        stct;
7663ea4a95cSchristos 	struct obj     *otmp;
76761f28255Scgd 	boolean         billx = inshop() && doinvbill(0);
76861f28255Scgd 	boolean         unpd = FALSE;
76961f28255Scgd 
77061f28255Scgd 	if (!invent && !u.ugold && !billx) {
77161f28255Scgd 		pline("You aren't carrying anything.");
77261f28255Scgd 		return (0);
77361f28255Scgd 	}
77461f28255Scgd 	stct = 0;
7753ea4a95cSchristos 	if (u.ugold)
7763ea4a95cSchristos 		stuff[stct++] = '$';
77761f28255Scgd 	stuff[stct] = 0;
77861f28255Scgd 	for (otmp = invent; otmp; otmp = otmp->nobj) {
7793ea4a95cSchristos 		if (!strchr(stuff, otmp->olet)) {
78061f28255Scgd 			stuff[stct++] = otmp->olet;
78161f28255Scgd 			stuff[stct] = 0;
78261f28255Scgd 		}
78361f28255Scgd 		if (otmp->unpaid)
78461f28255Scgd 			unpd = TRUE;
78561f28255Scgd 	}
7863ea4a95cSchristos 	if (unpd)
7873ea4a95cSchristos 		stuff[stct++] = 'u';
7883ea4a95cSchristos 	if (billx)
7893ea4a95cSchristos 		stuff[stct++] = 'x';
79061f28255Scgd 	stuff[stct] = 0;
791165c915bSdholland 	assert(stct < sizeof(stuff));
79261f28255Scgd 
79361f28255Scgd 	if (stct > 1) {
79461f28255Scgd 		pline("What type of object [%s] do you want an inventory of? ",
79561f28255Scgd 		      stuff);
79661f28255Scgd 		c = readchar();
7973ea4a95cSchristos 		if (strchr(quitchars, c))
7983ea4a95cSchristos 			return (0);
79961f28255Scgd 	} else
80061f28255Scgd 		c = stuff[0];
80161f28255Scgd 
80261f28255Scgd 	if (c == '$')
80361f28255Scgd 		return (doprgold());
80461f28255Scgd 
80561f28255Scgd 	if (c == 'x' || c == 'X') {
80661f28255Scgd 		if (billx)
80761f28255Scgd 			(void) doinvbill(1);
80861f28255Scgd 		else
80961f28255Scgd 			pline("No used-up objects on the shopping bill.");
81061f28255Scgd 		return (0);
81161f28255Scgd 	}
81261f28255Scgd 	if ((c == 'u' || c == 'U') && !unpd) {
81361f28255Scgd 		pline("You are not carrying any unpaid objects.");
81461f28255Scgd 		return (0);
81561f28255Scgd 	}
81661f28255Scgd 	stct = 0;
81761f28255Scgd 	ilet = 'a';
81861f28255Scgd 	for (otmp = invent; otmp; otmp = otmp->nobj) {
8193ea4a95cSchristos 		if (flags.invlet_constant)
8203ea4a95cSchristos 			ilet = otmp->invlet;
82161f28255Scgd 		if (c == otmp->olet || (c == 'u' && otmp->unpaid))
82261f28255Scgd 			stuff[stct++] = ilet;
8233ea4a95cSchristos 		if (!flags.invlet_constant)
8243ea4a95cSchristos 			if (++ilet > 'z')
8253ea4a95cSchristos 				ilet = 'A';
82661f28255Scgd 	}
82761f28255Scgd 	stuff[stct] = '\0';
828165c915bSdholland 	assert(stct < sizeof(stuff));
829165c915bSdholland 
83061f28255Scgd 	if (stct == 0)
83161f28255Scgd 		pline("You have no such objects.");
83261f28255Scgd 	else
83361f28255Scgd 		doinv(stuff);
83461f28255Scgd 
83561f28255Scgd 	return (0);
83661f28255Scgd }
83761f28255Scgd 
83861f28255Scgd /* look at what is here */
8393ea4a95cSchristos int
dolook(void)8401fa8a9a6Sdholland dolook(void)
8413ea4a95cSchristos {
8423aa9af7cSfair 	struct obj     *otmp = NULL, *otmp0 = NULL;
8433aa9af7cSfair 	struct gold    *gold = NULL;
844ab8b6343Sjsm 	const char     *verb = Blind ? "feel" : "see";
84561f28255Scgd 	int             ct = 0;
84661f28255Scgd 
84761f28255Scgd 	if (!u.uswallow) {
84861f28255Scgd 		if (Blind) {
84961f28255Scgd 			pline("You try to feel what is lying here on the floor.");
85061f28255Scgd 			if (Levitation) {	/* ab@unido */
85161f28255Scgd 				pline("You cannot reach the floor!");
85261f28255Scgd 				return (1);
85361f28255Scgd 			}
85461f28255Scgd 		}
85561f28255Scgd 		otmp0 = o_at(u.ux, u.uy);
85661f28255Scgd 		gold = g_at(u.ux, u.uy);
85761f28255Scgd 	}
85861f28255Scgd 	if (u.uswallow || (!otmp0 && !gold)) {
85961f28255Scgd 		pline("You %s no objects here.", verb);
86061f28255Scgd 		return (!!Blind);
86161f28255Scgd 	}
86261f28255Scgd 	cornline(0, "Things that are here:");
86361f28255Scgd 	for (otmp = otmp0; otmp; otmp = otmp->nobj) {
86461f28255Scgd 		if (otmp->ox == u.ux && otmp->oy == u.uy) {
86561f28255Scgd 			ct++;
86661f28255Scgd 			cornline(1, doname(otmp));
86761f28255Scgd 			if (Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
86861f28255Scgd 				pline("Touching the dead cockatrice is a fatal mistake ...");
86961f28255Scgd 				pline("You die ...");
87061f28255Scgd 				killer = "dead cockatrice";
87161f28255Scgd 				done("died");
87261f28255Scgd 			}
87361f28255Scgd 		}
87461f28255Scgd 	}
87561f28255Scgd 
87661f28255Scgd 	if (gold) {
87761f28255Scgd 		char            gbuf[30];
87861f28255Scgd 
879907fca1bSdholland 		(void) snprintf(gbuf, sizeof(gbuf), "%ld gold piece%s",
88061f28255Scgd 			       gold->amount, plur(gold->amount));
88161f28255Scgd 		if (!ct++)
88261f28255Scgd 			pline("You %s here %s.", verb, gbuf);
88361f28255Scgd 		else
88461f28255Scgd 			cornline(1, gbuf);
88561f28255Scgd 	}
88661f28255Scgd 	if (ct == 1 && !gold) {
88761f28255Scgd 		pline("You %s here %s.", verb, doname(otmp0));
8882c0ecb1aSdholland 		cornline(3, NULL);
88961f28255Scgd 	}
89061f28255Scgd 	if (ct > 1)
8912c0ecb1aSdholland 		cornline(2, NULL);
89261f28255Scgd 	return (!!Blind);
89361f28255Scgd }
89461f28255Scgd 
8953ea4a95cSchristos void
stackobj(struct obj * obj)8961fa8a9a6Sdholland stackobj(struct obj *obj)
8973ea4a95cSchristos {
8983ea4a95cSchristos 	struct obj     *otmp = fobj;
8993ea4a95cSchristos 	for (otmp = fobj; otmp; otmp = otmp->nobj)
9003ea4a95cSchristos 		if (otmp != obj)
90161f28255Scgd 			if (otmp->ox == obj->ox && otmp->oy == obj->oy &&
90261f28255Scgd 			    merged(obj, otmp, 1))
90361f28255Scgd 				return;
90461f28255Scgd }
90561f28255Scgd 
90661f28255Scgd /* merge obj with otmp and delete obj if types agree */
9079b92b189Sdholland static int
merged(struct obj * otmp,struct obj * obj,int lose)9081fa8a9a6Sdholland merged(struct obj *otmp, struct obj *obj, int lose)
9093ea4a95cSchristos {
91061f28255Scgd 	if (obj->otyp == otmp->otyp &&
91161f28255Scgd 	    obj->unpaid == otmp->unpaid &&
91261f28255Scgd 	    obj->spe == otmp->spe &&
91361f28255Scgd 	    obj->dknown == otmp->dknown &&
91461f28255Scgd 	    obj->cursed == otmp->cursed &&
9153ea4a95cSchristos 	    (strchr("%*?!", obj->olet) ||
91661f28255Scgd 	     (obj->known == otmp->known &&
91761f28255Scgd 	      (obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
91861f28255Scgd 		otmp->quan += obj->quan;
91961f28255Scgd 		otmp->owt += obj->owt;
9203ea4a95cSchristos 		if (lose)
9213ea4a95cSchristos 			freeobj(obj);
92261f28255Scgd 		obfree(obj, otmp);	/* free(obj), bill->otmp */
92361f28255Scgd 		return (1);
9243ea4a95cSchristos 	} else
9253ea4a95cSchristos 		return (0);
92661f28255Scgd }
92761f28255Scgd 
9283ea4a95cSchristos static long goldcounted;
92961f28255Scgd /*
93061f28255Scgd  * Gold is no longer displayed; in fact, when you have a lot of money,
93161f28255Scgd  * it may take a while before you have counted it all.
93261f28255Scgd  * [Bug: d$ and pickup still tell you how much it was.]
93361f28255Scgd  */
9349b92b189Sdholland static int
countgold(void)9351fa8a9a6Sdholland countgold(void)
9363ea4a95cSchristos {
93761f28255Scgd 	if ((goldcounted += 100 * (u.ulevel + 1)) >= u.ugold) {
93861f28255Scgd 		long            eps = 0;
9393ea4a95cSchristos 		if (!rn2(2))
9403ea4a95cSchristos 			eps = rnd((int) (u.ugold / 100 + 1));
94161f28255Scgd 		pline("You probably have about %ld gold pieces.",
94261f28255Scgd 		      u.ugold + eps);
94361f28255Scgd 		return (0);	/* done */
94461f28255Scgd 	}
94561f28255Scgd 	return (1);		/* continue */
94661f28255Scgd }
94761f28255Scgd 
9483ea4a95cSchristos int
doprgold(void)9491fa8a9a6Sdholland doprgold(void)
9503ea4a95cSchristos {
95161f28255Scgd 	if (!u.ugold)
95261f28255Scgd 		pline("You do not carry any gold.");
95361f28255Scgd 	else if (u.ugold <= 500)
95461f28255Scgd 		pline("You are carrying %ld gold pieces.", u.ugold);
95561f28255Scgd 	else {
95661f28255Scgd 		pline("You sit down in order to count your gold pieces.");
95761f28255Scgd 		goldcounted = 500;
95861f28255Scgd 		occupation = countgold;
95961f28255Scgd 		occtxt = "counting your gold";
96061f28255Scgd 	}
96161f28255Scgd 	return (1);
96261f28255Scgd }
96361f28255Scgd 
96461f28255Scgd /* --- end of gold counting section --- */
9653ea4a95cSchristos int
doprwep(void)9661fa8a9a6Sdholland doprwep(void)
9673ea4a95cSchristos {
9683ea4a95cSchristos 	if (!uwep)
9693ea4a95cSchristos 		pline("You are empty handed.");
9703ea4a95cSchristos 	else
9713ea4a95cSchristos 		prinv(uwep);
97261f28255Scgd 	return (0);
97361f28255Scgd }
97461f28255Scgd 
9753ea4a95cSchristos int
doprarm(void)9761fa8a9a6Sdholland doprarm(void)
9773ea4a95cSchristos {
97861f28255Scgd 	if (!uarm && !uarmg && !uarms && !uarmh)
97961f28255Scgd 		pline("You are not wearing any armor.");
98061f28255Scgd 	else {
98161f28255Scgd 		char            lets[6];
9823ea4a95cSchristos 		int             ct = 0;
98361f28255Scgd 
9843ea4a95cSchristos 		if (uarm)
9853ea4a95cSchristos 			lets[ct++] = obj_to_let(uarm);
9863ea4a95cSchristos 		if (uarm2)
9873ea4a95cSchristos 			lets[ct++] = obj_to_let(uarm2);
9883ea4a95cSchristos 		if (uarmh)
9893ea4a95cSchristos 			lets[ct++] = obj_to_let(uarmh);
9903ea4a95cSchristos 		if (uarms)
9913ea4a95cSchristos 			lets[ct++] = obj_to_let(uarms);
9923ea4a95cSchristos 		if (uarmg)
9933ea4a95cSchristos 			lets[ct++] = obj_to_let(uarmg);
99461f28255Scgd 		lets[ct] = 0;
99561f28255Scgd 		doinv(lets);
99661f28255Scgd 	}
99761f28255Scgd 	return (0);
99861f28255Scgd }
99961f28255Scgd 
10003ea4a95cSchristos int
doprring(void)10011fa8a9a6Sdholland doprring(void)
10023ea4a95cSchristos {
100361f28255Scgd 	if (!uleft && !uright)
100461f28255Scgd 		pline("You are not wearing any rings.");
100561f28255Scgd 	else {
100661f28255Scgd 		char            lets[3];
10073ea4a95cSchristos 		int             ct = 0;
100861f28255Scgd 
10093ea4a95cSchristos 		if (uleft)
10103ea4a95cSchristos 			lets[ct++] = obj_to_let(uleft);
10113ea4a95cSchristos 		if (uright)
10123ea4a95cSchristos 			lets[ct++] = obj_to_let(uright);
101361f28255Scgd 		lets[ct] = 0;
101461f28255Scgd 		doinv(lets);
101561f28255Scgd 	}
101661f28255Scgd 	return (0);
101761f28255Scgd }
101861f28255Scgd 
10193ea4a95cSchristos int
digit(int c)10201fa8a9a6Sdholland digit(int c)
10213ea4a95cSchristos {
102261f28255Scgd 	return (c >= '0' && c <= '9');
102361f28255Scgd }
1024