[net.sources] Repost of Hack

ed@gargoyle.UChicago.UUCP (Ed Friedman) (01/13/85)

# This is part 14 (of 15) of the Hack sources. Send complaints to
# mcvax!play .
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# mklev.c mklev.h mklv.makemaz.c mklv.shk.c mklv.shknam.c

echo x - mklev.c
cat > "mklev.c" << '//E*O*F mklev.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include <stdio.h>
#include "mklev.h"
#include "def.trap.h"

extern char *getlogin();
extern struct monst *makemon();

char *tfile,*tspe,**args;
char nul[40];

#include "savelev.h"

#ifdef WIZARD
boolean wizard;
#endif WIZARD


#define somex() ((rand()%(croom->hx-croom->lx+1))+croom->lx)
#define somey() ((rand()%(croom->hy-croom->ly+1))+croom->ly)

struct rm levl[COLNO][ROWNO];
struct monst *fmon;
struct obj *fobj;
struct gen *fgold, *ftrap;

char *fut_geno;		/* monsters that should not be created anymore */

struct mkroom rooms[MAXNROFROOMS+1], *croom, *troom;
coord doors[DOORMAX];
int doorindex = 0;
int comp();

xchar dlevel;
schar nxcor,xx,yy,dx,dy,tx,ty; /* for corridors and other things... */
boolean goldseen;
int nroom;

xchar xdnstair,xupstair,ydnstair,yupstair;


main(argc,argv)
char *argv[];
{
	register unsigned tryct;

	if(argc < 6) panic("Too few arguments!!");
	args = argv;
	tfile = argv[1];
	tspe = argv[2];
	dlevel = atoi(argv[3]);
	if(dlevel < 1) panic("Bad level");
	fut_geno = argv[4];
#ifdef WIZARD
	wizard = (argv[5][0] == 'w');
#endif WIZARD
	(void) srand(getpid());
	init_objects();
	rooms[0].hx = -1;	/* in case we are in a maze */

	/* a: normal; b: maze */
	if(*tspe == 'b') {
		makemaz();
		savelev();
		exit(0);
	}

	/* construct the rooms */
	while(nroom < (MAXNROFROOMS/3)) {
		croom = rooms;
		nroom = 0;
		(void) makerooms(0);		/* not secret */
	}

	/* for each room: put things inside */
	for(croom = rooms; croom->hx > 0; croom++) {

		/* put a sleeping monster inside */
		if(!rn2(3)) (void)
			makemon((struct permonst *) 0, somex(), somey());

		/* put traps and mimics inside */
		goldseen = FALSE;
		while(!rn2(8-(dlevel/6))) mktrap(0,0);
		if(!goldseen && !rn2(3)) mkgold(0,somex(),somey());
		if(!rn2(3)) {
			mkobj_at(0, somex(), somey());
			tryct = 0;
			while(!rn2(5)) {
				if(++tryct > 100){
					printf("tryct overflow4\n");
					break;
				}
				mkobj_at(0, somex(), somey());
			}
		}
	}
	tryct = 0;
	do {
		if(++tryct > 1000) panic("Cannot make dnstairs\n");
		croom = &rooms[rn2(nroom)];
		xdnstair = somex();
		ydnstair = somey();
	} while((*tspe =='n' && (!(xdnstair%2) || !(ydnstair%2))) ||
		g_at(xdnstair,ydnstair,ftrap));
	levl[xdnstair][ydnstair].scrsym ='>';
	levl[xdnstair][ydnstair].typ = STAIRS;
	troom = croom;
	do {
		if(++tryct > 2000) panic("Cannot make upstairs\n");
		croom = &rooms[rn2(nroom)];
		xupstair = somex();
		yupstair = somey();
	} while(croom == troom || m_at(xupstair,yupstair) ||
		g_at(xupstair,yupstair,ftrap));
	levl[xupstair][yupstair].scrsym ='<';
	levl[xupstair][yupstair].typ = STAIRS;

	qsort((char *) rooms, nroom, sizeof(struct mkroom), comp);
	croom = rooms;
	troom = croom+1;
	nxcor = 0;
	mkpos();
	do makecor();
	while (croom->hx > 0 && troom->hx > 0);

	/* make a secret treasure vault, not connected to the rest */
	if(nroom < (2*MAXNROFROOMS/3)) if(!rn2(3)) {
		register int x,y;
		troom = croom = &rooms[nroom];
		if(makerooms(1)) {		/* make secret room */
			troom->rtype = 6;		/* treasure vault */
			for(x = troom->lx; x <= troom->hx; x++)
			for(y = troom->ly; y <= troom->hy; y++)
				mkgold(rnd(dlevel*100) + 50, x, y);
		}
	}

#ifdef WIZARD
	if(wizard){
		if(rn2(3)) mkshop(); else mkzoo();
	} else
#endif WIZARD
 	if(dlevel > 1 && dlevel < 20 && rn2(dlevel) < 2) mkshop();
	else
	if(dlevel > 6 && (!rn2(7) || !strcmp("david", getlogin())))
		mkzoo();
	savelev();
	exit(0);
}

makerooms(secret) int secret; {
register int lowx, lowy;
register int tryct = 0;
	while(nroom < (MAXNROFROOMS/2) || secret)
	    for(lowy = rn1(3,3); lowy < ROWNO-7; lowy += rn1(2,4)) {
		for(lowx = rn1(3,4); lowx < COLNO-10; lowx += rn1(2,7)) {
			if(tryct++ > 10000) return(0);
			if((lowy += (rn2(5)-2)) < 3) lowy = 3;
			else if(lowy > ROWNO-6) lowy = ROWNO-6;
			if(levl[lowx][lowy].typ) continue;
			if((secret && maker(lowx, 1, lowy, 1)) ||
			   (!secret && maker(lowx,rn1(9,2),lowy,rn1(4,2))
				&& nroom+2 > MAXNROFROOMS)) return(1);
		}
	}
	return(1);
}

comp(x,y)
register struct mkroom *x,*y;
{
	if(x->lx < y->lx) return(-1);
	return(x->lx > y->lx);
}

coord
finddpos(xl,yl,xh,yh) {
coord ff;
register x,y;
	ff.x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
	ff.y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
	if(okdoor(ff.x, ff.y)) return(ff);
	if(xl < xh) for(x = xl; x <= xh; x++)
		if(okdoor(x, ff.y)){
			ff.x = x;
			return(ff);
		}
	if(yl < yh) for(y = yl; y <= yh; y++)
		if(okdoor(ff.x, y)){
			ff.y = y;
			return(ff);
		}
	return(ff);
}

/* when croom and troom exist, find position for a door in croom
   and direction for a corridor towards position [tx,ty] in the wall
   of troom */
mkpos()
{
coord cc,tt;
	if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
	if(troom->lx > croom->hx) {
		dx = 1;
		dy = 0;
		xx = croom->hx+1;
		tx = troom->lx-1;
		cc = finddpos(xx,croom->ly,xx,croom->hy);
		tt = finddpos(tx,troom->ly,tx,troom->hy);
	} else if(troom->hy < croom->ly) {
		dy = -1;
		dx = 0;
		yy = croom->ly-1;
		cc = finddpos(croom->lx,yy,croom->hx,yy);
		ty = troom->hy+1;
		tt = finddpos(troom->lx,ty,troom->hx,ty);
	} else if(troom->hx < croom->lx) {
		dx = -1;
		dy = 0;
		xx = croom->lx-1;
		tx = troom->hx+1;
		cc = finddpos(xx,croom->ly,xx,croom->hy);
		tt = finddpos(tx,troom->ly,tx,troom->hy);
	} else {
		dy = 1;
		dx = 0;
		yy = croom->hy+1;
		ty = troom->ly-1;
		cc = finddpos(croom->lx,yy,croom->hx,yy);
		tt = finddpos(troom->lx,ty,troom->hx,ty);
	}
	xx = cc.x;
	yy = cc.y;
	tx = tt.x;
	ty = tt.y;
	if(levl[xx+dx][yy+dy].typ) {
		if(nxcor) newloc();
		else {
			dodoor(xx,yy,croom);
			xx += dx;
			yy += dy;
		}
		return;
	}
	dodoor(xx,yy,croom);
}

