[net.sources.games] Larn 12.0 part 1/6

noah@condor.UUCP (Noah Morgan) (08/08/86)

*** REPLACE THIS LINE WITH YOUR MESSAGE ***
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Fixed.Bugs
#	Make.lint
#	Makefile
#	README
#	bill.c
#	config.c
#	create.c
#	diag.c
#	fortune.c
#	help.c
#	savelev.c
# This archive created: Wed Aug  6 14:58:42 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Fixed.Bugs'" '(11821 characters)'
if test -f 'Fixed.Bugs'
then
	echo shar: will not over-write existing file "'Fixed.Bugs'"
else
cat << \SHAR_EOF > 'Fixed.Bugs'
This is a list of the fixes/enhancements made to larn V11.0 in Version 12.0.
(Version numbers consist of 2 parts: ver.subver.  When the save file format
changes, ver must be bumped.  This is why the next release of Larn is 12.0
and not 11.1. This is used in the savefile routines to check for out-of-date
save files).  This list was mainly meant to be a record of what changed,
for my own sanity.  It's included for your benefit (Warning: SPOILER!):

0.  lprintf() in fileio.c (now called io.c) has been changed to use varargs
	so that its variable number of arguments usage is now portable.  Pyramids
	primarily had this problem.

1.	Panic handler was added to signal.c.  This routine catches fatal errors
	like segmentation faults, bus errors, illegal instructions, etc., and
	trys to performs a savegame() before dumping core.  This helps prevent
	the loss of a good game due to a game malfunction.  Also, the name of the
	signal received is printed, instead of just its number.

2.	The version number of the program is now selectable from the Makefile.
	see the symbols VER and SUBVER.

3.	When at an altar, pray and donate 3000000000 gp. and ye used to receive
	a whopping amount of gold due to a wraparound problem with the signed 
	ints.  This has been fixed by using unsigned longs when asking for money
	amounts.

4.	It was possible that when compiled with work hours checking, checkpointing
	enabled, and having "play-day-play" in the .larnopts file a segmentation
	fault would occur at its first attempt to do a checkpoint.  This was due
	to an improperly declared savefilename array in tok.c.  This has been fixed.

5.	on level H, casting a missile weapon (mle cld ssp bal lit) off the edge of
	the level would mess up the display, as it didn't know when to stop.  This
	is needless to say, fixed.  Absolute bounds are now in effect for missile
	type spells, see godirect() in monster.c.

6.  The create monster routine will now create monsters in random positions
	around the player.  Before, the 1st one would always be created to the
	upper left.

7.	If you vpr or lit at a throne, it would summon a gnome king that you
	would have to deal with.  However, as each throne has only one king with it,
	successive vpr's should not create more gnome kings.  Presently, successive
	vpr's will create more kings.  This has been fixed.

8.	The mechanism to manage spheres of annihilation has been reworked to provide
	a cleaner design and to eliminate some possible problems.

9.	The spell gen (genocide monsters) has been implemented.

10.	When dropping a ring of strength and having been weakened to STR=3 the
	player might end up with a negative strength.  Strength is now stored
	in 2 variables, real strength, and strength bonuses.  Only real strength
	can now be weakened down to a minimum of 3, so unless you have a ring of
	strength -3 or less, strengths below 3 should not occur.

11. larn -h will now print out a list of all available command line options.

12. larn -o<optsfile> now lets you specify a .larnopts file on the command
	line.  This was necessary as part of the solution to number 14 below.

13.	The "savefile:" statement has been aded to the .larnopts format to allow
	specifying the savefilename (full path) for the savegame operation.
	This too was needed as part of # 14 below.

14. A player id facility has been added to larn.  The complaint was that
	the game used the userid to order the scoreboard, thus only one scoreboard
	entry was allowed for each userid.  If the compile time symbol UIDSCORE
	is defined at compilation time (see Makefile), this will still be true.
	However, if this define is omitted, the game will create and manage a
	file called ".playerids" where names are taken from the specified
	.larnopts file (now a command line option) and assigned a unique playerid.
	playerid's will now be used to govern scoreboard entry posting.  This
	feature makes it easy for one person to have many characters, each
	appearing on the scoreboard.  Be kind to your fellow players!
	The philosophy of one score per player gives more players the opportunity
	to bask in glory for all to see!

15. It is no longer required that the player be WIZID to create the scoreboard
	or to examine the logfile.  Anyone with the correct wizard's password can
	now use these command line options (password is only needed to create/clear
	the scoreboard).  If you want to prevent players from zeroing the 
	scoreboard, change the wizard's password. (in config.c) By the way, wizards
	may be alot of fun, but they are prevented from being placed on any
	scoreboard. (for clarification)

16. Monsters now have intelligence, that is some of them.  This determines if
	the monster moves using the previously stupid movement method, or by using
	the new IMM (intelligent monster movement) algorithm.  With IMM, monsters
	will move around corners, avoid pits, traps, etc.  With increasing levels
	of difficulty, more monsters will be using IMM.  Beware of IMM when 
	aggravated!  Those little beasties can really find you!

17. Added the scroll of life protection.

18. Larn now consults the file ".holiday" to check for holidays if the TIMECHECK
	option (no playing during working hours) is enabled.  Before, larn knew
	nothing about holidays.  It should now let people play if it is a holiday.
	The format for a .holiday entry is: "mmm dd yyyy comments . . .".

19. In nap() and napms() it is possible that with nap(0) or napms(0) there
	would be an infinite loop and the game would hang.  The case of nap(0)
	is now looked for.

20. The granularity of gold piles has been increased.  iarg[] has been changed
	from char's to short's, so instead of 255 x 10^n granularity we now have
	32767 x 10^n granularity.  This also means more than 255000 gp can be
	dropped in one place.  Not realistic, but it prevents a worthless
	annoyance.  Who said games were supposed to be realistic?

21. Termcap capability has been added to larn.  If the symbol VT100 is defined
	in the makefile, the game will be compiled to use only VT100 compatible
	terminals (Much more efficient).  If the symbol VT100 is omitted, the game
	will be compiled to use the termcap entry for whatever terminal you are
	using.  This involves an extra layer of output interpretation, as every
	byte sent to the terminal must be inspected for control tokens.
	Only 3 termcap entries need be found for the game to be functional:
	CM (cursor movement), CE (clear to end of line), and CL (clear screen).
	For a better display, the following are optional: AL (insert line), DL
	(delete line), SO (Standout begin), SE (Standout end), and CD (clear to end
	of screen).  The .larn.help file was left as is, with VT100 escape
	sequences in it.  If the termcap version of larn reads it, it is translated
	for the desired terminal type.  The .mail60* files have been removed, and
	their text is now included in bill.c so it can be used with any terminal.
	Note:  If compiled for termcap, and using a VT100, the display will act
	a little different.  This is because the VT100 does not have insert line/
	delete line codes, and the scrolling region must be simulated with vertical
	wraparound instead of scrolling.  Thanks goes to Michiel Huisjes for the
	original termcap patch.

22. When playing as wizard, if you go down stairs on 10 or V3, or up stairs
	on H, 1, or V1, etc. you would be placed in a phantom zone where the display
	was really weird ([-1] subscripting), and would eventually lead to a
	segmentation fault.  Stairs and volcano shafts now check for the level
	they are being used on.

23. In response to some sites having only unsigned chars (flame the
	manufacturer), the chars that were used to store positive and negative
	numbers have been changed to shorts.  This includes diroffx[], diroffy[],
	iarg[][][], ivenarg[], and some others.  I believe the changes are correct,
	but I have none of these machines to try it out on. (Volunteers?)

24. The function fullhit(n) in monster.c was supposed to return the damage
	done by n full hits on a monster.  It only returned the damage for ONE hit,
	thus severely limiting the usefulness of the web and sle spells.

25. Someone said that they were getting segmentation faults when they were
	reading scrolls as the wizard.  I couldn't find the problem, which may
	have had something to do with the signed char problem mentioned above.
	However, I've added a check in read_scroll() and quaff_potion() to trap
	any scroll or potion types that are not in the game.

26. "vt125" has been added to the acceptable terminal list
	(checked only if compiled with -DVT100).

27. In savegame() and restoregame(), there was a 6 hardwired into the i/o
	statements which assumed the size of struct cel was 6.  On some machines
	this caused the rightmost part of each level to not be saved in a savefile.
	These 6's have been replaced with sizeof(struct cel), and should now be
	portable.

28. The option "no-beep" has been added to the .larnopts file.  When specified,
	beeping is inhibited at the terminal.

29. When becoming wizard, no longer to you wear the ring of protection, and
	null scrolls and potions are no longer created.

30. Many spelling errors have been fixed, both in player messages, and in the
	code itself.  A thanks goes to Mars Gralia who sent me a detailed list of
	the mistakes.

31. When a player wins a game, if getlogin() fails, a segmentation fault will
	result, because the NULL returned from getlogin() is used as a pointer.
	This call has been replaced (now using loginname already determined).
	Also, the mail creation upon winning has been rewritten, mainly to allow
	termcapping of the text.

