[comp.sources.games] v10i054: nethack3p9 - display oriented dungeons & dragons

billr@saab.CNA.TEK.COM (Bill Randle) (07/12/90)

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 10, Issue 54
Archive-name: nethack3p9/Part09
Supersedes: NetHack3: Volume 7, Issue 56-93



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 9 (of 56)."
# Contents:  others/random.c src/shk.c
# Wrapped by billr@saab on Wed Jul 11 17:11:02 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'others/random.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'others/random.c'\"
else
echo shar: Extracting \"'others/random.c'\" \(13466 characters\)
sed "s/^X//" >'others/random.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1983 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X/* Several minor changes were made for the NetHack distribution to satisfy
X * non-BSD compilers (by definition BSD compilers do not need to compile
X * this file for NetHack).  These changes consisted of:
X *	- changing the sccsid conditions to nested ifdefs from defined()s
X *	to accommodate stupid preprocessors
X *	- giving srandom() type void instead of allowing it to default to int
X *	- making the first return in initstate() return a value consistent
X *	with its type (instead of no value)
X *	- ANSI function prototyping in extern.h - therefore include hack.h
X *	instead of stdio.h and remove separate declaration of random() from
X *	the beginning of function srandom
X */
X
X#ifdef LIBC_SCCS
X# ifndef lint
Xstatic char sccsid[] = "@(#)random.c	5.5 (Berkeley) 7/6/88";
X# endif
X#endif /* LIBC_SCCS and not lint */
X
X#include "hack.h"
X
X/*
X * random.c:
X * An improved random number generation package.  In addition to the standard
X * rand()/srand() like interface, this package also has a special state info
X * interface.  The initstate() routine is called with a seed, an array of
X * bytes, and a count of how many bytes are being passed in; this array is then
X * initialized to contain information for random number generation with that
X * much state information.  Good sizes for the amount of state information are
X * 32, 64, 128, and 256 bytes.  The state can be switched by calling the
X * setstate() routine with the same array as was initiallized with initstate().
X * By default, the package runs with 128 bytes of state information and
X * generates far better random numbers than a linear congruential generator.
X * If the amount of state information is less than 32 bytes, a simple linear
X * congruential R.N.G. is used.
X * Internally, the state information is treated as an array of longs; the
X * zeroeth element of the array is the type of R.N.G. being used (small
X * integer); the remainder of the array is the state information for the
X * R.N.G.  Thus, 32 bytes of state information will give 7 longs worth of
X * state information, which will allow a degree seven polynomial.  (Note: the 
X * zeroeth word of state information also has some other information stored
X * in it -- see setstate() for details).
X * The random number generation technique is a linear feedback shift register
X * approach, employing trinomials (since there are fewer terms to sum up that
X * way).  In this approach, the least significant bit of all the numbers in
X * the state table will act as a linear feedback shift register, and will have
X * period 2^deg - 1 (where deg is the degree of the polynomial being used,
X * assuming that the polynomial is irreducible and primitive).  The higher
X * order bits will have longer periods, since their values are also influenced
X * by pseudo-random carries out of the lower bits.  The total period of the
X * generator is approximately deg*(2**deg - 1); thus doubling the amount of
X * state information has a vast influence on the period of the generator.
X * Note: the deg*(2**deg - 1) is an approximation only good for large deg,
X * when the period of the shift register is the dominant factor.  With deg
X * equal to seven, the period is actually much longer than the 7*(2**7 - 1)
X * predicted by this formula.
X */
X
X
X
X/*
X * For each of the currently supported random number generators, we have a
X * break value on the amount of state information (you need at least this
X * many bytes of state info to support this random number generator), a degree
X * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
X * the separation between the two lower order coefficients of the trinomial.
X */
X
X#define		TYPE_0		0		/* linear congruential */
X#define		BREAK_0		8
X#define		DEG_0		0
X#define		SEP_0		0
X
X#define		TYPE_1		1		/* x**7 + x**3 + 1 */
X#define		BREAK_1		32
X#define		DEG_1		7
X#define		SEP_1		3
X
X#define		TYPE_2		2		/* x**15 + x + 1 */
X#define		BREAK_2		64
X#define		DEG_2		15
X#define		SEP_2		1
X
X#define		TYPE_3		3		/* x**31 + x**3 + 1 */
X#define		BREAK_3		128
X#define		DEG_3		31
X#define		SEP_3		3
X
X#define		TYPE_4		4		/* x**63 + x + 1 */
X#define		BREAK_4		256
X#define		DEG_4		63
X#define		SEP_4		1
X
X
X/*
X * Array versions of the above information to make code run faster -- relies
X * on fact that TYPE_i == i.
X */
X
X#define		MAX_TYPES	5		/* max number of types above */
X
Xstatic  int		degrees[ MAX_TYPES ]	= { DEG_0, DEG_1, DEG_2,
X								DEG_3, DEG_4 };
X
Xstatic  int		seps[ MAX_TYPES ]	= { SEP_0, SEP_1, SEP_2,
X								SEP_3, SEP_4 };
X
X
X
X/*
X * Initially, everything is set up as if from :
X *		initstate( 1, &randtbl, 128 );
X * Note that this initialization takes advantage of the fact that srandom()
X * advances the front and rear pointers 10*rand_deg times, and hence the
X * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
X * element of the state information, which contains info about the current
X * position of the rear pointer is just
X *	MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3.
X */
X
Xstatic  long		randtbl[ DEG_3 + 1 ]	= { TYPE_3,
X			    0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 
X			    0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 
X			    0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 
X			    0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 
X			    0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 
X			    0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 
X			    0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 
X					0xf5ad9d0e, 0x8999220b, 0x27fb47b9 };
X
X/*
X * fptr and rptr are two pointers into the state info, a front and a rear
X * pointer.  These two pointers are always rand_sep places aparts, as they cycle
X * cyclically through the state information.  (Yes, this does mean we could get
X * away with just one pointer, but the code for random() is more efficient this
X * way).  The pointers are left positioned as they would be from the call
X *			initstate( 1, randtbl, 128 )
X * (The position of the rear pointer, rptr, is really 0 (as explained above
X * in the initialization of randtbl) because the state table pointer is set
X * to point to randtbl[1] (as explained below).
X */
X
Xstatic  long		*fptr			= &randtbl[ SEP_3 + 1 ];
Xstatic  long		*rptr			= &randtbl[ 1 ];
X
X
X
X/*
X * The following things are the pointer to the state information table,
X * the type of the current generator, the degree of the current polynomial
X * being used, and the separation between the two pointers.
X * Note that for efficiency of random(), we remember the first location of
X * the state information, not the zeroeth.  Hence it is valid to access
X * state[-1], which is used to store the type of the R.N.G.
X * Also, we remember the last location, since this is more efficient than
X * indexing every time to find the address of the last element to see if
X * the front and rear pointers have wrapped.
X */
X
Xstatic  long		*state			= &randtbl[ 1 ];
X
Xstatic  int		rand_type		= TYPE_3;
Xstatic  int		rand_deg		= DEG_3;
Xstatic  int		rand_sep		= SEP_3;
X
Xstatic  long		*end_ptr		= &randtbl[ DEG_3 + 1 ];
X
X
X
X/*
X * srandom:
X * Initialize the random number generator based on the given seed.  If the
X * type is the trivial no-state-information type, just remember the seed.
X * Otherwise, initializes state[] based on the given "seed" via a linear
X * congruential generator.  Then, the pointers are set to known locations
X * that are exactly rand_sep places apart.  Lastly, it cycles the state
X * information a given number of times to get rid of any initial dependencies
X * introduced by the L.C.R.N.G.
X * Note that the initialization of randtbl[] for default usage relies on
X * values produced by this routine.
X */
X
Xvoid
Xsrandom( x )
X
X    unsigned		x;
X{
X    	register  int		i, j;
X
X	if(  rand_type  ==  TYPE_0  )  {
X	    state[ 0 ] = x;
X	}
X	else  {
X	    j = 1;
X	    state[ 0 ] = x;
X	    for( i = 1; i < rand_deg; i++ )  {
X		state[i] = 1103515245*state[i - 1] + 12345;
X	    }
X	    fptr = &state[ rand_sep ];
X	    rptr = &state[ 0 ];
X	    for( i = 0; i < 10*rand_deg; i++ )  random();
X	}
X}
X
X
X
X/*
X * initstate:
X * Initialize the state information in the given array of n bytes for
X * future random number generation.  Based on the number of bytes we
X * are given, and the break values for the different R.N.G.'s, we choose
X * the best (largest) one we can and set things up for it.  srandom() is
X * then called to initialize the state information.
X * Note that on return from srandom(), we set state[-1] to be the type
X * multiplexed with the current value of the rear pointer; this is so
X * successive calls to initstate() won't lose this information and will
X * be able to restart with setstate().
X * Note: the first thing we do is save the current state, if any, just like
X * setstate() so that it doesn't matter when initstate is called.
X * Returns a pointer to the old state.
X */
X
Xchar  *
Xinitstate( seed, arg_state, n )
X
X    unsigned		seed;			/* seed for R. N. G. */
X    char		*arg_state;		/* pointer to state array */
X    int			n;			/* # bytes of state info */
X{
X	register  char		*ostate		= (char *)( &state[ -1 ] );
X
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	if(  n  <  BREAK_1  )  {
X	    if(  n  <  BREAK_0  )  {
X		fprintf( stderr, "initstate: not enough state (%d bytes) with which to do jack; ignored.\n", n );
X		return (char *)0;
X	    }
X	    rand_type = TYPE_0;
X	    rand_deg = DEG_0;
X	    rand_sep = SEP_0;
X	}
X	else  {
X	    if(  n  <  BREAK_2  )  {
X		rand_type = TYPE_1;
X		rand_deg = DEG_1;
X		rand_sep = SEP_1;
X	    }
X	    else  {
X		if(  n  <  BREAK_3  )  {
X		    rand_type = TYPE_2;
X		    rand_deg = DEG_2;
X		    rand_sep = SEP_2;
X		}
X		else  {
X		    if(  n  <  BREAK_4  )  {
X			rand_type = TYPE_3;
X			rand_deg = DEG_3;
X			rand_sep = SEP_3;
X		    }
X		    else  {
X			rand_type = TYPE_4;
X			rand_deg = DEG_4;
X			rand_sep = SEP_4;
X		    }
X		}
X	    }
X	}
X	state = &(  ( (long *)arg_state )[1]  );	/* first location */
X	end_ptr = &state[ rand_deg ];	/* must set end_ptr before srandom */
X	srandom( seed );
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	return( ostate );
X}
X
X
X
X/*
X * setstate:
X * Restore the state from the given state array.
X * Note: it is important that we also remember the locations of the pointers
X * in the current state information, and restore the locations of the pointers
X * from the old state information.  This is done by multiplexing the pointer
X * location into the zeroeth word of the state information.
X * Note that due to the order in which things are done, it is OK to call
X * setstate() with the same state as the current state.
X * Returns a pointer to the old state information.
X */
X
Xchar  *
Xsetstate( arg_state )
X
X    char		*arg_state;
X{
X	register  long		*new_state	= (long *)arg_state;
X	register  int		type		= new_state[0]%MAX_TYPES;
X	register  int		rear		= new_state[0]/MAX_TYPES;
X	char			*ostate		= (char *)( &state[ -1 ] );
X
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	switch(  type  )  {
X	    case  TYPE_0:
X	    case  TYPE_1:
X	    case  TYPE_2:
X	    case  TYPE_3:
X	    case  TYPE_4:
X		rand_type = type;
X		rand_deg = degrees[ type ];
X		rand_sep = seps[ type ];
X		break;
X
X	    default:
X		fprintf( stderr, "setstate: state info has been munged; not changed.\n" );
X	}
X	state = &new_state[ 1 ];
X	if(  rand_type  !=  TYPE_0  )  {
X	    rptr = &state[ rear ];
X	    fptr = &state[ (rear + rand_sep)%rand_deg ];
X	}
X	end_ptr = &state[ rand_deg ];		/* set end_ptr too */
X	return( ostate );
X}
X
X
X
X/*
X * random:
X * If we are using the trivial TYPE_0 R.N.G., just do the old linear
X * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
X * same in all ther other cases due to all the global variables that have been
X * set up.  The basic operation is to add the number at the rear pointer into
X * the one at the front pointer.  Then both pointers are advanced to the next
X * location cyclically in the table.  The value returned is the sum generated,
X * reduced to 31 bits by throwing away the "least random" low bit.
X * Note: the code takes advantage of the fact that both the front and
X * rear pointers can't wrap on the same call by not testing the rear
X * pointer if the front one has wrapped.
X * Returns a 31-bit random number.
X */
X
Xlong
Xrandom()
X{
X	long		i;
X	
X	if(  rand_type  ==  TYPE_0  )  {
X	    i = state[0] = ( state[0]*1103515245 + 12345 )&0x7fffffff;
X	}
X	else  {
X	    *fptr += *rptr;
X	    i = (*fptr >> 1)&0x7fffffff;	/* chucking least random bit */
X	    if(  ++fptr  >=  end_ptr  )  {
X		fptr = state;
X		++rptr;
X	    }
X	    else  {
X		if(  ++rptr  >=  end_ptr  )  rptr = state;
X	    }
X	}
X	return( i );
X}
X
END_OF_FILE
if test 13466 -ne `wc -c <'others/random.c'`; then
    echo shar: \"'others/random.c'\" unpacked with wrong size!