/* if allowable, create a door at [x,y] */
okdoor(x,y)
register x,y;
{
	if(levl[x-1][y].typ == DOOR || levl[x+1][y].typ == DOOR ||
	   levl[x][y+1].typ == DOOR || levl[x][y-1].typ == DOOR ||
	   levl[x-1][y].typ == SDOOR || levl[x+1][y].typ == SDOOR ||
	   levl[x][y-1].typ == SDOOR || levl[x][y+1].typ == SDOOR ||
	   (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
	   doorindex >= DOORMAX)
		return(0);
	return(1);
}

dodoor(x,y,aroom)
register x,y;
register struct mkroom *aroom;
{
	register struct mkroom *broom;
	register tmp;
	if(doorindex >= DOORMAX) panic("DOORMAX exceeded?");
	if(!okdoor(x,y) && nxcor) return;
	if(!rn2(8)) levl[x][y].typ = SDOOR;
	else {
		levl[x][y].scrsym ='+';
		levl[x][y].typ = DOOR;
	}
	aroom->doorct++;
	broom = aroom+1;
	if(broom->hx < 0) tmp = doorindex; else
	for(tmp = doorindex; tmp > broom->fdoor; tmp--)
		doors[tmp] = doors[tmp-1];
	doorindex++;
	doors[tmp].x = x;
	doors[tmp].y = y;
	for( ; broom->hx >= 0; broom++) broom->fdoor++;
}

newloc()
{
	register a,b;
	register int tryct = 0;

	++croom;
	++troom;
	if(nxcor || croom->hx < 0 || troom->hx < 0) {
		if(nxcor++ > rn1(nroom,4)) {
			croom = &rooms[nroom];
			return;
		}
		do {
			if(++tryct > 100){
				printf("tryct overflow5\n");
				croom = &rooms[nroom];
				return;
			}
			a = rn2(nroom);
			b = rn2(nroom);
			croom = &rooms[a];
			troom = &rooms[b];
		} while(croom == troom || (troom == croom+1 && !rn2(3)));
	}
	mkpos();
}

/* make a trap somewhere (in croom if mazeflag = 0) */
mktrap(num,mazeflag)
register num,mazeflag;
{
	register struct gen *gtmp;
	register int kind,nopierc,nomimic,fakedoor,fakegold,tryct = 0;
	register xchar mx,my;

	if(!num || num >= TRAPNUM) {
		nopierc = (dlevel < 4) ? 1 : 0;
		nomimic = (dlevel < 9 || goldseen ) ? 1 : 0;
		if(index(fut_geno, 'M')) nomimic = 1;
		kind = rn2(TRAPNUM - nopierc - nomimic);
		/* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
	} else kind = num;

	if(kind == MIMIC) {
		register struct monst *mtmp;

		fakedoor = (!rn2(3) && !mazeflag);
		fakegold = (!fakedoor && !rn2(2));
		if(fakegold) goldseen = TRUE;
		do {
			if(++tryct > 200) return;
			if(fakedoor) {
				/* note: fakedoor maybe on actual door */
				if(rn2(2)){
					if(rn2(2))
						mx = croom->hx+1;
					else mx = croom->lx-1;
					my = somey();
				} else {
					if(rn2(2))
						my = croom->hy+1;
					else my = croom->ly-1;
					mx = somex();
				}
			} else if(mazeflag) {
				extern coord mazexy();
				coord mm;
				mm = mazexy();
				mx = mm.x;
				my = mm.y;
			} else {
				mx = somex();
				my = somey();
			}
		} while(m_at(mx,my));
		if(mtmp = makemon(PM_MIMIC,mx,my))
		    mtmp->mimic =
			fakegold ? '$' : fakedoor ? '+' :
			(mazeflag && rn2(2)) ? AMULET_SYM :
			"=/)%?![<>" [ rn2(9) ];
		return;
	}
	gtmp = newgen();
	gtmp->gflag = kind;
	do {
		if(++tryct > 200){
			printf("tryct overflow7\n");
			free((char *) gtmp);
			return;
		}
		if(mazeflag){
			extern coord mazexy();
			coord mm;
			mm = mazexy();
			gtmp->gx = mm.x;
			gtmp->gy = mm.y;
		} else {
			gtmp->gx = somex();
			gtmp->gy = somey();
		}
	} while(g_at(gtmp->gx, gtmp->gy, ftrap));
	gtmp->ngen = ftrap;
	ftrap = gtmp;
	if(mazeflag && !rn2(10) && gtmp->gflag < PIERC) gtmp->gflag |= SEEN;
}

/*VARARGS1*/
panic(str,arg1,arg2,arg3)
char *str,*arg1,*arg2,*arg3;
{
	char bufr[BUFSZ];
	extern char *sprintf();
	(void) sprintf(bufr,str,arg1,arg2,arg3);
	(void) write(1,"\nMKLEV ERROR:  ",15);
	puts(bufr);
	(void) fflush(stdout);
	exit(1);
}

maker(lowx,ddx,lowy,ddy)
schar lowx,ddx,lowy,ddy;
{
	register x, y, hix = lowx+ddx, hiy = lowy+ddy;

	if(nroom >= MAXNROFROOMS) return(0);
	if(hix > COLNO-5) hix = COLNO-5;
	if(hiy > ROWNO-4) hiy = ROWNO-4;
chk:
	if(hix <= lowx || hiy <= lowy) return(0);

	/* check area around room (and make room smaller if necessary) */
	for(x = lowx-4; x <= hix+4; x++)
		for(y = lowy-3; y <= hiy+3; y++)
			if(levl[x][y].typ) {
				if(rn2(3)) return(0);
				lowx = x+5;
				lowy = y+4;
				goto chk;
			}

	/* on low levels the room is lit (usually) */
	/* secret vaults are always lit */
	if((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1))
		for(x = lowx-1; x <= hix+1; x++)
			for(y = lowy-1; y <= hiy+1; y++)
				levl[x][y].lit = 1;
	croom->lx = lowx;
	croom->hx = hix;
	croom->ly = lowy;
	croom->hy = hiy;
	croom->rtype = croom->doorct = croom->fdoor = 0;
	for(x = lowx-1; x <= hix+1; x++)
	    for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
		levl[x][y].scrsym = '-';
		levl[x][y].typ = HWALL;
	}
	for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
	    for(y = lowy; y <= hiy; y++) {
		levl[x][y].scrsym = '|';
		levl[x][y].typ = VWALL;
	}
	for(x = lowx; x <= hix; x++)
	    for(y = lowy; y <= hiy; y++) {
		levl[x][y].scrsym = '.';
		levl[x][y].typ = ROOM;
	}
	croom++;
	croom->hx = -1;
	nroom++;
	return(1);
}

makecor() {
	register nx, ny;
	register struct rm *crm;
	register dix, diy, secondtry = 0;

tryagain:
	nx = xx + dx;
	ny = yy + dy;

	if(nxcor && !rn2(35)) {
		newloc();
		return;
	}
	if(nx == COLNO-1 || nx == 0 || ny == 0 || ny == ROWNO-1) {
		if(nxcor) {
			newloc();
			return;
		} else {
			printf("something went wrong. we try again...\n");
		execl("./mklev",args[0],tfile,tspe,args[3],args[4],args[5],0);
			panic("cannot execute ./mklev\n");
		}
	}

	dix = abs(nx-tx);
	diy = abs(ny-ty);
	if(dy && dix > diy) {
		dy = 0;
		dx = (nx > tx) ? -1 : 1;
	} else if(dx && diy > dix) {
		dx = 0;
		dy = (ny > ty) ? -1 : 1;
	}

	crm = &levl[nx][ny];
	if(!(crm->typ)) {
		if(rn2(100)) {
			crm->typ = CORR;
			crm->scrsym = CORR_SYM;
		} else {
			crm->typ = SCORR;
			crm->scrsym = ' ';
		}
		xx = nx;
		yy = ny;
		if(nxcor && !rn2(50)) {
			mkobj_at(ROCK_SYM, nx, ny);
		}
		return;
	}
	if(crm->typ == CORR || crm->typ == SCORR) {
		xx = nx;
		yy = ny;
		return;
	}
	if(nx == tx && ny == ty) {
		dodoor(nx,ny,troom);
		newloc();
		return;
	}
	if(!secondtry++ && (nx != xx+dx || ny != yy+dy))
		goto tryagain;
	if(dx) {
		if(ty < ny) dy = -1;
		else dy = levl[nx+dx][ny-1].typ == ROOM?1:-1;
		dx = 0;
	} else {
		if(tx < nx) dx = -1;
		else dx = levl[nx-1][ny+dy].typ == ROOM?1:-1;
		dy = 0;
	}
}

struct monst *
m_at(x,y)
register x,y;
{
	register struct monst *mtmp;

	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
		if(mtmp->mx == x && mtmp->my == y) return(mtmp);
	return(0);
}

struct gen *
g_at(x,y,ptr)
register x,y;
register struct gen *ptr;
{
	while(ptr) {
		if(ptr->gx == x && ptr->gy == y) return(ptr);
		ptr = ptr->ngen;
	}
	return(0);
}
//E*O*F mklev.c//

echo x - mklev.h
cat > "mklev.h" << '//E*O*F mklev.h//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "config.h"

#ifdef BSD
#include <strings.h>		/* declarations for strcat etc. */
#else
#include <string.h>		/* idem on System V */
#define	index	strchr
#define	rindex	strrchr
#endif BSD

#include	"def.objclass.h"

typedef struct {
	xchar x,y;
} coord;

#include	"def.monst.h"	/* uses coord */
#include	"def.gen.h"
#include	"def.obj.h"

extern char *sprintf();

#define	BUFSZ	256	/* for getlin buffers */
#define	PL_NSIZ	32	/* name of player, ghost, shopkeeper */

#define	HWALL 1	/* Level location types */
#define	VWALL 2
#define	SDOOR 3
#define	SCORR 4
#define	LDOOR 5
#define	DOOR 6	/* smallest accessible type */
#define	CORR 7
#define	ROOM 8
#define	STAIRS 9
#ifdef QUEST
#define	CORR_SYM	':'
#else
#define	CORR_SYM	'#'
#endif QUEST

#define	ERRCHAR	'{'

#define TRAPNUM 9

struct rm {
	char scrsym;
	unsigned typ:5;
	unsigned new:1;
	unsigned seen:1;
	unsigned lit:1;
};
extern struct rm levl[COLNO][ROWNO];

#ifndef QUEST
struct mkroom {
	xchar lx,hx,ly,hy;
	schar rtype,rlit,doorct,fdoor;
};
#define	MAXNROFROOMS	15
extern struct mkroom rooms[MAXNROFROOMS+1];
#define	DOORMAX	100
extern coord doors[DOORMAX];
#endif QUEST


#include	"def.permonst.h"
extern struct permonst mons[];
#define PM_ACIDBLOB	&mons[7]
#define	PM_PIERC	&mons[17]
#define	PM_MIMIC	&mons[37]
#define	PM_CHAM		&mons[47]
#define	PM_DEMON	&mons[54]
#define	PM_MINOTAUR	&mons[55]	/* last in mons array */
#define	PM_SHK		&mons[56]	/* very last */
#define	CMNUM		55		/* number of common monsters */

extern long *alloc();

extern xchar xdnstair, ydnstair, xupstair, yupstair; /* stairs up and down. */

extern xchar dlevel;
#ifdef WIZARD
extern boolean wizard;
#endif WIZARD
#define	newstring(x)	(char *) alloc((unsigned)(x))
//E*O*F mklev.h//

echo x - mklv.makemaz.c
cat > "mklv.makemaz.c" << '//E*O*F mklv.makemaz.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "mklev.h"
extern struct monst *makemon();
extern coord mazexy();