32. The Larn Revenue Service will now always appear on level H.  Before, it
	was only created if the player had outstanding taxes.  In that multiple
	save files per player are now more possible, this was seen as incorrect.

33. Input buffer flushing is now in effect.  If the input char queue exceeds
	5 bytes, the excess is discarded.  Also, if the player hits or gets hit
	all input bytes are flushed (within 1).  This relieves the situation
	where many moves have been typed ahead of the display and the player keeps
	getting hit while the queue of moves is processed.

34. When a savefile has been altered, a warning message is displayed to the
	effect that you've cheated, and you will not be placed on the normal
	scoreboard.  If you then save the game, and start 'er up again, memory 
	of the cheating was lost.  This has been fixed, by letting the scoreboard
	routines consult the cheating flag.  Also, the I node number of the
	savefile is written into the savefile, so cp'ing, etc., will avail the
	cheater not.  If high security is needed, the game should be run suid.
	This suid mode has not been made the default because most installations
	do not want to install it that way.

35. The sources have been run through lint, and most of lint's complaints have
	been taken care of.  An attempt was made to adjust the code for 16 bit int
	machines.  Many casts to long have been put in.  I don't know if it will
	run on a 16 bitter, but it should be closer to that end.

36. When larn starts up, if it can't find the scoreboard, it will now make a
	blank one instead of complaining that there is no scoreboard.  It is not
	necessary to do "larn -c" to initially create the scoreboard.

37. When listing out the logfile (larn -l), the error message "error reading
	from input file" has been fixed.  Also, the date & time of a player's
	demise is now included in the logfile.

38. When casting web or sle into a mirror, the game will no longer bash the
	player.  Instead, the player will either fall asleep or get stuck in his
	web.

39. Items like cookies, books, chests, swords of slashing, and Bessmann's
	flailing hammer can now be sold at the trading post.

SHAR_EOF
if test 11821 -ne "`wc -c < 'Fixed.Bugs'`"
then
	echo shar: error transmitting "'Fixed.Bugs'" '(should have been 11821 characters)'
fi
fi
echo shar: extracting "'Make.lint'" '(433 characters)'
if test -f 'Make.lint'
then
	echo shar: will not over-write existing file "'Make.lint'"
else
cat << \SHAR_EOF > 'Make.lint'
# makefile for lint test
LARNHOME = /save/noah/miscellany/dnd/.lfiles

OPTIONS = -DEXTRA -DBSD -DVER=12 -DSUBVER=0 -DTIMECHECK -DWIZID=163 -Dlint

FILS= main.c object.c create.c tok.c display.c global.c data.c io.c\
    monster.c store.c diag.c help.c config.c nap.c bill.c scores.c\
    signal.c moreobj.c movem.c regen.c fortune.c savelev.c

FLAGS= $(OPTIONS) -DLARNHOME=\"$(LARNHOME)/\"

larn: $(FILS)
	lint -ub $(FLAGS) $(FILS)

SHAR_EOF
if test 433 -ne "`wc -c < 'Make.lint'`"
then
	echo shar: error transmitting "'Make.lint'" '(should have been 433 characters)'
fi
fi
echo shar: extracting "'Makefile'" '(4042 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# Configuration options
#  LARNHOME is the directory where the larn data files will be installed.
#  BINDIR is the directory where the larn binary will be installed.

LARNHOME = /c/noah/public/.lfiles
BINDIR = /c/noah/public
CC= cc

# -ltermlib may need to be changed to -ltermcap on some systems
TERMLIB= -ltermlib

# Available compile time options:
#   WIZID=xxx  - this is the userid (or playerid) of the wizard.  Default is
#					zero (superuser), which disables all wizard functions.
#					Players must have this userid (or playerid) in order to
#					become the non-scoring wizard player.  Definition of WIZID
#					to non-zero will enable the special wizard debugging
#					commands.  For root to become wizard, use WIZID= -1.
#   EXTRA      - incorporates code to gather additional performance statistics
#   TIMECHECK  - incorporates code to disable play during working hours (8-5)
#   SYSV       - use system III/V (instead of V7) type ioctl calls
#   BSD        - use BSD specific features (mostly timer and signal stuff)
#   BSD4.1     - use BSD4.1 to avoid some 4.2 dependencies (must be used with
#					BSD above; do not mix with SYSV)
#   HIDEBYLINK - if defined, the program attempts to hide from ps
#   DOCHECKPOINTS - if not defined, checkpoint files are periodically written
#                   by the larn process (no forking) if enabled in the .larnopts
#					description file.  Checkpointing is handy on an unreliable
#					system, but takes CPU. Inclusion of DOCHECKPOINTS will cause
#					fork()ing to perform the checkpoints (again if enabled in
#					the .larnopts file).  This usually avoids pauses in larn
#					while the checkpointing is being done (on large machines).
#   SAVEINHOME - put save files in users HOME instead of LARNHOME the as default
#	VER        - This is the version of the software, example:  12
#	SUBVER     - This is the revision of the software, example:  1
#	FLUSHNO=#  - Set the input queue excess flushing threshold (default 5)
#	NOVARARGS  - Define for systems that don't have varargs (a default varargs
#					will be used).
#	MACRORND   - Define to use macro version of rnd() and rund() (fast & big)
#	UIDSCORE   - Define to use user id's to manage scoreboard.  Leaving this out
#					will cause player id's from the file ".playerids" to be used
#					instead.  (.playerids is created upon demand).  Only one
#					entry per id # is allowed in each scoreboard
#					(winning & non-winning).
#	VT100	  - Compile for using vt100 family of terminals.  Omission of this
#					define will cause larn to use termcap, but it will be MUCH
#					slower due to an extra layer of output interpretation. 
#					Also, only VT100 mode allows 2 different standout modes,
#					inverse video, and bold video.  And only in VT100 mode is
#					the scrolling region of the terminal used (much nicer than
#					insert/delete line sequences to simulate it, if VT100 is
#					omitted).
#	NONAP	  - This causes napms() to return immediately instead of delaying
#					n milliseconds.  This define may be needed on some systems
#					if the nap stuff does not work correctly (possible hang).
#					nap() is primarilly used to delay for effect when casting
#					missile type spells.
#

OPTIONS = -DEXTRA -DBSD -DVER=12 -DSUBVER=0 -DTIMECHECK -DWIZID=1000 -DVT100 -DHIDEBYLINK

# End of configurable make options
########################################################################
#
OBJS= main.o object.o create.o tok.o display.o global.o data.o io.o monster.o\
	store.o diag.o help.o config.o nap.o bill.o scores.o signal.o moreobj.o\
	movem.o regen.o fortune.o savelev.o

DOTFILES= .larn.help .larnmaze .larnopts .lfortune

FLAGS= -O $(OPTIONS) -DLARNHOME=\"$(LARNHOME)/\"

larn: larn12.0
larn12.0: $(OBJS) 
	$(CC) $(FLAGS) $(OBJS) -o larn12.0 $(TERMLIB)
	size larn12.0

all: larn install

.c.o:	$<
	$(CC) -c $(FLAGS) $*.c
	chmod 0600 $*.o

$(OBJS): header.h

install:
	if test ! -d $(LARNHOME) ; then mkdir $(LARNHOME); fi
	-chmod a+w $(LARNHOME)
	cp larn12.0 $(BINDIR)/larn
	cp $(DOTFILES) $(LARNHOME)
SHAR_EOF
if test 4042 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 4042 characters)'
fi
fi
echo shar: extracting "'README'" '(6363 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
Larn is a dungeon type game program.  Larn is a adventure/action game similar
in concept to rogue or hack, but with a much different feel. 
Try it, you'll like it!

You will have to edit the Makefile to reflect your configuration.  Define
LARNHOME as the place where the larn auxiliary files will reside, and
BINDIR as the place where the larn executable should be placed.  Type
"make" to compile, or "make all" to compile and install ("make install"
does just the install).

Here's a list of what is in each of the various source files:

Fixed.Bugs		this is a list of the things that were changed since ver 11.0
Makefile        makefile script to compile the program
Make.lint		makefile script to run larn sources through lint
README			this is what you are now reading
bill.c          code for the letters of praise if player wins
config.c        data definitions for the installation dependent data --
                    savefilenames, where the scorefiles are, etc.
create.c        code to create the dungeon and all objects
data.c          data definitions for the game -- no code here
diag.c          code to produce diagnostic data for wizards, & savegame stuff
display.c       code to update the display on the screen
fortune.c		code for the fortune cookies
global.c        code for globally used functions that are specific to larn
header.h        constant and structure definitions
help.c          code for the help screens in the game of larn
.holidays		data file which lists upcoming holidays
io.c    	    code to handle file and terminal i/o
.larn.help.uue	larn help file (UUENCODED)
.larnmaze		data file for pre-made mazes
.larnopts		a sample .larnopts option data file
.lfortune		data file which contains the hints
main.c          code for the main command control and parsing
monster.c       code to handle attack and defense modes with monsters
moreobj.c		code for the fountains, altars, thrones
movem.c         code to move the monsters around the dungeon
nap.c           code to sleep for less than a second
object.c        code to handle objects in the dungeon
regen.c			code to regenerate the player and advance game time
savelev.c	code to get/put a level from level storage into working level memory
scores.c        code to process and manage the scoreboard
signal.c        code to handle UNIX signals that are trapped
store.c         code for the larn thrift shoppe, bank, trading post, lrs
tok.c           code for the input front end and options file processing

