[comp.sources.games] v07i081: NetHack3 - display oriented dungeons & dragons

billr@saab.CNA.TEK.COM (Bill Randle) (07/25/89)

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 7, Issue 81
Archive-name: NetHack3/Part26



#! /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 26 (of 38)."
# Contents:  others/random.c src/engrave.c src/mkobj.c src/shknam.c
# Wrapped by billr@saab on Sun Jul 23 21:33:09 1989
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'\" \(12793 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#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)random.c	5.5 (Berkeley) 7/6/88";
X#endif /* LIBC_SCCS and not lint */
X
X#include <stdio.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
Xsrandom( x )
X
X    unsigned		x;
X{
X    	register  int		i, j;
X	long random();
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;
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 12793 -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/engrave.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/engrave.c'\"
else
echo shar: Extracting \"'src/engrave.c'\" \(13424 characters\)
sed "s/^X//" >'src/engrave.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)engrave.c	3.0	89/06/12
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include	"hack.h"
X
Xstatic void del_engr P((struct engr *));
X
Xstruct engr {
X	struct engr *nxt_engr;
X	char *engr_txt;
X	xchar engr_x, engr_y;
X	unsigned engr_lth;	/* for save & restore; not length of text */
X	long engr_time;	/* moment engraving was (will be) finished */
X	xchar engr_type;
X#define	DUST	1
X#define	ENGRAVE	2
X#define	BURN	3
X#define MARK	4
X#define POLY	5	/* temporary type - for polymorphing engraving */
X} *head_engr;
X
X/* random engravings */
Xconst char *random_engr[] =
X			 {"Elbereth", "ad ae?ar um",
X			 "?la? ?as he??",
X			 /* more added by Eric Backus */
X			 "?ilroy wa? h?re", "?ala??iel",
X			 "Fo? a ?ood time c?ll 6?6-4311",
X			 /* some other famous engravings -3. */
X			 "Lasc?ate o?ni sp?ranz? o vo? c?'en?rate",
X			 "Y?u won?t get i? up ?he ste?s",
X			 "A.S. ->"};
X
Xstatic struct engr *
Xengr_at(x,y) register xchar x,y; {
Xregister struct engr *ep = head_engr;
X	while(ep) {
X		if(x == ep->engr_x && y == ep->engr_y)
X			return(ep);
X		ep = ep->nxt_engr;
X	}
X	return((struct engr *) 0);
X}
X
X#ifdef ELBERETH
Xint
Xsengr_at(s,x,y)
X	register char *s;
X	register xchar x,y;
X{
X	register struct engr *ep = engr_at(x,y);
X	register char *t;
X	register int n;
X
X	if(ep && ep->engr_time <= moves) {
X		t = ep->engr_txt;
X/*
X		if(!strcmp(s,t)) return(1);
X*/
X		n = strlen(s);
X		while(*t) {
X			if(!strncmp(s,t,n)) return(1);
X			t++;
X		}
X	}
X	return(0);
X}
X#endif
X
Xvoid
Xu_wipe_engr(cnt)
Xregister int cnt;
X{
X	if(!u.uswallow && !Levitation)
X		wipe_engr_at(u.ux, u.uy, cnt);
X}
X
Xvoid
Xwipe_engr_at(x,y,cnt) register xchar x,y,cnt; {
Xregister struct engr *ep = engr_at(x,y);
Xregister int lth,pos;
Xchar ch;
X	if(ep){
X	    if(ep->engr_type != BURN) {
X		if(ep->engr_type != DUST) {
X			cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
X		}
X		lth = strlen(ep->engr_txt);
X		if(lth && cnt > 0 ) {
X			while(cnt--) {
X				pos = rn2(lth);
X				if((ch = ep->engr_txt[pos]) == ' ')
X					continue;
X				ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
X			}
X		}
X		while(lth && ep->engr_txt[lth-1] == ' ')
X			ep->engr_txt[--lth] = 0;
X		while(ep->engr_txt[0] == ' ')
X			ep->engr_txt++;
X		if(!ep->engr_txt[0]) del_engr(ep);
X	    }
X	}
X}
X
Xvoid
Xread_engr_at(x,y) register int x,y; {
Xregister struct engr *ep = engr_at(x,y);
Xregister int	canfeel;
X	if(ep && ep->engr_txt[0]) {
X	    switch(ep->engr_type) {
X	    case DUST:
X		if(!Blind) pline("Something is written here in the dust.");
X		canfeel = 0;
X		break;
X	    case ENGRAVE:
X		pline("Something is engraved here on the floor.");
X		canfeel = 1;
X		break;
X	    case BURN:
X		pline("Some text has been burned here in the floor.");
X		canfeel = 1;
X		break;
X	    case MARK:
X		if(!Blind) pline("There's some graffiti here on the floor.");
X		canfeel = 0;
X		break;
X	    default:
X		impossible("Something is written in a very strange way.");
X		canfeel = 1;
X	    }
X	    if (canfeel || !Blind)
X		You("%s: \"%s\".",
X		      (Blind) ? "feel the words" : "read",  ep->engr_txt);
X	}
X}
X
Xvoid
Xmake_engr_at(x,y,s)
Xregister int x,y;
Xregister char *s;
X{
X	register struct engr *ep;
X
X	if(ep = engr_at(x,y))
X	    del_engr(ep);
X	ep = (struct engr *)
X	    alloc((unsigned)(sizeof(struct engr) + strlen(s) + 1));
X	ep->nxt_engr = head_engr;
X	head_engr = ep;
X	ep->engr_x = x;
X	ep->engr_y = y;
X	ep->engr_txt = (char *)(ep + 1);
X	Strcpy(ep->engr_txt, s);
X	ep->engr_time = 0;
X	ep->engr_type = DUST;
X	ep->engr_lth = strlen(s) + 1;
X}
X
X/*
X *	freehand - returns true if player has a free hand
X */
Xint
Xfreehand(){
X
X	return(!uwep ||
X	   !uwep->cursed ||
X	   (!bimanual(uwep) && (!uarms || !uarms->cursed)));
X/*	if ((uwep && bimanual(uwep)) ||
X	    (uwep && uarms))
X		return(0);
X	else
X		return(1);*/
X}
X
Xstatic const char styluses[] = { '#', '-', TOOL_SYM, WEAPON_SYM, WAND_SYM, 0 };
Xstatic const char too_large[] = { ARMOR_SYM, BALL_SYM, ROCK_SYM, 0 };
Xstatic const char paper[] = { SCROLL_SYM,
X#ifdef SPELLS
X	SPBOOK_SYM,
X#endif
X	0 };
X
Xint
Xdoengrave(){
Xregister int len, tmp;
Xregister char *sp, *sptmp;
Xregister struct engr *ep, *oep = engr_at(u.ux,u.uy);
Xchar buf[BUFSZ];
Xxchar type, polytype = 0;
Xint spct;		/* number of leading spaces */
Xregister struct obj *otmp;
X	multi = 0;
X
X	if(u.uswallow) {
X		pline("What would you write?  \"Jonah was here\"?");
X		return(0);
X	}
X
X	/* one may write with finger, weapon or wand */
X	/* edited by GAN 10/20/86 so as not to change
X	 * weapon wielded.
X	 */
X	otmp = getobj(styluses, "write with");
X	if(!otmp) return(0);
X
X	/* There's no reason you should be able to write with a wand
X	 * while both your hands are tied up.
X	 */
X	if (!freehand() && otmp != uwep) {
X		You("have no free %s to write with!", body_part(HAND));
X		return(0);
X	}
X#ifdef POLYSELF
X	if (cantwield(uasmon)) {
X		You("can't even hold anything!");
X		return(0);
X	}
X#endif
X	if(otmp != &zeroobj && index(too_large,otmp->olet)) {
X		You("can't engrave with such a large object!");
X		return(1);
X	}
X
X	if(otmp != &zeroobj && index(paper,otmp->olet)) {
X		Your("%s would get dirty.",xname(otmp));
X		return(1);
X	}
X
X	if(Levitation && otmp->olet != WAND_SYM){		/* riv05!a3 */
X		You("can't reach the floor!");
X		return(0);
X	}
X
X	if(otmp == &zeroobj) {
X		You("write in the dust with your %s.",
X			makeplural(body_part(FINGER)));
X		type = DUST;
X	} else if(otmp->olet == WAND_SYM && zappable(otmp)) {
X		/* changed so any wand gets zapped out, but fire
X		 * wands become known.
X		 */
X		if((objects[otmp->otyp].bits & NODIR))  {
X			zapnodir(otmp);
X			type = DUST;
X		}  else  {
X			switch(otmp->otyp)  {
X			case WAN_LIGHTNING:
X				if(!objects[otmp->otyp].oc_name_known) {
X				    if(flags.verbose)
X					pline("The %s is a wand of lightning!",
X						xname(otmp));
X				    makeknown(otmp->otyp);
X				    more_experienced(0,10);
X				}
X				type = BURN;
X				break;
X			case WAN_FIRE:
X				if(!objects[otmp->otyp].oc_name_known) {
X				    if(flags.verbose)
X					pline("The %s is a wand of fire!",
X					   xname(otmp));
X				    makeknown(otmp->otyp);
X				    more_experienced(0,10);
X				}
X				type = BURN;
X				break;
X			case WAN_DIGGING:
X				if(!objects[otmp->otyp].oc_name_known) {
X				    if(flags.verbose)
X					pline("The %s is a wand of digging!",
X					   xname(otmp));
X				    makeknown(otmp->otyp);
X				    more_experienced(0,10);
X				}
X				type = ENGRAVE;
X				break;
X			case WAN_POLYMORPH:
X				if(oep)  {
X					del_engr(oep);
X					oep = 0;
X					type = POLY;
X				}  else
X					type = DUST;
X				break;
X			case WAN_COLD:
X				type = DUST;
X				if(!oep || (oep->engr_type != BURN))
X					break;
X			case WAN_CANCELLATION:
X			case WAN_MAKE_INVISIBLE:
X				if(!oep) {		/* Eric Backus */
X					type = DUST;
X					break;
X				}
X				del_engr(oep);
X				pline("The engraving on the floor vanishes!");
X				return(1);
X				/* break; */
X			case WAN_TELEPORTATION:
X				if(!oep)
X					type = DUST;
X				else  {
X					register int tx,ty;
X
X					do  {
X						tx = rn1(COLNO-3,2);
X						ty = rn2(ROWNO);
X					}  while(!goodpos(tx,ty));
X					oep->engr_x = tx;
X					oep->engr_y = ty;
X					pline("The engraving on the floor vanishes!");
X					return(1);
X				}
X				break;
X			default:
X				type = DUST;
X			}
X		}
X		if(type == DUST)
X			You("write in the dust with %s.",
X			   doname(otmp));
X
X	} else {
X		if(otmp->otyp == DAGGER ||
X#ifdef WORM
X		   otmp->otyp == CRYSKNIFE ||
X#endif
X		   is_sword(otmp) || otmp->otyp == AXE) {
X			type = ENGRAVE;
X			if((int)otmp->spe <= -3) {
X				Your("%s too dull for engraving.",
X					aobjnam(otmp, "are"));
X				type = DUST;
X				/* following messaged added 10/20/86 - GAN */
X				You("write in the dust with %s.",
X				   doname(otmp));
X			}  else
X				You("engrave with %s.", doname(otmp));
X		} else if(otmp->otyp == MAGIC_MARKER)  {
X			if(otmp->spe <= 0)  {
X				Your("marker is dried out.");
X				You("write in the dust with the marker.");
X				type = DUST;
X			}  else  {
X				You("write with %s.", doname(otmp));
X				type = MARK;
X			}
X		}  else  {
X			You("write in the dust with %s.",
X			   doname(otmp));
X			type = DUST;
X		}
X	}
X
X	if(type != POLY && oep && oep->engr_type == DUST){
X		  You("wipe out the message that was written here.");
X		  del_engr(oep);
X		  oep = 0;
X	}
X	if(type == DUST && oep) {
X	    You("cannot wipe out the message that is %s in the rock.",
X		  (oep->engr_type == BURN) ? "burned" :
X		  (oep->engr_type == ENGRAVE) ? "engraved" : "scribbled");
X		  return(1);
X	}
X	if(type == POLY)  {
X		polytype = rnd(4);
X		Strcpy(buf,random_engr[rn2(SIZE(random_engr))]);
X		switch(polytype){
X		case DUST:
X			pline("\"%s\" is now written on the ground.",buf);
X			break;
X		case ENGRAVE:
X			pline("\"%s\" is now engraved in the rock.",buf);
X			break;
X		case BURN:
X			pline("\"%s\" is now burned in the rock.",buf);
X			break;
X		case MARK:
X			pline("\"%s\" is now scribbled on the rock.",buf);
X			break;
X		default:
X			impossible("\"%s\" is now written in a very strange way.",
X			   buf);
X		}
X	}  else  {
X		pline("What do you want to %s on the floor here? ",
X		  (type == ENGRAVE) ? "engrave" : (type == BURN) ? "burn" : "write");
X		getlin(buf);
X		clrlin();
X	}
X	spct = 0;
X	sp = buf;
X	while(*sp == ' ') spct++, sp++;
X	len = strlen(sp);
X	if(!len || *buf == '\033') {
X		/* changed by GAN 11/01/86 to not recharge wand */
X		return(1);
X	}
X	if(otmp->otyp == WAN_FIRE) {
X		if (!Blind) pline("Flames fly from the wand.");
X		else You("feel the wand heat up.");
X	} else if(otmp->otyp == WAN_LIGHTNING) {
X		if (!Blind) {
X			pline("Lightning arcs from the wand.");
X			You("are blinded by the flash!");
X			make_blinded((long)rnd(50),FALSE);
X		} else You("hear crackling!");
X	} else if(otmp->otyp == WAN_DIGGING) {
X		if (!Blind) pline("Gravel flies up from the floor.");
X		else You("hear drilling!");
X  	}
X		/* kludge by stewr 870708 */
X	for (sptmp = sp, tmp=0; !(tmp == len); sptmp++,tmp++) {
X		if (((type == DUST) && !rn2(25))
X		     || (Blind && !rn2(12))
X		     || (Confusion && !rn2(3))) {
X			 *sptmp = '!' + rn2(93); /* ASCII-code only */
X		       }
X	      }
X
X	switch(type) {
X	case DUST:
X	case BURN:
X		if(len > 15) {
X			multi = -(len/10);
X			nomovemsg = "You finish writing.";
X		}
X		break;
X	case ENGRAVE:
X	case MARK:
X		{	int len2;
X
X			if(type == ENGRAVE)
X				len2 = (otmp->spe + 3) * 2 + 1;
X			else
X				len2 = (otmp->spe) * 2;
X			nomovemsg = "You finish writing.";
X			if(type != MARK)
X			nomovemsg = "You finish engraving.";
X			if(otmp->olet != WAND_SYM)  {
X				if(otmp->olet == WEAPON_SYM)
X					Your("%s dull.",
X					       aobjnam(otmp, "get"));
X				if(len2 < len) {
X					len = len2;
X					sp[len] = 0;
X					if(type == ENGRAVE)  {
X						otmp->spe = -3;
X					}  else  {
X						Your("marker dries out!");
X						otmp->spe = 0;
X					}
X					/* next line added by GAN 10/20/86 */
X					You("only write \"%s\".", sp);
X					nomovemsg = "You cannot write more.";
X				} else
X					otmp->spe -= len >> 1;
X				if(type == MARK)
X					multi = -(len/10);
X				else
X					multi = -len;
X			}  else
X				multi = -(len/10);
X			if (multi == 0)
X				nomovemsg = (char *)0;
X		}
X		break;
X	case POLY:
X		type = polytype;
X		multi = 0;
X		break;
X	}
X	if(oep) len += strlen(oep->engr_txt) + spct;
X	ep = (struct engr *) alloc((unsigned)(sizeof(struct engr) + len + 1));
X	ep->nxt_engr = head_engr;
X	head_engr = ep;
X	ep->engr_x = u.ux;
X	ep->engr_y = u.uy;
X	sp = (char *)(ep + 1);	/* (char *)ep + sizeof(struct engr) */
X	ep->engr_txt = sp;
X	if(oep) {
X		Strcpy(sp, oep->engr_txt);
X		Strcat(sp, buf);
X		del_engr(oep);
X	} else
X		Strcpy(sp, buf);
X	ep->engr_lth = len+1;
X	ep->engr_type = type;
X	ep->engr_time = moves-multi;
X
X	/* kludge to protect pline against excessively long texts */
X	if(len > BUFSZ-20) sp[BUFSZ-20] = 0;
X
X	/* cute messages for odd wands */
X	switch(otmp->otyp)  {
X	case WAN_SLOW_MONSTER:
X		pline("The bugs on the ground slow down!");
X		break;
X	case WAN_SPEED_MONSTER:
X		pline("The bugs on the ground speed up!");
X		break;
X	case WAN_MAGIC_MISSILE:
X		pline("The ground is riddled by bullet holes!");
X		break;
X	case WAN_SLEEP:
X	case WAN_DEATH:	/* can't tell sleep from death - Eric Backus */
X		pline("The bugs on the ground stop moving!");
X		break;
X	case WAN_COLD:
X		pline("A few ice cubes drop from your %s.",xname(otmp));
X		break;
X	case WAN_STRIKING:
X		pline("The %s unsuccessfully fights your attempt to write!",xname(otmp));
X	}
X
X	return(1);
X}
X
Xvoid
Xsave_engravings(fd) int fd; {
Xregister struct engr *ep = head_engr;
Xregister struct engr *ep2;
X	while(ep) {
X	    ep2 = ep->nxt_engr;
X	    if(ep->engr_lth && ep->engr_txt[0]){
X		bwrite(fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
X		bwrite(fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
X	    }
X#if defined(DGK) && !defined(TOS)
X	    if (!count_only)
X#endif
X		free((genericptr_t) ep);
X	    ep = ep2;
X	}
X	bwrite(fd, (genericptr_t)nul, sizeof(unsigned));
X#if defined(DGK) && !defined(TOS)
X	if (!count_only)
X#endif
X		head_engr = 0;
X}
X
Xvoid
Xrest_engravings(fd) int fd; {
Xregister struct engr *ep;
Xunsigned lth;
X	head_engr = 0;
X	while(1) {
X		mread(fd, (genericptr_t) &lth, sizeof(unsigned));
X		if(lth == 0) return;
X		ep = (struct engr *) alloc(sizeof(struct engr) + lth);
X		mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth);
X		ep->nxt_engr = head_engr;
X		ep->engr_txt = (char *) (ep + 1);	/* Andreas Bormann */
X		head_engr = ep;
X	}
X}
X
Xstatic void
Xdel_engr(ep) register struct engr *ep; {
Xregister struct engr *ept;
X	if(ep == head_engr)
X		head_engr = ep->nxt_engr;
X	else {
X		for(ept = head_engr; ept; ept = ept->nxt_engr) {
X			if(ept->nxt_engr == ep) {
X				ept->nxt_engr = ep->nxt_engr;
X				goto fnd;
X			}
X		}
X		impossible("Error in del_engr?");
X		return;
X	fnd:	;
X	}
X	free((genericptr_t) ep);
X}
END_OF_FILE
if test 13424 -ne `wc -c <'src/engrave.c'`; then
    echo shar: \"'src/engrave.c'\" unpacked with wrong size!
fi
# end of 'src/engrave.c'
fi
if test -f 'src/mkobj.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/mkobj.c'\"
else
echo shar: Extracting \"'src/mkobj.c'\" \(12813 characters\)
sed "s/^X//" >'src/mkobj.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)mkobj.c	3.0	88/10/30
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include "hack.h"
X
Xstruct icp {
X    int  iprob; /* probability of an item type */
X    char ilet;	/* item class */
X};
X
Xconst struct icp mkobjprobs[] = {
X{10, WEAPON_SYM},
X{10, ARMOR_SYM},
X{20, FOOD_SYM},
X{ 8, TOOL_SYM},
X{ 8, GEM_SYM},
X#ifdef SPELLS
X{16, POTION_SYM},
X{16, SCROLL_SYM},
X{ 4, SPBOOK_SYM},
X#else
X{18, POTION_SYM},
X{18, SCROLL_SYM},
X#endif
X{ 4, WAND_SYM},
X{ 3, RING_SYM},
X{ 1, AMULET_SYM}};
X
Xconst struct icp boxiprobs[] = {
X{18, GEM_SYM},
X#ifdef SPELLS
X{15, FOOD_SYM},
X{20, POTION_SYM},
X{20, SCROLL_SYM},
X{15, SPBOOK_SYM},
X#else
X{20, FOOD_SYM},
X{25, POTION_SYM},
X{25, SCROLL_SYM},
X#endif
X{ 6, WAND_SYM},
X{ 5, RING_SYM},
X{ 1, AMULET_SYM}};
X
X#ifdef REINCARNATION
Xconst struct icp rogueprobs[] = {
X{12, WEAPON_SYM},
X{12, ARMOR_SYM},
X{22, FOOD_SYM},
X{22, POTION_SYM},
X{22, SCROLL_SYM},
X{ 5, WAND_SYM},
X{ 5, RING_SYM}};
X#endif
X
Xconst struct icp hellprobs[] = {
X{20, WEAPON_SYM},
X{20, ARMOR_SYM},
X{16, FOOD_SYM},
X{12, TOOL_SYM},
X{10, GEM_SYM},
X{ 1, POTION_SYM},
X{ 1, SCROLL_SYM},
X{ 8, WAND_SYM},
X{ 8, RING_SYM},
X{ 4, AMULET_SYM}};
X
Xstatic int mksx=0, mksy=0;
X
Xstruct obj *
Xmkobj_at(let,x,y)
Xchar let;
Xint x,y;
X{
X	register struct obj *otmp;
X
X	mksx = x; mksy = y;
X	/* We might need to know the X, Y coordinates while creating the
X	 * object, i.e. to insure shop boxes are empty.
X	 * Yes, this is a horrible kludge...
X	 */
X	otmp = mkobj(let,TRUE);
X	otmp->ox = x;
X	otmp->oy = y;
X	otmp->nobj = fobj;
X	fobj = otmp;
X	levl[x][y].omask = 1;
X	mksx = mksy = 0;
X	return(otmp);
X}
X
Xstruct obj *
Xmksobj_at(otyp,x,y)
Xint otyp,x,y;
X{
X	register struct obj *otmp;
X
X	mksx = x; mksy = y;
X	otmp = mksobj(otyp,TRUE);
X	otmp->ox = x;
X	otmp->oy = y;
X	otmp->nobj = fobj;
X	levl[x][y].omask = 1;
X	mksx = mksy = 0;
X	return((fobj = otmp));
X}
X
Xstruct obj *
Xmkobj(let, artif)
Xchar let;
Xboolean artif;
X{
X	register int tprob, i, prob = rnd(1000);
X
X	if(let == RANDOM_SYM) {
X		struct icp *iprobs =
X#ifdef REINCARNATION
X				    (dlevel == rogue_level) ? rogueprobs :
X#endif
X				    Inhell ? hellprobs :
X				    mkobjprobs;
X
X		for(tprob = rnd(100);
X		    (tprob -= iprobs->iprob) > 0;
X		    iprobs++);
X		let = iprobs->ilet;
X	}
X
X	i = bases[letindex(let)];
X	while((prob -= objects[i].oc_prob) > 0) i++;
X
X	if(objects[i].oc_olet != let || !objects[i].oc_name)
X		panic("probtype error, let=%c i=%d", let, i);
X
X	return(mksobj(i, artif));
X}
X
Xstatic void
Xmkbox_cnts(box)
X/* Note: does not check to see if it overloaded the box weight; usually
X * possible only with corpses in ice boxes.
X */
Xstruct obj *box;
X{
X	register int n;
X	register struct obj *otmp;
X
X	if(in_shop(mksx, mksy)) return; /* boxes are empty in shops */
X
X	switch(box->otyp) {
X		case ICE_BOX: 		n = 20; break;
X		case CHEST:		n = 5; break;
X		case LARGE_BOX:		n = 3; break;
X		case SACK:
X		case BAG_OF_HOLDING:	n = 1; break;
X		default:		n = 0; break;
X	}
X
X	for(n = rn2(n+1); n > 0; n--) {
X	    if (box->otyp == ICE_BOX) {
X		otmp = mksobj(CORPSE, TRUE);
X		otmp->age = moves;
X	    } else {
X		register int tprob;
X		struct icp *iprobs = boxiprobs;
X
X		for(tprob = rnd(100);
X		    (tprob -= iprobs->iprob) > 0;
X		    iprobs++);
X		otmp = mkobj(iprobs->ilet, TRUE);
X	    }
X	    if (otmp) {
X		otmp->cobj = box;
X		otmp->nobj = fcobj;
X		fcobj = otmp;
X		inc_cwt(box, otmp);
X	    }
X	}
X	return;
X}
X
Xint
Xrndmonnum() {	/* select a random, common monster type */
X
X	register struct permonst *ptr;
X	register int	i;
X
X	/* Plan A: get a level-appropriate common monster */
X	ptr = rndmonst();
X	if (ptr) return(monsndx(ptr));
X
X	/* Plan B: get any common monster */
X	do {
X	    ptr = &mons[(i = rn2(NUMMONS))];
X	} while((ptr->geno & G_NOGEN) || (!Inhell && (ptr->geno & G_HELL)));
X
X	return(i);
X}
X
Xconst char dknowns[] = { WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM,
X#ifdef SPELLS
XSPBOOK_SYM,
X#endif
XWEAPON_SYM, 0};
X
X/*ARGSUSED*/
Xstruct obj *
Xmksobj(otyp, artif)
Xint otyp;
Xboolean artif;
X{
X	int tryct;
X	struct obj *otmp;
X	char let = objects[otyp].oc_olet;
X
X	otmp = newobj(0);
X	*otmp = zeroobj;
X	otmp->age = moves;
X	otmp->o_id = flags.ident++;
X	otmp->quan = 1;
X	otmp->olet = let;
X	otmp->otyp = otyp;
X	otmp->dknown = index(dknowns, let) ? 0 : 1;
X	if (!uses_known(otmp))
X		otmp->known = 1;
X	switch(let) {
X	case WEAPON_SYM:
X		otmp->quan = (otmp->otyp <= SHURIKEN) ? rn1(6,6) : 1;
X		if(!rn2(11)) {
X			otmp->spe = rne(2);
X			otmp->blessed = rn2(2);
X		} else if(!rn2(10)) {
X			curse(otmp);
X			otmp->spe = -rne(2);
X		} else	blessorcurse(otmp, 10);
X
X#ifdef NAMED_ITEMS
X		if(artif && !rn2(20)) mkartifact(&otmp);
X#endif
X		break;
X	case FOOD_SYM:
X		if(otmp->otyp == CORPSE) {
X		    /* overridden by mkcorpse_at() */
X		    do otmp->corpsenm = rndmonnum();
X		    while (mons[otmp->corpsenm].geno & G_NOCORPSE);
X		    break;
X		} else if(otmp->otyp == EGG) {
X		    if(!rn2(3)) {		/* "live" eggs */
X			register struct permonst *ptr;
X			for(tryct = 0;
X			    (!(ptr = rndmonst()) ||
X			    (!lays_eggs(ptr) && ptr != &mons[PM_KILLER_BEE])) &&
X				tryct < 100;
X			    tryct++);
X			if(tryct < 100)	otmp->corpsenm = monsndx(ptr);
X			else		otmp->corpsenm = -1; /* empty */
X		    } else		otmp->corpsenm = -1; /* empty */
X		} else if(otmp->otyp == TIN) {
X		    if(!rn2(10)) {
X			otmp->spe = 1;		/* spinach */
X			otmp->corpsenm = -1;
X		    } else do {
X			otmp->corpsenm = rndmonnum();
X		    } while (mons[otmp->corpsenm].geno & G_NOCORPSE);
X		    blessorcurse(otmp, 10);
X		} else if (otmp->otyp == SLIME_MOLD)
X		    otmp->spe = current_fruit;
X		/* fall into next case */
X	case GEM_SYM:
X		if (otmp->otyp == LOADSTONE) curse(otmp);
X		else if (otmp->otyp == ROCK) otmp->quan = rn1(6,6);
X		else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2;
X		else otmp->quan = 1;
X		break;
X	case TOOL_SYM:
X	    switch(otmp->otyp) {
X		case LAMP:		otmp->spe = rnd(10);
X					blessorcurse(otmp, 5);
X					break;
X		case MAGIC_LAMP:	otmp->spe = 1;
X					blessorcurse(otmp, 2);
X					break;
X		case KEY:		/* key # index */
X		case SKELETON_KEY:	otmp->spe = rn2(N_LOX);
X					break;
X		case CHEST:		/* lock # index */
X		case LARGE_BOX:		otmp->spe = rn2(N_LOX);
X					otmp->olocked = !!(rn2(5));
X					otmp->otrapped = !(rn2(10));
X		case ICE_BOX:
X		case SACK:
X		case BAG_OF_HOLDING:	mkbox_cnts(otmp);
X					break;
X		case MAGIC_MARKER:	otmp->spe = rn1(70,30);
X					break;
X		case CRYSTAL_BALL:	otmp->spe = rnd(5);
X					blessorcurse(otmp, 2);
X					break;
X		case BAG_OF_TRICKS:	otmp->spe = rnd(20);
X					break;
X		case FIGURINE:		otmp->corpsenm = rndmonnum();
X					blessorcurse(otmp, 4);
X					break;
X#ifdef MUSIC
X		case MAGIC_FLUTE:
X		case MAGIC_HARP:
X		case FROST_HORN:
X		case FIRE_HORN:
X		case DRUM_OF_EARTHQUAKE:
X					otmp->spe = rn1(5,4);
X					break;
X#endif /* MUSIC /**/
X	    }
X	    break;
X	case AMULET_SYM:
X		if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION ||
X		   otmp->otyp == AMULET_OF_CHANGE ||
X		   otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
X			curse(otmp);
X		} else	blessorcurse(otmp, 10);
X	case VENOM_SYM:
X	case CHAIN_SYM:
X	case BALL_SYM:
X		break;
X	case POTION_SYM:
X	case SCROLL_SYM:
X#ifdef MAIL
X		if (otmp->otyp != SCR_MAIL)
X#endif
X			blessorcurse(otmp, 4);
X		break;
X#ifdef SPELLS
X	case SPBOOK_SYM:
X		blessorcurse(otmp, 17);
X		break;
X#endif
X	case ARMOR_SYM:
X		if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS ||
X		   otmp->otyp == LEVITATION_BOOTS ||
X		   otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT ||
X		   otmp->otyp == GAUNTLETS_OF_FUMBLING ||
X		   !rn2(11))) {
X			curse(otmp);
X			otmp->spe = -rne(2);
X		} else if(!rn2(10)) {
X			otmp->spe = rne(2);
X			otmp->blessed = rn2(2);
X		} else	blessorcurse(otmp, 10);
X		if(otmp->otyp == DRAGON_SCALE_MAIL)
X			otmp->corpsenm = PM_GREY_DRAGON +
X			    rn2(PM_YELLOW_DRAGON-PM_GREY_DRAGON+1);
X		break;
X	case WAND_SYM:
X#ifdef HARD
X		if(otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else
X#else		
X		if(otmp->otyp == WAN_WISHING) otmp->spe = 3; else
X#endif		
X		otmp->spe = rn1(5,
X			(objects[otmp->otyp].bits & NODIR) ? 11 : 4);
X		blessorcurse(otmp, 17);
X		otmp->recharged = 0; /* used to control recharging */
X		break;
X	case RING_SYM:
X		if(objects[otmp->otyp].oc_charged) {
X		    blessorcurse(otmp, 3);
X		    if(rn2(10)) {
X			if(rn2(10) && bcsign(otmp))
X			    otmp->spe = bcsign(otmp) * rne(3);
X			else otmp->spe = rn2(2) ? rne(3) : -rne(3);
X		    }
X		    if (otmp->spe < 0 && rn2(5)) curse(otmp);
X		} else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION ||
X#ifdef POLYSELF
X			  otmp->otyp == RIN_POLYMORPH ||
X#endif
X			  otmp->otyp == RIN_AGGRAVATE_MONSTER ||
X			  otmp->otyp == RIN_HUNGER || !rn2(9))) {
X			curse(otmp);
X		}
X		break;
X	case ROCK_SYM:
X		switch (otmp->otyp) {
X		    case STATUE:
X			/* contains book? */
X			otmp->spe = (rn2(dlevel/2 + 10) > 10);
X			/* overridden by mkstatue() */
X			otmp->corpsenm = rndmonnum();
X			otmp->owt = mons[otmp->corpsenm].cwt;
X		}
X		break;
X	default:
X		impossible("impossible mkobj %d, sym '%c'.", otmp->otyp, let);
X		return (struct obj *)0;
X	}
X	otmp->owt = weight(otmp);
X	return(otmp);
X}
X
Xvoid
Xbless(otmp)
Xregister struct obj *otmp;
X{
X	otmp->cursed = 0;
X	otmp->blessed = 1;
X	return;
X}
X
Xvoid
Xcurse(otmp)
Xregister struct obj *otmp;
X{
X	otmp->blessed = 0;
X	otmp->cursed = 1;
X	return;
X}
X
Xvoid
Xblessorcurse(otmp, chance)
Xregister struct obj *otmp;
Xregister int chance;
X{
X	if(otmp->blessed || otmp->cursed) return;
X
X	if(!rn2(chance))
X	    if(!rn2(2) || Inhell) { /* in hell, don't usually bless items */
X		curse(otmp);
X	    } else {
X		bless(otmp);
X	    }
X	return;
X}
X
Xint
Xbcsign(otmp)
Xregister struct obj *otmp;
X{
X	return(!!otmp->blessed - !!otmp->cursed);
X}
X
Xint
Xletter(c) {
X	return(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z'));
X}
X
Xint
Xweight(obj)
Xregister struct obj *obj;
X{
X	register int wt = objects[obj->otyp].oc_weight;
X
X	if (Is_container(obj)) {
X		struct obj *contents;
X		for(contents=fcobj; contents; contents=contents->nobj) {
X			if (contents->cobj == obj)
X				inc_cwt(obj, contents);
X		}
X		return obj->owt;
X	}
X	if (obj->otyp == CORPSE && obj->corpsenm > -1)
X		return obj->quan * mons[obj->corpsenm].cwt;
X	else if (obj->otyp == STATUE && obj->corpsenm > -1)
X		return obj->quan * (mons[obj->corpsenm].cwt * 3 / 2);
X	return(wt ? wt*obj->quan : (obj->quan + 1)>>1);
X}
X
Xvoid
Xmkgold(num,x,y)
Xlong num;
Xint x, y;
X{
X	register struct gold *gold;
X	register long amount = (num ? num : 1 + (rnd(dlevel+2) * rnd(30)));
X
X	if(levl[x][y].gmask) {
X		gold = g_at(x,y);
X		gold->amount += amount;
X	} else {
X		gold = newgold();
X		gold->ngold = fgold;
X		gold->gx = x;
X		gold->gy = y;
X		gold->amount = amount;
X		fgold = gold;
X		levl[x][y].gmask = 1;
X		/* do sth with display? */
X	}
X	return;
X}
X
Xstruct obj *
Xmkcorpse_at(ptr, x, y)
Xregister struct permonst *ptr;
Xint	x, y;
X{
X	register struct obj *otmp;
X
X	otmp = mksobj_at(CORPSE, x, y);
X	if(otmp)  {
X		otmp->corpsenm = monsndx(ptr);
X		otmp->owt = ptr->cwt;
X	}
X	return(otmp);
X}
X
Xstruct obj *
Xmk_tt_corpse(x, y)
Xregister int x, y;
X{
X	register struct obj *otmp;
X
X	if((otmp = mksobj(CORPSE,FALSE))) {
X		otmp->ox = x;
X		otmp->oy = y;
X		if(otmp = tt_oname(otmp)) {
X			otmp->nobj = fobj;
X			fobj = otmp;
X			levl[x][y].omask = 1;
X		}
X	}
X	return(otmp);
X}
X
Xstruct obj *
Xmkstatue(ptr, x, y)
Xregister struct permonst *ptr;
Xint x, y;
X{
X	register struct obj *otmp;
X
X	if((otmp = mksobj_at(STATUE, x, y))) {
X
X	    if(ptr)	otmp->corpsenm = monsndx(ptr);
X	    else	otmp->corpsenm = rndmonnum();
X	}
X	return(otmp);
X}
X
Xstruct obj *
Xmk_named_object(objtype, ptr, x, y, nm, lth)
Xint objtype; /* CORPSE or STATUE */
Xregister struct permonst *ptr;
Xint x, y;
Xchar * nm;
Xregister int lth;
X{
X	struct obj *otmp;
X	register struct obj *obj2;
X
X	if (lth == 0) {
X		switch(objtype) {
X			case STATUE: return (mkstatue(ptr, x, y));
X			case CORPSE: return (mkcorpse_at(ptr, x, y));
X			default: impossible("making named type %d", objtype);
X				return mksobj_at(objtype, x, y);
X		}
X	}
X
X	if((otmp = mksobj(objtype,FALSE))) {
X		obj2 = newobj(lth);
X		*obj2 = *otmp;
X		obj2->corpsenm = monsndx(ptr);
X		obj2->owt = ptr->cwt;
X		obj2->onamelth = lth;
X		Strcpy (ONAME(obj2), nm);
X		free( (genericptr_t)otmp);
X		obj2->ox = x;
X		obj2->oy = y;
X		obj2->nobj = fobj;
X		fobj = obj2;
X		levl[x][y].omask = 1;
X		return(obj2);
X	} else  return((struct obj *)0);
X}
X
X#ifdef MEDUSA
Xstruct obj *
Xmk_tt_statue(x, y)
Xregister int x, y;
X{
X	register struct obj *otmp;
X
X	if((otmp = mksobj(STATUE,FALSE))) {
X		otmp->ox = x;
X		otmp->oy = y;
X		if(otmp = tt_oname(otmp)) {
X			otmp->nobj = fobj;
X			fobj = otmp;
X			levl[x][y].omask = 1;
X			otmp->spe = 0;
X			/* player statues never contain books */
X		}
X	}
X	return(otmp);
X}
X#endif
X
Xboolean
Xis_flammable(otmp)
Xregister struct obj *otmp;
X{
X	return((objects[otmp->otyp].oc_material == WOOD ||
X			objects[otmp->otyp].oc_material == 0));
X
X}
X
Xboolean
Xis_rustprone(otmp)
Xregister struct obj *otmp;
X{
X	return(objects[otmp->otyp].oc_material == METAL);
X}
X
Xvoid
Xset_omask(x, y)
Xregister xchar x, y;
X{
X	levl[x][y].gmask = (g_at(x, y) != (struct gold *)0);
X	levl[x][y].omask = (o_at(x, y) != (struct obj *)0);
X}
END_OF_FILE
if test 12813 -ne `wc -c <'src/mkobj.c'`; then
    echo shar: \"'src/mkobj.c'\" unpacked with wrong size!
fi
# end of 'src/mkobj.c'
fi
if test -f 'src/shknam.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/shknam.c'\"
else
echo shar: Extracting \"'src/shknam.c'\" \(11750 characters\)
sed "s/^X//" >'src/shknam.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)shknam.c	3.0	88/04/13
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X/* shknam.c -- initialize a shop */
X
X#include "hack.h"
X#include "eshk.h"
X
Xstatic const char *shkliquors[] = {
X    /* Ukraine */
X    "Njezjin", "Tsjernigof", "Gomel", "Ossipewsk", "Gorlowka",
X    /* N. Russia */
X    "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",
X    "Narodnaja", "Kyzyl",
X    /* Silezie */
X    "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",
X    "Brzeg", "Krnov", "Hradec Kralove",
X    /* Schweiz */
X    "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",
X    "Flims", "Vals", "Schuls", "Zum Loch",
X    ""
X};
X
Xstatic const char *shkbooks[] = {
X    /* Eire */
X    "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",
X    "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",
X    "Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan",
X    "Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh",
X    "Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea",
X    "Culdaff", "Dunfanaghy", "Inishbofin", "Kesh",
X    ""
X};
X
Xstatic const char *shkarmors[] = {
X    /* Turquie */
X    "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
X    "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
X    "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
X    "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
X    "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
X    "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
X    ""
X};
X
Xstatic const char *shkwands[] = {
X    /* Wales */
X    "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
X    "Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
X    "Y-Fenni", "Measteg", "Rhydaman", "Beddgelert",
X    "Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
X    /* Scotland */
X    "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
X    "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",
X    "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",
X    "Kyleakin", "Dunvegan",
X    ""
X};
X
Xstatic const char *shkrings[] = {
X    /* Hollandse familienamen */
X    "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",
X    "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",
X    "Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix",
X    "Ypey",
X    /* Skandinaviske navne */
X    "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",
X    "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",
X    "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",
X    ""
X};
X
Xstatic const char *shkfoods[] = {
X    /* Indonesia */
X    "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
X    "Bandjar", "Parbalingga", "Bojolali", "Sarangan",
X    "Ngebel", "Djombang", "Ardjawinangun", "Berbek",
X    "Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi",
X    "Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan",
X    "Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe",
X    "Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe",
X    ""
X};
X
Xstatic const char *shkweapons[] = {
X    /* Perigord */
X    "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
X    "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",
X    "Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac",
X    "Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac",
X    "Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon",
X    "Eymoutiers", "Eygurande", "Eauze", "Labouheyre",
X    ""
X};
X
Xstatic const char *shktools[] = {
X    /* Spmi */
X    "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj",
X    "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil",
X    "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar",
X    "Yelpur", "Nosnehpets", "Stewe", "Renrut", "Zlaw", "Nosalnef",
X    "Rewuorb", "Rellenk",
X    ""
X};
X
Xstatic const char *shkgeneral[] = {
X    /* Suriname */
X    "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
X    "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
X    "Akalapi", "Sipaliwini",
X    /* Greenland */
X    "Annootok", "Upernavik", "Angmagssalik",
X    /* N. Canada */
X    "Aklavik", "Inuvik", "Tuktoyaktuk",
X    "Chicoutimi", "Ouiatchouane", "Chibougamau",
X    "Matagami", "Kipawa", "Kinojevis",
X    "Abitibi", "Maganasipi",
X    /* Iceland */
X    "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",
X    "Holmavik",
X    ""
X};
X
X/*
X * To add new shop types, all that is necessary is to edit the shtypes[] array.
X * See mkroom.h for the structure definition. Typically, you'll have to lower
X * some or all of the probability fields in old entries to free up some
X * percentage for the new type.
X *
X * The placement type field is not yet used but will be in the near future.
X *
X * The iprobs array in each entry defines the probabilities for various kinds
X * of artifacts to be present in the given shop type. You can associate with
X * each percentage either a generic artifact type (represented by one of the
X * *_SYM macros) or a specific artifact (represented by an onames.h define).
X * In the latter case, prepend it with a unary minus so the code can know
X * (by testing the sign) whether to use mkobj() or mksobj().
X */
Xconst struct shclass shtypes[] = {
X	{"general store", RANDOM_SYM,
X#ifdef SPELLS
X	    44,
X#else
X	    47,
X#endif
X	    D_SHOP, {{100, RANDOM_SYM}, {0, 0}, {0, 0}}, shkgeneral},
X	{"used armor dealership", ARMOR_SYM, 14,
X	    D_SHOP, {{90, ARMOR_SYM}, {10, WEAPON_SYM}, {0, 0}}, shkarmors},
X	{"second hand bookstore", SCROLL_SYM, 10, D_SHOP,
X#ifdef SPELLS
X	    {{90, SCROLL_SYM}, {10, SPBOOK_SYM}, {0, 0}},
X#else
X	    {{100, SCROLL_SYM}, {0, 0}, {0, 0}},
X#endif
X	    shkbooks},
X	{"liquor emporium", POTION_SYM, 10, D_SHOP,
X	    {{100, POTION_SYM}, {0, 0}, {0, 0}}, shkliquors},
X	{"antique weapons outlet", WEAPON_SYM, 5, D_SHOP,
X	    {{90, WEAPON_SYM}, {10, ARMOR_SYM}, {0, 0}}, shkweapons},
X	{"delicatessen", FOOD_SYM, 5, D_SHOP,
X	    {{95, FOOD_SYM}, {5, POTION_SYM}, {0, 0}}, shkfoods},
X	{"jewelers", RING_SYM, 3, D_SHOP,
X	    {{85, RING_SYM}, {10, GEM_SYM}, {5, AMULET_SYM}, {0, 0}}, shkrings},
X	{"quality apparel and accessories", WAND_SYM, 3, D_SHOP,
X	    {{90, WAND_SYM}, {5, -LEATHER_GLOVES}, {5, -ELVEN_CLOAK}, {0, 0}},
X	     shkwands},
X	{"hardware store", TOOL_SYM, 3, D_SHOP,
X	    {{100, TOOL_SYM}, {0, 0}, {0, 0}}, shktools},
X	/* Actually shktools is ignored; the code specifically chooses a
X	 * random implementor name (the only shop type with random shopkeepers)
X	 */
X#ifdef SPELLS
X	{"rare books", SPBOOK_SYM, 3, D_SHOP,
X	    {{90, SPBOOK_SYM}, {10, SCROLL_SYM}, {0, 0}}, shkbooks},
X#endif
X	{NULL, 0, 0, 0, {{0, 0}, {0, 0}, {0, 0}}, (char **)0}
X};
X
Xstatic void
Xmkshobj_at(shp, sx, sy)
X/* make an object of the appropriate type for a shop square */
Xstruct shclass *shp;
Xint sx, sy;
X{
X	register struct monst *mtmp;
X	int atype;
X
X	if (rn2(100) < dlevel && levl[sx][sy].mmask == 0 &&
X				(mtmp=makemon(mkclass(S_MIMIC),sx,sy))) {
X		mtmp->mimic = 1;
X		/* note: makemon will set the mimic symbol to a shop item */
X		if (rn2(10) >= dlevel) mtmp->mappearance = S_MIMIC_DEF;
X	} else if ((atype = get_shop_item(shp - shtypes)) < 0)
X		(void) mksobj_at(-atype, sx, sy);
X	else (void) mkobj_at(atype, sx, sy);
X}
X
Xstatic void
Xfindname(nampt, nlp)
X/* extract a shopkeeper name for the given shop type */
X	char *nampt;
X	char *nlp[];
X{
X    register int i;
X
X    for(i = 0; i < dlevel; i++)
X	if (strlen(nlp[i]) == 0) {
X	    /* Not enough names, try general name */
X	    if (nlp != shkgeneral)
X		findname(nampt, shkgeneral);
X	    else
X		Strcpy(nampt, "Dirk");
X	    return;
X	}
X    (void) strncpy(nampt, nlp[i-1], PL_NSIZ);
X    nampt[PL_NSIZ-1] = 0;
X}
X
Xstatic int
Xshkinit(shp, sroom)	/* create a new shopkeeper in the given room */
Xstruct shclass	*shp;
Xstruct mkroom	*sroom;
X{
X	register int sh, sx, sy;
X	struct monst *shk;
X
X	/* place the shopkeeper in the given room */
X	sh = sroom->fdoor;
X	sx = doors[sh].x;
X	sy = doors[sh].y;
X
X	/* check that the shopkeeper placement is sane */
X	if(sx == sroom->lx-1) sx++; else
X	    if(sx == sroom->hx+1) sx--; else
X		if(sy == sroom->ly-1) sy++; else
X		    if(sy == sroom->hy+1) sy--; else {
X#ifdef DEBUG
X# ifdef WIZARD
X		    /* Said to happen sometimes, but I have never seen it. */
X		    /* Supposedly fixed by fdoor change in mklev.c */
X			if(wizard) {
X			    register int j = sroom->doorct;
X
X			    pline("Where is shopdoor?");
X			    pline("Room at (%d,%d),(%d,%d).",
X				  sroom->lx, sroom->ly, sroom->hx, sroom->hy);
X			    pline("doormax=%d doorct=%d fdoor=%d",
X			    doorindex, sroom->doorct, sh);
X			    while(j--) {
X				pline("door [%d,%d]", doors[sh].x, doors[sh].y);
X				sh++;
X			    }
X			    more();
X			}
X# endif
X#endif
X			return(-1);
X		    }
X
X	/* now initialize the shopkeeper monster structure */
X	if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy))) return(-1);
X	shk->isshk = shk->mpeaceful = 1;
X	shk->msleep = 0;
X	shk->mtrapseen = ~0;	/* we know all the traps already */
X	ESHK(shk)->shoproom = sroom - rooms;
X	ESHK(shk)->shoplevel = dlevel;
X	ESHK(shk)->shd = doors[sh];
X	ESHK(shk)->shk.x = sx;
X	ESHK(shk)->shk.y = sy;
X	/* makemon() has already zeroed out all the extra space
X	ESHK(shk)->robbed = 0;
X	ESHK(shk)->credit = 0;
X	ESHK(shk)->debit = 0;
X	ESHK(shk)->visitct = 0;
X	ESHK(shk)->following = 0;
X	ESHK(shk)->billct = 0;
X	*/
X	shk->mgold = 1000 + 30*rnd(100);	/* initial capital */
X	if (shp->shknms == shktools) {
X		static int who;
X		who = rn2(sizeof(shktools)/sizeof(char *));
X		if (who==21) ESHK(shk)->ismale = FALSE;
X		else ESHK(shk)->ismale = TRUE;
X		(void) strncpy(ESHK(shk)->shknam, shp->shknms[who], PL_NSIZ);
X		ESHK(shk)->shknam[PL_NSIZ-1] = 0;
X	} else {
X		ESHK(shk)->ismale = dlevel%2;
X		findname(ESHK(shk)->shknam, shp->shknms);
X	}
X
X	return(sh);
X}
X
Xvoid
Xstock_room(shp, sroom)
X/* stock a newly-created room with artifacts */
Xstruct shclass	*shp;
Xregister struct mkroom *sroom;
X{
X    /*
X     * Someday soon we'll dispatch on the dist field of shclass to do
X     * different placements in this routine. Currently it only supports
X     * shop-style placement (all squares except a row nearest the first
X     * door get artifacts).
X     */
X    register int sx, sy, sh;
X
X    /* first, try to place a shopkeeper in the room */
X    if ((sh = shkinit(shp, sroom)) < 0)
X	return;
X
X    /* make sure no doorways without doors in shops */
X    for(sx = sroom->lx - 1; sx <= sroom->hx + 1; sx++)
X	for(sy = sroom->ly - 1; sy <= sroom->hy + 1; sy++) {
X	    if(IS_DOOR(levl[sx][sy].typ))
X		if (levl[sx][sy].doormask == D_NODOOR)
X		    levl[sx][sy].doormask = D_ISOPEN;
X    }
X
X    for(sx = sroom->lx; sx <= sroom->hx; sx++)
X	for(sy = sroom->ly; sy <= sroom->hy; sy++) {
X	    if((sx == sroom->lx && doors[sh].x == sx-1) ||
X	       (sx == sroom->hx && doors[sh].x == sx+1) ||
X	       (sy == sroom->ly && doors[sh].y == sy-1) ||
X	       (sy == sroom->hy && doors[sh].y == sy+1)) continue;
X	    mkshobj_at(shp, sx, sy);
X	}
X
X    /*
X     * Special monster placements (if any) should go here: that way,
X     * monsters will sit on top of artifacts and not the other way around.
X     */
X}
X
Xint
Xsaleable(nshop, obj)			/* does "shop" stock this item type */
Xregister int nshop;
Xregister struct	obj *obj;
X{
X	int i;
X
X	if(shtypes[nshop].symb == RANDOM_SYM) return(1);
X	else {
X	    for(i = 0; shtypes[nshop].iprobs[i].iprob; i++)
X		if(shtypes[nshop].iprobs[i].itype < 0) {
X		   if(shtypes[nshop].iprobs[i].itype == - obj->otyp) return(1);
X		}
X		else if(shtypes[nshop].iprobs[i].itype == obj->olet) return(1);
X	}
X	return(0);
X}
X
X/* positive value: letter; negative value: specific item type */
Xint
Xget_shop_item(type)
Xint type;
X{
X	struct shclass *shp = shtypes+type;
X	register int i,j;
X
X	/* select an appropriate artifact type at random */
X	for(j = rnd(100), i = 0; j -= shp->iprobs[i].iprob; i++)
X		if (j < 0) break;
X
X	return shp->iprobs[i].itype;
X}
END_OF_FILE
if test 11750 -ne `wc -c <'src/shknam.c'`; then
    echo shar: \"'src/shknam.c'\" unpacked with wrong size!
fi
# end of 'src/shknam.c'
fi
echo shar: End of archive 26 \(of 38\).
cp /dev/null ark26isdone
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 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 38 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