makemaz()
{
	int x,y;
	register zx,zy;
	coord mm;

	for(x = 2; x < COLNO-1; x++)
		for(y = 2; y < ROWNO-1; y++)
			levl[x][y].typ = (x%2 && y%2) ? 0 : HWALL;
	mm = mazexy();
	zx = mm.x;
	zy = mm.y;
	walkfrom(zx,zy);
	mkobj_at(AMULET_SYM, zx, zy);
	mkobj_at(ROCK_SYM, zx, zy);	/* put a rock on top of the amulet */
	/* (probably this means that one needs a wand of digging to reach 
	    the amulet - we must make sure that the player has a chance of
	    getting one; let us say when he kills the minotaur; of course
	    the minotaur itself may be blocked behind rocks, but well...) */
	for(x = 2; x < COLNO-1; x++)
		for(y = 2; y < ROWNO-1; y++) {
			switch(levl[x][y].typ) {
			case HWALL:
				levl[x][y].scrsym = '-';
				break;
			case ROOM:
				levl[x][y].scrsym = '.';
				break;
			}
		}
	for(x = rn1(8,11); x; x--) {
		mm = mazexy();
		mkobj_at(0, mm.x, mm.y);
	}
	for(x = rn1(10,2); x; x--) {
		mm = mazexy();
		mkobj_at(ROCK_SYM, mm.x, mm.y);
	}
	mm = mazexy();
	(void) makemon(PM_MINOTAUR, mm.x, mm.y);
	for(x = rn1(5,7); x; x--) {
		mm = mazexy();
		(void) makemon((struct permonst *) 0, mm.x, mm.y);
	}
	for(x = rn1(6,7); x; x--) {
		mm = mazexy();
		mkgold(0,mm.x,mm.y);
	}
	for(x = rn1(6,7); x; x--)
		mktrap(0,1);
	mm = mazexy();
	levl[(xupstair = mm.x)][(yupstair = mm.y)].scrsym = '<';
	levl[xupstair][yupstair].typ = STAIRS;
	xdnstair = ydnstair = 0;
}

walkfrom(x,y) int x,y; {
register int q,a,dir;
int dirs[4];
	levl[x][y].typ = ROOM;
	while(1) {
		q = 0;
		for(a = 0; a < 4; a++)
			if(okay(x,y,a)) dirs[q++]= a;
		if(!q) return;
		dir = dirs[rn2(q)];
		move(&x,&y,dir);
		levl[x][y].typ = ROOM;
		move(&x,&y,dir);
		walkfrom(x,y);
	}
}

move(x,y,dir)
register int *x, *y;
register int dir;
{
	switch(dir){
		case 0: --(*y); break;
		case 1: (*x)++; break;
		case 2: (*y)++; break;
		case 3: --(*x); break;
	}
}

okay(x,y,dir)
int x,y;
register int dir;
{
	move(&x,&y,dir);
	move(&x,&y,dir);
	if(x<3 || y<3 || x>COLNO-3 || y>ROWNO-3 || levl[x][y].typ != 0)
		return(0);
	else
		return(1);
}

coord
mazexy(){
	coord mm;
	mm.x = 3 + 2*rn2(COLNO/2 - 2);
	mm.y = 3 + 2*rn2(ROWNO/2 - 2);
	return mm;
}
//E*O*F mklv.makemaz.c//

echo x - mklv.shk.c
cat > "mklv.shk.c" << '//E*O*F mklv.shk.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#ifndef QUEST
#include "mklev.h"
#include "def.eshk.h"
#define	ESHK	((struct eshk *)(&(shk->mextra[0])))
extern struct monst *makemon();

char shtypes[] = "=/)%?!["; /* 8 shoptypes: 7 specialised, 1 mixed */
schar shprobs[] = { 3,3,5,5,10,10,14,50 };	/* their probabilities */

mkshop(){
register struct mkroom *sroom;
register int sh,sx,sy,i;
register char let;
int roomno;
register struct monst *shk;
	for(sroom = &rooms[0], roomno = 0; ; sroom++, roomno++){
		if(sroom->hx < 0) return;
		if(sroom->lx <= xdnstair && xdnstair <= sroom->hx &&
		   sroom->ly <= ydnstair && ydnstair <= sroom->hy) continue;
		if(sroom->lx <= xupstair && xupstair <= sroom->hx &&
		   sroom->ly <= yupstair && yupstair <= sroom->hy) continue;
		if(
#ifdef WIZARD
		   wizard ||
#endif WIZARD
			sroom->doorct == 1) break;
	}
#ifdef WIZARD
	if(wizard){
		extern char *getenv();
		register char *ep = getenv("SHOPTYPE");
		if(ep){
			if(*ep == 'z' || *ep == 'Z'){
				mkzoo();
				return;
			}
			for(i=0; shtypes[i]; i++)
				if(*ep == shtypes[i]) break;
			let = i;
			goto gotlet;
		}
	}
#endif WIZARD
	for(i = rn2(100),let = 0; (i -= shprobs[let])>= 0; let++)
		if(!shtypes[let]) break;	/* superfluous */
#ifdef WIZARD
gotlet:
#endif WIZARD
	sroom->rtype = 8+let;
	let = shtypes[let];
	sh = sroom->fdoor;
	sx = doors[sh].x;
	sy = doors[sh].y;
	if(sx == sroom->lx-1) sx++; else
	if(sx == sroom->hx+1) sx--; else
	if(sy == sroom->ly-1) sy++; else
	if(sy == sroom->hy+1) sy--; else {
		printf("Where is shopdoor?");
		return;
	}
	if(!(shk = makemon(PM_SHK,sx,sy))) return;
	shk->isshk = shk->mpeaceful = 1;
	shk->msleep = 0;
	shk->mtrapseen = ~0;	/* we know all the traps already */
	ESHK->shoproom = roomno;
	ESHK->shd = doors[sh];
	ESHK->shk.x = sx;
	ESHK->shk.y = sy;
	ESHK->robbed = 0;
	ESHK->visitct = 0;
	shk->mgold = 1000 + 30*rnd(100);	/* initial capital */
	ESHK->billct = 0;
	findname(ESHK->shknam, let);
	for(sx = sroom->lx; sx <= sroom->hx; sx++)
	for(sy = sroom->ly; sy <= sroom->hy; sy++){
		register struct monst *mtmp;
		if((sx == sroom->lx && doors[sh].x == sx-1) ||
		   (sx == sroom->hx && doors[sh].x == sx+1) ||
		   (sy == sroom->ly && doors[sh].y == sy-1) ||
		   (sy == sroom->hy && doors[sh].y == sy+1)) continue;
		if(rn2(100) < dlevel && !m_at(sx,sy) &&
		   (mtmp = makemon(PM_MIMIC, sx, sy))){
			mtmp->mimic =
			    (let && rn2(10) < dlevel) ? let : ']';
			continue;
		}
		mkobj_at(let, sx, sy);
	}
#ifdef WIZARD
	if(wizard) printf("I made a %c-shop.", let ? let : 'g');
#endif WIZARD
}

mkzoo(){
register struct mkroom *sroom;
register int sh,sx,sy,i;
int goldlim = 500 * dlevel;
	for(sroom = &rooms[0]; ; sroom++){
		if(sroom->hx < 0) return;
		if(sroom->lx <= xdnstair && xdnstair <= sroom->hx &&
		   sroom->ly <= ydnstair && ydnstair <= sroom->hy) continue;
		if(sroom->lx <= xupstair && xupstair <= sroom->hx &&
		   sroom->ly <= yupstair && yupstair <= sroom->hy) continue;
		if(sroom->doorct == 1) break;
	}
	sroom->rtype = 7;
	sh = sroom->fdoor;
	for(sx = sroom->lx; sx <= sroom->hx; sx++)
	for(sy = sroom->ly; sy <= sroom->hy; sy++){
		if((sx == sroom->lx && doors[sh].x == sx-1) ||
		   (sx == sroom->hx && doors[sh].x == sx+1) ||
		   (sy == sroom->ly && doors[sh].y == sy-1) ||
		   (sy == sroom->hy && doors[sh].y == sy+1)) continue;
		(void) makemon((struct permonst *) 0,sx,sy);
		i = sq(dist2(sx,sy,doors[sh].x,doors[sh].y));
		if(i >= goldlim) i = 5*dlevel;
		goldlim -= i;
		mkgold(10 + rn2(i), sx, sy);
	}
#ifdef WIZARD
	if(wizard) printf("I made a zoo.");
#endif WIZARD
}

dist2(x0,y0,x1,y1){
	return((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1));
}

sq(a) int a; {
	return(a*a);
}
#endif QUEST
//E*O*F mklv.shk.c//

echo x - mklv.shknam.c
cat > "mklv.shknam.c" << '//E*O*F mklv.shknam.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "mklev.h"

char *shkliquors[] = {
	/* Ukraine */
	"Njezjin", "Tsjernigof", "Gomel", "Ossipewsk", "Gorlowka",
	/* N. Russia */
	"Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",
	"Narodnaja", "Kyzyl",
	/* Silezie */
	"Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",
	"Brzeg", "Krnov", "Hradec Kralove",
	/* Schweiz */
	"Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",
	"Flims", "Vals", "Schuls", "Zum Loch",
	0
};

char *shkbooks[] = {
	/* Eire */
	"Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",
	"Loughrea", "Croagh", "Maumakeogh", "Ballyjamesduff",
	"Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",
	"Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan",
	"Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh",
	"Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea",
	"Culdaff", "Dunfanaghy", "Inishbofin", "Kesh",
	0
};

char *shkarmors[] = {
	/* Turquie */
	"Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",
	"Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",
	"Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",
	"Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",
	"Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",
	"Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",
	0
};

char *shkwands[] = {
	/* Wales */
	"Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",
	"Rhaeader", "Llandrindod", "Llanfair-ym-muallt",
	"Y-Fenni", "Measteg", "Rhydaman", "Beddgelert",
	"Curig", "Llanrwst", "Llanerchymedd", "Caergybi",
	/* Scotland */
	"Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",
	"Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",
	"Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",
	"Kyleakin", "Dunvegan",
	0
};

char *shkrings[] = {
	/* Hollandse familienamen */
	"Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",
	"Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",
	"Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix",
	"Ypey",
	/* Skandinaviske navne */
	"Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",
	"Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",
	"Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",
	0
};

char *shkfoods[] = {
	/* Indonesia */
	"Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",
	"Bandjar", "Parbalingga", "Bojolali", "Sarangan",
	"Ngebel", "Djombang", "Ardjawinangun", "Berbek",
	"Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi",
	"Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan",
	"Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe",
	"Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe",
	0
};