To find out how to play the game, run it and type in a '?' to get the help
screens.  By the way, the wizards password is "pvnert(x)" and to become wizard
type in an underscore, you are then prompted for the password.  Wizards are
non-scoring characters that get enlightenment, everlasting expanded 
awareness, and one of every object in the game.  They help the author to debug
the game.

Note regarding the wizard id:  If you are using userid's, then WIZID must be
set to the userid of the person who can become wizard.  If you are using
player id's, WIZID must be set to the playerid (edit file .playerids if needed)
of the player who can become wizard.

You may want to clear out the scoreboard.  The command "larn -c" will make a
new scoreboard.  It will prompt you for the wizards password.

BUGS & FIXES:

James McNamara has volunteered to maintain the latest sources, and provide
latest bug fixes to anyone who asks.  Both James and I will field requests for
sources, for those who ask.

			  ___	Prince of Gems (alias Noah Morgan)
			 /.  \	USENET: panda!condor!noah
			 \   /	at GenRad Inc.  Bolton MA
			  \ /
			   v

Below is some additional info about the installation of larn:

Install: Notes on the game LARN installation.
Larn is copyrighted 1986 by Noah Morgan.
This file (below) originally by James D. McNamara, last update 7/27/86 by nm

THIS DISTRIBUTION:

	You should receive six (6) shar files, which are:

	larn.part-1
	larn.part-2
	larn.part-3
	larn.part-4
	larn.part-5
	larn.part-6

I.	Use /bin/sh (or your system equivalent) to "unravel" shar files
	larn.part-1, ..., larn.part-6.  I suggest you do this directly
	into $LARNHOME (See Section III.).  Notable files:

	README	-	The author's how-to.
	MANIFEST -	Files you should have.

III.	Edit a copy of "Makefile" and leave the edited version in $LARNHOME.

All the "configuration" options are tidily near the top of the "Makefile."
Here are the ones you probably will want to edit:

LARNHOME	I specified (literally) the directory, with path from root,
	where "larn" will reside.  This included where I put the *.c files,
	it is where the *.o files ended up, as well as all data and *.h files.
	i suspect the *.c and intallation-documentation files can be moved off,
	but the data and bits must all remain here for execution.

BINDIR		I specified (literally) the directory, with path from root,
	where the executable "larn" will reside.  The "Makefile" will dump
	the "a.out", named "larn", in this directory.  My BINDIR was not
	my LARNHOME, so $BINDIR/larn was the ONLY file dumed here.  You'll
	probably have to chmod it for public execute, etc.


OPTIONS		This is how *I* specified them... they are documented in-line:
	OPTIONS = -DWIZZARD -DWIZID=157 -DEXTRA -DBSD -DSAVEINHOME

IV.	Compile the bugger.  Read "README" before you do.  You have a couple
	of options here:

	make			- will not install, suspect good for updates.
	make all		- compile (and) intall
	make install		- just install

	I did "make" and then "make install" -- seems to work "ok", but
	"make all" probably safer, if I had known.  Note that "Makefile"
	is the default file for "make."

V.	Execute and have fun.  If wizard code "ok", larn -c will refresh the
	scoreboard.  Play and win (or get killed) to put somebody on the
	scoreboard.

VI.	BUGS and FIXES.

	Please forward any bug-fixes in these regards to me (or Noah), so I may
	compile a fix-list for other installers.  Thanks.

Regards,
===============================================================================
James D. McNamara                    CSNET:   jim@bu-cs
                                     ARPANET: jim%bu-cs@csnet-relay
                                     UUCP:    ...harvard!bu-cs!jim
                                     BITNET:  jim%bu-cs%csnet-relay.arpa@wiscvm
===============================================================================

SHAR_EOF
if test 6363 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 6363 characters)'
fi
fi
echo shar: extracting "'bill.c'" '(5909 characters)'
if test -f 'bill.c'
then
	echo shar: will not over-write existing file "'bill.c'"
else
cat << \SHAR_EOF > 'bill.c'
#include "header.h"
/* bill.c		 "Larn is copyrighted 1986 by Noah Morgan. */
static char mail600[32];
/*
 *	function to create the tax bill for the user
 */
static int pid;
static letter1()
  {
  sprintf(mail600,"/tmp/#%dmail600",pid); /* prepare path */
  if (lcreat(mail600) < 0) { write(1,"can't write 600 letter\n",23); return(0);}
  lprcat("\n\n\n\n\n\n\n\n\n\n\n\n");
  standout("From:"); lprcat("  the LRS (Larn Revenue Service)\n");
  standout("\nSubject:"); lprcat("  undeclared income\n");
  lprcat("\n   We heard you survived the caverns of Larn.  Let me be the");
  lprcat("\nfirst to congratulate you on your success.  It is quite a feat.");
  lprcat("\nIt must also have been very profitable for you.");
  lprcat("\n\n   The Dungeon Master has informed us that you brought");
  lprintf("\n%d gold pieces back with you from your journey.  As the",(long)c[GOLD]);
  lprcat("\ncounty of Larn is in dire need of funds, we have spared no time");
  lprintf("\nin preparing your tax bill.  You owe %d gold pieces as",
	(long)c[GOLD]*TAXRATE);
  lprcat("\nof this notice, and is due within 5 days.  Failure to pay will");
  lprcat("\nmean penalties.  Once again, congratulations, We look forward");
  lprcat("\nto your future successful expeditions.\n");
  lwclose(); return(1);
  }

static letter2()
  {
  sprintf(mail600,"/tmp/#%dmail600",pid); /* prepare path */
  if (lcreat(mail600) < 0) { write(1,"can't write 601 letter\n",23); return(0);}
  lprcat("\n\n\n\n\n\n\n\n\n\n\n\n");
  standout("From:"); lprcat("  His Majesty King Wilfred of Larndom\n");
  standout("\nSubject:"); lprcat("  a noble deed\n");
  lprcat("\n   I have heard of your magnificent feat, and I, King Wilfred,");
  lprcat("\nforthwith declare today to be a national holiday.  Furthermore,");
  lprcat("\nhence three days, Ye be invited to the castle to receive the");
  lprcat("\nhonour of Knight of the realm.  Upon thy name shall it be written. . .");
  lprcat("\nBravery and courage be yours.");
  lprcat("\nMay you live in happiness forevermore . . .\n");
  lwclose(); return(1);
  }

static letter3()
  {
  sprintf(mail600,"/tmp/#%dmail600",pid); /* prepare path */
  if (lcreat(mail600) < 0) { write(1,"can't write 602 letter\n",23); return(0);}
  lprcat("\n\n\n\n\n\n\n\n\n\n\n\n");
  standout("From:"); lprcat("  Count Endelford\n");
  standout("\nSubject:"); lprcat("  You Bastard!\n");
  lprcat("\n   I heard (from sources) of your journey.  Congratulations!");
  lprcat("\nYou Bastard!  With several attempts I have yet to endure the");
  lprcat(" caves,\nand you, a nobody, makes the journey!  From this time");
  lprcat(" onward, bewarned\nupon our meeting you shall pay the price!\n");
  lwclose(); return(1);
  }

static letter4()
  {
  sprintf(mail600,"/tmp/#%dmail600",pid); /* prepare path */
  if (lcreat(mail600) < 0) { write(1,"can't write 603 letter\n",23); return(0);}
  lprcat("\n\n\n\n\n\n\n\n\n\n\n\n");
  standout("From:"); lprcat("  Mainair, Duke of Larnty\n");
  standout("\nSubject:"); lprcat("  High Praise\n");
  lprcat("\n   With a certainty a hero I declare to be amongst us!  A nod of");
  lprcat("\nfavour I send to thee.  Me thinks Count Endelford this day of");
  lprcat("\nright breath'eth fire as of dragon of whom ye are slayer.  I");
  lprcat("\nyearn to behold his anger and jealously.  Should ye choose to");
  lprcat("\nunleash some of thy wealth upon those who be unfortunate, I,");
  lprcat("\nDuke Mainair, Shall equal thy gift also.\n");
  lwclose(); return(1);
  }

static letter5()
  {
  sprintf(mail600,"/tmp/#%dmail600",pid); /* prepare path */
  if (lcreat(mail600) < 0) { write(1,"can't write 604 letter\n",23); return(0);}
  lprcat("\n\n\n\n\n\n\n\n\n\n\n\n");
  standout("From:"); lprcat("  St. Mary's Children's Home\n");
  standout("\nSubject:"); lprcat("  these poor children\n");
  lprcat("\n   News of your great conquests has spread to all of Larndom.");
  lprcat("\nMight I have a moment of a great man's time.  We here at St.");
  lprcat("\nMary's Children's Home are very poor, and many children are");
  lprcat("\nstarving.  Disease is widespread and very often fatal without");
  lprcat("\ngood food.  Could you possibly find it in your heart to help us");
  lprcat("\nin our plight?  Whatever you could give will help much.");
  lprcat("\n(your gift is tax deductible)\n");
  lwclose(); return(1);
  }

