[net.sources] Hack sources

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 1 (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:
# Bugs Makefile Original_READ_ME Porting READ_ME alloc.c config.h data date.h

echo x - Bugs
cat > "Bugs" << '//E*O*F Bugs//'
- the locking system is ridiculous
- the access of record should be locked
- record should be encrypted
- the level files and the save file should be encrypted and stored in the
  users directory
- for vaxen: mklev should be incorporated in hack
//E*O*F Bugs//

echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
# Hack or Quest Makefile.

# on some systems the termcap library is in -ltermcap
TERMLIB = -ltermlib


# make hack
GAME = hack
CAPGAME = HACK
GAMEDIR = ../tmp
CFLAGS = -O
HACKCSRC = hack.Decl.c\
	hack.apply.c hack.bones.c hack.c hack.cmdlist.c hack.do.c\
	hack.do_name.c hack.do_wear.c hack.dog.c hack.eat.c hack.end.c\
	hack.engrave.c hack.fight.c hack.invent.c hack.ioctl.c\
	hack.lev.c hack.main.c hack.makemon.c\
	hack.mkobj.c hack.mhitu.c\
	hack.mon.c hack.monst.c hack.o_init.c hack.objnam.c\
	hack.options.c\
	hack.pri.c hack.read.c hack.rip.c hack.rumors.c\
	hack.save.c\
	hack.search.c hack.shk.c hack.stat.c hack.steal.c\
	hack.termcap.c hack.timeout.c hack.topl.c\
	hack.track.c hack.trap.c hack.tty.c hack.u_init.c hack.vault.c\
	hack.whatis.c hack.wield.c hack.worm.c hack.worn.c hack.zap.c\
	hack.version.c rnd.c alloc.c

CSOURCES = $(HACKCSRC) mklev.c mklv.shk.c mklv.shknam.c mklv.makemaz.c\
	makedefs.c

HSOURCES = savelev.h\
	mklev.h hack.h hack.mfndpos.h config.h\
	def.edog.h def.eshk.h def.func_tab.h def.gen.h def.objclass.h\
	def.monst.h def.obj.h def.permonst.h def.trap.h def.wseg.h\
	def.objects.h

SOURCES = $(CSOURCES) $(HSOURCES)

AUX = data help hh rumors hack.6 hack.sh

HOBJ = hack.Decl.o hack.apply.o hack.bones.o hack.o hack.cmdlist.o hack.do.o\
	hack.do_name.o hack.do_wear.o hack.dog.o hack.eat.o hack.end.o\
	hack.engrave.o hack.fight.o hack.invent.o hack.ioctl.o\
	hack.lev.o hack.main.o hack.makemon.o\
	hack.mkobj.o hack.mhitu.o hack.mon.o\
	hack.monst.o hack.o_init.o hack.objnam.o hack.options.o hack.pri.o\
	hack.read.o hack.rip.o\
	hack.rumors.o hack.save.o\
	hack.search.o\
	hack.shk.o hack.stat.o hack.steal.o hack.termcap.o\
	hack.timeout.o hack.topl.o\
	hack.track.o hack.trap.o\
	hack.tty.o hack.u_init.o hack.vault.o hack.whatis.o hack.wield.o\
	hack.worm.o hack.worn.o hack.zap.o\
	hack.version.o

GOBJ = rnd.o alloc.o

all:	$(GAME) mklev
	@echo "Made Hack."

$(GAME):	$(HOBJ) $(GOBJ) Makefile
	@echo "Loading ..."
	@ld -X -o $(GAME) /lib/crt0.o $(GOBJ) $(HOBJ) $(TERMLIB) -lc

makedefs:	makedefs.c
	cc -o makedefs makedefs.c


hack.onames.h:	makedefs def.objects.h
	makedefs > hack.onames.h
mklv.mkobj.o:	mklev.h hack.onames.h hack.mkobj.c
	rm -f mklv.mkobj.c
	ln hack.mkobj.c mklv.mkobj.c
	cc -c $(CFLAGS) -DMKLEV mklv.mkobj.c
	rm -f mklv.mkobj.c
mklv.makemon.o:	mklev.h hack.makemon.c
	rm -f mklv.makemon.c
	ln hack.makemon.c mklv.makemon.c
	cc -c $(CFLAGS) -DMKLEV mklv.makemon.c
	rm -f mklv.makemon.c
mklv.o_init.o:	hack.o_init.c def.objects.h hack.onames.h
	rm -f mklv.o_init.c
	ln hack.o_init.c mklv.o_init.c
	cc -c $(CFLAGS) -DMKLEV mklv.o_init.c
	rm -f mklv.o_init.c
mklev.o:
	cc -c $(CFLAGS) -DMKLEV mklev.c
MKLOBJ = mklev.o hack.monst.o mklv.o_init.o mklv.mkobj.o mklv.shk.o\
	mklv.shknam.o mklv.makemon.o mklv.makemaz.o $(GOBJ)
mklev:	$(MKLOBJ)
	cc -o mklev $(MKLOBJ)

lint:	lint_h lint_m
	@echo "Lint done."

lint_h:
# lint cannot have -p here because (i) capitals are meaningful:
# [Ww]izard, (ii) identifiers may coincide in the first six places:
# doweararm() versus dowearring().
# _flsbuf comes from <stdio.h>, a bug in the system libraries.
	lint -axbh -DLINT $(HACKCSRC) | sed '/_flsbuf/d' > olint_h
	cat olint_h | sed '/never used/d;/warning/d'

lint_m:
	lint -axbh -DLINT -DMKLEV mklev.c hack.makemon.c hack.monst.c\
		hack.o_init.c hack.mkobj.c mklv.shk.c mklv.makemaz.c alloc.c\
		rnd.c


print:
	print *.h Makefile  $(AUX)
	print mklev.c mklev.*.c rnd.c alloc.c hack.c
	print hack.Decl.c Hack.magic.C hack.[a-m]*.c
	print hack.[n-z]*.c
	print show.c makedefs.c

diff:
	@- for i in $(SOURCES) $(AUX) ; do \
		echo ; echo diff $D/$$i $$i ; \
		diff $D/$$i $$i ; done

distribution: Makefile
	@- for i in READ_ME $(SOURCES) $(AUX) Makefile date.h hack.onames.h\
		; do \
		cmp -s $$i $D/$$i || \
		( echo cp $$i $D ; cp $$i $D ) ; done
# the distribution directory also contains the empty files
# perm and record, and the informative files Porting and Bugs.


install:
	rm -f /usr/games/$(CAPGAME)
	cp $(GAME) /usr/games/$(CAPGAME)
#	chmod 0710 /usr/games/$(CAPGAME)
	chmod 04711 /usr/games/$(CAPGAME)
	rm -f $(GAMEDIR)/mklev
	cp mklev $(GAMEDIR)/mklev
#	chmod 0750 $(GAMEDIR)/mklev
	chmod 0751 $(GAMEDIR)/mklev
	rm -f $(GAMEDIR)/bones*

depend:
# For the moment we are lazy and disregard /usr/include files because
# the sources contain them conditionally. Perhaps we should use cpp.
#			-e 's,<\(.*\)>,"/usr/include/\1",' \
#
	for i in ${CSOURCES}; do \
		( /bin/grep '^#[ 	]*include' $$i | sed -n \
			-e '/<.*>/d' \
			-e 's/[^"]*"\([^"]*\)".*/\1/' \
			-e H -e '$$g' -e '$$s/\n/ /g' \
			-e '$$s/.*/'$$i': &/' -e '$$s/\.c:/.o:/p' \
			>> makedep); done
	for i in ${HSOURCES}; do \
		( /bin/grep '^#[ 	]*include' $$i | sed -n \
			-e '/<.*>/d' \
			-e 's/[^"]*"\([^"]*\)".*/\1/' \
			-e H -e '$$g' -e '$$s/\n/ /g' \
			-e '$$s/.*/'$$i': &\
				touch '$$i/p \
			>> makedep); done
	@echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
	@echo '$$r makedep' >>eddep
	@echo 'w' >>eddep
	@cp Makefile Makefile.bak
	ed - Makefile < eddep
	rm eddep makedep
	@echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
	@echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
	@echo '# see make depend above' >> Makefile
	- diff Makefile Makefile.bak
	@rm -f Makefile.bak

# DO NOT DELETE THIS LINE

hack.Decl.o:  hack.h
hack.apply.o:  hack.h def.edog.h
hack.bones.o:  hack.h
hack.o:  hack.h def.trap.h
hack.cmdlist.o:  config.h def.objclass.h def.func_tab.h
hack.dog.o:  hack.h hack.mfndpos.h def.edog.h
hack.eat.o:  hack.h
hack.engrave.o:  hack.h
hack.fight.o:  hack.h
hack.invent.o:  hack.h def.wseg.h
hack.main.o:  hack.h
hack.makemon.o:  mklev.h hack.h
hack.mkobj.o:  mklev.h hack.h hack.onames.h
hack.mhitu.o:  hack.h
hack.mon.o:  hack.h hack.mfndpos.h
hack.monst.o:  mklev.h def.eshk.h
hack.o_init.o:  config.h def.objects.h hack.onames.h
hack.objnam.o:  hack.h
hack.options.o:  config.h hack.h
hack.pri.o:  hack.h def.wseg.h
hack.read.o:  hack.h
hack.rumors.o:  config.h
hack.search.o:  hack.h def.trap.h
hack.shk.o:  hack.h hack.mfndpos.h def.eshk.h
hack.steal.o:  hack.h
hack.termcap.o:  config.h
hack.timeout.o:  hack.h
hack.track.o:  hack.h
hack.trap.o:  hack.h def.trap.h
hack.vault.o:  hack.h
hack.whatis.o:  hack.h
hack.wield.o:  hack.h
hack.worm.o:  hack.h def.wseg.h
hack.worn.o:  hack.h
hack.zap.o:  hack.h
hack.version.o:  date.h
mklev.o:  mklev.h def.trap.h savelev.h
mklv.shk.o:  mklev.h def.eshk.h
mklv.shknam.o:  mklev.h
mklv.makemaz.o:  mklev.h
mklev.h:  config.h def.objclass.h def.monst.h def.gen.h def.obj.h def.permonst.h
			touch mklev.h
hack.h:  mklev.h hack.onames.h
			touch hack.h
def.objects.h:  def.objclass.h
			touch def.objects.h
# DEPENDENCIES MUST END AT END OF FILE
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see make depend above
//E*O*F Makefile//

echo x - Original_READ_ME
cat > "Original_READ_ME" << '//E*O*F Original_READ_ME//'
This is export hack, my first semester programming project.

To set it up for your system, you will have to do the following:
	1: create a hack uid, to own the top ten list, etc.
	2: create a hack directory "/usr/lib/game/hack" is the default.
	2.5: make the directory 700 mode.	/* sav files go in there...*/
	3: modify hack.main.c to use the new directory.
	4: modify hack.main.c so it uses the new hack gid.  Gid accounts can
go into magic mode without the password, can get cores with ^G, etc.
(make sure gid isn't checked anywhere else...)
	5: recompile hack.
	6: put it in games after making it set-uid hack.
	8: fix the bugs I undobtedly left in it.
	9: tell me what you think of it.

	Hack uses the UCB file /etc/termcap to get your terminal escape codes.
If you don't use it, you will have to make extensive changes to hack.pri.c

If you find any bugs (That you think I don't know about), or have any
awesome new changes (Like a better save (One that works!)), or have ANY
questions, write me
		Jay Fenlason
		29 East St.
		Sudbury Mass.
			01776

or call me at (617) 443-5036.  Since I have both a modem and a teen-age
sister, Good Luck.


Hack is split (roughly) into several source files that do different things.
I have tried to fit all the procedures having to do with a certain segment
of the game into a single file, but the job is not the best in the world.
The rough splits are:

hack.c		General random stuff and things I never got around to moving.
hack.main.c	main() and other random procedures, also the lock file stuff.
hack.mon.c	Monsters, moving, attacking, etc.
hack.do.c	drink, eat, read, wield, save, etc.
hack.do1.c	zap, wear, remove, etc...
hack.pri.c	stuff having to do with the screen, most of the terminal
		independant stuff is in here.
hack.lev.c	temp files and calling of mklev.

Because of the peculiar restraints on our system, I make mklev (create
a level) a separate procedure execd by hack when needed.  The source for
mklev is (Naturaly) mklev.c.  You may want to put mklev back into hack.
Good luck.

Most of hack was written by me, with help from
		Kenny Woodland (KW)	(general random things including
			the original BUZZ())
		Mike Thome	(MT)	(The original chamelian)
	and	Jon Payne	(JP)	(The original lock file kludge and
			the massive CURS())

This entire program would not have been possible without the SFSU Logo
Workshop.  I am eternally grateful to all of our students (Especially K.L.),
without whom I would never have seen Rogue.  I am especially grateful to
Mike Clancy, without whose generous help I would never have gotten to play
ROGUE.
//E*O*F Original_READ_ME//

echo x - Porting
cat > "Porting" << '//E*O*F Porting//'
Some remarks that may be useful when you try porting hack.

This program has grown slowly but steadily for several years.
Its original version was very buggy, and debugging soon became
rewriting. The program still bears all the signs of this slow
evolution: many similar problems are solved in dissimilar ways,
which is often rather confusing. Also, the program is much less
modular than it appears to be. Be very careful when you change
a piece of code! - everything depends on everything.

When we got the program one could not play for a quarter of an
hour without getting a core dump. Now a core dump is observed
once every other month (say, once in a thousand games).

The source was written and is reasonably well tested out on
a vax with BSD4.* . Older versions of the program run on a
PDP11/45 with V7, but at present the program is much too large.
As far as I can see, there are not many hidden assumptions about
the host machine, but there might well be problems if
one cannot cast a pointer into an integer or vice versa.
It is assumed that any structure can be at the address of a long.

The dialect of C used is rather rich: we use bitfields, structure
assignments and functions returning structures.

Porting to a M68000 with V7 took about one hour ( + compilation
time) to get the program running, and two evenings to locate a
strange bug in the shopkeeper movement, that turned out to be
a bug in the local C-compiler.
One hour of editing:
	Locate all identifier pairs that have the first 7 characters
	in common, and rename.
	[Note that case is important, and that some pairs of identifiers
	 have 10 or more initial characters in common.
	 Also note that some identifiers are generated by the program
	 makedefs (such as CROSSBOW and CROSSBOW_BOLT or DEAD_GIANT_RAT
	 and DEAD_GIANT_ANT or WORTHLESS_PIECE_OF_BLUE_GLASS and
	 WORTHLESS_PIECE_OF_YELLOW_GLASS).
	 If your C-compiler distinguishes 7 or more symbols then the
	 work is annoying but doable. However, if you are the unlucky
	 one with a compiler that only retains 6 symbols, then you
	 probably should write a C-program compactifier that reads a
	 C program and outputs an equivalent program but with all tags
	 replaced by short ones (like T0, T1, ...). This is easy but
	 not entirely trivial; e.g., references to external variables
	 and routines should remain intact.]
Two evenings of digging:
	It turned out that the C-compiler on this M68000 got confused
	when there were too many variables declared register char.
	[After  register char x,y; x = 1; y = 2;  the variable x would
	 contain 0, i.e., for the assignment y = 2 a word-move was
	 generated.]
Right now this M68000 version seems to work flawlessly.
(Note that I do not distribute a M68000 version; this porting work was
 done on a machine I no longer have access to.)
//E*O*F Porting//

echo x - READ_ME
cat > "READ_ME" << '//E*O*F READ_ME//'
Hack is a display oriented dungeons & dragons - like game.
Both display and command structure resemble rogue.
(For a game with the same structure but entirely different display -
a real cave instead of dull rectangles - try Quest)

Hack was originally written by Jay Fenlason (at lincolnsudbury:
 29 East St., Sudbury Mass., 01776) with help from
 Kenny Woodland, Mike Thome and Jon Payne.
Basically it was an implementation of Rogue, however, with 52+ instead of 26
 monster types.
The current version is more than twice as large (with such new features as
 the dog, the long worms, the shops, etc.) and almost entirely rewritten
 (only the display routines are the original ones - I must rewrite these
 too one day; especially when you are blind strange things still happen).

Files for hack:
	hack		The actual game
	mklev		The program that constructs the dungeon
	record		Top 100 list (just start with an empty file)
	news		Tells about recent changes in hack, or bugs found ...
			(Just start with no news file.)
	data		Auxiliary file used by hack to give you the names
			and sometimes some more information on the
			objects and monsters.
	help		Introductory information (no doubt outdated).
	hh		Compactified version of help.
	perm		An empty file used for locking purposes.
	rumors		Texts for fortune cookies.
			(Some of these contain information on the game,
			others are just plain stupid. Additional rumors
			are appreciated.)
	hack.sh		A shell script.
			(We have hack.sh in /usr/games/hack and
			hack in /usr/games/HACK and all the other hack stuff
			in /usr/games/lib/hack/tmp - perhaps this will make
			the script clear. There is no need for you to use it.)
	READ_ME		This file.
	Original_READ_ME Jay Fenlason's READ_ME

System files used:
	/etc/termcap	Used in conjunction with the environment variable
			$TERM.
	/bin/cat
	/usr/ucb/more
	/bin/sh		Used when $SHELL is undefined.

How to install hack:
0. Compile the sources. Perhaps you should first look at the file config.h
   and define BSD if you are on a BSDtype system, VAX if your C-compiler
   accepts struct initializations like PCC (and unlike the old V6 compiler
   on the PDP11/45), STUPID if your C-compiler chokes on complicated
   expressions; if your C compiler doesnt allow initialization of bit fields
   change Bitfield. When config.h looks reasonable, say 'make'.
1. If it didnt exist already, introduce a loginnname `play' .
2. The program  hack  resides in a directory so that it is executable
   for everybody and is suid play:
	---s--s--x  1 play	132096 Aug 10 13:43 HACK
   Perhaps you wish to restrict playing to certain hours, or have games
   running under nice; in that case you might write a program play.c
   such that the program play is suid play and executable for everybody
   while all the games in /usr/games are readable or executable for
   play only; all the program play does is asking for the name of a game,
   checking that time-of-day and system load do not forbid playing,
   and then executing the game. Thus:
	-r-sr-sr-x  1 play	 13312 May 24 12:52 play
	---x------  1 play	132096 Aug 10 13:43 HACK
   If you are worried about security you might let play do
   chroot("/usr/games") so that no player can get access to the rest
   of the system via shell escapes and the likes.
3. The rest of the stuff belonging to hack sits in a subdirectory hackdir
   (on our system /usr/games/lib/hack/tmp) with modes
	drwx------  3 play	1024 Aug  9 09:03 hackdir
   Here all the temporary files will be created (with names like xlock.17
   or user.5).
4. If you are not really short on file space, creating a subdirectory
   hackdir/save (modes again drwx------) will enable users to save their
   unfinished games.

The program hack is called
$ HACK [-d hackdir] [maxnrofplayers [pagingprogram]]
(for playing) or
$ HACK [-d hackdir] -s [listofusers | limit | all]
(for seeing part of the scorelist).
You will never want to call mklev, it is called from hack.
The shell file hack (in this kit called hack.sh) takes care of
calling HACK (in this kit called hack) with the right arguments.

Send complaints, bug reports, suggestions for improvements to
mcvax!aeb - in real life Andries Brouwer.
//E*O*F READ_ME//

echo x - alloc.c
cat > "alloc.c" << '//E*O*F alloc.c//'
#ifdef LINT

/*
   a ridiculous definition, suppressing
	"possible pointer alignment problem" for (long *) malloc()
	"enlarg defined but never used"
	"ftell defined (in <stdio.h>) but never used"
   from lint
*/
#include <stdio.h>
long *
alloc(n) unsigned n; {
long dummy = ftell(stderr);
	if(n) dummy = 0;	/* make sure arg is used */
	return(&dummy);
}

#else

extern char *malloc();
extern char *realloc();

long *
alloc(lth)
register unsigned lth;
{
	register char *ptr;

	if(!(ptr = malloc(lth)))
		panic("Cannot get %d bytes", lth);
	return((long *) ptr);
}

long *
enlarge(ptr,lth)
register char *ptr;
register unsigned lth;
{
	register char *nptr;

	if(!(nptr = realloc(ptr,lth)))
		panic("Cannot reallocate %d bytes", lth);
	return((long *) nptr);
}

#endif LINT
//E*O*F alloc.c//

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

#ifndef CONFIG	/* make sure the compiler doesnt see the typedefs twice */

#define	CONFIG
#define	VAX		/* to get proper struct initialization */
#define BSD		/* delete this line on System V */
/* #define STUPID */	/* avoid some complicated expressions if
			   your C compiler chokes on them */

#define WIZARD  "play"	/* the person allowed to use the -w option */
#define	NEWS	"news"	/* the file containing the latest hack news */
#define	FMASK	0660	/* file creation mask */

#define OPTIONS		/* do not delete the 'o' command */
#define SHELL		/* do not delete the '!' command */
#define	TRACK		/* do not delete the tracking properties of monsters */

/* size of terminal screen is (ROWNO+2) by COLNO */
#define	COLNO	80
#define	ROWNO	22

/*
 * small signed integers (8 bits suffice)
 *	typedef	char	schar;
 * will do when you have signed characters; otherwise use
 *	typedef	short int schar;
 */
typedef	char	schar;

/*
 * small unsigned integers (8 bits suffice - but 7 bits do not)
 * - these are usually object types; be careful with inequalities! -
 *	typedef	unsigned char	uchar;
 * will be satisfactory if you have an "unsigned char" type; otherwise use
 *	typedef unsigned short int uchar;
 */
typedef	unsigned char	uchar;

/*
 * small integers in the range 0 - 127, usually coordinates
 * although they are nonnegative they must not be declared unsigned
 * since otherwise comparisons with signed quantities are done incorrectly
 * (thus, in fact, you could make xchar equal to schar)
 */
typedef char	xchar;
typedef	xchar	boolean;		/* 0 or 1 */
#define	TRUE	1
#define	FALSE	0

/*
 * Declaration of bitfields in various structs; if your C compiler
 * doesnt handle bitfields well, e.g., if it is unable to initialize
 * structs containing bitfields, then you might use
 *	#define Bitfield(x,n)	xchar x
 * since the bitfields used never have more than 7 bits. (Most have 1 bit.)
 */
#define	Bitfield(x,n)	unsigned x:n

#endif CONFIG
//E*O*F config.h//

echo x - data
cat > "data" << '//E*O*F data//'
@	human (or you)
-	a wall
|	a wall
+	a door
.	the floor of a room
#	a corridor
}	water filled area
<	the staircase to the previous level
>	the staircase to the next level
^	a trap
$	a pile, pot or chest of gold
%	a piece of food
!	a potion
*	a gem
?	a scroll
=	a ring
/	a wand
[	a suit of armor
)	a weapon
(	a useful item (camera, key, rope etc.)
0	an iron ball
_	an iron chain
"	an amulet
,	a trapper
:	a chameleon
~	a lurker above
&	a demon
A	a giant ant
B	a giant bat
C	a centaur;
	Of all the monsters put together by  the  Greek  imagination
	the  Centaurs (Kentauroi) constituted a class in themselves.
	Despite a strong streak  of  sensuality  in  their  make-up,
	their  normal  behaviour  was  moral, and they took a kindly
	thought of man's welfare. The attempted outrage of Nessos on
	Deianeira,  and  that  of the whole tribe of Centaurs on the
	Lapith women, are more than offset  by  the  hospitality  of
	Pholos  and  by  the  wisdom of Cheiron, physician, prophet,
	lyrist, and the instructor of Achilles.  Further,  the  Cen-
	taurs  were  peculiar in that their nature, which united the
	body of a horse with the trunk and head of a  man,  involved
	an  unthinkable  duplication  of  vital organs and important
	members. So grotesque a combination seems  almost  un-Greek.
	These  strange  creatures were said to live in the caves and
	clefts of the mountains, myths associating  them  especially
	with the hills of Thessaly and the range of Erymanthos.
	               [Mythology of all races, Vol. 1, pp. 270-271]
D	a dragon
E	a floating eye
F	a freezing sphere
G	a gnome
H	a hobgoblin;
	Hobgoblin. Used by the  Puritans  and  in  later  times  for
	wicked  goblin  spirits,  as in Bunyan's 'Hobgoblin nor foul
	friend', but its more correct use is for the friendly  spir-
	its  of  the brownie type.  In 'A midsummer night's dream' a
	fairy says to Shakespeare's Puck:
	        Those that Hobgoblin call you, and sweet Puck,
	        You do their work, and they shall have good luck:
	        Are you not he?
	and obviously Puck would not wish to be called  a  hobgoblin
	if that was an ill-omened word.
	Hobgoblins are on the whole, good-humoured and ready  to  be
	helpful,  but fond of practical joking, and like most of the
	fairies rather nasty people to annoy. Boggarts hover on  the
	verge of hobgoblindom.  Bogles are just over the edge.
	One Hob mentioned by Henderson, was Hob Headless who haunted
	the  road  between Hurworth and Neasham, but could not cross
	the little river Kent, which flowed into the  Tess.  He  was
	exorcised  and  laid under a large stone by the roadside for
	ninety-nine years and a day. If anyone was so unwary  as  to
	sit  on  that stone, he would be unable to quit it for ever.
	The ninety-nine years is nearly up, so trouble may  soon  be
	heard of on the road between Hurworth and Neasham.
	               [Katharine Briggs, A  dictionary  of Fairies]
I	an invisible stalker
J	a jackal
K	a kobold
L	a leprechaun;
	The Irish Leprechaun is the Faeries' shoemaker and is  known
	under  various  names  in different parts of Ireland: Cluri-
	caune in Cork, Lurican in Kerry, Lurikeen in Kildare and Lu-
	rigadaun  in  Tipperary.  Although he works for the Faeries,
	the Leprechaun is not of the same species. He is small,  has
	dark  skin  and wears strange clothes.  His nature has some-
	thing of the manic-depressive about it: first  he  is  quite
	happy,  whistling merrily as he nails a sole on to a shoe; a
	few minutes later, he is sullen and  morose,  drunk  on  his
	home-made  heather ale. The Leprechaun's two great loves are
	tobacco and whiskey, and he is a first-rate con-man,  impos-
	sible  to  out-fox.  No  one, no matter how clever, has ever
	managed to cheat him out of his hidden pot of  gold  or  his
	magic  shilling. At the last minute he always thinks of some
	way to divert his captor's attention  and  vanishes  in  the
	twinkling  of  an eye.
	                  [From: A Field Guide to the Little People
	                     by  Nancy Arrowsmith & George Moorse. ]
M	a mimic
N	a nymph
O	an orc
P	a purple worm
Q	a quasit
R	a rust monster
S	a snake
T	a troll
U	an umber hulk
V	a vampire
W	a wraith
X	a xorn
Y	a yeti
Z	a zombie
a	an acid blob
b	a giant beetle
c	a cockatrice;
	Once in a great while, when the positions of the  stars  are
	just  right, a seven-year-old rooster will lay an egg. Then,
	along will come a snake, to coil around the egg, or a  toad,
	to  squat  upon  the  egg, keeping it warm and helping it to
	hatch. When it hatches, out comes a creature  called  basil-
	isk, or cockatrice, the most deadly of all creatures. A sin-
	gle glance from its yellow, piercing toad's eyes  will  kill
	both  man  and beast. Its power of destruction is said to be
	so great that sometimes simply to hear its  hiss  can  prove
	fatal.  Its breath is so venomenous that it causes all vege-
	tation to wither.
	There is, however, one  creature  which  can  withstand  the
	basilisk's deadly gaze, and this is the weasel. No one knows
	why this is so, but although the fierce weasel can slay  the
	basilisk,  it will itself be killed in the struggle. Perhaps
	the weasel knows the basilisk's fatal weakness: if  it  ever
	sees  its own reflection in a mirror it will perish instant-
	ly. But even a dead basilisk is dangerous, for  it  is  said
	that merely touching its lifeless body can cause a person to
	sicken and die.
	    [From: Mythical Beasts by Deirdre Headon (The Leprechaun
	           Library) and other sources. ]
d	a dog
e	an ettin
f	a fog cloud
g	a gelatinous cube
h	a homunculus
i	an imp;
	An 'imp' is an off-shoot or cutting. Thus an 'ymp tree'  was
	a grafted tree, or one grown from a cutting, not from seed.
	'Imp' properly means a small devil, an off-shoot  of  Satan,
	but  the distinction between goblins or bogles and imps from
	hell is hard to make, and many in the  Celtic  countries  as
	well as the English Puritans regarded all fairies as devils.
	The fairies of tradition often hover  uneasily  between  the
	ghostly and the diabolic state.
	                 [Katharine Briggs, A dictionary of Fairies]
j	a jaguar
k	a killer bee
l	a leocrotta
m	a minotaur
n	a nurse
o	an owlbear
p	a piercer
q	a quivering blob
r	a giant rat
s	a scorpion
t	a tengu;
	The tengu was the  most  troublesome  creature  of  Japanese
	legend.   Part  bird  and part man, with red beak for a nose
	and flashing eyes, the tengu was notorious for  stirring  up
	feuds  and  prolonging  enmity between families. Indeed, the
	belligerent tengus were supposed to have  been  man's  first
	instructors in the use of arms.
	                    [From: Mythical Beasts by Deirdre Headon
	                                 (The Leprechaun Library). ]
u	a unicorn;
	Men have always sought the elusive unicorn, for  the  single
	twisted  horn  which projected from its forehead was thought
	to be a powerful talisman. It was said that the unicorn  had
	simply  to  dip  the tip of its horn in a muddy pool for the
	water to become pure. Men also believed that to  drink  from
	this horn was a protection against all sickness, and that if
	the horn was ground to a powder it would act as an  antidote
	to  all poisons. Less than 200 years ago in France, the horn
	of a unicorn was used in a ceremony to test the  royal  food
	for poison.
	Although only the size of a small horse, the  unicorn  is  a
	very  fierce  beast,  capable  of killing an elephant with a
	single thrust from its horn.  Its  fleetness  of  foot  also
	makes  this solitary creature difficult to capture. However,
	it can be tamed and captured by a maiden. Made gentle by the
	sight  of a virgin, the unicorn can be lured to lay its head
	in her lap, and in this docile mood, the maiden  may  secure
	it with a golden rope.
	                    [From: Mythical Beasts by Deirdre Headon
	                                 (The Leprechaun Library). ]
v	a violet fungi
w	a long worm;
	From its teeth the crysknife can be manufactured.
x	a xan;
	The xan were animals sent to prick the legs of the Lords of Xibalba.
y	a yellow light
z	a zruty;
	The zruty are wild and gigantic beings, living in the wildernesses
	of the Tatra mountains.
//E*O*F data//

echo x - date.h
cat > "date.h" << '//E*O*F date.h//'

char datestring[] = "Mon Dec 17 1984";
//E*O*F date.h//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 2 (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:
# def.edog.h def.eshk.h def.func_tab.h def.gen.h def.monst.h def.obj.h def.objclass.h def.objects.h def.permonst.h def.trap.h def.wseg.h hack.6

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

struct edog {
	long hungrytime;	/* at this time dog gets hungry */
	long eattime;		/* dog is eating */
	long droptime;		/* moment dog dropped object */
	unsigned dropdist;		/* dist of drpped obj from @ */
	unsigned apport;		/* amount of training */
	long whistletime;		/* last time he whistled */
};
#define	EDOG(mp)	((struct edog *)(&(mp->mextra[0])))
//E*O*F def.edog.h//

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

#define	BILLSZ	200
struct bill_x {
	unsigned bo_id;
	unsigned useup:1;
	unsigned bquan:7;
	unsigned price;		/* price per unit */
};

struct eshk {
	long int robbed;	/* amount stolen by most recent customer */
	schar shoproom;		/* index in rooms; set by inshop() */
	coord shk;		/* usual position shopkeeper */
	coord shd;		/* position shop door */
	int billct;
	struct bill_x bill[BILLSZ];
	int visitct;		/* nr of visits by most recent customer */
	char customer[PL_NSIZ];	/* most recent customer */
	char shknam[PL_NSIZ];
};
//E*O*F def.eshk.h//

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

struct func_tab {
	char f_char;
	int (*f_funct)();
};

extern struct func_tab list[];
//E*O*F def.func_tab.h//

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

struct gen {
	struct gen *ngen;
	xchar gx,gy;
	unsigned gflag;		/* 037: trap type; 040: SEEN flag */
#define	SEEN	040
};
extern struct gen *fgold, *ftrap;
struct gen *g_at();
#define newgen()	(struct gen *) alloc(sizeof(struct gen))
//E*O*F def.gen.h//

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

struct monst {
	struct monst *nmon;
	struct permonst *data;
	unsigned m_id;
	xchar mx,my;
	xchar mdx,mdy;		/* if mdispl then pos where last displayed */
#define	MTSZ	4
	coord mtrack[MTSZ];	/* monster track */
	schar mhp,orig_hp;
	char mimic;		/* undetected mimic - this is its symbol */
	Bitfield(mdispl,1);	/* mdx,mdy valid */
	Bitfield(minvis,1);	/* invisible */
	Bitfield(cham,1);	/* shape-changer */
	Bitfield(mhide,1);	/* hides beneath objects */
	Bitfield(mundetected,1);	/* not seen in present hiding place */
	Bitfield(mspeed,2);
	Bitfield(msleep,1);
	Bitfield(mfroz,1);
	Bitfield(mconf,1);
	Bitfield(mflee,1);
	Bitfield(mcan,1);	/* has been cancelled */
	Bitfield(mtame,1);		/* implies peaceful */
	Bitfield(mpeaceful,1);	/* does not attack unprovoked */
	Bitfield(isshk,1);	/* is shopkeeper */
	Bitfield(isgd,1);	/* is guard */
	Bitfield(mcansee,1);	/* cansee 1, temp.blinded 0, blind 0 */
	Bitfield(mblinded,7);	/* cansee 0, temp.blinded n, blind 0 */
	Bitfield(mtrapped,1);	/* trapped in a pit or bear trap */
	Bitfield(mnamelth,6);	/* length of name (following mxlth) */
#ifndef NOWORM
	Bitfield(wormno,5);	/* at most 31 worms on any level */
#endif NOWORM
	unsigned mtrapseen;	/* bitmap of traps we've been trapped in */
	long mlstmv;	/* prevent two moves at once */
	struct obj *minvent;
	long mgold;
	unsigned mxlth;		/* length of following data */
	/* in order to prevent alignment problems mextra should
	   be (or follow) a long int */
	long mextra[1];		/* monster dependent info */
};

#define newmonst(xl)	(struct monst *) alloc((unsigned)(xl) + sizeof(struct monst))

extern struct monst *fmon;
#ifndef MKLEV
extern struct monst *fallen_down;
#endif MKLEV
struct monst *m_at();

/* these are in mspeed */
#define MSLOW 1 /* slow monster */
#define MFAST 2 /* speeded monster */

#define	NAME(mtmp)	(((char *) mtmp->mextra) + mtmp->mxlth)
//E*O*F def.monst.h//

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

struct obj {
	struct obj *nobj;
	unsigned o_id;
	unsigned o_cnt_id;		/* id of container object is in */
	xchar ox,oy;
	xchar odx,ody;
	uchar otyp;
	uchar owt;
	unsigned quan;	/* small in general but large in case of gold */
	schar spe;
	char olet;
	Bitfield(oinvis,1);
	Bitfield(odispl,1);
	Bitfield(known,1);	/* exact nature known */
	Bitfield(dknown,1);	/* color or text known */
	Bitfield(cursed,1);
	Bitfield(unpaid,1);	/* on some bill */
	Bitfield(rustfree,1);
	Bitfield(onamelth,6);
	long age;	/* creation date */
	long owornmask;
#define	W_ARM	01L
#define	W_ARM2	02L
#define	W_ARMH	04L
#define	W_ARMS	010L
#define	W_ARMG	020L
#define	W_ARMOR		(W_ARM | W_ARM2 | W_ARMH | W_ARMS | W_ARMG)
#define	W_RINGL	010000L	/* make W_RINGL = RING_LEFT (see uprop) */
#define	W_RINGR	020000L
#define	W_RING		(W_RINGL | W_RINGR)
#define	W_WEP	01000L
#define	W_BALL	02000L
#define	W_CHAIN	04000L
	long oextra[1];
};

extern struct obj *fobj;

#define newobj(xl)	(struct obj *) alloc((unsigned)(xl) + sizeof(struct obj))
#define	ONAME(otmp)	((char *) otmp->oextra)
//E*O*F def.obj.h//

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

/* definition of a class of objects */

struct objclass {
	char *oc_name;		/* actual name */
	char *oc_descr;		/* description when name unknown */
	char *oc_uname;		/* called by user */
	Bitfield(oc_name_known,1);
	Bitfield(oc_merge,1);	/* merge otherwise equal objects */
	char oc_olet;
	schar oc_prob;		/* probability for mkobj() */
	schar oc_delay;		/* delay when using such an object */
	uchar oc_weight;
	schar oc_oc1, oc_oc2;
	int oc_oi;
#define	nutrition	oc_oi	/* for foods */
#define	a_ac		oc_oc1	/* for armors */
#define	a_can		oc_oc2	/* for armors */
#define bits		oc_oc1	/* for wands and rings */
				/* wands */
#define		NODIR		1
#define		IMMEDIATE	2
#define		RAY		4
				/* rings */
#define		SPEC		1	/* +n is meaningful */
#define	wldam		oc_oc1	/* for weapons */
#define	wsdam		oc_oc2	/* for weapons */
#define	g_val		oc_oi	/* for gems: value on exit */
};

extern struct objclass objects[];

/* definitions of all object-symbols */

#define	ILLOBJ_SYM	'\\'
#define	AMULET_SYM	'"'
#define	FOOD_SYM	'%'
#define	WEAPON_SYM	')'
#define	TOOL_SYM	'('
#define	BALL_SYM	'0'
#define	CHAIN_SYM	'_'
#define	ROCK_SYM	'`'
#define	ARMOR_SYM	'['
#define	POTION_SYM	'!'
#define	SCROLL_SYM	'?'
#define	WAND_SYM	'/'
#define	RING_SYM	'='
#define	GEM_SYM		'*'
/* Other places with explicit knowledge of object symbols:
 * ....shk.c:	char shtypes[] = "=/)%?![";
 * mklev.c:	"=/)%?![<>"
 * hack.mkobj.c:	char mkobjstr[] = "))[[!!!!????%%%%/=**";
 * hack.apply.c:   otmp = getobj("0#%", "put in");
 * hack.eat.c:     otmp = getobj("%", "eat");
 * hack.invent.c:          if(index("!%?[)=*(0/\"", sym)){
 * hack.invent.c:    || index("%?!*",otmp->olet))){
 */
//E*O*F def.objclass.h//

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

/* objects have letter " % ) ( 0 _ [ ! ? / = * */
#include "def.objclass.h"
#define	NULL	(char *)0

struct objclass objects[] = {

	{ "strange object", NULL, NULL, 1, 0,
		ILLOBJ_SYM, 0, 0, 0, 0, 0, 0 },
	{ "amulet of Yendor", NULL, NULL, 1, 0,
		AMULET_SYM, 100, 0, 2, 0, 0, 0 },

#define	FOOD(name,prob,delay,weight,nutrition)	{ name, NULL, NULL, 1, 1,\
		FOOD_SYM, prob, delay, weight, 0, 0, nutrition }

/* dog eats foods 0-4 but prefers 1 above 0,2,3,4 */
/* food 4 can be read */
/* food 5 improves your vision */
/* food 6 makes you stronger (like Popeye) */
/* foods CORPSE=15 up to CORPSE+52 are cadavers */

	FOOD("food ration", 	50, 5, 4, 800),
	FOOD("tripe ration",	20, 1, 2, 200),
	FOOD("pancake",		3, 1, 1, 200),
	FOOD("dead lizard",	3, 0, 1, 40),
	FOOD("fortune cookie",	7, 0, 1, 40),
	FOOD("carrot",		2, 0, 1, 50),
	FOOD("tin",		7, 0, 1, 0),
	FOOD("orange",		1, 0, 1, 80),
	FOOD("apple",		1, 0, 1, 50),
	FOOD("pear",		1, 0, 1, 50),
	FOOD("melon",		1, 0, 1, 100),
	FOOD("banana",		1, 0, 1, 80),
	FOOD("candy bar",	1, 0, 1, 100),
	FOOD("egg",		1, 0, 1, 80),
	FOOD("clove of garlic",	1, 0, 1, 40),

	FOOD("dead human",	0, 4, 40, 400),
	FOOD("dead giant ant",	0, 1, 3, 30),
	FOOD("dead giant bat",	0, 1, 3, 30),
	FOOD("dead centaur",	0, 5, 50, 500),
	FOOD("dead dragon",	0, 15, 150, 1500),
	FOOD("dead floating eye",	0, 1, 1, 10),
	FOOD("dead freezing sphere",	0, 1, 1, 10),
	FOOD("dead gnome",	0, 1, 10, 100),
	FOOD("dead hobgoblin",	0, 2, 20, 200),
	FOOD("dead stalker",	0, 4, 40, 400),
	FOOD("dead jackal",	0, 1, 10, 100),
	FOOD("dead kobold",	0, 1, 10, 100),
	FOOD("dead leprechaun",	0, 4, 40, 400),
	FOOD("dead mimic",	0, 4, 40, 400),
	FOOD("dead nymph",	0, 4, 40, 400),
	FOOD("dead orc",	0, 2, 20, 200),
	FOOD("dead purple worm",	0, 7, 70, 700),
	FOOD("dead quasit",	0, 2, 20, 200),
	FOOD("dead rust monster",	0, 5, 50, 500),
	FOOD("dead snake",	0, 1, 10, 100),
	FOOD("dead troll",	0, 4, 40, 400),
	FOOD("dead umber hulk",	0, 5, 50, 500),
	FOOD("dead vampire",	0, 4, 40, 400),
	FOOD("dead wraith",	0, 1, 1, 10),
	FOOD("dead xorn",	0, 7, 70, 700),
	FOOD("dead yeti",	0, 7, 70, 700),
	FOOD("dead zombie",	0, 1, 3, 30),
	FOOD("dead acid blob",	0, 1, 3, 30),
	FOOD("dead giant beetle",	0, 1, 1, 10),
	FOOD("dead cockatrice",	0, 1, 3, 30),
	FOOD("dead dog",	0, 2, 20, 200),
	FOOD("dead ettin",	0, 1, 3, 30),
	FOOD("dead fog cloud",	0, 1, 1, 10),
	FOOD("dead gelatinous cube",	0, 1, 10, 100),
	FOOD("dead homunculus",	0, 2, 20, 200),
	FOOD("dead imp",	0, 1, 1, 10),
	FOOD("dead jaguar",	0, 3, 30, 300),
	FOOD("dead killer bee",	0, 1, 1, 10),
	FOOD("dead leocrotta",	0, 5, 50, 500),
	FOOD("dead minotaur",	0, 7, 70, 700),
	FOOD("dead nurse",	0, 4, 40, 400),
	FOOD("dead owlbear",	0, 7, 70, 700),
	FOOD("dead piercer",	0, 2, 20, 200),
	FOOD("dead quivering blob",	0, 1, 10, 100),
	FOOD("dead giant rat",	0, 1, 3, 30),
	FOOD("dead giant scorpion",	0, 1, 10, 100),
	FOOD("dead tengu",	0, 3, 30, 300),
	FOOD("dead unicorn",	0, 3, 30, 300),
	FOOD("dead violet fungi",	0, 1, 10, 100),
	FOOD("dead long worm",	0, 5, 50, 500),
/* %% wt of long worm should be proportional to its length */
	FOOD("dead xan",	0, 3, 30, 300),
	FOOD("dead yellow light",	0, 1, 1, 10),
	FOOD("dead zruty",	0, 6, 60, 600),

/* weapons ... - ROCK come several at a time */
/* weapons ... - (ROCK-1) are shot using idem+(BOW-ARROW) */
/* weapons AXE, SWORD, THSWORD are good for worm-cutting */
/* weapons AXE, DAGGER, CRYSKNIFE are good for tin-opening */
#define WEAPON(name,prob,wt,ldam,sdam)	{ name, NULL, NULL, 1, 0 /*%%*/,\
		WEAPON_SYM, prob, 0, wt, ldam, sdam, 0 }

	WEAPON("arrow",		7, 0, 6, 6),
	WEAPON("sling bullet",	7, 0, 4, 6),
	WEAPON("crossbow bolt",	7, 0, 4, 6),
	WEAPON("dart",		7, 0, 3, 2),
	WEAPON("rock",		6, 1, 3, 3),
	WEAPON("boomerang",	2, 3, 9, 9),
	WEAPON("mace",		9, 3, 6, 7),
	WEAPON("axe",		6, 3, 6, 4),
	WEAPON("flail",		6, 3, 6, 5),
	WEAPON("long sword",	8, 3, 8, 12),
	WEAPON("two handed sword",	6, 4, 10, 6),
	WEAPON("dagger",	6, 3, 4, 3),
	WEAPON("worm tooth",	0, 4, 2, 2),
	WEAPON("crysknife",	0, 3, 12, 12),
	WEAPON("spear",		6, 3, 6, 8),
	WEAPON("bow",		6, 3, 4, 6),
	WEAPON("sling",		5, 3, 6, 6),
	WEAPON("crossbow",	6, 3, 4, 6),

	{ "whistle", "whistle", NULL, 0, 0,
		TOOL_SYM, 90, 0, 2, 0, 0, 0 },
	{ "magic whistle", "whistle", NULL, 0, 0,
		TOOL_SYM, 10, 0, 2, 0, 0, 0 },
	{ "expensive camera", NULL, NULL, 1, 1,
		TOOL_SYM, 0, 0, 3, 0, 0, 0 },
	{ "ice box", "large box", NULL, 0, 0,
		TOOL_SYM, 0, 0, 40, 0, 0, 0 },
	{ "heavy iron ball", NULL, NULL, 1, 0,
		BALL_SYM, 100, 0, 20, 0, 0, 0 },
	{ "iron chain", NULL, NULL, 1, 0,
		CHAIN_SYM, 100, 0, 20, 0, 0, 0 },
	{ "enormous rock", NULL, NULL, 1, 0,
		ROCK_SYM, 100, 0, 200 /* > MAX_CARR_CAP */, 0, 0, 0 },

#define ARMOR(name,prob,delay,ac,can)	{ name, NULL, NULL, 1, 0,\
		ARMOR_SYM, prob, delay, 8, ac, can, 0 }
	ARMOR("helmet",		 3, 1, 9, 0),
	ARMOR("plate mail",		 5, 5, 3, 2),
	ARMOR("splint mail",	 8, 5, 4, 1),
	ARMOR("banded mail",	10, 5, 4, 0),
	ARMOR("chain mail",		10, 5, 5, 1),
	ARMOR("scale mail",		10, 5, 6, 0),
	ARMOR("ring mail",		15, 5, 7, 0),
	/* the armors below do not rust */
	ARMOR("studded leather armor", 13, 3, 7, 1),
	ARMOR("leather armor",	17, 3, 8, 0),
	ARMOR("elven cloak",	 5, 0, 9, 3),
	ARMOR("shield",		 3, 0, 9, 0),
	ARMOR("pair of gloves",	 1, 1, 9, 0),

#define POTION(name,color)	{ name, color, NULL, 0, 1,\
		POTION_SYM, 0, 0, 2, 0, 0, 0 }

	POTION("restore strength",	"orange"),
	POTION("booze",		"bubbly"),
	POTION("invisibility",	"glowing"),
	POTION("fruit juice",	"smoky"),
	POTION("healing",	"pink"),
	POTION("paralysis",	"puce"),
	POTION("monster detection",	"purple"),
	POTION("object detection",	"yellow"),
	POTION("sickness",	"white"),
	POTION("confusion",	"swirly"),
	POTION("gain strength",	"purple-red"),
	POTION("speed",		"ruby"),
	POTION("blindness",	"dark green"),
	POTION("gain level",	"emerald"),
	POTION("extra healing",	"sky blue"),
	POTION("levitation",	"brown"),
	POTION(NULL,	"brilliant blue"),
	POTION(NULL,	"clear"),
	POTION(NULL,	"magenta"),
	POTION(NULL,	"ebony"),

#define SCROLL(name,text,prob) { name, text, NULL, 0, 1,\
		SCROLL_SYM, prob, 0, 3, 0, 0, 0 }
	SCROLL("enchant armor", "ZELGO MER", 6),
	SCROLL("destroy armor", "JUYED AWK YACC", 5),
	SCROLL("confuse monster", "NR 9", 5),
	SCROLL("scare monster", "XIXAXA XOXAXA XUXAXA", 4),
	SCROLL("blank paper", "READ ME", 3),
	SCROLL("remove curse", "PRATYAVAYAH", 6),
	SCROLL("enchant weapon", "DAIYEN FOOELS", 6),
	SCROLL("damage weapon", "HACKEM MUCHE", 5),
	SCROLL("create monster", "LEP GEX VEN ZEA", 5),
	SCROLL("taming", "PRIRUTSENIE", 1),
	SCROLL("genocide", "ELBIB YLOH",2),
	SCROLL("light", "VERR YED HORRE", 10),
	SCROLL("teleportation", "VENZAR BORGAVVE", 5),
	SCROLL("gold detection", "THARR", 4),
	SCROLL("food detection", "YUM YUM", 1),
	SCROLL("identify", "KERNOD WEL", 18),
	SCROLL("magic mapping", "ELAM EBOW", 5),
	SCROLL("amnesia", "DUAM XNAHT", 3),
	SCROLL("fire", "ANDOVA BEGARIN", 5),
	SCROLL("punishment", "VE FORBRYDERNE", 1),
	SCROLL(NULL, "VELOX NEB", 0),
	SCROLL(NULL, "FOOBIE BLETCH", 0),
	SCROLL(NULL, "TEMOV", 0),
	SCROLL(NULL, "GARVEN DEH", 0),

#define	WAND(name,metal,prob,flags)	{ name, metal, NULL, 0, 0,\
		WAND_SYM, prob, 0, 3, flags, 0, 0 }

	WAND("light",	"iridium",		10,	NODIR),
	WAND("secret door detection",	"tin",	5,	NODIR),
	WAND("create monster",	"platinum",	5,	NODIR),
	WAND("wishing",		"glass",	1,	NODIR),
	WAND("striking",	"zinc",		9,	IMMEDIATE),
	WAND("slow monster",	"balsa",	5,	IMMEDIATE),
	WAND("speed monster",	"copper",	5,	IMMEDIATE),
	WAND("undead turning",	"silver",	5,	IMMEDIATE),
	WAND("polymorph",	"brass",	5,	IMMEDIATE),
	WAND("cancellation",	"maple",	5,	IMMEDIATE),
	WAND("teleport monster",	"pine",	5,	IMMEDIATE),
	WAND("make invisible",	"marble",	9,	IMMEDIATE),
	WAND("digging",	"iron",		5,	RAY),
	WAND("magic missile",	"aluminium",	10,	RAY),
	WAND("fire",	"steel",	5,	RAY),
	WAND("sleep",	"curved",	5,	RAY),
	WAND("cold",	"short",	5,	RAY),
	WAND("death",	"long",		1,	RAY),
	WAND(NULL,	"oak",		0,	0),
	WAND(NULL,	"ebony",	0,	0),
	WAND(NULL,	"runed",	0,	0),

#define	RING(name,stone,spec)	{ name, stone, NULL, 0, 0,\
		RING_SYM, 0, 0, 1, spec, 0, 0 }

	RING("adornment",	"engagement",	0),
	RING("teleportation",	"wooden",	0),
	RING("regeneration",	"black onyx",	0),
	RING("searching",	"topaz",	0),
	RING("see invisible",	"pearl",	0),
	RING("stealth",		"sapphire",	0),
	RING("levitation",	"moonstone",	0),
	RING("poison resistance", "agate",	0),
	RING("aggravate monster", "tiger eye",	0),
	RING("hunger",		"shining",	0),
	RING("fire resistance",	"gold",		0),
	RING("cold resistance",	"copper",	0),
	RING("protection from shape changers", "diamond", 0),
	RING("conflict",	"jade",		0),
	RING("gain strength",	"ruby",		SPEC),
	RING("increase damage",	"silver",	SPEC),
	RING("protection",	"granite",	SPEC),
	RING("warning",		"wire",		0),
	RING("teleport control", "iron",	0),
	RING(NULL,		"ivory",	0),
	RING(NULL,		"blackened",	0),

/* gems ************************************************************/
#define	GEM(name,color,prob,gval)	{ name, color, NULL, 0, 1,\
		GEM_SYM, prob, 0, 1, 0, 0, gval }
	GEM("diamond", "blue", 1, 4000),
	GEM("ruby", "red", 1, 3500),
	GEM("sapphire", "blue", 1, 3000),
	GEM("emerald", "green", 1, 2500),
	GEM("turquoise", "green", 1, 2000),
	GEM("aquamarine", "blue", 1, 1500),
	GEM("tourmaline", "green", 1, 1000),
	GEM("topaz", "yellow", 1, 900),
	GEM("opal", "yellow", 1, 800),
	GEM("garnet", "dark", 1, 700),
	GEM("amethyst", "violet", 2, 650),
	GEM("agate", "green", 2, 600),
	GEM("onyx", "white", 2, 550),
	GEM("jasper", "yellowish brown", 2, 500),
	GEM("jade", "green", 2, 450),
	GEM("worthless piece of blue glass", "blue", 20, 0),
	GEM("worthless piece of red glass", "red", 20, 0),
	GEM("worthless piece of yellow glass", "yellow", 20, 0),
	GEM("worthless piece of green glass", "green", 20, 0),
	{ NULL, NULL, NULL, 0, 0, ILLOBJ_SYM, 0, 0, 0, 0, 0, 0 }
};

char obj_symbols[] = {
	ILLOBJ_SYM, AMULET_SYM, FOOD_SYM, WEAPON_SYM, TOOL_SYM,
	BALL_SYM, CHAIN_SYM, ROCK_SYM, ARMOR_SYM, POTION_SYM, SCROLL_SYM,
	WAND_SYM, RING_SYM, GEM_SYM, 0 };
int bases[sizeof(obj_symbols)];
//E*O*F def.objects.h//

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

struct permonst {
	char *mname,mlet;
	schar mlevel,mmove,ac,damn,damd;
	unsigned pxlth;
};
//E*O*F def.permonst.h//

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

/* various kinds of traps */
#define BEAR_TRAP	0
#define	ARROW_TRAP	1
#define	DART_TRAP	2
#define TRAPDOOR	3
#define	TELEP_TRAP	4
#define PIT 5
#define SLP_GAS_TRAP	6
#define	PIERC	7
#define	MIMIC	8	/* used only in mklev.c */
/* before adding more trap types, check mfndpos ! */
/* #define SEEN 32 - trap which has been seen */
//E*O*F def.trap.h//

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

#ifndef NOWORM
/* worm structure */
struct wseg {
	struct wseg *nseg;
	xchar wx,wy;
	unsigned wdispl:1;
};

#define newseg()	(struct wseg *) alloc(sizeof(struct wseg))
#endif NOWORM
//E*O*F def.wseg.h//

echo x - hack.6
cat > "hack.6" << '//E*O*F hack.6//'
.TH HACK 6 "12 December 1984"
.UC 4
.SH NAME
hack \- Exploring The Dungeons of Doom
.SH SYNOPSIS
.B /usr/games/hack
[
.B \-d
.I directory
]
[
.B \-n
]
[
.B \-u
.I playername
]
.br
.B /usr/games/hack
[
.B \-d
.I directory
]
.B \-s
[
.B \-X
]
[
.I playernames
]
.SH DESCRIPTION
.PP
.I Hack
is a display oriented dungeons & dragons - like game.
Both display and command structure resemble rogue.
(For a game with the same structure but entirely different display -
a real cave instead of dull rectangles - try Quest.)
.PP
To get started you really only need to know two commands.  The command
.B ?
will give you a list of the available commands and the command
.B /
will identify the things you see on the screen.
.PP
To win the game (as opposed to merely playing to beat other people high
scores) you must locate the Amulet of Yendor which is somewhere below
the 20th level of the dungeon and get it out.  Nobody has achieved this
yet and if somebody does, he will probably go down in history as a hero
among heros.
.PP
When the game ends, either by your death, when you quit, or if you escape
from the caves,
.I hack
will give you (a fragment of) the list of top scorers.  The scoring
is based on many aspects of your behaviour but a rough estimate is
obtained by taking the amount of gold you've found in the cave plus four
times your (real) experience. Precious stones may be worth a lot of gold
when brought to the exit.
There is a 10% penalty for getting yourself killed.
.PP
The administration of the game is kept in the directory specified with the
.B \-d
option, or, if no such option is given, in the directory specified by
the environment variable HACKDIR, or, if no such variable exists, in
the current directory. This same directory contains several auxiliary
files such as lockfiles and the list of topscorers and a subdirectory
.I save
where games are saved.
.PP
The
.B \-n
option suppresses printing of the news.
.PP
The
.B \-u
.I playername
option supplies the answer to the question "Who are you?".
When
.I playername
has as suffix one of
.B \-T \-S \-K \-F \-C \-W
then this supplies the answer to the question "What kind of character ... ?".
.PP
The
.B \-s
option will print out the list of your scores. It may be followed by arguments
.B \-X
where X is one of the letters C, F, K, S, T, W to print the scores of
Cavemen, Fighters, Knights, Speleologists, Tourists or Wizards.
It may also be followed by one or more player names to print the scores of the
players mentioned.
.SH AUTHORS
Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the
original hack, very much like rogue (but full of bugs).
.br
Andries Brouwer continuously deformed their sources into the current
version - in fact an entirely different game.
.SH FILES
.DT
.ta \w'data, help, rumors\ \ \ 'u
hack, mklev	The hack program and an auxiliary
.br
	program called by hack.
.br
data, help, rumors	Data files used by hack.
.br
record	The list of topscorers.
.br
save	A subdirectory containing the saved games.
.br
bones_dd	Descriptions of the ghost and
.br
	belongings of a deceased adventurer.
.SH BUGS
.PP
Probably infinite.
Mail complaints to mcvax!aeb .
//E*O*F hack.6//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 3 (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.h hack.c help hh

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

#include "mklev.h"
#include "hack.onames.h"

#define ON 1
#define OFF 0

extern struct obj *invent, *uwep, *uarm, *uarm2, *uarmh, *uarms, *uarmg, 
	*uleft, *uright, *fcobj;
extern struct obj *uchain;	/* defined iff PUNISHED */
extern struct obj *uball;	/* defined if PUNISHED */
struct obj *o_at(), *getobj(), *sobj_at();

struct flag {
	unsigned ident;		/* social security number for each monster */
	unsigned topl:2;	/* a top line (message) has been printed */
				/* 0: top line empty; 2: no --More-- reqd. */
	unsigned cbreak:1;	/* in cbreak mode, rogue format */
	unsigned oneline:1;	/* give inventories 1 line at a time */
	unsigned move:1;
	unsigned mv:1;
	unsigned run:3;		/* 0: h (etc), 1: H (etc), 2: fh (etc) */
				/* 3: FH, 4: ff+, 5: ff-, 6: FF+, 7: FF- */
	unsigned nopick:1;	/* do not pickup objects */
	unsigned echo:1;	/* 1 to echo characters */
	unsigned botl:1;	/* partially redo status line */
	unsigned botlx:1;	/* print an entirely new bottom line */
	unsigned nscrinh:1;	/* inhibit nscr() in pline(); */
};
extern struct flag flags;

struct prop {
#define	TIMEOUT		007777	/* mask */
#define	LEFT_RING	W_RINGL	/* 010000L */
#define	RIGHT_RING	W_RINGR	/* 020000L */
#define	INTRINSIC	040000L
#define	LEFT_SIDE	LEFT_RING
#define	RIGHT_SIDE	RIGHT_RING
#define	BOTH_SIDES	(LEFT_SIDE | RIGHT_SIDE)
	long p_flgs;
	int (*p_tofn)();	/* called after timeout */
};

struct you {
	xchar ux, uy;
	schar dx, dy;		/* direction of fast move */
#ifdef QUEST
	schar di;		/* direction of FF */
	xchar ux0, uy0;		/* initial position FF */
#endif QUEST
	xchar udisx, udisy;	/* last display pos */
	char usym;		/* usually '@' */
	schar uluck;
	int last_str_turn:3;	/* 0: none, 1: half turn, 2: full turn */
				/* +: turn right, -: turn left */
	unsigned udispl:1;	/* @ on display */
	unsigned ulevel:5;
#ifdef QUEST
	unsigned uhorizon:7;
#endif QUEST
	unsigned utrap:3;	/* trap timeout */
	unsigned utraptype:1;	/* defined if utrap nonzero */
#define	TT_BEARTRAP	0
#define	TT_PIT		1
	unsigned uinshop:1;


/* perhaps these #define's should also be generated by makedefs */
#define	TELEPAT		LAST_RING		/* not a ring */
#define	Telepat		u.uprops[TELEPAT].p_flgs
#define	FAST		(LAST_RING+1)		/* not a ring */
#define	Fast		u.uprops[FAST].p_flgs
#define	CONFUSION	(LAST_RING+2)		/* not a ring */
#define	Confusion	u.uprops[CONFUSION].p_flgs
#define	INVIS		(LAST_RING+3)		/* not a ring */
#define	Invis		u.uprops[INVIS].p_flgs
#define	GLIB		(LAST_RING+4)		/* not a ring */
#define	Glib		u.uprops[GLIB].p_flgs
#define	PUNISHED	(LAST_RING+5)		/* not a ring */
#define	Punished	u.uprops[PUNISHED].p_flgs
#define	SICK		(LAST_RING+6)		/* not a ring */
#define	Sick		u.uprops[SICK].p_flgs
#define	BLIND		(LAST_RING+7)		/* not a ring */
#define	Blind		u.uprops[BLIND].p_flgs
#define	WOUNDED_LEGS	(LAST_RING+8)		/* not a ring */
#define Wounded_legs	u.uprops[WOUNDED_LEGS].p_flgs
#define PROP(x) (x-RIN_ADORNMENT)       /* convert ring to index in uprops */
	unsigned umconf:1;
	char *usick_cause;
	struct prop uprops[LAST_RING+9];

	unsigned uswallow:1;		/* set if swallowed by a monster */
	unsigned uswldtim:4;		/* time you have been swallowed */
	unsigned uhs:3;			/* hunger state - see hack.eat.c */
	schar ustr,ustrmax;
	schar udaminc;
	schar uac;
	int uhp,uhpmax;
	long int ugold,ugold0,uexp,urexp;
	int uhunger;			/* refd only in eat.c and shk.c */
	int uinvault;
	struct monst *ustuck;
	int nr_killed[CMNUM+2];		/* used for experience bookkeeping */
};

extern struct you u;

extern char *traps[];
extern char *plur(), *monnam(), *Monnam(), *amonnam(), *Amonnam(),
	*doname(), *aobjnam();
extern char readchar();
extern char vowels[];

extern xchar curx,cury;	/* cursor location on screen */

extern coord bhitpos;	/* place where thrown weapon falls to the ground */

extern xchar seehx,seelx,seehy,seely; /* where to see*/
extern char *save_cm,*killer;

extern xchar dlevel, maxdlevel; /* dungeon level */

extern long moves;

extern int multi;


extern char lock[];


#define DIST(x1,y1,x2,y2)       (((x1)-(x2))*((x1)-(x2)) + ((y1)-(y2))*((y1)-(y2)))

#define	PL_CSIZ		20	/* sizeof pl_character */
#define	MAX_CARR_CAP	120	/* so that boulders can be heavier */
#define	FAR	(COLNO+2)	/* position outside screen */
//E*O*F hack.h//

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

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


extern char news0();
extern char *nomovemsg;
extern char *exclam();
extern struct obj *addinv();
extern boolean hmon();



/* called on movement:
	1. when throwing ball+chain far away
	2. when teleporting
	3. when walking out of a lit room
 */
unsee() {
	register x,y;
	register struct rm *lev;

/*
	if(u.udispl){
		u.udispl = 0;
		newsym(u.udisx, u.udisy);
	}
*/
#ifndef QUEST
	if(seehx){
		seehx = 0;
	} else
#endif QUEST
	for(x = u.ux-1; x < u.ux+2; x++)
	  for(y = u.uy-1; y < u.uy+2; y++) {
		lev = &levl[x][y];
		if(!lev->lit && lev->scrsym == '.') {
			lev->scrsym =' ';
			lev->new = 1;
			on_scr(x,y);
		}
	}
}

/* called:
	in hack.eat.c: seeoff(0) - blind after eating rotten food
	in hack.mon.c: seeoff(0) - blinded by a yellow light
	in hack.mon.c: seeoff(1) - swallowed
	in hack.do.c:  seeoff(0) - blind after drinking potion
	in hack.do.c:  seeoff(1) - go up or down the stairs
	in hack.trap.c:seeoff(1) - fall through trapdoor
 */
seeoff(mode)	/* 1 to redo @, 0 to leave them */
{	/* 1 means misc movement, 0 means blindness */
	register x,y;
	register struct rm *lev;

	if(u.udispl && mode){
		u.udispl = 0;
		levl[u.udisx][u.udisy].scrsym = news0(u.udisx,u.udisy);
	}
#ifndef QUEST
	if(seehx) {
		seehx = 0;
	} else
#endif QUEST
	if(!mode) {
		for(x = u.ux-1; x < u.ux+2; x++)
			for(y = u.uy-1; y < u.uy+2; y++) {
				lev = &levl[x][y];
				if(!lev->lit && lev->scrsym == '.')
					lev->seen = 0;
			}
	}
}

/* 'rogue'-like direction commands */
char sdir[] = "hykulnjb";
schar xdir[8] = { -1,-1,0,1,1,1,0,-1 };
schar ydir[8] = { 0,-1,-1,-1,0,1,1,1 };

movecm(cmd)
register char *cmd;
{
register char *dp;
		if(!(dp = index(sdir, *cmd))) return(0);
		u.dx = xdir[dp-sdir];
		u.dy = ydir[dp-sdir];
		return(1);
}

#ifdef QUEST
finddir(){
register int i, ui = u.di;
	for(i = 0; i <= 8; i++){
		if(flags.run & 1) ui++; else ui += 7;
		ui %= 8;
		if(i == 8){
			pline("Not near a wall.");
			flags.move = multi = 0;
			return(0);
		}
		if(!isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
			break;
	}
	for(i = 0; i <= 8; i++){
		if(flags.run & 1) ui += 7; else ui++;
		ui %= 8;
		if(i == 8){
			pline("Not near a room.");
			flags.move = multi = 0;
			return(0);
		}
		if(isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
			break;
	}
	u.di = ui;
	u.dx = xdir[ui];
	u.dy = ydir[ui];
}

isroom(x,y)  register x,y; {
	return(isok(x,y) && (levl[x][y].typ == ROOM ||
				(levl[x][y].typ >= LDOOR && flags.run >= 6)));
}
#endif QUEST

isok(x,y) register x,y; {
	return(x >= 0 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1);
}

domove()
{
	xchar oldx,oldy;
	register struct monst *mtmp;
	register struct rm *tmpr,*ust;
	struct gen *trap;
	register struct obj *otmp;

	wipe_engr_at(u.ux, u.uy, rnd(5));
	if(inv_weight() > 0){
		pline("You collapse under your load.");
		nomul(0);
		return;
	}
	if(Confusion) {
		do {
			u.dx = rn1(3,-1);
			u.dy = rn1(3,-1);
			tmpr = &levl[u.ux+u.dx][u.uy+u.dy];
		} while((!u.dx && !u.dy) ||
			!isok(u.ux+u.dx, u.uy+u.dy) || tmpr->typ < DOOR);
	} else tmpr = &levl[u.ux+u.dx][u.uy+u.dy];
	if(!isok(u.ux+u.dx, u.uy+u.dy)){
		nomul(0);
		return;
	}

	ust = &levl[u.ux][u.uy];
	oldx = u.ux;
	oldy = u.uy;
	if(!u.uswallow)
	    if(trap = g_at(u.ux+u.dx,u.uy+u.dy,ftrap)) {
		if(trap->gflag & SEEN) nomul(0);
	}
	if(u.ustuck && !u.uswallow && (u.ux+u.dx != u.ustuck->mx ||
		u.uy+u.dy != u.ustuck->my)) {
		if(dist(u.ustuck->mx, u.ustuck->my) > 2){
			/* perhaps it fled (or was teleported or ... ) */
			u.ustuck = 0;
		} else {
			if(Blind) pline("You cannot escape from it!");
			else pline("You cannot escape from %s!.",
				monnam(u.ustuck));
			nomul(0);
			return;
		}
	}
	if((mtmp = m_at(u.ux+u.dx,u.uy+u.dy)) || u.uswallow) {
	/* attack monster */
		schar tmp;
		boolean malive = TRUE;
		register struct permonst *mdat;

		nomul(0);
		gethungry();
		if(multi < 0) return;	/* we just fainted */
		if(u.uswallow) mtmp = u.ustuck;
		mdat = mtmp->data;
		if(mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep &&
		   !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
		   (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */
			mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy))
			goto nomon;
		if(mtmp->mimic){
			if(!u.ustuck && !mtmp->mflee) u.ustuck = mtmp;
			switch(levl[u.ux+u.dx][u.uy+u.dy].scrsym){
			case '+':
				pline("The door actually was a Mimic.");
				break;
			case '$':
				pline("The chest was a Mimic!");
				break;
			default:
				pline("Wait! That's a Mimic!");
			}
			wakeup(mtmp);	/* clears mtmp->mimic */
			return;
		}
		wakeup(mtmp);	/* clears mtmp->mimic */
		if(mtmp->mhide && mtmp->mundetected){
			register struct obj *obj;
			mtmp->mundetected = 0;
			if((obj = o_at(mtmp->mx,mtmp->my)) && !Blind)
				pline("Wait! There's a %s hiding under %s!",
					mdat->mname, doname(obj));
			return;
		}
		tmp = u.uluck + u.ulevel + mdat->ac + abon();
		if(uwep) {
			if(uwep->olet == WEAPON_SYM)
				tmp += uwep->spe;
			if(uwep->otyp == TWO_HANDED_SWORD) tmp -= 1;
			else if(uwep->otyp == DAGGER) tmp += 2;
			else if(uwep->otyp == CRYSKNIFE) tmp += 3;
			else if(uwep->otyp == SPEAR &&
				index("XDne", mdat->mlet)) tmp += 2;
		}
		if(mtmp->msleep) {
			mtmp->msleep = 0;
			tmp += 2;
		}
		if(mtmp->mfroz) {
			tmp += 4;
			if(!rn2(10)) mtmp->mfroz = 0;
		}
		if(mtmp->mflee) tmp += 2;
		if(u.utrap) tmp -= 3;
		if(tmp <= rnd(20) && !u.uswallow){
			if(Blind) pline("You miss it.");
			else pline("You miss %s.",monnam(mtmp));
		} else {
			/* we hit the monster; be careful: it might die! */

			if((malive = hmon(mtmp,uwep,0)) == TRUE) {
				/* monster still alive */
				if(!rn2(25) && mtmp->mhp < mtmp->orig_hp/2) {
					mtmp->mflee = 1;
					if(u.ustuck == mtmp && !u.uswallow)
						u.ustuck = 0;
				}
#ifndef NOWORM
				if(mtmp->wormno)
					cutworm(mtmp, u.ux+u.dx, u.uy+u.dy,
						uwep ? uwep->otyp : 0);
#endif NOWORM
			}
			if(mdat->mlet == 'a') {
				if(rn2(2)) {
				pline("You are splashed by the blob's acid!");
					losehp_m(rnd(6), mtmp);
				}
				if(!rn2(6)) corrode_weapon();
				else if(!rn2(60)) corrode_armor();
			}
		}
		if(malive && !Blind && mdat->mlet == 'E' && rn2(3)) {
		    if(mtmp->mcansee) {
		      pline("You are frozen by the floating eye's gaze!");
		      nomul((u.ulevel > 6 || rn2(4)) ? rn1(20,-21) : -200);
		    } else {
		      pline("The blinded floating eye cannot defend itself.");
		      if(!rn2(500)) u.uluck--;
		    }
		}
		return;
	}
nomon:
	/* not attacking an animal, so we try to move */
	if(u.utrap) {
		if(u.utraptype == TT_PIT) {
			pline("You are still in a pit.");
			u.utrap--;
		} else {
			pline("You are caught in a beartrap.");
			if((u.dx && u.dy) || !rn2(5)) u.utrap--;
		}
		return;
	}
	if((tmpr->typ < DOOR) ||
	   (u.dx && u.dy && (tmpr->typ == DOOR || ust->typ == DOOR))){
		flags.move = 0;
		nomul(0);
		return;
	}
	while(otmp = sobj_at(ENORMOUS_ROCK, u.ux+u.dx, u.uy+u.dy)) {
		register xchar rx = u.ux+2*u.dx, ry = u.uy+2*u.dy;
		register struct gen *gtmp;
		nomul(0);
		if(isok(rx,ry) && (levl[rx][ry].typ > DOOR ||
		    (levl[rx][ry].typ == DOOR && (!u.dx || !u.dy)))) {
			if(m_at(rx,ry)) {
			    pline("You hear a monster behind the rock.");
			    pline("Perhaps that's why you cannot move it.");
			    return;
			}
			if(gtmp = g_at(rx,ry,ftrap))
#include	"def.trap.h"
			    switch(gtmp->gflag & ~SEEN) {
			    case PIT:
				pline("You push the rock into a pit!");
				deltrap(gtmp);
				delobj(otmp);
				pline("It completely fills the pit!");
				continue;
			    case TELEP_TRAP:
				pline("You push the rock and suddenly it disappears!");
				delobj(otmp);
				continue;
			    }
			otmp->ox = rx;
			otmp->oy = ry;
			/* pobj(otmp); */
			if(cansee(rx,ry)) atl(rx,ry,otmp->olet);
			if(Invis) newsym(u.ux+u.dx, u.uy+u.dy);

			{ static int lastmovetime;
			/* note: this var contains garbage initially and
			   after a restore */
			if(moves > lastmovetime+2 || moves < lastmovetime)
			pline("With great effort you move the enormous rock.");
			lastmovetime = moves;
			}
		} else {
		    pline("You try to move the enormous rock, but in vain.");
		    return;
		}
	    }
	if(u.dx && u.dy && levl[u.ux][u.uy+u.dy].typ < DOOR &&
		levl[u.ux+u.dx][u.uy].typ < DOOR &&
		invent && inv_weight()+40 > 0) {
		pline("You are carrying too much to get through.");
		nomul(0);
		return;
	}
	if(Punished &&
	   DIST(u.ux+u.dx, u.uy+u.dy, uchain->ox, uchain->oy) > 2){
		if(carried(uball)) {
			movobj(uchain, u.ux, u.uy);
			goto nodrag;
		}

		if(DIST(u.ux+u.dx, u.uy+u.dy, uball->ox, uball->oy) < 3){
			/* leave ball, move chain under/over ball */
			movobj(uchain, uball->ox, uball->oy);
			goto nodrag;
		}

		if(inv_weight() + (int) uball->owt/2 > 0) {
			pline("You cannot %sdrag the heavy iron ball.",
			invent ? "carry all that and also " : "");
			nomul(0);
			return;
		}

		movobj(uball, uchain->ox, uchain->oy);
		unpobj(uball);		/* BAH %% */
		uchain->ox = u.ux;
		uchain->oy = u.uy;
		nomul(-2);
		nomovemsg = "";
	nodrag:	;
	}
	u.ux += u.dx;
	u.uy += u.dy;
	if(flags.run) {
		if(tmpr->typ == DOOR ||
		(xupstair == u.ux && yupstair == u.uy) ||
		(xdnstair == u.ux && ydnstair == u.uy))
			nomul(0);
	}
/*
	if(u.udispl) {
		u.udispl = 0;
		newsym(oldx,oldy);
	}
*/
	if(!Blind) {
#ifdef QUEST
		setsee();
#else
		if(ust->lit) {
			if(tmpr->lit) {
				if(tmpr->typ == DOOR) prl1(u.ux+u.dx,u.uy+u.dy);
				else if(ust->typ == DOOR) nose1(oldx-u.dx,oldy-u.dy);
			} else {
				unsee();
				prl1(u.ux+u.dx,u.uy+u.dy);
			}
		} else {
			if(tmpr->lit) setsee();
			else {
				prl1(u.ux+u.dx,u.uy+u.dy);
				if(tmpr->typ == DOOR) {
					if(u.dy) {
						prl(u.ux-1,u.uy);
						prl(u.ux+1,u.uy);
					} else {
						prl(u.ux,u.uy-1);
						prl(u.ux,u.uy+1);
					}
				}
			}
			nose1(oldx-u.dx,oldy-u.dy);
		}
#endif QUEST
	} else {
		pru();
	}
	if(!flags.nopick) pickup();
	if(trap) dotrap(trap);		/* fall into pit, arrow trap, etc. */
	(void) inshop();
	if(!Blind) read_engr_at(u.ux,u.uy);
}

movobj(obj, ox, oy)
register struct obj *obj;
register int ox, oy;
{
	/* Some dirty programming to get display right */
	freeobj(obj);
	unpobj(obj);
	obj->nobj = fobj;
	fobj = obj;
	obj->ox = ox;
	obj->oy = oy;
}

pickup(){
register struct gen *gold;
register struct obj *obj, *obj2;
register int wt;
	if(Levitation) return;
	while(gold = g_at(u.ux,u.uy,fgold)) {
		pline("%u gold piece%s.", gold->gflag, plur(gold->gflag));
		u.ugold += gold->gflag;
		flags.botl = 1;
		freegold(gold);
		if(flags.run) nomul(0);
		if(Invis) newsym(u.ux,u.uy);
	}
	for(obj = fobj; obj; obj = obj2) {
	    obj2 = obj->nobj;	/* perhaps obj will be picked up */
	    if(obj->ox == u.ux && obj->oy == u.uy) {
		if(flags.run) nomul(0);

#define	DEAD_c	CORPSE+('c'-'a'+'Z'-'@'+1)
		if(obj->otyp == DEAD_COCKATRICE && !uarmg){
		    pline("Touching the dead cockatrice is a fatal mistake.");
		    pline("You turn to stone.");
		    killer = "cockatrice cadaver";
		    done("died");
		}

		if(obj->otyp == SCR_SCARE_MONSTER){
		  if(!obj->spe) obj->spe = 1;
		  else {
		    /* Note: perhaps the 1st pickup failed: you cannot
			carry anymore, and so we never dropped it -
			let's assume that treading on it twice also
			destroys the scroll */
		    pline("The scroll turns to dust as you pick it up.");
		    delobj(obj);
		    continue;
		  }
		}

		/* do not pick up uchain */
		if(Punished && obj == uchain)
			continue;

		wt = inv_weight() + obj->owt;
		if(wt > 0) {
			if(obj->quan > 1) {
				/* see how many we can lift */
				extern struct obj *splitobj();
				int savequan = obj->quan;
				int iw = inv_weight();
				int qq;
				for(qq = 1; qq < savequan; qq++){
					obj->quan = qq;
					if(iw + weight(obj) > 0)
						break;
				}
				obj->quan = savequan;
				qq--;
				/* we can carry qq of them */
				if(!qq) goto too_heavy;
			pline("You can only carry %s of the %s lying here.",
					(qq == 1) ? "one" : "some",
					doname(obj));
				(void) splitobj(obj, qq);
				/* note: obj2 is set already, so we'll never
				 * encounter the other half; if it should be
				 * otherwise then write
				 *	obj2 = splitobj(obj,qq);
				 */
				goto lift_some;
			}
		too_heavy:
			pline("There %s %s here, but %s.",
				(obj->quan == 1) ? "is" : "are",
				doname(obj),
				!invent ? "it is too heavy for you to lift"
					: "you cannot carry anymore");
			break;
		}
	lift_some:
		if(inv_cnt() >= 52) {
		    pline("Your knapsack cannot accomodate anymore items.");
		    break;
		}
		if(wt > -5) pline("You have a little trouble lifting");
		freeobj(obj);
		if(Invis) newsym(u.ux,u.uy);
		addtobill(obj);       /* sets obj->unpaid if necessary */
		{ int pickquan = obj->quan;
		  int mergquan;
		if(!Blind) obj->dknown = 1;	/* this is done by prinv(),
				 but addinv() needs it already for merging */
		obj = addinv(obj);    /* might merge it with other objects */
		  mergquan = obj->quan;
		  obj->quan = pickquan;	/* to fool prinv() */
		prinv(obj);
		  obj->quan = mergquan;
		}
	    }
	}
}

/* stop running if we see something interesting */
/* turn around a corner if that is the only way we can proceed */
/* do not turn left or right twice */
lookaround(){
register x,y,i,x0,y0,m0,i0 = 9;
register int corrct = 0, noturn = 0;
register struct monst *mtmp;
#ifdef lint
	/* suppress "used before set" message */
	x0 = y0 = 0;
#endif lint
	if(Blind || flags.run == 0) return;
	if(flags.run == 1 && levl[u.ux][u.uy].typ >= ROOM) return;
#ifdef QUEST
	if(u.ux0 == u.ux+u.dx && u.uy0 == u.uy+u.dy) goto stop;
#endif QUEST
	for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){
		if(x == u.ux && y == u.uy) continue;
		if(!levl[x][y].typ) continue;
		if((mtmp = m_at(x,y)) && !mtmp->mimic &&
		    (!mtmp->minvis || See_invisible)){
			if(!mtmp->mtame || (x == u.ux+u.dx && y == u.uy+u.dy))
				goto stop;
		} else mtmp = 0; /* invisible M cannot influence us */
		if(x == u.ux-u.dx && y == u.uy-u.dy) continue;
		switch(levl[x][y].scrsym){
		case '|':
		case '-':
		case '.':
		case ' ':
			break;
		case '+':
			if(x != u.ux && y != u.uy) break;
			if(flags.run != 1) goto stop;
			/* fall into next case */
		case CORR_SYM:
		corr:
			if(flags.run == 1 || flags.run == 3) {
				i = DIST(x,y,u.ux+u.dx,u.uy+u.dy);
				if(i > 2) break;
				if(corrct == 1 && DIST(x,y,x0,y0) != 1)
					noturn = 1;
				if(i < i0) {
					i0 = i;
					x0 = x;
					y0 = y;
					m0 = mtmp ? 1 : 0;
				}
			}
			corrct++;
			break;
		case '^':
			if(flags.run == 1) goto corr;	/* if you must */
			if(x == u.ux+u.dx && y == u.uy+u.dx) goto stop;
			break;
		default:	/* e.g. objects or trap or stairs */
			if(flags.run == 1) goto corr;
			if(mtmp) break;		/* d */
		stop:
			nomul(0);
			return;
		}
	}
#ifdef QUEST
	if(corrct > 0 && (flags.run == 4 || flags.run == 5)) goto stop;
#endif QUEST
	if(corrct > 1 && flags.run == 2) goto stop;
	if((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 &&
		(corrct == 1 || (corrct == 2 && i0 == 1))) {
		/* make sure that we do not turn too far */
		if(i0 == 2) {
		    if(u.dx == y0-u.uy && u.dy == u.ux-x0)
			i = 2;		/* straight turn right */
		    else
			i = -2;		/* straight turn left */
		} else if(u.dx && u.dy) {
		    if((u.dx == u.dy && y0 == u.uy) ||
			(u.dx != u.dy && y0 != u.uy))
			i = -1;		/* half turn left */
		    else
			i = 1;		/* half turn right */
		} else {
		    if((x0-u.ux == y0-u.uy && !u.dy) ||
			(x0-u.ux != y0-u.uy && u.dy))
			i = 1;		/* half turn right */
		    else
			i = -1;		/* half turn left */
		}
		i += u.last_str_turn;
		if(i <= 2 && i >= -2) {
			u.last_str_turn = i;
			u.dx = x0-u.ux, u.dy = y0-u.uy;
		}
	}
}

#ifdef QUEST
cansee(x,y) xchar x,y; {
register int dx,dy,adx,ady,sdx,sdy,dmax,d;
	if(Blind) return(0);
	if(!isok(x,y)) return(0);
	d = dist(x,y);
	if(d < 3) return(1);
	if(d > u.uhorizon*u.uhorizon) return(0);
	if(!levl[x][y].lit)
		return(0);
	dx = x - u.ux;	adx = abs(dx);	sdx = sgn(dx);
	dy = y - u.uy;  ady = abs(dy);	sdy = sgn(dy);
	if(dx == 0 || dy == 0 || adx == ady){
		dmax = (dx == 0) ? ady : adx;
		for(d = 1; d <= dmax; d++)
			if(!rroom(sdx*d,sdy*d))
				return(0);
		return(1);
	} else if(ady > adx){
		for(d = 1; d <= ady; d++){
			if(!rroom(sdx*( (d*adx)/ady ), sdy*d) ||
			   !rroom(sdx*( (d*adx-1)/ady+1 ), sdy*d))
				return(0);
		}
		return(1);
	} else {
		for(d = 1; d <= adx; d++){
			if(!rroom(sdx*d, sdy*( (d*ady)/adx )) ||
			   !rroom(sdx*d, sdy*( (d*ady-1)/adx+1 )))
				return(0);
		}
		return(1);
	}
}

rroom(x,y) register int x,y; {
	return(levl[u.ux+x][u.uy+y].typ >= ROOM);
}

#else

cansee(x,y) xchar x,y; {
	if(Blind || u.uswallow) return(0);
	if(dist(x,y) < 3) return(1);
	if(levl[x][y].lit && seelx <= x && x <= seehx && seely <= y &&
		y <= seehy) return(1);
	return(0);
}
#endif QUEST

sgn(a) register int a; {
	return((a> 0) ? 1 : (a == 0) ? 0 : -1);
}

pow(num) /* returns 2 to the num */
register unsigned num;
{
	return(1 << num);
}

#ifdef QUEST
setsee()
{
	register x,y;

	if(Blind) {
		pru();
		return;
	}
	for(y = u.uy-u.uhorizon; y <= u.uy+u.uhorizon; y++)
		for(x = u.ux-u.uhorizon; x <= u.ux+u.uhorizon; x++) {
			if(cansee(x,y))
				prl(x,y);
	}
}

#else

setsee()
{
	register x,y;

	if(Blind) {
		pru();
		return;
	}
	if(!levl[u.ux][u.uy].lit) {
		seelx = u.ux-1;
		seehx = u.ux+1;
		seely = u.uy-1;
		seehy = u.uy+1;
	} else {
		for(seelx = u.ux; levl[seelx-1][u.uy].lit; seelx--);
		for(seehx = u.ux; levl[seehx+1][u.uy].lit; seehx++);
		for(seely = u.uy; levl[u.ux][seely-1].lit; seely--);
		for(seehy = u.uy; levl[u.ux][seehy+1].lit; seehy++);
	}
	for(y = seely; y <= seehy; y++)
		for(x = seelx; x <= seehx; x++) {
			prl(x,y);
	}
	if(!levl[u.ux][u.uy].lit) seehx = 0; /* seems necessary elsewhere */
	else {
	    if(seely == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seely-1);
	    if(seehy == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seehy+1);
	    if(seelx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seelx-1,y);
	    if(seehx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seehx+1,y);
	}
}
#endif QUEST

nomul(nval)
register nval;
{
	if(multi < 0) return;
	multi = nval;
	flags.mv = flags.run = 0;
}

abon()
{
	if(u.ustr == 3) return(-3);
	else if(u.ustr < 6) return(-2);
	else if(u.ustr < 8) return(-1);
	else if(u.ustr < 17) return(0);
	else if(u.ustr < 69) return(1);	/* up to 18/50 */
	else if(u.ustr < 118) return(2);
	else return(3);
}

dbon()
{
	if(u.ustr < 6) return(-1);
	else if(u.ustr < 16) return(0);
	else if(u.ustr < 18) return(1);
	else if(u.ustr == 18) return(2);	/* up to 18 */
	else if(u.ustr < 94) return(3);	/* up to 18/75 */
	else if(u.ustr < 109) return(4);	/* up to 18/90 */
	else if(u.ustr < 118) return(5);	/* up to 18/99 */
	else return(6);
}

losestr(num)
register num;
{
	u.ustr -= num;
	while(u.ustr < 3) {
		u.ustr++;
		u.uhp -= 6;
		u.uhpmax -= 6;
	}
	flags.botl = 1;
}

losehp(n,knam)
register n;
register char *knam;
{
	u.uhp -= n;
	if(u.uhp > u.uhpmax)
		u.uhpmax = u.uhp;	/* perhaps n was negative */
	flags.botl = 1;
	if(u.uhp < 1)
		killer = knam;	/* the thing that killed you */
}

losehp_m(n,mtmp)
register n;
register struct monst *mtmp;
{
	u.uhp -= n;
	flags.botl = 1;
	if(u.uhp < 1) done_in_by(mtmp);
}

losexp()	/* hit by V or W */
{
	register num;

	if(u.ulevel > 1) pline("Goodbye level %d.",u.ulevel--);
	else u.uhp = -1;
	num = rnd(10);
	u.uhp -= num;
	u.uhpmax -= num;
	u.uexp = 10*pow(u.ulevel-1);
	flags.botl = 1;
}

inv_weight(){
register struct obj *otmp = invent;
register int wt = 0;
register int carrcap = 5*(((u.ustr > 18) ? 20 : u.ustr) + u.ulevel);
	if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
	if(Wounded_legs & LEFT_SIDE) carrcap -= 10;
	if(Wounded_legs & RIGHT_SIDE) carrcap -= 10;
	while(otmp){
		wt += otmp->owt;
		otmp = otmp->nobj;
	}
	return(wt - carrcap);
}

inv_cnt(){
register struct obj *otmp = invent;
register int ct = 0;
	while(otmp){
		ct++;
		otmp = otmp->nobj;
	}
	return(ct);
}
//E*O*F hack.c//

echo x - help
cat > "help" << '//E*O*F help//'
	Welcome to HACK!

	Hack is a Dungeons and Dragons like game where you (the adventurer)
descend into the depths of the dungeon in search of the Amulet of Yendor
(reputed to be hidden on the twentieth level).  You are accompanied by a
little dog that can help you in many ways and can be trained to do all
sorts of things. On the way you will find useful (or useless) items, (quite
possibly with magic properties) and assorted monsters.  You attack a monster
by trying to move into the space a monster is in (but often it is much
wiser to leave it alone).

	Unlike most adventure games, which give you a verbal description of
your location, hack gives you a visual image of the dungeon level you are on.

	Hack uses the following symbols:
		A to Z and a to z:  monsters.  You can find out what a letter
represents by saying "/ (letter)", as in "/A", which will tell you that 'A'
is a giant ant.
		- and |  These form the walls of a room (or maze).
		.  this is the floor of a room.
		#  this is a corridor.
		>  this is the staircase to the next level.
		<  the staircase to the previous level.
		`  A large boulder.
		@  You (usually).
		^  A trap.
		)  A weapon of some sort.
		(  Some other useful object (key, rope, dynamite, camera, ...)
		[  A suit of armor.
		%  A piece of food (not necessarily healthy ...).
		/  A wand.
		=  A ring.
		?  A scroll.
		!  A magic potion.
		$  A pile or pot of gold.

Commands:
	Hack knows the following commands:
	?	help: print this list.
	Q	Quit the game.
	<	up: go up the staircase (if you are standing on it).
	>	down: go down (just like up).
	kjhlyubn - go one step in the direction indicated.
		k: north (i.e., to the top of the screen),
		j: south, h: west, l: east, y: ne, u: nw, b: se, n: sw.
	KJHLYUBN - Go in that direction until you hit a wall or run
		into something.
	m	(followed by one of kjhlyubn): move without picking up
		any objects.
	M	(followed by one of KJHLYUBN): Move far, no pickup.
	f	(followed by one of kjhlyubn): move until something
		interesting is found.
	F	(followed by one of KJHLYUBN): as previous, but forking
		of corridors is not considered interesting.
	i	print your inventory.
	s	search for secret doors and traps around you.
	^	ask for the type of a trap you found earlier.
	)	ask for current wielded weapon.
	[	ask for current armor.
	=	ask for current rings.
	.	rest, do nothing.
	^R	redraw the screen.
	^P	repeat last message
		(subsequent ^P's repeat earlier messages).
	/	(followed by any symbol): tell what this symbol represents.
	e	eat food.
	w	wield weapon. w- means: wield nothing, use bare hands.
	q	drink (quaff) a potion.
	r	read a scroll.
	T	Takeoff armor.
	R	Remove Ring.
	W	Wear armor.
	P	Put on a ring.
	t	throw or shoot a weapon.
	p	pay your shopping bill.
	d	drop something. d7a: drop seven items of object a.
	D	Drop several things.
		In answer to the question "What kinds of things do you
		want to drop? [!%= au]" you should give zero or more
		object symbols possibly followed by 'a' and/or 'u'.
		'a' means: drop all such objects, without asking for
			confirmation.
		'u' means: drop only unpaid objects (when in a shop).
	a	use, apply - Generic command for using a key to lock
		or unlock a door, using a camera, using a rope, etc.
	c	call: name a certain object or class of objects.
	C	Call: Name an individual monster.
	E	Engrave: Write a message in the dust on the floor.
		E- means: use fingers for writing.
	o	set options. (see below)
	v	print version number.

	You can put a number before a command to repeat it that many times,
	as in "20s" or "40.".

	Options:
		To turn an option on, say 'ox', where x is the optionletter.
	To turn it off, say 'o!x'.  The following options currently exist.

	e	echo		Echo typed characters.
	o	oneline		Give inventories one line at a time
				(at the top of your screen).


	Have Fun, and Good Hacking!



//E*O*F help//

echo x - hh
cat > "hh" << '//E*O*F hh//'
y k u	Move commands:
 \|/		hykulnjb: single move in specified direction
h-.-l		HYKULNJB: repeated move in specified direction
 /|\			(until stopped by e.g. a wall)
b j n		f<dir>: fast movement in direction <dir>
			(until something interesting is seen)
		m<dir>: move without picking up objects
Meta commands:
Q	quit	leave the game
S	save	save the game (to be continued later)
o	set	set options
?	help	print information
/	whatis	give name (and sometimes more info) of specified monster
!	sh	escape to some SHELL
v	version	print version number
^R	redraw	redraw the screen (^R denotes the symbol CTRL/R)
^P	print	repeat last message  (subsequent ^P's repeat earlier messages)

Game commands:
a	apply, use  use something (a key, camera, etc.)
c	call	give a name to a class of objects
d	drop	drop an object. d7a: drop seven items of object a.
e	eat	eat something
i	invent	list the inventory (and shopping bill)
p	pay	pay your bill
q	drink	quaff a potion
r	read	read a scroll
s	search	search for secret doors, hidden traps and monsters
t	throw	throw or shoot a weapon
w	wield	wield a weapon	(w-  wield nothing)
z	zap	zap a wand
C	name	name an individual monster (e.g., baptize your dog)
D	Drop	drop several things
E	Engrave write a message in the dust on the floor  (E-  use fingers)
P	wear	put on a ring
R	remove	remove a ring
T	remove	take off some armor
W	wear	put on some armor
<	up	go up the stairs
>	down	go down the stairs
^	trap_id	identify a previously found trap
),[,=	ask for current weapon, armor, rings, respectively
. or <space>  wait a moment
//E*O*F hh//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 4 (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.Decl.c hack.apply.c hack.bones.c hack.cmdlist.c hack.do.c

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

#include	"hack.h"
char nul[40];			/* contains zeros */
char plname[PL_NSIZ] = "player";/* player name */
char lock[32] = "1lock";	/* long enough for login name */

#ifdef WIZARD
boolean wizard;			/* TRUE when called as  hack -w */
#endif WIZARD

struct rm levl[COLNO][ROWNO];	/* level map */
#ifndef QUEST
struct mkroom rooms[MAXNROFROOMS+1];
coord doors[DOORMAX];
#endif QUEST
struct monst *fmon = 0;
struct gen *fgold = 0, *ftrap = 0;
struct obj *fobj = 0, *fcobj = 0, *invent = 0, *uwep = 0, *uarm = 0,
	*uarm2 = 0, *uarmh = 0, *uarms = 0, *uarmg = 0, *uright = 0,
	*uleft = 0, *uchain = 0, *uball = 0;
struct flag flags;
struct you u;

xchar dlevel = 1;
xchar xupstair, yupstair, xdnstair, ydnstair;
char *save_cm = 0, *killer, *nomovemsg;

long moves = 1;
long wailmsg = 0;

int multi = 0;
char genocided[60];
char fut_geno[60];

xchar curx,cury;
xchar seelx, seehx, seely, seehy;	/* corners of lit room */

coord bhitpos;
//E*O*F hack.Decl.c//

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

#include	"hack.h"
extern struct monst *bchit();
extern struct obj *addinv();
extern char pl_character[];

doapply() {
register struct obj *obj;
	obj = getobj("(", "use or apply");
	if(!obj) return(0);
	switch(obj->otyp){
	case EXPENSIVE_CAMERA:
		use_camera(obj); break;
	case ICE_BOX:
		use_ice_box(obj); break;
	case MAGIC_WHISTLE:
		if(pl_character[0] == 'W' || u.ulevel > 9) {
			use_magic_whistle(obj);
			break;
		}
		/* fall into next case */
	case WHISTLE:
		use_whistle(obj); break;
	default:
		pline("Sorry, I don't know how to use that.");
		return(0);
	}
	return(1);
}

/* ARGSUSED */
use_camera(obj) /* register */ struct obj *obj; {
register struct monst *mtmp;
	if(!getdir()){
		flags.move = multi = 0;
		return;
	}
	if(mtmp = bchit(u.dx, u.dy, COLNO, '!')) {
		if(mtmp->msleep){
			mtmp->msleep = 0;
			pline("The flash awakens the %s.", monnam(mtmp));
		} else
		if(mtmp->data->mlet != 'y')
		if(mtmp->mcansee || mtmp->mblinded){
			register int tmp = dist(mtmp->mx,mtmp->my);
			register int tmp2;
			/* if(cansee(mtmp->mx,mtmp->my)) */
			  pline("%s is blinded by the flash!",Monnam(mtmp));
			setmangry(mtmp);
			if(tmp < 9 && !mtmp->isshk && !rn2(4))
				mtmp->mflee = 1;
			if(tmp < 3) mtmp->mcansee  = mtmp->mblinded = 0;
			else {
				tmp2 = mtmp->mblinded;
				tmp2 += rnd(1 + 50/tmp);
				if(tmp2 > 127) tmp2 = 127;
				mtmp->mblinded = tmp2;
				mtmp->mcansee = 0;
			}
		}
	}
}

struct obj *current_ice_box;	/* a local variable of use_ice_box, to be
				used by its local procedures in/ck_ice_box */
in_ice_box(obj) register struct obj *obj; {
	if(obj == current_ice_box ||
		(Punished && (obj == uball || obj == uchain))){
		pline("You must be kidding.");
		return(0);
	}
	if(obj->owornmask & (W_ARMOR | W_RING)) {
		pline("You cannot refrigerate something you are wearing.");
		return(0);
	}
	if(obj->owt + current_ice_box->owt > 70) {
		pline("It won't fit.");
		return(1);	/* be careful! */
	}
	if(obj == uwep) {
		if(uwep->cursed) {
			pline("Your weapon is welded to your hand!");
			return(0);
		}
		setuwep((struct obj *) 0);
	}
	current_ice_box->owt += obj->owt;
	freeinv(obj);
	obj->o_cnt_id = current_ice_box->o_id;
	obj->nobj = fcobj;
	fcobj = obj;
	obj->age = moves - obj->age;	/* actual age */
	return(1);
}

ck_ice_box(obj) register struct obj *obj; {
	return(obj->o_cnt_id == current_ice_box->o_id);
}

out_ice_box(obj) register struct obj *obj; {
register struct obj *otmp;
	if(obj == fcobj) fcobj = fcobj->nobj;
	else {
		for(otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj)
			if(!otmp->nobj) panic("out_ice_box");
		otmp->nobj = obj->nobj;
	}
	current_ice_box->owt -= obj->owt;
	obj->age = moves - obj->age;	/* simulated point of time */
	(void) addinv(obj);
}

use_ice_box(obj) register struct obj *obj; {
register int cnt = 0;
register struct obj *otmp;
	current_ice_box = obj;	/* for use by in/out_ice_box */
	for(otmp = fcobj; otmp; otmp = otmp->nobj)
		if(otmp->o_cnt_id == obj->o_id)
			cnt++;
	if(!cnt) pline("Your ice-box is empty.");
	else {
	    pline("Do you want to take something out of the ice-box? [yn] ");
	    if(readchar() == 'y')
		if(askchain(fcobj, (char *) 0, 0, out_ice_box, ck_ice_box, 0))
		    return;
		pline("That was all. Do you wish to put something in? [yn] ");
		if(readchar() != 'y') return;
	}
	/* call getobj: 0: allow cnt; #: allow all types; %: expect food */
	otmp = getobj("0#%", "put in");
	if(!otmp || !in_ice_box(otmp))
		flags.move = multi = 0;
}

struct monst *
bchit(ddx,ddy,range,sym) register int ddx,ddy,range; char sym; {
	register struct monst *mtmp = (struct monst *) 0;
	register int bchx = u.ux, bchy = u.uy;

	if(sym) Tmp_at(-1, sym);	/* open call */
	while(range--) {
		bchx += ddx;
		bchy += ddy;
		if(mtmp = m_at(bchx,bchy))
			break;
		if(levl[bchx][bchy].typ < CORR) {
			bchx -= ddx;
			bchy -= ddy;
			break;
		}
		if(sym) Tmp_at(bchx, bchy);
	}
	if(sym) Tmp_at(-1, -1);
	return(mtmp);
}

#include	"def.edog.h"
/* ARGSUSED */
use_whistle(obj) struct obj *obj; {
register struct monst *mtmp = fmon;
	pline("You produce a high whistling sound.");
	while(mtmp) {
		if(dist(mtmp->mx,mtmp->my) < u.ulevel*10) {
			if(mtmp->msleep)
				mtmp->msleep = 0;
			if(mtmp->mtame)
				EDOG(mtmp)->whistletime = moves;
		}
		mtmp = mtmp->nmon;
	}
}

/* ARGSUSED */
use_magic_whistle(obj) struct obj *obj; {
register struct monst *mtmp = fmon;
	pline("You produce a strange whistling sound.");
	while(mtmp) {
		if(mtmp->mtame) mnexto(mtmp);
		mtmp = mtmp->nmon;
	}
}
//E*O*F hack.apply.c//

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

#include "hack.h"
extern char plname[PL_NSIZ];
extern struct monst *makemon();

struct permonst pm_ghost = { "ghost", ' ', 10, 3, -5, 1, 1, sizeof(plname) };


char bones[] = "bones_xx";

/* save bones and possessions of a deceased adventurer */
savebones(){
register fd;
register struct obj *otmp;
register struct gen *gtmp;
register struct monst *mtmp;
	if(!rn2(1 + dlevel/2)) return;	/* not so many ghosts on low levels */
	bones[6] = '0' + (dlevel/10);
	bones[7] = '0' + (dlevel%10);
	if((fd = open(bones,0)) >= 0){
		(void) close(fd);
		return;
	}
	/* drop everything; the corpse's possessions are usually cursed */
	otmp = invent;
	while(otmp){
		otmp->ox = u.ux;
		otmp->oy = u.uy;
		otmp->known = 0;
		otmp->age = 0;		/* very long ago */
		otmp->owornmask = 0;
		if(rn2(5)) otmp->cursed = 1;
		if(!otmp->nobj){
			otmp->nobj = fobj;
			fobj = invent;
			invent = 0;	/* superfluous */
			break;
		}
		otmp = otmp->nobj;
	}
	if(!(mtmp = makemon(&pm_ghost, u.ux, u.uy))) return;
	mtmp->mx = u.ux;
	mtmp->my = u.uy;
	mtmp->msleep = 1;
	(void) strcpy((char *) mtmp->mextra, plname);
	mkgold(somegold() + d(dlevel,30), u.ux, u.uy);
	u.ux = FAR;		/* avoid animals standing next to us */
	keepdogs();		/* all tame animals become wild again */
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
		mtmp->mlstmv = 0;
		if(mtmp->mdispl) unpmon(mtmp);
	}
	for(gtmp = ftrap; gtmp; gtmp = gtmp->ngen)
		gtmp->gflag &= ~SEEN;
	for(otmp = fobj; otmp; otmp = otmp->nobj)
		otmp->onamelth = 0;
	if((fd = creat(bones, FMASK)) < 0) return;
	savelev(fd);
	(void) close(fd);
}

getbones(){
register fd,x,y,ok;
	if(rn2(3)) return(0);	/* only once in three times do we find bones */
	bones[6] = '0' + dlevel/10;
	bones[7] = '0' + dlevel%10;
	if((fd = open(bones, 0)) < 0) return(0);
	if((ok = uptodate(fd)) != 0){
		(void) getlev(fd);
		(void) close(fd);
		for(x = 0; x < COLNO; x++) for(y = 0; y < ROWNO; y++)
			levl[x][y].seen = levl[x][y].new = 0;
	}
	if(unlink(bones) < 0){
		pline("Cannot unlink %s", bones);
		return(0);
	}
	return(ok);
}
//E*O*F hack.bones.c//

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

#include	"config.h"
#include	"def.objclass.h"
#include	"def.func_tab.h"

int doredraw(),doredotopl(),dodrop(),dodrink(),doread(),dosearch(),
doversion(),doweararm(),dowearring(),doremarm(),doremring(),dopay(),doapply(),
dosave(),dowield(),ddoinv(),dozap(),ddocall(),dowhatis(),doengrave(),
dohelp(),doeat(),doddrop(),do_mname(),doidtrap(),doprwep(),doprarm(),doprring();
#ifdef SHELL
int dosh();
#endif SHELL
#ifdef OPTIONS
int doset();
#endif OPTIONS
int doup(), dodown(), done1(), donull();
int dothrow();
struct func_tab list[]={
	'\022', doredraw,
	'\020', doredotopl,
	'a', doapply,
/*	'A' : UNUSED */
/*	'b', 'B' : go sw */
	'c', ddocall,
	'C', do_mname,
	'd', dodrop,
	'D', doddrop,
	'e', doeat,
	'E', doengrave,
/*	'f', 'F' : multiple go (might become 'fight') */
/*	'g', 'G' : UNUSED */
/*	'h', 'H' : go west */
	'i', ddoinv,
/*	'I' : UNUSED */
/*	'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
#ifdef OPTIONS
	'o', doset,
#endif OPTIONS
/*	'O' : UNUSED */
	'p', dopay,
	'P', dowearring,
	'q', dodrink,
	'Q', done1,
	'r', doread,
	'R', doremring,
	's', dosearch,
	'S', dosave,
	't', dothrow,
	'T', doremarm,
/*	'u', 'U' : go ne */
	'v', doversion,
/*	'V' : UNUSED */
	'w', dowield,
	'W', doweararm,
/*	'x', 'X' : UNUSED */
/*	'y', 'Y' : go nw */
	'z', dozap,
/*	'Z' : UNUSED */
	'<', doup,
	'>', dodown,
	'/', dowhatis,
	'?', dohelp,
#ifdef SHELL
	'!', dosh,
#endif SHELL
	'.', donull,
	' ', donull,
	'^', doidtrap,
	 WEAPON_SYM,  doprwep,
	 ARMOR_SYM,  doprarm,
	 RING_SYM,  doprring,
	0,0,0
};
//E*O*F hack.cmdlist.c//

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

#include <stdio.h>
#include <signal.h>
#include "hack.h"
#include "def.func_tab.h"

extern char *getenv(),*parse(),*getlogin(),*lowc(),*unctrl();
extern int float_down();
extern char *nomovemsg, *catmore;
extern struct obj *splitobj(), *addinv();
extern boolean hmon();

/*	Routines to do various user commands */

int done1();

dodrink() {
	register struct obj *otmp,*objs;
	register struct monst *mtmp;
	register int unkn = 0, nothing = 0;

	otmp = getobj("!", "drink");
	if(!otmp) return(0);
	switch(otmp->otyp){
	case POT_RESTORE_STRENGTH:
		unkn++;
		pline("Wow!  This makes you feel great!");
		if(u.ustr < u.ustrmax) {
			u.ustr = u.ustrmax;
			flags.botl = 1;
		}
		break;
	case POT_BOOZE:
		unkn++;
		pline("Ooph!  This tastes like liquid fire!");
		Confusion += d(3,8);
		/* the whiskey makes us feel better */
		if(u.uhp < u.uhpmax) losehp(-1, "bottle of whiskey");
		if(!rn2(4)) {
			pline("You pass out.");
			multi = -rnd(15);
			nomovemsg = "You awake with a headache.";
		}
		break;
	case POT_INVISIBILITY:
		if(Invis)
		  nothing++;
		else {
		  if(!Blind)
		    pline("Gee!  All of a sudden, you can't see yourself.");
		  else
		    pline("You feel rather airy."), unkn++;
		  newsym(u.ux,u.uy);
		}
		Invis += rn1(15,31);
		break;
	case POT_FRUIT_JUICE:
		pline("This tastes like fruit juice.");
		lesshungry(20);
		break;
	case POT_HEALING:
		pline("You begin to feel better.");
		flags.botl = 1;
		u.uhp += rnd(10);
		if(u.uhp > u.uhpmax)
			u.uhp = ++u.uhpmax;
		if(Blind) Blind = 1;	/* see on next move */
		if(Sick) Sick = 0;
		break;
	case POT_PARALYSIS:
		pline("Your feet are frozen to the floor!");
		nomul(-(rn1(10,25)));
		break;
	case POT_MONSTER_DETECTION:
		if(!fmon) {
			strange_feeling(otmp);
			return(1);
		} else {
			cls();
			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
				if(mtmp->mx > 0)
				at(mtmp->mx,mtmp->my,mtmp->data->mlet);
			prme();
			pline("You sense the presence of monsters.");
			more();
			docrt();
		}
		break;
	case POT_OBJECT_DETECTION:
		if(!fobj) {
			strange_feeling(otmp);
			return(1);
		} else {
		    for(objs = fobj; objs; objs = objs->nobj)
			if(objs->ox != u.ux || objs->oy != u.uy)
				goto outobjmap;
		    pline("You sense the presence of objects close nearby.");
		    break;
		outobjmap:
			cls();
			for(objs = fobj; objs; objs = objs->nobj)
				at(objs->ox,objs->oy,objs->olet);
			prme();
			pline("You sense the presence of objects.");
			more();
			docrt();
		}
		break;
	case POT_SICKNESS:
		pline("Yech! This stuff tastes like poison.");
		if(Poison_resistance)
    pline("(But in fact it was biologically contaminated orange juice.)");
		losestr(rn1(4,3));
		losehp(rnd(10), "poison potion");
		break;
	case POT_CONFUSION:
		if(!Confusion)
			pline("Huh, What?  Where am I?");
		else
			nothing++;
		Confusion += rn1(7,16);
		break;
	case POT_GAIN_STRENGTH:
		pline("Wow do you feel strong!");
		if(u.ustr == 118) break;
		if(u.ustr > 17) u.ustr += rnd(118-u.ustr);
		else u.ustr++;
		if(u.ustr > u.ustrmax) u.ustrmax = u.ustr;
		flags.botl = 1;
		break;
	case POT_SPEED:
		if(Wounded_legs) {
			if((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
				pline("Your legs feel somewhat better.");
			else
				pline("Your leg feels somewhat better.");
			Wounded_legs = 0;
			unkn++;
			break;
		}
		if(!(Fast & ~INTRINSIC))
			pline("You are suddenly moving much faster.");
		else
			pline("Your legs get new energy."), unkn++;
		Fast += rn1(10,100);
		break;
	case POT_BLINDNESS:
		if(!Blind)
			pline("A cloud of darkness falls upon you.");
		else
			nothing++;
		Blind += rn1(100,250);
		seeoff(0);
		break;
	case POT_GAIN_LEVEL: 
		pluslvl();
		break;
	case POT_EXTRA_HEALING:
		pline("You feel much better.");
		flags.botl = 1;
		u.uhp += d(2,20)+1;
		if(u.uhp > u.uhpmax)
			u.uhp = (u.uhpmax += 2);
		if(Blind) Blind = 1;
		if(Sick) Sick = 0;
		break;
	case POT_LEVITATION:
		if(!Levitation)
			float_up();
		else
			nothing++;
		Levitation += rnd(100);
		u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down;
		break;
	default:
		pline("What a funny potion! (%d)", otmp->otyp);
		impossible();
		return(0);
	}
	if(nothing) {
	    unkn++;
	    pline("You have a peculiar feeling for a moment, then it passes.");
	}
	if(otmp->dknown && !objects[otmp->otyp].oc_name_known) {
		if(!unkn) {
			objects[otmp->otyp].oc_name_known = 1;
			u.urexp += 10;
		} else if(!objects[otmp->otyp].oc_uname)
			docall(otmp);
	}
	useup(otmp);
	return(1);
}

pluslvl()
{
	register num;

	pline("You feel more experienced.");
	num = rnd(10);
	u.uhpmax += num;
	u.uhp += num;
	u.uexp = (10*pow(u.ulevel-1))+1;
	pline("Welcome to level %d.", ++u.ulevel);
	flags.botl = 1;
}

strange_feeling(obj)
register struct obj *obj;
{
	pline("You have a strange feeling for a moment, then it passes.");
	if(!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
		docall(obj);
	useup(obj);
}

dodrop() {
	register struct obj *obj;

	obj = getobj("0$#", "drop");
	if(!obj) return(0);
	if(obj->olet == '$') {
		if(obj->quan == 0)
			pline("You didn't drop any gold pieces.");
		else {
			mkgold((int) obj->quan, u.ux, u.uy);
			pline("You dropped %u gold piece%s.",
				obj->quan, plur(obj->quan));
			if(Invis) newsym(u.ux, u.uy);
		}
		free((char *) obj);
		return(1);
	}
	return(drop(obj));
}

drop(obj) register struct obj *obj; {
	if(obj->owornmask & (W_ARMOR | W_RING)){
		pline("You cannot drop something you are wearing.");
		return(0);
	}
	if(obj == uwep) {
		if(uwep->cursed) {
			pline("Your weapon is welded to your hand!");
			return(0);
		}
		setuwep((struct obj *) 0);
	}
	pline("You dropped %s.", doname(obj));
	dropx(obj);
	return(1);
}

dropx(obj) register struct obj *obj; {
	if(obj->otyp == CRYSKNIFE)
		obj->otyp = WORM_TOOTH;
	freeinv(obj);
	obj->ox = u.ux;
	obj->oy = u.uy;
	obj->nobj = fobj;
	fobj = obj;
	if(Invis) newsym(u.ux,u.uy);
	subfrombill(obj);
	stackobj(obj);
}

/* drop several things */
doddrop() {
	return(ggetobj("drop", drop, 0));
}

rhack(cmd)
register char *cmd;
{
	register struct func_tab *tlist = list;
	boolean firsttime = FALSE;
	register res;

	if(!cmd) {
		firsttime = TRUE;
		flags.nopick = 0;
		cmd = parse();
	}
	if(!*cmd || *cmd == 0377)
		return;		/* probably we just had an interrupt */
	if(movecm(cmd)) {
	walk:
		if(multi) flags.mv = 1;
		domove();
		return;
	}
	if(movecm(lowc(cmd))) {
		flags.run = 1;
	rush:
		if(firsttime){
			if(!multi) multi = COLNO;
			u.last_str_turn = 0;
		}
		flags.mv = 1;
#ifdef QUEST
		if(flags.run >= 4) finddir();
		if(firsttime){
			u.ux0 = u.ux + u.dx;
			u.uy0 = u.uy + u.dy;
		}
#endif QUEST
		domove();
		return;
	}
	if((*cmd == 'f' && movecm(cmd+1)) ||
		movecm(unctrl(cmd))) {
		flags.run = 2;
		goto rush;
	}
	if(*cmd == 'F' && movecm(lowc(cmd+1))) {
		flags.run = 3;
		goto rush;
	}
	if(*cmd == 'm' && movecm(cmd+1)) {
		flags.run = 0;
		flags.nopick = 1;
		goto walk;
	}
	if(*cmd == 'M' && movecm(lowc(cmd+1))) {
		flags.run = 1;
		flags.nopick = 1;
		goto rush;
	}
#ifdef QUEST
	if(*cmd == cmd[1] && (*cmd == 'f' || *cmd == 'F')) {
		flags.run = 4;
		if(*cmd == 'F') flags.run += 2;
		if(cmd[2] == '-') flags.run += 1;
		goto rush;
	}
#endif QUEST
	while(tlist->f_char) {
		if(*cmd == tlist->f_char){
			res = (*(tlist->f_funct))(0);
			if(!res) {
				flags.move = 0;
				multi = 0;
			}
			return;
		}
		tlist++;
	}
	pline("Unknown command '%s'",cmd);
	multi = flags.move = 0;
}

doredraw()
{
	docrt();
	return(0);
}

dohelp()
{
	if(child(1)){
		execl(catmore,"more","help",(char *)0);
		exit(1);
	}
	return(0);
}

#ifdef SHELL
dosh(){
register char *str;
	if(child(0)) {
		(void) chdir(getenv("HOME"));
		if(str = getenv("SHELL")) execl(str,str,(char *) 0);
		if(strcmp("player", getlogin()))
			execl("/bin/sh","sh",(char *) 0);
		pline("sh: cannot execute.");
		exit(1);
	}
	return(0);
}
#endif SHELL

#ifdef BSD
#include	<sys/wait.h>
#else
#include	<wait.h>
#endif BSD

child(wt) {
register int f = fork();
	if(f == 0){		/* child */
		settty((char *) 0);
		(void) setuid(getuid());
		return(1);
	}
	if(f == -1) {	/* cannot fork */
		pline("Fork failed. Try again.");
		return(0);
	}
	/* fork succeeded; wait for child to exit */
	(void) signal(SIGINT,SIG_IGN);
	(void) signal(SIGQUIT,SIG_IGN);
	(void) wait((union wait *) 0);
	setctty();
	(void) signal(SIGINT,done1);
#ifdef WIZARD
	if(wizard) (void) signal(SIGQUIT,SIG_DFL);
#endif WIZARD
	if(wt) getret();
	docrt();
	return(0);
}

dodown()
{
	if(u.ux != xdnstair || u.uy != ydnstair) {
		pline("You can't go down here.");
		return(0);
	}
	if(u.ustuck) {
		pline("You are being held, and cannot go down.");
		return(1);
	}
	if(Levitation) {
		pline("You're floating high above the stairs.");
		return(0);
	}

	goto_level(dlevel+1, TRUE);
	return(1);
}

doup()
{
	if(u.ux != xupstair || u.uy != yupstair) {
		pline("You can't go up here.");
		return(0);
	}
	if(u.ustuck) {
		pline("You are being held, and cannot go up.");
		return(1);
	}
	if(inv_weight() + 5 > 0) {
		pline("Your load is too heavy to climb the stairs.");
		return(1);
	}

	goto_level(dlevel-1, TRUE);
	return(1);
}

goto_level(newlevel, at_stairs)
register int newlevel;
register boolean at_stairs;
{
	register fd;
	register boolean up = (newlevel < dlevel);

	if(newlevel <= 0) done("escaped");	/* in fact < 0 is impossible */
	if(newlevel == dlevel) return;		/* this cannot happen either */

	glo(dlevel);
	fd = creat(lock,FMASK);
	if(fd < 0) {
		/*
		 * This is not quite impossible: e.g., we may have
		 * exceeded our quota. If that is the case then we
		 * cannot leave this level, and cannot save either.
		 */
		pline("A mysterious force prevents you from going %d.",
			up ? "up" : "down");
		return;
	}

	if(Punished) unplacebc();
	keepdogs();
	seeoff(1);
	flags.nscrinh = 1;
	u.ux = FAR;				/* hack */
	(void) inshop();			/* probably was a trapdoor */

	savelev(fd);
	(void) close(fd);

	dlevel = newlevel;
	if(maxdlevel < dlevel)
		maxdlevel = dlevel;
	glo(dlevel);
	if((fd = open(lock,0)) < 0)
		mklev();
	else {
		(void) getlev(fd);
		(void) close(fd);
	}

	if(at_stairs) {
	    if(up) {
		u.ux = xdnstair;
		u.uy = ydnstair;
		if(!u.ux) {		/* entering a maze from below? */
		    u.ux = xupstair;	/* this will confuse the player! */
		    u.uy = yupstair;
		}
		if(Punished){
			pline("With great effort you climb the stairs");
			placebc(1);
		}
	    } else {
		u.ux = xupstair;
		u.uy = yupstair;
		if(inv_weight() + 5 > 0 || Punished){
			pline("You fall down the stairs.");
			losehp(rnd(3), "fall");
			if(Punished) {
			    if(uwep != uball && rn2(3)){
				pline("... and are hit by the iron ball");
				losehp(rnd(20), "iron ball");
			    }
			    placebc(1);
			}
			selftouch("Falling, you");
		}
	    }
	} else {	/* trapdoor or level_tele */
	    do {
		u.ux = rnd(COLNO-1);
		u.uy = rn2(ROWNO);
	    } while(levl[u.ux][u.uy].typ != ROOM ||
			m_at(u.ux,u.uy));
	    if(Punished){
		if(uwep != uball && !up /* %% */ && rn2(5)){
			pline("The iron ball falls on your head.");
			losehp(rnd(25), "iron ball");
		}
		placebc(1);
	    }
	    selftouch("Falling, you");
	}
	(void) inshop();
#ifdef TRACK
	initrack();
#endif TRACK

	losedogs();
	flags.nscrinh = 0;
	setsee();
	docrt();
	pickup();
	read_engr_at(u.ux,u.uy);
}

donull() {
	return(1);	/* Do nothing, but let other things happen */
}

struct monst *bhit(), *boomhit();
dothrow()
{
	register struct obj *obj;
	register struct monst *mon;
	register tmp;

	obj = getobj("#)", "throw");	/* it is also possible to throw food */
					/* (or jewels, or iron balls ... ) */
	if(!obj || !getdir())
		return(0);
	if(obj->owornmask & (W_ARMOR | W_RING)){
		pline("You can't throw something you are wearing");
		return(0);
	}
	if(obj == uwep){
		if(obj->cursed){
			pline("Your weapon is welded to your hand");
			return(1);
		}
		if(obj->quan > 1)
			setuwep(splitobj(obj, 1));
		else
			setuwep((struct obj *) 0);
	}
	else if(obj->quan > 1)
		(void) splitobj(obj, 1);
	freeinv(obj);
	if(u.uswallow) {
		mon = u.ustuck;
		bhitpos.x = mon->mx;
		bhitpos.y = mon->my;
	} else if(obj->otyp == BOOMERANG) {
		mon = boomhit(u.dx,u.dy);
		/* boomhit delivers -1 if the thing was caught */
		if((int) mon == -1) {
			(void) addinv(obj);
			return(1);
		}
	} else
		mon = bhit(u.dx,u.dy,
			(!Punished || obj != uball) ? 8 :
				!u.ustuck ? 5 : 1,
			obj->olet);
	if(mon) {
		/* awake monster if sleeping */
		wakeup(mon);

		if(obj->olet == WEAPON_SYM) {
			tmp = -1+u.ulevel+mon->data->ac+abon();
			if(obj->otyp < ROCK) {
				if(!uwep ||
				    uwep->otyp != obj->otyp+(BOW-ARROW))
					tmp -= 4;
				else {
					tmp += uwep->spe;
				}
			} else
			if(obj->otyp == BOOMERANG) tmp += 4;
			tmp += obj->spe;
			if(u.uswallow || tmp >= rnd(20)) {
				if(hmon(mon,obj,1) == TRUE){
				  /* mon still alive */
#ifndef NOWORM
				  cutworm(mon,bhitpos.x,bhitpos.y,obj->otyp);
#endif NOWORM
				} else mon = 0;
				/* weapons thrown disappear sometimes */
				if(obj->otyp < BOOMERANG && rn2(3)) {
					/* check bill; free */
					obfree(obj, (struct obj *) 0);
					return(1);
				}
			} else miss(objects[obj->otyp].oc_name, mon);
		} else if(obj->otyp == HEAVY_IRON_BALL) {
			tmp = -1+u.ulevel+mon->data->ac+abon();
			if(!Punished || obj != uball) tmp += 2;
			if(u.utrap) tmp -= 2;
			if(u.uswallow || tmp >= rnd(20)) {
				if(hmon(mon,obj,1) == FALSE)
					mon = 0;	/* he died */
			} else miss("iron ball", mon);
		} else {
			if(cansee(bhitpos.x,bhitpos.y))
				pline("You miss %s.",monnam(mon));
			else pline("You miss it.");
			if(obj->olet == FOOD_SYM && mon->data->mlet == 'd')
				if(tamedog(mon,obj)) return(1);
			if(obj->olet == GEM_SYM && mon->data->mlet == 'u'){
			 if(obj->dknown && objects[obj->otyp].oc_name_known){
			  if(objects[obj->otyp].g_val > 0){
			    u.uluck += 5;
			    goto valuable;
			  } else {
			    pline("%s is not interested in your junk.",
				Monnam(mon));
			  }
			 } else { /* value unknown to @ */
			    u.uluck++;
			valuable:
			    pline("%s graciously accepts your gift.",
				Monnam(mon));
			    mpickobj(mon, obj);
			    rloc(mon);
			    return(1);
			 }
			}
		}
	}
	obj->ox = bhitpos.x;
	obj->oy = bhitpos.y;
	obj->nobj = fobj;
	fobj = obj;
	/* prevent him from throwing articles to the exit and escaping */
	/* subfrombill(obj); */
	stackobj(obj);
	if(Punished && obj == uball &&
		(bhitpos.x != u.ux || bhitpos.y != u.uy)){
		freeobj(uchain);
		unpobj(uchain);
		if(u.utrap){
			if(u.utraptype == TT_PIT)
				pline("The ball pulls you out of the pit!");
			else {
			    register int side =
				rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
			    pline("The ball pulls you out of the bear trap.");
			    pline("Your %s leg is severely damaged.",
				(side == LEFT_SIDE) ? "left" : "right");
			    Wounded_legs |= side + rnd(1000);
			    losehp(2, "thrown ball");
			}
			u.utrap = 0;
		}
		unsee();
		uchain->nobj = fobj;
		fobj = uchain;
		u.ux = uchain->ox = bhitpos.x - u.dx;
		u.uy = uchain->oy = bhitpos.y - u.dy;
		setsee();
		(void) inshop();
	}
	if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
	return(1);
}

getdir()
{
char buf[2];
	pline("What direction?");
	buf[0] = readchar();
	buf[1] = 0;
	return(movecm(buf));
}

/* split obj so that it gets size num */
/* remainder is put in the object structure delivered by this call */
struct obj *
splitobj(obj, num) register struct obj *obj; register int num; {
register struct obj *otmp;
	otmp = newobj(0);
	*otmp = *obj;		/* copies whole structure */
	otmp->o_id = flags.ident++;
	otmp->onamelth = 0;
	obj->quan = num;
	obj->owt = weight(obj);
	otmp->quan -= num;
	otmp->owt = weight(otmp);	/* -= obj->owt ? */
	obj->nobj = otmp;
	if(obj->unpaid) splitbill(obj,otmp);
	return(otmp);
}

char *
lowc(str)
register char *str;
{
	static char buf[2];

	if(*str >= 'A' && *str <= 'Z') *buf = *str+'a'-'A';
	else *buf = *str;
	buf[1] = 0;
	return(buf);
}

char *
unctrl(str)
register char *str;
{
	static char buf[2];
	if(*str >= ('A' & 037) && *str <= ('Z' & 037))
		*buf = *str + 0140;
	else *buf = *str;
	buf[1] = 0;
	return(buf);
}
//E*O*F hack.do.c//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 5 (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.do_name.c hack.do_wear.c hack.dog.c hack.eat.c

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

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

coord
getpos(force,goal) int force; char *goal; {
register cx,cy,i,c;
extern char sdir[];		/* defined in hack.c */
extern schar xdir[], ydir[];	/* idem */
extern char *visctrl();		/* see below */
coord cc;
	pline("(For instructions type a ?)");
	cx = u.ux;
	cy = u.uy;
	curs(cx,cy+2);
	while((c = readchar()) != '.'){
		for(i=0; i<8; i++) if(sdir[i] == c){
			if(1 <= cx + xdir[i] && cx + xdir[i] <= COLNO)
				cx += xdir[i];
			if(0 <= cy + ydir[i] && cy + ydir[i] <= ROWNO-1)
				cy += ydir[i];
			goto nxtc;
		}
		if(c == '?'){
			pline("Use [hjkl] to move the cursor to %s.", goal);
			pline("Type a . when you are at the right place.");
		} else {
			pline("unknown direction: '%s' (%s)",
				visctrl(c),
				force ? "use hjkl or ." : "aborted");
			if(force) goto nxtc;
			cc.x = -1;
			cc.y = 0;
			return(cc);
		}
	nxtc:	;
		curs(cx,cy+2);
	}
	cc.x = cx;
	cc.y = cy;
	return(cc);
}

do_mname(){
char buf[BUFSZ];
coord cc;
register int cx,cy,lth,i;
register struct monst *mtmp, *mtmp2;
extern char *lmonnam();
	cc = getpos(0, "the monster you want to name");
	cx = cc.x;
	cy = cc.y;
	if(cx < 0) return(0);
	mtmp = m_at(cx,cy);
	if(!mtmp){
	    if(cx == u.ux && cy == u.uy){
		extern char plname[];
		pline("This ugly monster is called %s and cannot be renamed.",
		    plname);
	    } else	pline("There is no monster there.");
	    return(1);
	}
	if(mtmp->mimic){
	    pline("I see no monster there.");
	    return(1);
	}
	if(!cansee(cx,cy)) {
	    pline("I cannot see a monster there.");
	    return(1);
	}
	pline("What do you want to call %s? ", lmonnam(mtmp));
	getlin(buf);
	clrlin();
	if(!*buf) return(1);
	lth = strlen(buf)+1;
	if(lth > 63){
		buf[62] = 0;
		lth = 63;
	}
	mtmp2 = newmonst(mtmp->mxlth + lth);
	*mtmp2 = *mtmp;
	for(i=0; i<mtmp->mxlth; i++)
		((char *) mtmp2->mextra)[i] = ((char *) mtmp->mextra)[i];
	mtmp2->mnamelth = lth;
	(void) strcpy(NAME(mtmp2), buf);
	replmon(mtmp,mtmp2);
	if(mtmp2->isshk) setshk();	/* redefine shopkeeper and bill */
	if(mtmp2->isgd) setgd( /* mtmp2 */ );
	return(1);
}

/*
 * This routine changes the address of  obj . Be careful not to call it
 * when there might be pointers around in unknown places. For now: only
 * when  obj  is in the inventory.
 */
do_oname(obj) register struct obj *obj; {
register struct obj *otmp, *otmp2;
register lth;
char buf[BUFSZ];
	pline("What do you want to name %s? ", doname(obj));
	getlin(buf);
	clrlin();
	if(!*buf) return;
	lth = strlen(buf)+1;
	if(lth > 63){
		buf[62] = 0;
		lth = 63;
	}
	otmp2 = newobj(lth);
	*otmp2 = *obj;
	otmp2->onamelth = lth;
	(void) strcpy(ONAME(otmp2), buf);

	setworn((struct obj *) 0, obj->owornmask);
	setworn(otmp2, otmp2->owornmask);

	/* do freeinv(obj); etc. by hand in order to preserve
	   the position of this object in the inventory */
	if(obj == invent) invent = otmp2;
	else for(otmp = invent; ; otmp = otmp->nobj){
		if(!otmp)
			panic("Do_oname: cannot find obj.");
		if(otmp->nobj == obj){
			otmp->nobj = otmp2;
			break;
		}
	}
	/* obfree(obj, otmp2);	/* now unnecessary: no pointers on bill */
	free((char *) obj);	/* let us hope nobody else saved a pointer */
}

ddocall()
{
	register struct obj *obj;

	pline("Do you want to name an individual object? [yn] ");
	if(readchar() == 'y'){
		obj = getobj("#", "name");
		if(obj) do_oname(obj);
	} else {
		obj = getobj("?!=/", "call");
		if(obj) docall(obj);
	}
	return(0);
}

docall(obj)
register struct obj *obj;
{
	char buf[BUFSZ];
	register char **str1;
	extern char *xname();
	register char *str = xname(obj);

	pline("Call %s %s: ", index(vowels,*str) ? "an" : "a", str);
	getlin(buf);
	clrlin();
	if(!*buf) return;
	str = newstring(strlen(buf)+1);
	(void) strcpy(str,buf);
	str1 = &(objects[obj->otyp].oc_uname);
	if(*str1) free(*str1);
	*str1 = str;
}

char *
xmonnam(mtmp, vb) register struct monst *mtmp; int vb; {
static char buf[BUFSZ];		/* %% */
extern char *shkname();
	if(mtmp->mnamelth && !vb) return(NAME(mtmp));
	switch(mtmp->data->mlet) {
	case ' ':
		(void) sprintf(buf, "%s's ghost", (char *) mtmp->mextra);
		break;
	case '@':
		if(mtmp->isshk) {
			(void) strcpy(buf, shkname());
			break;
		}
		/* fall into next case */
	default:
		(void) sprintf(buf, "the %s%s",
			mtmp->minvis ? "invisible " : "",
			mtmp->data->mname);
	}
	if(vb && mtmp->mnamelth) {
		(void) strcat(buf, " called ");
		(void) strcat(buf, NAME(mtmp));
	}
	return(buf);
}

char *
lmonnam(mtmp) register struct monst *mtmp; {
	return(xmonnam(mtmp, 1));
}

char *
monnam(mtmp) register struct monst *mtmp; {
	return(xmonnam(mtmp, 0));
}

char *
Monnam(mtmp) register struct monst *mtmp; {
register char *bp = monnam(mtmp);
	if('a' <= *bp && *bp <= 'z') *bp += ('A' - 'a');
	return(bp);
}

char *
amonnam(mtmp,adj)
register struct monst *mtmp;
register char *adj;
{
	register char *bp = monnam(mtmp);
	static char buf[BUFSZ];		/* %% */

	if(!strncmp(bp, "the ", 4)) bp += 4;
	(void) sprintf(buf, "the %s %s", adj, bp);
	return(buf);
}

char *
Amonnam(mtmp, adj)
register struct monst *mtmp;
register char *adj;
{
	register char *bp = amonnam(mtmp,adj);

	*bp = 'T';
	return(bp);
}

char *
Xmonnam(mtmp) register struct monst *mtmp; {
register char *bp = Monnam(mtmp);
	if(!strncmp(bp, "The ", 4)) {
		bp += 2;
		*bp = 'A';
	}
	return(bp);
}

char *
visctrl(c)
char c;
{
static char ccc[3];
	if(c < 040) {
		ccc[0] = '^';
		ccc[1] = c + 0100;
		ccc[2] = 0;
	} else {
		ccc[0] = c;
		ccc[1] = 0;
	}
	return(ccc);
}
//E*O*F hack.do_name.c//

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

#include "hack.h"
#include <stdio.h>
extern char *nomovemsg;

off_msg(otmp) register struct obj *otmp; {
	pline("You were wearing %s.", doname(otmp));
}

doremarm() {
	register struct obj *otmp;
	if(!uarm && !uarmh && !uarms && !uarmg) {
		pline("Not wearing any armor.");
		return(0);
	}
	otmp = (!uarmh && !uarms && !uarmg) ? uarm :
		(!uarms && !uarm && !uarmg) ? uarmh :
		(!uarmh && !uarm && !uarmg) ? uarms :
		(!uarmh && !uarm && !uarms) ? uarmg :
		getobj("[", "take off");
	if(!otmp) return(0);
	if(!(otmp->owornmask & (W_ARMOR - W_ARM2))) {
		pline("You can't take that off.");
		return(0);
	}
	(void) armoroff(otmp);
	return(1);
}

doremring() {
	if(!uleft && !uright){
		pline("Not wearing any ring.");
		return(0);
	}
	if(!uleft)
		return(dorr(uright));
	if(!uright)
		return(dorr(uleft));
	if(uleft && uright) while(1) {
		pline("What ring, Right or Left? ");
		switch(readchar()) {
		case ' ':
		case '\n':
		case '\033':
			return(0);
		case 'l':
		case 'L':
			return(dorr(uleft));
		case 'r':
		case 'R':
			return(dorr(uright));
		}
	}
	/* NOTREACHED */
#ifdef lint
	return(0);
#endif lint
}

dorr(otmp) register struct obj *otmp; {
	if(cursed(otmp)) return(0);
	ringoff(otmp);
	off_msg(otmp);
	return(1);
}

cursed(otmp) register struct obj *otmp; {
	if(otmp->cursed){
		pline("You can't. It appears to be cursed.");
		return(1);
	}
	return(0);
}

armoroff(otmp) register struct obj *otmp; {
register int delay = -objects[otmp->otyp].oc_delay;
	if(cursed(otmp)) return(0);
	setworn((struct obj *) 0, otmp->owornmask & W_ARMOR);
	if(delay) {
		nomul(delay);
		switch(otmp->otyp) {
		case HELMET:
			nomovemsg = "You finished taking off your helmet.";
			break;
		case PAIR_OF_GLOVES:
			nomovemsg = "You finished taking off your gloves";
			break;
		default:
			nomovemsg = "You finished taking off your suit.";
		}
	} else {
		off_msg(otmp);
	}
	return(1);
}

doweararm() {
	register struct obj *otmp;
	register int delay;
	register int err = 0;
	long mask = 0;

	otmp = getobj("[", "wear");
	if(!otmp) return(0);
	if(otmp->owornmask & W_ARMOR) {
		pline("You are already wearing that!");
		return(0);
	}
	if(otmp->otyp == HELMET){
		if(uarmh) {
			pline("You are already wearing a helmet.");
			err++;
		} else
			mask = W_ARMH;
	} else if(otmp->otyp == SHIELD){
		if(uarms) pline("You are already wearing a shield."), err++;
		if(uwep && uwep->otyp == TWO_HANDED_SWORD)
	pline("You cannot wear a shield and wield a two-handed sword."), err++;
		if(!err) mask = W_ARMS;
	} else if(otmp->otyp == PAIR_OF_GLOVES){
		if(uarmg) pline("You are already wearing gloves."); else
		if(uwep && uwep->cursed)
			pline("You cannot wear gloves over your weapon.");
		else mask = W_ARMG;
	} else {
		if(uarm) {
			if(otmp->otyp != ELVEN_CLOAK || uarm2) {
				pline("You are already wearing some armor.");
				err++;
			}
		}
		if(!err) mask = W_ARM;
	}
	if(err) return(0);
	setworn(otmp, mask);
	if(otmp == uwep)
		setuwep((struct obj *) 0);
	delay = -objects[otmp->otyp].oc_delay;
	if(delay){
		nomul(delay);
		nomovemsg = "You finished your dressing manoeuvre.";
	}
	otmp->known = 1;
	return(1);
}

dowearring() {
	register struct obj *otmp;
	long mask = 0;
	long oldprop;

	if(uleft && uright){
		pline("There are no more ring-fingers to fill.");
		return(0);
	}
	otmp = getobj("=", "wear");
	if(!otmp) return(0);
	if(otmp->owornmask & W_RING) {
		pline("You are already wearing that!");
		return(0);
	}
	if(otmp == uleft || otmp == uright) {
		pline("You are already wearing that.");
		return(0);
	}
	if(uleft) mask = RIGHT_RING;
	else if(uright) mask = LEFT_RING;
	else do {
 		pline("What ring-finger, Right or Left? ");
		switch(readchar()){
		case 'l':
		case 'L':
			mask = LEFT_RING;
			break;
		case 'r':
		case 'R':
			mask = RIGHT_RING;
			break;
		case ' ':
		case '\n':
		case '\033':
			return(0);
		}
	} while(!mask);
	setworn(otmp, mask);
	if(otmp == uwep)
		setuwep((struct obj *) 0);
	oldprop = u.uprops[PROP(otmp->otyp)].p_flgs;
	u.uprops[PROP(otmp->otyp)].p_flgs |= mask;
	switch(otmp->otyp){
	case RIN_LEVITATION:
		if(!oldprop) float_up();
		break;
	case RIN_PROTECTION_FROM_SHAPE_CHANGERS:
		rescham();
		break;
	case RIN_GAIN_STRENGTH:
		u.ustr += otmp->spe;
		u.ustrmax += otmp->spe;
		flags.botl=1;
		break;
	case RIN_INCREASE_DAMAGE:
		u.udaminc += otmp->spe;
		break;
	}
	prinv(otmp);
	return(1);
}

ringoff(obj)
register struct obj *obj;
{
register unsigned mask;
	mask = obj->owornmask & W_RING;
	setworn((struct obj *) 0, obj->owornmask);
	if(!(u.uprops[PROP(obj->otyp)].p_flgs & mask)){
		pline("Strange... I didnt know you had that ring.");
		impossible();
	}
	u.uprops[PROP(obj->otyp)].p_flgs &= ~mask;
	switch(obj->otyp) {
	case RIN_LEVITATION:
		if(!Levitation) {	/* no longer floating */
			float_down();
		}
		break;
	case RIN_GAIN_STRENGTH:
		u.ustr -= obj->spe;
		u.ustrmax -= obj->spe;
		flags.botl = 1;
		break;
	case RIN_INCREASE_DAMAGE:
		u.udaminc -= obj->spe;
		break;
	}
}

find_ac(){
register int uac = 10;
	if(uarm) uac -= uarm->spe;
	if(uarm2) uac -= uarm2->spe;
	if(uarmh) uac -= uarmh->spe;
	if(uarms) uac -= uarms->spe;
	if(uarmg) uac -= uarmg->spe;
	if(uleft && uleft->otyp == RIN_PROTECTION) uac -= uleft->spe;
	if(uright && uright->otyp == RIN_PROTECTION) uac -= uright->spe;
	if(uac != u.uac){
		u.uac = uac;
		flags.botl = 1;
	}
}

glibr(){
register struct obj *otmp;
int xfl = 0;
	if(!uarmg) if(uleft || uright) {
		/* Note: at present also cursed rings fall off */
		pline("Your %s off your fingers.",
			(uleft && uright) ? "rings slip" : "ring slips");
		xfl++;
		if(otmp = uleft){
			ringoff(uleft);
			dropx(otmp);
		}
		if(otmp = uright){
			ringoff(uright);
			dropx(otmp);
		}
	}
	if(otmp = uwep){
		/* Note: at present also cursed weapons fall */
		setuwep((struct obj *) 0);
		dropx(otmp);
		pline("Your weapon %sslips from your hands.",
			xfl ? "also " : "");
	}
}

struct obj *
some_armor(){
register struct obj *otmph = uarm;
	if(uarmh && (!otmph || !rn2(4))) otmph = uarmh;
	if(uarmg && (!otmph || !rn2(4))) otmph = uarmg;
	if(uarms && (!otmph || !rn2(4))) otmph = uarms;
	return(otmph);
}

corrode_armor(){
register struct obj *otmph = some_armor();
	if(otmph){
		if(otmph->rustfree ||
		   otmph->otyp == ELVEN_CLOAK ||
		   otmph->otyp == LEATHER_ARMOR ||
		   otmph->otyp == STUDDED_LEATHER_ARMOR) {
			pline("Your %s not affected!",
				aobjnam(otmph, "are"));
			return;
		}
		pline("Your %s!", aobjnam(otmph, "corrode"));
		otmph->spe--;
	}
}
//E*O*F hack.do_wear.c//

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

#include	"hack.h"
#include	"hack.mfndpos.h"
extern char POISONOUS[];
extern struct monst *makemon();
#include "def.edog.h"

struct permonst li_dog =
	{ "little dog", 'd',2,18,6,1,6,sizeof(struct edog) };
struct permonst dog =
	{ "dog", 'd',4,16,5,1,6,sizeof(struct edog) };
struct permonst la_dog =
	{ "large dog", 'd',6,15,4,2,4,sizeof(struct edog) };


makedog(){
register struct monst *mtmp = makemon(&li_dog,u.ux,u.uy);
	if(!mtmp) return; /* dogs were genocided */
	initedog(mtmp);
}

initedog(mtmp) register struct monst *mtmp; {
	mtmp->mtame = mtmp->mpeaceful = 1;
	EDOG(mtmp)->hungrytime = 1000 + moves;
	EDOG(mtmp)->eattime = 0;
	EDOG(mtmp)->droptime = 0;
	EDOG(mtmp)->dropdist = 10000;
	EDOG(mtmp)->apport = 10;
	EDOG(mtmp)->whistletime = 0;
}

/* attach the monsters that went down (or up) together with @ */
struct monst *mydogs = 0;
struct monst *fallen_down = 0;	/* monsters that fell through a trapdoor */

losedogs(){
register struct monst *mtmp;
	while(mtmp = mydogs){
		mydogs = mtmp->nmon;
		mtmp->nmon = fmon;
		fmon = mtmp;
		mnexto(mtmp);
	}
	while(mtmp = fallen_down){
		fallen_down = mtmp->nmon;
		mtmp->nmon = fmon;
		fmon = mtmp;
		rloc(mtmp);
	}
}

keepdogs(){
register struct monst *mtmp;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->mtame) {
		if(dist(mtmp->mx,mtmp->my) > 2) {
			mtmp->mtame = 0;	/* dog becomes wild */
			mtmp->mpeaceful = 0;
			continue;
		}
		relmon(mtmp);
		mtmp->nmon = mydogs;
		mydogs = mtmp;
		unpmon(mtmp);
		keepdogs();	/* we destroyed the link, so use recursion */
		return;		/* (admittedly somewhat primitive) */
	}
}

fall_down(mtmp) register struct monst *mtmp; {
	relmon(mtmp);
	mtmp->nmon = fallen_down;
	fallen_down = mtmp;
	unpmon(mtmp);
	mtmp->mtame = 0;
}

/* return quality of food; the lower the better */
#define	DOGFOOD	0
#define	CADAVER	1
#define	ACCFOOD	2
#define	MANFOOD	3
#define	APPORT	4
#define	POISON	5
#define	UNDEF	6
dogfood(obj) register struct obj *obj; {
	switch(obj->olet) {
	case FOOD_SYM:
	    return(
		(obj->otyp == TRIPE_RATION) ? DOGFOOD :
		(obj->otyp < CARROT) ? ACCFOOD :
		(obj->otyp < CORPSE) ? MANFOOD :
		(index(POISONOUS, obj->spe) || obj->age + 50 <= moves ||
		    obj->otyp == DEAD_COCKATRICE)
			? POISON : CADAVER
	    );
	default:
	    if(!obj->cursed) return(APPORT);
	    /* fall into next case */
	case BALL_SYM:
	case CHAIN_SYM:
	case ROCK_SYM:
	    return(UNDEF);
	}
}

/* return 0 (no move), 1 (move) or 2 (dead) */
dog_move(mtmp, after) register struct monst *mtmp; {
register int nx,ny,omx,omy,appr,nearer,j;
int udist,chi,i,whappr;
register struct monst *mtmp2;
register struct permonst *mdat = mtmp->data;
register struct edog *edog = EDOG(mtmp);
struct obj *obj;
struct gen *trap;
xchar cnt,chcnt,nix,niy;
schar dogroom,uroom;
xchar gx,gy,gtyp,otyp;	/* current goal */
coord poss[9];
int info[9];
#define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
#define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))

	if(moves <= edog->eattime) return(0);	/* dog is still eating */
	omx = mtmp->mx;
	omy = mtmp->my;
	whappr = (moves - EDOG(mtmp)->whistletime < 5);
	if(moves > edog->hungrytime + 500 && !mtmp->mconf){
		mtmp->mconf = 1;
		mtmp->orig_hp /= 3;
		if(mtmp->mhp > mtmp->orig_hp)
			mtmp->mhp = mtmp->orig_hp;
		if(cansee(omx,omy))
			pline("%s is confused from hunger", Monnam(mtmp));
		else	pline("You feel worried about your %s.", monnam(mtmp));
	} else
	if(moves > edog->hungrytime + 750 || mtmp->mhp < 1){
		if(cansee(omx,omy))
			pline("%s dies from hunger", Monnam(mtmp));
		else
		pline("You have a sad feeling for a moment, then it passes");
		mondied(mtmp);
		return(2);
	}
	dogroom = inroom(omx,omy);
	uroom = inroom(u.ux,u.uy);
	udist = dist(omx,omy);

	/* if we are carrying sth then we drop it (perhaps near @) */
	/* Note: if apport == 1 then our behaviour is independent of udist */
	if(mtmp->minvent){
		if(!rn2(udist) || !rn2((int) edog->apport))
		if(rn2(10) < edog->apport){
			relobj(mtmp,0);
			if(edog->apport > 1) edog->apport--;
		}
	} else {
		if(obj = o_at(omx,omy)) if(!index("0_", obj->olet)){
		    if((otyp = dogfood(obj)) <= CADAVER){
			nix = omx;
			niy = omy;
			goto eatobj;
		    }
		    if(obj->owt < 10*mtmp->data->mlevel)
		    if(rn2(20) < edog->apport+3)
		    if(rn2(udist) || !rn2((int) edog->apport)){
			freeobj(obj);
			unpobj(obj);
			/* if(levl[omx][omy].scrsym == obj->olet)
				newsym(omx,omy); */
			mpickobj(mtmp,obj);
		    }
		}
	}

	/* first we look for food */
	gtyp = UNDEF;	/* no goal as yet */
#ifdef LINT
	gx = gy = 0;
#endif LINT
	for(obj = fobj; obj; obj = obj->nobj) {
		otyp = dogfood(obj);
		if(otyp > gtyp || otyp == UNDEF) continue;
		if(inroom(obj->ox,obj->oy) != dogroom) continue;
		if(otyp < MANFOOD &&
		 (dogroom >= 0 || DDIST(obj->ox,obj->oy) < 10)) {
			if(otyp < gtyp || (otyp == gtyp &&
				DDIST(obj->ox,obj->oy) < DDIST(gx,gy))){
				gx = obj->ox;
				gy = obj->oy;
				gtyp = otyp;
			}
		} else
		if(gtyp == UNDEF && dogroom >= 0 &&
		   uroom == dogroom &&
		   !mtmp->minvent && edog->apport > rn2(8)){
			gx = obj->ox;
			gy = obj->oy;
			gtyp = APPORT;
		}
	}
	if(gtyp == UNDEF ||
	  (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)){
		if(dogroom < 0 || dogroom == uroom){
			gx = u.ux;
			gy = u.uy;
#ifndef QUEST
		} else {
			int tmp = rooms[dogroom].fdoor;
			    cnt = rooms[dogroom].doorct;

			gx = gy = FAR;	/* random, far away */
			while(cnt--){
			    if(dist(gx,gy) >
				dist(doors[tmp].x, doors[tmp].y)){
					gx = doors[tmp].x;
					gy = doors[tmp].y;
				}
				tmp++;
			}
			/* here gx == FAR e.g. when dog is in a vault */
			if(gx == FAR || (gx == omx && gy == omy)){
				gx = u.ux;
				gy = u.uy;
			}
#endif QUEST
		}
		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
		if(after && udist <= 4 && gx == u.ux && gy == u.uy)
			return(0);
		if(udist > 1){
			if(levl[u.ux][u.uy].typ < ROOM || !rn2(4) ||
			   whappr ||
			   (mtmp->minvent && rn2((int) edog->apport)))
				appr = 1;
		}
		/* if you have dog food he'll follow you more closely */
		if(appr == 0){
			obj = invent;
			while(obj){
				if(obj->otyp == TRIPE_RATION){
					appr = 1;
					break;
				}
				obj = obj->nobj;
			}
		}
	} else	appr = 1;	/* gtyp != UNDEF */
	if(mtmp->mconf) appr = 0;
#ifdef TRACK
	if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)){
	extern coord *gettrack();
	register coord *cp;
		cp = gettrack(omx,omy);
		if(cp){
			gx = cp->x;
			gy = cp->y;
		}
	}
#endif TRACK
	nix = omx;
	niy = omy;
	cnt = mfndpos(mtmp,poss,info,ALLOW_M | ALLOW_TRAPS);
	chcnt = 0;
	chi = -1;
	for(i=0; i<cnt; i++){
		nx = poss[i].x;
		ny = poss[i].y;
		if(info[i] & ALLOW_M){
			mtmp2 = m_at(nx,ny);
			if(mtmp2->data->mlevel >= mdat->mlevel+2 ||
			  mtmp2->data->mlet == 'c')
				continue;
			if(after) return(0); /* hit only once each move */

			if(hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
			  mtmp2->mlstmv != moves &&
			  hitmm(mtmp2,mtmp) == 2) return(2);
			return(0);
		}

		/* dog avoids traps */
		/* but perhaps we have to pass a trap in order to follow @ */
		if((info[i] & ALLOW_TRAPS) && (trap = g_at(nx,ny,ftrap))){
			if(!(trap->gflag & SEEN) && rn2(40)) continue;
			if(rn2(10)) continue;
		}

		/* dog eschewes cursed objects */
		/* but likes dog food */
		obj = fobj;
		while(obj){
		    if(obj->ox != nx || obj->oy != ny)
			goto nextobj;
		    if(obj->cursed) goto nxti;
		    if(obj->olet == FOOD_SYM &&
			(otyp = dogfood(obj)) < MANFOOD &&
			(otyp < ACCFOOD || edog->hungrytime <= moves)){
			/* Note: our dog likes the food so much that he
			might eat it even when it conceals a cursed object */
			nix = nx;
			niy = ny;
			chi = i;
		     eatobj:
			edog->eattime = moves + objects[obj->otyp].oc_delay;
			edog->hungrytime =
				moves + 5*objects[obj->otyp].nutrition;
			mtmp->mconf = 0;
			if(cansee(nix,niy))
				pline("%s ate %s.", Monnam(mtmp), doname(obj));
			/* perhaps this was a reward */
			if(otyp != CADAVER)
			edog->apport += 200/(edog->dropdist+moves-edog->droptime);
			delobj(obj);
			goto newdogpos;
		    }
		nextobj:
		    obj = obj->nobj;
		}

		for(j=0; j<MTSZ && j<cnt-1; j++)
			if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
				if(rn2(4*(cnt-j))) goto nxti;

/* Some stupid C compilers cannot compute the whole expression at once. */
		nearer = GDIST(nx,ny);
		nearer -= GDIST(nix,niy);
		nearer *= appr;
		if((nearer == 0 && !rn2(++chcnt)) || nearer<0 ||
			(nearer > 0 && !whappr &&
				((omx == nix && omy == niy && !rn2(3))
				|| !rn2(12))
			)){
			nix = nx;
			niy = ny;
			if(nearer < 0) chcnt = 0;
			chi = i;
		}
	nxti:	;
	}
newdogpos:
	if(nix != omx || niy != omy){
		if(info[chi] & ALLOW_U){
			(void) hitu(mtmp, d(mdat->damn, mdat->damd)+1);
			return(0);
		}
		mtmp->mx = nix;
		mtmp->my = niy;
		for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
		mtmp->mtrack[0].x = omx;
		mtmp->mtrack[0].y = omy;
	}
	if(mintrap(mtmp) == 2)	/* he died */
		return(2);
	pmon(mtmp);
	return(1);
}

/* return roomnumber or -1 */
inroom(x,y) xchar x,y; {
#ifndef QUEST
	register struct mkroom *croom = &rooms[0];
	while(croom->hx >= 0){
		if(croom->hx >= x-1 && croom->lx <= x+1 &&
		   croom->hy >= y-1 && croom->ly <= y+1)
			return(croom - rooms);
		croom++;
	}
#endif QUEST
	return(-1);	/* not in room or on door */
}

tamedog(mtmp, obj)
register struct monst *mtmp;
register struct obj *obj;
{
register struct monst *mtmp2;
	if(mtmp->mtame ||
#ifndef NOWORM
		mtmp->wormno ||
#endif NOWORM
		mtmp->isshk || mtmp->isgd)
		return(0); /* no tame long worms? */
	if(obj) {
		if(dogfood(obj) >= MANFOOD) return(0);
		if(cansee(mtmp->mx,mtmp->my)){
			pline("%s devours the %s.", Monnam(mtmp),
				objects[obj->otyp].oc_name);
		}
		obfree(obj, (struct obj *) 0);
	}
	mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
	*mtmp2 = *mtmp;
	mtmp2->mxlth = sizeof(struct edog);
	if(mtmp->mnamelth) (void) strcpy(NAME(mtmp2), NAME(mtmp));
	initedog(mtmp2);
	replmon(mtmp,mtmp2);
	return(1);
}
//E*O*F hack.dog.c//

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

#include	"hack.h"
char POISONOUS[] = "ADKSVabhks";
extern char *nomovemsg;
extern int (*afternmv)();

/* hunger texts used on bottom line (each 8 chars long) */
#define	SATIATED	0
#define NOT_HUNGRY	1
#define	HUNGRY		2
#define	WEAK		3
#define	FAINTING	4

char *hu_stat[5] = {
	"Satiated",
	"        ",
	"Hungry  ",
	"Weak    ",
	"Fainting"
};

init_uhunger(){
	u.uhunger = 900;
	u.uhs = NOT_HUNGRY;
}

struct { char *txt; int nut; } tintxts[] = {
	"It contains first quality peaches - what a surprise!",	40,
	"It contains salmon - not bad!",	60,
	"It contains apple juice - perhaps not what you hoped for.", 20,
	"It contains some nondescript substance, tasting awfully.", 500,
	"It contains rotten meat. You vomit.", -50,
	"It turns out to be empty.",	0
};

tinopen(){
#define	TTSZ	(sizeof(tintxts)/sizeof(tintxts[0]))
register int r = rn2(2*TTSZ);
	if(r < TTSZ){
	    pline(tintxts[r].txt);
	    lesshungry(tintxts[r].nut);
	    if(r == 1)	/* SALMON */ {
		Glib = rnd(15);
		pline("Eating salmon made your fingers very slippery.");
	    }
	} else {
	    pline("It contains spinach - this makes you feel like Popeye!");
	    lesshungry(600);
	    if(u.ustr < 118)
		u.ustr += rnd( ((u.ustr < 17) ? 19 : 118) - u.ustr);
	    if(u.ustr > u.ustrmax) u.ustrmax = u.ustr;
	    flags.botl = 1;
	}
}

Meatdone(){
	u.usym = '@';
	prme();
}

doeat(){
	register struct obj *otmp;
	register struct objclass *ftmp;
	register tmp;

	otmp = getobj("%", "eat");
	if(!otmp) return(0);
	if(otmp->otyp == TIN){
		if(uwep && (uwep->otyp == AXE || uwep->otyp == DAGGER ||
			    uwep->otyp == CRYSKNIFE)){
			pline("Using your %s you try to open the tin",
				aobjnam(uwep, (char *) 0));
			tmp = 3;
		} else {
			pline("It is not so easy to open this tin.");
			if(Glib) {
				pline("The tin slips out of your hands.");
				dropx(otmp);
				return(1);
			}
			tmp = 2 + rn2(1 + 500/((int)(u.ulevel + u.ustr)));
		}
		if(tmp > 50){
			nomul(-50);
			nomovemsg="You give up your attempt to open the tin.";
		} else {
			nomul(-tmp);
			nomovemsg = "You succeed in opening the tin.";
			afternmv = tinopen;
			useup(otmp);
		}
		return(1);
	}
	ftmp = &objects[otmp->otyp];
	if(otmp->otyp >= CORPSE && eatcorpse(otmp)) goto eatx;
	if(!rn2(7) && otmp->otyp != FORTUNE_COOKIE) {
		pline("Blecch!  Rotten food!");
		if(!rn2(4)) {
			pline("You feel rather light headed.");
			Confusion += d(2,4);
		} else if(!rn2(4)&& !Blind) {
			pline("Everything suddenly goes dark.");
			Blind = d(2,10);
			seeoff(0);
		} else if(!rn2(3)) {
			if(Blind)
			  pline("The world spins and you slap against the floor.");
			else
			  pline("The world spins and goes dark.");
			nomul(-rnd(10));
			nomovemsg = "You are conscious again.";
		}
		lesshungry(ftmp->nutrition / 4);
	} else {
		multi = -ftmp->oc_delay;
		if(u.uhunger >= 1500) {
			pline("You choke over your food.");
			pline("You die...");
			killer = ftmp->oc_name;
			done("choked");
		}
		switch(otmp->otyp){
		case FOOD_RATION:
			if(u.uhunger <= 200)
				pline("That food really hit the spot!");
			else if(u.uhunger <= 700)
				pline("That satiated your stomach!");
			else {
		pline("You're having a hard time getting all that food down.");
				multi -= 2;
			}
			lesshungry(ftmp->nutrition);
			if(multi < 0) nomovemsg = "You finished your meal.";
			break;
		case TRIPE_RATION:
			pline("Yak - dog food!");
			u.uexp++;
			u.urexp += 4;
			flags.botl = 1;
			if(rn2(2)){
				pline("You vomit.");
				lesshungry(-20);
			} else	lesshungry(ftmp->nutrition);
			break;
		default:
			if(otmp->otyp >= CORPSE)
			pline("That %s tasted terrible!",ftmp->oc_name);
			else
			pline("That %s was delicious!",ftmp->oc_name);
			lesshungry(ftmp->nutrition);
#ifdef QUEST
			if(otmp->otyp == CARROT && !Blind){
				u.uhorizon++;
				setsee();
				pline("Your vision improves.");
			}
#endif QUEST
			if(otmp->otyp == FORTUNE_COOKIE) {
			  if(Blind) {
			    pline("This cookie has a scrap of paper inside!");
			    pline("What a pity, that you cannot read it!");
			  } else
			    outrumor();
			}
			break;
		}
	}
eatx:
	if(multi<0 && !nomovemsg){
		static char msgbuf[BUFSZ];
		(void) sprintf(msgbuf, "You finished eating the %s.",
				ftmp->oc_name);
		nomovemsg = msgbuf;
	}
	useup(otmp);
	return(1);
}

lesshungry(num) register num; {
/* called after eating something (and after drinking fruit juice) */
	register int newhunger;

	newhunger = u.uhunger + num;
	if(u.uhunger <= 1000 && newhunger > 1000) {
		flags.botl = 1;
		u.uhs = SATIATED;
	} else if(u.uhunger <= 150 && newhunger > 150) {
		if(u.uhunger <= 50 && u.ustr < u.ustrmax) losestr(-1);
		flags.botl = 1;
		u.uhs = NOT_HUNGRY;
	} else if(u.uhunger <= 50 && newhunger > 50) {
		pline("You only feel hungry now.");
		if(u.ustr < u.ustrmax) losestr(-1);
		flags.botl = 1;
		u.uhs = HUNGRY;
	} else if(u.uhunger <= 0 && newhunger < 50) {
		pline("You feel weak now.");
		flags.botl = 1;
		u.uhs = WEAK;
	}
	u.uhunger = newhunger;
}

/* called in hack.main.c */
gethungry(){
	--u.uhunger;
	if((Regeneration || Hunger) && moves%2) u.uhunger--;
	if(u.uhunger <= 1000 && u.uhs == SATIATED) {
		u.uhs = NOT_HUNGRY;
		flags.botl = 1;
	} else if(u.uhunger <= 150 && u.uhs == NOT_HUNGRY) {
		pline("You are beginning to feel hungry.");
		u.uhs = HUNGRY;
		flags.botl = 1;
	} else if(u.uhunger <= 50 && u.uhs == HUNGRY) {
		pline("You are beginning to feel weak.");
		u.uhs = WEAK;
		losestr(1);
		flags.botl = 1;
	} else if(u.uhunger < 1 &&
		(u.uhs == WEAK || rn2(20-u.uhunger/10) >= 19)) {
		if(multi >= 0)	/* not fainted already */ {
			pline("You faint from lack of food.");
			nomul(-10+(u.uhunger/10));
		}
		if(u.uhs != FAINTING) {
			u.uhs = FAINTING;
			flags.botl = 1;
		}
	} else if(u.uhunger < -(int)(200 + 25*u.ulevel)) {
		pline("You die from starvation.");
		done("starved");
	}
}

/* returns 1 if some text was printed */
eatcorpse(otmp) register struct obj *otmp; {
register schar let = otmp->spe;
register tp = 0;
	if(moves > otmp->age + 50 + rn2(100)) {
		tp++;
		pline("Ulch -- that meat was tainted!");
		pline("You get very sick.");
		Sick = 10 + rn2(10);
		u.usick_cause = objects[otmp->otyp].oc_name;
	} else if(index(POISONOUS, let) && rn2(5)){
		tp++;
		pline("Ecch -- that must have been poisonous!");
		if(!Poison_resistance){
			losehp(rnd(15), "poisonous corpse");
			losestr(rnd(4));
		} else
			pline("You don't seem affected by the poison.");
	} else if(index("ELNOPQRUuxz", let) && rn2(5)){
		tp++;
		pline("You feel sick.");
		losehp(rnd(8), "cadaver");
	}
	switch(let) {
	case 'L':
	case 'N':
	case 't':
		Teleportation |= INTRINSIC;
		break;
	case 'W':
		pluslvl();
		break;
	case 'n':
		u.uhp = u.uhpmax;
		flags.botl = 1;
		/* fall into next case */
	case '@':
		pline("You cannibal! You will be sorry for this!");
		/* not tp++; */
		/* fall into next case */
	case 'd':
		Aggravate_monster |= INTRINSIC;
		break;
	case 'I':
		See_invisible |= INTRINSIC;
		if(!Invis) newsym(u.ux, u.uy);
		Invis += 50;
		/* fall into next case */
	case 'y':
#ifdef QUEST
		u.uhorizon++;
#endif QUEST
		/* fall into next case */
	case 'B':
		Confusion = 50;
		break;
	case 'D':
		Fire_resistance |= INTRINSIC;
		break;
	case 'E':
		Telepat |= INTRINSIC;
		break;
	case 'F':
	case 'Y':
		Cold_resistance |= INTRINSIC;
		break;
	case 'k':
	case 's':
		Poison_resistance |= INTRINSIC;
		break;
	case 'c':
		pline("You turn to stone.");
		killer = "dead cockatrice";
		done("died");
	case 'M':
	  pline("You cannot resist the temptation to mimic a treasure chest.");
	  tp++;
	  nomul(-30);
	  afternmv = Meatdone;
	  nomovemsg = "You now again prefer mimicking a human.";
	  u.usym = '$';
	  prme();
	  break;
	}
	return(tp);
}
//E*O*F hack.eat.c//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 6 (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.end.c hack.engrave.c hack.fight.c

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

#include "hack.h"
#include <stdio.h>
#include <signal.h>
#define	Sprintf	(void) sprintf
extern char plname[], pl_character[];
extern char *itoa(), *ordin(), *eos(), *getlogin();

xchar maxdlevel = 1;

done1()
{
	(void) signal(SIGINT,SIG_IGN);
	pline("Really quit?");
	if(readchar() != 'y') {
		(void) signal(SIGINT,done1);
		clrlin();
		(void) fflush(stdout);
		if(multi > 0) nomul(0);
		return(0);
	}
	done("quit");
	/* NOTREACHED */
}

int done_stopprint;

done_intr(){
	done_stopprint++;
	(void) signal(SIGINT,SIG_IGN);
}

done_in_by(mtmp) register struct monst *mtmp; {
static char buf[BUFSZ];
	pline("You die ...");
	if(mtmp->data->mlet == ' '){
		Sprintf(buf, "the ghost of %s", (char *) mtmp->mextra);
		killer = buf;
	} else if(mtmp->mnamelth) {
		Sprintf(buf, "%s called %s",
			mtmp->data->mname, NAME(mtmp));
		killer = buf;
	} else if(mtmp->minvis) {
		Sprintf(buf, "invisible %s", mtmp->data->mname);
		killer = buf;
	} else killer = mtmp->data->mname;
	done("died");
}

/* called with arg "died", "escaped", "quit", "choked", "panic"
   or "starved" */
/* Be careful not to call panic from here! */
done(st1)
register char *st1;
{

#ifdef WIZARD
	if(wizard && *st1 == 'd'){
		u.ustr = u.ustrmax += 2;
		u.uhp = u.uhpmax += 10;
		if(uarm) uarm->spe++;
		if(uwep) uwep->spe++; /* NB: uwep need not be a weapon! */
		u.uswldtim = 0;
		pline("For some reason you are still alive.");
		flags.move = 0;
		if(multi > 0) multi = 0; else multi = -1;
		flags.botl = 1;
		return;
	}
#endif WIZARD
	(void) signal(SIGINT, done_intr);
	if(*st1 == 'q' && u.uhp < 1){
		st1 = "died";
		killer = "quit while already on Charon's boat";
	}
	if(*st1 == 's') killer = "starvation";
	paybill();
	clearlocks();
	if(index("cds", *st1)){
		savebones();
		outrip();
	}
	settty((char *) 0);	/* does a cls() */
	if(!done_stopprint)
		printf("Goodbye %s %s...\n\n", pl_character, plname);
	{ long int tmp;
	tmp = u.ugold - u.ugold0;
	if(tmp < 0) tmp = 0;
	if(*st1 == 'd') tmp -= tmp/10;
	else killer = st1;
	u.urexp += tmp;
	}
	if(*st1 == 'e') {
		extern struct monst *mydogs;
		register struct monst *mtmp = mydogs;
		register struct obj *otmp;
		register int i;
		register unsigned worthlessct = 0;

		u.urexp += 50 * maxdlevel;
		if(mtmp) {
			if(!done_stopprint) printf("You");
			while(mtmp) {
				if(!done_stopprint)
					printf(" and %s", monnam(mtmp));
				u.urexp += mtmp->mhp;
				mtmp = mtmp->nmon;
			}
			if(!done_stopprint)
		    printf("\nescaped from the dungeon with %lu points,\n",
			u.urexp);
		} else
		if(!done_stopprint)
		  printf("You escaped from the dungeon with %lu points,\n",
		    u.urexp);
		for(otmp = invent; otmp; otmp = otmp->nobj) {
			if(otmp->olet == GEM_SYM){
				objects[otmp->otyp].oc_name_known = 1;
				i = otmp->quan*objects[otmp->otyp].g_val;
				if(i == 0) {
					worthlessct += otmp->quan;
					continue;
				}
				u.urexp += i;
				if(!done_stopprint)
				  printf("\t%s (worth %d Zorkmids),\n",
				    doname(otmp), i);
			} else if(otmp->olet == AMULET_SYM) {
				otmp->known = 1;
				i = (otmp->spe < 0) ? 2 : 5000;
				u.urexp += i;
				if(!done_stopprint)
				  printf("\t%s (worth %d Zorkmids),\n",
				    doname(otmp), i);
				if(otmp->spe >= 0) u.urexp *= 2;
			}
		}
		if(worthlessct) if(!done_stopprint)
		  printf("\t%d worthless piece%s of coloured glass,\n",
		  worthlessct, plur(worthlessct));
		killer=st1;
	} else
		if(!done_stopprint)
		  printf("You %s on dungeon level %d with %lu points,\n",
		    st1,dlevel,u.urexp);
	if(!done_stopprint)
	  printf("and %lu piece%s of gold, after %lu move%s.\n",
	    u.ugold, (u.ugold == 1) ? "" : "s",
	    moves, (moves == 1) ? "" : "s");
	if(!done_stopprint)
  printf("You were level %d with a maximum of %d hit points when you %s.\n",
	    u.ulevel, u.uhpmax, st1);
	if(*st1 == 'e'){
		getret();	/* all those pieces of coloured glass ... */
		cls();
	}
#ifdef WIZARD
	if(!wizard)
#endif WIZARD
		topten();
	if(done_stopprint) printf("\n\n");
	exit(0);
}

#define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
#define	NAMSZ	8
#define	DTHSZ	40
#define	PERSMAX	1
#define	POINTSMIN	1	/* must be > 0 */
#define	ENTRYMAX	100	/* must be >= 10 */
struct toptenentry {
	struct toptenentry *tt_next;
	long int points;
	int level,maxlvl,hp,maxhp;
	char plchar;
	char str[NAMSZ+1];
	char death[DTHSZ+1];
} *tt_head;

topten(){
	int rank, rank0 = -1, rank1 = 0;
	int occ_cnt = PERSMAX;
	register struct toptenentry *t0, *t1, *tprev;
	char *recfile = "record";
	FILE *rfile;
	register flg = 0;

	if(!(rfile = fopen(recfile,"r"))){
		puts("Cannot open record file!");
		return;
	}
	(void) putchar('\n');

	/* create a new 'topten' entry */
	t0 = newttentry();
	t0->level = dlevel;
	t0->maxlvl = maxdlevel;
	t0->hp = u.uhp;
	t0->maxhp = u.uhpmax;
	t0->points = u.urexp;
	t0->plchar = pl_character[0];
	(void) strncpy(t0->str, plname, NAMSZ);
	(t0->str)[NAMSZ] = 0;
	(void) strncpy(t0->death, killer, DTHSZ);
	(t0->death)[DTHSZ] = 0;

	/* assure minimum number of points */
	if(t0->points < POINTSMIN)
		t0->points = 0;

	t1 = tt_head = newttentry();
	tprev = 0;
	/* rank0: -1 undefined, 0 not_on_list, n n_th on list */
	for(rank = 1; ; ) {
	  if(fscanf(rfile, "%d %d %d %d %ld %c %[^,],%[^\n]",
		&t1->level, &t1->maxlvl,
		&t1->hp, &t1->maxhp, &t1->points,
		&t1->plchar, t1->str, t1->death) != 8
	  || t1->points < POINTSMIN)
			t1->points = 0;
	  if(rank0 < 0 && t1->points < t0->points) {
		rank0 = rank++;
		if(tprev == 0)
			tt_head = t0;
		else
			tprev->tt_next = t0;
		t0->tt_next = t1;
		occ_cnt--;
		flg++;		/* ask for a rewrite */
	  } else
		tprev = t1;
	  if(t1->points == 0) break;
	  if(strncmp(t1->str, t0->str, NAMSZ) == 0 &&
	     t1->plchar == t0->plchar && --occ_cnt <= 0){
		if(rank0 < 0){
			rank0 = 0;
			rank1 = rank;
	printf("You didn't beat your previous score of %ld points.\n\n",
				t1->points);
		}
		if(occ_cnt < 0){
			flg++;
			continue;
		}
	  }
	  if(rank <= ENTRYMAX){
	  	t1 = t1->tt_next = newttentry();
	  	rank++;
	  }
	  if(rank > ENTRYMAX){
		t1->points = 0;
		break;
	  }
	}
	if(flg) {	/* rewrite record file */
		(void) fclose(rfile);
		if(!(rfile=fopen(recfile,"w"))){
			puts("Cannot write record file\n");
			return;
		}

		if(!done_stopprint) if(rank0 > 0){
		    if(rank0 <= 10)
			puts("You made the top ten list!\n");
		    else
		printf("You reached the %d%s place on the top %d list.\n\n",
			rank0, ordin(rank0), ENTRYMAX);
		}
	}
	if(rank0 == 0) rank0 = rank1;
	if(rank0 <= 0) rank0 = rank;
	if(!done_stopprint) outheader();
	t1 = tt_head;
	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
	  if(flg) fprintf(rfile,"%d %d %d %d %ld %c %s,%s\n",
	    t1->level, t1->maxlvl,
	    t1->hp, t1->maxhp, t1->points,
	    t1->plchar,t1->str,t1->death);
	  if(done_stopprint) continue;
	  if(rank > 5 && (rank < rank0 - 4 || rank > rank0 + 4))
	      continue;
	  if(rank == rank0 - 4 && rank0 > 10) (void) putchar('\n');
	  if(rank != rank0)
		(void) outentry(rank, t1, 0);
	  else if(!rank1)
		(void) outentry(rank, t1, 1);
	  else {
		int t0lth = outentry(0, t0, -1);
		int t1lth = outentry(rank, t1, t0lth);
		if(t1lth > t0lth) t0lth = t1lth;
		(void) outentry(0, t0, t0lth);
	  }
	}
	if(rank0 >= rank)
		(void) outentry(0, t0, 1);
	(void) fclose(rfile);
}

outheader() {
char linebuf[BUFSZ];
register char *bp;
	(void) strcpy(linebuf, "Number Points  Name");
	bp = eos(linebuf);
	while(bp < linebuf + COLNO - 9) *bp++ = ' ';
	(void) strcpy(bp, "Hp [max]");
	puts(linebuf);
}

/* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
int
outentry(rank,t1,so) register struct toptenentry *t1; {
boolean quit = FALSE, killed = FALSE, starv = FALSE;
char linebuf[BUFSZ];
	linebuf[0] = 0;
	if(rank) Sprintf(eos(linebuf), "%3d", rank);
		else Sprintf(eos(linebuf), "   ");
	Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->str);
	if(t1->plchar == 'X') Sprintf(eos(linebuf), " ");
	else Sprintf(eos(linebuf), "-%c ", t1->plchar);
	if(!strcmp("escaped", t1->death))
	  Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
	    t1->maxlvl);
	else {
	  if(!strncmp(t1->death,"quit",4))
	    Sprintf(eos(linebuf), "quit"), quit = TRUE;
	  else if(!strcmp(t1->death,"choked"))
	    Sprintf(eos(linebuf), "choked in his food");
	  else if(!strncmp(t1->death,"starv",5))
	    Sprintf(eos(linebuf), "starved to death"), starv = TRUE;
	  else Sprintf(eos(linebuf), "was killed"), killed = TRUE;
	  Sprintf(eos(linebuf), " on%s level %d",
	    (killed || starv) ? "" : " dungeon", t1->level);
	  if(t1->maxlvl != t1->level)
	    Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
	  if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4);
	}
	if(killed) Sprintf(eos(linebuf), " by %s%s",
	  !strncmp(t1->death, "the ", 4) ? "" :
	  index(vowels,*t1->death) ? "an " : "a ",
	  t1->death);
	Sprintf(eos(linebuf), ".");
	if(t1->maxhp) {
	  register char *bp = eos(linebuf);
	  char hpbuf[10];
	  int hppos;
	  Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-");
	  hppos = COLNO - 7 - strlen(hpbuf);
	  if(bp <= linebuf + hppos) {
	    while(bp < linebuf + hppos) *bp++ = ' ';
	    (void) strcpy(bp, hpbuf);
	    Sprintf(eos(bp), " [%d]", t1->maxhp);
	  }
	}
	if(so == 0) puts(linebuf);
	else if(so > 0) {
	  register char *bp = eos(linebuf);
	  if(so >= COLNO) so = COLNO-1;
	  while(bp < linebuf + so) *bp++ = ' ';
	  *bp = 0;
	  standoutbeg();
	  fputs(linebuf,stdout);
	  standoutend();
	  (void) putchar('\n');
	}
	return(strlen(linebuf));
}

char *
itoa(a) int a; {
static char buf[12];
	Sprintf(buf,"%d",a);
	return(buf);
}

char *
ordin(n) int n; {
register int d = n%10;
	return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :
		(d==2) ? "nd" : "rd");
}

clearlocks(){
register x;
	(void) signal(SIGHUP,SIG_IGN);
	for(x = 1; x <= maxdlevel; x++) {
		glo(x);
		(void) unlink(lock);	/* not all levels need be present */
	}
	(*index(lock,'.')) = 0;
	(void) unlink(lock);
}

#ifdef NOSAVEONHANGUP
hangup(){
	(void) signal(SIGINT,SIG_IGN);
	clearlocks();
	exit(1);
}
#endif NOSAVEONHANGUP

char *
eos(s) register char *s; {
	while(*s) s++;
	return(s);
}

/* it is the callers responsibility to check that there is room for c */
charcat(s,c) register char *s, c; {
	while(*s) s++;
	*s++ = c;
	*s = 0;
}

prscore(argc,argv) int argc; char **argv; {
	extern char *hname;
	char *player0;
	char **players;
	int playerct;
	int rank;
	register struct toptenentry *t1;
	char *recfile = "record";
	FILE *rfile;
	register flg = 0;
	register int i;

	if(!(rfile = fopen(recfile,"r"))){
		puts("Cannot open record file!");
		return;
	}

	if(argc > 1 && !strncmp(argv[1], "-s", 2)){
		if(!argv[1][2]){
			argc--;
			argv++;
		} else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) {
			argv[1]++;
			argv[1][0] = '-';
		} else	argv[1] += 2;
	}
	if(argc <= 1){
		player0 = getlogin();
		if(!player0) player0 = "player";
		playerct = 1;
		players = &player0;
	} else {
		playerct = --argc;
		players = ++argv;
	}
	putchar('\n');

	t1 = tt_head = newttentry();
	for(rank = 1; ; rank++) {
	  if(fscanf(rfile, "%d %d %d %d %ld %c %[^,],%[^\n]",
		&t1->level, &t1->maxlvl,
		&t1->hp, &t1->maxhp, &t1->points,
		&t1->plchar, t1->str, t1->death) != 8)
			t1->points = 0;
	  if(t1->points == 0) break;
	  for(i = 0; i < playerct; i++){
		if(strcmp(players[i], "all") == 0 ||
		   strncmp(t1->str, players[i], NAMSZ) == 0 ||
		  (players[i][0] == '-' &&
		   players[i][1] == t1->plchar &&
		   players[i][2] == 0) ||
		  (digit(players[i][0]) && rank <= atoi(players[i])))
			flg++;
	  }
	  t1 = t1->tt_next = newttentry();
	}
	(void) fclose(rfile);
	if(!flg) {
		printf("Cannot find any entries for ");
		if(playerct > 1) printf("any of ");
		for(i=0; i<playerct; i++)
			printf("%s%s", players[i], (i<playerct-1)?", ":".\n");
		printf("Call is: %s -s [playernames]\n", hname);
		return;
	}

	outheader();
	t1 = tt_head;
	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
		for(i = 0; i < playerct; i++){
			if(strcmp(players[i], "all") == 0 ||
			   strncmp(t1->str, players[i], NAMSZ) == 0 ||
			  (players[i][0] == '-' &&
			   players[i][1] == t1->plchar &&
			   players[i][2] == 0) ||
			  (digit(players[i][0]) && rank <= atoi(players[i])))
				goto out;
		}
		continue;
	out:
	  (void) outentry(rank, t1, 0);
	}
}
//E*O*F hack.end.c//

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

#include	"hack.h"
extern char *nomovemsg;
extern char nul[];
struct engr {
	struct engr *nxt_engr;
	char *engr_txt;
	xchar engr_x, engr_y;
	unsigned engr_lth;	/* for save & restore; not length of text */
	long engr_time;	/* moment engraving was (will be) finished */
	xchar engr_type;
#define	DUST	1
#define	ENGRAVE	2
#define	BURN	3
} *head_engr;

struct engr *
engr_at(x,y) register xchar x,y; {
register struct engr *ep = head_engr;
	while(ep) {
		if(x == ep->engr_x && y == ep->engr_y)
			return(ep);
		ep = ep->nxt_engr;
	}
	return((struct engr *) 0);
}

sengr_at(s,x,y) register char *s; register xchar x,y; {
register struct engr *ep = engr_at(x,y);
register char *t;
register int n;
	if(ep && ep->engr_time <= moves) {
		t = ep->engr_txt;
/*
		if(!strcmp(s,t)) return(1);
*/
		n = strlen(s);
		while(*t) {
			if(!strncmp(s,t,n)) return(1);
			t++;
		}
	}
	return(0);
}

wipe_engr_at(x,y,cnt) register xchar x,y,cnt; {
register struct engr *ep = engr_at(x,y);
register int lth,pos;
char ch;
	if(ep){
		if(ep->engr_type != DUST) {
			cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
		}
		lth = strlen(ep->engr_txt);
		if(lth && cnt > 0 ) {
			while(cnt--) {
				pos = rn2(lth);
				if((ch = ep->engr_txt[pos]) == ' ')
					continue;
				ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
			}
		}
		while(lth && ep->engr_txt[lth-1] == ' ')
			ep->engr_txt[--lth] = 0;
		while(ep->engr_txt[0] == ' ')
			ep->engr_txt++;
		if(!ep->engr_txt[0]) del_engr(ep);
	}
}

read_engr_at(x,y) register int x,y; {
register struct engr *ep = engr_at(x,y);
	if(ep && ep->engr_txt[0]) {
	    switch(ep->engr_type) {
	    case DUST:
		pline("Something is written here in the dust.");
		break;
	    case ENGRAVE:
		pline("Something is engraved here on the floor.");
		break;
	    case BURN:
		pline("Some text has been burned here in the floor.");
		break;
	    default:
		pline("Something is written in a very strange way.");
		impossible();
	    }
	    pline("You read: \"%s\".", ep->engr_txt);
	}
}

doengrave(){
register int len;
register char *sp;
register struct engr *ep, *oep = engr_at(u.ux,u.uy);
char buf[BUFSZ];
xchar type;
int spct;		/* number of leading spaces */
register struct obj *otmp;
	multi = 0;

	/* one may write with finger, weapon or wand */
	otmp = getobj("#-)/", "write with");
	if(!otmp) return(0);
	if(otmp == (struct obj *)(-1))
		type = DUST;
	else if(otmp->otyp == WAN_FIRE && otmp->spe) {
		type = BURN;
		otmp->spe--;
	} else if(otmp->otyp == DAGGER || otmp->otyp == TWO_HANDED_SWORD ||
		otmp->otyp == CRYSKNIFE ||
		otmp->otyp == LONG_SWORD || otmp->otyp == AXE){
		type = ENGRAVE;
		if((int)otmp->spe <= -3) {
			type = DUST;
			pline("Your %s too dull for engraving.",
				aobjnam(otmp, "are"));
			if(oep && oep->engr_type != DUST) return(1);
		}
	} else	type = DUST;
	if(oep && oep->engr_type == DUST){
		  pline("You wipe out the message that was written here.");
		  del_engr(oep);
		  oep = 0;
	}
	if(type == DUST && oep){
	pline("You cannot wipe out the message that is %s in the rock.",
		    (oep->engr_type == BURN) ? "burned" : "engraved");
		  return(1);
	}

	pline("What do you want to %s on the floor here? ",
	  (type == ENGRAVE) ? "engrave" : (type == BURN) ? "burn" : "write");
	getlin(buf);
	clrlin();
	spct = 0;
	sp = buf;
	while(*sp == ' ') spct++, sp++;
	len = strlen(sp);
	if(!len) {
		if(type == BURN) otmp->spe++;
		return(0);
	}
	
	switch(type) {
	case DUST:
	case BURN:
		if(len > 15) {
			multi = -(len/10);
			nomovemsg = "You finished writing.";
		}
		break;
	case ENGRAVE:
		{	int len2 = (otmp->spe + 3) * 2 + 1;
			char *bufp = doname(otmp);
			if(digit(*bufp))
				pline("Your %s get dull.", bufp);
			else {
				if(!strncmp(bufp,"a ",2))
					bufp += 2;
				else if(!strncmp(bufp,"an ",3))
					bufp += 3;
				pline("Your %s gets dull.", bufp);
			}
			if(len2 < len) {
				len = len2;
				sp[len] = 0;
				otmp->spe = -3;
				nomovemsg = "You cannot engrave more.";
			} else {
				otmp->spe -= len/2;
				nomovemsg = "You finished engraving.";
			}
			multi = -len;
		}
		break;
	}
	if(oep) len += strlen(oep->engr_txt) + spct;
	ep = (struct engr *) alloc((unsigned)(sizeof(struct engr) + len + 1));
	ep->nxt_engr = head_engr;
	head_engr = ep;
	ep->engr_x = u.ux;
	ep->engr_y = u.uy;
	sp = (char *)(ep + 1);	/* (char *)ep + sizeof(struct engr) */
	ep->engr_txt = sp;
	if(oep) {
		(void) strcpy(sp, oep->engr_txt);
		(void) strcat(sp, buf);
		del_engr(oep);
	} else
		(void) strcpy(sp, buf);
	ep->engr_lth = len+1;
	ep->engr_type = type;
	ep->engr_time = moves-multi;

	/* kludge to protect pline against excessively long texts */
	if(len > BUFSZ-20) sp[BUFSZ-20] = 0;

	return(1);
}

save_engravings(fd) int fd; {
register struct engr *ep = head_engr;
	while(ep) {
		if(!ep->engr_lth || !ep->engr_txt[0]){
			ep = ep->nxt_engr;
			continue;
		}
		bwrite(fd, (char *) & (ep->engr_lth), sizeof(ep->engr_lth));
		bwrite(fd, (char *) ep, sizeof(struct engr) + ep->engr_lth);
		ep = ep->nxt_engr;
	}
	bwrite(fd, (char *) nul, sizeof(unsigned));
}

rest_engravings(fd) int fd; {
register struct engr *ep;
unsigned lth;
	head_engr = 0;
	while(1) {
		mread(fd, (char *) &lth, sizeof(unsigned));
		if(lth == 0) return;
		ep = (struct engr *) alloc(sizeof(struct engr) + lth);
		mread(fd, (char *) ep, sizeof(struct engr) + lth);
		ep->nxt_engr = head_engr;
		head_engr = ep;
	}
}

del_engr(ep) register struct engr *ep; {
register struct engr *ept;
	if(ep == head_engr)
		head_engr = ep->nxt_engr;
	else {
		for(ept = head_engr; ept; ept = ept->nxt_engr)
			if(ept->nxt_engr == ep) {
				ept->nxt_engr = ep->nxt_engr;
				goto fnd;
			}
		pline("Error in del_engr?"); impossible();
	fnd:	;
	}
	free((char *) ep);
}
//E*O*F hack.engrave.c//

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

#include	"hack.h"
extern struct permonst li_dog, dog, la_dog;
extern char *exclam(), *xname();

static boolean far_noise;
static long noisetime;

/* hitmm returns 0 (miss), 1 (hit), or 2 (kill) */
hitmm(magr,mdef) register struct monst *magr,*mdef; {
register struct permonst *pa = magr->data, *pd = mdef->data;
int hit;
schar tmp;
boolean vis;
	if(index("Eauy", pa->mlet)) return(0);
	tmp = pd->ac + pa->mlevel;
	if(mdef->mconf || mdef->mfroz || mdef->msleep){
		tmp += 4;
		if(mdef->msleep) mdef->msleep = 0;
	}
	hit = (tmp > rnd(20));
	if(hit) mdef->msleep = 0;
	vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my));
	if(vis){
		char buf[BUFSZ];
		if(mdef->mimic) seemimic(mdef);
		if(magr->mimic) seemimic(magr);
		(void) sprintf(buf,"%s %s", Monnam(magr),
			hit ? "hits" : "misses");
		pline("%s %s.", buf, monnam(mdef));
	} else {
		boolean far = (dist(magr->mx, magr->my) > 15);
		if(far != far_noise || moves-noisetime > 10) {
			far_noise = far;
			noisetime = moves;
			pline("You hear some noises%s.",
				far ? " in the distance" : "");
		}
	}
	if(hit){
		if(magr->data->mlet == 'c' && !magr->cham) {
			magr->orig_hp += 3;
			if(vis) pline("%s is turned to stone!", Monnam(mdef));
			else if(mdef->mtame)
     pline("You have a peculiarly sad feeling for a moment, then it passes.");
			monstone(mdef);
			hit = 2;
		} else
		if((mdef->mhp -= d(pa->damn,pa->damd)) < 1) {
			magr->orig_hp += 1 + rn2(pd->mlevel+1);
			if(magr->mtame && magr->orig_hp > 8*pa->mlevel){
				if(pa == &li_dog) magr->data = pa = &dog;
				else if(pa == &dog) magr->data = pa = &la_dog;
			}
			if(vis) pline("%s is killed!", Monnam(mdef));
			else if(mdef->mtame)
		pline("You have a sad feeling for a moment, then it passes.");
			mondied(mdef);
			hit = 2;
		}
	}
	return(hit);
}

/* drop (perhaps) a cadaver and remove monster */
mondied(mdef) register struct monst *mdef; {
register struct permonst *pd = mdef->data;
		if(letter(pd->mlet) && rn2(3)){
			mksobj_at(pd->mlet,CORPSE,mdef->mx,mdef->my);
			if(cansee(mdef->mx,mdef->my)){
				unpmon(mdef);
				atl(mdef->mx,mdef->my,fobj->olet);
			}
			stackobj(fobj);
		}
		mondead(mdef);
}

/* drop a rock and remove monster */
monstone(mdef) register struct monst *mdef; {
	extern char mlarge[];
	if(index(mlarge, mdef->data->mlet))
		mksobj_at(ROCK_SYM, ENORMOUS_ROCK, mdef->mx, mdef->my);
	else
		mksobj_at(WEAPON_SYM, ROCK, mdef->mx, mdef->my);
	if(cansee(mdef->mx, mdef->my)){
		unpmon(mdef);
		atl(mdef->mx,mdef->my,fobj->olet);
	}
	mondead(mdef);
}
		

fightm(mtmp) register struct monst *mtmp; {
register struct monst *mon;
	for(mon = fmon; mon; mon = mon->nmon) if(mon != mtmp) {
		if(DIST(mon->mx,mon->my,mtmp->mx,mtmp->my) < 3)
		    if(rn2(4))
			return(hitmm(mtmp,mon));
	}
	return(-1);
}

hitu(mtmp,dam)
register struct monst *mtmp;
register dam;
{
	register tmp;

	if(mtmp->mhide && mtmp->mundetected) {
		mtmp->mundetected = 0;
		if(!Blind) {
			register struct obj *obj;
			extern char * Xmonnam();
			if(obj = o_at(mtmp->mx,mtmp->my))
				pline("%s was hidden under %s!",
					Xmonnam(mtmp), doname(obj));
		}
	}

	tmp = u.uac;
	/* give people with Ac = -10 at least some vulnerability */
	if(tmp < 0) {
		dam += tmp;		/* decrease damage */
		if(dam <= 0) dam = 1;
		tmp = -rn2(-tmp);
	}
	tmp += mtmp->data->mlevel;
	if(multi < 0) tmp += 4;
	if(Invis || !mtmp->mcansee) tmp -= 2;
	if(mtmp->mtrapped) tmp -= 2;
	if(tmp <= rnd(20)) {
		if(Blind) pline("It misses.");
		else pline("%s misses.",Monnam(mtmp));
		return(0);
	}
	if(Blind) pline("It hits!");
	else pline("%s hits!",Monnam(mtmp));
	losehp_m(dam, mtmp);
	return(1);
}

/* u is hit by sth, but not a monster */
thitu(tlev,dam,name)
register tlev,dam;
register char *name;
{
char buf[BUFSZ];
	setan(name,buf);
	if(u.uac + tlev <= rnd(20)) {
		if(Blind) pline("It misses.");
		else pline("You are almost hit by %s!", buf);
		return(0);
	} else {
		if(Blind) pline("You are hit!");
		else pline("You are hit by %s!", buf);
		losehp(dam,name);
		return(1);
	}
}

char mlarge[] = "bCDdegIlmnoPSsTUwY~,&";

boolean
hmon(mon,obj,thrown)	/* return TRUE if mon still alive */
register struct monst *mon;
register struct obj *obj;
register thrown;
{
	register tmp;

	if(!obj){
		tmp = rnd(2);	/* attack with bare hands */
		if(mon->data->mlet == 'c' && !uarmg){
			pline("You hit the cockatrice with your bare hands");
			pline("You turn to stone ...");
			done_in_by(mon);
		}
	} else if(obj->olet == WEAPON_SYM) {
	    if(obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG))
		tmp = rnd(2);
	    else {
		if(index(mlarge, mon->data->mlet)) {
			tmp = rnd(objects[obj->otyp].wldam);
			if(obj->otyp == TWO_HANDED_SWORD) tmp += d(2,6);
			else if(obj->otyp == FLAIL) tmp += rnd(4);
		} else {
			tmp = rnd(objects[obj->otyp].wsdam);
		}
		tmp += obj->spe;
		if(!thrown && obj == uwep && obj->otyp == BOOMERANG
		 && !rn2(3)){
		  pline("As you hit %s, the boomerang breaks into splinters.",
				monnam(mon));
			freeinv(obj);
			setworn((struct obj *) 0, obj->owornmask);
			obfree(obj, (struct obj *) 0);
			tmp++;
		}
	    }
	    if(mon->data->mlet == 'O' && !strcmp(ONAME(obj), "Orcrist"))
		tmp += rnd(10);
	} else	switch(obj->otyp) {
		case HEAVY_IRON_BALL:
			tmp = rnd(25); break;
		case EXPENSIVE_CAMERA:
	pline("You succeed in destroying your camera. Congratulations!");
			freeinv(obj);
			if(obj->owornmask)
				setworn((struct obj *) 0, obj->owornmask);
			obfree(obj, (struct obj *) 0);
			return(TRUE);
		case DEAD_COCKATRICE:
			pline("You hit %s with the cockatrice corpse",
				monnam(mon));
			pline("%s is turned to stone!", Monnam(mon));
			killed(mon);
			return(FALSE);
		case CLOVE_OF_GARLIC:
			if(index(" VWZ", mon->data->mlet))
				mon->mflee = 1;
			tmp = 1;
			break;
		default:
			/* non-weapons can damage because of their weight */
			/* (but not too much) */
			tmp = obj->owt/10;
			if(tmp < 1) tmp = 1;
			else tmp = rnd(tmp);
			if(tmp > 6) tmp = 6;
		}

	/****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) */

	tmp += u.udaminc + dbon();
	if(u.uswallow)
		if(mon->data->mlet == 'P') {
			if((tmp -= u.uswldtim) <= 0) {
				pline("Your arms are no longer able to hit.");
				return(TRUE);
			}
		}
	if(tmp < 1) tmp = 1;
	mon->mhp -= tmp;
	if(mon->mhp < 1) {
		killed(mon);
		return(FALSE);
	}

	if(thrown) {	/* this assumes that we cannot throw plural things */
		hit( xname(obj)		/* or: objects[obj->otyp].oc_name */,
			mon, exclam(tmp) );
		return(TRUE);
	}
	if(Blind) pline("You hit it.");
	else pline("You hit %s%s", monnam(mon), exclam(tmp));

	if(u.umconf) {
		if(!Blind) {
			pline("Your hands stop glowing blue.");
			if(!mon->mfroz && !mon->msleep)
				pline("%s appears confused.",Monnam(mon));
		}
		mon->mconf = 1;
		u.umconf = 0;
	}
	return(TRUE);	/* mon still alive */
}
//E*O*F hack.fight.c//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 7 (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.invent.c hack.ioctl.c hack.lev.c hack.main.c

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

#include	"hack.h"
#include	<stdio.h>
extern struct obj *splitobj();
extern char morc;
#ifndef NOWORM
#include	"def.wseg.h"

extern struct wseg *wsegs[32];
#endif NOWORM

struct obj *
addinv(obj) register struct obj *obj; {
	register struct obj *otmp;
	for(otmp = invent; otmp; otmp = otmp->nobj) {
		if(merged(otmp, obj, 0)) return(otmp);
		if(!otmp->nobj) {
			otmp->nobj = obj;
			obj->nobj = 0;
			return(obj);
		}
	}
	invent = obj;
	obj->nobj = 0;
	return(obj);
}

useup(obj)
register struct obj *obj;
{
	if(obj->quan > 1){
		obj->quan--;
		obj->owt = weight(obj);
	} else {
		setnotworn(obj);
		freeinv(obj);
		obfree(obj, (struct obj *) 0);
	}
}

freeinv(obj) register struct obj *obj; {
	register struct obj *otmp;
	if(obj == invent) invent = invent->nobj;
	else {
		for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
			if(!otmp->nobj) panic("freeinv");
		otmp->nobj = obj->nobj;
	}
}

/* destroy object in fobj chain (if unpaid, it remains on the bill) */
delobj(obj) register struct obj *obj; {
	freeobj(obj);
	unpobj(obj);
	obfree(obj, (struct obj *) 0);
}

/* unlink obj from chain starting with fobj */
freeobj(obj) register struct obj *obj; {
	register struct obj *otmp;

	if(obj == fobj) fobj = fobj->nobj;
	else {
		for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
			if(!otmp) panic("error in freeobj");
		otmp->nobj = obj->nobj;
	}
}

/* Note: freegold throws away its argument! */
freegold(gold) register struct gen *gold; {
	register struct gen *gtmp;

	if(gold == fgold) fgold = gold->ngen;
	else {
		for(gtmp = fgold; gtmp->ngen != gold; gtmp = gtmp->ngen)
			if(!gtmp) panic("error in freegold");
		gtmp->ngen = gold->ngen;
	}
	free((char *) gold);
}

deltrap(trap)
register struct gen *trap;
{
	register struct gen *gtmp;

	if(trap==ftrap) ftrap=ftrap->ngen;
	else {
		for(gtmp=ftrap;gtmp->ngen!=trap;gtmp=gtmp->ngen) ;
		gtmp->ngen=trap->ngen;
	}
	free((char *) trap);
}

struct wseg *m_atseg;

struct monst *
m_at(x,y)
register x,y;
{
	register struct monst *mtmp;
#ifndef NOWORM
	register struct wseg *wtmp;
#endif NOWORM

	m_atseg = 0;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
		if(mtmp->mx == x && mtmp->my == y)
			return(mtmp);
#ifndef NOWORM
		if(mtmp->wormno){
		    for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
		    if(wtmp->wx == x && wtmp->wy == y){
			m_atseg = wtmp;
			return(mtmp);
		    }
		}
#endif NOWORM
	}
	return(0);
}

struct obj *
o_at(x,y)
register x,y;
{
	register struct obj *otmp;

	for(otmp = fobj; otmp; otmp = otmp->nobj)
		if(otmp->ox == x && otmp->oy == y) return(otmp);
	return(0);
}

struct obj *
sobj_at(n,x,y)
register n,x,y;
{
	register struct obj *otmp;

	for(otmp = fobj; otmp; otmp = otmp->nobj)
		if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
			return(otmp);
	return(0);
}

carried(obj) register struct obj *obj; {
register struct obj *otmp;
	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp == obj) return(1);
	return(0);
}

struct obj *
o_on(id, objchn) unsigned int id; register struct obj *objchn; {
	while(objchn) {
		if(objchn->o_id == id) return(objchn);
		objchn = objchn->nobj;
	}
	return((struct obj *) 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);
}

/* getobj returns:
	struct obj *xxx:	object to do something with.
	0				error return: no object.
	-1			explicitly no object (as in w-).
*/
struct obj *
getobj(let,word)
register char *let,*word;
{
	register struct obj *otmp;
	register char ilet,ilet1,ilet2;
	char buf[BUFSZ];
	char lets[BUFSZ];
	register int foo = 0, foo2, cnt;
	register char *bp = buf;
	xchar allowcnt = 0;	/* 0, 1 or 2 */
	boolean allowgold = FALSE;
	boolean allowall = FALSE;
	boolean allownone = FALSE;
	xchar foox = 0;

	if(*let == '0') let++, allowcnt = 1;
	if(*let == '$') let++, allowgold = TRUE;
	if(*let == '#') let++, allowall = TRUE;
	if(*let == '-') let++, allownone = TRUE;
	if(allownone) *bp++ = '-';
	if(allowgold) *bp++ = '$';
	if(bp[-1] == '-') *bp++ = ' ';

	ilet = 'a';
	for(otmp = invent; otmp; otmp = otmp->nobj){
		if(!*let || index(let, otmp->olet)) {
			bp[foo++] = ilet;
			/* ugly check: remove inappropriate things */
			if((!strcmp(word, "take off") &&
			    !(otmp->owornmask & (W_ARMOR - W_ARM2)))
			|| (!strcmp(word, "wear") &&
			    (otmp->owornmask & (W_ARMOR | W_RING)))
			|| (!strcmp(word, "wield") &&
			    (otmp->owornmask & W_WEP))) {
				foo--;
				foox++;
			}
		}
		if(ilet == 'z') ilet = 'A'; else ilet++;
	}
	bp[foo] = 0;
	if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
	(void) strcpy(lets, bp);	/* necessary since we destroy buf */
	if(foo > 5) {			/* compactify string */
		foo = foo2 = 1;
		ilet2 = bp[0];
		ilet1 = bp[1];
		while(ilet = bp[++foo2] = bp[++foo]){
			if(ilet == ilet1+1){
				if(ilet1 == ilet2+1)
					bp[foo2 - 1] = ilet1 = '-';
				else if(ilet2 == '-') {
					bp[--foo2] = ++ilet1;
					continue;
				}
			}
			ilet2 = ilet1;
			ilet1 = ilet;
		}
	}
	if(!foo && !allowall && !allowgold && !allownone) {
		pline("You don't have anything %sto %s.",
			foox ? "else " : "", word);
		return(0);
	}
	for(;;) {
		if(!buf[0])
			pline("What do you want to %s [*]? ", word);
		else
			pline("What do you want to %s [%s or ?*]? ",
				word, buf);

		cnt = 0;
		ilet = readchar();
		while(digit(ilet) && allowcnt) {
			cnt = 10*cnt + (ilet - '0');
			allowcnt = 2;	/* signal presence of cnt */
			ilet = readchar();
		}
		if(digit(ilet)) {
			pline("No count allowed with this command.");
			continue;
		}
		if(ilet == '\033' || ilet == ' ' || ilet == '\n')
			return((struct obj *)0);
		if(ilet == '-') {
			return((struct obj *)(allownone ? -1 : 0));
		}
		if(ilet == '$') {
			if(!allowgold){
				pline("You cannot %s gold.", word);
				continue;
			}
			otmp = newobj(0);
			/* should set o_id etc. but otmp will be freed soon */
			otmp->olet = '$';
			if(allowcnt == 2 && cnt < u.ugold)
				u.ugold -= cnt;
			else {
				cnt = u.ugold;
				u.ugold = 0;
			}
			flags.botl = 1;
			otmp->quan = cnt;
			return(otmp);
		}
		if(ilet == '?') {
			doinv(lets);
			if(!(ilet = morc)) continue;
			/* he typed a letter (not a space) to more() */
		} else if(ilet == '*') {
			doinv("");
			if(!(ilet = morc)) continue;
			/* ... */
		}
		if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
		ilet -= 'a';
		for(otmp = invent; otmp && ilet; ilet--, otmp = otmp->nobj) ;
		if(!otmp) {
			pline("You don't have that object.");
			continue;
		}
		if(cnt < 0 || otmp->quan < cnt) {
			pline("You don't have that many! [You have %d]"
			, otmp->quan);
			continue;
		}
		break;
	}
	if(!allowall && let && !index(let,otmp->olet)) {
		pline("That is a silly thing to %s.",word);
		return(0);
	}
	if(allowcnt == 2) {	/* cnt given */
		if(cnt == 0) return(0);
		if(cnt != otmp->quan) {
			register struct obj *obj;
			obj = splitobj(otmp, cnt);
			if(otmp == uwep) setuwep(obj);
		}
	}
	return(otmp);
}

ckunpaid(otmp) register struct obj *otmp; {
	return( otmp->unpaid );
}

/* interactive version of getobj */
/* used for Drop and Identify */
ggetobj(word, fn, max)
char *word;
int (*fn)(),  max;
{
char buf[BUFSZ];
register char *ip;
register char sym;
register int oletct = 0, iletct = 0;
register boolean allflag = FALSE;
char olets[20], ilets[20];
int (*ckfn)() = (int (*)()) 0;
	if(!invent){
		pline("You have nothing to %s.", word);
		return(0);
	} else {
		register struct obj *otmp = invent;
		register int uflg = 0;

		ilets[0] = 0;
		while(otmp) {
			if(!index(ilets, otmp->olet)){
				ilets[iletct++] = otmp->olet;
				ilets[iletct] = 0;
			}
			if(otmp->unpaid) uflg = 1;
			otmp = otmp->nobj;
		}
		ilets[iletct++] = ' ';
		if(uflg) ilets[iletct++] = 'u';
		ilets[iletct++] = 'a';
		ilets[iletct] = 0;
	}
	pline("What kinds of thing do you want to %s? [%s] ",
		word, ilets);
	getlin(buf);
	ip = buf;
	olets[0] = 0;
	while(sym = *ip++){
		if(sym == ' ') continue;
		if(sym == 'a') allflag = TRUE; else
		if(sym == 'u') ckfn = ckunpaid; else
		if(index("!%?[()=*/\"0", sym)){
			if(!index(olets, sym)){
				olets[oletct++] = sym;
				olets[oletct] = 0;
			}
		}
		else pline("You don't have any %c's.", sym);
	}
	return askchain(invent, olets, allflag, fn, ckfn, max);
}

/* Walk through the chain starting at objchn and ask for all objects
   with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
   whether the action in question (i.e., fn) has to be performed.
   If allflag then no questions are asked. Max gives the max nr of
   objects treated.
 */
askchain(objchn, olets, allflag, fn, ckfn, max)
struct obj *objchn;
register char *olets;
int allflag;
int (*fn)(), (*ckfn)();
int max;
{
register struct obj *otmp, *otmp2;
register char sym, ilet;
register int cnt = 0;
	ilet = 'a'-1;
	for(otmp = objchn; otmp; otmp = otmp2){
		if(ilet == 'z') ilet = 'A'; else ilet++;
		otmp2 = otmp->nobj;
		if(olets && *olets && !index(olets, otmp->olet)) continue;
		if(ckfn && !(*ckfn)(otmp)) continue;
		if(!allflag) {
			prname(otmp, ilet, 1);
			addtopl(" (ynaq)? ");
			sym = readchar();
		}
		else	sym = 'y';

		switch(sym){
		case 'a':
			allflag = 1;
		case 'y':
			cnt += (*fn)(otmp);
			if(--max == 0) goto ret;
		case 'n':
		default:
			break;
		case 'q':
			goto ret;
		}
	}
	pline(cnt ? "That was all." : "No applicable objects.");
ret:
	if(!flags.echo) echo(OFF);
	return(cnt);
}

obj_to_let(obj)
register struct obj *obj;
{
	register struct obj *otmp;
	register char ilet = 'a';

	for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
		if(++ilet > 'z') ilet = 'A';
	return(otmp ? ilet : 0);
}

prinv(obj)
register struct obj *obj;
{
	prname(obj, obj_to_let(obj), 1);
}

prname(obj,let,onelin)
register struct obj *obj;
register char let;
{
	char li[BUFSZ];

	(void) sprintf(li, " %c - %s.", let, doname(obj));
	switch(onelin) {
	case 1:
		pline(li+1);
		break;
	case 0:
		puts(li+1);
		break;
	case -1:
		cl_end();
		fputs(li, stdout);
		curx += strlen(li);
	}
}

ddoinv()
{
	doinv((char *) 0);
	return(0);
}

/* called with "": all objects in inventory; with 0: also usedup ones */
/* otherwise: all objects with (serial) letter in lets */
doinv(lets) register char *lets; {
	register struct obj *otmp;
	register char ilet = 'a';
	int ct = 0;
	int maxlth = 0;
	int lth;

	if(!invent){
		pline("Not carrying anything");
		if(lets) return;
	}
	if(!flags.oneline) {
	    if(!lets || !*lets)
		for(otmp = invent; otmp; otmp = otmp->nobj) ct++;
	    else
		ct = strlen(lets);
	    if(ct > 1 && ct < ROWNO && (lets || !inshop())){
		for(otmp = invent; otmp; otmp = otmp->nobj) {
		    if(!lets || !*lets || index(lets, ilet)) {
			lth = strlen(doname(otmp));
			if(lth > maxlth) maxlth = lth;
		    }
		    if(++ilet > 'z') ilet = 'A';
		}
		ilet = 'a';
		lth = COLNO - maxlth - 7;
		if(lth < 10) goto clrscr;
		home();
		cl_end();
		flags.topl = 0;
		ct = 0;
		for(otmp = invent; otmp; otmp = otmp->nobj) {
		    if(!lets || !*lets || index(lets, ilet)) {
			curs(lth, ++ct);
			prname(otmp, ilet, -1);
		    }
		    if(++ilet > 'z') ilet = 'A';
		}
		curs(lth, ct+1);
		cl_end();
		cmore();	/* sets morc */
		/* test whether morc is a reasonable answer */
		if(lets && *lets && !index(lets, morc)) morc = 0;

		home();
		cl_end();
		docorner(lth, ct);
		return;
	    }
	}
    clrscr:
	if(ct > 1) cls();
	for(otmp = invent; otmp; otmp = otmp->nobj){
		if(!lets || !*lets || index(lets, ilet))
			prname(otmp, ilet, (ct > 1) ? 0 : 1);
		if(++ilet > 'z') ilet = 'A';
	}
	/* tell doinvbill whether we cleared the screen */
	if(!lets) doinvbill((ct > 1));
	if(ct > 1){
		cgetret();
		docrt();
	} else
		morc = 0;	/* %% */
}

stackobj(obj) register struct obj *obj; {
register struct obj *otmp = fobj;
	for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
	if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
		merged(obj,otmp,1))
			return;
}

/* merge obj with otmp and delete obj if types agree */
merged(otmp,obj,lose) register struct obj *otmp, *obj; {
	if(otmp->otyp == obj->otyp &&
	  obj->unpaid == otmp->unpaid && obj->spe == otmp->spe &&
	  obj->known == otmp->known && obj->dknown == otmp->dknown &&
	  obj->cursed == otmp->cursed &&
	  ((obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)
	  || index("%?!*",otmp->olet))){
		otmp->quan += obj->quan;
		otmp->owt += obj->owt;
		if(lose) freeobj(obj);
		obfree(obj,otmp);	/* free(obj), bill->otmp */
		return(1);
	} else	return(0);
}

doprwep(){
	if(!uwep) pline("You are empty handed.");
	else prinv(uwep);
	return(0);
}

doprarm(){
	if(!uarm && !uarmg && !uarms && !uarmh)
		pline("You are not wearing any armor.");
	else {
		char lets[6];
		register int ct = 0;

		if(uarm) lets[ct++] = obj_to_let(uarm);
		if(uarm2) lets[ct++] = obj_to_let(uarm2);
		if(uarmh) lets[ct++] = obj_to_let(uarmh);
		if(uarms) lets[ct++] = obj_to_let(uarms);
		if(uarmg) lets[ct++] = obj_to_let(uarmg);
		lets[ct] = 0;
		doinv(lets);
	}
	return(0);
}

doprring(){
	if(!uleft && !uright)
		pline("You are not wearing any rings.");
	else {
		char lets[3];
		register int ct = 0;

		if(uleft) lets[ct++] = obj_to_let(uleft);
		if(uright) lets[ct++] = obj_to_let(uright);
		lets[ct] = 0;
		doinv(lets);
	}
	return(0);
}

digit(c) char c; {
	return(c >= '0' && c <= '9');
}
//E*O*F hack.invent.c//

echo x - hack.ioctl.c
cat > "hack.ioctl.c" << '//E*O*F hack.ioctl.c//'
/* This cannot be part of hack.tty.c (as it was earlier) since on some
   systems (e.g. MUNIX) the include files <termio.h> and <sgtty.h>
   define the same constants, and the C preprocessor complains. */
#include <stdio.h>
#include "config.h"
#ifdef BSD
#include	<sgtty.h>
struct ltchars ltchars, ltchars0;
#else
#include	<termio.h>	/* also includes part of <sgtty.h> */
struct termio termio;
#endif BSD

getioctls() {
#ifdef BSD
	(void) ioctl(fileno(stdin), (int) TIOCGLTC, (char *) &ltchars);
	(void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars0);
#else
	(void) ioctl(fileno(stdin), (int) TCGETA, &termio);
#endif BSD
}

setioctls() {
#ifdef BSD
	(void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars);
#else
	(void) ioctl(fileno(stdin), (int) TCSETA, &termio);
#endif BSD
}


//E*O*F hack.ioctl.c//

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

#include "hack.h"
#include <signal.h>
#include <stdio.h>
extern struct monst *restmonchn();
extern struct obj *restobjchn();
extern struct obj *billobjs;
extern char *itoa();

extern char nul[];
#ifndef NOWORM
#include	"def.wseg.h"

extern struct wseg *wsegs[32], *wheads[32];
extern long wgrowtime[32];
#endif NOWORM

#include "savelev.h"

getlev(fd)
{
	register struct gen *gtmp;
#ifndef NOWORM
	register struct wseg *wtmp;
#endif NOWORM
	register tmp;
	long omoves;

	if(fd<0 || read(fd, (char *) levl, sizeof(levl)) != sizeof(levl))
		return(1);
	fgold = 0;
	ftrap = 0;
	mread(fd, (char *)&omoves, sizeof(omoves));	/* 0 from MKLEV */
	mread(fd, (char *)&xupstair, sizeof(xupstair));
	mread(fd, (char *)&yupstair, sizeof(yupstair));
	mread(fd, (char *)&xdnstair, sizeof(xdnstair));
	mread(fd, (char *)&ydnstair, sizeof(ydnstair));

	fmon = restmonchn(fd);
	if(omoves) {
	    /* regenerate animals while on another level */
	    long tmoves = (moves > omoves) ? moves-omoves : 0;
	    register struct monst *mtmp, *mtmp2;
	    extern char genocided[];

	    for(mtmp = fmon; mtmp; mtmp = mtmp2) {
		mtmp2 = mtmp->nmon;
		if(index(genocided, mtmp->data->mlet)) {
			mondead(mtmp);
			continue;
		}
		if(index("ViT", mtmp->data->mlet))
			mtmp->mhp += tmoves;
		else
			mtmp->mhp += tmoves/20;
		if(mtmp->mhp > mtmp->orig_hp)
			mtmp->mhp = mtmp->orig_hp;
	    }
	}

	setshk();
	setgd();
	gtmp = newgen();
	mread(fd, (char *)gtmp, sizeof(struct gen));
	while(gtmp->gx) {
		gtmp->ngen = fgold;
		fgold = gtmp;
		gtmp = newgen();
		mread(fd, (char *)gtmp, sizeof(struct gen));
	}
	mread(fd, (char *)gtmp, sizeof(struct gen));
	while(gtmp->gx) {
		gtmp->ngen = ftrap;
		ftrap = gtmp;
		gtmp = newgen();
		mread(fd, (char *)gtmp, sizeof(struct gen));
	}
	free((char *) gtmp);
	fobj = restobjchn(fd);
	billobjs = restobjchn(fd);
	rest_engravings(fd);
#ifndef QUEST
	mread(fd, (char *)rooms, sizeof(rooms));
	mread(fd, (char *)doors, sizeof(doors));
#endif QUEST
	if(!omoves) return(0);	/* from MKLEV */
#ifndef NOWORM
	mread(fd, (char *)wsegs, sizeof(wsegs));
	for(tmp = 1; tmp < 32; tmp++) if(wsegs[tmp]){
		wheads[tmp] = wsegs[tmp] = wtmp = newseg();
		while(1) {
			mread(fd, (char *)wtmp, sizeof(struct wseg));
			if(!wtmp->nseg) break;
			wheads[tmp]->nseg = wtmp = newseg();
			wheads[tmp] = wtmp;
		}
	}
	mread(fd, (char *)wgrowtime, sizeof(wgrowtime));
#endif NOWORM
	return(0);
}

mread(fd, buf, len)
register fd;
register char *buf;
register unsigned len;
{
register int rlen;
	rlen = read(fd, buf, (int) len);
	if(rlen != len){
		pline("Read %d instead of %d bytes\n", rlen, len);
		panic("Cannot read %d bytes from file #%d\n", len, fd);
	}
}

#ifdef BSD
#include	<sys/wait.h>
#else
#include	<wait.h>
#endif BSD

mklev()
{
	register int fd;
	char type[2];
	union wait status;
	extern char fut_geno[];

	if(getbones()) return;
	if(dlevel < rn1(3, 26)) type[0] = 'a';	/* normal level */
	else type[0] = 'b';			/* maze */
	type[1] = 0;
	switch(fork()){
	case 0:
		(void) signal(SIGINT, SIG_IGN);
		(void) signal(SIGQUIT, SIG_IGN);
		execl("./mklev", "mklev", lock, type, itoa(dlevel), fut_geno, 
#ifdef WIZARD
			wizard ? "w" :
#endif WIZARD
					"", (char *) 0);
		exit(2);
	case -1:
		settty("Cannot fork!\n");
		exit(1);
	default:
		(void) fflush(stdout);	/* You fell into a trap ... */
		(void) wait(&status);
	}
	if(status.w_status) {
		if(status.w_coredump) {
			settty("Mklev dumped core. Exiting...\n");
			exit(1);
		}
		if(status.w_termsig) {
			settty("Mklev killed by a signal. Exiting...\n");
			exit(1);
		}
		if(status.w_retcode) {
			if(status.w_retcode == 2) {
				settty("Cannot execl mklev.\n");
				exit(1);
			}
			pline("Mklev failed. Let's try again.");
			mklev();
			return;
		}
	}
	if((fd = open(lock, 0)) < 0) {
		pline("Can't open %s!", lock);
		mklev();
		return;
	}
	(void) getlev(fd);
	(void) close(fd);
}
//E*O*F hack.lev.c//

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

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

extern char *getlogin();
extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
extern char *getenv();

int (*afternmv)();

int done1();
int hangup();

char safelock[] = "safelock";
xchar locknum;				/* max num of players */
char *catmore = "/bin/cat";		/* or e.g. /usr/ucb/more */
char SAVEF[PL_NSIZ + 5] = "save/";
char perm[] = "perm";
char *hname;		/* name of the game (argv[0] of call) */
char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */

extern char *nomovemsg;
extern long wailmsg;

main(argc,argv)
int argc;
char *argv[];
{
	int fd;
#ifdef NEWS
	int nonews = 0;
#endif NEWS
	char *dir;

	hname = argv[0];

	/*
	 * See if we must change directory to the playground.
	 * (Perhaps hack runs suid and playground is inaccessible
	 *  for the player.)
	 * The environment variable HACKDIR is overridden by a
	 *  -d command line option.
	 */
	dir = getenv("HACKDIR");
	if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
		argc--;
		argv++;
		dir = argv[0]+2;
		if(*dir == '=' || *dir == ':') dir++;
		if(!*dir && argc > 1) {
			argc--;
			argv++;
			dir = argv[0];
		}
		if(!*dir)
			error("Flag -d must be followed by a directory name.");
	}

	/*
	 * Now we know the directory containing 'record' and
	 * may do a prscore().
	 */
	if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
		if(dir) chdirx(dir);
		prscore(argc, argv);
		exit(0);
	}

	/*
	 * It seems he really wants to play. Find the creation date of
	 * this game so as to avoid restoring outdated savefiles.
	 */
	gethdate(hname);

	/*
	 * We cannot do chdir earlier, otherwise gethdate will fail.
	 */
	if(dir) chdirx(dir);

	/*
	 * Who am i? Perhaps we should use $USER instead?
	 */
	(void) strncpy(plname, getlogin(), sizeof(plname)-1);

	/*
	 * Process options.
	 */
	while(argc > 1 && argv[1][0] == '-'){
		argv++;
		argc--;
		switch(argv[0][1]){
#ifdef WIZARD
		case 'w':
			if(!strcmp(getlogin(), WIZARD))
				wizard = TRUE;
			else printf("Sorry.\n");
			break;
#endif WIZARD
#ifdef NEWS
		case 'n':
			nonews++;
			break;
#endif NEWS
		case 'u':
			if(argv[0][2])
			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
			else if(argc > 1) {
			  argc--;
			  argv++;
			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
			} else
				printf("Player name expected after -u\n");
			break;
		default:
			printf("Unknown option: %s\n", *argv);
		}
	}

	if(argc > 1)
		locknum = atoi(argv[1]);
	if(argc > 2)
		catmore = argv[2];
#ifdef WIZARD
	if(wizard) (void) strcpy(plname, "wizard"); else
#endif WIZARD
	if(!*plname || !strncmp(plname, "player", 4)) askname();
	plnamesuffix();		/* strip suffix from name */

	setbuf(stdout,obuf);
 	(void) srand(getpid());
	startup();
	cls();
	(void) signal(SIGHUP, hangup);
#ifdef WIZARD
	if(!wizard) {
#endif WIZARD
		(void) signal(SIGQUIT,SIG_IGN);
		(void) signal(SIGINT,SIG_IGN);
		if(locknum)
			lockcheck();
		else
			(void) strcpy(lock,plname);
#ifdef WIZARD
	} else {
		register char *sfoo;
		(void) strcpy(lock,plname);
		if(sfoo = getenv("MAGIC"))
			while(*sfoo) {
				switch(*sfoo++) {
				case 'n': (void) srand(*sfoo++);
					break;
				}
			}
		if(sfoo = getenv("GENOCIDED")){
			if(*sfoo == '!'){
				extern struct permonst mons[CMNUM+2];
				extern char genocided[], fut_geno[];
				register struct permonst *pm = mons;
				register char *gp = genocided;

				while(pm < mons+CMNUM+2){
					if(!index(sfoo, pm->mlet))
						*gp++ = pm->mlet;
					pm++;
				}
				*gp = 0;
			} else
				(void) strcpy(genocided, sfoo);
			(void) strcpy(fut_geno, genocided);
		}
	}
#endif WIZARD
	u.uhp = 1;	/* prevent RIP on early quits */
	u.ux = FAR;	/* prevent nscr() */
	(void) strcat(SAVEF,plname);
	if((fd = open(SAVEF,0)) >= 0 &&
	   (uptodate(fd) || unlink(SAVEF) == 666)) {
		(void) signal(SIGINT,done1);
		puts("Restoring old save file...");
		(void) fflush(stdout);
		dorecover(fd);
		flags.move = 0;
	} else {
#ifdef NEWS
		if(!nonews)
			if((fd = open(NEWS,0)) >= 0)
				outnews(fd);
#endif NEWS
		flags.ident = 1;
		init_objects();
		u_init();
		(void) signal(SIGINT,done1);
		glo(1);
		mklev();
		u.ux = xupstair;
		u.uy = yupstair;
		(void) inshop();
		setsee();
		flags.botlx = 1;
		makedog();
		seemons();
		docrt();
		pickup();
		read_engr_at(u.ux,u.uy);	/* superfluous ? */
		flags.move = 1;
		flags.cbreak = ON;
		flags.echo = OFF;
	}
	setftty();
#ifdef TRACK
	initrack();
#endif TRACK
	for(;;) {
		if(flags.move) {
#ifdef TRACK
			settrack();
#endif TRACK
			if(moves%2 == 0 ||
			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
				extern struct monst *makemon();
				movemon();
				if(!rn2(70))
				    (void) makemon((struct permonst *)0, 0, 0);
			}
			if(Glib) glibr();
			timeout();
			++moves;
			if(u.uhp < 1) {
				pline("You die...");
				done("died");
			}
			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
			    wailmsg = moves;
			    if(u.uhp == 1)
			    pline("You hear the wailing of the Banshee...");
			    else
			    pline("You hear the howling of the CwnAnnwn...");
			}
			if(u.uhp < u.uhpmax) {
				if(u.ulevel > 9) {
					if(Regeneration || !(moves%3)) {
					    flags.botl = 1;
					    u.uhp += rnd((int) u.ulevel-9);
					    if(u.uhp > u.uhpmax)
						u.uhp = u.uhpmax;
					}
				} else if(Regeneration ||
					(!(moves%(22-u.ulevel*2)))) {
					flags.botl = 1;
					u.uhp++;
				}
			}
			if(Teleportation && !rn2(85)) tele();
			if(Searching && multi >= 0) (void) dosearch();
			gethungry();
			invault();
		}
		if(multi < 0) {
			if(!++multi){
				pline(nomovemsg ? nomovemsg :
					"You can move again.");
				nomovemsg = 0;
				if(afternmv) (*afternmv)();
				afternmv = 0;
			}
		}
		flags.move = 1;
		find_ac();
#ifndef QUEST
		if(!flags.mv || Blind)
#endif QUEST
		{
			seeobjs();
			seemons();
			nscr();
		}
		if(flags.botl || flags.botlx) bot();
		if(multi > 0) {
#ifdef QUEST
			if(flags.run >= 4) finddir();
#endif QUEST
			lookaround();
			if(!multi) {	/* lookaround may clear multi */
				flags.move = 0;
				continue;
			}
			if(flags.mv) {
				if(multi<COLNO && !--multi)
					flags.mv = flags.run = 0;
				domove();
			} else {
				--multi;
				rhack(save_cm);
			}
		} else if(multi == 0)
			rhack((char *) 0);
	}
}

lockcheck()
{
	extern int errno;
	register int i, fd;

	/* we ignore QUIT and INT at this point */
	if (link(perm,safelock) == -1)
		error("Cannot link safelock. (Try again or rm safelock.)");

	for(i = 0; i < locknum; i++) {
		lock[0]= 'a' + i;
		if((fd = open(lock,0)) == -1) {
			if(errno == ENOENT) goto gotlock;    /* no such file */
			(void) unlink(safelock);
			error("Cannot open %s", lock);
		}
		(void) close(fd);
	}
	(void) unlink(safelock);
	error("Too many hacks running now.");
gotlock:
	fd = creat(lock,FMASK);
	if(fd == -1) {
		error("cannot creat lock file.");
	} else {
		int pid;

		pid = getpid();
		if(write(fd, (char *) &pid, 2) != 2){
			error("cannot write lock");
		}
		if(close(fd) == -1){
			error("cannot close lock");
		}
	}
	if(unlink(safelock) == -1){
		error("Cannot unlink safelock");
	}
}

/*VARARGS1*/
error(s,a1,a2,a3,a4) char *s,*a1,*a2,*a3,*a4; {
	printf("Error: ");
	printf(s,a1,a2,a3,a4);
	(void) putchar('\n');
	exit(1);
}

glo(foo)
register foo;
{
	/* construct the string  xlock.n  */
	register char *tf;

	tf = lock;
	while(*tf && *tf!='.') tf++;
	(void) sprintf(tf, ".%d", foo);
}

/*
 * plname is filled either by an option (-u Player  or  -uPlayer) or
 * explicitly (-w implies wizard) or by askname.
 * It may still contain a suffix denoting pl_character.
 */
askname(){
register int c,ct;
	printf("\nWho are you? ");
	ct = 0;
	while((c = getchar()) != '\n'){
		if(c == EOF) error("End of input\n");
		if(c != '-')
		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
		if(ct < sizeof(plname)-1) plname[ct++] = c;
	}
	plname[ct] = 0;
	if(ct == 0) askname();
#ifdef QUEST
	else printf("Hello %s, welcome to quest!\n", plname);
#else
	else printf("Hello %s, welcome to hack!\n", plname);
#endif QUEST
}

impossible(){
	pline("Program in disorder - perhaps you'd better Quit");
}

#ifdef NEWS
int stopnews;

stopnws(){
	(void) signal(SIGINT, SIG_IGN);
	stopnews++;
}

outnews(fd) int fd; {
int (*prevsig)();
char ch;
	prevsig = signal(SIGINT, stopnws);
	while(!stopnews && read(fd,&ch,1) == 1)
		(void) putchar(ch);
	(void) putchar('\n');
	(void) fflush(stdout);
	(void) close(fd);
	(void) signal(SIGINT, prevsig);
	/* See whether we will ask TSKCFW: he might have told us already */
	if(!stopnews && pl_character[0])
		getret();
}
#endif NEWS

chdirx(dir) char *dir; {
	if(chdir(dir) < 0) {
		perror(dir);
		error("Cannot chdir to %s.", dir);
	}
}
//E*O*F hack.main.c//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 8 (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.makemon.c hack.mfndpos.h hack.mhitu.c hack.mkobj.c hack.mon.c

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

#ifdef MKLEV
#include	"mklev.h"
extern char *fut_geno;
#else MKLEV
#include	"hack.h"
extern char fut_geno[];
#endif MKLEV


extern char *index();

struct monst zeromonst;

/*
 * called with [x,y] = coordinates;
 *	[0,0] means anyplace
 *	[u.ux,u.uy] means: call mnexto (not in MKLEV)
 *
 *	In case we make an Orc or killer bee, we make an entire horde (swarm);
 *	note that in this case we return only one of them (the one at [x,y]).
 */
struct monst *
makemon(ptr,x,y)
register struct permonst *ptr;
{
	register struct monst *mtmp;
	register tmp, ct;
	boolean anything = (!ptr);

	if(x != 0 || y != 0) if(m_at(x,y)) return((struct monst *) 0);
	if(ptr){
		if(index(fut_geno, ptr->mlet)) return((struct monst *) 0);
	} else {
		ct = CMNUM - strlen(fut_geno);
		if(index(fut_geno, 'm')) ct++;  /* make only 1 minotaur */
		if(index(fut_geno, '@')) ct++;
		if(ct <= 0) return(0); 		  /* no more monsters! */
		tmp = rn2(ct*dlevel/24 + 7);
		if(tmp < dlevel - 4) tmp = rn2(ct*dlevel/24 + 12);
		if(tmp >= ct) tmp = rn1(ct - ct/2, ct/2);
		for(ct = 0; ct < CMNUM; ct++){
			ptr = &mons[ct];
			if(index(fut_geno, ptr->mlet))
				continue;
			if(!tmp--) goto gotmon;
		}
		panic("makemon?");
	}
gotmon:
	mtmp = newmonst(ptr->pxlth);
	*mtmp = zeromonst;	/* clear all entries in structure */
	for(ct = 0; ct < ptr->pxlth; ct++)
		((char *) &(mtmp->mextra[0]))[ct] = 0;
	mtmp->nmon = fmon;
	fmon = mtmp;
#ifndef MKLEV
	mtmp->m_id = flags.ident++;
#endif MKLEV
	mtmp->data = ptr;
	mtmp->mxlth = ptr->pxlth;
	if(ptr->mlet == 'D') mtmp->orig_hp = mtmp->mhp = 80;
	else if(!ptr->mlevel) mtmp->orig_hp = mtmp->mhp = rnd(4);
	else mtmp->orig_hp = mtmp->mhp = d(ptr->mlevel, 8);
	mtmp->mx = x;
	mtmp->my = y;
	mtmp->mcansee = 1;
	if(ptr->mlet == 'M')
		mtmp->mimic = ']';
#ifndef MKLEV
	if(x == u.ux && y == u.uy)
		mnexto(mtmp);
	if(x == 0 && y == 0)
		rloc(mtmp);
#endif MKLEV
	if(ptr->mlet == 's' || ptr->mlet == 'S') {
		mtmp->mhide = mtmp->mundetected = 1;
#ifdef MKLEV
		if(mtmp->mx && mtmp->my)
			mkobj_at(0, mtmp->mx, mtmp->my);
#endif MKLEV
	}
	if(ptr->mlet == ':') {
		mtmp->cham = 1;
#ifndef MKLEV
		(void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]);
#endif MKLEV
	}
	if(ptr->mlet == 'I') mtmp->minvis = 1;
	if(ptr->mlet == 'L' || ptr->mlet == 'N'
#ifdef MKLEV
		|| rn2(5)
#endif MKLEV
	) mtmp->msleep = 1;

#ifndef NOWORM
#ifndef MKLEV
	if(ptr->mlet == 'w' && getwn(mtmp))
		initworm(mtmp);
#endif MKLEV
#endif NOWORM

	if(anything) if(ptr->mlet == 'O' || ptr->mlet == 'k') {
		coord enexto();
		coord mm;
		register int cnt = rnd(10);
		mm.x = x;
		mm.y = y;
		while(cnt--) {
			mm = enexto(mm.x, mm.y);
			(void) makemon(ptr, mm.x, mm.y);
		}
	}

	return(mtmp);
}

coord
enexto(xx,yy)
register xchar xx,yy;
{
	register xchar x,y;
	coord foo[15], *tfoo;
	int range;

	tfoo = foo;
	range = 1;
	do {	/* full kludge action. */
		for(x = xx-range; x <= xx+range; x++)
			if(goodpos(x, yy-range)) {
				tfoo->x = x;
				tfoo++->y = yy-range;
				if(tfoo == &foo[15]) goto foofull;
			}
		for(x = xx-range; x <= xx+range; x++)
			if(goodpos(x,yy+range)) {
				tfoo->x = x;
				tfoo++->y = yy+range;
				if(tfoo == &foo[15]) goto foofull;
			}
		for(y = yy+1-range; y < yy+range; y++)
			if(goodpos(xx-range,y)) {
				tfoo->x = xx-range;
				tfoo++->y = y;
				if(tfoo == &foo[15]) goto foofull;
			}
		for(y = yy+1-range; y < yy+range; y++)
			if(goodpos(xx+range,y)) {
				tfoo->x = xx+range;
				tfoo++->y = y;
				if(tfoo == &foo[15]) goto foofull;
			}
		range++;
	} while(tfoo == foo);
foofull:
	return( foo[rn2(tfoo-foo)] );
}

goodpos(x,y)	/* used only in mnexto and rloc */
{
	return(
	! (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 ||
	   m_at(x,y) || levl[x][y].typ < DOOR
#ifndef MKLEV
	   || (x == u.ux && y == u.uy)
	   || sobj_at(ENORMOUS_ROCK, x, y)
#endif MKLEV
	));
}
//E*O*F hack.makemon.c//

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

#define	ALLOW_TRAPS	0777
#define	ALLOW_U		01000
#define	ALLOW_M		02000
#define	ALLOW_TM	04000
#define	ALLOW_ALL	(ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS)
#define	ALLOW_SSM	010000
#define	ALLOW_ROCK	020000
#define	NOTONL		040000
#define	NOGARLIC	0100000
//E*O*F hack.mfndpos.h//

echo x - hack.mhitu.c
cat > "hack.mhitu.c" << '//E*O*F hack.mhitu.c//'
#include	"hack.h"
extern struct monst *makemon();

/*
 * mhitu: monster hits you
 *	  returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise
 */
mhitu(mtmp)
register struct monst *mtmp;
{
	register struct permonst *mdat = mtmp->data;
	register int tmp, ctmp;

	nomul(0);
	if(!index("&DuxynNF",mdat->mlet) && !u.uswallow)
		tmp = hitu(mtmp,d(mdat->damn,mdat->damd));
	else tmp = 0;

	ctmp = tmp && !mtmp->mcan &&
	  (!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50));
	switch(mdat->mlet) {
	case '&':
		if(!mtmp->cham && !mtmp->mcan && !rn2(15)) {
			(void) makemon(PM_DEMON,u.ux,u.uy);
		} else {
			(void) hitu(mtmp,d(2,6));
			(void) hitu(mtmp,d(2,6));
			(void) hitu(mtmp,rnd(3));
			(void) hitu(mtmp,rnd(3));
			(void) hitu(mtmp,rn1(4,2));
		}
		break;
	case ',':
		if(u.uswallow)
			youswld(mtmp,4+u.uac,5,"The trapper");
		else if(tmp) justswld(mtmp,"The trapper");
		break;
	case '\'':
		if(u.uswallow)
			youswld(mtmp,rnd(6),7,"The lurker above");
		else if(tmp) justswld(mtmp,"The lurker above");
		break;
	case 'A':
		if(ctmp && rn2(2)) {
			pline("You feel weaker!");
			losestr(1);
		}
		break;
	case 'C':
		(void) hitu(mtmp,rnd(6));
		break;
	case 'c':
		if(!rn2(5)) {
			pline("You hear %s's hissing!", monnam(mtmp));
			if(ctmp || !rn2(5)) {
				pline("You get turned to stone!");
				done_in_by(mtmp);
			}
		}
		break;
	case 'D':
		if(rn2(6) || mtmp->mcan) {
			(void) hitu(mtmp,d(3,10));
			(void) hitu(mtmp,rnd(8));
			(void) hitu(mtmp,rnd(8));
			break;
		}
		kludge("%s breathes fire!","The dragon");
		buzz(-1,mtmp->mx,mtmp->my,u.ux-mtmp->mx,u.uy-mtmp->my);
		break;
	case 'd':
		(void) hitu(mtmp,d(2,4));
		break;
	case 'e':
		(void) hitu(mtmp,d(3,6));
		break;
	case 'F':
		if(mtmp->mcan) break;
		kludge("%s explodes!","The freezing sphere");
		if(Cold_resistance) pline("You don't seem affected by it.");
		else {
			xchar dn;
			if(17-(u.ulevel/2) > rnd(20)) {
				pline("You get blasted!");
				dn = 6;
			} else {
				pline("You duck the blast...");
				dn = 3;
			}
			losehp_m(d(dn,6), mtmp);
		}
		mondead(mtmp);
		return(1);
	case 'g':
		if(ctmp && multi >= 0 && !rn2(6)) {
kludge("You are frozen by %ss juices","the cube'");
			nomul(-rnd(10));
		}
		break;
	case 'h':
		if(ctmp && multi >= 0 && !rn2(5)) {
			nomul(-rnd(10));
kludge("You are put to sleep by %ss bite!","the homunculus'");
		}
		break;
	case 'j':
		tmp = hitu(mtmp,rnd(3));
		tmp &= hitu(mtmp,rnd(3));
		if(tmp){
			(void) hitu(mtmp,rnd(4));
			(void) hitu(mtmp,rnd(4));
		}
		break;
	case 'k':
		if((hitu(mtmp,rnd(4)) || !rn2(3)) && ctmp){
			poisoned("bee's sting",mdat->mname);
		}
		break;
	case 'L':
		if(tmp) stealgold(mtmp);
		break;
	case 'N':
		if(mtmp->mcan && !Blind) {
	pline("%s tries to seduce you, but you seem not interested.",
			Amonnam(mtmp, "plain"));
			if(rn2(3)) rloc(mtmp);
		} else if(steal(mtmp)) {
			rloc(mtmp);
			mtmp->mflee = 1;
		}
		break;
	case 'n':
		if(!uwep && !uarm && !uarmh && !uarms && !uarmg) {
		    pline("%s hits! (I hope you don't mind)",
			Monnam(mtmp));
			u.uhp += rnd(7);
			if(!rn2(7)) u.uhpmax++;
			if(u.uhp > u.uhpmax) u.uhp = u.uhpmax;
			flags.botl = 1;
			if(!rn2(50)) rloc(mtmp);
		} else {
			(void) hitu(mtmp,d(2,6));
			(void) hitu(mtmp,d(2,6));
		}
		break;
	case 'o':
		tmp = hitu(mtmp,rnd(6));
		if(hitu(mtmp,rnd(6)) && ctmp &&
		!u.ustuck && rn2(2)) {
			u.ustuck = mtmp;
			kludge("%s has grabbed you!","The owlbear");
			u.uhp -= d(2,8);
		} else if(u.ustuck == mtmp) {
			u.uhp -= d(2,8);
			pline("You are being crushed.");
		}
		break;
	case 'P':
		if(u.uswallow)
			youswld(mtmp,d(2,4),12,"The purple worm");
		else if(ctmp && !rn2(4))
			justswld(mtmp,"The purple worm");
		else (void) hitu(mtmp,d(2,4));
		break;
	case 'Q':
		(void) hitu(mtmp,rnd(2));
		(void) hitu(mtmp,rnd(2));
		break;
	case 'R':
		if(tmp && uarmh && !uarmh->rustfree &&
		    (int) uarmh->spe >= -1) {
			pline("Your helmet rusts!");
			uarmh->spe--;
		} else
		if(ctmp && uarm && !uarmh->rustfree &&
		 uarm->otyp < STUDDED_LEATHER_ARMOR &&
		 (int)uarm->spe >= -1) {
			pline("Your armor rusts!");
			uarm->spe--;
		}
		break;
	case 'S':
		if(ctmp && !rn2(8)) {
			poisoned("snake's bite",mdat->mname);
		}
		break;
	case 's':
		if(tmp && !rn2(8)) {
			poisoned("scorpion's sting",mdat->mname);
		}
		(void) hitu(mtmp,rnd(8));
		(void) hitu(mtmp,rnd(8));
		break;
	case 'T':
		(void) hitu(mtmp,rnd(6));
		(void) hitu(mtmp,rnd(6));
		break;
	case 't':
		if(!rn2(5)) rloc(mtmp);
		break;
	case 'u':
		mtmp->mflee = 1;
		break;
	case 'U':
		(void) hitu(mtmp,d(3,4));
		(void) hitu(mtmp,d(3,4));
		break;
	case 'v':
		if(ctmp && !u.ustuck) u.ustuck = mtmp;
		break;
	case 'V':
		if(tmp) u.uhp -= 4;
		if(ctmp && !rn2(3)) losexp();
		break;
	case 'W':
		if(ctmp && !rn2(5)) losexp();
		break;
#ifndef NOWORM
	case 'w':
		if(tmp) wormhit(mtmp);
#endif NOWORM
		break;
	case 'X':
		(void) hitu(mtmp,rnd(3));
		(void) hitu(mtmp,rnd(3));
		(void) hitu(mtmp,rnd(3));
		break;
	case 'x':
		{ register int side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
		  pline("%s pricks in your %s leg!",
			Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left");
		  Wounded_legs |= side + rnd(5);
		  losehp_m(2, mtmp);
		  break;
		}
	case 'y':
		if(mtmp->mcan) break;
		mondead(mtmp);
		if(!Blind) {
			pline("You are blinded by a blast of light!");
			Blind = d(4,12);
			seeoff(0);
		}
		return(1);
	case 'Y':
		(void) hitu(mtmp,rnd(6));
		break;
	}
	if(u.uhp < 1) done_in_by(mtmp);
	return(0);
}
//E*O*F hack.mhitu.c//

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

#ifdef MKLEV
#include "mklev.h"
#else
#include "hack.h"
#endif MKLEV

#include "hack.onames.h"

char mkobjstr[] = "))[[!!!!????%%%%/=**))[[!!!!????%%%%/=**(";
struct obj *mkobj(), *mksobj();

mkobj_at(let,x,y)
register let,x,y;
{
	register struct obj *otmp = mkobj(let);
	otmp->ox = x;
	otmp->oy = y;
	otmp->nobj = fobj;
	fobj = otmp;
}

#ifndef MKLEV
mksobj_at(let,otyp,x,y)
register let,otyp,x,y;
{
	register struct obj *otmp = mksobj(let, otyp);
	otmp->ox = x;
	otmp->oy = y;
	otmp->nobj = fobj;
	fobj = otmp;
}
#endif MKLEV

struct obj *
mkobj(let) {
	if(!let) let = mkobjstr[rn2(sizeof(mkobjstr) - 1)];
	return(mksobj(let, letter(let) ? CORPSE : probtype(let)));
}
	

struct obj zeroobj;

struct obj *
mksobj(let, otyp) {
	register struct obj *otmp;

	otmp = newobj(0);
	*otmp = zeroobj;
#ifdef MKLEV
	otmp->age = 0;
	otmp->o_id = 0;
#else
	otmp->age = moves;
	otmp->o_id = flags.ident++;
#endif MKLEV
	otmp->quan = 1;
	if(letter(let)){
		otmp->olet = FOOD_SYM;
		otmp->otyp = CORPSE + ((let > 'Z') ? (let-'a'+'Z'-'@'+1) :
				(let-'@'));
		otmp->spe = let;
		otmp->known = 1;
		otmp->owt = weight(otmp);
		return(otmp);
	}
	otmp->olet = let;
	otmp->otyp = otyp;
	otmp->dknown = index("/=!?*", let) ? 0 : 1;
	switch(let) {
	case WEAPON_SYM:
		otmp->quan = (otmp->otyp <= ROCK) ? rn1(6,6) : 1;
		if(!rn2(11)) otmp->spe = rnd(3);
		else if(!rn2(10)) {
			otmp->cursed = 1;
			otmp->spe = -rnd(3);
		}
		break;
	case FOOD_SYM:
	case GEM_SYM:
		otmp->quan = rn2(6) ? 1 : 2;
	case TOOL_SYM:
	case CHAIN_SYM:
	case BALL_SYM:
	case ROCK_SYM:
	case POTION_SYM:
	case SCROLL_SYM:
	case AMULET_SYM:
		break;
	case ARMOR_SYM:
		if(!rn2(8)) otmp->cursed = 1;
		if(!rn2(10)) otmp->spe = rnd(3);
		else if(!rn2(9)) {
			otmp->spe = -rnd(3);
			otmp->cursed = 1;
		}
		otmp->spe += 10 - objects[otmp->otyp].a_ac;
		break;
	case WAND_SYM:
		if(otmp->otyp == WAN_WISHING) otmp->spe = 3; else
		otmp->spe = rn1(5,
			(objects[otmp->otyp].bits & NODIR) ? 11 : 4);
		break;
	case RING_SYM:
		if(objects[otmp->otyp].bits & SPEC) {
			if(!rn2(3)) {
				otmp->cursed = 1;
				otmp->spe = -rnd(2);
			} else otmp->spe = rnd(2);
		} else if(otmp->otyp == RIN_TELEPORTATION ||
			  otmp->otyp == RIN_AGGRAVATE_MONSTER ||
			  otmp->otyp == RIN_HUNGER || !rn2(9))
			otmp->cursed = 1;
		break;
	default:
		panic("impossible mkobj");
	}
	otmp->owt = weight(otmp);
	return(otmp);
}

letter(c) {
	return(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z'));
}

weight(obj)
register struct obj *obj;
{
register int wt = objects[obj->otyp].oc_weight;
	return(wt ? wt*obj->quan : (obj->quan + 1)/2);
}

mkgold(num,x,y)
register num;
{
	register struct gen *gtmp;
	register int amount = num ? num : 1 + (rnd(dlevel+2) * rnd(30));

	if(gtmp = g_at(x,y,fgold))
		gtmp->gflag += amount;
	else {
		gtmp = newgen();
		gtmp->ngen = fgold;
		gtmp->gx = x;
		gtmp->gy = y;
		gtmp->gflag = amount;
		fgold = gtmp;
#ifdef MKLEV
		levl[x][y].scrsym = '$';
#endif MKLEV
	}
}
//E*O*F hack.mkobj.c//

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

#include "hack.h"
#include "hack.mfndpos.h"
#define	SIZE(x)	(int)(sizeof(x) / sizeof(x[0]))
#define	NULL	(char *) 0
extern struct monst *makemon();

int warnlevel;		/* used by movemon and dochugw */
long lastwarntime;
int lastwarnlev;
char *warnings[] = {
	"white", "pink", "red", "ruby", "purple", "black"
};

movemon()
{
	register struct monst *mtmp;
	register int fr;

	warnlevel = 0;

	while(1) {
		/* find a monster that we haven't treated yet */
		/* note that mtmp or mtmp->nmon might get killed
		   while mtmp moves, so we cannot just walk down the
		   chain (even new monsters might get created!) */
		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
			if(mtmp->mlstmv < moves) goto next_mon;
		/* treated all monsters */
		break;

	next_mon:
		mtmp->mlstmv = moves;
		if(mtmp->mblinded && !--mtmp->mblinded)
			mtmp->mcansee = 1;
		if(mtmp->mimic) continue;
		if(mtmp->mspeed != MSLOW || !(moves%2)){
			/* continue if the monster died fighting */
			fr = -1;
			if(Conflict && cansee(mtmp->mx,mtmp->my)
				&& (fr = fightm(mtmp)) == 2)
				continue;
			if(fr<0 && dochugw(mtmp))
				continue;
		}
		if(mtmp->mspeed == MFAST && dochugw(mtmp))
			continue;
	}

	warnlevel -= u.ulevel;
	if(warnlevel >= SIZE(warnings))
		warnlevel = SIZE(warnings)-1;
	if(warnlevel >= 0)
	if(warnlevel > lastwarnlev || moves > lastwarntime + 5){
	    register char *rr;
	    switch(Warning & (LEFT_RING | RIGHT_RING)){
	    case LEFT_RING:
		rr = "Your left ring glows";
		break;
	    case RIGHT_RING:
		rr = "Your right ring glows";
		break;
	    case LEFT_RING | RIGHT_RING:
		rr = "Both your rings glow";
		break;
	    default:
		rr = "Your fingertips glow";
		break;
	    }
	    pline("%s %s!", rr, warnings[warnlevel]);
	    lastwarntime = moves;
	    lastwarnlev = warnlevel;
	}

	dmonsfree();	/* remove all dead monsters */
}

justswld(mtmp,name)
register struct monst *mtmp;
char *name;
{

	mtmp->mx = u.ux;
	mtmp->my = u.uy;
	u.ustuck = mtmp;
	pmon(mtmp);
	kludge("%s swallows you!",name);
	more();
	seeoff(1);
	u.uswallow = 1;
	swallowed();
}

youswld(mtmp,dam,die,name)
register struct monst *mtmp;
register dam,die;
char *name;
{
	if(mtmp != u.ustuck) return;
	kludge("%s digests you!",name);
	u.uhp -= dam;
	if(u.uswldtim++ == die){
		pline("It totally digests you!");
		u.uhp = -1;
	}
	if(u.uhp < 1) done_in_by(mtmp);
}

dochugw(mtmp) register struct monst *mtmp; {
register x = mtmp->mx;
register y = mtmp->my;
register d = dochug(mtmp);
register dd;
	if(!d)		/* monster still alive */
	if(Warning)
	if(!mtmp->mpeaceful)
	if((dd = dist(mtmp->mx,mtmp->my)) < dist(x,y))
	if(dd < 100)
	if(!cansee(mtmp->mx, mtmp->my) || (mtmp->minvis && !See_invisible))
	if(mtmp->data->mlevel > warnlevel)
		warnlevel = mtmp->data->mlevel;
	return(d);
}

/* returns 1 if monster died moving, 0 otherwise */
dochug(mtmp)
register struct monst *mtmp;
{
	register struct permonst *mdat;
	register tmp;

	if(mtmp->cham && !rn2(6))
		(void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]);
	mdat = mtmp->data;
	if(mdat->mlevel < 0)
		panic("bad monster %c (%d)",mdat->mlet,mdat->mlevel);
	if((!(moves%20) || index("ViT",mdat->mlet)) &&
	    mtmp->mhp<mtmp->orig_hp)
		mtmp->mhp++; /* regenerate monsters. */
	if(mtmp->mfroz) return(0); /* frozen monsters don't do anything. */
	if(mtmp->msleep) {/* wake up a monster, or get out of here. */
		if(cansee(mtmp->mx,mtmp->my) && !Stealth &&
			(!index("NL",mdat->mlet) || !rn2(50)) &&
			(Aggravate_monster || (!rn2(7) && !mtmp->mimic)))
			mtmp->msleep = 0;
		else return(0);
	}

	/* not frozen or sleeping: wipe out texts written in the dust */
	wipe_engr_at(mtmp->mx, mtmp->my, 1);

	/* confused monsters get unconfused with small probability */
	if(mtmp->mconf && !rn2(50)) mtmp->mconf = 0;

	/* some monsters teleport */
	if(mtmp->mflee && index("tNL", mdat->mlet) && !rn2(40)){
		rloc(mtmp);
		return(0);
	}
	if(mdat->mmove < rnd(6)) return(0);
	if((mtmp->mflee ||
		mtmp->mconf ||
		(index("BIuy", mdat->mlet) && !rn2(4)) ||
		(mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) ||
		dist(mtmp->mx,mtmp->my) > 2 ||
		(!mtmp->mcansee && !rn2(4)) ||
		mtmp->mpeaceful
	   ) && (tmp = m_move(mtmp,0)) && mdat->mmove <= 12)
		return(tmp == 2);
	if(tmp == 2) return(1);	/* monster died moving */

	if(!index("Ea", mdat->mlet) && dist(mtmp->mx, mtmp->my) < 3 &&
	 !mtmp->mpeaceful && u.uhp > 0 &&
	 !sengr_at("Elbereth", u.ux, u.uy) &&
	 !sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy)) {
		if(mhitu(mtmp))
			return(1);	/* monster died (e.g. 'y' or 'F') */
	}
	/* extra movement for fast monsters */
	if(mdat->mmove-12 > rnd(12)) tmp = m_move(mtmp,1);
	return(tmp == 2);
}

inrange(mtmp)
register struct monst *mtmp;
{
	register schar tx,ty;

	/* spit fire only when both in a room or both in a corridor */
	if(inroom(u.ux,u.uy) != inroom(mtmp->mx,mtmp->my)) return;
	tx = u.ux - mtmp->mx;
	ty = u.uy - mtmp->my;
	if((!tx && abs(ty) < 8) || (!ty && abs(tx) < 8)
	    || (abs(tx) == abs(ty) && abs(tx) < 8)){
		/* spit fire in the direction of @ (not nec. hitting) */
		buzz(-1,mtmp->mx,mtmp->my,sgn(tx),sgn(ty));
		if(u.uhp < 1) done_in_by(mtmp);
	}
}

m_move(mtmp,after)
register struct monst *mtmp;
{
	register struct monst *mtmp2;
	register nx,ny,omx,omy,appr,nearer,cnt,i,j;
	xchar gx,gy,nix,niy,chcnt;
	schar chi;
	boolean likegold, likegems, likeobjs;
	schar mmoved = 0;	/* not strictly nec.: chi >= 0 will do */
	coord poss[9];
	int info[9];

	if(mtmp->mtrapped) {
		i = mintrap(mtmp);
		if(i == 2) return(2);	/* he died */
		if(i == 1) return(0);	/* still in trap, so didnt move */
	}
	if(mtmp->mhide && o_at(mtmp->mx,mtmp->my) && rn2(10))
		return(0);		/* do not leave hiding place */

	/* my dog gets a special treatment */
	if(mtmp->mtame) {
		return( dog_move(mtmp, after) );
	}

	/* likewise for shopkeeper */
	if(mtmp->isshk) {
		mmoved = shk_move();
		goto postmov;
	}

	/* and for the guard */
	if(mtmp->isgd) {
		mmoved = gd_move();
		goto postmov;
	}

	if(mtmp->data->mlet == 't' && !rn2(5)) {
		if(rn2(2))
			mnexto(mtmp);
		else
			rloc(mtmp);
		mmoved = 1;
		goto postmov;
	}
	if(mtmp->data->mlet == 'D' && !mtmp->mcan)
		inrange(mtmp);
	if(!Blind && !Confusion && mtmp->data->mlet == 'U' && !mtmp->mcan
		&& cansee(mtmp->mx,mtmp->my) && rn2(5)) {
		pline("%s's gaze has confused you!", Monnam(mtmp));
		if(rn2(5)) mtmp->mcan = 1;
		Confusion = d(3,4);		/* timeout */
	}
	if(!mtmp->mflee && u.uswallow && u.ustuck != mtmp) return(1);
	appr = 1;
	if(mtmp->mflee) appr = -1;
	if(mtmp->mconf || Invis ||  !mtmp->mcansee ||
		(index("BIy",mtmp->data->mlet) && !rn2(3)))
		appr = 0;
	omx = mtmp->mx;
	omy = mtmp->my;
	gx = u.ux;
	gy = u.uy;
	if(mtmp->data->mlet == 'L' && appr == 1 && mtmp->mgold > u.ugold)
		appr = -1;
#ifdef TRACK
	/* random criterion for 'smell'
	   should use mtmp->msmell
	 */
	if('a' <= mtmp->data->mlet && mtmp->data->mlet <= 'z') {
	extern coord *gettrack();
	register coord *cp;
	schar mroom;
		mroom = inroom(omx,omy);
		if(mroom < 0 || mroom != inroom(u.ux,u.uy)){
		    cp = gettrack(omx,omy);
		    if(cp){
			gx = cp->x;
			gy = cp->y;
		    }
		}
	}
#endif TRACK
	/* look for gold or jewels nearby */
	likegold = (index("LOD", mtmp->data->mlet) != NULL);
	likegems = (index("ODu", mtmp->data->mlet) != NULL);
	likeobjs = mtmp->mhide;
#define	SRCHRADIUS	25
	{ xchar mind = SRCHRADIUS;		/* not too far away */
	  register int dd;
	  if(likegold){
		register struct gen *gold;
		for(gold = fgold; gold; gold = gold->ngen)
		  if((dd = DIST(omx,omy,gold->gx,gold->gy)) < mind){
		    mind = dd;
		    gx = gold->gx;
		    gy = gold->gy;
		}
	  }
	  if(likegems || likeobjs){
		register struct obj *otmp;
		for(otmp = fobj; otmp; otmp = otmp->nobj)
		if(likeobjs || otmp->olet == GEM_SYM)
		if(mtmp->data->mlet != 'u' ||
			objects[otmp->otyp].g_val != 0)
		if((dd = DIST(omx,omy,otmp->ox,otmp->oy)) < mind){
		    mind = dd;
		    gx = otmp->ox;
		    gy = otmp->oy;
		}
	  }
	  if(mind < SRCHRADIUS && appr == -1) {
		if(dist(omx,omy) < 10) {
		    gx = u.ux;
		    gy = u.uy;
		} else
		    appr = 1;
	  }
	}
	nix = omx;
	niy = omy;
	cnt = mfndpos(mtmp,poss,info,
		mtmp->data->mlet == 'u' ? NOTONL :
		index(" VWZ", mtmp->data->mlet) ? NOGARLIC : ALLOW_TRAPS);
		/* ALLOW_ROCK for some monsters ? */
	chcnt = 0;
	chi = -1;
	for(i=0; i<cnt; i++) {
		nx = poss[i].x;
		ny = poss[i].y;
		for(j=0; j<MTSZ && j<cnt-1; j++)
			if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
				if(rn2(4*(cnt-j))) goto nxti;
#ifdef STUPID
		/* some stupid compilers think that this is too complicated */
		{ int d1 = DIST(nx,ny,gx,gy);
		  int d2 = DIST(nix,niy,gx,gy);
		  nearer = (d1 < d2);
		}
#else
		nearer = (DIST(nx,ny,gx,gy) < DIST(nix,niy,gx,gy));
#endif STUPID
		if((appr == 1 && nearer) || (appr == -1 && !nearer) ||
			!mmoved ||
			(!appr && !rn2(++chcnt))){
			nix = nx;
			niy = ny;
			chi = i;
			mmoved = 1;
		}
	nxti:	;
	}
	if(mmoved){
		if(info[chi] & ALLOW_M){
			mtmp2 = m_at(nix,niy);
			if(hitmm(mtmp,mtmp2) == 1 && rn2(4) &&
			  hitmm(mtmp2,mtmp) == 2) return(2);
			return(0);
		}
		if(info[chi] & ALLOW_U){
		  (void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd)+1);
		  return(0);
		}
		mtmp->mx = nix;
		mtmp->my = niy;
		for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
		mtmp->mtrack[0].x = omx;
		mtmp->mtrack[0].y = omy;
#ifndef NOWORM
		if(mtmp->wormno) worm_move(mtmp);
#endif NOWORM
	} else {
		if(mtmp->data->mlet == 'u' && rn2(2)){
			rloc(mtmp);
			return(0);
		}
#ifndef NOWORM
		if(mtmp->wormno) worm_nomove(mtmp);
#endif NOWORM
	}
postmov:
	if(mmoved == 1) {
		if(mintrap(mtmp) == 2)	/* he died */
			return(2);
		if(likegold) mpickgold(mtmp);
		if(likegems) mpickgems(mtmp);
		if(mtmp->mhide) mtmp->mundetected = 1;
	}
	pmon(mtmp);
	return(mmoved);
}

mpickgold(mtmp) register struct monst *mtmp; {
register struct gen *gold;
	while(gold = g_at(mtmp->mx, mtmp->my, fgold)){
		mtmp->mgold += gold->gflag;
		freegold(gold);
		if(levl[mtmp->mx][mtmp->my].scrsym == '$')
			newsym(mtmp->mx, mtmp->my);
	}
}

mpickgems(mtmp) register struct monst *mtmp; {
register struct obj *otmp;
	for(otmp = fobj; otmp; otmp = otmp->nobj)
	if(otmp->olet == GEM_SYM)
	if(otmp->ox == mtmp->mx && otmp->oy == mtmp->my)
	if(mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0){
		freeobj(otmp);
		mpickobj(mtmp, otmp);
		if(levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM)
			newsym(mtmp->mx, mtmp->my);	/* %% */
		return;	/* pick only one object */
	}
}

/* return number of acceptable neighbour positions */
mfndpos(mon,poss,info,flag)
register struct monst *mon; coord poss[9]; int info[9], flag; {
register int x,y,nx,ny,cnt = 0,tmp;
register struct monst *mtmp;
	x = mon->mx;
	y = mon->my;
	if(mon->mconf) {
		flag |= ALLOW_ALL;
		flag &= ~NOTONL;
	}
	for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++)
	if(nx != x || ny != y) if(isok(nx,ny))
	if((tmp = levl[nx][ny].typ) >= DOOR)
	if(!(nx != x && ny != y &&
		(levl[x][y].typ == DOOR || tmp == DOOR))){
		info[cnt] = 0;
		if(nx == u.ux && ny == u.uy){
			if(!(flag & ALLOW_U)) continue;
			info[cnt] = ALLOW_U;
		} else if(mtmp = m_at(nx,ny)){
			if(!(flag & ALLOW_M)) continue;
			info[cnt] = ALLOW_M;
			if(mtmp->mtame){
				if(!(flag & ALLOW_TM)) continue;
				info[cnt] |= ALLOW_TM;
			}
		}
		if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
			if(flag & NOGARLIC) continue;
			info[cnt] |= NOGARLIC;
		}
		if(sobj_at(SCR_SCARE_MONSTER, nx, ny) ||
		   (!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) {
			if(!(flag & ALLOW_SSM)) continue;
			info[cnt] |= ALLOW_SSM;
		}
		if(sobj_at(ENORMOUS_ROCK, nx, ny)) {
			if(!(flag & ALLOW_ROCK)) continue;
			info[cnt] |= ALLOW_ROCK;
		}
		if(!Invis && online(nx,ny)){
			if(flag & NOTONL) continue;
			info[cnt] |= NOTONL;
		}
		/* we cannot avoid traps of an unknown kind */
		{ register struct gen *gtmp = g_at(nx, ny, ftrap);
		  register int tt;
			if(gtmp) {
				tt = 1 << (gtmp->gflag & ~SEEN);
				if(mon->mtrapseen & tt){
					if(!(flag & tt)) continue;
					info[cnt] |= tt;
				}
			}
		}
		poss[cnt].x = nx;
		poss[cnt].y = ny;
		cnt++;
	}
	return(cnt);
}

dist(x,y) int x,y; {
	return((x-u.ux)*(x-u.ux) + (y-u.uy)*(y-u.uy));
}

poisoned(string, pname)
register char *string, *pname;
{
	if(Blind) pline("It was poisoned.");
	else pline("The %s was poisoned!",string);
	if(Poison_resistance) {
		pline("The poison doesn't seem to affect you.");
		return;
	}
	switch(rnd(6)) {
	case 1:
		u.uhp = -1;
		break;
	case 2:
	case 3:
	case 4:
		losestr(rn1(3,3));
		break;
	case 5:
	case 6:
		losehp(rn1(10,6), pname);
		return;
	}
	if(u.uhp < 1) killer = pname;
}

mondead(mtmp)
register struct monst *mtmp;
{
	relobj(mtmp,1);
	unpmon(mtmp);
	relmon(mtmp);
	if(u.ustuck == mtmp) {
		u.ustuck = 0;
		if(u.uswallow) {
			u.uswallow = 0;
			setsee();
			docrt();
		}
	}
	if(mtmp->isshk) shkdead();
	if(mtmp->isgd) gddead();
#ifndef NOWORM
	if(mtmp->wormno) wormdead(mtmp);
#endif NOWORM
	monfree(mtmp);
}

/* called when monster is moved to larger structure */
replmon(mtmp,mtmp2)
register struct monst *mtmp, *mtmp2;
{
	relmon(mtmp);
	monfree(mtmp);
	mtmp2->nmon = fmon;
	fmon = mtmp2;
}

relmon(mon)
register struct monst *mon;
{
	register struct monst *mtmp;

	if(mon == fmon) fmon = fmon->nmon;
	else {
		for(mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon) ;
		mtmp->nmon = mon->nmon;
	}
}

/* we do not free monsters immediately, in order to have their name
   available shortly after their demise */
struct monst *fdmon;	/* chain of dead monsters, need not to be saved */

monfree(mtmp) register struct monst *mtmp; {
	mtmp->nmon = fdmon;
	fdmon = mtmp;
}

dmonsfree(){
register struct monst *mtmp;
	while(mtmp = fdmon){
		fdmon = mtmp->nmon;
		free((char *) mtmp);
	}
}

killed(mtmp) struct monst *mtmp; {
#ifdef lint
#define	NEW_SCORING
#endif lint
register int tmp,tmp2,nk,x,y;
register struct permonst *mdat = mtmp->data;
	if(mtmp->cham) mdat = PM_CHAM;
	if(Blind) pline("You destroy it!");
	else {
		pline("You destroy %s!",
			mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp));
	}
	if(u.umconf) {
		if(!Blind) pline("Your hands stop glowing blue.");
		u.umconf = 0;
	}

	/* count killed monsters */
#define	MAXMONNO	100
	nk = 1;		      /* in case we cannot find it in mons */
	tmp = mdat - mons;    /* index in mons array (if not 'd', '@', ...) */
	if(tmp >= 0 && tmp < CMNUM+2) {
	    extern char fut_geno[];
	    u.nr_killed[tmp]++;
	    if((nk = u.nr_killed[tmp]) > MAXMONNO &&
		!index(fut_geno, mdat->mlet))
		    charcat(fut_geno,  mdat->mlet);
	}

	/* punish bad behaviour */
	if(mdat->mlet == '@') Telepat = 0, u.uluck -= 2;
	if(mtmp->mpeaceful || mtmp->mtame) u.uluck--;
	if(mdat->mlet == 'u') u.uluck -= 5;

	/* give experience points */
	tmp = 1 + mdat->mlevel * mdat->mlevel;
	if(mdat->ac < 3) tmp += 2*(7 - mdat->ac);
	if(index("AcsSDXaeRTVWU&In:P", mdat->mlet))
		tmp += 2*mdat->mlevel;
	if(index("DeV&P",mdat->mlet)) tmp += (7*mdat->mlevel);
	if(mdat->mlevel > 6) tmp += 50;

#ifdef NEW_SCORING
	/* ------- recent addition: make nr of points decrease
		   when this is not the first of this kind */
	{ int ul = u.ulevel;
	  int ml = mdat->mlevel;

	if(ul < 14)    /* points are given based on present and future level */
	    for(tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++)
		if(u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4<<(tmp2-1)))/nk
		    >= 10*pow((unsigned)(ul-1)))
			if(++ul == 14) break;

	tmp2 = ml - ul -1;
	tmp = (tmp + ((tmp2 < 0) ? 0 : 4<<tmp2))/nk;
	if(!tmp) tmp = 1;
	}
	/* note: ul is not necessarily the future value of u.ulevel */
	/* ------- end of recent valuation change ------- */
#endif NEW_SCORING

	u.uexp += tmp;
	u.urexp += 4*tmp;
	flags.botl = 1;
	while(u.ulevel < 14 && u.uexp >= 10*pow(u.ulevel-1)){
		pline("Welcome to level %d.", ++u.ulevel);
		tmp = rnd(10);
		if(tmp < 3) tmp = rnd(10);
		u.uhpmax += tmp;
		u.uhp += tmp;
		flags.botl = 1;
	}

	/* dispose of monster and make cadaver */
	x = mtmp->mx;	y = mtmp->my;
	mondead(mtmp);
	tmp = mdat->mlet;
	if(tmp == 'm') { /* he killed a minotaur, give him a wand of digging */
			/* note: the dead minotaur will be on top of it! */
		mksobj_at(WAND_SYM, WAN_DIGGING, x, y);
		/* if(cansee(x,y)) atl(x,y,fobj->olet); */
		stackobj(fobj);
	} else
#ifndef NOWORM
	if(tmp == 'w') {
		mksobj_at(WEAPON_SYM, WORM_TOOTH, x, y);
		stackobj(fobj);
	} else
#endif	NOWORM
	if(!letter(tmp) || !rn2(3)) tmp = 0;

	if(levl[x][y].typ >= DOOR)	/* might be mimic in wall */
	    if(x != u.ux || y != u.uy) /* might be here after swallowed */
		if(index("NTVm&",mdat->mlet) || rn2(5)) {
		mkobj_at(tmp,x,y);
		if(cansee(x,y)) atl(x,y,fobj->olet);
		stackobj(fobj);
	}
}

kludge(str,arg)
register char *str,*arg;
{
	if(Blind) {
		if(*str == '%') pline(str,"It");
		else pline(str,"it");
	} else pline(str,arg);
}

rescham()	/* force all chameleons to become normal */
{
	register struct monst *mtmp;

	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
		if(mtmp->cham) {
			mtmp->cham = 0;
			(void) newcham(mtmp,PM_CHAM);
		}
}

newcham(mtmp,mdat)	/* make a chameleon look like a new monster */
			/* returns 1 if the monster actually changed */
register struct monst *mtmp;
register struct permonst *mdat;
{
	register mhp, hpn, hpd;

	if(mdat == mtmp->data) return(0);	/* still the same monster */
#ifndef NOWORM
	if(mtmp->wormno) wormdead(mtmp);	/* throw tail away */
#endif NOWORM
	hpn = mtmp->mhp;
	hpd = (mtmp->data->mlevel)*8;
	if(!hpd) hpd = 4;
	mtmp->data = mdat;
	mhp = (mdat->mlevel)*8;
	/* new hp: same fraction of max as before */
	mtmp->mhp = 2 + (hpn*mhp)/hpd;
	hpn = mtmp->orig_hp;
	mtmp->orig_hp = 2 + (hpn*mhp)/hpd;
	mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0;
#ifndef NOWORM
	if(mdat->mlet == 'w' && getwn(mtmp)) initworm(mtmp);
#endif NOWORM
	unpmon(mtmp);	/* necessary for 'I' and to force pmon */
	pmon(mtmp);
	return(1);
}

mnexto(mtmp)	/* Make monster mtmp next to you (if possible) */
struct monst *mtmp;
{
	extern coord enexto();
	coord mm;
	mm = enexto(u.ux, u.uy);
	mtmp->mx = mm.x;
	mtmp->my = mm.y;
	pmon(mtmp);
}

rloc(mtmp)
struct monst *mtmp;
{
	register tx,ty;
	register char ch = mtmp->data->mlet;

#ifndef NOWORM
	if(ch == 'w' && mtmp->mx) return;	/* do not relocate worms */
#endif NOWORM
	do {
		tx = rn1(COLNO-3,2);
		ty = rn2(ROWNO);
	} while(!goodpos(tx,ty));
	mtmp->mx = tx;
	mtmp->my = ty;
	if(u.ustuck == mtmp){
		if(u.uswallow) {
			u.ux = tx;
			u.uy = ty;
			docrt();
		} else	u.ustuck = 0;
	}
	pmon(mtmp);
}

ishuman(mtmp) register struct monst *mtmp; {
	return(mtmp->data->mlet == '@');
}

setmangry(mtmp) register struct monst *mtmp; {
	if(!mtmp->mpeaceful) return;
	if(mtmp->mtame) return;
	mtmp->mpeaceful = 0;
	if(ishuman(mtmp)) pline("%s gets angry!", Monnam(mtmp));
}
//E*O*F hack.mon.c//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 9 (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.monst.c hack.o_init.c hack.objnam.c hack.onames.h hack.options.c hack.pri.c

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

#include "mklev.h"
#include "def.eshk.h"

struct permonst mons[CMNUM+2] = {
	{ "bat",		'B',1,22,8,1,4,0 },
	{ "gnome",		'G',1,6,5,1,6,0 },
	{ "hobgoblin",	'H',1,9,5,1,8,0 },
	{ "jackal",		'J',0,12,7,1,2,0 },
	{ "kobold",		'K',1,6,7,1,4,0 },
	{ "leprechaun",	'L',5,15,8,1,2,0 },
	{ "giant rat",	'r',0,12,7,1,3,0 },
	{ "acid blob",	'a',2,3,8,0,0,0 },
	{ "floating eye",	'E',2,1,9,0,0,0 },
	{ "homunculus",	'h',2,6,6,1,3,0 },
	{ "imp",		'i',2,6,2,1,4,0 },
	{ "orc",		'O',2,9,6,1,8,0 },
	{ "yellow light",	'y',3,15,0,0,0,0 },
	{ "zombie",		'Z',2,6,8,1,8,0 },
	{ "giant ant",		'A',3,18,3,1,6,0 },
	{ "fog cloud",		'f',3,1,0,1,6,0 },
	{ "nymph",		'N',6,12,9,1,2,0 },
	{ "piercer",		'p',3,1,3,2,6,0 },
	{ "quasit",		'Q',3,15,3,1,4,0 },
	{ "quivering blob",	'q',3,1,8,1,8,0 },
	{ "violet fungi",	'v',3,1,7,1,4,0 },
	{ "giant beetle",	'b',4,6,4,3,4,0 },
	{ "centaur",		'C',4,18,4,1,6,0 },
	{ "cockatrice",		'c',4,6,6,1,3,0 },
	{ "gelatinous cube",	'g',4,6,8,2,4,0 },
	{ "jaguar",		'j',4,15,6,1,8,0 },
	{ "killer bee",		'k',4,14,4,2,4,0 },
	{ "snake",		'S',4,15,3,1,6,0 },
	{ "freezing sphere",	'F',2,13,4,0,0,0 },
	{ "owlbear",		'o',5,12,5,2,6,0 },
	{ "rust monster",	'R',10,18,3,0,0,0 },
	{ "scorpion",		's',5,15,3,1,4,0 },
	{ "tengu",		't',5,13,5,1,7,0 },
	{ "wraith",		'W',5,12,5,1,6,0 },
#ifdef NOWORM
	{ "wumpus",		'w',8,3,2,3,6,0 },
#else
	{ "long worm",	'w',8,3,5,1,4,0 },
#endif NOWORM
	{ "large dog",	'd',6,15,4,2,4,0 },
	{ "leocrotta",	'l',6,18,4,3,6,0 },
	{ "mimic",		'M',7,3,7,3,4,0 },
	{ "troll",		'T',7,12,4,2,6,0 },
	{ "unicorn",		'u',8,24,5,1,10,0 },
	{ "yeti",		'Y',5,15,6,1,6,0 },
	{ "stalker",'I',8,12,3,4,4,0 },
	{ "umber hulk",	'U',9,6,2,2,10,0 },
	{ "vampire",	'V',8,12,1,1,6,0 },
	{ "xorn",		'X',8,9,-2,4,6,0 },
	{ "xan",		'x',7,18,-2,2,4,0 },
	{ "zruty",		'z',9,8,3,3,6,0 },
	{ "chameleon",		':',6,5,6,4,2,0 },
	{ "dragon",		'D',10,9,-1,3,8,0 },
	{ "ettin",		'e',10,12,3,2,8,0 },
	{ "lurker above",	'~',10,3,3,0,0,0 },
	{ "nurse",		'n',11,6,0,1,3,0 },
	{ "trapper",		',',12,3,3,0,0,0 },
	{ "purple worm",	'P',15,9,6,2,8,0 },
	{ "demon",		'&',10,9,-4,1,4,0 },
	{ "minotaur",		'm',15,15,6,4,8,0 },
	{ "shopkeeper", 	'@', 10, 18, 0, 4, 8, sizeof(struct eshk) }
};
//E*O*F hack.monst.c//

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

#include	"config.h"		/* for typedefs */
#include	"def.objects.h"

int
letindex(let) register char let; {
register int i = 0;
register char ch;
	while((ch = obj_symbols[i++]) != 0)
		if(ch == let) return(i);
	return(0);
}

init_objects(){
register int i, j, first, last, sum, end;
register char let, *tmp;
	/* init base; if probs given check that they add up to 100, 
	   otherwise compute probs; shuffle descriptions */
	end = sizeof(objects)/sizeof(objects[0]);
	first = 0;
	while( first < end ) {
		let = objects[first].oc_olet;
		last = first+1;
		while(last < end && objects[last].oc_olet == let
				&& objects[last].oc_name != NULL)
			last++;
		i = letindex(let);
		if((!i && let != ILLOBJ_SYM) || bases[i] != 0)
			panic("initialization error");
		bases[i] = first;
	check:
#ifdef MKLEV
#include	"hack.onames.h"
		if(let == GEM_SYM) {
			extern xchar dlevel;
			for(j=0; j < 9-dlevel/3; j++)
				objects[first+j].oc_prob = 0;
			first += j;
			if(first >= last || first >= LAST_GEM)
				printf("Not enough gems? - first=%d last=%d j=%d LAST_GEM=%d\n", first, last, j, LAST_GEM);
			for(j = first; j < LAST_GEM; j++)
			    objects[j].oc_prob = (20+j-first)/(LAST_GEM-first);
		}
#endif MKLEV
		sum = 0;
		for(j = first; j < last; j++) sum += objects[j].oc_prob;
		if(sum == 0) {
			for(j = first; j < last; j++)
			    objects[j].oc_prob = (100+j-first)/(last-first);
			goto check;
		}
		if(sum != 100)
#ifdef MKLEV
			panic
#else
			error
#endif MKLEV
				("init-prob error for %c", let);
		/* shuffling is rather meaningless in mklev, 
		   but we must update  last  anyway */
		if(objects[first].oc_descr != NULL && let != TOOL_SYM){
			/* shuffle, also some additional descriptions */
			while(last < end && objects[last].oc_olet == let)
				last++;
			j = last;
			while(--j > first) {
				i = first + rn2(j+1-first);
				tmp = objects[j].oc_descr;
				objects[j].oc_descr = objects[i].oc_descr;
				objects[i].oc_descr = tmp;
			}
		}
		first = last;
	}
}

probtype(let) register char let; {
register int i = bases[letindex(let)];
register int prob = rn2(100);
	while((prob -= objects[i].oc_prob) >= 0) i++;
	if(objects[i].oc_olet != let || !objects[i].oc_name)
		panic("probtype(%c) error, i=%d", let, i);
	return(i);
}

#ifndef MKLEV
#define SIZE(x) (sizeof x)/(sizeof x[0])
extern long *alloc();

savenames(fd) register fd; {
register int i;
unsigned len;
	bwrite(fd, (char *) bases, sizeof bases);
	bwrite(fd, (char *) objects, sizeof objects);
	/* as long as we use only one version of Hack/Quest we
	   need not save oc_name and oc_descr, but we must save
	   oc_uname for all objects */
	for(i=0; i < SIZE(objects); i++) {
		if(objects[i].oc_uname) {
			len = strlen(objects[i].oc_uname)+1;
			bwrite(fd, (char *) &len, sizeof len);
			bwrite(fd, objects[i].oc_uname, len);
		}
	}
}

restnames(fd) register fd; {
register int i;
unsigned len;
	mread(fd, (char *) bases, sizeof bases);
	mread(fd, (char *) objects, sizeof objects);
	for(i=0; i < SIZE(objects); i++) if(objects[i].oc_uname) {
		mread(fd, (char *) &len, sizeof len);
		objects[i].oc_uname = (char *) alloc(len);
		mread(fd, objects[i].oc_uname, len);
	}
}
#endif MKLEV
//E*O*F hack.o_init.c//

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

#include	"hack.h"
#define Sprintf (void) sprintf
#define Strcat  (void) strcat
#define	Strcpy	(void) strcpy
#define	PREFIX	15
extern char *eos();
extern int bases[];

char *
strprepend(s,pref) register char *s, *pref; {
register int i = strlen(pref);
	if(i > PREFIX) {
		pline("WARNING: prefix too short.");
		return(s);
	}
	s -= i;
	(void) strncpy(s, pref, i);	/* do not copy trailing 0 */
	return(s);
}

char *
sitoa(a) int a; {
static char buf[13];
	Sprintf(buf, (a < 0) ? "%d" : "+%d", a);
	return(buf);
}

char *
xname(obj)
register struct obj *obj;
{
static char bufr[BUFSZ];
register char *buf = &(bufr[PREFIX]);	/* leave room for "17 -3 " */
register int nn = objects[obj->otyp].oc_name_known;
register char *an = objects[obj->otyp].oc_name;
register char *dn = objects[obj->otyp].oc_descr;
register char *un = objects[obj->otyp].oc_uname;
register int pl = (obj->quan != 1);
	if(!obj->dknown && !Blind) obj->dknown = 1; /* %% doesnt belong here */
	switch(obj->olet) {
	case AMULET_SYM:
		Strcpy(buf, (obj->spe < 0 && obj->known)
			? "cheap plastic imitation of the " : "");
		Strcat(buf,"Amulet of Yendor");
		break;
	case TOOL_SYM:
		if(!nn) {
			Strcpy(buf, dn);
			break;
		}
		Strcpy(buf,an);
		break;
	case FOOD_SYM:
		if(obj->otyp == CLOVE_OF_GARLIC && pl) {
			pl = 0;
			Strcpy(buf, "cloves of garlic");
			break;
		}
		if(obj->otyp == DEAD_HOMUNCULUS && pl) {
			pl = 0;
			Strcpy(buf, "dead homunculi");
			break;
		}
		/* fungis ? */
		/* fall into next case */
	case WEAPON_SYM:
		if(obj->otyp == WORM_TOOTH && pl) {
			pl = 0;
			Strcpy(buf, "worm teeth");
			break;
		}
		if(obj->otyp == CRYSKNIFE && pl) {
			pl = 0;
			Strcpy(buf, "crysknives");
			break;
		}
		/* fall into next case */
	case ARMOR_SYM:
	case CHAIN_SYM:
	case ROCK_SYM:
		Strcpy(buf,an);
		break;
	case BALL_SYM:
		Sprintf(buf, "%sheavy iron ball",
		  (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
		break;
	case POTION_SYM:
		if(nn || un || !obj->dknown) {
			Strcpy(buf, "potion");
			if(pl) {
				pl = 0;
				Strcat(buf, "s");
			}
			if(!obj->dknown) break;
			if(un) {
				Strcat(buf, " called ");
				Strcat(buf, un);
			} else {
				Strcat(buf, " of ");
				Strcat(buf, an);
			}
		} else {
			Strcpy(buf, dn);
			Strcat(buf, " potion");
		}
		break;
	case SCROLL_SYM:
		Strcpy(buf, "scroll");
		if(pl) {
			pl = 0;
			Strcat(buf, "s");
		}
		if(!obj->dknown) break;
		if(nn) {
			Strcat(buf, " of ");
			Strcat(buf, an);
		} else if(un) {
			Strcat(buf, " called ");
			Strcat(buf, un);
		} else {
			Strcat(buf, " labeled ");
			Strcat(buf, dn);
		}
		break;
	case WAND_SYM:
		if(!obj->dknown)
			Sprintf(buf, "wand");
		else if(nn)
			Sprintf(buf, "wand of %s", an);
		else if(un)
			Sprintf(buf, "wand called %s", un);
		else
			Sprintf(buf, "%s wand", dn);
		break;
	case RING_SYM:
		if(!obj->dknown)
			Sprintf(buf, "ring");
		else if(nn)
			Sprintf(buf, "ring of %s", an);
		else if(un)
			Sprintf(buf, "ring called %s", un);
		else
			Sprintf(buf, "%s ring", dn);
		break;
	case GEM_SYM:
		if(!obj->dknown) {
			Strcpy(buf, "gem");
			break;
		}
		if(!nn) {
			Sprintf(buf, "%s gem", dn);
			break;
		}
		if(pl && !strncmp("worthless piece", an, 15)) {
			pl = 0;
			Sprintf(buf, "worthless pieces%s", an+15);
			break;
		}
		Strcpy(buf, an);
		if(obj->otyp >= TURQUOISE && obj->otyp <= JADE)
			Strcat(buf, " stone");
		break;
	default:
		Sprintf(buf,"glorkum %c (0%o) %d %d",
			obj->olet,obj->olet,obj->otyp,obj->spe);
	}
	if(pl) {
		register char *p = eos(buf)-1;
		if(*p == 's' || *p == 'z' || *p == 'x' ||
		    (*p == 'h' && p[-1] == 's'))
			Strcat(buf, "es");	/* boxes */
		else if(*p == 'y' && !index(vowels, p[-1]))
			Strcpy(p, "ies");	/* rubies, zruties */
		else
			Strcat(buf, "s");
	}
	if(obj->onamelth) {
		Strcat(buf, " named ");
		Strcat(buf, ONAME(obj));
	}
	return(buf);
}

char *
doname(obj)
register struct obj *obj;
{
char prefix[PREFIX];
register char *bp = xname(obj);
	if(obj->quan != 1)
		Sprintf(prefix, "%d ", obj->quan);
	else
		Strcpy(prefix, "a ");
	switch(obj->olet) {
	case AMULET_SYM:
		if(strncmp(bp, "cheap ", 6))
			Strcpy(prefix, "the ");
		break;
	case ARMOR_SYM:
		if(obj->owornmask & W_ARMOR)
			Strcat(bp, " (being worn)");
		if(obj->known) {
			Strcat(prefix,
			    sitoa(obj->spe - 10 + objects[obj->otyp].a_ac));
			Strcat(prefix, " ");
		}
		break;
	case WEAPON_SYM:
		if(obj->known) {
			Strcat(prefix, sitoa(obj->spe));
			Strcat(prefix, " ");
		}
		break;
	case WAND_SYM:
		if(obj->known)
			Sprintf(eos(bp), " (%d)", obj->spe);
		break;
	case RING_SYM:
		if(obj->owornmask & W_RINGR) Strcat(bp, " (on right hand)");
		if(obj->owornmask & W_RINGL) Strcat(bp, " (on left hand)");
		if(obj->known && (objects[obj->otyp].bits & SPEC)) {
			Strcat(prefix, sitoa(obj->spe));
			Strcat(prefix, " ");
		}
		break;
	}
	if(obj->owornmask & W_WEP)
		Strcat(bp, " (weapon in hand)");
	if(obj->unpaid)
		Strcat(bp, " (unpaid)");
	if(!strcmp(prefix, "a ") && index(vowels, *bp))
		Strcpy(prefix, "an ");
	bp = strprepend(bp, prefix);
	return(bp);
}

/* used only in hack.fight.c (thitu) */
setan(str,buf)
register char *str,*buf;
{
	if(index(vowels,*str))
		Sprintf(buf, "an %s", str);
	else
		Sprintf(buf, "a %s", str);
}

char *
aobjnam(otmp,verb) register struct obj *otmp; register char *verb; {
register char *bp = xname(otmp);
char prefix[PREFIX];
	if(otmp->quan != 1) {
		Sprintf(prefix, "%d ", otmp->quan);
		bp = strprepend(bp, prefix);
	}

	if(verb) {
		/* verb is given in plural (i.e., without trailing s) */
		Strcat(bp, " ");
		if(otmp->quan != 1)
			Strcat(bp, verb);
		else if(!strcmp(verb, "are"))
			Strcat(bp, "is");
		else {
			Strcat(bp, verb);
			Strcat(bp, "s");
		}
	}
	return(bp);
}

char *wrp[] = { "wand", "ring", "potion", "scroll", "gem" };
char wrpsym[] = { WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM };

struct obj *
readobjnam(bp) register char *bp; {
register char *p;
register int i;
int cnt, spe, spesgn, typ, heavy;
char let;
char *un, *dn, *an;
/* int the = 0; char *oname = 0; */
	cnt = spe = spesgn = typ = heavy = 0;
	let = 0;
	an = dn = un = 0;
	for(p = bp; *p; p++)
		if('A' <= *p && *p <= 'Z') *p += 'a'-'A';
	if(!strncmp(bp, "the ", 4)){
/*		the = 1; */
		bp += 4;
	} else if(!strncmp(bp, "an ", 3)){
		cnt = 1;
		bp += 3;
	} else if(!strncmp(bp, "a ", 2)){
		cnt = 1;
		bp += 2;
	}
	if(!cnt && digit(*bp)){
		cnt = atoi(bp);
		while(digit(*bp)) bp++;
		while(*bp == ' ') bp++;
	}
	if(!cnt) cnt = 1;		/* %% what with "gems" etc. ? */

	if(*bp == '+' || *bp == '-'){
		spesgn = (*bp++ == '+') ? 1 : -1;
		spe = atoi(bp);
		while(digit(*bp)) bp++;
		while(*bp == ' ') bp++;
	} else {
		p = rindex(bp, '(');
		if(p) {
			if(p > bp && p[-1] == ' ') p[-1] = 0;
			else *p = 0;
			p++;
			spe = atoi(p);
			while(digit(*p)) p++;
			if(strcmp(p, ")")) spe = 0;
			else spesgn = 1;
		}
	}
	/* now we have the actual name, as delivered by xname, say
		green potions called whisky
		scrolls labeled "QWERTY"
		egg
		dead zruties
		fortune cookies
		very heavy iron ball named hoei
		wand of wishing
		elven cloak
	*/
	for(p = bp; *p; p++) if(!strncmp(p, " named ", 7)) {
		*p = 0;
/*		oname = p+7; */
	}
	for(p = bp; *p; p++) if(!strncmp(p, " called ", 8)) {
		*p = 0;
		un = p+8;
	}
	for(p = bp; *p; p++) if(!strncmp(p, " labeled ", 9)) {
		*p = 0;
		dn = p+9;
	}

	/* first change to singular if necessary */
	if(cnt != 1) {
		/* find "cloves of garlic", "worthless pieces of blue glass" */
		for(p = bp; *p; p++) if(!strncmp(p, "s of ", 5)){
			while(*p = p[1]) p++;
			goto sing;
		}
		/* remove -s or -es (boxes) or -ies (rubies, zruties) */
		p = eos(bp);
		if(p[-1] == 's') {
			if(p[-2] == 'e') {
				if(p[-3] == 'i') {
					if(!strcmp(p-7, "cookies"))
						goto mins;
					Strcpy(p-3, "y");
					goto sing;
				}

				/* note: cloves / knives from clove / knife */
				if(!strcmp(p-6, "knives")) {
					Strcpy(p-3, "fe");
					goto sing;
				}

				/* note: nurses, axes but boxes */
				if(!strcmp(p-5, "boxes")) {
					p[-2] = 0;
					goto sing;
				}
			}
		mins:
			p[-1] = 0;
		} else {
			if(!strcmp(p-9, "homunculi")) {
				Strcpy(p-1, "us"); /* !! makes string longer */
				goto sing;
			}
			if(!strcmp(p-5, "teeth")) {
				Strcpy(p-5, "tooth");
				goto sing;
			}
			/* here we cannot find the plural suffix */
		}
	}
sing:
	if(!strcmp(bp, "amulet of yendor")) {
		typ = AMULET_OF_YENDOR;
		goto typfnd;
	}
	p = eos(bp);
	if(!strcmp(p-5, " mail")){	/* Note: ring mail is not a ring ! */
		let = ARMOR_SYM;
		an = bp;
		goto srch;
	}
	for(i = 0; i < sizeof(wrpsym); i++) {
		register int j = strlen(wrp[i]);
		if(!strncmp(bp, wrp[i], j)){
			let = wrpsym[i];
			bp += j;
			if(!strncmp(bp, " of ", 4)) an = bp+4;
			/* else if(*bp) ?? */
			goto srch;
		}
		if(!strcmp(p-j, wrp[i])){
			let = wrpsym[i];
			p -= j;
			*p = 0;
			if(p[-1] == ' ') p[-1] = 0;
			dn = bp;
			goto srch;
		}
	}
	if(!strcmp(p-6, " stone")){
		p[-6] = 0;
		let = GEM_SYM;
		an = bp;
		goto srch;
	}
	if(!strcmp(bp, "very heavy iron ball")){
		heavy = 1;
		typ = HEAVY_IRON_BALL;
		goto typfnd;
	}
	an = bp;
srch:
	if(!an && !dn && !un)
		goto any;
	i = 1;
	if(let) i = bases[letindex(let)];
	while(i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)){
		if(an && strcmp(an, objects[i].oc_name))
			goto nxti;
		if(dn && strcmp(dn, objects[i].oc_descr))
			goto nxti;
		if(un && strcmp(un, objects[i].oc_uname))
			goto nxti;
		typ = i;
		goto typfnd;
	nxti:
		i++;
	}
any:
	if(!let) let = wrpsym[rn2(sizeof(wrpsym))];
	typ = probtype(let);
typfnd:
	{ register struct obj *otmp;
	  extern struct obj *mksobj();
	let = objects[typ].oc_olet;
	if(let == FOOD_SYM && typ >= CORPSE)
	    let = typ-CORPSE+'@'+((typ > CORPSE + 'Z' - '@') ? 'a'-'Z'-1 : 0);
	otmp = mksobj(let, typ);
	if(heavy)
		otmp->owt += 15;
	if(cnt > 0 && index("%?!*)", let) &&
		(cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20)))
		otmp->quan = cnt;
	if(spesgn == -1)
		otmp->cursed = 1;
	if(spe > 3 && spe > otmp->spe)
		spe = 0;
	else if(let == WAND_SYM)
		spe = otmp->spe;
	if(spe == 3 && u.uluck < 0)
		spesgn = -1;
	if(let != WAND_SYM && spesgn == -1)
		spe = -spe;
	if(let == BALL_SYM)
		spe = 0;
	else if(let == AMULET_SYM)
		spe = -1;
	else if(typ == WAN_WISHING && rn2(10))
		spe = 0;
	else if(let == ARMOR_SYM) {
		spe += 10 - objects[typ].a_ac;
		if(spe > 5 && rn2(spe - 5))
			otmp->cursed = 1;
	}
	otmp->spe = spe;
	return(otmp);
	}
}
//E*O*F hack.objnam.c//

echo x - hack.onames.h
cat > "hack.onames.h" << '//E*O*F hack.onames.h//'
#define	STRANGE_OBJECT	0
#define	AMULET_OF_YENDOR	1
#define	FOOD_RATION	2
#define	TRIPE_RATION	3
#define	PANCAKE	4
#define	DEAD_LIZARD	5
#define	FORTUNE_COOKIE	6
#define	CARROT	7
#define	TIN	8
#define	ORANGE	9
#define	APPLE	10
#define	PEAR	11
#define	MELON	12
#define	BANANA	13
#define	CANDY_BAR	14
#define	EGG	15
#define	CLOVE_OF_GARLIC	16
#define	DEAD_HUMAN	17
#define	DEAD_GIANT_ANT	18
#define	DEAD_GIANT_BAT	19
#define	DEAD_CENTAUR	20
#define	DEAD_DRAGON	21
#define	DEAD_FLOATING_EYE	22
#define	DEAD_FREEZING_SPHERE	23
#define	DEAD_GNOME	24
#define	DEAD_HOBGOBLIN	25
#define	DEAD_STALKER	26
#define	DEAD_JACKAL	27
#define	DEAD_KOBOLD	28
#define	DEAD_LEPRECHAUN	29
#define	DEAD_MIMIC	30
#define	DEAD_NYMPH	31
#define	DEAD_ORC	32
#define	DEAD_PURPLE_WORM	33
#define	DEAD_QUASIT	34
#define	DEAD_RUST_MONSTER	35
#define	DEAD_SNAKE	36
#define	DEAD_TROLL	37
#define	DEAD_UMBER_HULK	38
#define	DEAD_VAMPIRE	39
#define	DEAD_WRAITH	40
#define	DEAD_XORN	41
#define	DEAD_YETI	42
#define	DEAD_ZOMBIE	43
#define	DEAD_ACID_BLOB	44
#define	DEAD_GIANT_BEETLE	45
#define	DEAD_COCKATRICE	46
#define	DEAD_DOG	47
#define	DEAD_ETTIN	48
#define	DEAD_FOG_CLOUD	49
#define	DEAD_GELATINOUS_CUBE	50
#define	DEAD_HOMUNCULUS	51
#define	DEAD_IMP	52
#define	DEAD_JAGUAR	53
#define	DEAD_KILLER_BEE	54
#define	DEAD_LEOCROTTA	55
#define	DEAD_MINOTAUR	56
#define	DEAD_NURSE	57
#define	DEAD_OWLBEAR	58
#define	DEAD_PIERCER	59
#define	DEAD_QUIVERING_BLOB	60
#define	DEAD_GIANT_RAT	61
#define	DEAD_GIANT_SCORPION	62
#define	DEAD_TENGU	63
#define	DEAD_UNICORN	64
#define	DEAD_VIOLET_FUNGI	65
#define	DEAD_LONG_WORM	66
#define	DEAD_XAN	67
#define	DEAD_YELLOW_LIGHT	68
#define	DEAD_ZRUTY	69
#define	ARROW	70
#define	SLING_BULLET	71
#define	CROSSBOW_BOLT	72
#define	DART	73
#define	ROCK	74
#define	BOOMERANG	75
#define	MACE	76
#define	AXE	77
#define	FLAIL	78
#define	LONG_SWORD	79
#define	TWO_HANDED_SWORD	80
#define	DAGGER	81
#define	WORM_TOOTH	82
#define	CRYSKNIFE	83
#define	SPEAR	84
#define	BOW	85
#define	SLING	86
#define	CROSSBOW	87
#define	WHISTLE	88
#define	MAGIC_WHISTLE	89
#define	EXPENSIVE_CAMERA	90
#define	ICE_BOX	91
#define	HEAVY_IRON_BALL	92
#define	IRON_CHAIN	93
#define	ENORMOUS_ROCK	94
#define	HELMET	95
#define	PLATE_MAIL	96
#define	SPLINT_MAIL	97
#define	BANDED_MAIL	98
#define	CHAIN_MAIL	99
#define	SCALE_MAIL	100
#define	RING_MAIL	101
#define	STUDDED_LEATHER_ARMOR	102
#define	LEATHER_ARMOR	103
#define	ELVEN_CLOAK	104
#define	SHIELD	105
#define	PAIR_OF_GLOVES	106
#define	POT_RESTORE_STRENGTH	107
#define	POT_BOOZE	108
#define	POT_INVISIBILITY	109
#define	POT_FRUIT_JUICE	110
#define	POT_HEALING	111
#define	POT_PARALYSIS	112
#define	POT_MONSTER_DETECTION	113
#define	POT_OBJECT_DETECTION	114
#define	POT_SICKNESS	115
#define	POT_CONFUSION	116
#define	POT_GAIN_STRENGTH	117
#define	POT_SPEED	118
#define	POT_BLINDNESS	119
#define	POT_GAIN_LEVEL	120
#define	POT_EXTRA_HEALING	121
#define	POT_LEVITATION	122
#define	SCR_ENCHANT_ARMOR	127
#define	SCR_DESTROY_ARMOR	128
#define	SCR_CONFUSE_MONSTER	129
#define	SCR_SCARE_MONSTER	130
#define	SCR_BLANK_PAPER	131
#define	SCR_REMOVE_CURSE	132
#define	SCR_ENCHANT_WEAPON	133
#define	SCR_DAMAGE_WEAPON	134
#define	SCR_CREATE_MONSTER	135
#define	SCR_TAMING	136
#define	SCR_GENOCIDE	137
#define	SCR_LIGHT	138
#define	SCR_TELEPORTATION	139
#define	SCR_GOLD_DETECTION	140
#define	SCR_FOOD_DETECTION	141
#define	SCR_IDENTIFY	142
#define	SCR_MAGIC_MAPPING	143
#define	SCR_AMNESIA	144
#define	SCR_FIRE	145
#define	SCR_PUNISHMENT	146
#define	WAN_LIGHT	151
#define	WAN_SECRET_DOOR_DETECTION	152
#define	WAN_CREATE_MONSTER	153
#define	WAN_WISHING	154
#define	WAN_STRIKING	155
#define	WAN_SLOW_MONSTER	156
#define	WAN_SPEED_MONSTER	157
#define	WAN_UNDEAD_TURNING	158
#define	WAN_POLYMORPH	159
#define	WAN_CANCELLATION	160
#define	WAN_TELEPORT_MONSTER	161
#define	WAN_MAKE_INVISIBLE	162
#define	WAN_DIGGING	163
#define	WAN_MAGIC_MISSILE	164
#define	WAN_FIRE	165
#define	WAN_SLEEP	166
#define	WAN_COLD	167
#define	WAN_DEATH	168
#define	Adornment	u.uprops[0].p_flgs
#define	RIN_ADORNMENT	172
#define	Teleportation	u.uprops[1].p_flgs
#define	RIN_TELEPORTATION	173
#define	Regeneration	u.uprops[2].p_flgs
#define	RIN_REGENERATION	174
#define	Searching	u.uprops[3].p_flgs
#define	RIN_SEARCHING	175
#define	See_invisible	u.uprops[4].p_flgs
#define	RIN_SEE_INVISIBLE	176
#define	Stealth	u.uprops[5].p_flgs
#define	RIN_STEALTH	177
#define	Levitation	u.uprops[6].p_flgs
#define	RIN_LEVITATION	178
#define	Poison_resistance	u.uprops[7].p_flgs
#define	RIN_POISON_RESISTANCE	179
#define	Aggravate_monster	u.uprops[8].p_flgs
#define	RIN_AGGRAVATE_MONSTER	180
#define	Hunger	u.uprops[9].p_flgs
#define	RIN_HUNGER	181
#define	Fire_resistance	u.uprops[10].p_flgs
#define	RIN_FIRE_RESISTANCE	182
#define	Cold_resistance	u.uprops[11].p_flgs
#define	RIN_COLD_RESISTANCE	183
#define	Protection_from_shape_changers	u.uprops[12].p_flgs
#define	RIN_PROTECTION_FROM_SHAPE_CHANGERS	184
#define	Conflict	u.uprops[13].p_flgs
#define	RIN_CONFLICT	185
#define	Gain_strength	u.uprops[14].p_flgs
#define	RIN_GAIN_STRENGTH	186
#define	Increase_damage	u.uprops[15].p_flgs
#define	RIN_INCREASE_DAMAGE	187
#define	Protection	u.uprops[16].p_flgs
#define	RIN_PROTECTION	188
#define	Warning	u.uprops[17].p_flgs
#define	RIN_WARNING	189
#define	Teleport_control	u.uprops[18].p_flgs
#define	RIN_TELEPORT_CONTROL	190
#define	DIAMOND	193
#define	RUBY	194
#define	SAPPHIRE	195
#define	EMERALD	196
#define	TURQUOISE	197
#define	AQUAMARINE	198
#define	TOURMALINE	199
#define	TOPAZ	200
#define	OPAL	201
#define	GARNET	202
#define	AMETHYST	203
#define	AGATE	204
#define	ONYX	205
#define	JASPER	206
#define	JADE	207
/* #define WORTHLESS_PIECE_OF_BLUE_GLASS	208 */
/* #define WORTHLESS_PIECE_OF_RED_GLASS	209 */
/* #define WORTHLESS_PIECE_OF_YELLOW_GLASS	210 */
/* #define WORTHLESS_PIECE_OF_GREEN_GLASS	211 */

#define	CORPSE	DEAD_HUMAN
#define	LAST_GEM	(JADE+1)
#define	LAST_RING	19
#define	NROFOBJECTS	211
//E*O*F hack.onames.h//

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

#include "config.h"
#ifdef OPTIONS
#include "hack.h"

doset()
{
	register flg = 1;
	char buf[BUFSZ];
	register char *str;

	pline("What option do you want to set? [(!)eo] ");
	getlin(buf);
	str = buf;
	while(*str == ' ') str++;
	if(*str == '!') {
		flg = 0;
		str++;
	}
	switch(*str) {
	case 'e':
		flags.echo = flg;
		if(flg) echo(ON);
		else echo(OFF);
		break;
	case 'o':
		flags.oneline = flg;
		break;
	default:
		pline("Unknown option '%s'",str);
	}
	return(0);
}
#endif OPTIONS
//E*O*F hack.options.c//

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

#include "hack.h"
#include <stdio.h>
xchar scrlx, scrhx, scrly, scrhy;	/* corners of new area on screen */

extern char *hu_stat[];	/* in eat.c */

swallowed()
{
	char *ulook = "|@|";
	ulook[1] = u.usym;

	cls();
	curs(u.ux-1, u.uy+1);
	fputs("/-\\", stdout);
	curx = u.ux+2;
	curs(u.ux-1, u.uy+2);
	fputs(ulook, stdout);
	curx = u.ux+2;
	curs(u.ux-1, u.uy+3);
	fputs("\\-/", stdout);
	curx = u.ux+2;
	u.udispl = 1;
	u.udisx = u.ux;
	u.udisy = u.uy;
}


/*VARARGS1*/
boolean panicking;

panic(str,a1,a2,a3,a4,a5,a6)
char *str;
{
	if(panicking++) exit(1);	/* avoid loops */
	home();
	puts(" Suddenly, the dungeon collapses.");
	fputs(" ERROR:  ",stdout);
	printf(str,a1,a2,a3,a4,a5,a6);
	if(fork())
		done("panic");
	else
		abort();	/* generate core dump */
}

atl(x,y,ch)
register x,y;
{
	register struct rm *crm = &levl[x][y];

	if(x<0 || x>COLNO-1 || y<0 || y>ROWNO-1)
		panic("at(%d,%d,%c_%o_)",x,y,ch,ch);
	if(crm->seen && crm->scrsym == ch) return;
	crm->scrsym = ch;
	crm->new = 1;
	on_scr(x,y);
}

on_scr(x,y)
register x,y;
{
	if(x<scrlx) scrlx = x;
	if(x>scrhx) scrhx = x;
	if(y<scrly) scrly = y;
	if(y>scrhy) scrhy = y;
}

/* call: (x,y) - display
	(-1,0) - close (leave last symbol)
	(-1,-1)- close (undo last symbol)
	(-1,let)-open: initialize symbol
	(-2,let)-change let
*/

tmp_at(x,y) schar x,y; {
static schar prevx, prevy;
static char let;
	if((int)x == -2){	/* change let call */
		let = y;
		return;
	}
	if((int)x == -1 && (int)y >= 0){	/* open or close call */
		let = y;
		prevx = -1;
		return;
	}
	if(prevx >= 0 && cansee(prevx,prevy)) {
		delay_output();
		prl(prevx, prevy);	/* in case there was a monster */
		at(prevx, prevy, levl[prevx][prevy].scrsym);
	}
	if(x >= 0){	/* normal call */
		if(cansee(x,y)) at(x,y,let);
		prevx = x;
		prevy = y;
	} else {	/* close call */
		let = 0;
		prevx = -1;
	}
}

/* like the previous, but the symbols are first erased on completion */
Tmp_at(x,y) schar x,y; {
static char let;
static xchar cnt;
static coord tc[COLNO];		/* but watch reflecting beams! */
register xx,yy;
	if((int)x == -1) {
		if(y > 0) {	/* open call */
			let = y;
			cnt = 0;
			return;
		}
		/* close call (do not distinguish y==0 and y==-1) */
		while(cnt--) {
			xx = tc[cnt].x;
			yy = tc[cnt].y;
			prl(xx, yy);
			at(xx, yy, levl[xx][yy].scrsym);
		}
		cnt = let = 0;	/* superfluous */
		return;
	}
	if((int)x == -2) {	/* change let call */
		let = y;
		return;
	}
	/* normal call */
	if(cansee(x,y)) {
		if(cnt) delay_output();
		at(x,y,let);
		tc[cnt].x = x;
		tc[cnt].y = y;
		if(++cnt >= COLNO) panic("Tmp_at overflow?");
		levl[x][y].new = 0;	/* prevent pline-nscr erasing --- */
	}
}

at(x,y,ch)
register xchar x,y;
char ch;
{
#ifndef lint
	/* if xchar is unsigned, lint will complain about  if(x < 0)  */
	if(x < 0 || x > COLNO-1 || y < 0 || y > ROWNO-1)
		panic("At gets 0%o at %d %d(%d %d)",ch,x,y,u.ux,u.uy);
#endif lint
	if(!ch) {
		home();
		printf("At gets null at %2d %2d.",x,y);
		curx = ROWNO+1;
		return;
	}
	y += 2;
	curs(x,y);
	(void) putchar(ch);
	curx++;
}

prme(){
	if(!Invis) at(u.ux,u.uy,u.usym);
}

docrt()
{
	register x,y;
	register struct rm *room;
	register struct monst *mtmp;

	if(u.uswallow) {
		swallowed();
		return;
	}
	cls();
	if(!Invis){
		levl[(u.udisx = u.ux)][(u.udisy = u.uy)].scrsym = u.usym;
		levl[u.udisx][u.udisy].seen = 1;
		u.udispl = 1;
	} else	u.udispl = 0;

	/* %% - is this really necessary? */
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
		if(mtmp->mdispl && !(room = &levl[mtmp->mx][mtmp->my])->new &&
		   !room->seen)
			mtmp->mdispl = 0;

	for(y = 0; y < ROWNO; y++)
		for(x = 0; x < COLNO; x++)
			if((room = &levl[x][y])->new) {
				room->new = 0;
				at(x,y,room->scrsym);
			} else if(room->seen) at(x,y,room->scrsym);
	scrlx = COLNO;
	scrly = ROWNO;
	scrhx = scrhy = 0;
	flags.botlx = 1;
	bot();
}

docorner(xmin,ymax) register xmin,ymax; {
	register x,y;
	register struct rm *room;
	if(u.uswallow) {	/* Can be done more efficiently */
		swallowed();
		return;
	}
	for(y = 0; y < ymax; y++) {
		curs(xmin,y+2);
		cl_end();
		for(x = xmin; x < COLNO; x++) {
			if((room = &levl[x][y])->new) {
				room->new = 0;
				at(x,y,room->scrsym);
			} else if(room->seen) at(x,y,room->scrsym);
		}
	}
}

pru()
{
	if(u.udispl && (Invis || u.udisx != u.ux || u.udisy != u.uy))
		/* if(! levl[u.udisx][u.udisy].new) */
			if(!vism_at(u.udisx, u.udisy))
				newsym(u.udisx, u.udisy);
	if(Invis) {
		u.udispl = 0;
		prl(u.ux,u.uy);
	} else
	if(!u.udispl || u.udisx != u.ux || u.udisy != u.uy) {
		atl(u.ux, u.uy, u.usym);
		u.udispl = 1;
		u.udisx = u.ux;
		u.udisy = u.uy;
	}
	levl[u.ux][u.uy].seen = 1;
}

#ifndef NOWORM
#include	"def.wseg.h"
extern struct wseg *m_atseg;
#endif NOWORM

/* print a position that is visible for @ */
prl(x,y)
{
	register struct rm *room;
	register struct monst *mtmp;
	register struct obj *otmp;

	if(x == u.ux && y == u.uy && !Invis) {
		pru();
		return;
	}
	room = &levl[x][y];
	if((!room->typ) || (room->typ<DOOR && levl[u.ux][u.uy].typ == CORR))
		return;
	if((mtmp = m_at(x,y)) && !mtmp->mhide &&
		(!mtmp->minvis || See_invisible)) {
#ifndef NOWORM
		if(m_atseg)
			pwseg(m_atseg);
		else
#endif NOWORM
		pmon(mtmp);
	}
	else if(otmp = o_at(x,y))
		atl(x,y,otmp->olet);
	else if(mtmp && (!mtmp->minvis || See_invisible)) {
		/* must be a hiding monster, but not hiding right now */
		/* assume for the moment that long worms do not hide */
		pmon(mtmp);
	}
	else if(g_at(x,y,fgold)) atl(x,y,'$');
	else if(!room->seen || room->scrsym == ' ') {
		room->new = room->seen = 1;
		newsym(x,y);
		on_scr(x,y);
	}
	room->seen = 1;
}

char
news0(x,y)
register xchar x,y;
{
	register struct obj *otmp;
	register struct gen *gtmp;
	struct rm *room;
	register char tmp;

	room = &levl[x][y];
	if(!room->seen) tmp = ' ';
	else if(!Blind && (otmp = o_at(x,y))) tmp = otmp->olet;
	else if(!Blind && g_at(x,y,fgold)) tmp = '$';
	else if(x == xupstair && y == yupstair) tmp = '<';
	else if(x == xdnstair && y == ydnstair) tmp = '>';
	else if((gtmp = g_at(x,y,ftrap)) && (gtmp->gflag & SEEN)) tmp = '^';
	else switch(room->typ) {
	case SCORR:
	case SDOOR:
		tmp = room->scrsym;	/* %% wrong after killing mimic ! */
		break;
	case HWALL:
		tmp = '-';
		break;
	case VWALL:
		tmp = '|';
		break;
	case LDOOR:
	case DOOR:
		tmp = '+';
		break;
	case CORR:
		tmp = CORR_SYM;
		break;
	case ROOM:
		if(room->lit || cansee(x,y) || Blind) tmp = '.';
		else tmp = ' ';
		break;
	default: tmp = ERRCHAR;
	}
	return(tmp);
}

newsym(x,y)
register x,y;
{
	atl(x,y,news0(x,y));
}

/* used with wand of digging: fill scrsym and force display */
mnewsym(x,y) register x,y; {
register struct monst *mtmp = m_at(x,y);
	if(!mtmp || (mtmp->minvis && !See_invisible) ||
		    (mtmp->mhide && o_at(x,y))){
		levl[x][y].scrsym = news0(x,y);
		levl[x][y].seen = 0;
	}
}

nosee(x,y)
register x,y;
{
	register struct rm *room;

	room = &levl[x][y];
	if(room->scrsym == '.' && !room->lit && !Blind) {
		room->scrsym = ' ';
		room->new = 1;
		on_scr(x,y);
	}
}

#ifndef QUEST
prl1(x,y)
register x,y;
{
	if(u.dx) {
		if(u.dy) {
			prl(x-(2*u.dx),y);
			prl(x-u.dx,y);
			prl(x,y);
			prl(x,y-u.dy);
			prl(x,y-(2*u.dy));
		} else {
			prl(x,y-1);
			prl(x,y);
			prl(x,y+1);
		}
	} else {
		prl(x-1,y);
		prl(x,y);
		prl(x+1,y);
	}
}

nose1(x,y)
register x,y;
{
	if(u.dx) {
		if(u.dy) {
			nosee(x,u.uy);
			nosee(x,u.uy-u.dy);
			nosee(x,y);
			nosee(u.ux-u.dx,y);
			nosee(u.ux,y);
		} else {
			nosee(x,y-1);
			nosee(x,y);
			nosee(x,y+1);
		}
	} else {
		nosee(x-1,y);
		nosee(x,y);
		nosee(x+1,y);
	}
}
#endif QUEST

vism_at(x,y) register x,y; {
register struct monst *mtmp;
register int csi = See_invisible;
	return((x == u.ux && y == u.uy && (!Invis || csi)) ? 1 :
		((mtmp = m_at(x,y)) && (!mtmp->minvis || csi) &&
			(!mtmp->mhide || !o_at(mtmp->mx,mtmp->my)))
		? cansee(x,y) : 0);
}

#ifdef NEWSCR
pobj(obj) register struct obj *obj; {
register int show = (!obj->oinvis || See_invisible) &&
		cansee(obj->ox,obj->oy);
	if(obj->odispl){
		if(obj->odx != obj->ox || obj->ody != obj->oy || !show)
		if(!vism_at(obj->odx,obj->ody)){
			newsym(obj->odx, obj->ody);
			obj->odispl = 0;
		}
	}
	if(show && !vism_at(obj->ox,obj->oy)){
		atl(obj->ox,obj->oy,obj->olet);
		obj->odispl = 1;
		obj->odx = obj->ox;
		obj->ody = obj->oy;
	}
}
#endif NEWSCR

unpobj(obj) register struct obj *obj; {
/* 	if(obj->odispl){
		if(!vism_at(obj->odx, obj->ody))
			newsym(obj->odx, obj->ody);
		obj->odispl = 0;
	}
*/
	if(!vism_at(obj->ox,obj->oy))
		newsym(obj->ox,obj->oy);
}

seeobjs(){
register struct obj *obj, *obj2;
	for(obj = fobj; obj; obj = obj2) {
		obj2 = obj->nobj;
		if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
			&& obj->age + 250 < moves)
				delobj(obj);
	}
	for(obj = invent; obj; obj = obj2) {
		obj2 = obj->nobj;
		if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
			&& obj->age + 250 < moves)
				useup(obj);
	}
}

seemons(){
register struct monst *mtmp;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
		pmon(mtmp);
#ifndef NOWORM
		if(mtmp->wormno) wormsee(mtmp->wormno);
#endif NOWORM
	}
}

pmon(mon) register struct monst *mon; {
register int show =
	((!mon->minvis || See_invisible) &&
		(!mon->mhide || !o_at(mon->mx,mon->my)) &&
		cansee(mon->mx,mon->my))
	 || (Blind && Telepat);
	if(mon->mdispl){
		if(mon->mdx != mon->mx || mon->mdy != mon->my || !show)
			unpmon(mon);
	}
	if(show && !mon->mdispl){
		atl(mon->mx,mon->my,
		  mon->mimic ? mon->mimic : mon->data->mlet);
		mon->mdispl = 1;
		mon->mdx = mon->mx;
		mon->mdy = mon->my;
	}
}

unpmon(mon) register struct monst *mon; {
	if(mon->mdispl){
		newsym(mon->mdx, mon->mdy);
		mon->mdispl = 0;
	}
}

nscr()
{
	register x,y;
	register struct rm *room;

	if(u.uswallow || u.ux == FAR || flags.nscrinh) return;
	pru();
	for(y = scrly; y <= scrhy; y++)
		for(x = scrlx; x <= scrhx; x++)
			if((room = &levl[x][y])->new) {
				room->new = 0;
				at(x,y,room->scrsym);
			}
	scrhx = scrhy = 0;
	scrlx = COLNO;
	scrly = ROWNO;
}

char oldbot[100], newbot[100];		/* 100 >= COLNO */
bot()
{
register char *ob = oldbot, *nb = newbot;
register int i;
	if(flags.botlx) *ob = 0;
	flags.botl = flags.botlx = 0;
	(void) sprintf(newbot, "Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Str ",
		dlevel, u.ugold, u.uhp, u.uhpmax, u.uac);
	if(u.ustr>18) {
		if(u.ustr>117) (void) strcat(newbot,"18/**");
		else (void) sprintf(newbot + strlen(newbot), "18/%02d",u.ustr-18);
	} else (void) sprintf(newbot + strlen(newbot), "%-2d   ",u.ustr);
	(void) sprintf(newbot + strlen(newbot), "  Exp %2d/%-5lu ", u.ulevel,u.uexp);
	(void) strcat(newbot, hu_stat[u.uhs]);
	for(i = 1; i<COLNO; i++) {
		if(*ob != *nb){
			curs(i,ROWNO+2);
			(void) putchar(*nb ? *nb : ' ');
			curx++;
		}
		if(*ob) ob++;
		if(*nb) nb++;
	}
	(void) strcpy(oldbot, newbot);
}

#ifdef WAN_PROBING
mstatusline(mtmp) register struct monst *mtmp; {
	pline("Status of %s: ", monnam(mtmp));
	pline("Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Dam %d",
	    mtmp->data->mlevel, mtmp->mgold, mtmp->mhp, mtmp->orig_hp,
	    mtmp->data->ac, (mtmp->data->damn + 1) * (mtmp->data->damd + 1));
}
#endif WAN_PROBING

cls(){
	if(flags.topl == 1)
		more();
	flags.topl = 0;

	clear_screen();

	flags.botlx = 1;
}
//E*O*F hack.pri.c//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# This is part 10 (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.read.c hack.rip.c hack.rumors.c hack.save.c hack.search.c hack.sh

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

#include "hack.h"

extern struct monst *makemon();
int identify();

doread() {
	register struct obj *scroll;
	register boolean confused = (Confusion != 0);
	register boolean known = FALSE;

	scroll = getobj("?", "read");
	if(!scroll) return(0);
	if(!scroll->dknown && Blind) {
	    pline("Being blind, you cannot read the formula on the scroll.");
	    return(0);
	}
	if(Blind)
	  pline("As you pronounce the formula on it, the scroll disappears.");
	else
	  pline("As you read the scroll, it disappears.");
	if(confused)
	  pline("Being confused, you mispronounce the magic words ... ");

	switch(scroll->otyp) {

	case SCR_ENCHANT_ARMOR:
	    {	extern struct obj *some_armor();
		register struct obj *otmp = some_armor();
		if(!otmp) {
			strange_feeling(scroll);
			return(1);
		}
		if(confused) {
			pline("Your %s glows silver for a moment.",
				objects[otmp->otyp].oc_name);
			otmp->rustfree = 1;
			break;
		}
		if(otmp->spe*2 + objects[otmp->otyp].a_ac > 23 &&
			!rn2(3)) {
	pline("Your %s glows violently green for a while, then evaporates.",
			objects[otmp->otyp].oc_name);
			useup(otmp);
			break;
		}
		pline("Your %s glows green for a moment.",
			objects[otmp->otyp].oc_name);
		otmp->cursed = 0;
		otmp->spe++;
		break;
	    }
	case SCR_DESTROY_ARMOR:
		if(confused) {
			register struct obj *otmp = some_armor();
			if(!otmp) {
				strange_feeling(scroll);
				return(1);
			}
			pline("Your %s glows purple for a moment.",
				objects[otmp->otyp].oc_name);
			otmp->rustfree = 0;
			break;
		}
		if(uarm) {
		    pline("Your armor turns to dust and falls to the floor!");
		    useup(uarm);
		} else if(uarmh) {
		    pline("Your helmet turns to dust and is blown away!");
		    useup(uarmh);
		} else if(uarmg) {
			pline("Your gloves vanish!");
			useup(uarmg);
			selftouch("You");
		} else {
			strange_feeling(scroll);
			return(1);
		}
		break;
	case SCR_CONFUSE_MONSTER:
		if(confused) {
			pline("Your hands begin to glow purple.");
			Confusion += rnd(100);
		} else {
			pline("Your hands begin to glow blue.");
			u.umconf = 1;
		}
		break;
	case SCR_SCARE_MONSTER:
	    {	register int ct = 0;
		register struct monst *mtmp;

		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
			if(cansee(mtmp->mx,mtmp->my)) {
				if(confused)
					mtmp->mflee = mtmp->mfroz =
					mtmp->msleep = 0;
				else
					mtmp->mflee = 1;
				ct++;
			}
		if(!ct) {
		    if(confused)
			pline("You hear sad wailing in the distance.");
		    else
			pline("You hear maniacal laughter in the distance.");
		}
		break;
	    }
	case SCR_BLANK_PAPER:
		if(confused)
		    pline("You see strange patterns on this scroll.");
		else
		    pline("This scroll seems to be blank.");
		break;
	case SCR_REMOVE_CURSE:
	    {	register struct obj *obj;
		if(confused)
		  pline("You feel like you need some help.");
		else
		  pline("You feel like someone is helping you.");
		for(obj = invent; obj ; obj = obj->nobj)
			if(obj->owornmask)
				obj->cursed = confused;
		if(Punished && !confused) {
			Punished = 0;
			freeobj(uchain);
			unpobj(uchain);
			free((char *) uchain);
			uball->spe = 0;
			uball->owornmask &= ~W_BALL;
			uchain = uball = (struct obj *) 0;
		}
		break;
	    }
	case SCR_CREATE_MONSTER:
	    {	register int cnt = 1;

		if(!rn2(73)) cnt += rn2(4) + 1;
		if(confused) cnt += 12;
		while(cnt--)
		    (void) makemon(confused ? PM_ACIDBLOB :
			(struct permonst *) 0, u.ux, u.uy);
		break;
	    }
	case SCR_ENCHANT_WEAPON:
		if(!uwep) {
			strange_feeling(scroll);
			return(1);
		}
		if(confused) {
			pline("Your %s glows silver for a moment.",
				objects[uwep->otyp].oc_name);
			uwep->rustfree = 1;
		} else
			if(!chwepon(scroll, 1)) return(1);
		break;
	case SCR_DAMAGE_WEAPON:
		if(confused) {
			pline("Your %s glows purple for a moment.",
				objects[uwep->otyp].oc_name);
			uwep->rustfree = 0;
		} else
			if(!chwepon(scroll, -1)) return(1);
		break;
	case SCR_TAMING:
	    {	register int i,j;
		register int bd = confused ? 5 : 1;
		register struct monst *mtmp;

		for(i = -bd; i <= bd; i++) for(j = -bd; j <= bd; j++)
		if(mtmp = m_at(u.ux+i, u.uy+j))
			(void) tamedog(mtmp, (struct obj *) 0);
		break;
	    }
	case SCR_GENOCIDE:
	    {	extern char genocided[], fut_geno[];
		char buf[BUFSZ];
		register struct monst *mtmp, *mtmp2;

		pline("You have found a scroll of genocide!");
		known = TRUE;
		if(confused)
			*buf = u.usym;
		else do {
	    pline("What monster do you want to genocide (Type the letter)? ");
			getlin(buf);
		} while(strlen(buf) != 1 || !letter(*buf));
		if(!index(fut_geno, *buf))
			charcat(fut_geno, *buf);
		if(!index(genocided, *buf))
			charcat(genocided, *buf);
		else {
			pline("Such monsters do not exist in this world.");
			break;
		}
		for(mtmp = fmon; mtmp; mtmp = mtmp2){
			mtmp2 = mtmp->nmon;
			if(mtmp->data->mlet == *buf)
				mondead(mtmp);
		}
		pline("Wiped out all %c's.", *buf);
		if(*buf == u.usym) {
			killer = "scroll of genocide";
			u.uhp = -1;
		}
		break;
		}
	case SCR_LIGHT:
		if(!Blind) known = TRUE;
		litroom(!confused);
		break;
	case SCR_TELEPORTATION:
		if(confused)
			level_tele();
		else {
#ifdef QUEST
			register int oux = u.ux, ouy = u.uy;
			tele();
			if(dist(oux, ouy) > 100) known = TRUE;
#else QUEST
			register int uroom = inroom(u.ux, u.uy);
			tele();
			if(uroom != inroom(u.ux, u.uy)) known = TRUE;
#endif QUEST
		}
		break;
	case SCR_GOLD_DETECTION:
	    {	register struct gen *head = confused ? ftrap : fgold;
		register struct gen *gtmp;

		if(!head) {
			strange_feeling(scroll);
			return(1);
		} else {
			known = TRUE;
			for(gtmp = head; gtmp; gtmp = gtmp->ngen)
				if(gtmp->gx != u.ux || gtmp->gy != u.uy)
					goto outgoldmap;
			/* only under me - no separate display required */
			if(confused)
			    pline("You feel very giddy!");
			else
			    pline("You notice some gold between your feet.");
			break;
		outgoldmap:
			cls();
			for(gtmp = head; gtmp; gtmp = gtmp->ngen)
				at(gtmp->gx, gtmp->gy, '$');
			prme();
			if(confused)
			    pline("You feel very greedy!");
			else
			    pline("You feel very greedy, and sense gold!");
			more();
			docrt();
		}
		break;
	    }
	case SCR_FOOD_DETECTION:
	    {	register ct = 0, ctu = 0;
		register struct obj *obj;
		register char foodsym = confused ? POTION_SYM : FOOD_SYM;

		for(obj = fobj; obj; obj = obj->nobj)
			if(obj->olet == FOOD_SYM) {
				if(obj->ox == u.ux && obj->oy == u.uy) ctu++;
				else ct++;
			}
		if(!ct && !ctu) {
			strange_feeling(scroll);
			return(1);
		} else if(!ct) {
			known = TRUE;
			pline("You smell %s close nearby.",
				confused ? "something" : "food");
			
		} else {
			known = TRUE;
			cls();
			for(obj = fobj; obj; obj = obj->nobj)
			    if(obj->olet == foodsym)
				at(obj->ox, obj->oy, FOOD_SYM);
			prme();
			pline("Your nose tingles and you smell %s!",
				confused ? "something" : "food");
			more();
			docrt();
		}
		break;
	    }
	case SCR_IDENTIFY:
		/* known = TRUE; */
		if(confused)
			pline("You identify this as an identify scroll.");
		else
			pline("This is an identify scroll.");
		useup(scroll);
		objects[SCR_IDENTIFY].oc_name_known = 1;
		if(!confused)
		    while(
			!ggetobj("identify", identify, rn2(5) ? 1 : rn2(5))
			&& invent
		    );
		return(1);
	case SCR_MAGIC_MAPPING:
	    {	register struct rm *lev;
		register int num, zx, zy;

		known = TRUE;
		pline("On this scroll %s a map!",
			confused ? "was" : "is");
		for(zy = 0; zy < ROWNO; zy++)
			for(zx = 0; zx < COLNO; zx++) {
				if(confused && rn2(7)) continue;
				lev = &(levl[zx][zy]);
				if((num = lev->typ) == 0)
					continue;
				if(num == SCORR) {
					lev->typ = CORR;
					lev->scrsym = CORR_SYM;
				} else
				if(num == SDOOR) {
					lev->typ = DOOR;
					lev->scrsym = '+';
					/* do sth in doors ? */
				} else if(lev->seen) continue;
#ifndef QUEST
				if(num != ROOM)
#endif QUEST
				{
				  lev->seen = lev->new = 1;
				  on_scr(zx,zy);
				}
			}
		break;
	    }
	case SCR_AMNESIA:
	    {	register int zx, zy;

		known = TRUE;
		for(zx = 0; zx < COLNO; zx++) for(zy = 0; zy < ROWNO; zy++)
		    if(!confused || rn2(7))
			if(!cansee(zx,zy))
			    levl[zx][zy].seen = 0;
		docrt();
		pline("Thinking of Maud you forget everything else.");
		break;
	    }
	case SCR_FIRE:
	    {	register int num;

		known = TRUE;
		if(confused) {
		    pline("The scroll catches fire and you burn your hands.");
		    losehp(1, "scroll of fire");
		} else {
		    pline("The scroll erupts in a tower of flame!");
		    if(Fire_resistance)
			pline("You are uninjured.");
		    else {
			num = rnd(6);
			u.uhpmax -= num;
			losehp(num, "scroll of fire");
		    }
		}
		break;
	    }
	case SCR_PUNISHMENT:
		known = TRUE;
		if(confused) {
			pline("You feel guilty.");
			break;
		}
		pline("You are being punished for your misbehaviour!");
		if(Punished){
			pline("Your iron ball gets heavier.");
			uball->owt += 15;
			break;
		}
		Punished = INTRINSIC;
		mkobj_at(CHAIN_SYM, u.ux, u.uy);
		setworn(fobj, W_CHAIN);
		mkobj_at(BALL_SYM, u.ux, u.uy);
		setworn(fobj, W_BALL);
		uball->spe = 1;		/* special ball (see save) */
		break;
	default:
		pline("What weird language is this written in? (%d)",
			scroll->otyp);
		impossible();
	}
	if(!objects[scroll->otyp].oc_name_known) {
		if(known && !confused) {
			objects[scroll->otyp].oc_name_known = 1;
			u.urexp += 10;
		} else if(!objects[scroll->otyp].oc_uname)
			docall(scroll);
	}
	useup(scroll);
	return(1);
}

identify(otmp)
register struct obj *otmp;
{
	objects[otmp->otyp].oc_name_known = 1;
	otmp->known = otmp->dknown = 1;
	prinv(otmp);
	return(1);
}

litroom(on)
register boolean on;
{
	register num,zx,zy;

	/* first produce the text (provided he is not blind) */
	if(Blind) goto do_it;
	if(!on) {
		if(u.uswallow || !xdnstair || levl[u.ux][u.uy].typ == CORR ||
		    !levl[u.ux][u.uy].lit) {
			pline("It seems even darker in here than before.");
			return;
		} else
			pline("It suddenly becomes dark in here.");
	} else {
		if(u.uswallow){
			pline("%s's stomach is lit.", Monnam(u.ustuck));
			return;
		}
		if(!xdnstair){
			pline("Nothing Happens");
			return;
		}
#ifdef QUEST
		pline("The cave lights up around you, then fades.");
		return;
#else QUEST
		if(levl[u.ux][u.uy].typ == CORR) {
		    pline("The corridor lights up around you, then fades.");
		    return;
		} else if(levl[u.ux][u.uy].lit) {
		    pline("The light here seems better now.");
		    return;
		} else
		    pline("The room is lit.");
#endif QUEST
	}

do_it:
#ifdef QUEST
	return;
#else QUEST
	if(levl[u.ux][u.uy].lit == on)
		return;
	if(levl[u.ux][u.uy].typ == DOOR) {
		if(levl[u.ux][u.uy+1].typ >= ROOM) zy = u.uy+1;
		else if(levl[u.ux][u.uy-1].typ >= ROOM) zy = u.uy-1;
		else zy = u.uy;
		if(levl[u.ux+1][u.uy].typ >= ROOM) zx = u.ux+1;
		else if(levl[u.ux-1][u.uy].typ >= ROOM) zx = u.ux-1;
		else zx = u.ux;
	} else {
		zx = u.ux;
		zy = u.uy;
	}
	for(seelx = u.ux; (num = levl[seelx-1][zy].typ) != CORR && num != 0;
		seelx--);
	for(seehx = u.ux; (num = levl[seehx+1][zy].typ) != CORR && num != 0;
		seehx++);
	for(seely = u.uy; (num = levl[zx][seely-1].typ) != CORR && num != 0;
		seely--);
	for(seehy = u.uy; (num = levl[zx][seehy+1].typ) != CORR && num != 0;
		seehy++);
	for(zy = seely; zy <= seehy; zy++)
		for(zx = seelx; zx <= seehx; zx++) {
			levl[zx][zy].lit = on;
			if(!Blind && dist(zx,zy) > 2)
				if(on) prl(zx,zy); else nosee(zx,zy);
		}
	if(!on) seehx = 0;
#endif	QUEST
}
//E*O*F hack.read.c//

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

#include	<sys/types.h>		/* for time_t */
#include <stdio.h>
#include "hack.h"
#ifdef BSD
#include	<sys/time.h>
#else
#include	<time.h>
#endif BSD

extern char plname[];

static char *rip[] = {
"                       ----------",
"                      /          \\",
"                     /    REST    \\",
"                    /      IN      \\",
"                   /     PEACE      \\",
"                  /                  \\",
"                  |                  |",
"                  |                  |",
"                  |                  |",
"                  |                  |",
"                  |                  |",
"                  |       1001       |",
"                 *|     *  *  *      | *",
"        _________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______\n",
0
};

outrip(){
	register char **dp = rip;
	register char *dpx;
	register struct tm *lt;
	time_t date;
	char buf[BUFSZ];
	struct tm *localtime();
	register x,y;

	cls();
	(void) time(&date);
	lt = localtime(&date);
	(void) strcpy(buf, plname);
	buf[16] = 0;
	center(6, buf);
	(void) sprintf(buf, "%ld AU", u.ugold);
	center(7, buf);
	(void) sprintf(buf, "killed by%s",
		!strncmp(killer, "the ", 4) ? "" :
		!strcmp(killer, "starvation") ? "" :
		index(vowels, *killer) ? " an" : " a");
	center(8, buf);
	(void) strcpy(buf, killer);
	if(strlen(buf) > 16) {
	    register int i,i0,i1;
		i0 = i1 = 0;
		for(i = 0; i <= 16; i++)
			if(buf[i] == ' ') i0 = i, i1 = i+1;
		if(!i0) i0 = i1 = 16;
		buf[i1 + 16] = 0;
		center(10, buf+i1);
		buf[i0] = 0;
	}
	center(9, buf);
	(void) sprintf(buf, "19%2d", lt->tm_year);
	center(11, buf);
	for(y=8; *dp; y++,dp++){
		x = 0;
		dpx = *dp;
		while(dpx[x]) {
			while(dpx[x] == ' ') x++;
			curs(x,y);
			while(dpx[x] && dpx[x] != ' '){
				extern int done_stopprint;
				if(done_stopprint)
					return;
				curx++;
				(void) putchar(dpx[x++]);
			}
		}
	}
	getret();
}

center(line, text) int line; char *text; {
register char *ip,*op;
	ip = text;
	op = &rip[line][28 - ((strlen(text)+1)/2)];
	while(*ip) *op++ = *ip++;
}
//E*O*F hack.rip.c//

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

#include	<stdio.h>
#include	"config.h"
#define	CHARSZ	8	/* number of bits in a char */
#define	RUMORFILE	"rumors"
extern long *alloc();
extern char *index();
int n_rumors = 0;
int n_used_rumors = -1;
char *usedbits;

init_rumors(rumf) register FILE *rumf; {
register int i;
	n_used_rumors = 0;
	while(skipline(rumf)) n_rumors++;
	rewind(rumf);
	i = n_rumors/CHARSZ;
	usedbits = (char *) alloc((unsigned)(i+1));
	for( ; i>=0; i--) usedbits[i] = 0;
}

skipline(rumf) register FILE *rumf; {
char line[COLNO];
	while(1) {
		if(!fgets(line, sizeof(line), rumf)) return(0);
		if(index(line, '\n')) return(1);
	}
}

outline(rumf) register FILE *rumf; {
char line[COLNO];
register char *ep;
	if(!fgets(line, sizeof(line), rumf)) return;
	if((ep = index(line, '\n')) != 0) *ep = 0;
	pline("This cookie has a scrap of paper inside! It reads: ");
	pline(line);
}

outrumor(){
register int rn,i;
register FILE *rumf;
	if(n_rumors <= n_used_rumors ||
	  (rumf = fopen(RUMORFILE, "r")) == NULL) return;
	if(n_used_rumors < 0) init_rumors(rumf);
	if(!n_rumors) goto none;
	rn = rn2(n_rumors - n_used_rumors);
	i = 0;
	while(rn || used(i)) {
		(void) skipline(rumf);
		if(!used(i)) rn--;
		i++;
	}
	usedbits[i/CHARSZ] |= (1 << (i % CHARSZ));
	n_used_rumors++;
	outline(rumf);
none:
	(void) fclose(rumf);
}

used(i) register int i; {
	return(usedbits[i/CHARSZ] & (1 << (i % CHARSZ)));
}
//E*O*F hack.rumors.c//

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

#include "hack.h"
extern char genocided[60];	/* defined in Decl.c */
extern char fut_geno[60];	/* idem */
#include <signal.h>

extern char SAVEF[], nul[];
extern char pl_character[PL_CSIZ];
extern long lseek();
extern struct obj *restobjchn();
extern struct monst *restmonchn();

dosave(){
	if(dosave0(0)) {
		settty("Be seeing you ...\n");
		exit(0);
	}
#ifdef lint
	return(0);
#endif lint
}

#ifndef NOSAVEONHANGUP
hangup(){
	(void) dosave0(1);
	exit(1);
}
#endif NOSAVEONHANGUP

/* returns 1 if save successful */
dosave0(hu) int hu; {
	register fd, ofd;
	int tmp;		/* not register ! */

	(void) signal(SIGHUP, SIG_IGN);
	(void) signal(SIGINT, SIG_IGN);
	if((fd = creat(SAVEF, FMASK)) < 0) {
		if(!hu) pline("Cannot open save file. (Continue or Quit)");
		return(0);
	}
	savelev(fd);
	saveobjchn(fd, invent);
	saveobjchn(fd, fcobj);
	savemonchn(fd, fallen_down);
	bwrite(fd, (char *) &flags, sizeof(struct flag));
	bwrite(fd, (char *) &dlevel, sizeof dlevel);
	bwrite(fd, (char *) &maxdlevel, sizeof maxdlevel);
	bwrite(fd, (char *) &moves, sizeof moves);
	bwrite(fd, (char *) &u, sizeof(struct you));
	bwrite(fd, (char *) pl_character, sizeof pl_character);
	bwrite(fd, (char *) genocided, sizeof genocided);
	bwrite(fd, (char *) fut_geno, sizeof fut_geno);
	savenames(fd);
	for(tmp = 1; tmp <= maxdlevel; tmp++) {
		glo(tmp);
		if((ofd = open(lock, 0)) < 0)
			continue;
		(void) getlev(ofd);
		(void) close(ofd);
		bwrite(fd, (char *) &tmp, sizeof tmp);	/* level number */
		savelev(fd);				/* actual level */
		(void) unlink(lock);
	}
	(void) close(fd);
	(*index(lock, '.')) = 0;
	(void) unlink(lock);
	return(1);
}

dorecover(fd)
register fd;
{
	register nfd;
	int tmp;		/* not a register ! */
	struct obj *otmp;

	(void) getlev(fd);
	invent = restobjchn(fd);
	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp->owornmask)
			setworn(otmp, otmp->owornmask);
	fcobj = restobjchn(fd);
	fallen_down = restmonchn(fd);
	mread(fd, (char *) &flags, sizeof(struct flag));
	mread(fd, (char *) &dlevel, sizeof dlevel);
	mread(fd, (char *) &maxdlevel, sizeof maxdlevel);
	mread(fd, (char *) &moves, sizeof moves);
	mread(fd, (char *) &u, sizeof(struct you));
	mread(fd, (char *) pl_character, sizeof pl_character);
	mread(fd, (char *) genocided, sizeof genocided);
	mread(fd, (char *) fut_geno, sizeof fut_geno);
	restnames(fd);
	while(1) {
		if(read(fd, (char *) &tmp, sizeof tmp) != sizeof tmp)
			break;
		if(getlev(fd))
			break;		/* this is actually an error */
		glo(tmp);
		if((nfd = creat(lock, FMASK)) < 0)
			panic("Cannot open temp file %s!\n", lock);
		savelev(nfd);
		(void) close(nfd);
	}
	(void) lseek(fd, 0L, 0);
	(void) getlev(fd);
	(void) close(fd);
	(void) unlink(SAVEF);
	if(Punished) {
		for(otmp = fobj; otmp; otmp = otmp->nobj)
			if(otmp->olet == CHAIN_SYM) goto chainfnd;
		panic("Cannot find the iron chain?");
	chainfnd:
		uchain = otmp;
		if(!uball){
			for(otmp = fobj; otmp; otmp = otmp->nobj)
				if(otmp->olet == BALL_SYM && otmp->spe)
					goto ballfnd;
			panic("Cannot find the iron ball?");
		ballfnd:
			uball = otmp;
		}
	}
#ifndef QUEST
	setsee();  /* only to recompute seelx etc. - these weren't saved */
#endif QUEST
	docrt();
}

struct obj *
restobjchn(fd)
register fd;
{
	register struct obj *otmp, *otmp2;
	register struct obj *first = 0;
	int xl;
#ifdef lint
	/* suppress "used before set" warning from lint */
	otmp2 = 0;
#endif lint
	while(1) {
		mread(fd, (char *) &xl, sizeof(xl));
		if(xl == -1) break;
		otmp = newobj(xl);
		if(!first) first = otmp;
		else otmp2->nobj = otmp;
		mread(fd, (char *) otmp, (unsigned) xl + sizeof(struct obj));
		if(!otmp->o_id)	/* from MKLEV */
			otmp->o_id = flags.ident++;
		otmp2 = otmp;
	}
	if(first && otmp2->nobj){
		pline("Restobjchn: error reading objchn.");
		impossible();
		otmp2->nobj = 0;
	}
	return(first);
}

struct monst *
restmonchn(fd)
register fd;
{
	register struct monst *mtmp, *mtmp2;
	register struct monst *first = 0;
	int xl;

	struct permonst *monbegin;
	long differ;

	mread(fd, (char *)&monbegin, sizeof(monbegin));
	differ = (char *)(&mons[0]) - (char *)(monbegin);

#ifdef lint
	/* suppress "used before set" warning from lint */
	mtmp2 = 0;
#endif lint
	while(1) {
		mread(fd, (char *) &xl, sizeof(xl));
		if(xl == -1) break;
		mtmp = newmonst(xl);
		if(!first) first = mtmp;
		else mtmp2->nmon = mtmp;
		mread(fd, (char *) mtmp, (unsigned) xl + sizeof(struct monst));
		mtmp->data = (struct permonst *)
			((char *) mtmp->data + differ);
		if(!mtmp->m_id) {			/* from MKLEV */
			mtmp->m_id = flags.ident++;
#ifndef NOWORM
			if(mtmp->data->mlet == 'w' && getwn(mtmp)){
				initworm(mtmp);
				mtmp->msleep = 0;
			}
#endif NOWORM
		}
		if(mtmp->minvent)
			mtmp->minvent = restobjchn(fd);
		mtmp2 = mtmp;
	}
	if(first && mtmp2->nmon){
		pline("Restmonchn: error reading monchn.");
		impossible();
		mtmp2->nmon = 0;
	}
	return(first);
}
//E*O*F hack.save.c//

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

#include "hack.h"
#include	"def.trap.h"

extern struct monst *makemon();

findit()	/* returns number of things found */
{
	int num;
	register xchar zx,zy;
	register struct gen *gtmp;
	register struct monst *mtmp;
	xchar lx,hx,ly,hy;

	if(u.uswallow) return(0);
	for(lx = u.ux;(num = levl[lx-1][u.uy].typ) && num != CORR;lx--) ;
	for(hx = u.ux;(num = levl[hx+1][u.uy].typ) && num != CORR;hx++) ;
	for(ly = u.uy;(num = levl[u.ux][ly-1].typ) && num != CORR;ly--) ;
	for(hy = u.uy;(num = levl[u.ux][hy+1].typ) && num != CORR;hy++) ;
	num = 0;
	for(zy = ly;zy <= hy;zy++)
		for(zx = lx;zx <= hx;zx++) {
			if(levl[zx][zy].typ == SDOOR) {
				levl[zx][zy].typ = DOOR;
				atl(zx,zy,'+');
				num++;
			} else if(levl[zx][zy].typ == SCORR) {
				levl[zx][zy].typ = CORR;
				atl(zx,zy,CORR_SYM);
				num++;
			} else if(gtmp = g_at(zx,zy,ftrap)) {
				if(gtmp->gflag == PIERC){
					(void) makemon(PM_PIERC,zx,zy);
					num++;
					deltrap(gtmp);
				} else if(!gtmp->gflag&SEEN) {
					gtmp->gflag |= SEEN;
					if(!vism_at(zx,zy)) atl(zx,zy,'^');
					num++;
				}
			} else if(mtmp = m_at(zx,zy)) if(mtmp->mimic){
				seemimic(mtmp);
				num++;
			}
		}
	return(num);
}

dosearch()
{
	register xchar x,y;
	register struct gen *tgen;
	register struct monst *mtmp;

	for(x = u.ux-1; x < u.ux+2; x++)
	for(y = u.uy-1; y < u.uy+2; y++) if(x != u.ux || y != u.uy) {
		if(levl[x][y].typ == SDOOR && !rn2(7)) {
			levl[x][y].typ = DOOR;
			levl[x][y].seen = 0;	/* force prl */
			prl(x,y);
			nomul(0);
		} else if(levl[x][y].typ == SCORR && !rn2(7)) {
			levl[x][y].typ = CORR;
			levl[x][y].seen = 0;	/* force prl */
			prl(x,y);
			nomul(0);
		} else {
			if(mtmp = m_at(x,y)) if(mtmp->mimic){
				seemimic(mtmp);
				pline("You find a mimic.");
				return(1);
			}
			for(tgen = ftrap;tgen;tgen = tgen->ngen)
			if(tgen->gx == x && tgen->gy == y &&
			   !(tgen->gflag & SEEN) && !rn2(8)) {
				nomul(0);
				pline("You find a%s.",
					traps[tgen->gflag]);
				if(tgen->gflag == PIERC) {
					deltrap(tgen);
					(void) makemon(PM_PIERC,x,y);
					return(1);
				}
				tgen->gflag |= SEEN;
				if(!vism_at(x,y)) atl(x,y,'^');
			}
		}
	}
	return(1);
}

/* ARGSUSED */
doidtrap(str) /* register */ char *str; {
register struct gen *tgen;
register int x,y;
	if(!getdir()) return(0);
	x = u.ux + u.dx;
	y = u.uy + u.dy;
	for(tgen = ftrap; tgen; tgen = tgen->ngen)
		if(tgen->gx == x && tgen->gy == y &&
		   (tgen->gflag & SEEN)) {
			pline("That is a%s.", traps[tgen->gflag & ~SEEN]);
			return(0);
		}
	pline("I can't see a trap there.");
	return(0);
}

wakeup(mtmp)
register struct monst *mtmp;
{
	mtmp->msleep = 0;
	setmangry(mtmp);
	if(mtmp->mimic) seemimic(mtmp);
}

/* NOTE: we must check if(mtmp->mimic) before calling this routine */
seemimic(mtmp)
register struct monst *mtmp;
{
		mtmp->mimic = 0;
		unpmon(mtmp);
		pmon(mtmp);
}
//E*O*F hack.search.c//

echo x - hack.sh
cat > "hack.sh" << '//E*O*F hack.sh//'
#!/bin/sh
HACK=/usr/games/HACK
HACKDIR=/usr/games/lib/hack/tmp
MAXNROFPLAYERS=6
MORE=/usr/ucb/more

cd $HACKDIR
case $1 in
	-s*)
		$HACK $@
		;;
	*)
#		/bin/cat news
		$HACK $HACKDIR $MAXNROFPLAYERS $MORE
		;;
esac
//E*O*F hack.sh//

exit 0

play@mcvax.UUCP (funhouse) (12/18/84)

# 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

play@mcvax.UUCP (funhouse) (12/18/84)

# 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

play@mcvax.UUCP (funhouse) (12/18/84)

# 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

jwg@galbp.UUCP (Joe Guthridge) (12/20/84)

Hack sources part 9 didn't make it here intact!  Someone please mail me one!
-- 
					Joe Guthridge
					..!akgua!galbp!jwg
			NOTE NEW MACHINE NAME    ^^^^^

ron@vaxnix.UUCP (12/30/84)

# This is part 11 (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.shk.c hack.stat.c hack.steal.c hack.termcap.c hack.timeout.c hack.topl.c

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

#include "hack.h"
#ifdef QUEST
int shlevel = 0;
struct monst *shopkeeper = 0;
struct obj *billobjs = 0;
obfree(obj,merge) register struct obj *obj, *merge; {
	free((char *) obj);
}
inshop(){ return(0); }
addtobill(){}
subfrombill(){}
splitbill(){}
dopay(){}
paybill(){}
doinvbill(){}
shkdead(){}
shk_move(){ return(0); }
setshk(){}
char *shkname(){ return(""); }

#else
#include	"hack.mfndpos.h"
#include	"def.eshk.h"

#define	ESHK	((struct eshk *)(&(shopkeeper->mextra[0])))
#define	NOTANGRY	shopkeeper->mpeaceful
#define	ANGRY	!NOTANGRY

extern char plname[];
extern struct obj *o_on();
struct monst *shopkeeper = 0;
struct bill_x *bill;
int shlevel = 0;	/* level of this shopkeeper */
struct obj *billobjs;	/* objects on bill with bp->useup */
/* #define	billobjs	shopkeeper->minvent
   doesnt work so well, since we do not want these objects to be dropped
   when the shopkeeper is killed.
   (See also the save and restore routines.)
 */

/* invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
		obj->quan <= bp->bquan
 */

long int total;

char shtypes[] = "=/)%?!["; /* 8 shoptypes: 7 specialized, 1 mixed */
char *shopnam[] = {
	"engagement ring", "walking cane", "antique weapon",
	"delicatessen", "second hand book", "liquor",
	"used armor", "assorted antiques"
};

char *
shkname() {
	return(ESHK->shknam);
}

shkdead(){
	rooms[ESHK->shoproom].rtype = 0;
	setpaid();
	shopkeeper = 0;
	bill = (struct bill_x *) -1000;	/* dump core when referenced */
}

setpaid(){	/* caller has checked that shopkeeper exists */
register struct obj *obj;
	for(obj = invent; obj; obj = obj->nobj)
		obj->unpaid = 0;
	for(obj = fobj; obj; obj = obj->nobj)
		obj->unpaid = 0;
	while(obj = billobjs){
		billobjs = obj->nobj;
		free((char *) obj);
	}
	ESHK->billct = 0;
}

addupbill(){	/* delivers result in total */
		/* caller has checked that shopkeeper exists */
register ct = ESHK->billct;
register struct bill_x *bp = bill;
	total = 0;
	while(ct--){
		total += bp->price * bp->bquan;
		bp++;
	}
}

inshop(){
register tmp = inroom(u.ux,u.uy);
	if(tmp < 0 || rooms[tmp].rtype < 8) {
		u.uinshop = 0;
		if(shopkeeper && ESHK->billct){
			pline("Somehow you escaped the shop without paying!");
			addupbill();
			pline("You stole for a total worth of %lu zorkmids.",
				total);
			ESHK->robbed += total;
			setpaid();
		}
		if(tmp >= 0 && rooms[tmp].rtype == 7){
			register struct monst *mtmp;
			pline("Welcome to David's treasure zoo!");
			rooms[tmp].rtype = 0;
			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
				if(!rn2(4)) mtmp->msleep = 0;
		}
	} else {
		if(shlevel != dlevel) setshk();
		if(!shopkeeper) u.uinshop = 0;
		else if(!u.uinshop){
			if(!ESHK->visitct ||
				strncmp(ESHK->customer, plname, PL_NSIZ)){
				/* He seems to be new here */
				ESHK->visitct = 0;
				(void) strncpy(ESHK->customer,plname,PL_NSIZ);
				NOTANGRY = 1;
			}
			pline("Hello %s! Welcome%s to %s's %s shop!",
				plname,
				ESHK->visitct++ ? " again" : "",
				shkname(),
				shopnam[rooms[ESHK->shoproom].rtype - 8] );
			u.uinshop = 1;
		}
	}
	return(u.uinshop);
}

setshk(){
register struct monst *mtmp;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isshk){
		shopkeeper = mtmp;
		bill = &(ESHK->bill[0]);
		shlevel = dlevel;
		if(ANGRY && strncpy(ESHK->customer,plname,PL_NSIZ))
			NOTANGRY = 1;
		billobjs = 0;
		return;
	}
	shopkeeper = 0;
	bill = (struct bill_x *) -1000;	/* dump core when referenced */
}

struct bill_x *
onbill(obj) register struct obj *obj; {
register struct bill_x *bp;
	if(!shopkeeper) return(0);
	for(bp = bill; bp < &bill[ESHK->billct]; bp++)
		if(bp->bo_id == obj->o_id) {
			if(!obj->unpaid) pline("onbill: paid obj on bill?");
			return(bp);
		}
	if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
	return(0);
}

/* called with two args on merge */
obfree(obj,merge) register struct obj *obj, *merge; {
register struct bill_x *bp = onbill(obj);
register struct bill_x *bpm;
	if(bp) {
		if(!merge){
			bp->useup = 1;
			obj->unpaid = 0;	/* only for doinvbill */
			obj->nobj = billobjs;
			billobjs = obj;
			return;
		}
		bpm = onbill(merge);
		if(!bpm){
			/* this used to be a rename */
			impossible();
			return;
		} else {
			/* this was a merger */
			bpm->bquan += bp->bquan;
			ESHK->billct--;
			*bp = bill[ESHK->billct];
		}
	}
	free((char *) obj);
}

pay(tmp) long tmp; {
	u.ugold -= tmp;
	shopkeeper->mgold += tmp;
	flags.botl = 1;
}

dopay(){
long ltmp;
register struct bill_x *bp;
int shknear = (shlevel == dlevel && shopkeeper &&
	dist(shopkeeper->mx,shopkeeper->my) < 3);
int pass, tmp;

	multi = 0;
	if(!inshop() && !shknear) {
		pline("You are not in a shop.");
		return(0);
	}
	if(!shknear &&
	    inroom(shopkeeper->mx,shopkeeper->my) != ESHK->shoproom){
		pline("There is nobody here to receive your payment.");
		return(0);
	}
	if(!ESHK->billct){
		pline("You do not owe %s anything.", monnam(shopkeeper));
		if(!u.ugold){
			pline("Moreover, you have no money.");
			return(1);
		}
		if(ESHK->robbed){
			pline("But since the shop has been robbed recently,");
			pline("you %srepay %s's expenses.",
				(u.ugold < ESHK->robbed) ? "partially " : "",
				monnam(shopkeeper));
			pay((u.ugold<ESHK->robbed) ? u.ugold : ESHK->robbed);
			ESHK->robbed = 0;
			return(1);
		}
		if(ANGRY){
			pline("But in order to appease %s,",
				amonnam(shopkeeper, "angry"));
			if(u.ugold >= 1000){
				ltmp = 1000;
				pline(" you give him 1000 gold pieces.");
			} else {
				ltmp = u.ugold;
				pline(" you give him all your money.");
			}
			pay(ltmp);
			if(rn2(3)){
				pline("%s calms down.", Monnam(shopkeeper));
				NOTANGRY = 1;
			} else	pline("%s is as angry as ever.",
					Monnam(shopkeeper));
		}
		return(1);
	}
	for(pass = 0; pass <= 1; pass++) {
		tmp = 0;
		while(tmp < ESHK->billct) {
			bp = &bill[tmp];
			if(!pass && !bp->useup) {
				tmp++;
				continue;
			}
			if(!dopayobj(bp)) return(1);
			bill[tmp] = bill[--ESHK->billct];
		}
	}
	pline("Thank you for shopping in %s's %s store!",
		shkname(),
		shopnam[rooms[ESHK->shoproom].rtype - 8]);
	NOTANGRY = 1;
	return(1);
}

/* return 1 if paid successfully */
/*        0 if not enough money */
/*       -1 if object could not be found (but was paid) */
dopayobj(bp) register struct bill_x *bp; {
register struct obj *obj;
long ltmp;

	/* find the object on one of the lists */
	if(bp->useup)
		obj = o_on(bp->bo_id, billobjs);
	else if(!(obj = o_on(bp->bo_id, invent)) &&
		!(obj = o_on(bp->bo_id, fobj)) &&
		!(obj = o_on(bp->bo_id, fcobj))) {
		    register struct monst *mtmp;
		    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
			if(obj = o_on(bp->bo_id, mtmp->minvent))
			    break;
		    for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
			if(obj = o_on(bp->bo_id, mtmp->minvent))
			    break;
		}
	if(!obj) {
		pline("Shopkeeper administration out of order.");
		impossible();
		setpaid();	/* be nice to the player */
		return(0);
	}

	if(!obj->unpaid && !bp->useup){
		pline("Paid object on bill??");
		impossible();
		return(1);
	}
	obj->unpaid = 0;
	ltmp = bp->price * bp->bquan;
	if(ANGRY) ltmp += ltmp/3;
	if(u.ugold < ltmp){
		pline("You don't have gold enough to pay %s.",
			doname(obj));
		obj->unpaid = 1;
		return(0);
	}
	pay(ltmp);
	pline("You bought %s for %ld gold piece%s.",
		doname(obj), ltmp, (ltmp == 1) ? "" : "s");
	if(bp->useup) {
		register struct obj *otmp = billobjs;
		if(obj == billobjs)
			billobjs = obj->nobj;
		else {
			while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
			if(otmp) otmp->nobj = obj->nobj;
			else pline("Error in shopkeeper administration");
		}
		free((char *) obj);
	}
	return(1);
}

/* routine called after dying (or quitting) with nonempty bill */
paybill(){
	if(shopkeeper && ESHK->billct){
		addupbill();
		if(total > u.ugold){
			shopkeeper->mgold += u.ugold;
			u.ugold = 0;
		pline("%s comes and takes all your possessions.",
			Monnam(shopkeeper));
		} else {
			u.ugold -= total;
			shopkeeper->mgold += total;
	pline("%s comes and takes the %ld zorkmids you owed him.",
		Monnam(shopkeeper), total);
		}
		setpaid();	/* in case we create bones */
	}
}

/* called in hack.c when we pickup an object */
addtobill(obj) register struct obj *obj; {
register struct bill_x *bp;
	if(!inshop() || (u.ux == ESHK->shk.x && u.uy == ESHK->shk.y) ||
		(u.ux == ESHK->shd.x && u.uy == ESHK->shd.y) ||
		onbill(obj) /* perhaps we threw it away earlier */
	) return;
	if(ESHK->billct == BILLSZ){
		pline("You got that for free!");
		return;
	}
	bp = &bill[ESHK->billct];
	bp->bo_id = obj->o_id;
	bp->bquan = obj->quan;
	bp->useup = 0;
	bp->price = getprice(obj);
	ESHK->billct++;
	obj->unpaid = 1;
}

splitbill(obj,otmp) register struct obj *obj, *otmp; {
	/* otmp has been split off from obj */
register struct bill_x *bp;
register int tmp;
	bp = onbill(obj);
	if(!bp) { impossible(); return; }
	if(bp->bquan < otmp->quan) {
		pline("Negative quantity on bill??");
		impossible();
	}
	if(bp->bquan == otmp->quan) {
		pline("Zero quantity on bill??");
		impossible();
	}
	bp->bquan -= otmp->quan;

	/* addtobill(otmp); */
	if(ESHK->billct == BILLSZ) otmp->unpaid = 0;
	else {
		tmp = bp->price;
		bp = &bill[ESHK->billct];
		bp->bo_id = otmp->o_id;
		bp->bquan = otmp->quan;
		bp->useup = 0;
		bp->price = tmp;
		ESHK->billct++;
	}
}

subfrombill(obj) register struct obj *obj; {
long ltmp;
register int tmp;
register struct obj *otmp;
register struct bill_x *bp;
	if(!inshop() || (u.ux == ESHK->shk.x && u.uy == ESHK->shk.y) ||
		(u.ux == ESHK->shd.x && u.uy == ESHK->shd.y))
		return;
	if((bp = onbill(obj)) != 0){
		obj->unpaid = 0;
		if(bp->bquan > obj->quan){
			otmp = newobj(0);
			*otmp = *obj;
			bp->bo_id = otmp->o_id = flags.ident++;
			otmp->quan = (bp->bquan -= obj->quan);
			otmp->owt = 0;	/* superfluous */
			otmp->onamelth = 0;
			bp->useup = 1;
			otmp->nobj = billobjs;
			billobjs = otmp;
			return;
		}
		ESHK->billct--;
		*bp = bill[ESHK->billct];
		return;
	}
	if(obj->unpaid){
		pline("%s didn't notice.", Monnam(shopkeeper));
		obj->unpaid = 0;
		return;		/* %% */
	}
	/* he dropped something of his own - probably wants to sell it */
	if(shopkeeper->msleep || shopkeeper->mfroz ||
		inroom(shopkeeper->mx,shopkeeper->my) != ESHK->shoproom)
		return;
	if(ESHK->billct == BILLSZ ||
	  ((tmp = shtypes[rooms[ESHK->shoproom].rtype-8]) && tmp != obj->olet)
	  || index("_0", obj->olet)) {
		pline("%s seems not interested.", Monnam(shopkeeper));
		return;
	}
	ltmp = getprice(obj) * obj->quan;
	if(ANGRY) {
		ltmp /= 3;
		NOTANGRY = 1;
	} else	ltmp /= 2;
	if(ESHK->robbed){
		if((ESHK->robbed -= ltmp) < 0) ESHK->robbed = 0;
pline("Thank you for your contribution to restock this recently plundered shop.");
		return;
	}
	if(ltmp > shopkeeper->mgold) ltmp = shopkeeper->mgold;
	pay(-ltmp);
	if(!ltmp)
	pline("%s gladly accepts %s but cannot pay you at present.",
		Monnam(shopkeeper), doname(obj));
	else
	pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp,
		(ltmp == 1) ? "" : "s");
}

doinvbill(cl) int cl; {
register unsigned tmp,cnt = 0;
register struct obj *obj;
char buf[BUFSZ];
	if(!shopkeeper) return;
	for(tmp = 0; tmp < ESHK->billct; tmp++) if(bill[tmp].useup) cnt++;
	if(!cnt) return;
	if(!cl && !flags.oneline) cls();
	if(!flags.oneline) puts("\n\nUnpaid articles already used up:\n");
	for(tmp = 0; tmp < ESHK->billct; tmp++) if(bill[tmp].useup){
		for(obj = billobjs; obj; obj = obj->nobj)
			if(obj->o_id == bill[tmp].bo_id) break;
		if(!obj) {
			pline("Bad shopkeeper administration.");
			impossible();
			return;
		}
		(void) sprintf(buf, "* -  %s", doname(obj));
		for(cnt=0; buf[cnt]; cnt++);
		while(cnt < 50) buf[cnt++] = ' ';
		(void) sprintf(&buf[cnt], " %5d zorkmids",
				bill[tmp].price * bill[tmp].bquan);
		if(flags.oneline)
			pline(buf);
		else
			puts(buf);
	}
	if(!cl && !flags.oneline) {
		getret();
		docrt();
	}
}

getprice(obj) register struct obj *obj; {
register int tmp,ac;
	switch(obj->olet){
		case AMULET_SYM:
			tmp = 10*rnd(500);
			break;
		case TOOL_SYM:
			tmp = 10*rnd(150);
			break;
		case RING_SYM:
			tmp = 10*rnd(100);
			break;
		case WAND_SYM:
			tmp = 10*rnd(100);
			break;
		case SCROLL_SYM:
			tmp = 10*rnd(50);
			break;
		case POTION_SYM:
			tmp = 10*rnd(50);
			break;
		case FOOD_SYM:
			tmp = 10*rnd(5 + (2000/realhunger()));
			break;
		case GEM_SYM:
			tmp = 10*rnd(20);
			break;
		case ARMOR_SYM:
			ac = 10 - obj->spe;
			tmp = 100 + (10-ac)*(10-ac)*rnd(20-ac);
			break;
		case WEAPON_SYM:
			if(obj->otyp < BOOMERANG)
				tmp = 5*rnd(10);
			else if(obj->otyp == LONG_SWORD ||
				obj->otyp == TWO_HANDED_SWORD)
				tmp = 10*rnd(150);
			else	tmp = 10*rnd(75);
			break;
		case CHAIN_SYM:
			pline("Strange ..., carrying a chain?");
		case BALL_SYM:
			tmp = 10;
			break;
		default:
			tmp = 10000;
	}
	return(tmp);
}

realhunger(){	/* not completely foolproof */
register tmp = u.uhunger;
register struct obj *otmp = invent;
	while(otmp){
		if(otmp->olet == FOOD_SYM && !otmp->unpaid)
			tmp += objects[otmp->otyp].nutrition;
		otmp = otmp->nobj;
	}
	return((tmp <= 0) ? 1 : tmp);
}

shk_move(){
register struct monst *mtmp;
register struct permonst *mdat = shopkeeper->data;
register xchar gx,gy,omx,omy,nx,ny,nix,niy;
register schar appr,i;
schar shkr,tmp,chi,chcnt,cnt;
boolean uondoor, avoid;
coord poss[9];
int info[9];
	omx = shopkeeper->mx;
	omy = shopkeeper->my;
	shkr = inroom(omx,omy);
	if(ANGRY && dist(omx,omy) < 3){
		(void) hitu(shopkeeper, d(mdat->damn, mdat->damd)+1);
		return(0);
	}
	appr = 1;
	gx = ESHK->shk.x;
	gy = ESHK->shk.y;
	if(ANGRY){
		int saveBlind = Blind;
		Blind = 0;
		if(shopkeeper->mcansee && !Invis && cansee(omx,omy)) {
			gx = u.ux;
			gy = u.uy;
		}
		Blind = saveBlind;
		avoid = FALSE;
	} else {
#define	GDIST(x,y)	((x-gx)*(x-gx)+(y-gy)*(y-gy))
		if(Invis)
		  avoid = FALSE;
		else {
		  uondoor = (u.ux == ESHK->shd.x && u.uy == ESHK->shd.y);
		  avoid = ((u.uinshop && dist(gx,gy) > 8) || uondoor);
		  if(((!ESHK->robbed && !ESHK->billct) || avoid)
		  	&& GDIST(omx,omy) < 3){
		  	if(!online(omx,omy)) return(0);
		  	if(omx == gx && omy == gy)
		  		appr = gx = gy = 0;
		  }
		}
	}
	if(omx == gx && omy == gy) return(0);
	if(shopkeeper->mconf) appr = 0;
	nix = omx;
	niy = omy;
	cnt = mfndpos(shopkeeper,poss,info,
		(avoid ? NOTONL : 0) | ALLOW_SSM);
	if(cnt == 0 && avoid && uondoor)
		cnt = mfndpos(shopkeeper,poss,info,ALLOW_SSM);
	chi = -1;
	chcnt = 0;
	for(i=0; i<cnt; i++){
		nx = poss[i].x;
		ny = poss[i].y;
	   	if((tmp = levl[nx][ny].typ) == ROOM ||
		(shkr != ESHK->shoproom && (tmp==CORR || tmp==DOOR)))
#ifdef STUPID
		/* cater for stupid compilers */
		{ int zz;
		if((!appr && !rn2(++chcnt)) ||
		   (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny))){
#else
		if((!appr && !rn2(++chcnt)) ||
		   (appr && GDIST(nx,ny) < GDIST(nix,niy))){
#endif STUPID
			nix = nx;
			niy = ny;
			chi = i;
#ifdef STUPID
		   }
#endif STUPID
		}
	}
	if(nix != omx || niy != omy){
		if(info[chi] & ALLOW_M){
			mtmp = m_at(nix,niy);
			if(hitmm(shopkeeper,mtmp) == 1 && rn2(3) &&
			   hitmm(mtmp,shopkeeper) == 2) return(2);
			return(0);
		} else if(info[chi] & ALLOW_U){
			(void) hitu(shopkeeper, d(mdat->damn, mdat->damd)+1);
			return(0);
		}
		shopkeeper->mx = nix;
		shopkeeper->my = niy;
		pmon(shopkeeper);
		return(1);
	}
	return(0);
}
#endif QUEST

char *
plur(n) unsigned n; {
	return((n==1) ? "" : "s");
}

online(x,y) {
	return(x==u.ux || y==u.uy ||
		(x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
}
//E*O*F hack.shk.c//

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

#include <sys/types.h>
#include <sys/stat.h>
extern char *index();
struct stat buf,hbuf;

gethdate(name) char *name; {
register char *np;
	if(stat(name, &hbuf))
		error("Cannot get status of %s.",
			(np = index(name, '/')) ? np+1 : name);
}

uptodate(fd) {
	if(fstat(fd, &buf)) {
		pline("Cannot get status?");
		return(0);
	}
	if(buf.st_ctime < hbuf.st_ctime) {
		pline("Saved level is out of date.");
		return(0);
	}
	return(1);
}
//E*O*F hack.stat.c//

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

#include "hack.h"

stealgold(mtmp)  register struct monst *mtmp; {
register struct gen *gold = g_at(u.ux, u.uy, fgold);
register tmp;
	if(gold && ( !u.ugold || gold->gflag > u.ugold || !rn2(5))) {
		mtmp->mgold += gold->gflag;
		freegold(gold);
		if(Invis) newsym(u.ux, u.uy);
		pline("%s quickly snatches some gold from between your feet!",
			Monnam(mtmp));
		if(!u.ugold || !rn2(5)) {
			rloc(mtmp);
			mtmp->mflee = 1;
		}
	} else if(u.ugold) {
		u.ugold -= (tmp = somegold());
		pline("Your purse feels lighter.");
		mtmp->mgold += tmp;
		rloc(mtmp);
		mtmp->mflee = 1;
		flags.botl = 1;
	}
}

somegold(){
	return( (u.ugold < 100) ? u.ugold :
		(u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) );
}

/* steal armor after he finishes taking it off */
unsigned stealoid;		/* object to be stolen */
unsigned stealmid;		/* monster doing the stealing */
stealarm(){
	register struct monst *mtmp;
	register struct obj *otmp;

	for(otmp = invent; otmp; otmp = otmp->nobj)
	  if(otmp->o_id == stealoid) {
	    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
	      if(mtmp->m_id == stealmid) {
		if(dist(mtmp->mx,mtmp->my) < 3) {
		  freeinv(otmp);
		  pline("%s steals %s!", Monnam(mtmp), doname(otmp));
		  mpickobj(mtmp,otmp);
		  mtmp->mflee = 1;
		  rloc(mtmp);
		}
		break;
	      }
	    break;
	  }
	stealoid = 0;
}

/* returns 1 when something was stolen */
/* (or at least, when N should flee now) */
/* avoid stealing the object stealoid */
steal(mtmp)
struct monst *mtmp;
{
	register struct obj *otmp;
	register tmp;
	register named = 0;

	if(!invent){
	    if(Blind)
	      pline("Somebody tries to rob you, but finds nothing to steal.");
	    else
	      pline("%s tries to rob you, but she finds nothing to steal!",
		Monnam(mtmp));
	    return(1);	/* let her flee */
	}
	tmp = 0;
	for(otmp = invent; otmp; otmp = otmp->nobj)
		tmp += ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1);
	tmp = rn2(tmp);
	for(otmp = invent; otmp; otmp = otmp->nobj)
		if((tmp -= ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1))
			< 0) break;
	if(!otmp) panic("Steal fails!");
	if(otmp->o_id == stealoid) return(0);
	if((otmp->owornmask & (W_ARMOR | W_RING))){
		switch(otmp->olet) {
		case RING_SYM:
			ringoff(otmp);
			break;
		case ARMOR_SYM:
			if(multi < 0 || otmp == uarms){
			  setworn((struct obj *) 0, otmp->owornmask & W_ARMOR);
			  break;
			}
		{ int curssv = otmp->cursed;
			otmp->cursed = 0;
			pline("%s seduces you and %s off your %s.",
				Amonnam(mtmp, Blind ? "gentle" : "beautiful"),
				otmp->cursed ? "helps you to take"
					    : "you start taking",
				(otmp == uarmg) ? "gloves" :
				(otmp == uarmh) ? "helmet" : "armor");
			named++;
			(void) armoroff(otmp);
			otmp->cursed = curssv;
			if(multi < 0){
				extern char *nomovemsg;
				extern int (*afternmv)();
				/*
				multi = 0;
				nomovemsg = 0;
				afternmv = 0;
				*/
				stealoid = otmp->o_id;
				stealmid = mtmp->m_id;
				afternmv = stealarm;
				return(0);
			}
			break;
		}
		default:
			impossible();
		}
	}
	else if(otmp == uwep)
		setuwep((struct obj *) 0);
	if(otmp->olet == CHAIN_SYM) {
		pline("How come you are carrying that chain?");
		impossible();
	}
	if(Punished && otmp == uball){
		Punished = 0;
		freeobj(uchain);
		free((char *) uchain);
		uchain = (struct obj *) 0;
		uball->spe = 0;
		uball = (struct obj *) 0;	/* superfluous */
	}
	freeinv(otmp);
	pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
	mpickobj(mtmp,otmp);
	return((multi < 0) ? 0 : 1);
}

mpickobj(mtmp,otmp)
register struct monst *mtmp;
register struct obj *otmp;
{
	otmp->nobj = mtmp->minvent;
	mtmp->minvent = otmp;
}

/* release the objects the killed animal has stolen */
relobj(mtmp,show)
register struct monst *mtmp;
register show;
{
	register struct obj *otmp, *otmp2;

	for(otmp = mtmp->minvent; otmp; otmp = otmp2){
		otmp->ox = mtmp->mx;
		otmp->oy = mtmp->my;
		otmp2 = otmp->nobj;
		otmp->nobj = fobj;
		fobj = otmp;
		stackobj(fobj);
		if(show & cansee(mtmp->mx,mtmp->my))
			atl(otmp->ox,otmp->oy,otmp->olet);
	}
	mtmp->minvent = (struct obj *) 0;
	if(mtmp->mgold || mtmp->data->mlet == 'L') {
		register int tmp;

		tmp = (mtmp->mgold > 10000) ? 10000 : mtmp->mgold;
		mkgold( tmp + d(dlevel,30), mtmp->mx, mtmp->my);
		if(show & cansee(mtmp->mx,mtmp->my))
			atl(mtmp->mx,mtmp->my,'$');
	}
}
//E*O*F hack.steal.c//

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

#include <stdio.h>
#include "config.h"	/* for ROWNO and COLNO */
extern char *tgetstr(), *tgoto(), *getenv();
extern long *alloc();

short ospeed;		/* terminal baudrate; used by tputs */
char tbuf[512];
char *HO, *CL, *CE, *UP, *CM, *ND, *XD, *BC, *SO, *SE;
char PC = '\0';

startup()
{
	register char *tmp;
	register char *tptr;
	char *tbufptr, *pc;

	gettty();	/* sets ospeed */

	tptr = (char *) alloc(1024);

	tbufptr = tbuf;
	if(!(tmp = getenv("TERM")))
		error("Can't get TERM.");
	if(tgetent(tptr,tmp) < 1)
		error("Unknown terminal type: %s.", tmp);
	if(pc = tgetstr("pc",&tbufptr))
		PC = *pc;
	if(!(BC = tgetstr("bc",&tbufptr))) {	
		if(!tgetflag("bs"))
			error("Terminal must backspace.");
		BC = tbufptr;
		tbufptr += 2;
		*BC = '\b';
	}
	HO = tgetstr("ho", &tbufptr);
	if(tgetnum("co") < COLNO || tgetnum("li") < ROWNO+2)
		error("Screen must be at least %d by %d!",
			ROWNO+2, COLNO);
	if(!(CL = tgetstr("cl",&tbufptr)) || !(CE = tgetstr("ce",&tbufptr)) ||
		!(ND = tgetstr("nd", &tbufptr)) ||
		!(UP = tgetstr("up",&tbufptr)) || tgetflag("os"))
		error("Hack needs CL, CE, UP, ND, and no OS.");
	if(!(CM = tgetstr("cm",&tbufptr)))
		printf("Use of hack on terminals without CM is suspect...\n");
	XD = tgetstr("xd",&tbufptr);
	SO = tgetstr("so",&tbufptr);
	SE = tgetstr("se",&tbufptr);
	if(!SO || !SE) SO = SE = 0;
	if(tbufptr-tbuf > sizeof(tbuf)) error("TERMCAP entry too big...\n");
	free(tptr);
}

/* Cursor movements */
extern xchar curx, cury;

curs(x,y)
register int x,y;	/* not xchar: perhaps xchar is unsigned and
			   curx-x would be unsigned as well */
{

	if (y == cury && x == curx) return;
	if(abs(cury-y)<= 3 && abs(curx-x)<= 3) nocmov(x,y);
	else if((x <= 3 && abs(cury-y)<= 3) || (!CM && x<abs(curx-x))) {
		(void) putchar('\r');
		curx = 1;
		nocmov(x,y);
	} else if(!CM) nocmov(x,y);
	else cmov(x,y);
}

nocmov(x,y)
{
	if (curx < x) {		/* Go to the right. */
		while (curx < x) {
			xputs(ND);
			curx++;
		}
	} else if (curx > x) {
		while (curx > x) {	/* Go to the left. */
			xputs(BC);
			curx--;
		}
	}
	if (cury > y) {
		if(UP) {
			while (cury > y) {	/* Go up. */
				xputs(UP);
				cury--;
			}
		} else cmov(x,y);
	} else if (cury < y) {
		if(XD) {
			while(cury<y) {
				xputs(XD);
				cury++;
			}
		} else cmov(x,y);
	}
}

cmov(x,y)
register x,y;
{
	if(!CM) error("Tries to cmov from %d %d to %d %d\n",curx,cury,x,y);
	xputs(tgoto(CM,x-1,y-1));
	cury = y;
	curx = x;
}

xputc(c) char c; {
	(void) fputc(c,stdout);
}

xputs(s) char *s; {
	tputs(s, 1, xputc);
}

cl_end() {
	xputs(CE);
}

clear_screen() {
	xputs(CL);
	curx = cury = 1;
}

home()
{
	if(HO) xputs(HO);
	else xputs(tgoto(CM,0,0));
	curx = cury = 1;
}

standoutbeg()
{
	if(SO) xputs(SO);
}

standoutend()
{
	if(SE) xputs(SE);
}

backsp()
{
	xputs(BC);
	curx--;
}

bell()
{
	putsym('\007');
}

delay_output() {
	/* delay 40 ms - could also use a 'nap'-system call */
	tputs("40", 1, xputc);
}
//E*O*F hack.termcap.c//

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

#include	"hack.h"
#define	SIZE(x)	(sizeof(x) / sizeof(x[0]))

timeout(){
register struct prop *upp;
	for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++)
	    if((upp->p_flgs & TIMEOUT) && !--upp->p_flgs) {
		if(upp->p_tofn) (*upp->p_tofn)();
		else switch(upp - u.uprops){
		case SICK:
			pline("You die because of food poisoning");
			killer = u.usick_cause;
			done("died");
			/* NOTREACHED */
		case FAST:
			pline("You feel yourself slowing down");
			break;
		case CONFUSION:
			pline("You feel less confused now");
			break;
		case BLIND:
			pline("You can see again");
			setsee();
			break;
		case INVIS:
			on_scr(u.ux,u.uy);
			pline("You are no longer invisible.");
		}
	}
}
//E*O*F hack.timeout.c//

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

#include "hack.h"
#include <stdio.h>
extern char *eos();
#define	TOPLSZ	(COLNO-8)	/* leave room for --More-- */
char toplines[BUFSZ];
xchar tlx, tly;			/* set by pline; used by addtopl */

struct topl {
	struct topl *next_topl;
	char *topl_text;
} *old_toplines, *last_redone_topl;
#define	OTLMAX	20		/* max nr of old toplines remembered */

doredotopl(){
	if(last_redone_topl)
		last_redone_topl = last_redone_topl->next_topl;
	if(!last_redone_topl)
		last_redone_topl = old_toplines;
	if(last_redone_topl){
		(void) strcpy(toplines, last_redone_topl->topl_text);
	}
	redotoplin();
	return(0);
}

redotoplin() {
	home();
	if(index(toplines, '\n')) cl_end();
	putstr(toplines);
	cl_end();
	tlx = curx;
	tly = cury;
	flags.topl = 1;
	if(tly > 1)
		more();
}

remember_topl() {
register struct topl *tl;
register int cnt = OTLMAX;
	if(last_redone_topl &&
	   !strcmp(toplines, last_redone_topl->topl_text)) return;
	if(old_toplines &&
	   !strcmp(toplines, old_toplines->topl_text)) return;
	last_redone_topl = 0;
	tl = (struct topl *)
		alloc((unsigned)(strlen(toplines) + sizeof(struct topl) + 1));
	tl->next_topl = old_toplines;
	tl->topl_text = (char *)(tl + 1);
	(void) strcpy(tl->topl_text, toplines);
	old_toplines = tl;
	while(cnt && tl){
		cnt--;
		tl = tl->next_topl;
	}
	if(tl && tl->next_topl){
		free((char *) tl->next_topl);
		tl->next_topl = 0;
	}
}

addtopl(s) char *s; {
	curs(tlx,tly);
	if(tlx + strlen(s) > COLNO) putsym('\n');
	putstr(s);
	tlx = curx;
	tly = cury;
	flags.topl = 1;
}

xmore(spaceflag)
boolean spaceflag;	/* TRUE if space required */
{
	if(flags.topl) {
		curs(tlx, tly);
		if(tlx + 8 > COLNO) putsym('\n'), tly++;
	}
	putstr("--More--");
	xwaitforspace(spaceflag);
	if(flags.topl && tly > 1) {
		home();
		cl_end();
		docorner(1, tly-1);
	}
	flags.topl = 0;
}

more(){
	xmore(TRUE);
}

cmore(){
	xmore(FALSE);
}

clrlin(){
	if(flags.topl) {
		home();
		cl_end();
		if(tly > 1) docorner(1, tly-1);
		remember_topl();
	}
	flags.topl = 0;
}

/*VARARGS1*/
pline(line,arg1,arg2,arg3,arg4,arg5,arg6)
register char *line,*arg1,*arg2,*arg3,*arg4,*arg5,*arg6;
{
	char pbuf[BUFSZ];
	register char *bp = pbuf, *tl;
	register int n,n0;

	if(!line || !*line) return;
	if(!index(line, '%')) (void) strcpy(pbuf,line); else
	(void) sprintf(pbuf,line,arg1,arg2,arg3,arg4,arg5,arg6);
	if(flags.topl == 1 && !strcmp(pbuf, toplines)) return;
	nscr();		/* %% */

	/* If there is room on the line, print message on same line */
	/* But messages like "You die..." deserve their own line */
	n0 = strlen(bp);
	if(flags.topl == 1 && tly == 1 &&
	    n0 + strlen(toplines) + 3 < TOPLSZ &&
	    strncmp(bp, "You ", 4)) {
		(void) strcat(toplines, "  ");
		(void) strcat(toplines, bp);
		tlx += 2;
		addtopl(bp);
		return;
	}
	if(flags.topl == 1) more();
	remember_topl();
	toplines[0] = 0;
	while(n0){
		if(n0 >= COLNO){
			/* look for appropriate cut point */
			n0 = 0;
			for(n = 0; n < COLNO; n++) if(bp[n] == ' ')
				n0 = n;
			if(!n0) for(n = 0; n < COLNO-1; n++)
				if(!letter(bp[n])) n0 = n;
			if(!n0) n0 = COLNO-2;
		}
		(void) strncpy((tl = eos(toplines)), bp, n0);
		tl[n0] = 0;
		bp += n0;

		/* remove trailing spaces, but leave one */
		while(n0 > 1 && tl[n0-1] == ' ' && tl[n0-2] == ' ')
			tl[--n0] = 0;

		n0 = strlen(bp);
		if(n0 && tl[0]) (void) strcat(tl, "\n");
	}
	redotoplin();
}

putsym(c) char c; {
	switch(c) {
	case '\b':
		backsp();
		return;
	case '\n':
		curx = 1;
		cury++;
		if(cury > tly) tly = cury;
		break;
	default:
		curx++;
		if(curx == COLNO) putsym('\n');
	}
	(void) putchar(c);
}

putstr(s) register char *s; {
	while(*s) putsym(*s++);
}
//E*O*F hack.topl.c//

exit 0

ron@vaxnix.UUCP (12/30/84)

# This is part 12 (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.track.c hack.trap.c hack.tty.c hack.u_init.c hack.vault.c hack.version.c

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

#include "hack.h"
#ifdef TRACK
#define	UTSZ	50

coord utrack[UTSZ];
int utcnt = 0;
int utpnt = 0;

initrack(){
	utcnt = utpnt = 0;
}

/* add to track */
settrack(){
	if(utcnt < UTSZ) utcnt++;
	if(utpnt == UTSZ) utpnt = 0;
	utrack[utpnt].x = u.ux;
	utrack[utpnt].y = u.uy;
	utpnt++;
}

coord *
gettrack(x,y) register x,y; {
register int i,cnt;
coord tc;
	cnt = utcnt;
	for(i = utpnt-1; cnt--; i--){
		if(i == -1) i = UTSZ-1;
		tc = utrack[i];
		if((x-tc.x)*(x-tc.x) + (y-tc.y)*(y-tc.y) < 3)
			return(&(utrack[i]));
	}
	return(0);
}
#endif TRACK
//E*O*F hack.track.c//

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

#include	"hack.h"
#include	"def.trap.h"

extern struct monst *makemon();

char vowels[] = "aeiou";

char *traps[] = {
	" bear trap",
	"n arrow trap",
	" dart trap",
	" trapdoor",
	" teleportation trap",
	" pit",
	" sleeping gas trap",
	" piercer",
	" mimic"
};

dotrap(trap) register struct gen *trap; {
	nomul(0);
	if(trap->gflag&SEEN && !rn2(5))
		pline("You escape a%s.",traps[trap->gflag&037]);
	else {
		trap->gflag |= SEEN;
		switch(trap->gflag & ~SEEN) {
		case SLP_GAS_TRAP:
			pline("A cloud of gas puts you to sleep!");
			nomul(-rnd(25));
			break;
		case BEAR_TRAP:
			if(Levitation) {
				pline("You float over a bear trap.");
				break;
			}
			u.utrap = 4 + rn2(4);
			u.utraptype = TT_BEARTRAP;
			pline("A bear trap closes on your foot!");
			break;
		case PIERC:
			deltrap(trap);
			if(makemon(PM_PIERC,u.ux,u.uy)) {
			  pline("A piercer suddenly drops from the ceiling!");
			  if(uarmh)
				pline("Its blow glances off your helmet.");
			  else
				(void) thitu(3,d(4,6),"falling piercer");
			}
			break;
		case ARROW_TRAP:
			pline("An arrow shoots out at you!");
			if(!thitu(8,rnd(6),"arrow")){
				mksobj_at(WEAPON_SYM, ARROW, u.ux, u.uy);
				fobj->quan = 1;
			}
			break;
		case TRAPDOOR:
			if(!xdnstair) {
pline("A trap door in the ceiling opens and a rock falls on your head!");
if(uarmh) pline("Fortunately, you are wearing a helmet!");
			losehp(uarmh ? 2 : d(2,10),"falling rock");
			} else {
			    register int newlevel = dlevel + 1;
				while(!rn2(4) && newlevel < 29)
					newlevel++;
				pline("A trap door opens up under you!");
				if(Levitation || u.ustuck) {
 				pline("For some reason you don't fall in.");
					break;
				}

				goto_level(newlevel, FALSE);
			}
			break;
		case DART_TRAP:
			pline("A little dart shoots out at you!");
			if(thitu(7,rnd(3),"little dart")) {
			    if(!rn2(6))
				poisoned("dart","poison dart");
			} else {
				mksobj_at(WEAPON_SYM, DART, u.ux, u.uy);
				fobj->quan = 1;
			}
			break;
		case TELEP_TRAP:
			newsym(u.ux,u.uy);
			tele();
			break;
		case PIT:
			if(Levitation) {
				pline("A pit opens up under you!");
				pline("You don't fall in!");
				break;
			}
			pline("You fall into a pit!");
			u.utrap = rn1(6,2);
			u.utraptype = TT_PIT;
			losehp(rnd(6),"fall into a pit");
			selftouch("Falling, you");
			break;
		default:
			pline("You hit a trap of type %d",trap->gflag);
			impossible();
		}
	}
}

mintrap(mtmp) register struct monst *mtmp; {
	register struct gen *gen = g_at(mtmp->mx, mtmp->my, ftrap);
	register int wasintrap = mtmp->mtrapped;

	if(!gen) {
		mtmp->mtrapped = 0;	/* perhaps teleported? */
	} else if(wasintrap) {
		if(!rn2(40)) mtmp->mtrapped = 0;
	} else {
	    register int tt = (gen->gflag & ~SEEN);
	    int in_sight = cansee(mtmp->mx,mtmp->my);
	    extern char mlarge[];
	    if(mtmp->mtrapseen & (1 << tt)) {
		/* he has been in such a trap - perhaps he escapes */
		if(rn2(4)) return(0);
	    }
	    mtmp->mtrapseen |= (1 << tt);
	    switch (tt) {
		case BEAR_TRAP:
			if(index(mlarge, mtmp->data->mlet)) {
				if(in_sight)
				  pline("%s is caught in a bear trap!",
					Monnam(mtmp));
				else
				  if(mtmp->data->mlet == 'o')
			    pline("You hear the roaring of an angry bear!");
				mtmp->mtrapped = 1;
			}
			break;
		case PIT:
			if(!index("Eyw", mtmp->data->mlet)) {
				mtmp->mtrapped = 1;
				if(in_sight)
				  pline("%s falls in a pit!", Monnam(mtmp));
			}
			break;
		case SLP_GAS_TRAP:
			if(!mtmp->msleep && !mtmp->mfroz) {
				mtmp->msleep = 1;
				if(in_sight)
				  pline("%s suddenly falls asleep!",
					Monnam(mtmp));
			}
			break;
		case TELEP_TRAP:
			rloc(mtmp);
			if(in_sight && !cansee(mtmp->mx,mtmp->my))
				pline("%s suddenly disappears!",
					Monnam(mtmp));
			break;
		case ARROW_TRAP:
			if(in_sight) {
				pline("%s is hit by an arrow!",
					Monnam(mtmp));
			}
			mtmp->mhp -= 3;
			break;
		case DART_TRAP:
			if(in_sight) {
				pline("%s is hit by a dart!",
					Monnam(mtmp));
			}
			mtmp->mhp -= 2;
			/* not mondied here !! */
			break;
		case TRAPDOOR:
			if(!xdnstair) {
				mtmp->mhp -= 10;
				if(in_sight)
pline("A trap door in the ceiling opens and a rock hits %s!", monnam(mtmp));
				break;
			}
			if(mtmp->data->mlet != 'w'){
				fall_down(mtmp);
				if(in_sight)
		pline("Suddenly, %s disappears out of sight.", monnam(mtmp));
				return(2);	/* no longer on this level */
			}
			break;
		case PIERC:
			break;
		default:
			pline("Some monster encountered an impossible trap.");
			impossible();
	    }
	}
	return(mtmp->mtrapped);
}

selftouch(arg) char *arg; {
	if(uwep && uwep->otyp == DEAD_COCKATRICE){
		pline("%s touch the dead cockatrice.", arg);
		pline("You turn to stone.");
		killer = objects[uwep->otyp].oc_name;
		done("died");
	}
}

float_up(){
	if(u.utrap) {
		if(u.utraptype == TT_PIT) {
			u.utrap = 0;
			pline("You float up, out of the pit!");
		} else {
			pline("You float up, only your leg is still stuck.");
		}
	} else
		pline("You start to float in the air!");
}

float_down(){
	register struct gen *trap;
	pline("You float gently to the ground.");
	if(trap = g_at(u.ux,u.uy,ftrap))
		switch(trap->gflag & 037) {
		case PIERC:
			break;
		case TRAPDOOR:
			if(!xdnstair || u.ustuck) break;
			/* fall into next case */
		default:
			dotrap(trap);
	}
	pickup();
}

tele()
{
extern coord getpos();
coord cc;
register int nux,nuy;
	if(Teleport_control) {
		pline("To what position do you want to be teleported?");
		cc = getpos(1, "the desired position"); /* 1: force valid */
		/* possible extensions: introduce a small error if
		   magic power is low; allow transfer to solid rock */
		if(teleok(cc.x, cc.y)){
			nux = cc.x;
			nuy = cc.y;
			goto gotpos;
		}
		pline("Sorry ...");
	}
	do {
		nux = rnd(COLNO-1);
		nuy = rn2(ROWNO);
	} while(!teleok(nux, nuy));
gotpos:
	if(Punished) unplacebc();
	unsee();
	u.utrap = 0;
	u.ustuck = 0;
	u.ux = nux;
	u.uy = nuy;
	setsee();
	if(Punished) placebc(1);
	if(u.uswallow){
		u.uswldtim = u.uswallow = 0;
		docrt();
	}
	nomul(0);
	(void) inshop();
	pickup();
	if(!Blind) read_engr_at(u.ux,u.uy);
}

teleok(x,y) register int x,y; {
	return( isok(x,y) && levl[x][y].typ > DOOR && !m_at(x,y) &&
		!sobj_at(ENORMOUS_ROCK,x,y) && !g_at(x,y,ftrap)
	);
	/* Note: gold is permitted (because of vaults) */
}

placebc(attach) int attach; {
	if(!uchain || !uball){
		pline("Where are your chain and ball??");
		impossible();
		return;
	}
	uball->ox = uchain->ox = u.ux;
	uball->oy = uchain->oy = u.uy;
	if(attach){
		uchain->nobj = fobj;
		fobj = uchain;
		if(!carried(uball)){
			uball->nobj = fobj;
			fobj = uball;
		}
	}
}

unplacebc(){
	if(!carried(uball)){
		freeobj(uball);
		unpobj(uball);
	}
	freeobj(uchain);
	unpobj(uchain);
}

level_tele() {
register int newlevel = 5 + rn2(20);	/* 5 - 24 */
	if(dlevel == newlevel)
		if(!xdnstair) newlevel--; else newlevel++;
	goto_level(newlevel, FALSE);
}
//E*O*F hack.trap.c//

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

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

struct sgttyb inittyb, curttyb;
extern short ospeed;


gettty(){
	(void) gtty(0, &inittyb);
	(void) gtty(0, &curttyb);
	ospeed = inittyb.sg_ospeed;
/*
	if(ospeed <= B300) flags.oneline = 1;
*/
	getioctls();
	xtabs();
}

/* reset terminal to original state */
settty(s) char *s; {
	clear_screen();
	if(s) printf(s);
	(void) fflush(stdout);
	if(stty(0, &inittyb) == -1) puts("Cannot change tty");
	flags.echo = (inittyb.sg_flags & ECHO) ? ON : OFF;
	flags.cbreak = (inittyb.sg_flags & CBREAK) ? ON : OFF;
	setioctls();
}

setctty(){
	if(stty(0, &curttyb) == -1) puts("Cannot change tty");
}

setftty(){
register int ef = (flags.echo == ON) ? ECHO : 0;
register int cf = (flags.cbreak == ON) ? CBREAK : 0;
register int change = 0;
	if((curttyb.sg_flags & ECHO) != ef){
		curttyb.sg_flags &= ~ECHO;
		curttyb.sg_flags |= ef;
		change++;
	}
	if((curttyb.sg_flags & CBREAK) != cf){
		curttyb.sg_flags &= ~CBREAK;
		curttyb.sg_flags |= cf;
		change++;
	}
	if(change){
		setctty();
	}
}

echo(n)
register n;
{

	/* (void) gtty(0,&curttyb); */
	if(n == ON)
		curttyb.sg_flags |= ECHO;
	else
		curttyb.sg_flags &= ~ECHO;
	setctty();
}

/* always want to expand tabs, or to send a clear line char before
   printing something on topline */
xtabs()
{

	/* (void) gtty(0, &curttyb); */
	curttyb.sg_flags |= XTABS;
	setctty();
}

#ifdef LONG_CMD
cbreak(n)
register n;
{

	/* (void) gtty(0,&curttyb); */
	if(n == ON)
		curttyb.sg_flags |= CBREAK;
	else
		curttyb.sg_flags &= ~CBREAK;
	setctty();
}
#endif LONG_CMD

getlin(bufp)
register char *bufp;
{
	register char *obufp = bufp;
	register int c;

	flags.topl = 2;		/* nonempty, no --More-- required */
	for(;;) {
		(void) fflush(stdout);
		if((c = getchar()) == EOF) {
			*bufp = 0;
			return;
		}
		if(c == '\b') {
			if(bufp != obufp) {
				bufp--;
				putstr("\b \b"); /* putsym converts \b */
			} else	bell();
		} else if(c == '\n') {
			*bufp = 0;
			return;
		} else {
			*bufp = c;
			bufp[1] = 0;
			putstr(bufp);
			if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
				bufp++;
		}
	}
}

getret() {
	xgetret(TRUE);
}

cgetret() {
	xgetret(FALSE);
}

xgetret(spaceflag)
boolean spaceflag;	/* TRUE if space (return) required */
{
	printf("\nHit %s to continue: ",
		flags.cbreak ? "space" : "return");
	xwaitforspace(spaceflag);
}

char morc;	/* tell the outside world what char he used */

xwaitforspace(spaceflag)
boolean spaceflag;
{
register int c;

	(void) fflush(stdout);
	morc = 0;

	while((c = getchar()) != '\n') {
	    if(c == EOF) {
		settty("End of input?\n");
		exit(0);
	    }
	    if(flags.cbreak) {
		if(c == ' ') break;
		if(!spaceflag && letter(c)) {
			morc = c;
			break;
		}
	    }
	}
}

char *
parse()
{
	static char inline[COLNO];
	register foo;

	flags.move = 1;
	if(!Invis) curs(u.ux,u.uy+2); else home();
	(void) fflush(stdout);
	while((foo = getchar()) >= '0' && foo <= '9')
		multi += 10*multi+foo-'0';
	if(multi) {
		multi--;
		save_cm = inline;
	}
	inline[0] = foo;
	inline[1] = 0;
	if(foo == EOF) {
		settty("End of input?\n");
		exit(0);
	}
	if(foo == 'f' || foo == 'F'){
		inline[1] = getchar();
#ifdef QUEST
		if(inline[1] == foo) inline[2] = getchar(); else
#endif QUEST
		inline[2] = 0;
	}
	if(foo == 'm' || foo == 'M'){
		inline[1] = getchar();
		inline[2] = 0;
	}
	clrlin();
	return(inline);
}

char
readchar() {
	register int sym;
	(void) fflush(stdout);
	if((sym = getchar()) == EOF) {
		settty("End of input?\n");
		exit(0);
	}
	if(flags.topl == 1) flags.topl = 2;
	return((char) sym);
}
//E*O*F hack.tty.c//

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

#include "hack.h"
#include <stdio.h>
#include <signal.h>
#define	Strcat	(void) strcat
#define	UNDEF_TYP	0
#define	UNDEF_SPE	(-1)
extern struct obj *addinv();
extern char plname[];

char pl_character[PL_CSIZ];

struct trobj {
	uchar trotyp;
	schar trspe;
	char trolet;
	Bitfield(trquan,6);
	Bitfield(trknown,1);
};

#ifdef WIZARD
struct trobj Extra_objs[] = {
	{ 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0 }
};
#endif WIZARD

struct trobj Cave_man[] = {
	{ MACE, 1, WEAPON_SYM, 1, 1 },
	{ BOW, 1, WEAPON_SYM, 1, 1 },
	{ ARROW, 0, WEAPON_SYM, 25, 1 },	/* quan is variable */
	{ LEATHER_ARMOR, 2, ARMOR_SYM, 1, 1 },
	{ 0, 0, 0, 0, 0}
};

struct trobj Fighter[] = {
	{ TWO_HANDED_SWORD, 0, WEAPON_SYM, 1, 1 },
	{ RING_MAIL, 3, ARMOR_SYM, 1, 1 },
	{ 0, 0, 0, 0, 0 }
};

struct trobj Knight[] = {
	{ LONG_SWORD, 0, WEAPON_SYM, 1, 1 },
	{ SPEAR, 2, WEAPON_SYM, 1, 1 },
	{ RING_MAIL, 4, ARMOR_SYM, 1, 1 },
	{ HELMET, 1, ARMOR_SYM, 1, 1 },
	{ SHIELD, 1, ARMOR_SYM, 1, 1 },
	{ PAIR_OF_GLOVES, 1, ARMOR_SYM, 1, 1 },
	{ 0, 0, 0, 0, 0 }
};

struct trobj Speleologist[] = {
	{ STUDDED_LEATHER_ARMOR, 3, ARMOR_SYM, 1, 1 },
	{ UNDEF_TYP, 0, POTION_SYM, 2, 0 },
	{ FOOD_RATION, 0, FOOD_SYM, 3, 1 },
	{ ICE_BOX, 0, TOOL_SYM, 1, 0 },
	{ 0, 0, 0, 0, 0}
};

struct trobj Tourist[] = {
	{ UNDEF_TYP, 0, FOOD_SYM, 10, 1 },
	{ POT_EXTRA_HEALING, 0, POTION_SYM, 2, 0 },
	{ EXPENSIVE_CAMERA, 0, TOOL_SYM, 1, 1 },
	{ DART, 2, WEAPON_SYM, 25, 1 },	/* quan is variable */
	{ 0, 0, 0, 0, 0 }
};

struct trobj Wizard[] = {
	{ ELVEN_CLOAK, 1, ARMOR_SYM, 1, 1 },
	{ UNDEF_TYP, UNDEF_SPE, WAND_SYM, 2, 0 },
	{ UNDEF_TYP, UNDEF_SPE, RING_SYM, 2, 0 },
	{ UNDEF_TYP, UNDEF_SPE, POTION_SYM, 2, 0 },
	{ UNDEF_TYP, UNDEF_SPE, SCROLL_SYM, 3, 0 },
	{ 0, 0, 0, 0, 0 }
};

#ifdef NEWS
int u_in_infl;

u_in_intrup(){
	u_in_infl++;
	(void) signal(SIGINT, u_in_intrup);
}
#endif NEWS

u_init(){
register int c,pc,i;
#ifdef NEWS
	/* It is not unlikely that we get an interrupt here
	   intended to kill the news; unfortunately this would
	   also kill (part of) the following question */
int (*prevsig)() = signal(SIGINT, u_in_intrup);
#endif NEWS
register char *cp;
char buf[256];
	if(pc = pl_character[0]) goto got_suffix;
	buf[0] = 0;
	Strcat(buf, "\nTell me what kind of character you are:\n");
	Strcat(buf, "Are you a Tourist, a Speleologist, a Fighter,\n");
	Strcat(buf, "\ta Knight, a Cave-man or a Wizard? [TSFKCW] ");
intrup:
	for(cp = buf; *cp; cp++){
#ifdef NEWS
		if(u_in_infl){
			u_in_infl = 0;
			goto intrup;
		}
#endif NEWS
		(void) putchar(*cp);
	}
loop:
	(void) fflush(stdout);
	pc = 0;
	while((c = getchar()) != '\n') {
		if(c == EOF) {
#ifdef NEWS
			if(u_in_infl) goto intrup;	/* %% */
#endif NEWS
			settty("\nEnd of input?\n");
			exit(0);
		}
		if(!pc) pc = c;
	}
	if(!pc || !index("TSFKCWtsfkcw", pc)){
		printf("Answer with T,S,F,K,C or W. What are you? ");
		goto loop;
	}
got_suffix:
	if('a' <= pc && pc <= 'z') pc += 'A'-'a';

#ifdef NEWS
	(void) signal(SIGINT,prevsig);
#endif NEWS

	u.usym = '@';
	u.ulevel = 1;
	init_uhunger();
	u.uhpmax = u.uhp = 12;
	u.ustrmax = u.ustr = !rn2(20) ? 14 + rn2(7) : 16;
#ifdef QUEST
	u.uhorizon = 6;
#endif QUEST
	switch(pc) {
	case 'C':
		setpl_char("Cave-man");
		Cave_man[2].trquan = 12 + rnd(9)*rnd(9);
		u.uhp = u.uhpmax = 16;
		u.ustr = u.ustrmax = 18;
		ini_inv(Cave_man);
		break;
	case 'T':
		setpl_char("Tourist");
		Tourist[3].trquan = 20 + rnd(20);
		u.ugold = u.ugold0 = rnd(1000);
		u.uhp = u.uhpmax = 10;
		u.ustr = u.ustrmax = 8;
		ini_inv(Tourist);
		break;
	case 'W':
		setpl_char("Wizard");
		for(i=1; i<=4; i++) if(!rn2(5))
			Wizard[i].trquan += rn2(3) - 1;
		u.uhp = u.uhpmax = 15;
		u.ustr = u.ustrmax = 16;
		ini_inv(Wizard);
		break;
	case 'S':
		setpl_char("Speleologist");
		Fast = INTRINSIC;
		Stealth = INTRINSIC;
		u.uhp = u.uhpmax = 12;
		u.ustr = u.ustrmax = 10;
		ini_inv(Speleologist);
		break;
	case 'K':
		setpl_char("Knight");
		u.uhp = u.uhpmax = 12;
		u.ustr = u.ustrmax = 10;
		ini_inv(Knight);
		break;
	case 'F':
		setpl_char("Fighter");
		u.uhp = u.uhpmax = 14;
		u.ustr = u.ustrmax = 17;
		ini_inv(Fighter);
	}
	find_ac();
	/* make sure he can carry all he has - especially for T's */
	while(inv_weight() > 0 && u.ustr < 118)
		u.ustr++, u.ustrmax++;
#ifdef WIZARD
	if(wizard) wiz_inv();
#endif WIZARD
}

ini_inv(trop) register struct trobj *trop; {
register struct obj *obj;
extern struct obj *mkobj();
	while(trop->trolet) {
		obj = mkobj(trop->trolet);
		obj->known = trop->trknown;
		obj->cursed = 0;
		if(obj->olet == WEAPON_SYM){
			obj->quan = trop->trquan;
			trop->trquan = 1;
		}
		if(trop->trspe != UNDEF_SPE)
			obj->spe = trop->trspe;
		if(trop->trotyp != UNDEF_TYP)
			obj->otyp = trop->trotyp;
		obj->owt = weight(obj);	/* defined after setting otyp+quan */
		obj = addinv(obj);
		if(obj->olet == ARMOR_SYM){
			switch(obj->otyp){
			case SHIELD:
				if(!uarms) setworn(obj, W_ARMS);
				break;
			case HELMET:
				if(!uarmh) setworn(obj, W_ARMH);
				break;
			case PAIR_OF_GLOVES:
				if(!uarmg) setworn(obj, W_ARMG);
				break;
			case ELVEN_CLOAK:
				if(!uarm2)
					setworn(obj, W_ARM);
				break;
			default:
				if(!uarm) setworn(obj, W_ARM);
			}
		}
		if(obj->olet == WEAPON_SYM)
			if(!uwep) setuwep(obj);
		if(--trop->trquan) continue;	/* make a similar object */
		trop++;
	}
}

#ifdef WIZARD
wiz_inv(){
register struct trobj *trop = &Extra_objs[0];
extern char *getenv();
register char *ep = getenv("INVENT");
register int type;
	while(ep && *ep) {
		type = atoi(ep);
		ep = index(ep, ',');
		if(ep) while(*ep == ',' || *ep == ' ') ep++;
		if(type <= 0 || type > NROFOBJECTS) continue;
		trop->trotyp = type;
		trop->trolet = objects[type].oc_olet;
		trop->trspe = 4;
		trop->trknown = 1;
		trop->trquan = 1;
		ini_inv(trop);
	}
	/* give him a wand of wishing by default */
	trop->trotyp = WAN_WISHING;
	trop->trolet = WAND_SYM;
	trop->trspe = 20;
	trop->trknown = 1;
	trop->trquan = 1;
	ini_inv(trop);
}
#endif WIZARD

setpl_char(plc) char *plc; {
	(void) strncpy(pl_character, plc, PL_CSIZ-1);
	pl_character[PL_CSIZ-1] = 0;
}

plnamesuffix() {
register char *p;
	if(p = rindex(plname, '-')) {
		*p = 0;
		if(!plname[0]) {
			askname();
			plnamesuffix();
		}
		if(index("TSFKCWtsfkcw", p[1])) {
			pl_character[0] = p[1];
			pl_character[1] = 0;
		}
	}
}
//E*O*F hack.u_init.c//

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

#include	"hack.h"
#ifdef QUEST
setgd(/* mtmp */) /* struct monst *mtmp; */ {}
gd_move() { return(2); }
gddead(mtmp) struct monst *mtmp; {}
invault(){}

#else


extern struct monst *makemon();
#define	VAULT	6
#define	FCSIZ	(ROWNO+COLNO)
struct fakecorr {
	xchar fx,fy,ftyp;
};

struct egd {
	int fcbeg, fcend;	/* fcend: first unused pos */
	xchar gdx, gdy;		/* goal of guard's walk */
	unsigned gddone:1;
	struct fakecorr fakecorr[FCSIZ];
};

struct permonst pm_guard =
	{ "guard", '@', 12, 12, -1, 4, 10, sizeof(struct egd) };

struct monst *guard;
int gdlevel;
#define	EGD	((struct egd *)(&(guard->mextra[0])))

restfakecorr(){
register fcx,fcy,fcbeg;
register struct rm *crm;

	while((fcbeg = EGD->fcbeg) < EGD->fcend) {
		fcx = EGD->fakecorr[fcbeg].fx;
		fcy = EGD->fakecorr[fcbeg].fy;
		if((u.ux == fcx && u.uy == fcy) || cansee(fcx,fcy) ||
		   m_at(fcx,fcy))
			return;
		crm = &levl[fcx][fcy];
		crm->typ = EGD->fakecorr[fcbeg].ftyp;
		if(!crm->typ) crm->seen = 0;
		newsym(fcx,fcy);
		EGD->fcbeg++;
	}
	/* it seems he left the corridor - let the guard disappear */
	mondead(guard);
	guard = 0;
}

setgd(){
register struct monst *mtmp;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isgd){
		guard = mtmp;
		gdlevel = dlevel;
		return;
	}
	guard = 0;
}

invault(){
register tmp = inroom(u.ux, u.uy);
	if(tmp < 0 || rooms[tmp].rtype != VAULT) {
		u.uinvault = 0;
		return;
	}
	if(++u.uinvault % 50 == 0 && (!guard || gdlevel != dlevel)) {
	char buf[BUFSZ];
	register x,y,dx,dy,gx,gy;

		/* first find the goal for the guard */
		for(dy = 0; dy < ROWNO; dy++)
		  for(y = u.uy-dy; y <= u.uy+dy; y++) {
		    if(y > u.uy-dy) y = u.uy+dy;
		    if(y < 0 || y > ROWNO-1) continue;
		    for(x = u.ux; x < COLNO; x++)
			if(levl[x][y].typ == CORR) goto fnd;
		    for(x = u.ux-1; x > 0; x--)
			if(levl[x][y].typ == CORR) goto fnd;
		}
		impossible();
		tele();
		return;
	fnd:
		gx = x; gy = y;

		/* next find a good place for a door in the wall */
		x = u.ux; y = u.uy;
		while(levl[x][y].typ > DOOR) {
			dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
			dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
			if(abs(gx-x) >= abs(gy-y)) x += dx;
			else y += dy;
		}

		/* make something interesting happen */
		if(!(guard = makemon(&pm_guard,x,y))) return;
		guard->isgd = guard->mpeaceful = 1;
		EGD->gddone = 0;
		gdlevel = dlevel;
		if(!cansee(guard->mx, guard->my)) {
			mondead(guard);
			guard = 0;
			return;
		}
		EGD->gdx = gx;
		EGD->gdy = gy;
		EGD->fcbeg = 0;
		EGD->fakecorr[0].fx = x;
		EGD->fakecorr[0].fy = y;
		EGD->fakecorr[0].ftyp = levl[x][y].typ;
		levl[x][y].typ = DOOR;
		EGD->fcend = 1;

		pline("Suddenly one of the Vault's guards enters!");
		pmon(guard);
		pline("\"Hello stranger, who are you?\" - ");
		getlin(buf);
		clrlin();
		pline("\"I don't know you.\"");
		if(!u.ugold) pline("\"Please follow me.\"");
		else {
		    pline("\"Most likely all that gold was stolen from this vault.\"");
		    pline("\"Please drop your gold (say d$ ) and follow me.\"");
		}
	}
}

gd_move(){
register int x,y,dx,dy,gx,gy,nx,ny,tmp;
register struct fakecorr *fcp;
register struct rm *crm;
	if(!guard || gdlevel != dlevel){
		pline("Where is the guard?");
		impossible();
		return(2);	/* died */
	}
	if(u.ugold || dist(guard->mx,guard->my) > 2 || EGD->gddone){
		restfakecorr();
		return(0);	/* didnt move */
	}
	x = guard->mx;
	y = guard->my;
	/* look around (hor & vert only) for accessible places */
	for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++)
	    if(nx == x || ny == y) if(nx != x || ny != y)
	    if(isok(nx,ny))
	    if((tmp = (crm = &levl[nx][ny])->typ) >= SDOOR) {
		register int i;
		for(i = EGD->fcbeg; i < EGD->fcend; i++)
			if(EGD->fakecorr[i].fx == nx &&
			   EGD->fakecorr[i].fy == ny)
				goto nextnxy;
		if((i = inroom(nx,ny)) >= 0 && rooms[i].rtype == VAULT)
			goto nextnxy;
		/* seems we found a good place to leave him alone */
		EGD->gddone = 1;
		if(tmp >= DOOR) goto newpos;
		crm->typ = (tmp == SCORR) ? CORR : DOOR;
		goto proceed;
	nextnxy:	;
	}
	nx = x;
	ny = y;
	gx = EGD->gdx;
	gy = EGD->gdy;
	dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
	dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
	if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy;

	while((tmp = (crm = &levl[nx][ny])->typ) != 0) {
	/* in view of the above we must have  tmp < SDOOR */
	/* must be a wall here */
		if(isok(nx+nx-x,ny+ny-y) && levl[nx+nx-x][ny+ny-y].typ > DOOR){
			crm->typ = DOOR;
			goto proceed;
		}
		if(dy && nx != x) {
			nx = x; ny = y+dy; dx = 0;
			continue;
		}
		if(dx && ny != y) {
			ny = y; nx = x+dx; dy = 0;
			continue;
		}
		/* I don't like this, but ... */
		crm->typ = DOOR;
		goto proceed;
	}
	crm->typ = CORR;
proceed:
	fcp = &(EGD->fakecorr[EGD->fcend]);
	if(EGD->fcend++ == FCSIZ) panic("fakecorr overflow");
	fcp->fx = nx;
	fcp->fy = ny;
	fcp->ftyp = tmp;
newpos:
	if(EGD->gddone) nx = ny = 0;
	guard->mx = nx;
	guard->my = ny;
	pmon(guard);
	restfakecorr();
	return(1);
}

gddead(){
	guard = 0;
}


#endif QUEST
//E*O*F hack.vault.c//

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

#include	"date.h"

doversion(){
	pline("%s 1.0 preliminary version - last edit %s.",
#ifdef QUEST
		"Quest"
#else
		"Hack"
#endif QUEST
	, datestring);
	return(0);
}
//E*O*F hack.version.c//

exit 0

Ron Reisor <reisor%udel-eecis3.delaware@udel-relay.ARPA> (01/06/85)

Would someone please send out another copy?

Ron