fi
# end of 'others/random.c'
fi
if test -f 'src/shk.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/shk.c'\"
else
echo shar: Extracting \"'src/shk.c'\" \(42124 characters\)
sed "s/^X//" >'src/shk.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)shk.c	3.0	89/11/27
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#define MONATTK_H	/* comment line for pre-compiled headers */
X/* block some unused #defines to avoid overloading some cpp's */
X#include "hack.h"
X
X#include "eshk.h"
X
X
X# ifdef KOPS
XSTATIC_DCL int FDECL(makekops, (coord *));
X# ifdef OVLB
Xstatic void NDECL(kops_gone);
X# endif /* OVLB */
X#endif /* KOPS */
X
X#define	NOTANGRY(mon)	mon->mpeaceful
X#define	ANGRY(mon)	!NOTANGRY(mon)
X
X/* Descriptor of current shopkeeper. Note that the bill need not be
X   per-shopkeeper, since it is valid only when in a shop. */
XSTATIC_VAR struct monst NEARDATA *shopkeeper;
XSTATIC_VAR struct bill_x NEARDATA *bill;
XSTATIC_VAR int NEARDATA shlevel; /* level of this shopkeeper */
X/* struct obj *billobjs;	/* objects on bill with bp->useup */
X				/* only accessed here and by save & restore */
XSTATIC_VAR long int NEARDATA total; 	/* filled by addupbill() */
XSTATIC_VAR long int NEARDATA followmsg;	/* last time of follow message */
X
XSTATIC_DCL void NDECL(setpaid);
XSTATIC_DCL void NDECL(addupbill);
XSTATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int));
XSTATIC_DCL void FDECL(findshk, (int));
X
X#ifdef OVLB
X
Xstatic struct bill_x * FDECL(onbill, (struct obj *));
Xstatic long FDECL(check_credit, (long,struct monst *));
Xstatic void FDECL(pay, (long,struct monst *));
Xstatic unsigned FDECL(get_cost, (struct obj *));
Xstatic unsigned FDECL(cost_per_charge, (struct obj *));
Xstatic int FDECL(dopayobj, (struct bill_x *)), FDECL(getprice, (struct obj *));
Xstatic struct obj *FDECL(bp_to_obj, (struct bill_x *));
X
X/*
X	invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
X		obj->quan <= bp->bquan
X */
X
Xchar *
Xshkname(mtmp)				/* called in do_name.c */
Xregister struct monst *mtmp;
X{
X	return(ESHK(mtmp)->shknam);
X}
X
Xvoid
Xshkdead(mtmp)				/* called in mon.c */
Xregister struct monst *mtmp;
X{
X	register struct eshk *eshk = ESHK(mtmp);
X
X	if(eshk->shoplevel == dlevel)
X		rooms[eshk->shoproom].rtype = OROOM;
X	if(mtmp == shopkeeper) {
X		setpaid();
X		shopkeeper = 0;
X		bill = (struct bill_x *) -1000;	/* dump core when referenced */
X	}
X}
X
Xvoid
Xreplshk(mtmp,mtmp2)
Xregister struct monst *mtmp, *mtmp2;
X{
X	if(mtmp == shopkeeper) {
X		shopkeeper = mtmp2;
X		bill = &(ESHK(shopkeeper)->bill[0]);
X	}
X}
X
XSTATIC_OVL void
Xsetpaid(){	/* caller has checked that shopkeeper exists */
X		/* either we paid or left the shop or he just died */
X	register struct obj *obj;
X	register struct monst *mtmp;
X	for(obj = invent; obj; obj = obj->nobj)
X		obj->unpaid = 0;
X	for(obj = fobj; obj; obj = obj->nobj)
X		obj->unpaid = 0;
X	for(obj = fcobj; obj; obj = obj->nobj)
X		obj->unpaid = 0;
X	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X		for(obj = mtmp->minvent; obj; obj = obj->nobj)
X			obj->unpaid = 0;
X	for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
X		for(obj = mtmp->minvent; obj; obj = obj->nobj)
X			obj->unpaid = 0;
X	while(obj = billobjs){
X		billobjs = obj->nobj;
X		free((genericptr_t) obj);
X	}
X	if(shopkeeper) {
X		ESHK(shopkeeper)->billct = 0;
X		ESHK(shopkeeper)->credit = 0L;
X		ESHK(shopkeeper)->debit = 0L;
X	}
X}
X
XSTATIC_OVL void
Xaddupbill(){	/* delivers result in total */
X		/* caller has checked that shopkeeper exists */
X	register int ct = ESHK(shopkeeper)->billct;
X	register struct bill_x *bp = bill;
X	total = 0;
X	while(ct--){
X		total += bp->price * bp->bquan;
X		bp++;
X	}
X}
X
XSTATIC_OVL boolean
Xmonstinroom(mdat,roomno)
Xstruct permonst *mdat;
Xint roomno;
X{
X	register struct monst *mtmp;
X
X	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X		if(mtmp->data == mdat && inroom(mtmp->mx,mtmp->my) == roomno)
X			return(TRUE);
X	return(FALSE);
X}
X
X#endif /* OVLB */
X#ifdef OVL1
X
Xint
Xinshop() {
X	register int roomno = inroom(u.ux,u.uy);
X
X	/* Did we just leave a shop? */
X	if(u.uinshop &&
X	    (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
X
X	/* This is part of the bugfix for shopkeepers not having their
X	 * bill paid.  As reported by ab@unido -dgk
X	 * I made this standard due to the KOPS code below. -mrs
X	 */
X		if(shopkeeper) {
X		    if(ESHK(shopkeeper)->billct || ESHK(shopkeeper)->debit) {
X			if(inroom(shopkeeper->mx, shopkeeper->my)
X			    == u.uinshop - 1)	/* ab@unido */
X			    You("escaped the shop without paying!");
X			addupbill();
X			total += ESHK(shopkeeper)->debit;
X			You("stole %ld zorkmid%s worth of merchandise.",
X				total, plur(total));
X			ESHK(shopkeeper)->robbed += total;
X			ESHK(shopkeeper)->credit = 0L;
X			ESHK(shopkeeper)->debit = 0L;
X			if (pl_character[0] != 'R') /* stealing is unlawful */
X				adjalign(-sgn(u.ualigntyp));
X			setpaid();
X			if((rooms[ESHK(shopkeeper)->shoproom].rtype == SHOPBASE)
X			    == (rn2(3) == 0))
X			    ESHK(shopkeeper)->following = 1;
X#ifdef KOPS
X		    {   /* Keystone Kops srt@ucla */
X			coord mm;
X
X			if (flags.soundok)
X			    pline("An alarm sounds throughout the dungeon!");
X			if(flags.verbose) {
X			    if((mons[PM_KEYSTONE_KOP].geno & G_GENOD) &&
X 			       (mons[PM_KOP_SERGEANT].geno & G_GENOD) &&
X 			       (mons[PM_KOP_LIEUTENANT].geno & G_GENOD) &&
X			       (mons[PM_KOP_KAPTAIN].geno & G_GENOD)) {
X				if (flags.soundok)
X				    pline("But no one seems to respond to it.");
X			    } else
X				pline("The Keystone Kops are after you!");
X			}
X			/* Create a swarm near the staircase */
X			mm.x = xdnstair;
X			mm.y = ydnstair;
X			(void) makekops(&mm);
X			/* Create a swarm near the shopkeeper */
X			mm.x = shopkeeper->mx;
X			mm.y = shopkeeper->my;
X			(void) makekops(&mm);
X		    }
X#endif
X		    }
X		    shopkeeper = 0;
X		    shlevel = 0;
X		}
X		u.uinshop = 0;
X	}
X
X	/* Did we just enter a zoo of some kind? */
X	/* This counts everything except shops and vaults
X	   -- vault.c insists that a vault remain a VAULT */
X	if(roomno >= 0) {
X		register int rt = rooms[roomno].rtype;
X		register struct monst *mtmp;
X
X		switch (rt) {
X		case ZOO:
X		    pline("Welcome to David's treasure zoo!");
X		    break;
X		case SWAMP:
X		    pline("It looks rather muddy down here.");
X		    break;
X#ifdef THRONES
X		case COURT:
X		    You("enter an opulent throne room!");
X		    break;
X#endif
X		case MORGUE:
X		    if(midnight())
X			pline("Run away!  Run away!");
X		    else
X			You("have an uncanny feeling...");
X		    break;
X		case BEEHIVE:
X		    You("enter a giant beehive!");
X		    break;
X#ifdef ARMY
X		case BARRACKS:
X		    if(monstinroom(&mons[PM_SOLDIER], roomno) ||
X			    monstinroom(&mons[PM_SERGEANT], roomno) ||
X			    monstinroom(&mons[PM_LIEUTENANT], roomno) ||
X			    monstinroom(&mons[PM_CAPTAIN], roomno))
X		    	You("enter a military barracks!");
X		    else You("enter an abandoned barracks.");
X		    break;
X#endif
X#ifdef ORACLE
X		case DELPHI:
X		    if(monstinroom(&mons[PM_ORACLE], roomno))
X			    pline("\"Hello, %s, welcome to Delphi!\"", plname);
X		    break;
X#endif
X		default:
X		    rt = 0;
X		}
X
X		if(rt != 0) {
X		    rooms[roomno].rtype = OROOM;
X		    if(rt==COURT || rt==SWAMP || rt==MORGUE || rt==ZOO)
X			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X			    /* was if(rt != ZOO || !rn2(3)) -- why should ZOO
X			       be different from COURT or MORGUE? */
X			    if(!Stealth && !rn2(3))
X				mtmp->msleep = 0;
X		}
X	}
X#if defined(ALTARS) && defined(THEOLOGY)
X	if(roomno >= 0 && rooms[roomno].rtype == TEMPLE) {
X	    intemple();
X	}
X#endif
X	/* Did we just enter a shop? */
X	if(roomno >= 0 && rooms[roomno].rtype >= SHOPBASE) {
X	    register int rt = rooms[roomno].rtype;
X
X	    if(shlevel != dlevel || !shopkeeper
X				 || ESHK(shopkeeper)->shoproom != roomno)
X		findshk(roomno);
X	    if(!shopkeeper) {
X		rooms[roomno].rtype = OROOM;
X		u.uinshop = 0;
X	    } else if(!u.uinshop){
X		if(!ESHK(shopkeeper)->visitct ||
X		   strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)) {
X		    /* He seems to be new here */
X		    ESHK(shopkeeper)->visitct = 0;
X		    ESHK(shopkeeper)->following = 0;
X		    (void) strncpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
X		    NOTANGRY(shopkeeper) = 1;
X		}
X		if(!ESHK(shopkeeper)->following && inhishop(shopkeeper)) {
X		    if(Invis) {
X			pline("%s senses your presence.", shkname(shopkeeper));
X			verbalize("Invisible customers are not welcome!");
X		    }
X		    else
X		    if(ANGRY(shopkeeper))
X			pline("\"So, %s, you dare return to %s's %s?!\"",
X			    plname,
X			    shkname(shopkeeper),
X			    shtypes[rt - SHOPBASE].name);
X		    else
X		    if(ESHK(shopkeeper)->robbed)
X			pline("\"Beware, %s!  I am upset about missing stock!\"",
X			    plname);
X		    else
X			pline("\"Hello, %s!  Welcome%s to %s's %s!\"",
X			    plname,
X			    ESHK(shopkeeper)->visitct++ ? " again" : "",
X			    shkname(shopkeeper),
X			    shtypes[rt - SHOPBASE].name);
X		    if(carrying(PICK_AXE) != (struct obj *)0 && !Invis) {
X			verbalize(NOTANGRY(shopkeeper) ?
X			   "Will you please leave your pick-axe outside?" :
X			   "Leave the pick-axe outside.");
X			if(dochug(shopkeeper)) {
X			    u.uinshop = 0;	/* he died moving */
X			    return(0);
X			}
X		    }
X		}
X		u.uinshop = (unsigned int)(roomno + 1);
X	    }
X	}
X	return (int)u.uinshop;
X}
X
X#endif /* OVL1 */
X#ifdef OVLB
X
Xint
Xinhishop(mtmp)
Xregister struct monst *mtmp;
X{
X	return((ESHK(mtmp)->shoproom == inroom(mtmp->mx, mtmp->my) &&
X		ESHK(mtmp)->shoplevel == dlevel));
X}
X
X#ifdef SOUNDS
Xboolean
Xtended_shop(sroom)
Xstruct mkroom *sroom;
X{
X	register struct monst *mtmp;
X
X	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X	    if(mtmp->isshk && &rooms[ESHK(mtmp)->shoproom] == sroom
X		&& inhishop(mtmp)) return(TRUE);
X	return(FALSE);
X}
X#endif
X
XSTATIC_OVL void
Xfindshk(roomno)
Xregister int roomno;
X{
X	register struct monst *mtmp;
X
X	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X	    if(mtmp->isshk && ESHK(mtmp)->shoproom == roomno
X			   && ESHK(mtmp)->shoplevel == dlevel) {
X		shopkeeper = mtmp;
X		bill = &(ESHK(shopkeeper)->bill[0]);
X		shlevel = dlevel;
X		if(ANGRY(shopkeeper) &&
X		   strncmp(ESHK(shopkeeper)->customer,plname,PL_NSIZ))
X			NOTANGRY(shopkeeper) = 1;
X		/* billobjs = 0; -- this is wrong if we save in a shop */
X		/* (and it is harmless to have too many things in billobjs) */
X		return;
X	}
X	shopkeeper = 0;
X	shlevel = 0;
X	bill = (struct bill_x *) -1000;	/* dump core when referenced */
X}
X
Xstatic struct bill_x *
Xonbill(obj)
Xregister struct obj *obj;
X{
X	register struct bill_x *bp;
X	if(!shopkeeper) return (struct bill_x *)0;
X	for(bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++)
X		if(bp->bo_id == obj->o_id) {
X			if(!obj->unpaid) pline("onbill: paid obj on bill?");
X			return(bp);
X		}
X	if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
X	return (struct bill_x *)0;
X}
X
X/* called with two args on merge */
Xvoid
Xobfree(obj, merge)
Xregister struct obj *obj, *merge;
X{
X	register struct bill_x *bp = onbill(obj);
X	register struct bill_x *bpm;
X	if(bp) {
X		if(!merge){
X			bp->useup = 1;
X			obj->unpaid = 0;	/* only for doinvbill */
X			obj->nobj = billobjs;
X			billobjs = obj;
X			return;
X		}
X		bpm = onbill(merge);
X		if(!bpm){
X			/* this used to be a rename */
X			impossible("obfree: not on bill??");
X			return;
X		} else {
X			/* this was a merger */
X			bpm->bquan += bp->bquan;
X			ESHK(shopkeeper)->billct--;
X			*bp = bill[ESHK(shopkeeper)->billct];
X		}
X	}
X	free((genericptr_t) obj);
X}
X
Xstatic long
Xcheck_credit(tmp, shkp)
Xlong tmp;
Xregister struct monst *shkp;
X{
X	long credit = ESHK(shkp)->credit;
X
X	if(credit == 0L) return(tmp);
X	if(credit >= tmp) {
X		pline("The price is deducted from your credit.");
X		ESHK(shkp)->credit -=tmp;
X		tmp = 0L;
X	} else {
X		pline("The price is partially covered by your credit.");
X		ESHK(shkp)->credit = 0L;
X		tmp -= credit;
X	}
X	return(tmp);
X}
X
Xstatic void
Xpay(tmp,shkp)
Xlong tmp;
Xregister struct monst *shkp;
X{
X	long robbed = ESHK(shkp)->robbed;
X	long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp));
X
X	u.ugold -= balance;
X	shkp->mgold += balance;
X	flags.botl = 1;
X	if(robbed) {
X		robbed -= tmp;
X		if(robbed < 0) robbed = 0L;
X		ESHK(shkp)->robbed = robbed;
X	}
X}
X
X/* return shkp to home position */
Xvoid
Xhome_shk(shkp)
Xregister struct monst *shkp;
X{
X	register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
X	if(MON_AT(x, y))
X		mnearto(m_at(x,y), x, y, FALSE);
X	remove_monster(shkp->mx, shkp->my);
X	place_monster(shkp, x, y);
X	unpmon(shkp);
X}
X
Xvoid
Xmake_happy_shk(shkp)
Xstruct monst *shkp;
X{
X	register boolean wasmad = ANGRY(shkp);
X
X	NOTANGRY(shkp) = 1;
X	ESHK(shkp)->following = 0;
X	ESHK(shkp)->robbed = 0L;
X	if (pl_character[0] != 'R')
X		adjalign(sgn(u.ualigntyp));
X	if(!inhishop(shkp)) {
X		pline("Satisfied, %s suddenly disappears!", mon_nam(shkp));
X		if(ESHK(shkp)->shoplevel == dlevel)
X			home_shk(shkp);
X		else
X			fall_down(shkp, ESHK(shkp)->shoplevel);
X	} else if(wasmad)
X		pline("%s calms down.", Monnam(shkp));
X#ifdef KOPS
X	kops_gone();
X#endif
X}
X
Xstatic const char no_money[] = "Moreover, you have no money.";
X
Xint
Xdopay()
X{
X	long ltmp;
X	register struct bill_x *bp;
X	register struct monst *shkp;
X	int pass, tmp;
X
X	multi = 0;
X	(void) inshop();
X	for(shkp = fmon; shkp; shkp = shkp->nmon)
X		if(shkp->isshk && dist(shkp->mx,shkp->my) < 3)
X			break;
X	if(!shkp && u.uinshop && inhishop(shopkeeper))
X		shkp = shopkeeper;
X
X	if(!shkp) {
X		pline("There is nobody here to receive your payment.");
X		return(0);
X	}
X	ltmp = ESHK(shkp)->robbed;
X	if(shkp != shopkeeper && NOTANGRY(shkp)) {
X		if(!ltmp)
X		    You("do not owe %s anything.", mon_nam(shkp));
X		else if(!u.ugold)
X		    You("have no money.");
X		else {
X		    long ugold = u.ugold;
X
X		    if(ugold > ltmp) {
X			You("give %s the %ld gold piece%s %s asked for.",
X			    mon_nam(shkp), ltmp, plur(ltmp),
X			    ESHK(shkp)->ismale ? "he" : "she");
X			pay(ltmp, shkp);
X		    } else {
X			You("give %s all your gold.", mon_nam(shkp));
X			pay(u.ugold, shkp);
X		    }
X		    if(ugold < ltmp/2L)
X			pline("Unfortunately, %s doesn't look satisfied.",
X			    ESHK(shkp)->ismale ? "he" : "she");
X		    else
X			make_happy_shk(shkp);
X		}
X		return(1);
X	}
X
X	/* ltmp is still ESHK(shkp)->robbed here */
X	if(!ESHK(shkp)->billct && !ESHK(shkp)->debit) {
X		if(!ltmp && NOTANGRY(shkp)) {
X		    You("do not owe %s anything.", mon_nam(shkp));
X		    if(!u.ugold) pline(no_money);
X		} else if(ltmp) {
X		    pline("%s is after blood, not money!", mon_nam(shkp));
X		    if(u.ugold < ltmp/2L) {
X			if(!u.ugold) pline(no_money);
X			else pline("Besides, you don't have enough to interest %s.",
X				ESHK(shkp)->ismale ? "him" : "her");
X			return(1);
X		    }
X		    pline("But since %s shop has been robbed recently,",
X			ESHK(shkp)->ismale ? "his" : "her");
X		    pline("you %scompensate %s for %s losses.",
X			(u.ugold < ltmp) ? "partially " : "",
X			mon_nam(shkp),
X			ESHK(shkp)->ismale ? "his" : "her");
X		    pay(u.ugold < ltmp ? u.ugold : ltmp, shkp);
X		    make_happy_shk(shkp);
X		} else {
X		    /* shopkeeper is angry, but has not been robbed --
X		     * door broken, attacked, etc. */
X		    pline("%s is after your hide, not your money!",
X					mon_nam(shkp));
X		    if(u.ugold < 1000L) {
X			if(!u.ugold) pline(no_money);
X			else
X		pline("Besides, you don't have enough to interest %s.",
X				ESHK(shkp)->ismale ? "him" : "her");
X			return(1);
X		    }
X		    You("try to appease %s by giving %s 1000 gold pieces.",
X				a_monnam(shkp, "angry"),
X				ESHK(shkp)->ismale ? "him" : "her");
X		    pay(1000L,shkp);
X		    if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)
X		    		|| rn2(3))
X			make_happy_shk(shkp);
X		    else
X			pline("But %s is as angry as ever.", Monnam(shkp));
X		}
X		return(1);
X	}
X	if(shkp != shopkeeper) {
X		impossible("dopay: not to shopkeeper?");
X		if(shopkeeper) setpaid();
X		return(0);
X	}
X	/* pay debt, if any, first */
X	if(ESHK(shopkeeper)->debit) {
X	        You("owe %s %ld zorkmid%s for the use of merchandise.",
X			shkname(shopkeeper), ESHK(shopkeeper)->debit,
X		        plur(ESHK(shopkeeper)->debit));
X	        if(u.ugold + ESHK(shopkeeper)->credit < 
X					ESHK(shopkeeper)->debit) {
X		    pline("But you don't have enough gold%s.",
X			ESHK(shopkeeper)->credit ? " or credit" : "");
X		    return(1);
X	        } else {
X		    long dtmp = ESHK(shopkeeper)->debit;
X
X		    if(ESHK(shopkeeper)->credit >= dtmp) {
X			ESHK(shopkeeper)->credit -= dtmp;
X			ESHK(shopkeeper)->debit = 0L;
X	                Your("debt is covered by your credit.");
X		    } else if(!ESHK(shopkeeper)->credit) {
X			u.ugold -= dtmp;
X			shopkeeper->mgold += dtmp;
X			ESHK(shopkeeper)->debit = 0L;
X			You("pay that debt.");
X			flags.botl = 1;
X		    } else {
X			dtmp -= ESHK(shopkeeper)->credit;
X			ESHK(shopkeeper)->credit = 0L;
X			u.ugold -= dtmp;
X			shopkeeper->mgold += dtmp;
X			ESHK(shopkeeper)->debit = 0L;
X			pline("That debt is partially offset by your credit.");
X			You("pay the remainder.");
X			flags.botl = 1;
X		    }
X		}
X	}
X	for(pass = 0; pass <= 1; pass++) {
X		tmp = 0;
X		while(tmp < ESHK(shopkeeper)->billct) {
X		    bp = &bill[tmp];
X		    if(!pass && !bp->useup) {
X			tmp++;
X			continue;
X		    }
X		    if(!dopayobj(bp)) return(1);
X#ifdef MSDOS
X		    *bp = bill[--ESHK(shopkeeper)->billct];
X#else
X		    bill[tmp] = bill[--ESHK(shopkeeper)->billct];
X#endif /* MSDOS /**/
X		}
X	}
X	if(!ANGRY(shopkeeper))
X	    pline("\"Thank you for shopping in %s's %s!\"",
X		shkname(shopkeeper),
X		shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype - SHOPBASE].name);
X	return(1);
X}
X
X/* return 1 if paid successfully */
X/*        0 if not enough money */
X/*       -1 if object could not be found (but was paid) */
Xstatic int
Xdopayobj(bp)
Xregister struct bill_x *bp;
X{
X	register struct obj *obj;
X	long ltmp;
X
X	/* find the object on one of the lists */
X	obj = bp_to_obj(bp);
X
X	if(!obj) {
X		impossible("Shopkeeper administration out of order.");
X		setpaid();	/* be nice to the player */
X		return(0);
X	}
X
X	if(!obj->unpaid && !bp->useup){
X		impossible("Paid object on bill??");
X		return(1);
X	}
X	obj->unpaid = 0;
X	ltmp = bp->price * bp->bquan;
X	if(ANGRY(shopkeeper)) ltmp += ltmp/3L;
X	if(u.ugold + ESHK(shopkeeper)->credit < ltmp){
X		You("don't have gold%s enough to pay for %s.",
X			(ESHK(shopkeeper)->credit > 0L) ? " or credit" : "",
X			doname(obj));
X		obj->unpaid = 1;
X		return(0);
X	}
X	pay(ltmp, shopkeeper);
X	You("bought %s for %ld gold piece%s.",
X		doname(obj), ltmp, plur(ltmp));
X	if(bp->useup) {
X		register struct obj *otmp = billobjs;
X		if(obj == billobjs)
X			billobjs = obj->nobj;
X		else {
X			while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
X			if(otmp) otmp->nobj = obj->nobj;
X			else pline("Error in shopkeeper administration.");
X		}
X		free((genericptr_t) obj);
X	}
X	return(1);
X}
X
X/* routine called after dying (or quitting) with nonempty bill or upset shk */
Xboolean
Xpaybill(){
X	register struct monst *mtmp, *mtmp2;
X	register long loss = 0L;
X	register struct obj *otmp;
X	register xchar ox, oy;
X	register boolean take = FALSE;
X	register boolean taken = FALSE;
X
X	for(mtmp = fmon; mtmp; mtmp = mtmp2) {
X	    mtmp2 = mtmp->nmon;
X	    if(mtmp->isshk) {
X		/* for bones: we don't want a shopless shk around */
X		if(ESHK(mtmp)->shoplevel != dlevel) mongone(mtmp);
X		else shopkeeper = mtmp;
X	    }
X	}
X
X	if(!shopkeeper) goto clear;
X
X	/* get one case out of the way: you die in the shop, the */
X	/* shopkeeper is peaceful, nothing stolen, nothing owed. */
X	if(in_shop(u.ux,u.uy) && !IS_DOOR(levl[u.ux][u.uy].typ) &&
X	    !ESHK(shopkeeper)->billct && !ESHK(shopkeeper)->robbed &&
X	    !ESHK(shopkeeper)->debit && inhishop(shopkeeper) && 
X	     NOTANGRY(shopkeeper) && !ESHK(shopkeeper)->following) {
X		pline("%s gratefully inherits all your possessions.",
X				Monnam(shopkeeper));
X		goto clear;
X	}
X
X	if(ESHK(shopkeeper)->billct || ESHK(shopkeeper)->debit ||
X			ESHK(shopkeeper)->robbed) {
X		addupbill();
X		total += ESHK(shopkeeper)->debit;
X		loss = ((total >= ESHK(shopkeeper)->robbed) ? total :
X				ESHK(shopkeeper)->robbed);
X		take = TRUE;
X	}
X
X	if(ESHK(shopkeeper)->following || ANGRY(shopkeeper) || take) {
X		if((loss > u.ugold) || !loss) {
X			pline("%s %sand takes all your possessions.",
X				Monnam(shopkeeper), 
X				(shopkeeper->msleep || shopkeeper->mfrozen) ?
X				"wakes up " : "comes ");
X			taken = TRUE;
X			shopkeeper->mgold += u.ugold;
X			u.ugold = 0L;
X			/* in case bones: make it be for real... */
X			if(!in_shop(u.ux, u.uy) || IS_DOOR(levl[u.ux][u.uy].typ)) {
X			    /* shk.x,shk.y is the position immediately in
X			     * front of the door -- move in one more space
X			     */
X			    ox = ESHK(shopkeeper)->shk.x;
X			    oy = ESHK(shopkeeper)->shk.y;
X			    ox += sgn(ox - ESHK(shopkeeper)->shd.x);
X			    oy += sgn(oy - ESHK(shopkeeper)->shd.y);
X			} else {
X			    ox = u.ux;
X			    oy = u.uy;
X			}
X
X			if (invent) {
X			    for(otmp = invent; otmp; otmp = otmp->nobj)
X				place_object(otmp, ox, oy);
X
X			    /* add to main object list at end so invent is
X			       still good */
X			    if (fobj) {
X				otmp = fobj;
X				while(otmp->nobj)
X				    otmp = otmp->nobj;
X				otmp->nobj = invent;
X			    } else
X				fobj = invent;
X			}
X		} else {
X			u.ugold -= loss;
X			shopkeeper->mgold += loss;
X			pline("%s %sand takes %ld zorkmid%s %sowed %s.",
X			      Monnam(shopkeeper),
X			      (shopkeeper->msleep || shopkeeper->mfrozen) ?
X					"wakes up " : "comes ",
X			      loss,
X			      plur(loss),
X			      strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ) ? "" : "you ",
X			      ESHK(shopkeeper)->ismale ? "him" : "her");
X		}
X
X		/* in case we create bones */
X		if(!inhishop(shopkeeper))
X			home_shk(shopkeeper);
X	}
Xclear:
X	setpaid();
X	return(taken);
X}
X
X/* find obj on one of the lists */
Xstatic struct obj *
Xbp_to_obj(bp)
Xregister struct bill_x *bp;
X{
X	register struct obj *obj;
X	register struct monst *mtmp;
X	register unsigned int id = bp->bo_id;
X
X	if(bp->useup)
X		obj = o_on(id, billobjs);
X	else if(!(obj = o_on(id, invent)) &&
X		!(obj = o_on(id, fobj)) &&
X		!(obj = o_on(id, fcobj))) {
X		    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X			if(obj = o_on(id, mtmp->minvent))
X			    break;
X		    for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
X			if(obj = o_on(id, mtmp->minvent))
X			    break;
X		}
X	return(obj);
X}
X
Xstatic unsigned
Xget_cost(obj)
Xregister struct obj *obj;
X{
X	register unsigned tmp;
X
X	tmp = getprice(obj);
X	if (!tmp) tmp = 5;
X	if (ANGRY(shopkeeper) || 
X		(pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
X#ifdef SHIRT
X	    || (uarmu && !uarm) /* wearing just a Hawaiian shirt */
X#endif
X	   )
X		tmp += tmp/3;
X	if (ACURR(A_CHA) > 18)		tmp /= 2;
X	else if (ACURR(A_CHA) > 17)	tmp = (tmp * 2)/3;
X	else if (ACURR(A_CHA) > 15)	tmp = (tmp * 3)/4;
X	else if (ACURR(A_CHA) < 6)	tmp *= 2;
X	else if (ACURR(A_CHA) < 8)	tmp = (tmp * 3)/2;
X	else if (ACURR(A_CHA) < 11)	tmp = (tmp * 4)/3;
X	if (!tmp) return 1;
X	return(tmp);
X}
X
X
X/* called in hack.c when we pickup an object */
Xvoid
Xaddtobill(obj, ininv)
Xregister struct obj *obj;
Xregister boolean ininv;
X{
X	register struct bill_x *bp;
X	char	buf[40];
X	if(!shopkeeper || !inhishop(shopkeeper)) return;
X
X	if(!costly_spot(obj->ox,obj->oy) ||	/* either pickup or kick */
X		onbill(obj) /* perhaps we threw it away earlier */
X	      ) return;
X	if(ESHK(shopkeeper)->billct == BILLSZ) {
X		You("got that for free!");
X		return;
X	}
X	/* To recognize objects the shopkeeper is not interested in. -dgk
X	 */
X	if (obj->no_charge) {
X		obj->no_charge = 0;
X		return;
X	}
X	bp = &bill[ESHK(shopkeeper)->billct];
X	bp->bo_id = obj->o_id;
X	bp->bquan = obj->quan;
X	bp->useup = 0;
X	bp->price = get_cost(obj);
X	if(!shopkeeper->msleep && !shopkeeper->mfrozen) {
X	    Strcpy(buf, "\"For you, ");
X	    if (ANGRY(shopkeeper)) Strcat(buf, "scum ");
X	    else {
X	        switch(rnd(4)
X#ifdef HARD
X		   + u.udemigod
X#endif
X				) {
X		case 1:	Strcat(buf, "good");
X			break;
X		case 2:	Strcat(buf, "honored");
X			break;
X		case 3:	Strcat(buf, "most gracious");
X			break;
X		case 4:	Strcat(buf, "esteemed");
X			break;
X		case 5: if (u.ualigntyp == U_CHAOTIC) Strcat(buf, "un");
X			Strcat(buf, "holy");
X			break;
X	        }
X#ifdef POLYSELF
X	        if(!is_human(uasmon)) Strcat(buf, " creature");
X	        else
X#endif
X		    Strcat(buf, (flags.female) ? " lady" : " sir");
X	    }
X	    obj->dknown = 1; /* after all, the shk is telling you what it is */
X	    if(ininv) {
X		obj->quan = 1; /* fool xname() into giving singular */
X		pline("%s; only %d %s %s.\"", buf, bp->price,
X			(bp->bquan > 1) ? "per" : "for this", xname(obj));
X		obj->quan = bp->bquan;
X	    } else pline("The %s will cost you %d zorkmid%s%s.",
X			xname(obj), bp->price, plur((long)bp->price),
X			(bp->bquan > 1) ? " each" : "");
X	} else pline("The list price of %s is %d zorkmid%s%s.",
X			xname(obj), bp->price, plur((long)bp->price),
X			(bp->bquan > 1) ? " each" : "");
X	ESHK(shopkeeper)->billct++;
X	obj->unpaid = 1;
X}
X
Xvoid
Xsplitbill(obj, otmp)
Xregister struct obj *obj, *otmp;
X{
X	/* otmp has been split off from obj */
X	register struct bill_x *bp;
X	register int tmp;
X	bp = onbill(obj);
X	if(!bp) {
X		impossible("splitbill: not on bill?");
X		return;
X	}
X	if(bp->bquan < otmp->quan) {
X		impossible("Negative quantity on bill??");
X	}
X	if(bp->bquan == otmp->quan) {
X		impossible("Zero quantity on bill??");
X	}
X	bp->bquan -= otmp->quan;
X
X	if(ESHK(shopkeeper)->billct == BILLSZ) otmp->unpaid = 0;
X	else {
X		tmp = bp->price;
X		bp = &bill[ESHK(shopkeeper)->billct];
X		bp->bo_id = otmp->o_id;
X		bp->bquan = otmp->quan;
X		bp->useup = 0;
X		bp->price = tmp;
X		ESHK(shopkeeper)->billct++;
X	}
X}
X
Xvoid
Xsubfrombill(obj)
Xregister struct obj *obj;
X{
X	register struct bill_x *bp;
X
X	if(!shopkeeper) return;
X
X	if((bp = onbill(obj)) != 0) {
X		register struct obj *otmp;
X
X		obj->unpaid = 0;
X		if(bp->bquan > obj->quan){
X			otmp = newobj(0);
X			*otmp = *obj;
X			bp->bo_id = otmp->o_id = flags.ident++;
X			otmp->quan = (bp->bquan -= obj->quan);
X			otmp->owt = 0;	/* superfluous */
X			otmp->onamelth = 0;
X			bp->useup = 1;
X			otmp->nobj = billobjs;
X			billobjs = otmp;
X			return;
X		}
X		ESHK(shopkeeper)->billct--;
X		*bp = bill[ESHK(shopkeeper)->billct];
X		return;
X	} else if (obj->unpaid) {
X		impossible("subfrombill: unpaid object not on bill");
X		obj->unpaid = 0;
X	}
X}
X
Xvoid
Xsellobj(obj)
Xregister struct obj *obj;
X{
X	long ltmp;
X
X	if(!costly_spot(u.ux,u.uy))
X		return;
X	if(obj->unpaid) {
X		subfrombill(obj);
X		return;
X	}
X	/* you dropped something of your own - probably want to sell it */
X	if(shopkeeper->msleep || !shopkeeper->mcanmove || !inhishop(shopkeeper))
X		return;
X	ltmp = (long) getprice(obj) * (long) obj->quan;
X	if (ANGRY(shopkeeper) || (pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
X#ifdef SHIRT
X	    || (uarmu && !uarm) /* wearing just a Hawaiian shirt */
X#endif
X	   ) {
X		ltmp /= 3L;
X		NOTANGRY(shopkeeper) = 1;
X	} else	ltmp /= 2L;
X	if(ESHK(shopkeeper)->billct == BILLSZ
X	   || !saleable(rooms[ESHK(shopkeeper)->shoproom].rtype-SHOPBASE, obj)
X	   || obj->olet == BALL_SYM || ltmp == 0L
X	   || (obj->olet == FOOD_SYM && obj->oeaten)) {
X		pline("%s seems not interested.", Monnam(shopkeeper));
X		obj->no_charge = 1;
X		return;
X	}
X	if(ESHK(shopkeeper)->robbed) {
X		if((ESHK(shopkeeper)->robbed -= ltmp) < 0L)
X			ESHK(shopkeeper)->robbed = 0L;
Xverbalize("Thank you for your contribution to restock this recently plundered shop.");
X		return;
X	}
X	if(ltmp > shopkeeper->mgold)
X		ltmp = shopkeeper->mgold;
X	pay(-ltmp, shopkeeper);
X	if(!ltmp) {
X		pline("%s gladly accepts %s but cannot pay you at present.",
X			Monnam(shopkeeper), doname(obj));
X			obj->no_charge = 1;
X	} else
X	You("sold %s for %ld gold piece%s.", doname(obj), ltmp,
X		plur(ltmp));
X}
X
Xint
Xdoinvbill(mode)
Xint mode;		/* 0: deliver count 1: paged */
X{
X	register struct bill_x *bp;
X	register struct obj *obj;
X#ifdef __GNULINT__
X	long totused, thisused = 0L;
X/* possibly a bug in the GCC; clearly thisused is always set before use */
X#else
X	long totused, thisused;
X#endif
X	char buf[BUFSZ];
X
X	if(mode == 0) {
X	    register int cnt = 0;
X
X	    if(shopkeeper)
X		for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++)
X		    if(bp->useup ||
X		      ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan))
X			cnt++;
X	    return(cnt);
X	}
X
X	if(!shopkeeper) {
X		impossible("doinvbill: no shopkeeper?");
X		return(0);
X	}
X
X	set_pager(0);
X	if(page_line("Unpaid articles already used up:") || page_line(""))
X	    goto quit;
X
X	totused = 0L;
X	for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) {
X	    obj = bp_to_obj(bp);
X	    if(!obj) {
X		impossible("Bad shopkeeper administration.");
X		goto quit;
X	    }
X	    if(bp->useup || bp->bquan > obj->quan) {
X		register int cnt;
X		register unsigned oquan, uquan;
X
X		oquan = obj->quan;
X		uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
X		thisused = bp->price * uquan;
X		totused += thisused;
X		obj->quan = uquan;		/* cheat doname */
X		Sprintf(buf, "x -  %s", doname(obj));
X		obj->quan = oquan;		/* restore value */
X		for(cnt = 0; buf[cnt]; cnt++);
X		while(cnt < 50)
X			buf[cnt++] = ' ';
X		Sprintf(&buf[cnt], " %5ld zorkmid%s", thisused, plur(thisused));
X		if(page_line(buf))
X			goto quit;
X	    }
X	}
X	Sprintf(buf, "Total:%50ld zorkmid%s", totused, plur(totused));
X	if(page_line("") || page_line(buf))
X		goto quit;
X	set_pager(1);
X	return(0);
Xquit:
X	set_pager(2);
X	return(0);
X}
X
X#define HUNGRY	2
Xstatic int
Xgetprice(obj)
Xregister struct obj *obj;
X{
X	register int tmp = objects[obj->otyp].oc_cost;
X
X	switch(obj->olet) {
X	case AMULET_SYM:
X		if(obj->otyp == AMULET_OF_YENDOR) {
X			/* don't let the player get rich selling fakes */
X			tmp = (obj->spe < 0 ? 0 : 3500);
X		}
X		break;
X	case FOOD_SYM:
X		/* simpler hunger check, (2-4)*cost */
X		if (u.uhs >= HUNGRY) tmp *= u.uhs;
X		if (obj->oeaten) tmp = eaten_stat(tmp, obj); /* partly eaten */
X		break;
X	case WAND_SYM:
X		if (obj->spe == -1) tmp = 0;
X		break;
X	case POTION_SYM:
X		if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed)
X			tmp = 0;
X		break;
X	case ARMOR_SYM:
X	case WEAPON_SYM:
X		if (obj->spe > 0) tmp += 10 * obj->spe;
X		break;
X	case CHAIN_SYM:
X		pline("Strange... carrying a chain?");
X		break;
X	}
X	return(tmp);
X}
X
Xint
Xshkcatch(obj)
Xregister struct obj *obj;
X{
X	register struct monst *shkp = shopkeeper;
X
X	if(obj->otyp != PICK_AXE) return(0);
X	if(u.uinshop && shkp && shkp->mcanmove && !shkp->msleep &&
X	    inroom(u.ux+u.dx, u.uy+u.dy) + 1 == u.uinshop &&
X	    shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y &&
X	    u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y) {
X		pline("%s nimbly catches the %s.", Monnam(shkp), xname(obj));
X		obj->nobj = shkp->minvent;
X		shkp->minvent = obj;
X		subfrombill(obj);
X		return(1);
X	}
X	return(0);
X}
X
X/*
X * shk_move: return 1: he moved  0: he didn't  -1: let m_move do it  -2: died
X */
Xint
Xshk_move(shkp)
Xregister struct monst *shkp;
X{
X	register xchar gx,gy,omx,omy;
X	register int udist;
X	register schar appr;
X	int z;
X	schar shkroom;
X	boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv;
X
X	omx = shkp->mx;
X	omy = shkp->my;
X
X	if((udist = dist(omx,omy)) < 3 &&
X	   (shkp->data != &mons[PM_GRID_BUG] || (omx==u.ux || omy==u.uy))) {
X		if(ANGRY(shkp)) {
X			if(Displaced)
X			  Your("displaced image doesn't fool %s!",
X				Monnam(shkp));
X			(void) mattacku(shkp);
X			return(0);
X		}
X		if(ESHK(shkp)->following) {
X			if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)) {
X			    pline("\"Hello, %s!  I was looking for %s.\"",
X				    plname, ESHK(shkp)->customer);
X				    ESHK(shkp)->following = 0;
X			    return(0);
X			}
X			if(moves > followmsg+4) {
X			    pline("\"Hello, %s!  Didn't you forget to pay?\"",
X				    plname);
X			    followmsg = moves;
X#ifdef HARD
X			    if (!rn2(4)) {
X	    pline ("%s doesn't like customers who don't pay.", Monnam(shkp));
X				NOTANGRY(shkp) = 0;
X			    }
X#endif
X			}
X			if(udist < 2)
X			    return(0);
X		}
X	}
X
X	shkroom = inroom(omx,omy);
X	appr = 1;
X	gx = ESHK(shkp)->shk.x;
X	gy = ESHK(shkp)->shk.y;
X	satdoor = (gx == omx && gy == omy);
X	if(ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){
X		gx = u.ux;
X		gy = u.uy;
X		if(shkroom < 0 || shkroom != inroom(u.ux,u.uy))
X		    if(udist > 4)
X			return(-1);	/* leave it to m_move */
X	} else if(ANGRY(shkp)) {
X		long saveBlind = Blinded;
X		struct obj *saveUblindf = ublindf;
X		Blinded = 0;
X		ublindf = (struct obj *)0;
X		if(shkp->mcansee && !Invis && cansee(omx,omy)) {
X			gx = u.ux;
X			gy = u.uy;
X		}
X		Blinded = saveBlind;
X		ublindf = saveUblindf;
X		avoid = FALSE;
X	} else {
X#define	GDIST(x,y)	(dist2(x,y,gx,gy))
X		if(Invis)
X		    avoid = FALSE;
X		else {
X		    uondoor = (u.ux == ESHK(shkp)->shd.x &&
X				u.uy == ESHK(shkp)->shd.y);
X		    if(uondoor) {
X			if((ESHK(shkp)->billct || ESHK(shkp)->debit) 
X					&& inhishop(shkp))
X			    pline(NOTANGRY(shkp) ?
X				"\"Hello, %s!  Will you please pay before leaving?\"" :
X				"\"Hey, %s!  Don't leave without paying!\"",
X				plname);
X			badinv = (!!carrying(PICK_AXE));
X			if(satdoor && badinv)
X			    return(0);
X			avoid = !badinv;
X		    } else {
X			avoid = (u.uinshop && dist(gx,gy) > 8);
X			badinv = FALSE;
X		    }
X
X		    if(((!ESHK(shkp)->robbed && !ESHK(shkp)->billct &&
X				!ESHK(shkp)->debit) || avoid)
X			&& GDIST(omx,omy) < 3) {
X			if(!badinv && !online(omx,omy))
X			    return(0);
X			if(satdoor)
X			    appr = gx = gy = 0;
X		    }
X		}
X	}
X	
X	return(move_special(shkp,shkroom,appr,uondoor,avoid,omx,omy,gx,gy));
X}
X
X#endif /* OVLB */
X#ifdef OVL0
X
Xint
Xonline(x,y)		/*	New version to speed things up.
X			 *	Compiler dependant, may not always work.
X			 */
Xregister xchar x, y;
X{
X	return((x-=u.ux) == 0 || (y-=u.uy) == 0 || x == y || (x+=y) == 0);
X}
X
X/*			Original version, just in case...
X *online(x,y) {
X *	return(x==u.ux || y==u.uy || (x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
X *}
X */
X
X#endif /* OVL0 */
X#ifdef OVLB
X
X/* for use in levl_follower (mondata.c) */
Xboolean
Xis_fshk(mtmp)
Xregister struct monst *mtmp;
X{
X	return(mtmp->isshk && ESHK(mtmp)->following);
X}
X
X/* He is digging in the shop. */
Xvoid
Xshopdig(fall)
Xregister int fall;
X{
X    if(!shopkeeper) return;
X    if(!inhishop(shopkeeper)) {
X	if (pl_character[0] == 'K') adjalign(-sgn(u.ualigntyp));
X	return;
X    }
X
X    if(!fall) {
X	if(u.utraptype == TT_PIT)
X	    pline("\"Be careful, %s, or you might fall through the floor.\"",
X		flags.female ? "madam" : "sir");
X	else
X	    pline("\"%s, do not damage the floor here!\"",
X			flags.female ? "Madam" : "Sir");
X	if (pl_character[0] == 'K') adjalign(-sgn(u.ualigntyp));
X    } else 
X	if(!um_dist(shopkeeper->mx, shopkeeper->my, 5) &&
X	      !shopkeeper->msleep && shopkeeper->mcanmove &&
X	      (ESHK(shopkeeper)->billct || ESHK(shopkeeper)->debit)) {
X	    register struct obj *obj, *obj2;
X
X	    if(dist(shopkeeper->mx, shopkeeper->my) > 2) {
X		mnexto(shopkeeper);
X		/* for some reason he can't come next to you */
X		if(dist(shopkeeper->mx, shopkeeper->my) > 2) {
X		    pline("%s curses you in anger and frustration!",
X					shkname(shopkeeper));
X		    NOTANGRY(shopkeeper) = 0;
X		    return;
X		} else pline("%s leaps, and grabs your backpack!",
X					shkname(shopkeeper));
X	    } else pline("%s grabs your backpack!", shkname(shopkeeper));
X
X	    for(obj = invent; obj; obj = obj2) {
X		obj2 = obj->nobj;
X		if(obj->owornmask) continue;
X#ifdef WALKIES
X		if(obj->otyp == LEASH && obj->leashmon) continue;
X#endif
X		freeinv(obj);
X		obj->nobj = shopkeeper->minvent;
X		shopkeeper->minvent = obj;
X		subfrombill(obj);
X	    }
X    }
X}
X
X#ifdef KOPS
XSTATIC_OVL int
Xmakekops(mm)		/* returns the number of (all types of) Kops  made */
Xcoord *mm;
X{
X	register int cnt = dlevel + rnd(5);
X	register int scnt = (cnt / 3) + 1;	/* at least one sarge */
X	register int lcnt = (cnt / 6);		/* maybe a lieutenant */
X	register int kcnt = (cnt / 9);		/* and maybe a kaptain */
X
X	while(cnt--) {
X	    if (enexto(mm, mm->x, mm->y, &mons[PM_KEYSTONE_KOP]))
X		    (void) makemon(&mons[PM_KEYSTONE_KOP], mm->x, mm->y);
X	}
X	while(scnt--) {
X	    if (enexto(mm, mm->x, mm->y, &mons[PM_KOP_SERGEANT]))
X		    (void) makemon(&mons[PM_KOP_SERGEANT], mm->x, mm->y);
X	}
X	while(lcnt--) {
X	    if (enexto(mm, mm->x, mm->y, &mons[PM_KOP_LIEUTENANT]))
X		    (void) makemon(&mons[PM_KOP_LIEUTENANT], mm->x, mm->y);
X	}
X	while(kcnt--) {
X	    if (enexto(mm, mm->x, mm->y, &mons[PM_KOP_KAPTAIN]))
X		    (void) makemon(&mons[PM_KOP_KAPTAIN], mm->x, mm->y);
X	}
X	return(cnt + scnt + lcnt + kcnt);
X}
X#endif
X
X#endif /* OVLB */
X#ifdef OVL1
X
Xboolean
Xin_shop(x,y)
Xregister int x, y;
X{
X	register int roomno = inroom(x, y);
X
X	if (roomno < 0) return(FALSE);
X	return (IS_SHOP(rooms[roomno]));
X}
X
X#endif /* OVL1 */
X#ifdef OVLB
X
Xvoid
Xpay_for_door(x,y,dmgstr)
Xint x, y;
Xconst char *dmgstr;
X{
X	struct monst *mtmp;
X	int roomno = inroom(x, y);
X	long damage;
X	boolean uinshp = in_shop(u.ux, u.uy);
X
X	/* make sure this function is not used in the wrong place */
X	if(!(IS_DOOR(levl[x][y].typ) && in_shop(x, y))) return;
X
X	findshk(roomno);
X
X	if(!shopkeeper) return;
X
X	/* not the best introduction to the shk... */
X	(void) strncpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
X
X	/* if he is already on the war path, be sure it's all out */
X	if(ANGRY(shopkeeper) || ESHK(shopkeeper)->following) {
X		NOTANGRY(shopkeeper) = 0;
X		ESHK(shopkeeper)->following = 1;
X		return;
X	}
X
X	/* if he's not in his shop.. */
X	if(!in_shop(shopkeeper->mx ,shopkeeper->my)) {
X		if(!cansee(shopkeeper->mx, shopkeeper->my)) return;
X		goto gethim;
X	}
X
X	if(uinshp) {
X		if(um_dist(shopkeeper->mx, shopkeeper->my, 1) &&
X		       !um_dist(shopkeeper->mx, shopkeeper->my, 3)) { 
X		    pline("%s leaps towards you!", shkname(shopkeeper));
X		    mnexto(shopkeeper);
X		}
X		if(um_dist(shopkeeper->mx, shopkeeper->my, 1)) goto gethim;
X	} else {
X	    /* if a !shopkeeper shows up at the door, move him */
X	    if((mtmp = m_at(x, y)) && mtmp != shopkeeper) {
X		if(flags.soundok) {
X		    You("hear an angry voice:");
X		    verbalize("Out of my way, scum!");
X		    (void) fflush(stdout);
X#if defined(SYSV) || defined(ULTRIX) || defined(VMS)
X		    (void)
X#endif
X#if defined(UNIX) || defined(VMS)
X			sleep(1);
X#endif
X		}
X		mnearto(mtmp, x, y, FALSE);
X	    }
X
X	    /* make shk show up at the door */
X	    remove_monster(shopkeeper->mx, shopkeeper->my);
X	    place_monster(shopkeeper, x, y);
X	    pmon(shopkeeper);
X	}
X
X	if(!strcmp(dmgstr, "destroy")) damage = 400L;
X	else damage = (long)(ACURR(A_STR) > 18) ? 400 : 20 * ACURR(A_STR);
X
X	if((um_dist(x, y, 1) && !uinshp) || 
X			(u.ugold + ESHK(shopkeeper)->credit) < damage 
X				|| !rn2(50)) {
X		if(um_dist(x, y, 1) && !uinshp) {
X		    pline("%s shouts:", shkname(shopkeeper));
X		    pline("\"Who dared %s my door?\"", dmgstr);
X		} 
X		else
Xgethim:
X		    pline("\"How dare you %s my door?\"", dmgstr);
X
X		NOTANGRY(shopkeeper) = 0;
X		ESHK(shopkeeper)->following = 1;
X		return;
X	}
X
X	if(Invis) Your("invisibility does not fool %s!", shkname(shopkeeper));
X	pline("\"Cad!  You did %ld zorkmids worth of damage!\"  Pay? ", damage);
X	if(yn() != 'n') {
X		damage = check_credit(damage, shopkeeper);
X		u.ugold -= damage;
X		shopkeeper->mgold += damage;
X		flags.botl = 1;
X		pline("Mollified, %s accepts your restitution.",
X			shkname(shopkeeper));
X		/* move shk back to his home loc */
X		home_shk(shopkeeper);
X		NOTANGRY(shopkeeper) = 1;
X	} else {
X		verbalize("Oh, yes!  You'll pay!");
X		ESHK(shopkeeper)->following = 1;
X		NOTANGRY(shopkeeper) = 0;
X		adjalign(-sgn(u.ualigntyp));
X	}
X}
X
X/* called in dokick.c when we kick an object in a store */
Xboolean
Xcostly_spot(x, y)
Xregister int x, y;
X{
X	register struct monst *shkp = shopkeeper;
X	
X	if(!shkp) return(FALSE);
X
X	return(in_shop(x, y) && levl[x][y].typ != DOOR &&
X		!(x == ESHK(shkp)->shk.x && y == ESHK(shkp)->shk.y));
X}
X
X#ifdef KOPS
Xstatic void
Xkops_gone()
X{
X	register int cnt = 0;
X	register struct monst *mtmp, *mtmp2;
X
X	/* turn off automatic resurrection of kops */
X	allow_kops = FALSE;
X
X	for(mtmp = fmon; mtmp; mtmp = mtmp2) {
X		mtmp2 = mtmp->nmon;
X		if(mtmp->data->mlet == S_KOP) {
X			mongone(mtmp);
X			cnt++;
X		}
X	}
X	if(cnt) pline("The Kops (disappointed) disappear into thin air.");
X	allow_kops = TRUE;
X}
X#endif
X
Xstatic unsigned
Xcost_per_charge(otmp)
Xregister struct obj *otmp;
X{
X	register unsigned tmp = get_cost(otmp);
X
X	/* The idea is to make the exhaustive use of */
X	/* an unpaid item more expensive than buying */
X	/* outright.				     */
X	if(otmp->otyp == MAGIC_LAMP) {			 /* 1 */
X		tmp += (tmp/3);
X	} else if(otmp->otyp == MAGIC_MARKER) {  	 /* 70 - 100 */
X		/* no way to determine in advance   */
X		/* how many charges will be wasted. */
X		/* so, arbitrarily, one half of the */
X		/* price per use.		    */
X		tmp = (tmp/2);
X	} else if(otmp->otyp == BAG_OF_TRICKS) { 	 /* 1 - 20 */
X		tmp = (tmp/5);
X	} else if(otmp->otyp == CRYSTAL_BALL ||  	 /* 1 - 5 */
X		  otmp->otyp == LAMP ||	                 /* 1-10 */
X#ifdef MUSIC
X		 (otmp->otyp >= MAGIC_FLUTE &&
X		  otmp->otyp <= DRUM_OF_EARTHQUAKE) || 	 /* 5 - 9 */
X#endif
X	  	  otmp->olet == WAND_SYM) {		 /* 3 - 11 */
X		if(otmp->spe > 1) tmp = (tmp/4);
X	}
X	else return(0);
X	return(tmp);
X}
X
X/* for using charges of unpaid objects */
Xvoid
Xcheck_unpaid(otmp)
Xregister struct obj *otmp;
X{
X	if(!in_shop(u.ux, u.uy)) return;
X	
X	if(otmp->spe <= 0) return;
X
X	if(otmp->unpaid) {
X		ESHK(shopkeeper)->debit += cost_per_charge(otmp);
X	}
X}
X
Xboolean
Xblock_door(x,y)  	/* used in domove to block diagonal shop-exit */
Xregister int x, y;
X{
X	register int roomno = inroom(x, y);
X
X	if(!in_shop(u.ux, u.uy)) return(FALSE);
X
X	if(!IS_DOOR(levl[x][y].typ)) return(FALSE);
X
X	if(roomno != inroom(u.ux,u.uy)) return(FALSE);
X
X	findshk(roomno);
X
X	if(inhishop(shopkeeper)
X	    && shopkeeper->mx == ESHK(shopkeeper)->shk.x
X	    && shopkeeper->my == ESHK(shopkeeper)->shk.y
X	    /* Actually, the shk should be made to block _any_ */
X	    /* door, including a door the player digs, if the  */
X	    /* shk is within a 'jumping' distance.	       */
X	    && ESHK(shopkeeper)->shd.x == x && ESHK(shopkeeper)->shd.y == y
X	    && shopkeeper->mcanmove && !shopkeeper->msleep
X	    && (ESHK(shopkeeper)->debit || ESHK(shopkeeper)->billct ||
X		ESHK(shopkeeper)->robbed)) {
X		pline("%s%s blocks your way!", shkname(shopkeeper),
X				Invis ? " senses your motion and" : "");
X		return(TRUE);
X	}
X	return(FALSE);
X}
X
Xboolean
Xblock_entry(x,y)  	/* used in domove to block diagonal shop-entry */
Xregister int x, y;
X{
X	register int sx, sy, roomno = inroom(x, y);
X
X	if(roomno != inroom(u.ux,u.uy)) return(FALSE);
X
X	if(!(in_shop(u.ux, u.uy) && IS_DOOR(levl[u.ux][u.uy].typ) &&
X		levl[u.ux][u.uy].doormask == D_BROKEN)) return(FALSE);
X
X	findshk(roomno);
X	if(!inhishop(shopkeeper)) return(FALSE);
X
X	if(ESHK(shopkeeper)->shd.x != u.ux || ESHK(shopkeeper)->shd.y != u.uy)
X		return(FALSE);
X
X	sx = ESHK(shopkeeper)->shk.x;
X	sy = ESHK(shopkeeper)->shk.y;
X
X	if(shopkeeper->mx == sx && shopkeeper->my == sy
X	    	&& shopkeeper->mcanmove && !shopkeeper->msleep
X	    	&& in_shop(x, y)
X	        && (x == sx-1 || x == sx+1 || y == sy-1 || y == sy+1)  
X	    	&& (Invis || carrying(PICK_AXE))
X          ) {
X		pline("%s%s blocks your way!", shkname(shopkeeper),
X				Invis ? " senses your motion and" : "");
X		return(TRUE);
X	}
X	return(FALSE);
X}
X
X#endif /* OVLB */
END_OF_FILE
if test 42124 -ne `wc -c <'src/shk.c'`; then
    echo shar: \"'src/shk.c'\" unpacked with wrong size!
fi
# end of 'src/shk.c'
fi
echo shar: End of archive 9 \(of 56\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 56 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0