static letter6()
  {
  sprintf(mail600,"/tmp/#%dmail600",pid); /* prepare path */
  if (lcreat(mail600) < 0) { write(1,"can't write 605 letter\n",23); return(0);}
  lprcat("\n\n\n\n\n\n\n\n\n\n\n\n");
  standout("From:"); lprcat("  The National Cancer Society of Larn\n");
  standout("\nSubject:"); lprcat("  hope\n");
  lprcat("\nCongratulations on your successful expedition.  We are sure much");
  lprcat("\ncourage and determination were needed on your quest.  There are");
  lprcat("\nmany though, that could never hope to undertake such a journey");
  lprcat("\ndue to an enfeebling disease -- cancer.  We at the National");
  lprcat("\nCancer Society of Larn wish to appeal to your philanthropy in");
  lprcat("\norder to save many good people -- possibly even yourself a few");
  lprcat("\nyears from now.  Much work needs to be done in researching this");
  lprcat("\ndreaded disease, and you can help today.  Could you please see it");
  lprcat("\nin your heart to give generously?  Your continued good health");
  lprcat("\ncan be your everlasting reward.\n");
  lwclose(); return(1);
  }

/*
 *	function to mail the letters to the player if a winner
 */
static int (*pfn[])()= { letter1, letter2, letter3, letter4, letter5, letter6 };
mailbill()
	{
	register int i;
	char buf[128];
	wait(0);  pid=getpid();
	if (fork() == 0)
		{
		resetscroll();
		for (i=0; i<sizeof(pfn)/sizeof(int (*)()); i++)
			if ((*pfn[i])())
				{
				sleep(20);  sprintf(buf,"mail %s < %s",loginname,mail600);
				system(buf);  unlink(mail600);
				}
		exit();
		}
	}
SHAR_EOF
if test 5909 -ne "`wc -c < 'bill.c'`"
then
	echo shar: error transmitting "'bill.c'" '(should have been 5909 characters)'
fi
fi
echo shar: extracting "'config.c'" '(1819 characters)'
if test -f 'config.c'
then
	echo shar: will not over-write existing file "'config.c'"
else
cat << \SHAR_EOF > 'config.c'
/*
 *	config.c	--	This defines the installation dependent variables.
 *                  Some strings are modified later.  ANSI C would
 *                  allow compile time string concatenation, we must
 *                  do runtime concatenation, in main.
 *
 *		Larn is copyrighted 1986 by Noah Morgan.
 */
#include "header.h"

#ifndef LARNHOME
#define LARNHOME "/usr/games/larn/"		/* normally supplied by a Makefile */
#endif

#ifndef WIZID
#define WIZID	0
#endif

/*
 *	All these strings will be appended to in main() to be complete filenames
 */

		/* the game save filename   */
char savefilename[SAVEFILENAMESIZE] = 					LARNHOME;

		/* the score file	    	*/
char scorefile[sizeof(LARNHOME)+sizeof(SCORENAME)] =	LARNHOME;

		/* the logging file     	*/
char logfile[sizeof(LARNHOME)+sizeof(LOGFNAME)]  =		LARNHOME;

		/* the help text file		*/
char helpfile[sizeof(LARNHOME)+sizeof(HELPNAME)] = 		LARNHOME;

		/* the maze data file		*/
char larnlevels[sizeof(LARNHOME)+sizeof(LEVELSNAME)] = 	LARNHOME;

		/* the fortune data file	*/
char fortfile[sizeof(LARNHOME)+sizeof(FORTSNAME)] =		LARNHOME;

		/* the .larnopts filename */
char optsfile[128] ="/.larnopts";				/* the option file			*/

		/* the player id datafile name */
char playerids[sizeof(LARNHOME)+sizeof(PLAYERIDS)] =	LARNHOME;

		/* the holiday datafile */
char holifile[sizeof(LARNHOME)+sizeof(HOLIFILE)] =		LARNHOME;

char diagfile[] ="Diagfile";					/* the diagnostic filename	*/
char ckpfile[] ="Larn12.0.ckp";					/* the checkpoint filename	*/
char *password ="pvnert(x)";					/* the wizards password <=32*/
#if WIZID == -1
int wisid=0;			/* the user id of the only person who can be wizard */
#else
int wisid=WIZID;		/* the user id of the only person who can be wizard */
#endif
char psname[PSNAMESIZE]="larn";						/* the process name		*/
SHAR_EOF
if test 1819 -ne "`wc -c < 'config.c'`"
then
	echo shar: error transmitting "'config.c'" '(should have been 1819 characters)'
fi
fi
echo shar: extracting "'create.c'" '(12972 characters)'
if test -f 'create.c'
then
	echo shar: will not over-write existing file "'create.c'"
else
cat << \SHAR_EOF > 'create.c'
/*	create.c		Larn is copyrighted 1986 by Noah Morgan. */
#include "header.h"
extern char spelknow[],larnlevels[];
extern char beenhere[],wizard,level;
extern short oldx,oldy;
/*
	makeplayer()

	subroutine to create the player and the players attributes
	this is called at the beginning of a game and at no other time
 */
makeplayer()
	{
	register int i;
	scbr();  clear();
	c[HPMAX]=c[HP]=10;		/*	start player off with 15 hit points	*/
	c[LEVEL]=1;				/*	player starts at level one			*/
	c[SPELLMAX]=c[SPELLS]=1;	/*	total # spells starts off as 3	*/
	c[REGENCOUNTER]=16;		c[ECOUNTER]=96;	/*start regeneration correctly*/
	c[SHIELD] = c[WEAR] = c[WIELD] = -1;
	for (i=0; i<26; i++)  iven[i]=0;
	spelknow[0]=spelknow[1]=1; /*he knows protection, magic missile*/
	if (c[HARDGAME]<=0)
		{
		iven[0]=OLEATHER; iven[1]=ODAGGER;
		ivenarg[1]=ivenarg[0]=c[WEAR]=0;  c[WIELD]=1;
		}
	playerx=rnd(MAXX-2);	playery=rnd(MAXY-2);
	oldx=0;			oldy=25;
	gtime=0;			/*	time clock starts at zero	*/
	cbak[SPELLS] = -50;
	for (i=0; i<6; i++)  c[i]=12; /* make the attributes, ie str, int, etc.	*/
	recalc();
	}

/*
	newcavelevel(level)
	int level;

	function to enter a new level.  This routine must be called anytime the
	player changes levels.  If that level is unknown it will be created.
	A new set of monsters will be created for a new level, and existing
	levels will get a few more monsters.
	Note that it is here we remove genocided monsters from the present level.
 */
newcavelevel(x)
	register int x;
	{
	register int i,j;
	if (beenhere[level]) savelevel();	/* put the level back into storage	*/
	level = x;				/* get the new level and put in working storage */
	if (beenhere[x]==0) for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++) know[j][i]=mitem[j][i]=0;
		else { getlevel(); sethp(0);  goto chgn; }
	makemaze(x);	makeobject(x);	beenhere[x]=1;  sethp(1);

#if WIZID
	if (wizard || x==0)
#else
	if (x==0)
#endif

		for (j=0; j<MAXY; j++)
			for (i=0; i<MAXX; i++)
				know[i][j]=1;
chgn: checkgen();	/* wipe out any genocided monsters */
	}

/*
	makemaze(level)
	int level;

	subroutine to make the caverns for a given level.  only walls are made.
 */
static int mx,mxl,mxh,my,myl,myh,tmp2;
 makemaze(k)
	int k;
	{
	register int i,j,tmp;
	int z;
	if (k > 1 && (rnd(17)<=4 || k==MAXLEVEL-1 || k==MAXLEVEL+MAXVLEVEL-1))
		{
		if (cannedlevel(k));	return;		/* read maze from data file */
		}
	if (k==0)  tmp=0;  else tmp=OWALL;
	for (i=0; i<MAXY; i++)	for (j=0; j<MAXX; j++)	item[j][i]=tmp;
	if (k==0) return;		eat(1,1);
	if (k==1) item[33][MAXY-1]=0;	/* exit from dungeon */

/*	now for open spaces -- not on level 10	*/
	if (k != MAXLEVEL-1)
		{
		tmp2 = rnd(3)+3;
		for (tmp=0; tmp<tmp2; tmp++)
			{
			my = rnd(11)+2;   myl = my - rnd(2);  myh = my + rnd(2);
			if (k < MAXLEVEL)
				{
				mx = rnd(44)+5;  mxl = mx - rnd(4);  mxh = mx + rnd(12)+3;
				z=0;
				}
		  	else
				{
				mx = rnd(60)+3;  mxl = mx - rnd(2);  mxh = mx + rnd(2);
				z = makemonst(k);
				}
			for (i=mxl; i<mxh; i++)		for (j=myl; j<myh; j++)
				{  item[i][j]=0;
				   if ((mitem[i][j]=z)) hitp[i][j]=monster[z].hitpoints;
				}
			}
		}
	if (k!=MAXLEVEL-1) { my=rnd(MAXY-2);  for (i=1; i<MAXX-1; i++)	item[i][my] = 0; }
	if (k>1)  treasureroom(k);
	}