char *shkweapons[] = {
	/* Perigord */
	"Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",
	"Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",
	"Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac",
	"Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac",
	"Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon",
	"Eymoutiers", "Eygurande", "Eauze", "Labouheyre",
	0
};

char *shkgeneral[] = {
	/* Suriname */
	"Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",
	"Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",
	"Akalapi", "Sipaliwini",
	/* Greenland */
	"Annootok", "Upernavik", "Angmagssalik",
	/* N. Canada */
	"Aklavik", "Inuvik", "Tuktoyaktuk",
	"Chicoutimi", "Ouiatchouane", "Chibougamau",
	"Matagami", "Kipawa", "Kinojevis",
	"Abitibi", "Maganasipi",
	/* Iceland */
	"Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",
	"Holmavik",
	0
};

struct shk_nx {
	char x;
	char **xn;
} shk_nx[] = {
	{ POTION_SYM,	shkliquors },
	{ SCROLL_SYM,	shkbooks },
	{ ARMOR_SYM,	shkarmors },
	{ WAND_SYM,	shkwands },
	{ RING_SYM,	shkrings },
	{ FOOD_SYM,	shkfoods },
	{ WEAPON_SYM,	shkweapons },
	{ 0,		shkgeneral }
};

findname(nampt, let) char *nampt; char let; {
register struct shk_nx *p = shk_nx;
register char **q;
register int i;
	while(p->x && p->x != let) p++;
	q = p->xn;
	for(i=0; i<dlevel; i++) if(!q[i]){
		/* Not enough names, try general name */
		if(let) findname(nampt, 0);
		else (void) strcpy(nampt, "Dirk");
		return;
	}
	(void) strncpy(nampt, q[i], PL_NSIZ);
	nampt[PL_NSIZ-1] = 0;
}
//E*O*F mklv.shknam.c//

exit 0

ed@gargoyle.UChicago.UUCP (Ed Friedman) (01/13/85)

# This is part 13 (of 15) of the Hack sources. Send complaints to
# mcvax!play .
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# hack.whatis.c hack.wield.c hack.worm.c hack.worn.c hack.zap.c makedefs.c

echo x - hack.whatis.c
cat > "hack.whatis.c" << '//E*O*F hack.whatis.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include	<stdio.h>
#include "hack.h"

dowhatis(str)
register char *str;
{
	FILE *fp;
	char bufr[BUFSZ];
	register char *ep, q;

	pline("Specify what? ");
	getlin(bufr);
	str = bufr;
	while(*str == ' ') str++;
	q = *str;
	if(*(str+1)) pline("One character please.");
	else if(!(fp = fopen("data","r"))) pline("Cannot open data file!");
	else {
		while(fgets(bufr,BUFSZ,fp))
			if(*bufr == q) {
				ep = index(bufr, '\n');
				if(ep) *ep = 0;
				else impossible();
				pline(bufr);
				if(ep[-1] == ';') morewhat(fp);
				goto fnd;
			}
		pline("Unknown symbol.");
	fnd:
		(void) fclose(fp);
	}
}

morewhat(fp) FILE *fp; {
char bufr[BUFSZ];
register char *ep;
	pline("More info? ");
	if(readchar() != 'y') return;
	cls();
	while(fgets(bufr,BUFSZ,fp) && *bufr == '\t'){
		ep = index(bufr, '\n');
		if(!ep) break;
		*ep = 0;
		puts(bufr+1);
	}
	more();
	docrt();
}
//E*O*F hack.whatis.c//

echo x - hack.wield.c
cat > "hack.wield.c" << '//E*O*F hack.wield.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include	"hack.h"

setuwep(obj) register struct obj *obj; {
	setworn(obj, W_WEP);
}

dowield()
{
	register struct obj *wep;
	register int res = 0;

	multi = 0;
	if(!(wep = getobj("#-)", "wield"))) /* nothing */;
	else if(uwep == wep)
		pline("You are already wielding that!");
	else if(uwep && uwep->cursed)
		pline("The %s welded to your hand!",
			aobjnam(uwep, "are"));
	else if((int) wep == -1) {
		if(uwep == 0){
			pline("You are already empty handed.");
		} else {
			setuwep((struct obj *) 0);
			res++;
			pline("You are empty handed.");
		}
	} else if(uarms && wep->otyp == TWO_HANDED_SWORD)
	pline("You cannot wield a two-handed sword and wear a shield.");
	else if(wep->owornmask & (W_ARMOR | W_RING))
		pline("You cannot wield that!");
	else {
		setuwep(wep);
		res++;
		if(uwep->cursed) pline("The %s itself to your hand!",
			aobjnam(uwep, "weld"));
		else prinv(uwep);
	}
	return(res);
}

corrode_weapon(){
	if(!uwep || uwep->olet != WEAPON_SYM) return;	/* %% */
	if(uwep->rustfree)
		pline("Your %s not affected.", aobjnam(uwep, "are"));
	else {
		pline("Your %s!", aobjnam(uwep, "corrode"));
		uwep->spe--;
	}
}

chwepon(otmp,amount)
register struct obj *otmp;
register amount;
{
register char *color = (amount < 0) ? "black" : "green";
register char *time;
	if(!uwep || uwep->olet != WEAPON_SYM) {
		strange_feeling(otmp);
		return(0);
	}

	if(uwep->otyp == WORM_TOOTH && amount > 0) {
		uwep->otyp = CRYSKNIFE;
		pline("Your weapon seems sharper now.");
		uwep->cursed = 0;
		return(1);
	}

	if(uwep->otyp == CRYSKNIFE && amount < 0) {
		uwep->otyp = WORM_TOOTH;
		pline("Your weapon looks duller now.");
		return(1);
	}

	/* there is a (soft) upper limit to uwep->spe */
	if(amount > 0 && uwep->spe > 5 && rn2(3)) {
	    pline("Your %s violently green for a while and then evaporates.",
		aobjnam(uwep, "glow"));
	    useup(uwep);
	    return(1);
	}
	if(!rn2(6)) amount *= 2;
	time = (amount*amount == 1) ? "moment" : "while";
	pline("Your %s %s for a %s.",
		aobjnam(uwep, "glow"), color, time);
	uwep->spe += amount;
	if(amount > 0) uwep->cursed = 0;
	return(1);
}
//E*O*F hack.wield.c//

echo x - hack.worm.c
cat > "hack.worm.c" << '//E*O*F hack.worm.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
#ifndef NOWORM
#include "def.wseg.h"

struct wseg *wsegs[32];	/* linked list, tail first */
struct wseg *wheads[32];
long wgrowtime[32];

getwn(mtmp) struct monst *mtmp; {
register tmp;
	for(tmp=1; tmp<32; tmp++) if(!wsegs[tmp]) {
		mtmp->wormno = tmp;
		return(1);
	}
	return(0);	/* level infested with worms */
}

/* called to initialize a worm unless cut in half */
initworm(mtmp) struct monst *mtmp; {
register struct wseg *wtmp;
register tmp = mtmp->wormno;
	if(!tmp) return;
	wheads[tmp] = wsegs[tmp] = wtmp = newseg();
	wgrowtime[tmp] = 0;
	wtmp->wx = mtmp->mx;
	wtmp->wy = mtmp->my;
/*	wtmp->wdispl = 0;*/
	wtmp->nseg = 0;
}

worm_move(mtmp) struct monst *mtmp; {
register struct wseg *wtmp, *whd;
register tmp = mtmp->wormno;
	wtmp = newseg();
	wtmp->wx = mtmp->mx;
	wtmp->wy = mtmp->my;
	wtmp->nseg = 0;
/*	wtmp->wdispl = 0;*/
	(whd = wheads[tmp])->nseg = wtmp;
	wheads[tmp] = wtmp;
	if(cansee(whd->wx,whd->wy)){
		unpmon(mtmp);
		atl(whd->wx, whd->wy, '~');
		whd->wdispl = 1;
	} else	whd->wdispl = 0;
	if(wgrowtime[tmp] <= moves) {
		if(!wgrowtime[tmp]) wgrowtime[tmp] = moves + rnd(5);
		else wgrowtime[tmp] += 2+rnd(15);
		mtmp->orig_hp++;
		mtmp->mhp++;
		return;
	}
	whd = wsegs[tmp];
	wsegs[tmp] = whd->nseg;
	remseg(whd);
}

worm_nomove(mtmp) register struct monst *mtmp; {
register tmp;
register struct wseg *wtmp;
	tmp = mtmp->wormno;
	wtmp = wsegs[tmp];
	if(wtmp == wheads[tmp]) return;
	if(wtmp == 0 || wtmp->nseg == 0) panic("worm_nomove?");
	wsegs[tmp] = wtmp->nseg;
	remseg(wtmp);
	mtmp->mhp--;	/* orig_hp not changed ! */
}

wormdead(mtmp) register struct monst *mtmp; {
register tmp = mtmp->wormno;
register struct wseg *wtmp, *wtmp2;
	if(!tmp) return;
	mtmp->wormno = 0;
	for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2){
		wtmp2 = wtmp->nseg;
		remseg(wtmp);
	}
	wsegs[tmp] = 0;
}

wormhit(mtmp) register struct monst *mtmp; {
register tmp = mtmp->wormno;
register struct wseg *wtmp;
	if(!tmp) return;	/* worm without tail */
	for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp->nseg)
		(void) hitu(mtmp,1);
}

wormsee(tmp) register unsigned tmp; {
register struct wseg *wtmp = wsegs[tmp];
	if(!wtmp) panic("wormsee: wtmp==0");
	for(; wtmp->nseg; wtmp = wtmp->nseg)
		if(!cansee(wtmp->wx,wtmp->wy) && wtmp->wdispl){
			newsym(wtmp->wx, wtmp->wy);
			wtmp->wdispl = 0;
		}
}

pwseg(wtmp) register struct wseg *wtmp; {
	if(!wtmp->wdispl){
		atl(wtmp->wx, wtmp->wy, '~');
		wtmp->wdispl = 1;
	}
}