/*
	function to eat away a filled in maze
 */
eat(xx,yy)
	register int xx,yy;
	{
	register int dir,try;
	dir = rnd(4);	try=2;
	while (try)
		{
		switch(dir)
			{
			case 1:	if (xx <= 2) break;		/*	west	*/
					if ((item[xx-1][yy]!=OWALL) || (item[xx-2][yy]!=OWALL))	break;
					item[xx-1][yy] = item[xx-2][yy] = 0;
					eat(xx-2,yy);	break;

			case 2:	if (xx >= MAXX-3) break;	/*	east	*/
					if ((item[xx+1][yy]!=OWALL) || (item[xx+2][yy]!=OWALL))	break;
					item[xx+1][yy] = item[xx+2][yy] = 0;
					eat(xx+2,yy);	break;

			case 3:	if (yy <= 2) break;		/*	south	*/
					if ((item[xx][yy-1]!=OWALL) || (item[xx][yy-2]!=OWALL))	break;
					item[xx][yy-1] = item[xx][yy-2] = 0;
					eat(xx,yy-2);	break;

			case 4:	if (yy >= MAXY-3 ) break;	/*	north	*/
					if ((item[xx][yy+1]!=OWALL) || (item[xx][yy+2]!=OWALL))	break;
					item[xx][yy+1] = item[xx][yy+2] = 0;
					eat(xx,yy+2);	break;
			};
		if (++dir > 4)	{ dir=1;  --try; }
		}
	}

/*
 *	function to read in a maze from a data file
 *
 *	Format of maze data file:  1st character = # of mazes in file (ascii digit)
 *				For each maze: 18 lines (1st 17 used) 67 characters per line
 *
 *	Special characters in maze data file:
 *
 *		#	wall			D	door			.	random monster
 *		~	eye of larn		!	cure dianthroritis
 *		-	random object
 */
cannedlevel(k)
	int k;
	{
	char *row,*lgetl();
	register int i,j;
	int it,arg,mit,marg;
	if (lopen(larnlevels)<0)
		{
		write(1,"Can't open the maze data file\n",30);	 died(-282); return(0);
		}
	i=lgetc();  if (i<='0') { died(-282); return(0); }
	for (i=18*rund(i-'0'); i>0; i--)	lgetl();   /* advance to desired maze */
	for (i=0; i<MAXY; i++)
		{
		row = lgetl();
		for (j=0; j<MAXX; j++)
			{
			it = mit = arg = marg = 0;
			switch(*row++)
				{
				case '#': it = OWALL;								break;
				case 'D': it = OCLOSEDDOOR;  	arg = rnd(30);		break;
				case '~': if (k!=MAXLEVEL-1) break;
						  it = OLARNEYE;
						  mit = rund(8)+DEMONLORD;
						  marg = monster[mit].hitpoints;			break;
				case '!': if (k!=MAXLEVEL+MAXVLEVEL-1)  break;
						  it = OPOTION;			arg = 21;
						  mit = DEMONLORD+7;
						  marg = monster[mit].hitpoints;			break;
				case '.': if (k<MAXLEVEL)  break;
						  mit = makemonst(k+1);
						  marg = monster[mit].hitpoints;			break;
				case '-': it = newobject(k+1,&arg);					break;
				};
			item[j][i] = it;		iarg[j][i] = arg;
			mitem[j][i] = mit;		hitp[j][i] = marg;

#if WIZID
			know[j][i] = (wizard) ? 1 : 0;
#else
			know[j][i] = 0;
#endif
			}
		}
	lrclose();
	return(1);
	}

/*
	function to make a treasure room on a level
	level 10's treasure room has the eye in it and demon lords
	level V3 has potion of cure dianthroritis and demon prince
 */
treasureroom(lv)
	register int lv;
	{
	register int tx,ty,xsize,ysize;

	for (tx=1+rnd(10);  tx<MAXX-10;  tx+=10)
	  if ( (lv==MAXLEVEL-1) || (lv==MAXLEVEL+MAXVLEVEL-1) || rnd(13)==2)
		{
		xsize = rnd(6)+3;  	    ysize = rnd(3)+3;  
		ty = rnd(MAXY-9)+1;  /* upper left corner of room */
		if (lv==MAXLEVEL-1 || lv==MAXLEVEL+MAXVLEVEL-1)
			troom(lv,xsize,ysize,tx=tx+rnd(MAXX-24),ty,rnd(3)+6);
			else troom(lv,xsize,ysize,tx,ty,rnd(9));
		}
	}

/*
 *	subroutine to create a treasure room of any size at a given location 
 *	room is filled with objects and monsters 
 *	the coordinate given is that of the upper left corner of the room
 */
troom(lv,xsize,ysize,tx,ty,glyph)
	int lv,xsize,ysize,tx,ty,glyph;
	{
	register int i,j;
	int tp1,tp2;
	for (j=ty-1; j<=ty+ysize; j++)
		for (i=tx-1; i<=tx+xsize; i++)			/* clear out space for room */
			item[i][j]=0;
	for (j=ty; j<ty+ysize; j++)
		for (i=tx; i<tx+xsize; i++)				/* now put in the walls */
			{
			item[i][j]=OWALL; mitem[i][j]=0; 
			}
	for (j=ty+1; j<ty+ysize-1; j++)
		for (i=tx+1; i<tx+xsize-1; i++)			/* now clear out interior */
			item[i][j]=0;

	switch(rnd(2))		/* locate the door on the treasure room */
		{
		case 1:	item[i=tx+rund(xsize)][j=ty+(ysize-1)*rund(2)]=OCLOSEDDOOR;
				iarg[i][j] = glyph;		/* on horizontal walls */
				break;
		case 2: item[i=tx+(xsize-1)*rund(2)][j=ty+rund(ysize)]=OCLOSEDDOOR;
				iarg[i][j] = glyph;		/* on vertical walls */
				break;
		};

	tp1=playerx;  tp2=playery;  playery=ty+(ysize>>1);
	if (c[HARDGAME]<2)
		for (playerx=tx+1; playerx<=tx+xsize-2; playerx+=2)
			for (i=0, j=rnd(6); i<=j; i++)
				{ something(lv+2); createmonster(makemonst(lv+1)); }
	else
		for (playerx=tx+1; playerx<=tx+xsize-2; playerx+=2)
			for (i=0, j=rnd(4); i<=j; i++)
				{ something(lv+2); createmonster(makemonst(lv+3)); }

	playerx=tp1;  playery=tp2;
	}

/*
	***********
	MAKE_OBJECT
	***********
	subroutine to create the objects in the maze for the given level
 */
makeobject(j)
	register int j;
	{
	register int i;
	if (j==0)
		{
		fillroom(OENTRANCE,0);		/*	entrance to dungeon			*/
		fillroom(ODNDSTORE,0);		/*	the DND STORE				*/
		fillroom(OSCHOOL,0);		/*	college of Larn				*/
		fillroom(OBANK,0);			/*	1st national bank of larn 	*/
		fillroom(OVOLDOWN,0);		/*	volcano shaft to temple 	*/
		fillroom(OHOME,0);			/*	the players home & family 	*/
		fillroom(OTRADEPOST,0);		/*  the trading post			*/
		fillroom(OLRS,0);			/*  the larn revenue service 	*/
		return;
		}

	if (j==MAXLEVEL) fillroom(OVOLUP,0); /* volcano shaft up from the temple */

/*	make the fixed objects in the maze STAIRS	*/
	if ((j>0) && (j != MAXLEVEL-1) && (j != MAXLEVEL+MAXVLEVEL-1))
		fillroom(OSTAIRSDOWN,0);
	if ((j > 1) && (j != MAXLEVEL))			fillroom(OSTAIRSUP,0);

/*	make the random objects in the maze		*/

	fillmroom(rund(3),OBOOK,j);				fillmroom(rund(3),OALTAR,0);
	fillmroom(rund(3),OSTATUE,0);			fillmroom(rund(3),OPIT,0);
	fillmroom(rund(3),OFOUNTAIN,0);			fillmroom( rnd(3)-2,OIVTELETRAP,0);
	fillmroom(rund(2),OTHRONE,0);			fillmroom(rund(2),OMIRROR,0);
	fillmroom(rund(2),OTRAPARROWIV,0);		fillmroom( rnd(3)-2,OIVDARTRAP,0);
	fillmroom(rund(3),OCOOKIE,0);
	if (j==1) fillmroom(1,OCHEST,j);
		else fillmroom(rund(2),OCHEST,j);
	if ((j != MAXLEVEL-1) && (j != MAXLEVEL+MAXVLEVEL-1))
		fillmroom(rund(2),OIVTRAPDOOR,0);
	if (j<=10)
		{
		fillmroom((rund(2)),ODIAMOND,rnd(10*j+1)+10);
		fillmroom(rund(2),ORUBY,rnd(6*j+1)+6);
		fillmroom(rund(2),OEMERALD,rnd(4*j+1)+4);
		fillmroom(rund(2),OSAPPHIRE,rnd(3*j+1)+2);
		}
	for (i=0; i<rnd(4)+3; i++)
		fillroom(OPOTION,newpotion());	/*	make a POTION	*/
	for (i=0; i<rnd(5)+3; i++)
		fillroom(OSCROLL,newscroll());	/*	make a SCROLL	*/
	for (i=0; i<rnd(12)+11; i++)
		fillroom(OGOLDPILE,12*rnd(j+1)+(j<<3)+10); /* make GOLD	*/
	if (j==5)	fillroom(OBANK2,0);				/*	branch office of the bank */
	froom(2,ORING,0);				/* a ring mail 			*/
	froom(1,OSTUDLEATHER,0);		/* a studded leather	*/
	froom(3,OSPLINT,0);				/* a splint mail		*/
	froom(5,OSHIELD,rund(3));		/* a shield				*/
	froom(2,OBATTLEAXE,rund(3));	/* a battle axe			*/
	froom(5,OLONGSWORD,rund(3));	/* a long sword			*/
	froom(5,OFLAIL,rund(3));		/* a flail				*/
	froom(4,OREGENRING,rund(3));	/* ring of regeneration */
	froom(1,OPROTRING,rund(3));	/* ring of protection	*/
	froom(2,OSTRRING,4);   		/* ring of strength + 4 */
	froom(7,OSPEAR,rnd(5));		/* a spear				*/
	froom(3,OORBOFDRAGON,0);	/* orb of dragon slaying*/
	froom(4,OSPIRITSCARAB,0);		/*scarab of negate spirit*/
	froom(4,OCUBEofUNDEAD,0);		/* cube of undead control	*/
	froom(2,ORINGOFEXTRA,0);	/* ring of extra regen		*/
	froom(3,ONOTHEFT,0);			/* device of antitheft 		*/
	froom(2,OSWORDofSLASHING,0); /* sword of slashing */
	if (c[BESSMANN]==0)
		{
		froom(4,OHAMMER,0);/*Bessman's flailing hammer*/ c[BESSMANN]=1;
		}
	if (c[HARDGAME]<3 || (rnd(4)==3))
		{
		if (j>3)
			{
			froom(3,OSWORD,3); 		/* sunsword + 3  		*/
			froom(5,O2SWORD,rnd(4));  /* a two handed sword	*/
			froom(3,OBELT,4);			/* belt of striking		*/
			froom(3,OENERGYRING,3);	/* energy ring			*/
			froom(4,OPLATE,5);		/* platemail + 5 		*/
			}
		}
	}

/*
	subroutine to fill in a number of objects of the same kind
 */

fillmroom(n,what,arg)
	int n,arg;
	char what;
	{
	register int i;
	for (i=0; i<n; i++)		fillroom(what,arg);
	}
froom(n,itm,arg)
	int n,arg;
	char itm;
	{	if (rnd(151) < n) fillroom(itm,arg);	}

/*
	subroutine to put an object into an empty room
 *	uses a random walk
 */
static fillroom(what,arg)
	int arg;
	char what;
	{
	register int x,y;

#ifdef EXTRA
	c[FILLROOM]++;
#endif

	x=rnd(MAXX-2);  y=rnd(MAXY-2);
	while (item[x][y])
		{

#ifdef EXTRA
		c[RANDOMWALK]++;	/* count up these random walks */
#endif

		x += rnd(3)-2;		y += rnd(3)-2;
		if (x > MAXX-2)  x=1;		if (x < 1)  x=MAXX-2;
		if (y > MAXY-2)  y=1;		if (y < 1)  y=MAXY-2;
		}
	item[x][y]=what;		iarg[x][y]=arg;
	}

/*
	subroutine to put monsters into an empty room without walls or other
	monsters
 */
fillmonst(what)
	char what;
	{
	register int x,y,trys;
	for (trys=5; trys>0; --trys) /* max # of creation attempts */
	  {
	  x=rnd(MAXX-2);  y=rnd(MAXY-2);
	  if ((item[x][y]==0) && (mitem[x][y]==0) && ((playerx!=x) || (playery!=y)))
	  	{
		mitem[x][y] = what;  know[x][y]=0;
		hitp[x][y] = monster[what].hitpoints;  return(0);
		}
	  }
	return(-1); /* creation failure */
	}

/*
	creates an entire set of monsters for a level
	must be done when entering a new level
	if sethp(1) then wipe out old monsters else leave them there
 */
sethp(flg)
	int flg;
	{
	register int i,j;
	if (flg) for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++) stealth[j][i]=0;
	if (level==0) { c[TELEFLAG]=0; return; } /*	if teleported and found level 1 then know level we are on */
	if (flg)   j = rnd(12) + 2 + (level>>1);   else   j = (level>>1) + 1;
	for (i=0; i<j; i++)  fillmonst(makemonst(level));
	positionplayer();
	}

/*
 *	Function to destroy all genocided monsters on the present level
 */
checkgen()
	{
	register int x,y;
	for (y=0; y<MAXY; y++)
		for (x=0; x<MAXX; x++)
			if (monster[mitem[x][y]].genocided)
				mitem[x][y]=0; /* no more monster */
	}
SHAR_EOF
if test 12972 -ne "`wc -c < 'create.c'`"
then
	echo shar: error transmitting "'create.c'" '(should have been 12972 characters)'
fi
fi
echo shar: extracting "'diag.c'" '(10229 characters)'
if test -f 'diag.c'
then
	echo shar: will not over-write existing file "'diag.c'"
else
cat << \SHAR_EOF > 'diag.c'
/*	diag.c		Larn is copyrighted 1986 by Noah Morgan. */
#include <sys/types.h>
#include <sys/times.h>
#include <sys/stat.h>
#include "header.h"
extern long int initialtime;
extern int rmst,maxitm,lasttime;
extern char nosignal;
static struct tms cputime;
/*
	***************************
	DIAG -- dungeon diagnostics
	***************************

	subroutine to print out data for debugging
 */
#ifdef EXTRA
static int rndcount[16];
diag()
	{
	register int i,j;
	int hit,dam;
	cursors();  lwclose();
	if (lcreat(diagfile) < 0)	/*	open the diagnostic file	*/
		{
		lcreat((char*)0); lprcat("\ndiagnostic failure\n"); return(-1);
		}

	write(1,"\nDiagnosing . . .\n",18);
	lprcat("\n\nBeginning of DIAG diagnostics ----------\n");

/*	for the character attributes	*/

	lprintf("\n\nPlayer attributes:\n\nHit points: %2d(%2d)",(long)c[HP],(long)c[HPMAX]);
	lprintf("\ngold: %d  Experience: %d  Character level: %d  Level in caverns: %d",
		(long)c[GOLD],(long)c[EXPERIENCE],(long)c[LEVEL],(long)level);
	lprintf("\nTotal types of monsters: %d",(long)MAXMONST+8);

	lprcat("\f\nHere's the dungeon:\n\n");

	i=level;
	for (j=0; j<MAXLEVEL+MAXVLEVEL; j++)
		{
		newcavelevel(j);
		lprintf("\nMaze for level %s:\n",levelname[level]);
		diagdrawscreen();
		}
	newcavelevel(i);

	lprcat("\f\nNow for the monster data:\n\n");
	lprcat("   Monster Name      LEV  AC   DAM  ATT  DEF    GOLD   HP     EXP   \n");
	lprcat("--------------------------------------------------------------------------\n");
	for (i=0; i<=MAXMONST+8; i++)
		{
		lprintf("%19s  %2d  %3d ",monster[i].name,(long)monster[i].level,(long)monster[i].armorclass);
		lprintf(" %3d  %3d  %3d  ",(long)monster[i].damage,(long)monster[i].attack,(long)monster[i].defense);
		lprintf("%6d  %3d   %6d\n",(long)monster[i].gold,(long)monster[i].hitpoints,(long)monster[i].experience);
		}

	lprcat("\n\nHere's a Table for the to hit percentages\n");
	lprcat("\n     We will be assuming that players level = 2 * monster level");
	lprcat("\n     and that the players dexterity and strength are 16.");
	lprcat("\n    to hit: if (rnd(22) < (2[monst AC] + your level + dex + WC/8 -1)/2) then hit");
	lprcat("\n    damage = rund(8) + WC/2 + STR - c[HARDGAME] - 4");
	lprcat("\n    to hit:  if rnd(22) < to hit  then player hits\n");
	lprcat("\n    Each entry is as follows:  to hit / damage / number hits to kill\n");
	lprcat("\n          monster     WC = 4         WC = 20        WC = 40");
	lprcat("\n---------------------------------------------------------------");
	for (i=0; i<=MAXMONST+8; i++)
		{
		hit = 2*monster[i].armorclass+2*monster[i].level+16;
		dam = 16 - c[HARDGAME];
		lprintf("\n%20s   %2d/%2d/%2d       %2d/%2d/%2d       %2d/%2d/%2d",
					monster[i].name,
					(long)(hit/2),(long)max(0,dam+2),(long)(monster[i].hitpoints/(dam+2)+1),
					(long)((hit+2)/2),(long)max(0,dam+10),(long)(monster[i].hitpoints/(dam+10)+1),
					(long)((hit+5)/2),(long)max(0,dam+20),(long)(monster[i].hitpoints/(dam+20)+1));
		}

	lprcat("\n\nHere's the list of available potions:\n\n");
	for (i=0; i<MAXPOTION; i++)	lprintf("%20s\n",&potionname[i][1]);
	lprcat("\n\nHere's the list of available scrolls:\n\n");
	for (i=0; i<MAXSCROLL; i++)	lprintf("%20s\n",&scrollname[i][1]);
	lprcat("\n\nHere's the spell list:\n\n");
	lprcat("spell          name           description\n");
	lprcat("-------------------------------------------------------------------------------------------\n\n");
	for (j=0; j<SPNUM; j++)
		{
		lprc(' ');	lprcat(spelcode[j]);
		lprintf(" %21s  %s\n",spelname[j],speldescript[j]); 
		}

	lprcat("\n\nFor the c[] array:\n");
	for (j=0; j<100; j+=10)
		{
		lprintf("\nc[%2d] = ",(long)j); for (i=0; i<9; i++) lprintf("%5d ",(long)c[i+j]);
		}

	lprcat("\n\nTest of random number generator ----------------");
	lprcat("\n    for 25,000 calls divided into 16 slots\n\n");

	for (i=0; i<16; i++)  rndcount[i]=0;
	for (i=0; i<25000; i++)	rndcount[rund(16)]++;
	for (i=0; i<16; i++)  { lprintf("  %5d",(long)rndcount[i]); if (i==7) lprc('\n'); }

	lprcat("\n\n");			lwclose();
	lcreat((char*)0);		lprcat("Done Diagnosing . . .");
	return(0);
	}