cutworm(mtmp,x,y,weptyp)
register struct monst *mtmp;
register xchar x,y;
register uchar weptyp;		/* uwep->otyp or 0 */
{
	register struct wseg *wtmp, *wtmp2;
	register struct monst *mtmp2;
	register tmp,tmp2;
	if(mtmp->mx == x && mtmp->my == y) return;	/* hit headon */

	/* cutting goes best with axe or sword */
	tmp = rnd(20);
	if(weptyp == LONG_SWORD || weptyp == TWO_HANDED_SWORD ||
		weptyp == AXE) tmp += 5;
	if(tmp < 12) return;

	/* if tail then worm just loses a tail segment */
	tmp = mtmp->wormno;
	wtmp = wsegs[tmp];
	if(wtmp->wx == x && wtmp->wy == y){
		wsegs[tmp] = wtmp->nseg;
		remseg(wtmp);
		return;
	}

	/* cut the worm in two halves */
	mtmp2 = newmonst(0);
	*mtmp2 = *mtmp;
	mtmp2->mxlth = mtmp2->mnamelth = 0;

	/* sometimes the tail end dies */
	if(rn2(3) || !getwn(mtmp2)){
		monfree(mtmp2);
		tmp2 = 0;
	} else {
		tmp2 = mtmp2->wormno;
		wsegs[tmp2] = wsegs[tmp];
		wgrowtime[tmp2] = 0;
	}
	do {
		if(wtmp->nseg->wx == x && wtmp->nseg->wy == y){
			if(tmp2) wheads[tmp2] = wtmp;
			wsegs[tmp] = wtmp->nseg->nseg;
			remseg(wtmp->nseg);
			wtmp->nseg = 0;
			if(tmp2){
				pline("You cut the worm in half.");
				mtmp2->orig_hp = mtmp2->mhp =
					d(mtmp2->data->mlevel, 8);
				mtmp2->mx = wtmp->wx;
				mtmp2->my = wtmp->wy;
				mtmp2->nmon = fmon;
				fmon = mtmp2;
				pmon(mtmp2);
			} else {
				pline("You cut off part of the worm's tail.");
				remseg(wtmp);
			}
			mtmp->mhp /= 2;
			return;
		}
		wtmp2 = wtmp->nseg;
		if(!tmp2) remseg(wtmp);
		wtmp = wtmp2;
	} while(wtmp->nseg);
	panic("Cannot find worm segment");
}

remseg(wtmp) register struct wseg *wtmp; {
	if(wtmp->wdispl)
		newsym(wtmp->wx, wtmp->wy);
	free((char *) wtmp);
}
#endif NOWORM
//E*O*F hack.worm.c//

echo x - hack.worn.c
cat > "hack.worn.c" << '//E*O*F hack.worn.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"

struct worn {
	long w_mask;
	struct obj **w_obj;
} worn[] = {
	{ W_ARM, &uarm },
	{ W_ARM2, &uarm2 },
	{ W_ARMH, &uarmh },
	{ W_ARMS, &uarms },
	{ W_ARMG, &uarmg },
	{ W_RINGL, &uleft },
	{ W_RINGR, &uright },
	{ W_WEP, &uwep },
	{ W_BALL, &uball },
	{ W_CHAIN, &uchain },
	{ 0, 0 }
};

setworn(obj, mask)
register struct obj *obj;
long mask;
{
	register struct worn *wp;
	register struct obj *oobj;

	for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) {
		oobj = *(wp->w_obj);
		if(oobj && !(oobj->owornmask & wp->w_mask)){
			pline("Setworn: mask = %d.", wp->w_mask);
			impossible();
		}
		if(oobj) oobj->owornmask &= ~wp->w_mask;
		if(obj && oobj && wp->w_mask == W_ARM){
			if(uarm2) {
				pline("Setworn: uarm2 set?");
				impossible();
			} else
				setworn(uarm, W_ARM2);
		}
		*(wp->w_obj) = obj;
		if(obj) obj->owornmask |= wp->w_mask;
	}
	if(uarm2 && !uarm) {
		uarm = uarm2;
		uarm2 = 0;
		uarm->owornmask ^= (W_ARM | W_ARM2);
	}
}

/* called e.g. when obj is destroyed */
setnotworn(obj) register struct obj *obj; {
	register struct worn *wp;

	for(wp = worn; wp->w_mask; wp++)
		if(obj == *(wp->w_obj)) {
			*(wp->w_obj) = 0;
			obj->owornmask &= ~wp->w_mask;
		}
	if(uarm2 && !uarm) {
		uarm = uarm2;
		uarm2 = 0;
		uarm->owornmask ^= (W_ARM | W_ARM2);
	}
}
//E*O*F hack.worn.c//

echo x - hack.zap.c
cat > "hack.zap.c" << '//E*O*F hack.zap.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"

extern struct monst *makemon();
struct monst *bhit();
char *exclam();

char *fl[]= {
	"magic missile",
	"bolt of fire",
	"sleep ray",
	"bolt of cold",
	"death ray"
};

dozap()
{
	register struct obj *obj;
	register struct monst *mtmp;
	xchar zx,zy;
	register num;

	obj = getobj("/", "zap");
	if(!obj) return(0);
	if(obj->spe < 0 || (obj->spe == 0 && rn2(121))) {
		pline("Nothing Happens");
		return(1);
	}
	if(obj->spe == 0)
		pline("You wrest one more spell from the worn-out wand.");
	if(!(objects[obj->otyp].bits & NODIR) && !getdir())
		return(1); /* make him pay for knowing !NODIR */
	obj->spe--;
	if(objects[obj->otyp].bits & IMMEDIATE) {
		if((u.uswallow && (mtmp = u.ustuck)) ||
		   (mtmp = bhit(u.dx,u.dy,rn1(8,6),0))) {
			wakeup(mtmp);
			switch(obj->otyp) {
			case WAN_STRIKING:
				if(rnd(20) < 10+mtmp->data->ac) {
					register int tmp = d(2,12);
					hit("wand", mtmp, exclam(tmp));
					mtmp->mhp -= tmp;
					if(mtmp->mhp < 1) killed(mtmp);
				} else miss("wand", mtmp);
				break;
			case WAN_SLOW_MONSTER:
				mtmp->mspeed = MSLOW;
				break;
			case WAN_SPEED_MONSTER:
				mtmp->mspeed = MFAST;
				break;
			case WAN_UNDEAD_TURNING:
				if(index("WVZ&",mtmp->data->mlet)) {
					mtmp->mhp -= rnd(8);
					if(mtmp->mhp<1) killed(mtmp);
					else mtmp->mflee = 1;
				}
				break;
			case WAN_POLYMORPH:
				if( newcham(mtmp,&mons[rn2(CMNUM)]) )
					objects[obj->otyp].oc_name_known = 1;
				break;
			case WAN_CANCELLATION:
				mtmp->mcan = 1;
				break;
			case WAN_TELEPORT_MONSTER:
				rloc(mtmp);
				break;
			case WAN_MAKE_INVISIBLE:
				mtmp->minvis = 1;
				break;
#ifdef WAN_PROBING
			case WAN_PROBING:
				mstatusline(mtmp);
				break;
#endif WAN_PROBING
			default:
				pline("What an interesting wand (%d)",
					obj->otyp);
				impossible();
			}
		}
	} else {
	switch(obj->otyp){
		case WAN_LIGHT:
			litroom(TRUE);
			break;
		case WAN_SECRET_DOOR_DETECTION:
			if(!findit()) return(1);
			break;
		case WAN_CREATE_MONSTER:
			{ register int cnt = 1;
			if(!rn2(23)) cnt += rn2(7) + 1;
			while(cnt--)
			    (void) makemon((struct permonst *) 0, u.ux, u.uy);
			}
			break;
		case WAN_WISHING:
			{ char buf[BUFSZ];
			  register struct obj *otmp;
			  extern struct obj *readobjnam(), *addinv();
		      if(u.uluck + rn2(5) < 0) {
			pline("Unfortunately, nothing happens.");
			break;
		      }
		      pline("You may wish for an object. What do you want? ");
		      getlin(buf);
		      otmp = readobjnam(buf);
		      otmp = addinv(otmp);
		      prinv(otmp);
		      break;
			}
		case WAN_DIGGING:
			{ register struct rm *room;
			  register int digdepth;
			if(u.uswallow) {
				pline("You pierce %s's stomach wall!",
					monnam(u.ustuck));
				u.uswallow = 0;
				mnexto(u.ustuck);
				u.ustuck->mhp = 1;	/* almost dead */
				u.ustuck = 0;
				setsee();
				docrt();
				break;
			}
			zx = u.ux+u.dx;
			zy = u.uy+u.dy;
			if(!isok(zx,zy)) break;
			digdepth = 4 + rn2(10);
			if(levl[zx][zy].typ == CORR) num = CORR;
			else num = ROOM;
			Tmp_at(-1, '*');	/* open call */
			while(digdepth--) {
				if(zx == 0 || zx == COLNO-1 ||
					 zy == 0 || zy == ROWNO-1)
					break;
				room = &levl[zx][zy];
				Tmp_at(zx,zy);
				if(!xdnstair){
					if(zx < 3 || zx > COLNO-3 ||
					    zy < 3 || zy > ROWNO-3)
						break;
					if(room->typ == HWALL ||
					    room->typ == VWALL){
						room->typ = ROOM;
						break;
					}
				} else if(num == ROOM || num == 10){
					if(room->typ != ROOM && room->typ) {
						if(room->typ != CORR)
							room->typ = DOOR;
						if(num == 10) break;
						num = 10;
					} else if(!room->typ)
						room->typ = CORR;
				} else {
					if(room->typ != CORR && room->typ) {
						room->typ = DOOR;
						break;
					} else room->typ = CORR;
				}
				mnewsym(zx,zy);
				zx += u.dx;
				zy += u.dy;
			}
			mnewsym(zx,zy);	/* not always necessary */
			Tmp_at(-1,-1);	/* closing call */
			break;
			}
		default:
			buzz((int) obj->otyp - WAN_MAGIC_MISSILE,
				u.ux, u.uy, u.dx, u.dy);
			break;
		}
		if(!objects[obj->otyp].oc_name_known) {
			u.urexp += 10;
			objects[obj->otyp].oc_name_known = 1;
		}
	}
	return(1);
}