/*
	subroutine to count the number of occurrences of an object
 */
dcount(l)
	int l;
	{
	register int i,j,p;
	int k;
	k=0;
	for (i=0; i<MAXX; i++)
		for (j=0; j<MAXY; j++)
			for (p=0; p<MAXLEVEL; p++)
				if (cell[p*MAXX*MAXY+i*MAXY+j].item == l) k++;
	return(k);
	}

/*
	subroutine to draw the whole screen as the player knows it
 */
diagdrawscreen()
	{
	register int i,j,k;

	for (i=0; i<MAXY; i++)

/*	for the east west walls of this line	*/
		{
		for (j=0; j<MAXX; j++)	if (k=mitem[j][i]) lprc(monstnamelist[k]); else
								lprc(objnamelist[item[j][i]]);
		lprc('\n');
		}
	}
#endif

/*
	to save the game in a file
 */
static long int zzz=0;
savegame(fname)
	char *fname;
	{
	register int i,k;
	register struct sphere *sp;
	struct stat statbuf;
	nosignal=1;  lflush();	savelevel();
	ointerest();
	if (lcreat(fname) < 0)
		{
		lcreat((char*)0); lprintf("\nCan't open file <%s> to save game\n",fname);
		nosignal=0;  return(-1);
		}

	set_score_output();
	lwrite((char*)beenhere,MAXLEVEL+MAXVLEVEL);
	for (k=0; k<MAXLEVEL+MAXVLEVEL; k++)
		if (beenhere[k])
			lwrite((char*)&cell[k*MAXX*MAXY],sizeof(struct cel)*MAXY*MAXX);
	times(&cputime);	/* get cpu time */
	c[CPUTIME] += (cputime.tms_utime+cputime.tms_stime)/60;
	lwrite((char*)&c[0],100*sizeof(long));
	lprint((long)gtime);		lprc(level);
	lprc(playerx);		lprc(playery);
	lwrite((char*)iven,26);	lwrite((char*)ivenarg,26*sizeof(short));
	for (k=0; k<MAXSCROLL; k++)  lprc(scrollname[k][0]);
	for (k=0; k<MAXPOTION; k++)  lprc(potionname[k][0]);
	lwrite((char*)spelknow,SPNUM);		 lprc(wizard);
	lprc(rmst);		/*	random monster generation counter */
	for (i=0; i<90; i++)	lprc(itm[i].qty);
	lwrite((char*)course,25);			lprc(cheat);		lprc(VERSION);
	for (i=0; i<MAXMONST; i++) lprc(monster[i].genocided); /* genocide info */
	for (sp=spheres; sp; sp=sp->p)
		lwrite((char*)sp,sizeof(struct sphere));	/* save spheres of annihilation */
	time(&zzz);			lprint((long)(zzz-initialtime));
	lwrite((char*)&zzz,sizeof(long));
	if (fstat(lfd,&statbuf)< 0) lprint(0L);
	else lprint((long)statbuf.st_ino); /* inode # */
	lwclose();	lastmonst[0] = 0;
#ifndef VT100
	setscroll();
#endif VT100
	lcreat((char*)0);  nosignal=0;
	return(0);
	}

restoregame(fname)
	char *fname;
	{
	register int i,k;
	register struct sphere *sp,*sp2;
	struct stat filetimes;
	cursors(); lprcat("\nRestoring . . .");  lflush();
	if (lopen(fname) <= 0)
		{
		lcreat((char*)0); lprintf("\nCan't open file <%s>to restore game\n",fname);
		nap(2000); c[GOLD]=c[BANKACCOUNT]=0;  died(-265); return;
		}

	lrfill((char*)beenhere,MAXLEVEL+MAXVLEVEL);
	for (k=0; k<MAXLEVEL+MAXVLEVEL; k++)
		if (beenhere[k])
			lrfill((char*)&cell[k*MAXX*MAXY],sizeof(struct cel)*MAXY*MAXX);

	lrfill((char*)&c[0],100*sizeof(long));	gtime = lrint();
	level = c[CAVELEVEL] = lgetc();
	playerx = lgetc();		playery = lgetc();
	lrfill((char*)iven,26);		lrfill((char*)ivenarg,26*sizeof(short));
	for (k=0; k<MAXSCROLL; k++)  scrollname[k][0] = lgetc();
	for (k=0; k<MAXPOTION; k++)  potionname[k][0] = lgetc();
	lrfill((char*)spelknow,SPNUM);		wizard = lgetc();
	rmst = lgetc();			/*	random monster creation flag */

	for (i=0; i<90; i++)	itm[i].qty = lgetc();
	lrfill((char*)course,25);			cheat = lgetc();
	if (VERSION != lgetc())		/*  version number  */
		{
		cheat=1;
		lprcat("Sorry, But your save file is for an older version of larn\n");
		nap(2000); c[GOLD]=c[BANKACCOUNT]=0;  died(-266); return;
		}

	for (i=0; i<MAXMONST; i++) monster[i].genocided=lgetc(); /* genocide info */
	for (sp=0,i=0; i<c[SPHCAST]; i++)
		{
		sp2 = sp;
		sp = (struct sphere *)malloc(sizeof(struct sphere));
		if (sp==0) { write(2,"Can't malloc() for sphere space\n",32); break; }
		lrfill((char*)sp,sizeof(struct sphere));	/* get spheres of annihilation */
		sp->p=0;	/* null out pointer */
		if (i==0) spheres=sp;	/* beginning of list */
			else sp2->p = sp;
		}

	time(&zzz);
	initialtime = zzz-lrint();
	fstat(fd,&filetimes);	/*	get the creation and modification time of file	*/
	lrfill((char*)&zzz,sizeof(long));	zzz += 6;
	if (filetimes.st_ctime > zzz) fsorry();	/*	file create time	*/
	else if (filetimes.st_mtime > zzz) fsorry(); /*	file modify time	*/
	if (c[HP]<0) { died(284); return; }	/* died a post mortem death */

	oldx = oldy = 0;
	i = lrint();  /* inode # */
	if (i && (filetimes.st_ino!=i)) fsorry();
	lrclose();
	if (strcmp(fname,ckpfile) == 0)
		{
		if (lappend(fname) < 0) fcheat();  else { lprc(' '); lwclose(); }
		lcreat((char*)0);
		}
	else if (unlink(fname) < 0) fcheat(); /* can't unlink save file */
/*	for the greedy cheater checker	*/
	for (k=0; k<6; k++) if (c[k]>99) greedy();
	if (c[HPMAX]>999 || c[SPELLMAX]>125) greedy();
	if (c[LEVEL]==25 && c[EXPERIENCE]>skill[24]) /* if patch up lev 25 player */
		{
		long tmp;
		tmp = c[EXPERIENCE]-skill[24]; /* amount to go up */
		c[EXPERIENCE] = skill[24];
		raiseexperience((long)tmp);
		}
	getlevel();  lasttime=gtime;
	}

/*
	subroutine to not allow greedy cheaters
 */