char *
exclam(force)
register int force;
{
	/* force == 0 occurs e.g. with sleep ray */
	/* note that large force is usual with wands so that !! would
		require information about hand/weapon/wand */
	return( (force < 0) ? "?" : (force <= 4) ? "." : "!" );
}

hit(str,mtmp,force)
register char *str;
register struct monst *mtmp;
register char *force;		/* usually either "." or "!" */
{
	if(!cansee(mtmp->mx,mtmp->my)) pline("The %s hits it.", str);
	else pline("The %s hits %s%s", str, monnam(mtmp), force);
}

miss(str,mtmp)
register char *str;
register struct monst *mtmp;
{
	if(!cansee(mtmp->mx,mtmp->my)) pline("The %s misses it.",str);
	else pline("The %s misses %s.",str,monnam(mtmp));
}

/* sets bhitpos to the final position of the weapon thrown */
/* coord bhitpos; */

/* check !u.uswallow before calling bhit() */
struct monst *
bhit(ddx,ddy,range,sym)
register ddx,ddy,range;
char sym;
{
	register struct monst *mtmp;

	bhitpos.x = u.ux;
	bhitpos.y = u.uy;

	if(sym) tmp_at(-1, sym);	/* open call */
	while(range--) {
		bhitpos.x += ddx;
		bhitpos.y += ddy;
		if(mtmp = m_at(bhitpos.x,bhitpos.y)){
			if(sym) tmp_at(-1, -1);	/* close call */
			return(mtmp);
		}
		if(levl[bhitpos.x][bhitpos.y].typ<CORR) {
			bhitpos.x -= ddx;
			bhitpos.y -= ddy;
			break;
		}
		if(sym) tmp_at(bhitpos.x, bhitpos.y);
	}
	if(sym) tmp_at(-1, 0);	/* leave last symbol */
	return(0);
}

struct monst *
boomhit(dx,dy) {
	register int i, ct;
	register struct monst *mtmp;
	char sym = ')';
	extern schar xdir[], ydir[];

	bhitpos.x = u.ux;
	bhitpos.y = u.uy;

	for(i=0; i<8; i++) if(xdir[i] == dx && ydir[i] == dy) break;
	tmp_at(-1, sym);	/* open call */
	for(ct=0; ct<10; ct++) {
		if(i == 8) i = 0;
		sym = ')' + '(' - sym;
		tmp_at(-2, sym);	/* change let call */
		dx = xdir[i];
		dy = ydir[i];
		bhitpos.x += dx;
		bhitpos.y += dy;
		if(mtmp = m_at(bhitpos.x, bhitpos.y)){
			tmp_at(-1,-1);
			return(mtmp);
		}
		if(levl[bhitpos.x][bhitpos.y].typ<CORR) {
			bhitpos.x -= dx;
			bhitpos.y -= dy;
			break;
		}
		if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
			if(rn2(20) >= 10+u.ulevel){	/* we hit ourselves */
				(void) thitu(10, rnd(10), "boomerang");
				break;
			} else {	/* we catch it */
				tmp_at(-1,-1);
				pline("Skillfully, you catch the boomerang.");
				return((struct monst *) -1);
			}
		}
		tmp_at(bhitpos.x, bhitpos.y);
		if(ct % 5 != 0) i++;
	}
	tmp_at(-1, -1);	/* do not leave last symbol */
	return(0);
}