greedy()
	{
#if WIZID
	if (wizard) return;
#endif

	lprcat("\n\nI am so sorry, but your character is a little TOO good!  Since this\n");
	lprcat("cannot normally happen from an honest game, I must assume that you cheated.\n");
	lprcat("In that you are GREEDY as well as a CHEATER, I cannot allow this game\n");
	lprcat("to continue.\n"); nap(5000);  c[GOLD]=c[BANKACCOUNT]=0;  died(-267); return;
	}

/*
	subroutine to not allow altered save files and terminate the attempted
	restart
 */
fsorry()
	{
	lprcat("\nSorry, but your savefile has been altered.\n");
	lprcat("However, seeing as I am a good sport, I will let you play.\n");
	lprcat("Be advised though, you won't be placed on the normal scoreboard.");
	cheat = 1;	nap(4000);
	}

/*
	subroutine to not allow game if save file can't be deleted
 */
fcheat()
	{
#if WIZID
	if (wizard) return;
#endif

	lprcat("\nSorry, but your savefile can't be deleted.  This can only mean\n");
	lprcat("that you tried to CHEAT by protecting the directory the savefile\n");
	lprcat("is in.  Since this is unfair to the rest of the larn community, I\n");
	lprcat("cannot let you play this game.\n");
	nap(5000);  c[GOLD]=c[BANKACCOUNT]=0;  died(-268); return;
	}
SHAR_EOF
if test 10229 -ne "`wc -c < 'diag.c'`"
then
	echo shar: error transmitting "'diag.c'" '(should have been 10229 characters)'
fi
fi
echo shar: extracting "'fortune.c'" '(1874 characters)'
if test -f 'fortune.c'
then
	echo shar: will not over-write existing file "'fortune.c'"
else
cat << \SHAR_EOF > 'fortune.c'
/* fortune.c		 Larn is copyrighted 1986 by Noah Morgan. */
#include <sys/types.h>
#include <sys/stat.h>

#ifndef BSD4.1
#include <fcntl.h>
#else BSD4.1
#define O_RDONLY 0
#endif BSD4.1

#include "header.h"
/*
 *	function to return a random fortune from the fortune file
 */
static char *base=0;	/* pointer to the fortune text */
static char **flines=0;	/* array of pointers to each fortune */
static int fd=0;		/* true if we have load the fortune info */
static int nlines=0;	/* # lines in fortune database */

char *fortune(file)
	char *file;
	{
	register char *p;
	register int lines,tmp;
	struct stat stat;
	char *malloc();
	if (fd==0)
		{
		if ((fd=open(file,O_RDONLY)) < 0)	/* open the file */
			return(0); /* can't find file */

	/* find out how big fortune file is and get memory for it */
		stat.st_size = 16384;
		if ((fstat(fd,&stat) < 0) || ((base=malloc(1+stat.st_size)) == 0))
			{
			close(fd); fd= -1; free((char*)base); return(0); 	/* can't stat file */
			}

	/* read in the entire fortune file */
		if (read(fd,base,stat.st_size) != stat.st_size)
			{
			close(fd); fd= -1; free((char*)base); return(0); 	/* can't read file */
			}
		close(fd);  base[stat.st_size]=0;	/* final NULL termination */

	/* count up all the lines (and NULL terminate) to know memory needs */
		for (p=base,lines=0; p<base+stat.st_size; p++) /* count lines */
			if (*p == '\n') *p=0,lines++;
		nlines = lines;

	/* get memory for array of pointers to each fortune */
		if ((flines=(char**)malloc(nlines*sizeof(char*))) == 0)
			{
			free((char*)base); fd= -1; return(0); /* malloc() failure */
			}

	/* now assign each pointer to a line */
		for (p=base,tmp=0; tmp<nlines; tmp++)
			{
			flines[tmp]=p;  while (*p++); /* advance to next line */
			}
		}

	if (fd > 2)	/* if we have a database to look at */
		return(flines[rund((nlines<=0)?1:nlines)]);
	else 
		return(0);
	}
SHAR_EOF
if test 1874 -ne "`wc -c < 'fortune.c'`"
then
	echo shar: error transmitting "'fortune.c'" '(should have been 1874 characters)'
fi
fi
echo shar: extracting "'help.c'" '(2234 characters)'
if test -f 'help.c'
then
	echo shar: will not over-write existing file "'help.c'"
else
cat << \SHAR_EOF > 'help.c'
/*	help.c		Larn is copyrighted 1986 by Noah Morgan. */
#include "header.h"
/*
 *	help function to display the help info	
 *
 *	format of the .larn.help file
 *
 *	1st character of file:	# of pages of help available (ascii digit)
 *	page (23 lines) for the introductory message (not counted in above)
 *	pages of help text (23 lines per page)
 */
extern char helpfile[];
help()
	{
	register int i,j;
#ifndef VT100
	char tmbuf[128];	/* intermediate translation buffer when not a VT100 */
#endif VT100
	if ((j=openhelp()) < 0)  return;	/* open the help file and get # pages */
	for (i=0; i<23; i++) lgetl();	/* skip over intro message */
	for (;  j>0; j--)
		{
		clear();
		for (i=0; i<23; i++)
#ifdef VT100
			lprcat(lgetl());	/* print out each line that we read in */
#else VT100
			{ tmcapcnv(tmbuf,lgetl());  lprcat(tmbuf); } /* intercept \33's */
#endif VT100
		if (j>1)
			{
			lprcat("    ---- Press ");  standout("return");
			lprcat(" to exit, ");  standout("space");
			lprcat(" for more help ---- ");
			i=0; while ((i!=' ') && (i!='\n') && (i!='\33')) i=getchar();
			if ((i=='\n') || (i=='\33'))
				{
				lrclose();  setscroll();  drawscreen();  return;
				}
			}
		}
	lrclose();  retcont();  drawscreen();
	}

/*
 *	function to display the welcome message and background
 */
welcome()
	{
	register int i;
#ifndef VT100
	char tmbuf[128];	/* intermediate translation buffer when not a VT100 */
#endif VT100
	if (openhelp() < 0)  return;   	/* open the help file */
	clear();
	for(i=0; i<23; i++)
#ifdef VT100
			lprcat(lgetl());	/* print out each line that we read in */
#else VT100
			{ tmcapcnv(tmbuf,lgetl());  lprcat(tmbuf); } /* intercept \33's */
#endif VT100
	lrclose();  retcont();	/* press return to continue */
	}

/*
 *	function to say press return to continue and reset scroll when done
 */
retcont()
	{
	cursor(1,24); lprcat("Press "); standout("return");
	lprcat(" to continue: ");   while (getchar() != '\n');
	setscroll();
	}

/*
 *	routine to open the help file and return the first character - '0'
 */
openhelp()
	{
	if (lopen(helpfile)<0)
		{
		lprintf("Can't open help file \"%s\" ",helpfile);
		lflush(); sleep(4);	drawscreen();	setscroll(); return(-1);
		}
	resetscroll();  return(lgetc() - '0');
	}

SHAR_EOF
if test 2234 -ne "`wc -c < 'help.c'`"
then
	echo shar: error transmitting "'help.c'" '(should have been 2234 characters)'
fi
fi
echo shar: extracting "'savelev.c'" '(1267 characters)'
if test -f 'savelev.c'
then
	echo shar: will not over-write existing file "'savelev.c'"
else
cat << \SHAR_EOF > 'savelev.c'
/* savelev.c		 Larn is copyrighted 1986 by Noah Morgan. */
#include "header.h"
extern struct cel *cell;

/*
 *	routine to save the present level into storage
 */
savelevel()
	{
	register struct cel *pcel;
	register char *pitem,*pknow,*pmitem;
	register short *phitp,*piarg;
	register struct cel *pecel;
	pcel = &cell[level*MAXX*MAXY];	/* pointer to this level's cells */
	pecel = pcel + MAXX*MAXY;	/* pointer to past end of this level's cells */
	pitem=item[0]; piarg=iarg[0]; pknow=know[0]; pmitem=mitem[0]; phitp=hitp[0];
	while (pcel < pecel)
		{
		pcel->mitem  = *pmitem++;
		pcel->hitp   = *phitp++;
		pcel->item   = *pitem++;
		pcel->know   = *pknow++;
		pcel++->iarg = *piarg++;
		}
	}

/*
 *	routine to restore a level from storage
 */
getlevel()
	{
	register struct cel *pcel;
	register char *pitem,*pknow,*pmitem;
	register short *phitp,*piarg;
	register struct cel *pecel;
	pcel = &cell[level*MAXX*MAXY];	/* pointer to this level's cells */
	pecel = pcel + MAXX*MAXY;	/* pointer to past end of this level's cells */
	pitem=item[0]; piarg=iarg[0]; pknow=know[0]; pmitem=mitem[0]; phitp=hitp[0];
	while (pcel < pecel)
		{
		*pmitem++ = pcel->mitem;
		*phitp++ = pcel->hitp;
		*pitem++ = pcel->item;
		*pknow++ = pcel->know;
		*piarg++ = pcel++->iarg;
		}
	}
SHAR_EOF
if test 1267 -ne "`wc -c < 'savelev.c'`"
then
	echo shar: error transmitting "'savelev.c'" '(should have been 1267 characters)'
fi
fi
exit 0
#	End of shell archive