char
dirlet(dx,dy) register dx,dy; {
	return
		(dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
}

/* type < 0: monster spitting fire at you */
buzz(type,sx,sy,dx,dy)
register int type;
register xchar sx,sy;
register int dx,dy;
{
	register char *fltxt = (type < 0) ? "blaze of fire" : fl[type];
	struct rm *lev;
	xchar range;
	struct monst *mon;

	if(u.uswallow) {
		register int tmp;

		if(type < 0) return;
		tmp = zhit(u.ustuck, type);
		pline("The %s rips into %s%s",
			fltxt, monnam(u.ustuck), exclam(tmp));
		return;
	}
	if(type < 0) pru();
	range = rn1(7,7);
	Tmp_at(-1, dirlet(dx,dy));	/* open call */
	while(range-- > 0) {
		sx += dx;
		sy += dy;
		if((lev = &levl[sx][sy])->typ) Tmp_at(sx,sy);
		else {
			int bounce = 0;
			if(cansee(sx-dx,sy-dy)) pline("The %s bounces!",fltxt);
			if(levl[sx][sy-dy].typ > DOOR) bounce = 1;
			if(levl[sx-dx][sy].typ > DOOR) {
				if(!bounce || rn2(2)) bounce = 2;
			}
			switch(bounce){
			case 0:
				dx = -dx;
				dy = -dy;
				continue;
			case 1:
				dy = -dy;
				sx -= dx;
				break;
			case 2:
				dx = -dx;
				sy -= dy;
				break;
			}
			Tmp_at(-2,dirlet(dx,dy));
			continue;
		}
		if((mon = m_at(sx,sy)) &&
		   (type >= 0 || mon->data->mlet != 'D')) {
			wakeup(mon);
			if(rnd(20) < 18 + mon->data->ac) {
				register int tmp = zhit(mon,type);
				if(mon->mhp < 1) {
					if(type < 0) {
					    if(cansee(mon->mx,mon->my))
					      pline("%s is killed by the %s!",
						Monnam(mon), fltxt);
					    mondied(mon);
					} else
					    killed(mon);
				} else
					hit(fltxt, mon, exclam(tmp));
				range -= 2;
			} else
				miss(fltxt,mon);
		} else if(sx == u.ux && sy == u.uy) {
			if(rnd(20) < 18+u.uac) {
				register int dam = 0;
				range -= 2;
				pline("The %s hits you!",fltxt);
				switch(type) {
				case 0:
					dam = d(2,6);
					break;
				case -1:	/* dragon fire */
				case 1:
					if(Fire_resistance)
						pline("You don't feel hot!");
					else dam = d(6,6);
					break;
				case 2:
					nomul(-rnd(25)); /* sleep ray */
					break;
				case 3:
					if(Cold_resistance)
						pline("You don't feel cold!");
					else dam = d(6,6);
					break;
				case 4:
					u.uhp = -1;
				}
				losehp(dam,fltxt);
			} else pline("The %s whizzes by you!",fltxt);
		}
		if(lev->typ <= DOOR) {
			int bounce = 0, rmn;
			if(cansee(sx,sy)) pline("The %s bounces!",fltxt);
			range--;
			if(!dx || !dy || !rn2(20)){
				dx = -dx;
				dy = -dy;
			} else {
			  if((rmn = levl[sx][sy-dy].typ) > DOOR &&
			    (
			     rmn >= ROOM ||
				levl[sx+dx][sy-dy].typ > DOOR)){
				bounce = 1;
			  }
			  if((rmn = levl[sx-dx][sy].typ) > DOOR &&
			    (
			     rmn >= ROOM ||
				levl[sx-dx][sy+dy].typ > DOOR)){
				if(!bounce || rn2(2)){
					bounce = 2;
				}
			  }
			  switch(bounce){
			  case 0:
				dy = -dy;
				dx = -dx;
				break;
			  case 1:
				dy = -dy;
				break;
			  case 2:
				dx = -dx;
				break;
			  }
			  Tmp_at(-2, dirlet(dx,dy));
			}
		}
	}
	Tmp_at(-1,-1);
}

zhit(mon,type)			/* returns damage to mon */
register struct monst *mon;
register type;
{
	register int tmp = 0;

	switch(type) {
	case 0:			/* magic missile */
		tmp = d(2,6);
		break;
	case -1:		/* Dragon blazing fire */
	case 1:			/* fire */
		if(index("Dg", mon->data->mlet)) break;
		tmp = d(6,6);
		if(mon->data->mlet == 'Y') tmp += 7;
		break;
	case 2:			/* sleep*/
		mon->mfroz = 1;
		break;
	case 3:			/* cold */
		if(index("YFgf", mon->data->mlet)) break;
		tmp = d(6,6);
		if(mon->data->mlet == 'D') tmp += 7;
		break;
	case 4:			/* death*/
		if(index("WVZ",mon->data->mlet)) break;
		tmp = mon->mhp+1;
		break;
	}
	mon->mhp -= tmp;
	return(tmp);
}
//E*O*F hack.zap.c//

echo x - makedefs.c
cat > "makedefs.c" << '//E*O*F makedefs.c//'
/* construct definitions of object constants */
#define	DEF_FILE	"def.objects.h"
#define	LINSZ	1000
#define	STRSZ	40

int fd;
char string[STRSZ];

main(){
register int index = 0;
register int propct = 0;
register char *sp;
	fd = open(DEF_FILE, 0);
	if(fd < 0) {
		perror(DEF_FILE);
		exit(1);
	}
	skipuntil("objects[] = {");
	while(getentry()) {
		if(!*string){
			index++;
			continue;
		}
		for(sp = string; *sp; sp++)
			if(*sp == ' ' || *sp == '\t')
				*sp = '_';
		if(!strncmp(string, "RIN_", 4)){
			capitalize(string+4);
			printf("#define	%s	u.uprops[%d].p_flgs\n",
				string+4, propct++);
		}
		for(sp = string; *sp; sp++) capitalize(sp);
		/* avoid trouble with stupid C preprocessors */
		if(!strncmp(string, "WORTHLESS_PIECE_OF_", 19))
			printf("/* #define %s	%d */\n", string, index);
		else
			printf("#define	%s	%d\n", string, index);
		index++;
	}
	printf("\n#define	CORPSE	DEAD_HUMAN\n");
	printf("#define	LAST_GEM	(JADE+1)\n");
	printf("#define	LAST_RING	%d\n", propct);
	printf("#define	NROFOBJECTS	%d\n", index-1);
}

char line[LINSZ], *lp = line, *lp0 = line, *lpe = line;
int eof;

readline(){
register int n = read(fd, lp0, (line+LINSZ)-lp0);
	if(n < 0){
		printf("Input error.\n");
		exit(1);
	}
	if(n == 0) eof++;
	lpe = lp0+n;
}

char
nextchar(){
	if(lp == lpe){
		readline();
		lp = lp0;
	}
	return((lp == lpe) ? 0 : *lp++);
}

skipuntil(s) char *s; {
register char *sp0, *sp1;
loop:
	while(*s != nextchar())
		if(eof) {
			printf("Cannot skipuntil %s\n", s);
			exit(1);
		}
	if(strlen(s) > lpe-lp+1){
		register char *lp1, *lp2;
		lp2 = lp;
		lp1 = lp = lp0;
		while(lp2 != lpe) *lp1++ = *lp2++;
		lp2 = lp0;	/* save value */
		lp0 = lp1;
		readline();
		lp0 = lp2;
		if(strlen(s) > lpe-lp+1) {
			printf("error in skipuntil");
			exit(1);
		}
	}
	sp0 = s+1;
	sp1 = lp;
	while(*sp0 && *sp0 == *sp1) sp0++, sp1++;
	if(!*sp0){
		lp = sp1;
		return(1);
	}
	goto loop;
}

getentry(){
int inbraces = 0, inparens = 0, stringseen = 0, commaseen = 0;
int prefix = 0;
char ch;
#define	NSZ	10
char identif[NSZ], *ip;
	string[0] = string[4] = 0;
	/* read until {...} or XXX(...) followed by ,
	   skip comment and #define lines
	   deliver 0 on failure
	 */
	while(1) {
		ch = nextchar();
	swi:
		if(letter(ch)){
			ip = identif;
			do {
				if(ip < identif+NSZ-1) *ip++ = ch;
				ch = nextchar();
			} while(letter(ch) || digit(ch));
			*ip = 0;
			while(ch == ' ' || ch == '\t') ch = nextchar();
			if(ch == '(' && !inparens && !stringseen)
				if(!strcmp(identif, "WAND") ||
				   !strcmp(identif, "RING") ||
				   !strcmp(identif, "POTION") ||
				   !strcmp(identif, "SCROLL"))
				(void) strncpy(string, identif, 3),
				string[3] = '_',
				prefix = 4;
		}
		switch(ch) {
		case '/':
			/* watch for comment */
			if((ch = nextchar()) == '*')
				skipuntil("*/");
			goto swi;
		case '{':
			inbraces++;
			continue;
		case '(':
			inparens++;
			continue;
		case '}':
			inbraces--;
			if(inbraces < 0) return(0);
			continue;
		case ')':
			inparens--;
			if(inparens < 0) {
				printf("too many ) ?");
				exit(1);
			}
			continue;
		case '\n':
			/* watch for #define at begin of line */
			if((ch = nextchar()) == '#'){
				register char pch;
				/* skip until '\n' not preceded by '\\' */
				do {
					pch = ch;
					ch = nextchar();
				} while(ch != '\n' || pch == '\\');
				continue;
			}
			goto swi;
		case ',':
			if(!inparens && !inbraces){
				if(prefix && !string[prefix])
					string[0] = 0;
				if(stringseen) return(1);
				printf("unexpected ,\n");
				exit(1);
			}
			commaseen++;
			continue;
		case '\'':
			if((ch = nextchar()) == '\\') ch = nextchar();
			if(nextchar() != '\''){
				printf("strange character denotation?\n");
				exit(1);
			}
			continue;
		case '"':
			{
				register char *sp = string + prefix;
				register char pch;
				register int store = (inbraces || inparens)
					&& !stringseen++ && !commaseen;
				do {
					pch = ch;
					ch = nextchar();
					if(store && sp < string+STRSZ)
						*sp++ = ch;
				} while(ch != '"' || pch == '\\');
				if(store) *--sp = 0;
				continue;
			}
		}
	}
}

capitalize(sp) register char *sp; {
	if('a' <= *sp && *sp <= 'z') *sp += 'A'-'a';
}

letter(ch) register char ch; {
	return( ('a' <= ch && ch <= 'z') ||
		('A' <= ch && ch <= 'Z') );
}

digit(ch) register char ch; {
	return( '0' <= ch && ch <= '9' );
}
//E*O*F makedefs.c//

exit 0

ed@gargoyle.UChicago.UUCP (Ed Friedman) (01/13/85)

# This is part 15 and last of the Hack sources. Now you should read
# READ_ME, edit config.h and say make. If you are running BSD4.2
# probably all will go well; otherwise I wish you good luck.
# I would like to hear about any problems encountered while trying
# to setup or play Hack. Also suggestions for modifications & extensions
# are welcome. Mail to decvax!mcvax!play or decvax!mcvax!aeb .
#
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# perm record rnd.c rumors savelev.h

echo x - perm
cat > "perm" << '//E*O*F perm//'
//E*O*F perm//

echo x - record
cat > "record" << '//E*O*F record//'
//E*O*F record//

echo x - rnd.c
cat > "rnd.c" << '//E*O*F rnd.c//'
#define RND(x)	((rand()>>3) % x)

rn1(x,y)
register x,y;
{
	return(RND(x)+y);
}

rn2(x)
register x;
{
	return(RND(x));
}

rnd(x)
register x;
{
	return(RND(x)+1);
}

d(n,x)
register n,x;
{
	register tmp = n;

	while(n--) tmp += RND(x);
	return(tmp);
}
//E*O*F rnd.c//

echo x - rumors
cat > "rumors" << '//E*O*F rumors//'
"Quit" is a four letter word.
A fading corridor enlightens your insight.
A glowing potion is too hot to drink.
A long worm hits with all of its length.
A monstrous mind is a toy for ever.
A ring of adornment protects against Nymphs.
A rumour has it that rumours are just rumours.
A smoky potion surely affects your vision.
A spear might hit a nurse.
A spear will hit an ettin.
A tin of smoked eel is a wonderful find.
A truly wise man never plays leapfrog with a unicorn.
A two-handed sword usually misses.
A unicorn can be tamed only by a fair maiden.
A visit to the Zoo is very educational; you meet interesting animals.
A wand of vibration might bring the whole cave crashing about your ears.
Afraid of falling piercers? Wear a helmet!
All monsters are created evil, but some are more evil than others.
An elven cloak is always the height of fashion.
An elven cloak protects against magic.
Any small object that is accidentally dropped will hide under a larger object.
Attack long worms from the rear - that is so much safer!
Be careful when eating salmon - your fingers might become greasy.
Be careful when throwing a boomerang - you might hit the back of your head.
Better go home and hit your kids. They are just little monsters!
Better go home and play with your kids. They are just little monsters!
Better leave the dungeon, otherwise you might get hurt badly.
Beware of dark rooms - they may be the Morgue.
Beware of falling rocks, wear a helmet!
Beware of wands of instant disaster.
Beyond the 23-rd level lies a happy retirement in a room of your own.
Blank scrolls make more interesting reading.
Booksellers never read scrolls; it might carry them to far away.
Booksellers never read scrolls; it might leave their shop unguarded.
Dead lizards protect against a cockatrice.
Death is just around the next door.
Death is life's way of telling you you've been fired.
Descend in order to meet more decent monsters.
Direct a direct hit on your direct opponent, directing in the right direction.
Don't bother about money: only Leprechauns and shopkeepers are interested.
Don't forget! Large dogs are MUCH harder to kill than little dogs.
Don't tell a soul you found a secret door, otherwise it isn't secret anymore.
Don't throw gems. They are so precious! Besides, you might hit a roommate.
Drinking might affect your health.
Drop your vanity and get rid of your jewels! Pickpockets about!
Dungeon expects every monster to do his duty.
Dust is an armor of poor quality.
Eventually all wands of striking do strike.
Eventually you will come to admire the swift elegance of a retreating nymph.
Ever tried to catch a flying boomerang?
Every dog should be a domesticated one.
Every hand has only one finger to put a ring on. You've got only two hands. So?
Everybody should have tasted a scorpion at least once in his life.
Fiery letters might deter monsters.
First Law of Hacking: leaving is much more difficult than entering.
For any remedy there is a misery.
Fourth Law of Hacking: you will find the exit at the entrance.
Gems are the droppings of other inmates.
Gems do get a burden.
Genocide on shopkeepers is punishable.
Giving head to a long worm is like a long lasting reception.
Good day for overcoming obstacles.  Try a steeplechase.
Gossip is the opiate of the depressed.
Hackers do it with bugs.
Half Moon tonight.  (At least it's better than no Moon at all.)
Hitting is the lingua franca in these regions.
Hungry dogs are unreliable.
Hungry? There is an abundance of food on the next level.
I doubt whether nurses are virgins.
I once knew a hacker who ate too fast and choked to death.....
I smell a maze of twisty little passages.
If a shopkeeper kicks you out of his shop, he'll kick you out of the dungeon.
If you are too cute some monsters might be tempted to embrace you.
If you can't learn to do it well, learn to enjoy doing it badly.
If you need a wand of digging, kindly ask the minotaur.
If you see nurses you better start looking somewhere for a doctor.
If you turn blind: don't expect your dog to be turned into a seeing-eye dog.
If you want to hit, use a dagger.
If you want to rob a shop, train your dog.
If you're afraid of trapdoors, just cover the floor with all you've got.
Improve your environment, using a wand of rearrangement.
In a hurry? Try a ride on a fast moving quasit!
In need of a rest? Quaff a potion of sickness!
Inside a shop you better take a look at the price tags before buying anything.
It is bad manners to use a wand in a shop.
It is not always a good idea to whistle for your dog.
It might be a good idea to offer the unicorn a ruby.
It seems you keep overlooking a sign reading "No trespassing"!
It's all a matter of life and death, so beware of the undead.
It's not safe to Save.
Just below any trapdoor there may be another one. Just keep falling!
Keep a clear mind: quaff clear potions.
Keep your armours away from rust.
Keep your weaponry away from acids.
Kill a unicorn and you kill your luck.
Latest news? Put newsgroup 'netUNX.indoor.hackers-scroll' in your .newsrc!
Leprechauns hide their gold in a secret room.
Liquor sellers do not drink; they hate to see you twice.
Looking pale? Quaff a red potion!
M.M.Vault cashiers teleport any amount of gold to the next local branch.
Many monsters make a murdering mob.
Money is the root of all evil.
Money to invest? Take it to the local branch of the Magic Memory Vault!
Monsters come from nowhere to hit you everywhere.
Monsters sleep because you are boring, not because they ever get tired.
Most monsters prefer minced meat. That's why they are hitting you!
Most rumors are just as misleading as this one.
Much ado Nothing Happens.
Murder complaint? Mail to 'netnix!devil!gamble!freak!trap!lastwill!rip'.
Never ask a shopkeeper for a price list.
Never attack a guard.
Never fight a monster: you might get killed.
Never kick a sleeping dog.
Never map the labyrinth.
Never mind the monsters hitting you: they just replace the charwomen.
Never ride a long worm.
Never trust a random generator in magic fields.
Never use your best weapon to engrave a curse.
Never vomit on a door mat.
No weapon is better than a crysknife.
Not all rumors are as misleading as this one.
Not even a spear will hit a Xorn.
One has to leave shops before closing time.
One level further down somebody is getting killed, right now.
One wand of concentration equals eight scrolls of create monster.
Only a wizard can use a magic whistle.
Only david can find the zoo!
Only real trappers escape traps.
Only wizards are able to zap a wand.
Opening a tin is difficult, especially when you are not so strong!
Opening a tin is difficult, especially when you attempt this bare handed!
Operation coded OVERKILL has started now.
PLEASE ignore previous rumour.
Plain nymphs are harmless.
Playing billiards pays when you are in a shop.
Pursue the monsters and you will be had indeed.
Put on a ring of teleportation: it will take you away from onslaught.
Reading Tolkien might help you.
Reading Herbert will disgust you, but in one case it might be enlightening.
Reading might change your vision.
Reading might improve your scope.
Relying on a dog might turn you in a dog addict.
Savings do include amnesia.
Scorpions often hide under tripe rations.
Screw up your courage!  You've screwed up everything else.
Second Law of Hacking: first in, first out.
Shopkeepers accept creditcards, as long as you pay cash.
Snakes are often found under worthless objects.
Some monsters can be tamed. I once saw a hacker with a tame Dragon!
Speed Kills (The Doors)
Spinach, carrot, and a melon - a meal fit for a nurse!
Stay clear of the level of no return.
Suddenly the dungeon will collapse ...
Take a long worm from the rear, according to its mate it's a lot more fun.
Teleportation lessens your orientation.
The Jackal only eats bad food.
The Leprechaun Gold Tru$t is no division of the Magic Memory Vault.
The Leprechauns hide their treasure in a small hidden room.
The air is positively magic in here. Better wear a negative armor.
The best equipment for your work is, of course, the most expensive.
The emptiness of a ghost is too heavy to bear.
The longer the wand the better.
The secret of wands of Nothing Happens: try again!
The use of dynamite is dangerous.
There are monsters of softening penetration.
There are monsters of striking charity.
There have been people like you in here; their ghosts seek revenge on you.
There is a VIP-lounge on this level. Only first-class travellers admitted.
There is a big treasure hidden in the zoo!
There is a message concealed in each fortune cookie.
There is a trap on this level!
There is more magic in this cave than meets the eye.
There is no business like throw business.
There is no harm in praising a large dog.
There seem to be monsters of touching benevolence.
They say that a dagger hits.
They say that a dog avoids traps.
They say that a dog can be trained to fetch objects.
They say that a dog never steps on a cursed object.
They say that a spear will hit a Dragon.
They say that a spear will hit a Xorn.
They say that a spear will hit a neo-otyugh. (Do YOU know what that is?)
They say that a spear will hit an ettin.
They say that a two-handed sword misses.
They say that a unicorn might bring you luck.
They say that an elven cloak may be worn over your armor.
They say that an elven cloak protects against magic.
They say that dead lizards protect against a cockatrice.
They say that killing a shopkeeper brings bad luck.
They say that monsters never step on a scare monster scroll.
They say that only david can find the zoo!
They say that the use of dynamite is dangerous.
They say that there is a big treasure hidden in the zoo!
They say that there is a message concealed in each fortune cookie.
They say that there is a trap on this level!
They say that throwing food at a wild dog might tame him.
They say that you cannot trust scrolls of rumour.
They say that you need a key in order to open locked doors.
Third Law of Hacking: the last blow counts most.
This is the Leprechaun Law: every purse has a price.
Throwing food at a wild dog might tame him.
Tin openers are rare indeed.
To hit or not to hit, that is the question.
Travel fast, use some magic speed!
Tripe on its own is revolting,  but with onions it's delicious!
Try hacking in the wee hours: you will have more room.
Vampires hate garlic.
Visitors are requested not to apply genocide to shopkeepers.
WARNING from H.M. Govt:  Quaffing may be dangerous to your health.
Watch your steps on staircases.
Wear armor, going naked seems to offend public decency in here.
What do you think would be the use of a sword called "Orcrist" ?
When a piercer drops in on you, you will be tempted to hit the ceiling!
When in a shop, do as shopkeepers do.
When punished, watch your steps on the stairs!
Why would anybody in his sane mind engrave "Elbereth" ?
You are heading for head-stone for sure.
You are just the kind of bad food some monsters like to digest.
You can always wear an elven cloak.
You can't leave a shop through the back door: there ain't one!
You cannot trust scrolls of rumour.
You feel greedy and want more gold? Why don't you try digging?
You feel like someone is pulling your leg.
You may have a kick from kicking a little dog.
You might cut yourself on a long sword.
You need a key in order to open locked doors.
You want to regain strength? Two levels ahead is a guesthouse!
You offend Shai-Hulud by sheathing your crysknife without having drawn blood.
You'll need a spear if you want to attack a Dragon.
You've got to know how to put out a yellow light.
Zapping a wand of Nothing Happens doesn't harm you a bit.
//E*O*F rumors//

echo x - savelev.h
cat > "savelev.h" << '//E*O*F savelev.h//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#ifdef MKLEV

savelev(){
	int fd;

#else
extern struct obj *billobjs;

savelev(fd){
#ifndef NOWORM
	register struct wseg *wtmp, *wtmp2;
	register tmp;
#endif NOWORM

#endif MKLEV

#ifdef MKLEV
	if((fd = creat(tfile,FMASK)) < 0) panic("Cannot create %s\n", tfile);
#else
	if(fd < 0) panic("Save on bad file!");
#endif MKLEV
	bwrite(fd,(char *) levl,sizeof(levl));
#ifdef MKLEV
	bwrite(fd,(char *) nul,sizeof(long));
#else
	bwrite(fd,(char *) &moves,sizeof(long));
#endif MKLEV
	bwrite(fd,(char *) &xupstair,sizeof(xupstair));
	bwrite(fd,(char *) &yupstair,sizeof(yupstair));
	bwrite(fd,(char *) &xdnstair,sizeof(xdnstair));
	bwrite(fd,(char *) &ydnstair,sizeof(ydnstair));
	savemonchn(fd, fmon);
	savegenchn(fd, fgold);
	savegenchn(fd, ftrap);
	saveobjchn(fd, fobj);
#ifdef MKLEV
	saveobjchn(fd, (struct obj *) 0);
	bwrite(fd,(char *) nul, sizeof(unsigned));
#else
	saveobjchn(fd, billobjs);
	billobjs = 0;
	save_engravings(fd);
#endif MKLEV
#ifndef QUEST
	bwrite(fd,(char *) rooms,sizeof(rooms));
	bwrite(fd,(char *) doors,sizeof(doors));
#endif QUEST
	fgold = ftrap = 0;
	fmon = 0;
	fobj = 0;
#ifndef MKLEV
/*--------------------------------------------------------------------*/
#ifndef NOWORM
	bwrite(fd,(char *) wsegs,sizeof(wsegs));
	for(tmp=1; tmp<32; tmp++){
		for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2){
			wtmp2 = wtmp->nseg;
			bwrite(fd,(char *) wtmp,sizeof(struct wseg));
		}
		wsegs[tmp] = 0;
	}
	bwrite(fd,(char *) wgrowtime,sizeof(wgrowtime));
#endif NOWORM
/*--------------------------------------------------------------------*/
#endif MKLEV
}

bwrite(fd,loc,num)
register fd;
register char *loc;
register unsigned num;
{
/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
	if(write(fd, loc, (int) num) != num)
		panic("cannot write %d bytes to file #%d",num,fd);
}

saveobjchn(fd,otmp)
register fd;
register struct obj *otmp;
{
	register struct obj *otmp2;
	unsigned xl;
	int minusone = -1;

	while(otmp) {
		otmp2 = otmp->nobj;
		xl = otmp->onamelth;
		bwrite(fd, (char *) &xl, sizeof(int));
		bwrite(fd, (char *) otmp, xl + sizeof(struct obj));
		free((char *) otmp);
		otmp = otmp2;
	}
	bwrite(fd, (char *) &minusone, sizeof(int));
}

savemonchn(fd,mtmp)
register fd;
register struct monst *mtmp;
{
	register struct monst *mtmp2;
	unsigned xl;
	int minusone = -1;
	struct permonst *monbegin = &mons[0];

	bwrite(fd, (char *) &monbegin, sizeof(monbegin));

	while(mtmp) {
		mtmp2 = mtmp->nmon;
		xl = mtmp->mxlth + mtmp->mnamelth;
		bwrite(fd, (char *) &xl, sizeof(int));
		bwrite(fd, (char *) mtmp, xl + sizeof(struct monst));
		if(mtmp->minvent) saveobjchn(fd,mtmp->minvent);
		free((char *) mtmp);
		mtmp = mtmp2;
	}
	bwrite(fd, (char *) &minusone, sizeof(int));
}

savegenchn(fd,gtmp)
register fd;
register struct gen *gtmp;
{
	register struct gen *gtmp2;
	while(gtmp) {
		gtmp2 = gtmp->ngen;
		bwrite(fd, (char *) gtmp, sizeof(struct gen));
		free((char *) gtmp);
		gtmp = gtmp2;
	}
	bwrite(fd, nul, sizeof(struct gen));
}
//E*O*F savelev.h//

exit 0