summaryrefslogtreecommitdiffstats
path: root/games/larn
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1994-09-04 04:03:31 +0000
committerjkh <jkh@FreeBSD.org>1994-09-04 04:03:31 +0000
commit057afceb86e030ad65b0130436860d9a18066186 (patch)
treea0ced9c9b9278eb776d89cd2565c27ddcf020b51 /games/larn
parenteedec95276cdb8aef98e92c5371000f10b8d6ba7 (diff)
downloadFreeBSD-src-057afceb86e030ad65b0130436860d9a18066186.zip
FreeBSD-src-057afceb86e030ad65b0130436860d9a18066186.tar.gz
Bring in the 4.4 Lite games directory, modulo man page changes and segregation
of the x11 based games. I'm not going to tag the originals with bsd_44_lite and do this in two stages since it's just not worth it for this collection, and I've got directory renames to deal with that way. Bleah. Submitted by: jkh
Diffstat (limited to 'games/larn')
-rw-r--r--games/larn/COPYRIGHT6
-rw-r--r--games/larn/Fixed.Bugs216
-rw-r--r--games/larn/Makefile69
-rw-r--r--games/larn/OWNER3
-rw-r--r--games/larn/README148
-rw-r--r--games/larn/bill.c156
-rw-r--r--games/larn/config.c47
-rw-r--r--games/larn/create.c463
-rw-r--r--games/larn/data.c648
-rw-r--r--games/larn/datfiles/larn.help140
-rw-r--r--games/larn/datfiles/larnmaze288
-rw-r--r--games/larn/datfiles/larnopts12
-rw-r--r--games/larn/diag.c314
-rw-r--r--games/larn/display.c434
-rw-r--r--games/larn/fortune.c87
-rw-r--r--games/larn/global.c621
-rw-r--r--games/larn/header.h435
-rw-r--r--games/larn/help.c87
-rw-r--r--games/larn/holidays66
-rw-r--r--games/larn/io.c915
-rw-r--r--games/larn/larn.6158
-rw-r--r--games/larn/main.c878
-rw-r--r--games/larn/monster.c1387
-rw-r--r--games/larn/moreobj.c372
-rw-r--r--games/larn/movem.c312
-rw-r--r--games/larn/nap.c116
-rw-r--r--games/larn/object.c807
-rw-r--r--games/larn/pathnames.h41
-rw-r--r--games/larn/regen.c92
-rw-r--r--games/larn/savelev.c47
-rw-r--r--games/larn/scores.c652
-rw-r--r--games/larn/signal.c148
-rw-r--r--games/larn/store.c691
-rw-r--r--games/larn/tok.c218
34 files changed, 11074 insertions, 0 deletions
diff --git a/games/larn/COPYRIGHT b/games/larn/COPYRIGHT
new file mode 100644
index 0000000..43ff637
--- /dev/null
+++ b/games/larn/COPYRIGHT
@@ -0,0 +1,6 @@
+This entire subtree is copyright by Noah Morgan.
+The following copyright notice applies to all files found here. None of
+these files contain AT&T proprietary source code.
+_____________________________________________________________________________
+
+/* Larn is copyrighted 1986 by Noah Morgan. */
diff --git a/games/larn/Fixed.Bugs b/games/larn/Fixed.Bugs
new file mode 100644
index 0000000..d2acae0
--- /dev/null
+++ b/games/larn/Fixed.Bugs
@@ -0,0 +1,216 @@
+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.
+
diff --git a/games/larn/Makefile b/games/larn/Makefile
new file mode 100644
index 0000000..3522a51
--- /dev/null
+++ b/games/larn/Makefile
@@ -0,0 +1,69 @@
+# @(#)Makefile 5.12 (Berkeley) 5/30/93
+
+# EXTRA
+# Incorporates code to gather additional performance statistics
+# 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).
+# 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 and 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.
+# NOLOG
+# Turn off logging.
+
+PROG= larn
+MAN6= larn.6
+CFLAGS+=-DBSD -DVER=12 -DSUBVER=0 -DNONAP -DUIDSCORE -fwritable-strings
+SRCS= 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
+DPADD= ${LIBTERM} ${LIBCOMPAT}
+LDADD= -ltermcap -lcompat
+HIDEGAME=hidegame
+
+beforeinstall:
+ (cd ${.CURDIR}/datfiles; install -c -o ${BINOWN} -g ${BINGRP} -m 444 \
+ larnmaze larnopts larn.help \
+ ${DESTDIR}/usr/share/games/larn)
+
+.include <bsd.prog.mk>
diff --git a/games/larn/OWNER b/games/larn/OWNER
new file mode 100644
index 0000000..06aaf47
--- /dev/null
+++ b/games/larn/OWNER
@@ -0,0 +1,3 @@
+ Noah Morgan
+ panda!condor!noah
+ GenRad Inc. Bolton, MA
diff --git a/games/larn/README b/games/larn/README
new file mode 100644
index 0000000..71e477b
--- /dev/null
+++ b/games/larn/README
@@ -0,0 +1,148 @@
+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
+===============================================================================
+
diff --git a/games/larn/bill.c b/games/larn/bill.c
new file mode 100644
index 0000000..dd74c11
--- /dev/null
+++ b/games/larn/bill.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)bill.c 5.2 (Berkeley) 5/28/91";
+#endif /* not lint */
+
+#include <sys/file.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "header.h"
+
+/* bill.c Larn is copyrighted 1986 by Noah Morgan. */
+
+char *mail[] = {
+ "From: the LRS (Larn Revenue Service)\n",
+ "~s undeclared income\n",
+ "\n We have heard you survived the caverns of Larn. Let me be the",
+ "\nfirst to congratulate you on your success. It was quite a feat.",
+ "\nIt was also very profitable for you...",
+ "\n\n The Dungeon Master has informed us that you brought",
+ "1",
+ "\ncounty of Larn is in dire need of funds, we have spared no time",
+ "2",
+ "\nof this notice, and is due within 5 days. Failure to pay will",
+ "\nmean penalties. Once again, congratulations, We look forward",
+ "\nto your future successful expeditions.\n",
+ NULL,
+ "From: His Majesty King Wilfred of Larndom\n",
+ "~s a noble deed\n",
+ "\n I have heard of your magnificent feat, and I, King Wilfred,",
+ "\nforthwith declare today to be a national holiday. Furthermore,",
+ "\nhence three days, ye be invited to the castle to receive the",
+ "\nhonour of Knight of the realm. Upon thy name shall it be written...",
+ "\n\nBravery and courage be yours.",
+ "\n\nMay you live in happiness forevermore...\n",
+ NULL,
+ "From: Count Endelford\n",
+ "~s You Bastard!\n",
+ "\n I have heard (from sources) of your journey. Congratulations!",
+ "\nYou Bastard! With several attempts I have yet to endure the",
+ " caves,\nand you, a nobody, makes the journey! From this time",
+ " onward, bewarned\nupon our meeting you shall pay the price!\n",
+ NULL,
+ "From: Mainair, Duke of Larnty\n",
+ "~s High Praise\n",
+ "\n With certainty, a hero I declare to be amongst us! A nod of",
+ "\nfavour I send to thee. Me thinks Count Endelford this day of",
+ "\nright breath'eth fire as of dragon of whom ye are slayer. I",
+ "\nyearn to behold his anger and jealously. Should ye choose to",
+ "\nunleash some of thy wealth upon those who be unfortunate, I,",
+ "\nDuke Mainair, shall equal thy gift also.\n",
+ NULL,
+ "From: St. Mary's Children's Home\n",
+ "~s these poor children\n",
+ "\n News of your great conquests has spread to all of Larndom.",
+ "\nMight I have a moment of a great adventurers's time? We here at",
+ "\nSt. Mary's Children's Home are very poor, and many children are",
+ "\nstarving. Disease is widespread and very often fatal without",
+ "\ngood food. Could you possibly find it in your heart to help us",
+ "\nin our plight? Whatever you could give will help much.",
+ "\n(your gift is tax deductible)\n",
+ NULL,
+ "From: The National Cancer Society of Larn\n",
+ "~s hope\n",
+ "\nCongratulations on your successful expedition. We are sure much",
+ "\ncourage and determination were needed on your quest. There are",
+ "\nmany though, that could never hope to undertake such a journey",
+ "\ndue to an enfeebling disease -- cancer. We at the National",
+ "\nCancer Society of Larn wish to appeal to your philanthropy in",
+ "\norder to save many good people -- possibly even yourself a few",
+ "\nyears from now. Much work needs to be done in researching this",
+ "\ndreaded disease, and you can help today. Could you please see it",
+ "\nin your heart to give generously? Your continued good health",
+ "\ncan be your everlasting reward.\n",
+ NULL
+};
+
+/*
+ * function to mail the letters to the player if a winner
+ */
+
+void
+mailbill()
+{
+ register int i;
+ char fname[32];
+ char buf[128];
+ char **cp;
+ int fd;
+
+ wait(0);
+ if (fork() == 0) {
+ resetscroll();
+ cp = mail;
+ sprintf(fname, "/tmp/#%dlarnmail", getpid());
+ for (i = 0; i < 6; i++) {
+ if ((fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT),
+ 0666) == -1)
+ exit(0);
+ while (*cp != NULL) {
+ if (*cp[0] == '1') {
+ sprintf(buf, "\n%d gold pieces back with you from your journey. As the",
+ (long)c[GOLD]);
+ write(fd, buf, strlen(buf));
+ } else if (*cp[0] == '2') {
+ sprintf(buf, "\nin preparing your tax bill. You owe %d gold pieces as", (long)c[GOLD]*TAXRATE);
+ write(fd, buf, strlen(buf));
+ } else
+ write(fd, *cp, strlen(*cp));
+ cp++;
+ }
+ cp++;
+
+ close(fd);
+ sprintf(buf, "mail -I %s < %s > /dev/null",
+ loginname, fname);
+ system(buf);
+ unlink(fname);
+ }
+ }
+ exit(0);
+}
diff --git a/games/larn/config.c b/games/larn/config.c
new file mode 100644
index 0000000..ccdd6d5
--- /dev/null
+++ b/games/larn/config.c
@@ -0,0 +1,47 @@
+/*
+ * 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"
+#include "pathnames.h"
+
+/*
+ * All these strings will be appended to in main() to be complete filenames
+ */
+
+/* the game save filename */
+char savefilename[1024];
+
+/* the logging file */
+char logfile[] = _PATH_LOG;
+
+/* the help text file */
+char helpfile[] = _PATH_HELP;
+
+/* the score file */
+char scorefile[] = _PATH_SCORE;
+
+/* the maze data file */
+char larnlevels[] = _PATH_LEVELS;
+
+/* the fortune data file */
+char fortfile[] = _PATH_FORTS;
+
+/* the .larnopts filename */
+char optsfile[1024] ="/.larnopts";
+
+/* the player id datafile name */
+char playerids[] = _PATH_PLAYERIDS;
+
+char diagfile[] ="Diagfile"; /* the diagnostic filename */
+char ckpfile[] ="Larn12.0.ckp"; /* the checkpoint filename */
+char *password ="pvnert(x)"; /* the wizards password <=32 */
+char psname[PSNAMESIZE]="larn"; /* the process name */
+
+#define WIZID 1
+int wisid=0; /* the user id of the only person who can be wizard */
+
diff --git a/games/larn/create.c b/games/larn/create.c
new file mode 100644
index 0000000..46c09c9
--- /dev/null
+++ b/games/larn/create.c
@@ -0,0 +1,463 @@
+/* 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;
+ }
+
+static void fillroom();
+
+/*
+ ***********
+ 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 void
+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 */
+ }
diff --git a/games/larn/data.c b/games/larn/data.c
new file mode 100644
index 0000000..a8739ba
--- /dev/null
+++ b/games/larn/data.c
@@ -0,0 +1,648 @@
+/*-
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)data.c 5.3 (Berkeley) 5/13/91";
+#endif /* not lint */
+
+/* data.c Larn is copyrighted 1986 by Noah Morgan. */
+#define NODEFS
+#include "header.h"
+
+/*
+ class[c[LEVEL]-1] gives the correct name of the players experience level
+ */
+static char aa1[] = " mighty evil master";
+static char aa2[] = "apprentice demi-god";
+static char aa3[] = " minor demi-god ";
+static char aa4[] = " major demi-god ";
+static char aa5[] = " minor deity ";
+static char aa6[] = " major deity ";
+static char aa7[] = " novice guardian ";
+static char aa8[] = "apprentice guardian";
+static char aa9[] = " The Creator ";
+char *class[]=
+{ " novice explorer ", "apprentice explorer", " practiced explorer",/* -3*/
+ " expert explorer ", " novice adventurer", " adventurer ",/* -6*/
+ "apprentice conjurer", " conjurer ", " master conjurer ",/* -9*/
+ " apprentice mage ", " mage ", " experienced mage ",/* -12*/
+ " master mage ", " apprentice warlord", " novice warlord ",/* -15*/
+ " expert warlord ", " master warlord ", " apprentice gorgon ",/* -18*/
+ " gorgon ", " practiced gorgon ", " master gorgon ",/* -21*/
+ " demi-gorgon ", " evil master ", " great evil master ",/* -24*/
+ aa1 , aa1 , aa1 ,/* -27*/
+ aa1 , aa1 , aa1 ,/* -30*/
+ aa1 , aa1 , aa1 ,/* -33*/
+ aa1 , aa1 , aa1 ,/* -36*/
+ aa1 , aa1 , aa1 ,/* -39*/
+ aa2 , aa2 , aa2 ,/* -42*/
+ aa2 , aa2 , aa2 ,/* -45*/
+ aa2 , aa2 , aa2 ,/* -48*/
+ aa3 , aa3 , aa3 ,/* -51*/
+ aa3 , aa3 , aa3 ,/* -54*/
+ aa3 , aa3 , aa3 ,/* -57*/
+ aa4 , aa4 , aa4 ,/* -60*/
+ aa4 , aa4 , aa4 ,/* -63*/
+ aa4 , aa4 , aa4 ,/* -66*/
+ aa5 , aa5 , aa5 ,/* -69*/
+ aa5 , aa5 , aa5 ,/* -72*/
+ aa5 , aa5 , aa5 ,/* -75*/
+ aa6 , aa6 , aa6 ,/* -78*/
+ aa6 , aa6 , aa6 ,/* -81*/
+ aa6 , aa6 , aa6 ,/* -84*/
+ aa7 , aa7 , aa7 ,/* -87*/
+ aa8 , aa8 , aa8 ,/* -90*/
+ aa8 , aa8 , aa8 ,/* -93*/
+ " earth guardian ", " air guardian ", " fire guardian ",/* -96*/
+ " water guardian ", " time guardian ", " ethereal guardian ",/* -99*/
+ aa9 , aa9 , aa9 ,/* -102*/
+};
+
+/*
+ table of experience needed to be a certain level of player
+ skill[c[LEVEL]] is the experience required to attain the next level
+ */
+#define MEG 1000000
+long skill[] = {
+0, 10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120, /* 1-11 */
+10240, 20480, 40960, 100000, 200000, 400000, 700000, 1*MEG, /* 12-19 */
+2*MEG,3*MEG,4*MEG,5*MEG,6*MEG,8*MEG,10*MEG, /* 20-26 */
+12*MEG,14*MEG,16*MEG,18*MEG,20*MEG,22*MEG,24*MEG,26*MEG,28*MEG, /* 27-35 */
+30*MEG,32*MEG,34*MEG,36*MEG,38*MEG,40*MEG,42*MEG,44*MEG,46*MEG, /* 36-44 */
+48*MEG,50*MEG,52*MEG,54*MEG,56*MEG,58*MEG,60*MEG,62*MEG,64*MEG, /* 45-53 */
+66*MEG,68*MEG,70*MEG,72*MEG,74*MEG,76*MEG,78*MEG,80*MEG,82*MEG, /* 54-62 */
+84*MEG,86*MEG,88*MEG,90*MEG,92*MEG,94*MEG,96*MEG,98*MEG,100*MEG, /* 63-71 */
+105*MEG,110*MEG,115*MEG,120*MEG, 125*MEG, 130*MEG, 135*MEG, 140*MEG, /* 72-79 */
+145*MEG,150*MEG,155*MEG,160*MEG, 165*MEG, 170*MEG, 175*MEG, 180*MEG, /* 80-87 */
+185*MEG,190*MEG,195*MEG,200*MEG, 210*MEG, 220*MEG, 230*MEG, 240*MEG, /* 88-95 */
+250*MEG,260*MEG,270*MEG,280*MEG, 290*MEG, 300*MEG /* 96-101*/
+};
+#undef MEG
+
+char *lpbuf,*lpnt,*inbuffer,*lpend; /* input/output pointers to the buffers */
+struct cel *cell; /* pointer to the dungeon storage */
+short hitp[MAXX][MAXY]; /* monster hp on level */
+short iarg[MAXX][MAXY]; /* arg for the item array */
+char item[MAXX][MAXY]; /* objects in maze if any */
+char know[MAXX][MAXY]; /* 1 or 0 if here before */
+char mitem[MAXX][MAXY]; /* monster item array */
+char moved[MAXX][MAXY]; /* monster movement flags */
+char stealth[MAXX][MAXY]; /* 0=sleeping 1=awake monst*/
+char iven[26]; /* inventory for player */
+short ivenarg[26]; /* inventory for player */
+char lastmonst[40]; /* this has the name of the current monster */
+char beenhere[MAXLEVEL+MAXVLEVEL]={0}; /* 1 if have been on this level */
+char VERSION=VER; /* this is the present version # of the program */
+char SUBVERSION=SUBVER;
+char nosignal=0; /* set to 1 to disable the signals from doing anything */
+char predostuff=0; /* 2 means that the trap handling routines must do a
+ showplayer() after a trap. 0 means don't showplayer()
+ 0 - we are in create player screen
+ 1 - we are in welcome screen
+ 2 - we are in the normal game */
+char loginname[20]; /* players login name */
+char logname[LOGNAMESIZE]; /* players name storage for scoring */
+char sex=1; /* default is a man 0=woman */
+char boldon=1; /* 1=bold objects 0=inverse objects */
+char ckpflag=0; /* 1 if want checkpointing of game, 0 otherwise */
+char cheat=0; /* 1 if the player has fudged save file */
+char level=0; /* cavelevel player is on = c[CAVELEVEL] */
+char wizard=0; /* the wizard mode flag */
+short lastnum=0; /* the number of the monster last hitting player */
+short hitflag=0; /* flag for if player has been hit when running */
+short hit2flag=0; /* flag for if player has been hit when running */
+short hit3flag=0; /* flag for if player has been hit flush input */
+short playerx,playery; /* the room on the present level of the player */
+short lastpx,lastpy; /* 0 --- MAXX-1 or 0 --- MAXY-1 */
+short oldx,oldy;
+short lasthx=0,lasthy=0; /* location of monster last hit by player */
+short nobeep=0; /* true if program is not to beep */
+unsigned long randx=33601; /* the random number seed */
+long initialtime=0; /* time playing began */
+long gtime=0; /* the clock for the game */
+long outstanding_taxes=0; /* present tax bill from score file */
+long c[100],cbak[100]; /* the character description arrays */
+int enable_scroll=0; /* constant for enabled/disabled scrolling regn */
+char aborted[] = " aborted";
+struct sphere *spheres=0; /*pointer to linked list for spheres of annihilation*/
+char *levelname[]=
+{ " H"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9","10","V1","V2","V3" };
+
+char objnamelist[]=" ATOP%^F&^+M=%^$$f*OD#~][[)))(((||||||||{?!BC}o:@.<<<<EVV))([[]]](^ [H*** ^^ S tsTLc............................................";
+char monstnamelist[]=" BGHJKOScjtAELNQRZabhiCTYdegmvzFWflorXV pqsyUkMwDDPxnDDuD ...............................................................";
+char *objectname[]=
+{ 0,"a holy altar","a handsome jewel encrusted throne","the orb","a pit",
+ "a staircase leading upwards","an elevator going up","a bubbling fountain",
+ "a great marble statue","a teleport trap","the college of Larn",
+ "a mirror","the DND store","a staircase going down","an elevator going down",
+ "the bank of Larn","the 5th branch of the Bank of Larn",
+ "a dead fountain","gold","an open door","a closed door",
+ "a wall","The Eye of Larn","plate mail","chain mail","leather armor",
+ "a sword of slashing","Bessman's flailing hammer","a sunsword",
+ "a two handed sword","a spear","a dagger",
+ "ring of extra regeneration","a ring of regeneration","a ring of protection",
+ "an energy ring","a ring of dexterity","a ring of strength",
+ "a ring of cleverness","a ring of increase damage","a belt of striking",
+ "a magic scroll","a magic potion","a book","a chest",
+ "an amulet of invisibility","an orb of dragon slaying",
+ "a scarab of negate spirit","a cube of undead control",
+ "device of theft prevention","a brilliant diamond","a ruby",
+ "an enchanting emerald","a sparkling sapphire","the dungeon entrance",
+ "a volcanic shaft leaning downward","the base of a volcanic shaft",
+ "a battle axe","a longsword","a flail","ring mail","studded leather armor",
+ "splint mail","plate armor","stainless plate armor","a lance of death",
+ "an arrow trap","an arrow trap","a shield","your home",
+ "gold","gold","gold","a dart trap",
+ "a dart trap","a trapdoor","a trapdoor","the local trading post",
+ "a teleport trap", "a massive throne",
+ "a sphere of annihilation","a handsome jewel encrusted throne",
+ "the Larn Revenue Service","a fortune cookie","","","","","","",
+ "","","","","","","","","","","","","","","","","","","",""
+ };
+
+
+/*
+ * for the monster data
+ *
+ * array to do rnd() to create monsters <= a given level
+ */
+char monstlevel[] = { 5, 11, 17, 22, 27, 33, 39, 42, 46, 50, 53, 56, 59 };
+
+struct monst monster[] = {
+/* NAME LV AC DAM ATT DEF GEN INT GOLD HP EXP
+----------------------------------------------------------------- */
+{ "", 0, 0, 0, 0, 0, 0, 3, 0, 0, 0 },
+{ "bat", 1, 0, 1, 0, 0, 0, 3, 0, 1, 1 },
+{ "gnome", 1, 10, 1, 0, 0, 0, 8, 30, 2, 2 },
+{ "hobgoblin", 1, 14, 2, 0, 0, 0, 5, 25, 3, 2 },
+{ "jackal", 1, 17, 1, 0, 0, 0, 4, 0, 1, 1 },
+{ "kobold", 1, 20, 1, 0, 0, 0, 7, 10, 1, 1 },
+
+{ "orc", 2, 12, 1, 0, 0, 0, 9, 40, 4, 2 },
+{ "snake", 2, 15, 1, 0, 0, 0, 3, 0, 3, 1 },
+{ "giant centipede",2, 14, 0, 4, 0, 0, 3, 0, 1, 2 },
+{ "jaculi", 2, 20, 1, 0, 0, 0, 3, 0, 2, 1 },
+{ "troglodyte", 2, 10, 2, 0, 0, 0, 5, 80, 4, 3 },
+{ "giant ant", 2, 8, 1, 4, 0, 0, 4, 0, 5, 5 },
+
+/* NAME LV AC DAM ATT DEF GEN INT GOLD HP EXP
+----------------------------------------------------------------- */
+
+{ "floating eye", 3, 8, 1, 0, 0, 0, 3, 0, 5, 2 },
+{ "leprechaun", 3, 3, 0, 8, 0, 0, 3,1500, 13, 45 },
+{ "nymph", 3, 3, 0, 14, 0, 0, 9, 0, 18, 45 },
+{ "quasit", 3, 5, 3, 0, 0, 0, 3, 0, 10, 15 },
+{ "rust monster", 3, 4, 0, 1, 0, 0, 3, 0, 18, 25 },
+{ "zombie", 3, 12, 2, 0, 0, 0, 3, 0, 6, 7 },
+
+{ "assassin bug", 4, 9, 3, 0, 0, 0, 3, 0, 20, 15 },
+{ "bugbear", 4, 5, 4, 15, 0, 0, 5, 40, 20, 35 },
+{ "hell hound", 4, 5, 2, 2, 0, 0, 6, 0, 16, 35 },
+{ "ice lizard", 4, 11, 2, 10, 0, 0, 6, 50, 16, 25 },
+{ "centaur", 4, 6, 4, 0, 0, 0, 10, 40, 24, 45 },
+
+/* NAME LV AC DAM ATT DEF GEN INT GOLD HP EXP
+----------------------------------------------------------------- */
+
+{ "troll", 5, 4, 5, 0, 0, 0, 9, 80, 50, 300 },
+{ "yeti", 5, 6, 4, 0, 0, 0, 5, 50, 35, 100 },
+{ "white dragon", 5, 2, 4, 5, 0, 0, 16, 500, 55, 1000},
+{ "elf", 5, 8, 1, 0, 0, 0, 15, 50, 22, 35 },
+{ "gelatinous cube",5, 9, 1, 0, 0, 0, 3, 0, 22, 45 },
+
+{ "metamorph", 6, 7, 3, 0, 0, 0, 3, 0, 30, 40 },
+{ "vortex", 6, 4, 3, 0, 0, 0, 3, 0, 30, 55 },
+{ "ziller", 6, 15, 3, 0, 0, 0, 3, 0, 30, 35 },
+{ "violet fungi", 6, 12, 3, 0, 0, 0, 3, 0, 38, 100 },
+{ "wraith", 6, 3, 1, 6, 0, 0, 3, 0, 30, 325 },
+{ "forvalaka", 6, 2, 5, 0, 0, 0, 7, 0, 50, 280 },
+
+/* NAME LV AC DAM ATT DEF GEN INT GOLD HP EXP
+----------------------------------------------------------------- */
+
+{ "lama nobe", 7, 7, 3, 0, 0, 0, 6, 0, 35, 80 },
+{ "osequip", 7, 4, 3, 16, 0, 0, 4, 0, 35, 100 },
+{ "rothe", 7, 15, 5, 0, 0, 0, 3, 100, 50, 250 },
+{ "xorn", 7, 0, 6, 0, 0, 0, 13, 0, 60, 300 },
+{ "vampire", 7, 3, 4, 6, 0, 0, 17, 0, 50, 1000},
+{ "invisible stalker",7,3, 6, 0, 0, 0, 5, 0, 50, 350 },
+
+{ "poltergeist", 8, 1, 4, 0, 0, 0, 3, 0, 50, 450 },
+{ "disenchantress", 8, 3, 0, 9, 0, 0, 3, 0, 50, 500 },
+{ "shambling mound",8, 2, 5, 0, 0, 0, 6, 0, 45, 400 },
+{ "yellow mold", 8, 12, 4, 0, 0, 0, 3, 0, 35, 250 },
+{ "umber hulk", 8, 3, 7, 11, 0, 0, 14, 0, 65, 600 },
+
+/* NAME LV AC DAM ATT DEF GEN INT GOLD HP EXP
+----------------------------------------------------------------- */
+
+{ "gnome king", 9, -1, 10, 0, 0, 0, 18, 2000, 100,3000 },
+{ "mimic", 9, 5, 6, 0, 0, 0, 8, 0, 55, 99 },
+{ "water lord", 9, -10, 15, 7, 0, 0, 20, 0, 150,15000 },
+{ "bronze dragon", 9, 2, 9, 3, 0, 0, 16, 300, 80, 4000 },
+{ "green dragon", 9, 3, 8, 10, 0, 0, 15, 200, 70, 2500 },
+{ "purple worm", 9, -1, 11, 0, 0, 0, 3, 100, 120,15000 },
+{ "xvart", 9, -2, 12, 0, 0, 0, 13, 0, 90, 1000 },
+
+{ "spirit naga", 10, -20,12, 12, 0, 0, 23, 0, 95, 20000 },
+{ "silver dragon", 10, -1, 12, 3, 0, 0, 20, 700, 100,10000 },
+{ "platinum dragon",10, -5, 15, 13, 0, 0, 22, 1000, 130,24000 },
+{ "green urchin", 10, -3, 12, 0, 0, 0, 3, 0, 85, 5000 },
+{ "red dragon", 10, -2, 13, 3, 0, 0, 19, 800, 110,14000 },
+
+{ "type I demon lord", 12,-30, 18, 0, 0, 0, 20, 0, 140,50000 },
+{ "type II demon lord", 13,-30, 18, 0, 0, 0, 21, 0, 160,75000 },
+{ "type III demon lord",14,-30, 18, 0, 0, 0, 22, 0, 180,100000 },
+{ "type IV demon lord", 15,-35, 20, 0, 0, 0, 23, 0, 200,125000 },
+{ "type V demon lord", 16,-40, 22, 0, 0, 0, 24, 0, 220,150000 },
+{ "type VI demon lord", 17,-45, 24, 0, 0, 0, 25, 0, 240,175000 },
+{ "type VII demon lord",18,-70, 27, 6, 0, 0, 26, 0, 260,200000 },
+{ "demon prince", 25,-127,30, 6, 0, 0, 28, 0, 345,300000 }
+
+/* NAME LV AC DAM ATT DEF GEN INT GOLD HP EXP
+--------------------------------------------------------------------- */
+ };
+
+/* name array for scrolls */
+
+char *scrollname[] = {
+"\0enchant armor",
+"\0enchant weapon",
+"\0enlightenment",
+"\0blank paper",
+"\0create monster",
+"\0create artifact",
+"\0aggravate monsters",
+"\0time warp",
+"\0teleportation",
+"\0expanded awareness",
+"\0haste monsters",
+"\0monster healing",
+"\0spirit protection",
+"\0undead protection",
+"\0stealth",
+"\0magic mapping",
+"\0hold monsters",
+"\0gem perfection",
+"\0spell extension",
+"\0identify",
+"\0remove curse",
+"\0annihilation",
+"\0pulverization",
+"\0life protection",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 "
+ };
+
+/* name array for magic potions */
+char *potionname[] = {
+"\0sleep",
+"\0healing",
+"\0raise level",
+"\0increase ability",
+"\0wisdom",
+"\0strength",
+"\0raise charisma",
+"\0dizziness",
+"\0learning",
+"\0gold detection",
+"\0monster detection",
+"\0forgetfulness",
+"\0water",
+"\0blindness",
+"\0confusion",
+"\0heroism",
+"\0sturdiness",
+"\0giant strength",
+"\0fire resistance",
+"\0treasure finding",
+"\0instant healing",
+" cure dianthroritis",
+"\0poison",
+"\0see invisible",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 ",
+"\0 "
+ };
+
+
+/*
+ spell data
+ */
+char spelknow[SPNUM]={0};
+char splev[] = { 1, 4, 9, 14, 18, 22, 26, 29, 32, 35, 37, 37, 37, 37, 37 };
+
+char *spelcode[]={
+ "pro", "mle", "dex", "sle", "chm", "ssp",
+ "web", "str", "enl", "hel", "cbl", "cre", "pha", "inv",
+ "bal", "cld", "ply", "can", "has", "ckl", "vpr",
+ "dry", "lit", "drl", "glo", "flo", "fgr",
+ "sca", "hld", "stp", "tel", "mfi", /* 31 */
+ "sph", "gen", "sum", "wtw", "alt", "per"
+ };
+
+char *spelname[]={
+ "protection", "magic missile", "dexterity",
+ "sleep", "charm monster", "sonic spear",
+
+ "web", "strength", "enlightenment",
+ "healing", "cure blindness", "create monster",
+ "phantasmal forces", "invisibility",
+
+ "fireball", "cold", "polymorph",
+ "cancellation", "haste self", "cloud kill",
+ "vaporize rock",
+
+ "dehydration", "lightning", "drain life",
+ "invulnerability", "flood", "finger of death",
+
+ "scare monster", "hold monster", "time stop",
+ "teleport away", "magic fire",
+
+ "sphere of annihilation", "genocide", "summon demon",
+ "walk through walls", "alter reality", "permanence",
+ ""
+ };
+
+char *speldescript[]={
+/* 1 */
+ "generates a +2 protection field",
+ "creates and hurls a magic missile equivalent to a + 1 magic arrow",
+ "adds +2 to the casters dexterity",
+ "causes some monsters to go to sleep",
+ "some monsters may be awed at your magnificence",
+ "causes your hands to emit a screeching sound toward what they point",
+/* 7 */
+ "causes strands of sticky thread to entangle an enemy",
+ "adds +2 to the casters strength for a short term",
+ "the caster becomes aware of things around him",
+ "restores some hp to the caster",
+ "restores sight to one so unfortunate as to be blinded",
+ "creates a monster near the caster appropriate for the location",
+ "creates illusions, and if believed, monsters die",
+ "the caster becomes invisible",
+/* 15 */
+ "makes a ball of fire that burns on what it hits",
+ "sends forth a cone of cold which freezes what it touches",
+ "you can find out what this does for yourself",
+ "negates the ability of a monster to use his special abilities",
+ "speeds up the casters movements",
+ "creates a fog of poisonous gas which kills all that is within it",
+ "this changes rock to air",
+/* 22 */
+ "dries up water in the immediate vicinity",
+ "you finger will emit a lightning bolt when this spell is cast",
+ "subtracts hit points from both you and a monster",
+ "this globe helps to protect the player from physical attack",
+ "this creates an avalanche of H2O to flood the immediate chamber",
+ "this is a holy spell and calls upon your god to back you up",
+/* 28 */
+ "terrifies the monster so that hopefully he wont hit the magic user",
+ "the monster is frozen in his tracks if this is successful",
+ "all movement in the caverns ceases for a limited duration",
+ "moves a particular monster around in the dungeon (hopefully away from you)",
+ "this causes a curtain of fire to appear all around you",
+/* 33 */
+ "anything caught in this sphere is instantly killed. Warning -- dangerous",
+ "eliminates a species of monster from the game -- use sparingly",
+ "summons a demon who hopefully helps you out",
+ "allows the player to walk through walls for a short period of time",
+ "god only knows what this will do",
+ "makes a character spell permanent, i. e. protection, strength, etc.",
+ ""
+ };
+
+char spelweird[MAXMONST+8][SPNUM] = {
+/* p m d s c s w s e h c c p i b c p c h c v d l d g f f s h s t m s g s w a p */
+/* r l e l h s e t n e b r h n a l l a a k p r i r l l g c l t e f p e u t l e */
+/* o e x e m p b r l l l e a v l d y n s l r y t l o o r a d p l i h n m w t r */
+
+
+/* bat */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* gnome */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* hobgoblin */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* jackal */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* kobold */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* orc */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 4,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* snake */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/*giant centipede */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* jaculi */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* troglodyte */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* giant ant */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* floating eye */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* leprechaun */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* nymph */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* quasit */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* rust monster */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 4,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* zombie */ { 0,0,0,8,0,4, 0,0,0,0,0,0,0,0, 0,0,0,0,0,4,0, 4,0,0,0,0,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* assassin bug */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* bugbear */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* hell hound */ { 0,6,0,0,0,0, 12,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* ice lizard */ { 0,0,0,0,0,0, 11,0,0,0,0,0,0,0, 0,15,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* centaur */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* troll */ { 0,7,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 4,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* yeti */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,15,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* white dragon */ { 0,0,0,0,0,0, 0,0,0,0,0,0,14,0, 0,15,0,0,0,0,0, 4,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* elf */ { 0,0,0,0,0,0, 0,0,0,0,0,0,14,5, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/*gelatinous cube */ { 0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 0,0,0,0,0,4,0, 0,0,0,0,0,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* metamorph */ { 0,13,0,0,0,0, 2,0,0,0,0,0,0,0, 0,0,0,0,0,4,0, 4,0,0,0,0,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* vortex */ { 0,13,0,0,0,10, 1,0,0,0,0,0,0,0, 0,0,0,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* ziller */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* violet fungi */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* wraith */ { 0,0,0,8,0,4, 0,0,0,0,0,0,0,0, 0,0,0,0,0,4,0, 4,0,0,0,0,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* forvalaka */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* lama nobe */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* osequip */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* rothe */ { 0,7,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* xorn */ { 0,7,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 4,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* vampire */ { 0,0,0,8,0,4, 0,0,0,0,0,0,0,0, 0,0,0,0,0,4,0, 0,0,0,0,0,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/*invisible staker*/ { 0,0,0,0,0,0, 1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* poltergeist */ { 0,13,0,8,0,4, 1,0,0,0,0,0,0,0, 0,4,0,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* disenchantress */ { 0,0,0,8,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/*shambling mound */ { 0,0,0,0,0,10, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* yellow mold */ { 0,0,0,8,0,0, 1,0,0,0,0,0,4,0, 0,0,0,0,0,4,0, 0,0,0,0,0,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* umber hulk */ { 0,7,0,0,0,0, 0,0,0,0,0,0,0,5, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* gnome king */ { 0,7,0,0,3,0, 0,0,0,0,0,0,0,5, 0,0,9,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* mimic */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* water lord */ { 0,13,0,8,3,4, 1,0,0,0,0,0,0,0, 0,0,9,0,0,4,0, 0,0,0,0,16,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* bronze dragon */ { 0,7,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* green dragon */ { 0,7,0,0,0,0, 11,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* purple worm */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* xvart */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* spirit naga */ { 0,13,0,8,3,4, 1,0,0,0,0,0,0,5, 0,4,9,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* silver dragon */ { 0,6,0,9,0,0, 12,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/*platinum dragon */ { 0,7,0,9,0,0, 11,0,0,0,0,0,14,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* green urchin */ { 0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+/* red dragon */ { 0,6,0,0,0,0, 12,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0 },
+
+/* p m d s c s w s e h c c p i b c p c h c v d l d g f f s h s t m s g s w a p */
+/* r l e l h s e t n e b r h n a l l a a k p r i r l l g c l t e f p e u t l e */
+/* o e x e m p b r l l l e a v l d y n s l r y t l o o r a d p l i h n m w t r */
+
+/* demon lord */ { 0,7,0,4,3,0, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 9,0,0,0,0,0 },
+/* demon lord */ { 0,7,0,4,3,0, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 9,0,0,0,0,0 },
+/* demon lord */ { 0,7,0,4,3,0, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 9,0,0,0,0,0 },
+/* demon lord */ { 0,7,0,4,3,0, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 9,0,0,0,0,0 },
+/* demon lord */ { 0,7,0,4,3,0, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 9,0,0,0,0,0 },
+/* demon lord */ { 0,7,0,4,3,0, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 9,0,0,0,0,0 },
+/* demon lord */ { 0,7,0,4,3,0, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 0,0,0,0,0, 9,0,0,0,0,0 },
+/* demon prince */ { 0,7,0,4,3,9, 1,0,0,0,0,0,14,5, 0,0,4,0,0,4,0, 4,0,0,0,4,4, 4,0,0,0,4, 9,0,0,0,0,0 }
+
+ };
+
+char *spelmes[] = { "",
+/* 1 */ "the web had no effect on the %s",
+/* 2 */ "the %s changed shape to avoid the web",
+/* 3 */ "the %s isn't afraid of you",
+/* 4 */ "the %s isn't affected",
+/* 5 */ "the %s can see you with his infravision",
+/* 6 */ "the %s vaporizes your missile",
+/* 7 */ "your missile bounces off the %s",
+/* 8 */ "the %s doesn't sleep",
+/* 9 */ "the %s resists",
+/* 10 */ "the %s can't hear the noise",
+/* 11 */ "the %s's tail cuts it free of the web",
+/* 12 */ "the %s burns through the web",
+/* 13 */ "your missiles pass right through the %s",
+/* 14 */ "the %s sees through your illusions",
+/* 15 */ "the %s loves the cold!",
+/* 16 */ "the %s loves the water!"
+ };
+
+char to_lower[]= /* tolower[character] = lower case converted character */
+ {
+ 0000,0001,0002,0003,0004,0005,0006,0007,0010,0011,0012,0013,0014,0015,0016,0017, /* NUL-SI*/
+ 0020,0021,0022,0023,0024,0025,0026,0027,0030,0031,0032,0033,0034,0035,0036,0037, /* DLE-US*/
+ 0040,0041,0042,0043,0044,0045,0046,0047,0050,0051,0052,0053,0054,0055,0056,0057, /* SP-/ */
+ 0060,0061,0062,0063,0064,0065,0066,0067,0070,0071,0072,0073,0074,0075,0076,0077, /* 0-? */
+ 0100,0141,0142,0143,0144,0145,0146,0147,0150,0151,0152,0153,0154,0155,0156,0157, /* @-O */
+ 0160,0161,0162,0163,0164,0165,0166,0167,0170,0171,0172,0133,0134,0135,0136,0137, /* P-_ */
+ 0140,0141,0142,0143,0144,0145,0146,0147,0150,0151,0152,0153,0154,0155,0156,0157, /* `-o */
+ 0160,0161,0162,0163,0164,0165,0166,0167,0170,0171,0172,0173,0174,0175,0176,0177, /* p-DEL */
+ };
+
+char to_upper[]= /* toupper[character] = upper case converted character */
+ {
+ 0000,0001,0002,0003,0004,0005,0006,0007,0010,0011,0012,0013,0014,0015,0016,0017, /* NUL-SI*/
+ 0020,0021,0022,0023,0024,0025,0026,0027,0030,0031,0032,0033,0034,0035,0036,0037, /* DLE-US*/
+ 0040,0041,0042,0043,0044,0045,0046,0047,0050,0051,0052,0053,0054,0055,0056,0057, /* SP-/ */
+ 0060,0061,0062,0063,0064,0065,0066,0067,0070,0071,0072,0073,0074,0075,0076,0077, /* 0-? */
+ 0100,0101,0102,0103,0104,0105,0106,0107,0110,0111,0112,0113,0114,0115,0116,0117, /* @-O */
+ 0120,0121,0122,0123,0124,0125,0126,0127,0130,0131,0132,0133,0134,0135,0136,0137, /* P-_ */
+ 0140,0101,0102,0103,0104,0105,0106,0107,0110,0111,0112,0113,0114,0115,0116,0117, /* `-o */
+ 0120,0121,0122,0123,0124,0125,0126,0127,0130,0131,0132,0173,0174,0175,0176,0177, /* p-DEL */
+ };
+
+char is_digit[]= /* isdigit[character] = TRUE || FALSE */
+ {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* NUL-SI*/
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* DLE-US*/
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SP-/ */
+ 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 0-? */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* @-O */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* P-_ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* `-o */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* p-DEL */
+ };
+
+char is_alpha[]= /* isalpha[character] = TRUE || FALSE */
+ {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* NUL-SI*/
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* DLE-US*/
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SP-/ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0-? */
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* @-O */
+ 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, /* P-_ */
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* `-o */
+ 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, /* p-DEL */
+ };
+
+/*
+ * function to create scroll numbers with appropriate probability of
+ * occurrence
+ *
+ * 0 - armor 1 - weapon 2 - enlightenment 3 - paper
+ * 4 - create monster 5 - create item 6 - aggravate 7 - time warp
+ * 8 - teleportation 9 - expanded awareness 10 - haste monst
+ * 11 - heal monster 12 - spirit protection 13 - undead protection
+ * 14 - stealth 15 - magic mapping 16 - hold monster
+ * 17 - gem perfection 18 - spell extension 19 - identify
+ * 20 - remove curse 21 - annihilation 22 - pulverization
+ * 23 - life protection
+ */
+char scprob[]= { 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9,
+ 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14,
+ 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, 20, 20, 21, 22,
+ 22, 22, 23 };
+
+/*
+ * function to return a potion number created with appropriate probability
+ * of occurrence
+ *
+ * 0 - sleep 1 - healing 2 - raise level
+ * 3 - increase ability 4 - gain wisdom 5 - gain strength
+ * 6 - charismatic character 7 - dizziness 8 - learning
+ * 9 - gold detection 10 - monster detection 11 - forgetfulness
+ * 12 - water 13 - blindness 14 - confusion
+ * 15 - heroism 16 - sturdiness 17 - giant strength
+ * 18 - fire resistance 19 - treasure finding 20 - instant healing
+ * 21 - cure dianthroritis 22 - poison 23 - see invisible
+ */
+char potprob[] = { 0, 0, 1, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 20, 22, 22, 23, 23 };
+
+char nlpts[] = { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7 };
+char nch[] = { 0, 0, 0, 1, 1, 1, 2, 2, 3, 4 };
+char nplt[] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 4 };
+char ndgg[] = { 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5 };
+char nsw[] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3 };
diff --git a/games/larn/datfiles/larn.help b/games/larn/datfiles/larn.help
new file mode 100644
index 0000000..0e5edc5
--- /dev/null
+++ b/games/larn/datfiles/larn.help
@@ -0,0 +1,140 @@
+5 Welcome to the game of Larn. At this moment, you face a great problem.
+Your daughter has contracted a strange disease, and none of your home remedies
+seem to have any effect. You sense that she is in mortal danger, and you must
+try to save her. Time ago you heard of a land of great danger and opportunity.
+Perhaps here is the solution you need.
+
+ It has been said that there once was a great magician who called himself
+Polinneaus. Many years ago, after having many miraculous successes, Polinneaus
+retired to the caverns of Larn, where he devoted most of his time to the
+creation of magic. Rumors have it that one day Polinneaus set out to dispel
+an attacking army in a forest some distance to the north. It is believed that
+here he met his demise.
+
+ The caverns of Larn, it is thought, must be magnificent in design,
+and contain much magic and treasure. One option you have is to undertake a
+journey into these caverns.
+
+
+ Good Luck! You're going to need it!
+
+
+
+
+ Help File for The Caverns of Larn
+
+h move to the left H run left . stay here
+j move down J run down Z teleport yourself
+k move up K run up c cast a spell
+l move to the right L run right r read a scroll
+y move northwest Y run northwest q quaff a potion
+u move northeast U run northeast W wear armor
+b move southwest B run southwest T take off armor
+n move southeast N run southeast w wield a weapon
+^ identify a trap g give present pack weight P give tax status
+d drop an item i inventory your pockets Q quit the game
+v print program version S save the game D list all items found
+? this help screen A create diagnostic file e eat something
+ (wizards only)
+larn ++ restore checkpointed game
+larn -s list the scoreboard
+larn -i list scores with inventories
+larn -n suppress welcome message when beginning a game
+larn -h print out all the command line options
+larn -<number> specify difficulty of the game (may be used with -n)
+larn -o<optsfile> specify the .larnopts file to be used
+larn -c create new scoreboards -- prompts for a password
+ Special Notes
+
+When dropping gold, if you type '*' as your amount, all your gold gets dropped.
+In general, typing in '*' means all of what your interested in. This is true
+when visiting the bank, or when contributing at altars.
+
+Larn may need a VT100 to operate. A check is made of the environment variable
+"TERM" and it must be equal to "vt100". This only applies if
+the game has been compiled with "VT100" defined in the Makefile. If compiled
+to use termcap, there are no terminal restrictions, save needing cm, ce, & cl
+termcap entries.
+
+When in the store, trading post, school, or home, an <escape> will get you out.
+
+larn -l print out the larn log file
+
+When casting a spell, if you need a list of spells you can cast, type 'D' as
+the first letter of your spell. The available list of spells will be shown,
+after which you may enter the spell code. This only works on the 1st letter
+of the spell you are casting.
+
+The Author of Larn is Noah Morgan (1982-3), Copying for Profit is Prohibited
+Copyright 1986 by Noah Morgan, All Rights Reserved.
+ Background Information for Larn
+
+ Welcome to the game of Larn. At this moment, you face a great problem.
+Your daughter has contracted a strange disease, and none of your home remedies
+seem to have any effect. You sense that she is in mortal danger, and you must
+try to save her. Time ago you heard of a land of great danger and opportunity.
+Perhaps here is the solution you need.
+
+ It has been said that there once was a great magician who called himself
+Polinneaus. Many years ago, after having many miraculous successes, Polinneaus
+retired to the caverns of Larn, where he devoted most of his time to the
+creation of magic. Rumors have it that one day Polinneaus set out to dispel
+an attacking army in a forest some distance to the north. It is believed that
+here he met his demise.
+
+ The caverns of Larn, it is thought, must be magnificent in design,
+and contain much magic and treasure. One option you have is to undertake a
+journey into these caverns.
+
+ Good Luck! You're going to need it!
+
+
+
+ How to use the .larnopts option file
+
+The file ".larnopts", if used, should be in your home directory (see -o).
+A sequence of words terminated by whitespace is used to specify options.
+
+ Word Meaning
+
+ bold-objects select bold display of objects
+ inverse-objects select inverse video display of objects
+ no-introduction do not display intro message
+ enable-checkpointing turn on periodic checkpointing
+ no-beep disable beeping of the terminal
+ male choose your sex to be a man
+ female choose your sex to be a woman
+ name: "your name" choose your playing name
+ monster: "monst name" choose a name for a monster
+ savefile: "save-file-name" define what the savegame filename will be
+
+Your name and monster names must be enclosed in double quotation marks and may
+be up to 34 characters long. Longer names are truncated. Anything enclosed in
+quotation marks is considered one word, and must be separated from other words
+by whitespace.
+
+ Explanation of the Larn scoreboard facility
+
+ Larn supports TWO scoreboards, one for winners, and one for deceased
+characters. Each player (by userid or playerid, see UIDSCORE in Makefile)
+is allowed one slot on each scoreboard, if the score is in the top ten for
+that scoreboard. This design helps insure that frequent players of Larn
+do not hog the scoreboard, and gives more players a chance for glory. Level
+of difficulty is also noted on the scoreboards, and this takes precedence
+over score for determining what entry is on the scoreboard. For example:
+if "Yar, the Bug Slayer" has a score of 128003 on the scoreboard at diff 0,
+then his game at diff 1 and a score of 4112 would replace his previous
+entry on the scoreboard. Note that when a player dies, his inventory is
+stored in the scoreboard so that everyone can see what items the player had
+at the time of his death.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/games/larn/datfiles/larnmaze b/games/larn/datfiles/larnmaze
new file mode 100644
index 0000000..37a89c3
--- /dev/null
+++ b/games/larn/datfiles/larnmaze
@@ -0,0 +1,288 @@
+@###################################################################
+# # . # # # # # . #
+# D D . . D . #
+###D########################################## # # ###D###
+# -# #. # # ################ . .#
+# ####### ######## ############ D #### # # #
+# ... #.# # # # . # # # #### # ############ # ###D###
+# #.# # # ## # # # ############ #### # #- # # # #. #
+# . # # # # ## #- # # # - D #### # # . D # #.# # ... #
+# # #.# # # # # # . . # # # # # # #-# # ~.! #
+###D### ### #######D## # ############ ###### ########## ### #######
+# # @ .# # ..... ...#
+###D###########################################################D###
+# . #.....# # # # -# # # # # #
+# ..... . D D D D. #
+# #.....# # # # # # .# # # #
+###################################################################
+
+###################################################################
+#.. . D # . # #- #
+############# ######### # ## ### ##### ## #### ###### ####### ### #
+#.#!#~# # # .-# # #- # # # # -# # # #
+# # #.# . # ####### # # # # # # # # # #####
+# # ..# ##### # # # #### # ## ## ## # ###### ####### # #
+# - ..D # D # . D # # # #.##### ## ## # #. #.# #..# # ### #
+####### ####### ### # # # # # # D # D D #..D # #
+#- # # # #### # ###### # ## # #. # #..# #####
+### #######################- # # # ###################### # #
+# ... # . #..# ### # - .. . #. ### #
+# # # # ### #################### # # #
+# ### #
+################################################################# #
+#- D ### # # # #
+# . # # # D #
+###################################################################
+
+###################################################################
+# .. #
+# ############## ############################################## # #
+# # # # # .. # # #
+# #D## # # ############D################# ########### # # #
+######### #- # # # #- D # # ~ # # # # # # #
+# # # # # # # ### # # # D - # # ####### # # # #
+# .... # #### # # # #!# # # ###### .. #.# # # # # # #
+# .... # # # # ### # # # # #########D#### # ### # # # # #
+# .... ######## # # D # #- # #.. # ...#.# # #.# # # # # #
+# # # ### # #### #.- D - #.# #.#.# # # # # #
+#####DD## ######## # # D D. # # # #...# # # # # #
+# # ..# # # # ############################## # ##### # # # # #
+# ......# # # # # # # # # #
+# ####### ###### ################################ ######### # ### #
+# .D. # #
+###################################################################
+
+###################################################################
+# ## ## ### ## #
+# ##### ## ..- ## ##.## ## #
+# # ! ## ## . ## ## .## .. ## #
+# #....###### ## ## ## . ## ## #
+# # - # ## ##D# ## . ## ## #
+# #####D ~ ####### ###........ ## ... ## ## #
+# # # ## ## .... ## . ## ## #
+# #. ######## ## ## . - ####D#### - #
+# #.- #...## ## ... ## ### ...... ## ## #
+# #. #..## ## ######### ## ... ## ### ## .. #
+# #.. #.## ## ## - ## . #### ## ## ##### ## #
+# #####D## ## ## ###### ## ## ####### ## #
+# D -.## #### ######## ##DD## ######## #D #
+# ###### ... ## ########## ## #
+#### . . ###
+###################################################################
+
+###################################################################
+# #
+# ####.########################################## ## ##########
+# # #.#.#.# #.. #. # # #
+####### # # # # # ##### #! # ########### # ### #
+# # # # # # # ##...## # # # # # #-# #
+# ..- D # # # # # ## . ## ####D##### .. ### # # # #
+# # # # ##. ~ .## # # ### # # ##### # #
+############ # # # # ## . . .## #...# .. #.# # # # #
+# .. .# # # # # ## - ## # # D.D # ######### #
+# . D # # # # ##.......## ####D#####.# # #
+# - . # # # # # ## ## # . # ### ########### #
+############ #.#.# # ###D### # . #....# # #
+# # #-# D .. # .# ###....## ##-### #
+#### ########################################## ###### ### #
+# . #
+###################################################################
+
+###################################################################
+# #
+# ###########################D####### ## #
+# ####################### # ##...... ## ## #
+# ########D###### # # !##.... ## ## #
+# ############ ## ## ... # # #...## ~ ## ###### #
+# # # # # ...... # # # .. ##### ## #
+# # - .. # # # ########### # # . ######### ## #
+# ##### ##### # # # # #... ## ## #
+# # # ########## ######## ########DD#### ####### #
+# # # .... # # # # # ## ## #
+# ##### # # ....# # ######### # # ##### ## #
+# #- ######D##########..# # ######### # - #.. ## ## #
+# ##### # # # #... #.....## #
+# # ################### ###############... #### # ######
+# # #
+###################################################################
+
+###################################################################
+# #
+########### ##### ##### #####D#### ##### ###### #
+#.. # #-..D ###### ## # ## # ## ..## ### #### #
+# #### ### ##### # ## # ##### # ## ### ## # # #
+# # # # # # ##### # ## # # #### # #..##### - ### #
+# # # ####### ### #...# # ######## # # #~. .... # #
+# # # # #...# # # ######### ############## #
+# # ###### ####### # ### ### # .. # #
+# # # - # #-#####!# # # #### ## #### # #
+# ###### # ########## #.. ....# # ######## # # # ## ## #
+# -.# ##### ####...## # . .# #..# # ## # #
+# #### ###### #.### #####.#### #### ### ## # #
+# #- #######....#### ...... #.# . # ## # #
+# ####### ##### ###########.############### ### #
+# . #
+###################################################################
+
+###################################################################
+# # #- . # # # # # # # # #
+# # # #####.##### # # # # # # # # # # ###########D########### #
+# # ##### # # ### # # # # # # # # # ### #.... # # # #
+# # # # # # # # # # # # # # #.!. -.. #.##.# # #
+# # . - # # ####### # # # # # # # # # ########## ## # #
+#.####### # # D # . # # #
+#. -# ################################################### #
+# ##### D. . #
+# # ### ###D### ### ### ###D### ### ### ###D### ###.### #
+# # ###### ### .# .# #. # # # # # # # # . # #
+# ### # -# ### .#. - .# # # #...- # # .. # # -..# # . # #
+# # # ### #. ~ .# # # # # # # # .. .# # # #
+#.###### # ### # # #.....# # # # # # # # # #
+# # ####### ####### ####### ####### ####### ####### ####### #
+# # ... .. #
+###################################################################
+
+###################################################################
+# # . # ### # # # # . #
+# D D . # . D . #
+############################################### # # ###D###
+# -# #. # # ################ . .#
+# #######D######## ############ # #### # # #
+# ... #. # #!~ . # # # #--# # ############ #####D###
+# #.# # # ## # # # ############ #--# # #- # # # #. #
+# . # #-# # ## #- # # # - D ## # # # . D #### #.# # ... #
+# # #-# # # # # # . . # # # # # # #-# # -.- #
+###D### ### ####### ## # ############ ###### ########## ### ###D###
+# # @ . ..... ...#
+##################################### ###############D###
+# . #.....# # # # -# # # # #
+# ..... . D D D D. #
+# #.....# # # # # .# # # #
+###################################################################
+
+###################################################################
+#.. . # D . #- #
+### ######### ######### # ## ### ##### ## ########### ####### ### #
+#.# # # # .-# # #- # # # # -# # # #
+# # #.# . # ####### # # # # # # # # # #####
+# # ..####### # # # #### # ## ## ##!# ###### ####### # #
+# - ..D # D # . D # # # #.##### ## ## # #. #.# #..# # ### #
+####### ####### ### # # # # # # D # D D #..D # #
+#- # # # #### # ###### # ## # #. # #..# #####
+### #######################- # # # ###################### # #
+# ... # . #..# ### # - .. . #. ### #
+# # # # #-# #################### # # #
+# # -# #
+################################-################################ #
+#-..... # ####D ### # # # #
+#~..... # # # # D #
+###################################################################
+
+###################################################################
+# .. #
+# ############## ############################################## # #
+# # # # # .. # # #
+# #D## # # ############D################# ########### # # #
+######### #- # # # #- D # #.!..# # # # # # #
+# # # # # # # # ### ## # #....D - # # ####### # # # #
+# .... # #### # # # #~# # # ###### .. #.# # # # # # #
+###....## # # # ###.# # # #########D## # # ### # # # # #
+# .... ######## # # D .# #- # .. # ...#.# # #.# # # # # #
+# # ## # ### .# #### .- D - #.# #.#.# # # # # #
+#####DD## ######## #... .# . # # # #.#. # # # # #
+# # ..# # # ############################## # # ##### # # # #
+# ......# # # # # # # # # # #
+# ####### ###### ################################D# ######### ### #
+# .D. #-.-#
+###################################################################
+
+###################################################################
+# ## ## ## ## ## #
+# ############## ## ..- ## ## . ## ## #
+# # # ## ## . ## ## . ##.. ## #
+# #....###### ## ## ######## ####### . ## ## #
+# # - # ## ## ##D# ## . ## ## #
+# # D###### ###........ ## ... ## ###### #
+# # # ## ## .... ## . ## ## - # #
+# #. ######## ## ## . - ####D####.. D #
+# #.- #...## ## ... ## ### ...... ## ##### #
+# #. #..## ## ######### ## ... ## ### ## .. #
+# #.. #.## ## ## - ## . #### ## ## ##### ## #
+# #####D####### # ## ## ##..## ## ## ## ## ## #
+# D -.## # # #### ##.-.-## ##DD## ### #### ## #
+# ######. ...# #### ## #### ##### ## ##D#
+####~!.... D . . #
+###################################################################
+
+###################################################################
+# #
+# ####.########################################## ## ##########
+# # #.#.#.# #.. . # # #
+####### # # # # # ############# # ########### # ### #
+# # # # # # # --##...##-- # # # # #-# #
+# ..- D # # # # # #-## . ##-# ####D##### .. ### # # # #
+# # # # ###. .### # ~ # ### ### ##### # #
+############ # # # # ## . . .## #...# .. #.# # #
+# .. .# # # # # ## - ## # # D. # ######### #
+# . D # # # # ###.......### ####D#####.# # #
+# - . # # # # # -## ##- # . ### ########### #
+############ #.#.# # ######D###### # . ....# # #
+# #!#-# # .. # . ###....## ##-### #
+#### ############################## ########## ###### ### #
+# D . #
+###################################################################
+
+###################################################################
+# #
+# ###############D####################D# #
+# ####################### # ##...... # #
+# ########D###### # # ##.... # #
+# ############### ## ## ... # # #...## ##### #
+# # ~ # # #!...... # # # .. ##### # #
+# # - .. # # # ########### # # . ######### # #
+# ##### ######## # # # # # #... ## # #
+# # # # ########## ######## ########D #### ###### #
+# # # ....# # # # # # ## # #
+# ##### # ###### # ....# # ######### # # #####D# #
+# #- ## # #######..# # ######### # - #.. #
+# ##### # # # #... #..... #
+# # ################### ###############... #### ######
+# # #
+###################################################################
+
+###################################################################
+# # #
+########### ##### # #####D#### ##### ###### #
+#.. # #~..D ###### ## # ## # ## ..## ### #### #
+# #### ### ##### # ## # ##### # ## ### ## # # #
+# # # # # # ##### # ## # # #### # #..##### - ### #
+# # # ####### ### #...# # ######## # # #!. .... # #
+# # # # #...# # # ######### ############## #
+# # ###### ####### # ### ### # .. # #
+# # # - # #- # # # ######## #### # #
+# # # ########## #.. ....# # ######## # ## ## #
+# # -. ##### ####...## # . .# .. # # #
+# # ###### ##### #####.#### ####### # #
+# # - #######....#### ...... #.# . # ## # #
+# ######### ##### ###########.############### ### #
+# . #
+###################################################################
+
+###################################################################
+# D D #-..........# # # # # #
+#D#D# #####.#####.# # # # # # #############D########### #
+# # ##### #.#~###.# # # # # # ### .... # # # #
+#D# # #.......# # # # # # # . . -.. #. #.# # #
+# # . - # #.####### # # # # # ################## # #
+#D####### #. # D # . # # #
+#. D D -# ################################################### #
+# ###### . . #
+# # D ### ###D### ####### ###D### ####### ###D### ####### #
+# # ###### # # .# .# #. # # # # # # # # . # #
+# ### -# # # .#. - .# # # #...- # # .. # # -..# # . # #
+#DD# # # # #. .# # # # # # # # .. .# # # #
+#.###### # # # # #.....# # # # # # ! # # # #
+# # ####### ####### ### ### ####### ### ### ####### ### ### #
+# # ... .. #
+###################################################################
+
diff --git a/games/larn/datfiles/larnopts b/games/larn/datfiles/larnopts
new file mode 100644
index 0000000..17216ed
--- /dev/null
+++ b/games/larn/datfiles/larnopts
@@ -0,0 +1,12 @@
+process-name: "Winnie-the-Pooh"
+enable-checkpointing
+bold-objects
+male
+play-day-play
+no-introduction
+name: "King of the Realm"
+monster: "abominable snowman"
+monster: "tooth fairy"
+monster: "Yaccerous Lexicous"
+savefile: "/save/noah/games/Larn12.0.sav"
+
diff --git a/games/larn/diag.c b/games/larn/diag.c
new file mode 100644
index 0000000..4ed557d
--- /dev/null
+++ b/games/larn/diag.c
@@ -0,0 +1,314 @@
+/* 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;
+ }
diff --git a/games/larn/display.c b/games/larn/display.c
new file mode 100644
index 0000000..b49de50
--- /dev/null
+++ b/games/larn/display.c
@@ -0,0 +1,434 @@
+/* display.c Larn is copyrighted 1986 by Noah Morgan. */
+#include "header.h"
+#define makecode(_a,_b,_c) (((_a)<<16) + ((_b)<<8) + (_c))
+
+static int minx,maxx,miny,maxy,k,m;
+static char bot1f=0,bot2f=0,bot3f=0;
+char always=0;
+/*
+ bottomline()
+
+ now for the bottom line of the display
+ */
+bottomline()
+ { recalc(); bot1f=1; }
+bottomhp()
+ { bot2f=1; }
+bottomspell()
+ { bot3f=1; }
+bottomdo()
+ {
+ if (bot1f) { bot3f=bot1f=bot2f=0; bot_linex(); return; }
+ if (bot2f) { bot2f=0; bot_hpx(); }
+ if (bot3f) { bot3f=0; bot_spellx(); }
+ }
+
+static void botsub();
+
+bot_linex()
+ {
+ register int i;
+ if (cbak[SPELLS] <= -50 || (always))
+ {
+ cursor( 1,18);
+ if (c[SPELLMAX]>99) lprintf("Spells:%3d(%3d)",(long)c[SPELLS],(long)c[SPELLMAX]);
+ else lprintf("Spells:%3d(%2d) ",(long)c[SPELLS],(long)c[SPELLMAX]);
+ lprintf(" AC: %-3d WC: %-3d Level",(long)c[AC],(long)c[WCLASS]);
+ if (c[LEVEL]>99) lprintf("%3d",(long)c[LEVEL]);
+ else lprintf(" %-2d",(long)c[LEVEL]);
+ lprintf(" Exp: %-9d %s\n",(long)c[EXPERIENCE],class[c[LEVEL]-1]);
+ lprintf("HP: %3d(%3d) STR=%-2d INT=%-2d ",
+ (long)c[HP],(long)c[HPMAX],(long)(c[STRENGTH]+c[STREXTRA]),(long)c[INTELLIGENCE]);
+ lprintf("WIS=%-2d CON=%-2d DEX=%-2d CHA=%-2d LV:",
+ (long)c[WISDOM],(long)c[CONSTITUTION],(long)c[DEXTERITY],(long)c[CHARISMA]);
+
+ if ((level==0) || (wizard)) c[TELEFLAG]=0;
+ if (c[TELEFLAG]) lprcat(" ?"); else lprcat(levelname[level]);
+ lprintf(" Gold: %-6d",(long)c[GOLD]);
+ always=1; botside();
+ c[TMP] = c[STRENGTH]+c[STREXTRA];
+ for (i=0; i<100; i++) cbak[i]=c[i];
+ return;
+ }
+
+ botsub(makecode(SPELLS,8,18),"%3d");
+ if (c[SPELLMAX]>99) botsub(makecode(SPELLMAX,12,18),"%3d)");
+ else botsub(makecode(SPELLMAX,12,18),"%2d) ");
+ botsub(makecode(HP,5,19),"%3d");
+ botsub(makecode(HPMAX,9,19),"%3d");
+ botsub(makecode(AC,21,18),"%-3d");
+ botsub(makecode(WCLASS,30,18),"%-3d");
+ botsub(makecode(EXPERIENCE,49,18),"%-9d");
+ if (c[LEVEL] != cbak[LEVEL])
+ { cursor(59,18); lprcat(class[c[LEVEL]-1]); }
+ if (c[LEVEL]>99) botsub(makecode(LEVEL,40,18),"%3d");
+ else botsub(makecode(LEVEL,40,18)," %-2d");
+ c[TMP] = c[STRENGTH]+c[STREXTRA]; botsub(makecode(TMP,18,19),"%-2d");
+ botsub(makecode(INTELLIGENCE,25,19),"%-2d");
+ botsub(makecode(WISDOM,32,19),"%-2d");
+ botsub(makecode(CONSTITUTION,39,19),"%-2d");
+ botsub(makecode(DEXTERITY,46,19),"%-2d");
+ botsub(makecode(CHARISMA,53,19),"%-2d");
+ if ((level != cbak[CAVELEVEL]) || (c[TELEFLAG] != cbak[TELEFLAG]))
+ {
+ if ((level==0) || (wizard)) c[TELEFLAG]=0;
+ cbak[TELEFLAG] = c[TELEFLAG];
+ cbak[CAVELEVEL] = level; cursor(59,19);
+ if (c[TELEFLAG]) lprcat(" ?"); else lprcat(levelname[level]);
+ }
+ botsub(makecode(GOLD,69,19),"%-6d");
+ botside();
+ }
+
+/*
+ special subroutine to update only the gold number on the bottomlines
+ called from ogold()
+ */
+bottomgold()
+ {
+ botsub(makecode(GOLD,69,19),"%-6d");
+/* botsub(GOLD,"%-6d",69,19); */
+ }
+
+/*
+ special routine to update hp and level fields on bottom lines
+ called in monster.c hitplayer() and spattack()
+ */
+bot_hpx()
+ {
+ if (c[EXPERIENCE] != cbak[EXPERIENCE])
+ {
+ recalc(); bot_linex();
+ }
+ else botsub(makecode(HP,5,19),"%3d");
+ }
+
+/*
+ special routine to update number of spells called from regen()
+ */
+bot_spellx()
+ {
+ botsub(makecode(SPELLS,9,18),"%2d");
+ }
+
+/*
+ common subroutine for a more economical bottomline()
+ */
+static struct bot_side_def
+ {
+ int typ;
+ char *string;
+ }
+ bot_data[] =
+ {
+ STEALTH,"stealth", UNDEADPRO,"undead pro", SPIRITPRO,"spirit pro",
+ CHARMCOUNT,"Charm", TIMESTOP,"Time Stop", HOLDMONST,"Hold Monst",
+ GIANTSTR,"Giant Str", FIRERESISTANCE,"Fire Resit", DEXCOUNT,"Dexterity",
+ STRCOUNT,"Strength", SCAREMONST,"Scare", HASTESELF,"Haste Self",
+ CANCELLATION,"Cancel", INVISIBILITY,"Invisible", ALTPRO,"Protect 3",
+ PROTECTIONTIME,"Protect 2", WTW,"Wall-Walk"
+ };
+
+botside()
+ {
+ register int i,idx;
+ for (i=0; i<17; i++)
+ {
+ idx = bot_data[i].typ;
+ if ((always) || (c[idx] != cbak[idx]))
+ {
+ if ((always) || (cbak[idx] == 0))
+ { if (c[idx]) { cursor(70,i+1); lprcat(bot_data[i].string); } } else
+ if (c[idx]==0) { cursor(70,i+1); lprcat(" "); }
+ cbak[idx]=c[idx];
+ }
+ }
+ always=0;
+ }
+
+static void
+botsub(idx,str)
+ register int idx;
+ char *str;
+ {
+ register int x,y;
+ y = idx & 0xff; x = (idx>>8) & 0xff; idx >>= 16;
+ if (c[idx] != cbak[idx])
+ { cbak[idx]=c[idx]; cursor(x,y); lprintf(str,(long)c[idx]); }
+ }
+
+/*
+ * subroutine to draw only a section of the screen
+ * only the top section of the screen is updated. If entire lines are being
+ * drawn, then they will be cleared first.
+ */
+int d_xmin=0,d_xmax=MAXX,d_ymin=0,d_ymax=MAXY; /* for limited screen drawing */
+draws(xmin,xmax,ymin,ymax)
+ int xmin,xmax,ymin,ymax;
+ {
+ register int i,idx;
+ if (xmin==0 && xmax==MAXX) /* clear section of screen as needed */
+ {
+ if (ymin==0) cl_up(79,ymax);
+ else for (i=ymin; i<ymin; i++) cl_line(1,i+1);
+ xmin = -1;
+ }
+ d_xmin=xmin; d_xmax=xmax; d_ymin=ymin; d_ymax=ymax; /* for limited screen drawing */
+ drawscreen();
+ if (xmin<=0 && xmax==MAXX) /* draw stuff on right side of screen as needed*/
+ {
+ for (i=ymin; i<ymax; i++)
+ {
+ idx = bot_data[i].typ;
+ if (c[idx])
+ {
+ cursor(70,i+1); lprcat(bot_data[i].string);
+ }
+ cbak[idx]=c[idx];
+ }
+ }
+ }
+
+/*
+ drawscreen()
+
+ subroutine to redraw the whole screen as the player knows it
+ */
+char screen[MAXX][MAXY],d_flag; /* template for the screen */
+drawscreen()
+ {
+ register int i,j,k;
+ int lastx,lasty; /* variables used to optimize the object printing */
+ if (d_xmin==0 && d_xmax==MAXX && d_ymin==0 && d_ymax==MAXY)
+ {
+ d_flag=1; clear(); /* clear the screen */
+ }
+ else
+ {
+ d_flag=0; cursor(1,1);
+ }
+ if (d_xmin<0)
+ d_xmin=0; /* d_xmin=-1 means display all without bottomline */
+
+ for (i=d_ymin; i<d_ymax; i++)
+ for (j=d_xmin; j<d_xmax; j++)
+ if (know[j][i]==0) screen[j][i] = ' '; else
+ if (k=mitem[j][i]) screen[j][i] = monstnamelist[k]; else
+ if ((k=item[j][i])==OWALL) screen[j][i] = '#';
+ else screen[j][i] = ' ';
+
+ for (i=d_ymin; i<d_ymax; i++)
+ {
+ j=d_xmin; while ((screen[j][i]==' ') && (j<d_xmax)) j++;
+ /* was m=0 */
+ if (j >= d_xmax) m=d_xmin; /* don't search backwards if blank line */
+ else
+ { /* search backwards for end of line */
+ m=d_xmax-1; while ((screen[m][i]==' ') && (m>d_xmin)) --m;
+ if (j<=m) cursor(j+1,i+1); else continue;
+ }
+ while (j <= m)
+ {
+ if (j <= m-3)
+ {
+ for (k=j; k<=j+3; k++) if (screen[k][i] != ' ') k=1000;
+ if (k < 1000)
+ { while(screen[j][i]==' ' && j<=m) j++; cursor(j+1,i+1); }
+ }
+ lprc(screen[j++][i]);
+ }
+ }
+ setbold(); /* print out only bold objects now */
+
+ for (lastx=lasty=127, i=d_ymin; i<d_ymax; i++)
+ for (j=d_xmin; j<d_xmax; j++)
+ {
+ if (k=item[j][i])
+ if (k != OWALL)
+ if ((know[j][i]) && (mitem[j][i]==0))
+ if (objnamelist[k]!=' ')
+ {
+ if (lasty!=i+1 || lastx!=j)
+ cursor(lastx=j+1,lasty=i+1); else lastx++;
+ lprc(objnamelist[k]);
+ }
+ }
+
+ resetbold(); if (d_flag) { always=1; botside(); always=1; bot_linex(); }
+ oldx=99;
+ d_xmin = 0 , d_xmax = MAXX , d_ymin = 0 , d_ymax = MAXY; /* for limited screen drawing */
+ }
+
+/*
+ showcell(x,y)
+
+ subroutine to display a cell location on the screen
+ */
+showcell(x,y)
+ int x,y;
+ {
+ register int i,j,k,m;
+ if (c[BLINDCOUNT]) return; /* see nothing if blind */
+ if (c[AWARENESS]) { minx = x-3; maxx = x+3; miny = y-3; maxy = y+3; }
+ else { minx = x-1; maxx = x+1; miny = y-1; maxy = y+1; }
+
+ if (minx < 0) minx=0; if (maxx > MAXX-1) maxx = MAXX-1;
+ if (miny < 0) miny=0; if (maxy > MAXY-1) maxy = MAXY-1;
+
+ for (j=miny; j<=maxy; j++)
+ for (m=minx; m<=maxx; m++)
+ if (know[m][j]==0)
+ {
+ cursor(m+1,j+1);
+ x=maxx; while (know[x][j]) --x;
+ for (i=m; i<=x; i++)
+ {
+ if ((k=mitem[i][j]) != 0) lprc(monstnamelist[k]);
+ else switch(k=item[i][j])
+ {
+ case OWALL: case 0: case OIVTELETRAP: case OTRAPARROWIV:
+ case OIVDARTRAP: case OIVTRAPDOOR:
+ lprc(objnamelist[k]); break;
+
+ default: setbold(); lprc(objnamelist[k]); resetbold();
+ };
+ know[i][j]=1;
+ }
+ m = maxx;
+ }
+ }
+
+/*
+ this routine shows only the spot that is given it. the spaces around
+ these coordinated are not shown
+ used in godirect() in monster.c for missile weapons display
+ */
+show1cell(x,y)
+ int x,y;
+ {
+ if (c[BLINDCOUNT]) return; /* see nothing if blind */
+ cursor(x+1,y+1);
+ if ((k=mitem[x][y]) != 0) lprc(monstnamelist[k]);
+ else switch(k=item[x][y])
+ {
+ case OWALL: case 0: case OIVTELETRAP: case OTRAPARROWIV:
+ case OIVDARTRAP: case OIVTRAPDOOR:
+ lprc(objnamelist[k]); break;
+
+ default: setbold(); lprc(objnamelist[k]); resetbold();
+ };
+ know[x][y]|=1; /* we end up knowing about it */
+ }
+
+/*
+ showplayer()
+
+ subroutine to show where the player is on the screen
+ cursor values start from 1 up
+ */
+showplayer()
+ {
+ cursor(playerx+1,playery+1);
+ oldx=playerx; oldy=playery;
+ }
+
+/*
+ moveplayer(dir)
+
+ subroutine to move the player from one room to another
+ returns 0 if can't move in that direction or hit a monster or on an object
+ else returns 1
+ nomove is set to 1 to stop the next move (inadvertent monsters hitting
+ players when walking into walls) if player walks off screen or into wall
+ */
+short diroffx[] = { 0, 0, 1, 0, -1, 1, -1, 1, -1 };
+short diroffy[] = { 0, 1, 0, -1, 0, -1, -1, 1, 1 };
+moveplayer(dir)
+ int dir; /* from = present room # direction = [1-north]
+ [2-east] [3-south] [4-west] [5-northeast]
+ [6-northwest] [7-southeast] [8-southwest]
+ if direction=0, don't move--just show where he is */
+ {
+ register int k,m,i,j;
+ if (c[CONFUSE]) if (c[LEVEL]<rnd(30)) dir=rund(9); /*if confused any dir*/
+ k = playerx + diroffx[dir]; m = playery + diroffy[dir];
+ if (k<0 || k>=MAXX || m<0 || m>=MAXY) { nomove=1; return(yrepcount = 0); }
+ i = item[k][m]; j = mitem[k][m];
+ if (i==OWALL && c[WTW]==0) { nomove=1; return(yrepcount = 0); } /* hit a wall */
+ if (k==33 && m==MAXY-1 && level==1)
+ {
+ newcavelevel(0); for (k=0; k<MAXX; k++) for (m=0; m<MAXY; m++)
+ if (item[k][m]==OENTRANCE)
+ { playerx=k; playery=m; positionplayer(); drawscreen(); return(0); }
+ }
+ if (j>0) { hitmonster(k,m); return(yrepcount = 0); } /* hit a monster*/
+ lastpx = playerx; lastpy = playery;
+ playerx = k; playery = m;
+ if (i && i!=OTRAPARROWIV && i!=OIVTELETRAP && i!=OIVDARTRAP && i!=OIVTRAPDOOR) return(yrepcount = 0); else return(1);
+ }
+
+/*
+ * function to show what magic items have been discovered thus far
+ * enter with -1 for just spells, anything else will give scrolls & potions
+ */
+static int lincount,count;
+seemagic(arg)
+ int arg;
+ {
+ register int i,number;
+ count = lincount = 0; nosignal=1;
+
+ if (arg== -1) /* if display spells while casting one */
+ {
+ for (number=i=0; i<SPNUM; i++) if (spelknow[i]) number++;
+ number = (number+2)/3 + 4; /* # lines needed to display */
+ cl_up(79,number); cursor(1,1);
+ }
+ else
+ {
+ resetscroll(); clear();
+ }
+
+ lprcat("The magic spells you have discovered thus far:\n\n");
+ for (i=0; i<SPNUM; i++)
+ if (spelknow[i])
+ { lprintf("%s %-20s ",spelcode[i],spelname[i]); seepage(); }
+
+ if (arg== -1)
+ {
+ seepage(); more(); nosignal=0;
+ draws(0,MAXX,0,number); return;
+ }
+
+ lincount += 3; if (count!=0) { count=2; seepage(); }
+
+ lprcat("\nThe magic scrolls you have found to date are:\n\n");
+ count=0;
+ for (i=0; i<MAXSCROLL; i++)
+ if (scrollname[i][0])
+ if (scrollname[i][1]!=' ')
+ { lprintf("%-26s",&scrollname[i][1]); seepage(); }
+
+ lincount += 3; if (count!=0) { count=2; seepage(); }
+
+ lprcat("\nThe magic potions you have found to date are:\n\n");
+ count=0;
+ for (i=0; i<MAXPOTION; i++)
+ if (potionname[i][0])
+ if (potionname[i][1]!=' ')
+ { lprintf("%-26s",&potionname[i][1]); seepage(); }
+
+ if (lincount!=0) more(); nosignal=0; setscroll(); drawscreen();
+ }
+
+/*
+ * subroutine to paginate the seemagic function
+ */
+seepage()
+ {
+ if (++count==3)
+ {
+ lincount++; count=0; lprc('\n');
+ if (lincount>17) { lincount=0; more(); clear(); }
+ }
+ }
diff --git a/games/larn/fortune.c b/games/larn/fortune.c
new file mode 100644
index 0000000..f5cff64
--- /dev/null
+++ b/games/larn/fortune.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)fortune.c 5.5 (Berkeley) 6/10/91";
+#endif /* not lint */
+
+/* fortune.c Larn is copyrighted 1986 by Noah Morgan. */
+
+/*
+ * function to return a random fortune from the fortune file
+ */
+
+char *flines[] = {
+ "gem value = gem * 2 ^ perfection",
+ "sitting down can have unexpected results",
+ "don't pry into the affairs of others",
+ "drinking can be hazardous to your health",
+ "beware of the gusher!",
+ "some monsters are greedy",
+ "nymphs have light fingers",
+ "try kissing a disenchantress!",
+ "hammers and brains don't mix",
+ "what does a potion of cure dianthroritis taste like?",
+ "hit point gain/loss when raising a level depends on constitution",
+ "healing a mighty wizard can be exhilarating",
+ "be sure to pay your taxes",
+ "are Vampires afraid of something?",
+ "some dragons can fly",
+ "dos thou strive for perfection?",
+ "patience is a virtue, unless your daughter dies",
+ "what does the Eye of Larn see in its guardian?",
+ "a level 25 player casts like crazy!",
+ "energy rings affect spell regeneration",
+ "difficulty affects regeneration",
+ "control of the pesty spirits is most helpful",
+ "don't fall into a bottomless pit",
+ "dexterity allows you to carry more",
+ "you can get 2 points of WC for the price of one",
+ "never enter the dungeon naked! the monsters will laugh at you!",
+ "did someone put itching powder in your armor?",
+ "you klutz!",
+ "avoid opening doors. you never know whats on the other side.",
+ "infinite regeneration ---> temptation",
+ "the greatest weapon in the game has not the highest Weapon Class",
+ "you can't buy the most powerful scroll",
+ "identify things before you use them",
+ "there's more than one way through a wall"
+};
+
+#define NFORTUNES 34
+
+char *
+fortune()
+{
+ return (flines[random() % NFORTUNES]);
+}
diff --git a/games/larn/global.c b/games/larn/global.c
new file mode 100644
index 0000000..80a3dd4
--- /dev/null
+++ b/games/larn/global.c
@@ -0,0 +1,621 @@
+/* global.c Larn is copyrighted 1986 by Noah Morgan.
+ *
+ * raiselevel() subroutine to raise the player one level
+ * loselevel() subroutine to lower the player by one level
+ * raiseexperience(x) subroutine to increase experience points
+ * loseexperience(x) subroutine to lose experience points
+ * losehp(x) subroutine to remove hit points from the player
+ * losemhp(x) subroutine to remove max # hit points from the player
+ * raisehp(x) subroutine to gain hit points
+ * raisemhp(x) subroutine to gain maximum hit points
+ * losespells(x) subroutine to lose spells
+ * losemspells(x) subroutine to lose maximum spells
+ * raisespells(x) subroutine to gain spells
+ * raisemspells(x) subroutine to gain maximum spells
+ * recalc() function to recalculate the armor class of the player
+ * makemonst(lev) function to return monster number for a randomly selected monster
+ * positionplayer() function to be sure player is not in a wall
+ * quit() subroutine to ask if the player really wants to quit
+ */
+
+#include "header.h"
+extern int score[],srcount,dropflag;
+extern int random;/* the random number seed */
+extern short playerx,playery,lastnum;
+extern char cheat,level,monstnamelist[];
+extern char lastmonst[],*what[],*who[];
+extern char winner[];
+extern char logname[],monstlevel[];
+extern char sciv[SCORESIZE+1][26][2],*potionname[],*scrollname[];
+/*
+ ***********
+ RAISE LEVEL
+ ***********
+ raiselevel()
+
+ subroutine to raise the player one level
+ uses the skill[] array to find level boundarys
+ uses c[EXPERIENCE] c[LEVEL]
+ */
+raiselevel()
+ {
+ if (c[LEVEL] < MAXPLEVEL) raiseexperience((long)(skill[c[LEVEL]]-c[EXPERIENCE]));
+ }
+
+/*
+ ***********
+ LOOSE LEVEL
+ ***********
+ loselevel()
+
+ subroutine to lower the players character level by one
+ */
+loselevel()
+ {
+ if (c[LEVEL] > 1) loseexperience((long)(c[EXPERIENCE] - skill[c[LEVEL]-1] + 1));
+ }
+
+/*
+ ****************
+ RAISE EXPERIENCE
+ ****************
+ raiseexperience(x)
+
+ subroutine to increase experience points
+ */
+raiseexperience(x)
+ register long x;
+ {
+ register int i,tmp;
+ i=c[LEVEL]; c[EXPERIENCE]+=x;
+ while (c[EXPERIENCE] >= skill[c[LEVEL]] && (c[LEVEL] < MAXPLEVEL))
+ {
+ tmp = (c[CONSTITUTION]-c[HARDGAME])>>1;
+ c[LEVEL]++; raisemhp((int)(rnd(3)+rnd((tmp>0)?tmp:1)));
+ raisemspells((int)rund(3));
+ if (c[LEVEL] < 7-c[HARDGAME]) raisemhp((int)(c[CONSTITUTION]>>2));
+ }
+ if (c[LEVEL] != i)
+ {
+ cursors();
+ beep(); lprintf("\nWelcome to level %d",(long)c[LEVEL]); /* if we changed levels */
+ }
+ bottomline();
+ }
+
+/*
+ ****************
+ LOOSE EXPERIENCE
+ ****************
+ loseexperience(x)
+
+ subroutine to lose experience points
+ */
+loseexperience(x)
+ register long x;
+ {
+ register int i,tmp;
+ i=c[LEVEL]; c[EXPERIENCE]-=x;
+ if (c[EXPERIENCE] < 0) c[EXPERIENCE]=0;
+ while (c[EXPERIENCE] < skill[c[LEVEL]-1])
+ {
+ if (--c[LEVEL] <= 1) c[LEVEL]=1; /* down one level */
+ tmp = (c[CONSTITUTION]-c[HARDGAME])>>1; /* lose hpoints */
+ losemhp((int)rnd((tmp>0)?tmp:1)); /* lose hpoints */
+ if (c[LEVEL] < 7-c[HARDGAME]) losemhp((int)(c[CONSTITUTION]>>2));
+ losemspells((int)rund(3)); /* lose spells */
+ }
+ if (i!=c[LEVEL])
+ {
+ cursors();
+ beep(); lprintf("\nYou went down to level %d!",(long)c[LEVEL]);
+ }
+ bottomline();
+ }
+
+/*
+ ********
+ LOOSE HP
+ ********
+ losehp(x)
+ losemhp(x)
+
+ subroutine to remove hit points from the player
+ warning -- will kill player if hp goes to zero
+ */
+losehp(x)
+ register int x;
+ {
+ if ((c[HP] -= x) <= 0)
+ {
+ beep(); lprcat("\n"); nap(3000); died(lastnum);
+ }
+ }
+
+losemhp(x)
+ register int x;
+ {
+ c[HP] -= x; if (c[HP] < 1) c[HP]=1;
+ c[HPMAX] -= x; if (c[HPMAX] < 1) c[HPMAX]=1;
+ }
+
+/*
+ ********
+ RAISE HP
+ ********
+ raisehp(x)
+ raisemhp(x)
+
+ subroutine to gain maximum hit points
+ */
+raisehp(x)
+ register int x;
+ {
+ if ((c[HP] += x) > c[HPMAX]) c[HP] = c[HPMAX];
+ }
+
+raisemhp(x)
+ register int x;
+ {
+ c[HPMAX] += x; c[HP] += x;
+ }
+
+/*
+ ************
+ RAISE SPELLS
+ ************
+ raisespells(x)
+ raisemspells(x)
+
+ subroutine to gain maximum spells
+ */
+raisespells(x)
+ register int x;
+ {
+ if ((c[SPELLS] += x) > c[SPELLMAX]) c[SPELLS] = c[SPELLMAX];
+ }
+
+raisemspells(x)
+ register int x;
+ {
+ c[SPELLMAX]+=x; c[SPELLS]+=x;
+ }
+
+/*
+ ************
+ LOOSE SPELLS
+ ************
+ losespells(x)
+ losemspells(x)
+
+ subroutine to lose maximum spells
+ */
+losespells(x)
+ register int x;
+ {
+ if ((c[SPELLS] -= x) < 0) c[SPELLS]=0;
+ }
+
+losemspells(x)
+ register int x;
+ {
+ if ((c[SPELLMAX] -= x) < 0) c[SPELLMAX]=0;
+ if ((c[SPELLS] -= x) < 0) c[SPELLS]=0;
+ }
+
+/*
+ makemonst(lev)
+ int lev;
+
+ function to return monster number for a randomly selected monster
+ for the given cave level
+ */
+makemonst(lev)
+ register int lev;
+ {
+ register int tmp,x;
+ if (lev < 1) lev = 1; if (lev > 12) lev = 12;
+ tmp=WATERLORD;
+ if (lev < 5)
+ while (tmp==WATERLORD) tmp=rnd((x=monstlevel[lev-1])?x:1);
+ else while (tmp==WATERLORD)
+ tmp=rnd((x=monstlevel[lev-1]-monstlevel[lev-4])?x:1)+monstlevel[lev-4];
+
+ while (monster[tmp].genocided && tmp<MAXMONST) tmp++; /* genocided? */
+ return(tmp);
+ }
+
+/*
+ positionplayer()
+
+ function to be sure player is not in a wall
+ */
+positionplayer()
+ {
+ int try;
+ try = 2;
+ while ((item[playerx][playery] || mitem[playerx][playery]) && (try))
+ if (++playerx >= MAXX-1)
+ {
+ playerx = 1;
+ if (++playery >= MAXY-1)
+ { playery = 1; --try; }
+ }
+ if (try==0) lprcat("Failure in positionplayer\n");
+ }
+
+/*
+ recalc() function to recalculate the armor class of the player
+ */
+recalc()
+ {
+ register int i,j,k;
+ c[AC] = c[MOREDEFENSES];
+ if (c[WEAR] >= 0)
+ switch(iven[c[WEAR]])
+ {
+ case OSHIELD: c[AC] += 2 + ivenarg[c[WEAR]]; break;
+ case OLEATHER: c[AC] += 2 + ivenarg[c[WEAR]]; break;
+ case OSTUDLEATHER: c[AC] += 3 + ivenarg[c[WEAR]]; break;
+ case ORING: c[AC] += 5 + ivenarg[c[WEAR]]; break;
+ case OCHAIN: c[AC] += 6 + ivenarg[c[WEAR]]; break;
+ case OSPLINT: c[AC] += 7 + ivenarg[c[WEAR]]; break;
+ case OPLATE: c[AC] += 9 + ivenarg[c[WEAR]]; break;
+ case OPLATEARMOR: c[AC] += 10 + ivenarg[c[WEAR]]; break;
+ case OSSPLATE: c[AC] += 12 + ivenarg[c[WEAR]]; break;
+ }
+
+ if (c[SHIELD] >= 0) if (iven[c[SHIELD]] == OSHIELD) c[AC] += 2 + ivenarg[c[SHIELD]];
+ if (c[WIELD] < 0) c[WCLASS] = 0; else
+ {
+ i = ivenarg[c[WIELD]];
+ switch(iven[c[WIELD]])
+ {
+ case ODAGGER: c[WCLASS] = 3 + i; break;
+ case OBELT: c[WCLASS] = 7 + i; break;
+ case OSHIELD: c[WCLASS] = 8 + i; break;
+ case OSPEAR: c[WCLASS] = 10 + i; break;
+ case OFLAIL: c[WCLASS] = 14 + i; break;
+ case OBATTLEAXE: c[WCLASS] = 17 + i; break;
+ case OLANCE: c[WCLASS] = 19 + i; break;
+ case OLONGSWORD: c[WCLASS] = 22 + i; break;
+ case O2SWORD: c[WCLASS] = 26 + i; break;
+ case OSWORD: c[WCLASS] = 32 + i; break;
+ case OSWORDofSLASHING: c[WCLASS] = 30 + i; break;
+ case OHAMMER: c[WCLASS] = 35 + i; break;
+ default: c[WCLASS] = 0;
+ }
+ }
+ c[WCLASS] += c[MOREDAM];
+
+/* now for regeneration abilities based on rings */
+ c[REGEN]=1; c[ENERGY]=0;
+ j=0; for (k=25; k>0; k--) if (iven[k]) {j=k; k=0; }
+ for (i=0; i<=j; i++)
+ {
+ switch(iven[i])
+ {
+ case OPROTRING: c[AC] += ivenarg[i] + 1; break;
+ case ODAMRING: c[WCLASS] += ivenarg[i] + 1; break;
+ case OBELT: c[WCLASS] += ((ivenarg[i]<<1)) + 2; break;
+
+ case OREGENRING: c[REGEN] += ivenarg[i] + 1; break;
+ case ORINGOFEXTRA: c[REGEN] += 5 * (ivenarg[i]+1); break;
+ case OENERGYRING: c[ENERGY] += ivenarg[i] + 1; break;
+ }
+ }
+ }
+
+
+/*
+ quit()
+
+ subroutine to ask if the player really wants to quit
+ */
+quit()
+ {
+ register int i;
+ cursors(); strcpy(lastmonst,"");
+ lprcat("\n\nDo you really want to quit?");
+ while (1)
+ {
+ i=getchar();
+ if (i == 'y') { died(300); return; }
+ if ((i == 'n') || (i == '\33')) { lprcat(" no"); lflush(); return; }
+ lprcat("\n"); setbold(); lprcat("Yes"); resetbold(); lprcat(" or ");
+ setbold(); lprcat("No"); resetbold(); lprcat(" please? Do you want to quit? ");
+ }
+ }
+
+/*
+ function to ask --more-- then the user must enter a space
+ */
+more()
+ {
+ lprcat("\n --- press "); standout("space"); lprcat(" to continue --- ");
+ while (getchar() != ' ');
+ }
+
+/*
+ function to put something in the players inventory
+ returns 0 if success, 1 if a failure
+ */
+take(itm,arg)
+ int itm,arg;
+ {
+ register int i,limit;
+/* cursors(); */
+ if ((limit = 15+(c[LEVEL]>>1)) > 26) limit=26;
+ for (i=0; i<limit; i++)
+ if (iven[i]==0)
+ {
+ iven[i] = itm; ivenarg[i] = arg; limit=0;
+ switch(itm)
+ {
+ case OPROTRING: case ODAMRING: case OBELT: limit=1; break;
+ case ODEXRING: c[DEXTERITY] += ivenarg[i]+1; limit=1; break;
+ case OSTRRING: c[STREXTRA] += ivenarg[i]+1; limit=1; break;
+ case OCLEVERRING: c[INTELLIGENCE] += ivenarg[i]+1; limit=1; break;
+ case OHAMMER: c[DEXTERITY] += 10; c[STREXTRA]+=10;
+ c[INTELLIGENCE]-=10; limit=1; break;
+
+ case OORBOFDRAGON: c[SLAYING]++; break;
+ case OSPIRITSCARAB: c[NEGATESPIRIT]++; break;
+ case OCUBEofUNDEAD: c[CUBEofUNDEAD]++; break;
+ case ONOTHEFT: c[NOTHEFT]++; break;
+ case OSWORDofSLASHING: c[DEXTERITY] +=5; limit=1; break;
+ };
+ lprcat("\nYou pick up:"); srcount=0; show3(i);
+ if (limit) bottomline(); return(0);
+ }
+ lprcat("\nYou can't carry anything else"); return(1);
+ }
+
+/*
+ subroutine to drop an object returns 1 if something there already else 0
+ */
+drop_object(k)
+ int k;
+ {
+ int itm;
+ if ((k<0) || (k>25)) return(0);
+ itm = iven[k]; cursors();
+ if (itm==0) { lprintf("\nYou don't have item %c! ",k+'a'); return(1); }
+ if (item[playerx][playery])
+ { beep(); lprcat("\nThere's something here already"); return(1); }
+ if (playery==MAXY-1 && playerx==33) return(1); /* not in entrance */
+ item[playerx][playery] = itm;
+ iarg[playerx][playery] = ivenarg[k];
+ srcount=0; lprcat("\n You drop:"); show3(k); /* show what item you dropped*/
+ know[playerx][playery] = 0; iven[k]=0;
+ if (c[WIELD]==k) c[WIELD]= -1; if (c[WEAR]==k) c[WEAR] = -1;
+ if (c[SHIELD]==k) c[SHIELD]= -1;
+ adjustcvalues(itm,ivenarg[k]);
+ dropflag=1; /* say dropped an item so wont ask to pick it up right away */
+ return(0);
+ }
+
+/*
+ function to enchant armor player is currently wearing
+ */
+enchantarmor()
+ {
+ register int tmp;
+ if (c[WEAR]<0) { if (c[SHIELD] < 0)
+ { cursors(); beep(); lprcat("\nYou feel a sense of loss"); return; }
+ else { tmp=iven[c[SHIELD]]; if (tmp != OSCROLL) if (tmp != OPOTION) { ivenarg[c[SHIELD]]++; bottomline(); } } }
+ tmp = iven[c[WEAR]];
+ if (tmp!=OSCROLL) if (tmp!=OPOTION) { ivenarg[c[WEAR]]++; bottomline(); }
+ }
+
+/*
+ function to enchant a weapon presently being wielded
+ */
+enchweapon()
+ {
+ register int tmp;
+ if (c[WIELD]<0)
+ { cursors(); beep(); lprcat("\nYou feel a sense of loss"); return; }
+ tmp = iven[c[WIELD]];
+ if (tmp!=OSCROLL) if (tmp!=OPOTION)
+ { ivenarg[c[WIELD]]++;
+ if (tmp==OCLEVERRING) c[INTELLIGENCE]++; else
+ if (tmp==OSTRRING) c[STREXTRA]++; else
+ if (tmp==ODEXRING) c[DEXTERITY]++; bottomline(); }
+ }
+
+/*
+ routine to tell if player can carry one more thing
+ returns 1 if pockets are full, else 0
+ */
+pocketfull()
+ {
+ register int i,limit;
+ if ((limit = 15+(c[LEVEL]>>1)) > 26) limit=26;
+ for (i=0; i<limit; i++) if (iven[i]==0) return(0);
+ return(1);
+ }
+
+/*
+ function to return 1 if a monster is next to the player else returns 0
+ */
+nearbymonst()
+ {
+ register int tmp,tmp2;
+ for (tmp=playerx-1; tmp<playerx+2; tmp++)
+ for (tmp2=playery-1; tmp2<playery+2; tmp2++)
+ if (mitem[tmp][tmp2]) return(1); /* if monster nearby */
+ return(0);
+ }
+
+/*
+ function to steal an item from the players pockets
+ returns 1 if steals something else returns 0
+ */
+stealsomething()
+ {
+ register int i,j;
+ j=100;
+ while (1)
+ {
+ i=rund(26);
+ if (iven[i]) if (c[WEAR]!=i) if (c[WIELD]!=i) if (c[SHIELD]!=i)
+ {
+ srcount=0; show3(i);
+ adjustcvalues(iven[i],ivenarg[i]); iven[i]=0; return(1);
+ }
+ if (--j <= 0) return(0);
+ }
+ }
+
+/*
+ function to return 1 is player carrys nothing else return 0
+ */
+emptyhanded()
+ {
+ register int i;
+ for (i=0; i<26; i++)
+ if (iven[i]) if (i!=c[WIELD]) if (i!=c[WEAR]) if (i!=c[SHIELD]) return(0);
+ return(1);
+ }
+
+/*
+ function to create a gem on a square near the player
+ */
+creategem()
+ {
+ register int i,j;
+ switch(rnd(4))
+ {
+ case 1: i=ODIAMOND; j=50; break;
+ case 2: i=ORUBY; j=40; break;
+ case 3: i=OEMERALD; j=30; break;
+ default: i=OSAPPHIRE; j=20; break;
+ };
+ createitem(i,rnd(j)+j/10);
+ }
+
+/*
+ function to change character levels as needed when dropping an object
+ that affects these characteristics
+ */
+adjustcvalues(itm,arg)
+ int itm,arg;
+ {
+ register int flag;
+ flag=0;
+ switch(itm)
+ {
+ case ODEXRING: c[DEXTERITY] -= arg+1; flag=1; break;
+ case OSTRRING: c[STREXTRA] -= arg+1; flag=1; break;
+ case OCLEVERRING: c[INTELLIGENCE] -= arg+1; flag=1; break;
+ case OHAMMER: c[DEXTERITY] -= 10; c[STREXTRA] -= 10;
+ c[INTELLIGENCE] += 10; flag=1; break;
+ case OSWORDofSLASHING: c[DEXTERITY] -= 5; flag=1; break;
+ case OORBOFDRAGON: --c[SLAYING]; return;
+ case OSPIRITSCARAB: --c[NEGATESPIRIT]; return;
+ case OCUBEofUNDEAD: --c[CUBEofUNDEAD]; return;
+ case ONOTHEFT: --c[NOTHEFT]; return;
+ case OLANCE: c[LANCEDEATH]=0; return;
+ case OPOTION: case OSCROLL: return;
+
+ default: flag=1;
+ };
+ if (flag) bottomline();
+ }
+
+/*
+ function to read a string from token input "string"
+ returns a pointer to the string
+ */
+gettokstr(str)
+ register char *str;
+ {
+ register int i,j;
+ i=50;
+ while ((getchar() != '"') && (--i > 0));
+ i=36;
+ while (--i > 0)
+ {
+ if ((j=getchar()) != '"') *str++ = j; else i=0;
+ }
+ *str = 0;
+ i=50;
+ if (j != '"') while ((getchar() != '"') && (--i > 0)); /* if end due to too long, then find closing quote */
+ }
+
+/*
+ function to ask user for a password (no echo)
+ returns 1 if entered correctly, 0 if not
+ */
+static char gpwbuf[33];
+getpassword()
+ {
+ register int i,j;
+ register char *gpwp;
+ extern char *password;
+ scbr(); /* system("stty -echo cbreak"); */
+ gpwp = gpwbuf; lprcat("\nEnter Password: "); lflush();
+ i = strlen(password);
+ for (j=0; j<i; j++) read(0,gpwp++,1); gpwbuf[i]=0;
+ sncbr(); /* system("stty echo -cbreak"); */
+ if (strcmp(gpwbuf,password) != 0)
+ { lprcat("\nSorry\n"); lflush(); return(0); }
+ else return(1);
+ }
+
+/*
+ subroutine to get a yes or no response from the user
+ returns y or n
+ */
+getyn()
+ {
+ register int i;
+ i=0; while (i!='y' && i!='n' && i!='\33') i=getchar();
+ return(i);
+ }
+
+/*
+ function to calculate the pack weight of the player
+ returns the number of pounds the player is carrying
+ */
+packweight()
+ {
+ register int i,j,k;
+ k=c[GOLD]/1000; j=25; while ((iven[j]==0) && (j>0)) --j;
+ for (i=0; i<=j; i++)
+ switch(iven[i])
+ {
+ case 0: break;
+ case OSSPLATE: case OPLATEARMOR: k += 40; break;
+ case OPLATE: k += 35; break;
+ case OHAMMER: k += 30; break;
+ case OSPLINT: k += 26; break;
+ case OSWORDofSLASHING: case OCHAIN:
+ case OBATTLEAXE: case O2SWORD: k += 23; break;
+ case OLONGSWORD: case OSWORD:
+ case ORING: case OFLAIL: k += 20; break;
+ case OLANCE: case OSTUDLEATHER: k += 15; break;
+ case OLEATHER: case OSPEAR: k += 8; break;
+ case OORBOFDRAGON: case OBELT: k += 4; break;
+ case OSHIELD: k += 7; break;
+ case OCHEST: k += 30 + ivenarg[i]; break;
+ default: k++;
+ };
+ return(k);
+ }
+
+#ifndef MACRORND
+ /* macros to generate random numbers 1<=rnd(N)<=N 0<=rund(N)<=N-1 */
+rnd(x)
+ int x;
+ {
+ return((((randx=randx*1103515245+12345)>>7)%(x))+1);
+ }
+
+rund(x)
+ int x;
+ {
+ return((((randx=randx*1103515245+12345)>>7)%(x)) );
+ }
+#endif MACRORND
diff --git a/games/larn/header.h b/games/larn/header.h
new file mode 100644
index 0000000..f667345
--- /dev/null
+++ b/games/larn/header.h
@@ -0,0 +1,435 @@
+/* header.h Larn is copyrighted 1986 by Noah Morgan. */
+
+#define MAXLEVEL 11
+ /* max # levels in the dungeon */
+#define MAXVLEVEL 3
+ /* max # of levels in the temple of the luran */
+#define MAXX 67
+#define MAXY 17
+
+#define SCORESIZE 10
+ /* this is the number of people on a scoreboard max */
+#define MAXPLEVEL 100
+ /* maximum player level allowed */
+#define MAXMONST 56
+ /* maximum # monsters in the dungeon */
+#define SPNUM 38
+ /* maximum number of spells in existance */
+#define MAXSCROLL 28
+ /* maximum number of scrolls that are possible */
+#define MAXPOTION 35
+ /* maximum number of potions that are possible */
+#define TIMELIMIT 30000
+ /* the maximum number of moves before the game is called */
+#define TAXRATE 1/20
+ /* the tax rate for the LRS */
+#define MAXOBJ 93
+ /* the maximum number of objects n < MAXOBJ */
+
+/* this is the structure definition of the monster data */
+struct monst
+ {
+ char *name;
+ char level;
+ short armorclass;
+ char damage;
+ char attack;
+ char defense;
+ char genocided;
+ char intelligence; /* monsters intelligence -- used to choose movement */
+ short gold;
+ short hitpoints;
+ unsigned long experience;
+ };
+
+/* this is the structure definition for the items in the dnd store */
+struct _itm
+ {
+ short price;
+ char **mem;
+ char obj;
+ char arg;
+ char qty;
+ };
+
+/* this is the structure that holds the entire dungeon specifications */
+struct cel
+ {
+ short hitp; /* monster's hit points */
+ char mitem; /* the monster ID */
+ char item; /* the object's ID */
+ short iarg; /* the object's argument */
+ char know; /* have we been here before*/
+ };
+
+/* this is the structure for maintaining & moving the spheres of annihilation */
+struct sphere
+ {
+ struct sphere *p; /* pointer to next structure */
+ char x,y,lev; /* location of the sphere */
+ char dir; /* direction sphere is going in */
+ char lifetime; /* duration of the sphere */
+ };
+
+/* defines for the character attribute array c[] */
+#define STRENGTH 0 /* characters physical strength not due to objects */
+#define INTELLIGENCE 1
+#define WISDOM 2
+#define CONSTITUTION 3
+#define DEXTERITY 4
+#define CHARISMA 5
+#define HPMAX 6
+#define HP 7
+#define GOLD 8
+#define EXPERIENCE 9
+#define LEVEL 10
+#define REGEN 11
+#define WCLASS 12
+#define AC 13
+#define BANKACCOUNT 14
+#define SPELLMAX 15
+#define SPELLS 16
+#define ENERGY 17
+#define ECOUNTER 18
+#define MOREDEFENSES 19
+#define WEAR 20
+#define PROTECTIONTIME 21
+#define WIELD 22
+#define AMULET 23
+#define REGENCOUNTER 24
+#define MOREDAM 25
+#define DEXCOUNT 26
+#define STRCOUNT 27
+#define BLINDCOUNT 28
+#define CAVELEVEL 29
+#define CONFUSE 30
+#define ALTPRO 31
+#define HERO 32
+#define CHARMCOUNT 33
+#define INVISIBILITY 34
+#define CANCELLATION 35
+#define HASTESELF 36
+#define EYEOFLARN 37
+#define AGGRAVATE 38
+#define GLOBE 39
+#define TELEFLAG 40
+#define SLAYING 41
+#define NEGATESPIRIT 42
+#define SCAREMONST 43
+#define AWARENESS 44
+#define HOLDMONST 45
+#define TIMESTOP 46
+#define HASTEMONST 47
+#define CUBEofUNDEAD 48
+#define GIANTSTR 49
+#define FIRERESISTANCE 50
+#define BESSMANN 51
+#define NOTHEFT 52
+#define HARDGAME 53
+#define CPUTIME 54
+#define BYTESIN 55
+#define BYTESOUT 56
+#define MOVESMADE 57
+#define MONSTKILLED 58
+#define SPELLSCAST 59
+#define LANCEDEATH 60
+#define SPIRITPRO 61
+#define UNDEADPRO 62
+#define SHIELD 63
+#define STEALTH 64
+#define ITCHING 65
+#define LAUGHING 66
+#define DRAINSTRENGTH 67
+#define CLUMSINESS 68
+#define INFEEBLEMENT 69
+#define HALFDAM 70
+#define SEEINVISIBLE 71
+#define FILLROOM 72
+#define RANDOMWALK 73
+#define SPHCAST 74 /* nz if an active sphere of annihilation */
+#define WTW 75 /* walk through walls */
+#define STREXTRA 76 /* character strength due to objects or enchantments */
+#define TMP 77 /* misc scratch space */
+#define LIFEPROT 78 /* life protection counter */
+
+/* defines for the objects in the game */
+
+#define OALTAR 1
+#define OTHRONE 2
+#define OORB 3
+#define OPIT 4
+#define OSTAIRSUP 5
+#define OELEVATORUP 6
+#define OFOUNTAIN 7
+#define OSTATUE 8
+#define OTELEPORTER 9
+#define OSCHOOL 10
+#define OMIRROR 11
+#define ODNDSTORE 12
+#define OSTAIRSDOWN 13
+#define OELEVATORDOWN 14
+#define OBANK2 15
+#define OBANK 16
+#define ODEADFOUNTAIN 17
+#define OMAXGOLD 70
+#define OGOLDPILE 18
+#define OOPENDOOR 19
+#define OCLOSEDDOOR 20
+#define OWALL 21
+#define OTRAPARROW 66
+#define OTRAPARROWIV 67
+
+#define OLARNEYE 22
+
+#define OPLATE 23
+#define OCHAIN 24
+#define OLEATHER 25
+#define ORING 60
+#define OSTUDLEATHER 61
+#define OSPLINT 62
+#define OPLATEARMOR 63
+#define OSSPLATE 64
+#define OSHIELD 68
+#define OELVENCHAIN 92
+
+#define OSWORDofSLASHING 26
+#define OHAMMER 27
+#define OSWORD 28
+#define O2SWORD 29
+#define OSPEAR 30
+#define ODAGGER 31
+#define OBATTLEAXE 57
+#define OLONGSWORD 58
+#define OFLAIL 59
+#define OLANCE 65
+#define OVORPAL 90
+#define OSLAYER 91
+
+#define ORINGOFEXTRA 32
+#define OREGENRING 33
+#define OPROTRING 34
+#define OENERGYRING 35
+#define ODEXRING 36
+#define OSTRRING 37
+#define OCLEVERRING 38
+#define ODAMRING 39
+
+#define OBELT 40
+
+#define OSCROLL 41
+#define OPOTION 42
+#define OBOOK 43
+#define OCHEST 44
+#define OAMULET 45
+
+#define OORBOFDRAGON 46
+#define OSPIRITSCARAB 47
+#define OCUBEofUNDEAD 48
+#define ONOTHEFT 49
+
+#define ODIAMOND 50
+#define ORUBY 51
+#define OEMERALD 52
+#define OSAPPHIRE 53
+
+#define OENTRANCE 54
+#define OVOLDOWN 55
+#define OVOLUP 56
+#define OHOME 69
+
+#define OKGOLD 71
+#define ODGOLD 72
+#define OIVDARTRAP 73
+#define ODARTRAP 74
+#define OTRAPDOOR 75
+#define OIVTRAPDOOR 76
+#define OTRADEPOST 77
+#define OIVTELETRAP 78
+#define ODEADTHRONE 79
+#define OANNIHILATION 80 /* sphere of annihilation */
+#define OTHRONE2 81
+#define OLRS 82 /* Larn Revenue Service */
+#define OCOOKIE 83
+#define OURN 84
+#define OBRASSLAMP 85
+#define OHANDofFEAR 86 /* hand of fear */
+#define OSPHTAILSMAN 87 /* tailsman of the sphere */
+#define OWWAND 88 /* wand of wonder */
+#define OPSTAFF 89 /* staff of power */
+/* used up to 92 */
+
+/* defines for the monsters as objects */
+
+#define BAT 1
+#define GNOME 2
+#define HOBGOBLIN 3
+#define JACKAL 4
+#define KOBOLD 5
+#define ORC 6
+#define SNAKE 7
+#define CENTIPEDE 8
+#define JACULI 9
+#define TROGLODYTE 10
+#define ANT 11
+#define EYE 12
+#define LEPRECHAUN 13
+#define NYMPH 14
+#define QUASIT 15
+#define RUSTMONSTER 16
+#define ZOMBIE 17
+#define ASSASSINBUG 18
+#define BUGBEAR 19
+#define HELLHOUND 20
+#define ICELIZARD 21
+#define CENTAUR 22
+#define TROLL 23
+#define YETI 24
+#define WHITEDRAGON 25
+#define ELF 26
+#define CUBE 27
+#define METAMORPH 28
+#define VORTEX 29
+#define ZILLER 30
+#define VIOLETFUNGI 31
+#define WRAITH 32
+#define FORVALAKA 33
+#define LAMANOBE 34
+#define OSEQUIP 35
+#define ROTHE 36
+#define XORN 37
+#define VAMPIRE 38
+#define INVISIBLESTALKER 39
+#define POLTERGEIST 40
+#define DISENCHANTRESS 41
+#define SHAMBLINGMOUND 42
+#define YELLOWMOLD 43
+#define UMBERHULK 44
+#define GNOMEKING 45
+#define MIMIC 46
+#define WATERLORD 47
+#define BRONZEDRAGON 48
+#define GREENDRAGON 49
+#define PURPLEWORM 50
+#define XVART 51
+#define SPIRITNAGA 52
+#define SILVERDRAGON 53
+#define PLATINUMDRAGON 54
+#define GREENURCHIN 55
+#define REDDRAGON 56
+#define DEMONLORD 57
+#define DEMONPRINCE 64
+
+#define NULL 0
+#define BUFBIG 4096 /* size of the output buffer */
+#define MAXIBUF 4096 /* size of the input buffer */
+#define LOGNAMESIZE 40 /* max size of the players name */
+#define PSNAMESIZE 40 /* max size of the process name */
+
+#ifndef NODEFS
+extern char VERSION,SUBVERSION;
+extern char aborted[],alpha[],beenhere[],boldon,cheat,ckpfile[],ckpflag;
+extern char *class[],course[],diagfile[],fortfile[],helpfile[];
+extern char *inbuffer,is_alpha[],is_digit[];
+extern char item[MAXX][MAXY],iven[],know[MAXX][MAXY],larnlevels[],lastmonst[];
+extern char level,*levelname[],logfile[],loginname[],logname[],*lpbuf,*lpend;
+extern char *lpnt,moved[MAXX][MAXY],mitem[MAXX][MAXY],monstlevel[];
+extern char monstnamelist[],nch[],ndgg[],nlpts[],nomove,nosignal,nowelcome;
+extern char nplt[],nsw[],*objectname[];
+extern char objnamelist[],optsfile[],*potionname[],playerids[],potprob[];
+extern char predostuff,psname[],restorflag,savefilename[],scorefile[],scprob[];
+extern char screen[MAXX][MAXY],*scrollname[],sex,*spelcode[],*speldescript[];
+extern char spelknow[],*spelname[],*spelmes[],spelweird[MAXMONST+8][SPNUM];
+extern char splev[],stealth[MAXX][MAXY],to_lower[],to_upper[],wizard;
+extern short diroffx[],diroffy[],hitflag,hit2flag,hit3flag,hitp[MAXX][MAXY];
+extern short iarg[MAXX][MAXY],ivenarg[],lasthx,lasthy,lastnum,lastpx,lastpy;
+extern short nobeep,oldx,oldy,playerx,playery;
+extern int dayplay,enable_scroll,srcount,yrepcount,userid,wisid,lfd,fd;
+extern long initialtime,outstanding_taxes,skill[],gtime,c[],cbak[];
+extern unsigned long randx;
+extern struct cel *cell;
+extern struct monst monster[];
+extern struct sphere *spheres;
+extern struct _itm itm[];
+
+char *fortune(),*getenv(),*getlogin(),*lgetw(),*lgetl(),*ctime();
+char *tmcapcnv(),*tgetstr(),*tgoto();
+long paytaxes(),lgetc(),lrint(),time();
+unsigned long readnum();
+void *malloc();
+
+ /* macro to create scroll #'s with probability of occurrence */
+#define newscroll() (scprob[rund(81)])
+ /* macro to return a potion # created with probability of occurrence */
+#define newpotion() (potprob[rund(41)])
+ /* macro to return the + points on created leather armor */
+#define newleather() (nlpts[rund(c[HARDGAME]?13:15)])
+ /* macro to return the + points on chain armor */
+#define newchain() (nch[rund(10)])
+ /* macro to return + points on plate armor */
+#define newplate() (nplt[rund(c[HARDGAME]?4:12)])
+ /* macro to return + points on new daggers */
+#define newdagger() (ndgg[rund(13)])
+ /* macro to return + points on new swords */
+#define newsword() (nsw[rund(c[HARDGAME]?6:13)])
+ /* macro to destroy object at present location */
+#define forget() (item[playerx][playery]=know[playerx][playery]=0)
+ /* macro to wipe out a monster at a location */
+#define disappear(x,y) (mitem[x][y]=know[x][y]=0)
+
+#ifdef VT100
+ /* macro to turn on bold display for the terminal */
+#define setbold() (lprcat(boldon?"\33[1m":"\33[7m"))
+ /* macro to turn off bold display for the terminal */
+#define resetbold() (lprcat("\33[m"))
+ /* macro to setup the scrolling region for the terminal */
+#define setscroll() (lprcat("\33[20;24r"))
+ /* macro to clear the scrolling region for the terminal */
+#define resetscroll() (lprcat("\33[;24r"))
+ /* macro to clear the screen and home the cursor */
+#define clear() (lprcat("\33[2J\33[f"), cbak[SPELLS]= -50)
+#define cltoeoln() lprcat("\33[K")
+#else VT100
+ /* defines below are for use in the termcap mode only */
+#define ST_START 1
+#define ST_END 2
+#define BOLD 3
+#define END_BOLD 4
+#define CLEAR 5
+#define CL_LINE 6
+#define CL_DOWN 14
+#define CURSOR 15
+ /* macro to turn on bold display for the terminal */
+#define setbold() (*lpnt++ = ST_START)
+ /* macro to turn off bold display for the terminal */
+#define resetbold() (*lpnt++ = ST_END)
+ /* macro to setup the scrolling region for the terminal */
+#define setscroll() enable_scroll=1
+ /* macro to clear the scrolling region for the terminal */
+#define resetscroll() enable_scroll=0
+ /* macro to clear the screen and home the cursor */
+#define clear() (*lpnt++ =CLEAR, cbak[SPELLS]= -50)
+ /* macro to clear to end of line */
+#define cltoeoln() (*lpnt++ = CL_LINE)
+#endif VT100
+
+ /* macro to output one byte to the output buffer */
+#define lprc(ch) ((lpnt>=lpend)?(*lpnt++ =(ch), lflush()):(*lpnt++ =(ch)))
+
+ /* macro to seed the random number generator */
+#define srand(x) (randx=x)
+#ifdef MACRORND
+ /* macros to generate random numbers 1<=rnd(N)<=N 0<=rund(N)<=N-1 */
+#define rnd(x) ((((randx=randx*1103515245+12345)>>7)%(x))+1)
+#define rund(x) ((((randx=randx*1103515245+12345)>>7)%(x)) )
+#endif MACRORND
+ /* macros for miscellaneous data conversion */
+#define min(x,y) (((x)>(y))?(y):(x))
+#define max(x,y) (((x)>(y))?(x):(y))
+#define isalpha(x) (is_alpha[x])
+#define isdigit(x) (is_digit[x])
+#define tolower(x) (to_lower[x])
+#define toupper(x) (to_upper[x])
+#define lcc(x) (to_lower[x])
+#define ucc(x) (to_upper[x])
+#endif NODEFS
+
diff --git a/games/larn/help.c b/games/larn/help.c
new file mode 100644
index 0000000..0f21367
--- /dev/null
+++ b/games/larn/help.c
@@ -0,0 +1,87 @@
+/* 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');
+ }
+
diff --git a/games/larn/holidays b/games/larn/holidays
new file mode 100644
index 0000000..3071ea4
--- /dev/null
+++ b/games/larn/holidays
@@ -0,0 +1,66 @@
+"Nov 27 1986 Thanksgiving"
+"Dec 25 1986 Christmas"
+
+"Jan 01 1987 New Years Day."
+"Feb 16 1987 Washingtons Birthday (Presidents Day)"
+"May 25 1987 Memorial Day"
+"Jul 04 1987 Independence Day"
+"Sep 07 1987 Labor Day"
+"Oct 12 1987 Columbus Day"
+"Nov 26 1987 Thanksgiving"
+"Dec 25 1987 Christmas"
+
+"Jan 01 1988 New Years Day."
+"Feb 15 1988 Washingtons Birthday (Presidents Day)"
+"May 30 1988 Memorial Day"
+"Jul 04 1988 Independence Day"
+"Sep 05 1988 Labor Day"
+"Oct 10 1988 Columbus Day"
+"Nov 24 1988 Thanksgiving"
+"Dec 25 1988 Christmas"
+
+"Jan 01 1989 New Years Day."
+"Feb 13 1989 Washingtons Birthday (Presidents Day)"
+"May 28 1989 Memorial Day"
+"Jul 04 1989 Independence Day"
+"Sep 03 1989 Labor Day"
+"Oct 15 1989 Columbus Day"
+"Nov 29 1989 Thanksgiving"
+"Dec 25 1989 Christmas"
+
+"Jan 01 1990 New Years Day."
+"Feb 12 1990 Washingtons Birthday (Presidents Day)"
+"May 27 1990 Memorial Day"
+"Jul 04 1990 Independence Day"
+"Sep 02 1990 Labor Day"
+"Oct 14 1990 Columbus Day"
+"Nov 28 1990 Thanksgiving"
+"Dec 25 1990 Christmas"
+
+"Jan 01 1991 New Years Day."
+"Feb 11 1991 Washingtons Birthday (Presidents Day)"
+"May 26 1991 Memorial Day"
+"Jul 04 1991 Independence Day"
+"Sep 01 1991 Labor Day"
+"Oct 10 1991 Columbus Day"
+"Nov 27 1991 Thanksgiving"
+"Dec 25 1991 Christmas"
+
+"Jan 01 1992 New Years Day."
+"Feb 10 1992 Washingtons Birthday (Presidents Day)"
+"May 25 1992 Memorial Day"
+"Jul 04 1992 Independence Day"
+"Sep 07 1992 Labor Day"
+"Oct 12 1992 Columbus Day"
+"Nov 26 1992 Thanksgiving"
+"Dec 25 1992 Christmas"
+
+"Jan 01 1993 New Years Day."
+"Feb 15 1993 Washingtons Birthday (Presidents Day)"
+"May 30 1993 Memorial Day"
+"Jul 04 1993 Independence Day"
+"Sep 05 1993 Labor Day"
+"Oct 10 1993 Columbus Day"
+"Nov 24 1993 Thanksgiving"
+"Dec 25 1993 Christmas"
+
diff --git a/games/larn/io.c b/games/larn/io.c
new file mode 100644
index 0000000..dc0d5e7
--- /dev/null
+++ b/games/larn/io.c
@@ -0,0 +1,915 @@
+/* io.c Larn is copyrighted 1986 by Noah Morgan.
+ *
+ * Below are the functions in this file:
+ *
+ * setupvt100() Subroutine to set up terminal in correct mode for game
+ * clearvt100() Subroutine to clean up terminal when the game is over
+ * getchar() Routine to read in one character from the terminal
+ * scbr() Function to set cbreak -echo for the terminal
+ * sncbr() Function to set -cbreak echo for the terminal
+ * newgame() Subroutine to save the initial time and seed rnd()
+ *
+ * FILE OUTPUT ROUTINES
+ *
+ * lprintf(format,args . . .) printf to the output buffer
+ * lprint(integer) send binary integer to output buffer
+ * lwrite(buf,len) write a buffer to the output buffer
+ * lprcat(str) sent string to output buffer
+ *
+ * FILE OUTPUT MACROS (in header.h)
+ *
+ * lprc(character) put the character into the output buffer
+ *
+ * FILE INPUT ROUTINES
+ *
+ * long lgetc() read one character from input buffer
+ * long lrint() read one integer from input buffer
+ * lrfill(address,number) put input bytes into a buffer
+ * char *lgetw() get a whitespace ended word from input
+ * char *lgetl() get a \n or EOF ended line from input
+ *
+ * FILE OPEN / CLOSE ROUTINES
+ *
+ * lcreat(filename) create a new file for write
+ * lopen(filename) open a file for read
+ * lappend(filename) open for append to an existing file
+ * lrclose() close the input file
+ * lwclose() close output file
+ * lflush() flush the output buffer
+ *
+ * Other Routines
+ *
+ * cursor(x,y) position cursor at [x,y]
+ * cursors() position cursor at [1,24] (saves memory)
+ * cl_line(x,y) Clear line at [1,y] and leave cursor at [x,y]
+ * cl_up(x,y) Clear screen from [x,1] to current line.
+ * cl_dn(x,y) Clear screen from [1,y] to end of display.
+ * standout(str) Print the string in standout mode.
+ * set_score_output() Called when output should be literally printed.
+ ** putchar(ch) Print one character in decoded output buffer.
+ ** flush_buf() Flush buffer with decoded output.
+ ** init_term() Terminal initialization -- setup termcap info
+ ** char *tmcapcnv(sd,ss) Routine to convert VT100 \33's to termcap format
+ * beep() Routine to emit a beep if enabled (see no-beep in .larnopts)
+ *
+ * Note: ** entries are available only in termcap mode.
+ */
+
+#include "header.h"
+
+#ifdef SYSV /* system III or system V */
+#include <termio.h>
+#define sgttyb termio
+#define stty(_a,_b) ioctl(_a,TCSETA,_b)
+#define gtty(_a,_b) ioctl(_a,TCGETA,_b)
+static int rawflg = 0;
+static char saveeof,saveeol;
+#define doraw(_a) if(!rawflg){++rawflg;saveeof=_a.c_cc[VMIN];saveeol=_a.c_cc[VTIME];}\
+ _a.c_cc[VMIN]=1;_a.c_cc[VTIME]=1;_a.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL)
+#define unraw(_a) _a.c_cc[VMIN]=saveeof;_a.c_cc[VTIME]=saveeol;_a.c_lflag |= ICANON|ECHO|ECHOE|ECHOK|ECHONL
+
+#else not SYSV
+
+#ifndef BSD
+#define CBREAK RAW /* V7 has no CBREAK */
+#endif
+
+#define doraw(_a) (_a.sg_flags |= CBREAK,_a.sg_flags &= ~ECHO)
+#define unraw(_a) (_a.sg_flags &= ~CBREAK,_a.sg_flags |= ECHO)
+#include <sgtty.h>
+#endif not SYSV
+
+#ifndef NOVARARGS /* if we have varargs */
+#include <varargs.h>
+#else NOVARARGS /* if we don't have varargs */
+typedef char *va_list;
+#define va_dcl int va_alist;
+#define va_start(plist) plist = (char *) &va_alist
+#define va_end(plist)
+#define va_arg(plist,mode) ((mode *)(plist += sizeof(mode)))[-1]
+#endif NOVARARGS
+
+#define LINBUFSIZE 128 /* size of the lgetw() and lgetl() buffer */
+int lfd; /* output file numbers */
+int fd; /* input file numbers */
+static struct sgttyb ttx; /* storage for the tty modes */
+static int ipoint=MAXIBUF,iepoint=MAXIBUF; /* input buffering pointers */
+static char lgetwbuf[LINBUFSIZE]; /* get line (word) buffer */
+
+/*
+ * setupvt100() Subroutine to set up terminal in correct mode for game
+ *
+ * Attributes off, clear screen, set scrolling region, set tty mode
+ */
+setupvt100()
+ {
+ clear(); setscroll(); scbr(); /* system("stty cbreak -echo"); */
+ }
+
+/*
+ * clearvt100() Subroutine to clean up terminal when the game is over
+ *
+ * Attributes off, clear screen, unset scrolling region, restore tty mode
+ */
+clearvt100()
+ {
+ resetscroll(); clear(); sncbr(); /* system("stty -cbreak echo"); */
+ }
+
+/*
+ * getchar() Routine to read in one character from the terminal
+ */
+getchar()
+ {
+ char byt;
+#ifdef EXTRA
+ c[BYTESIN]++;
+#endif
+ lflush(); /* be sure output buffer is flushed */
+ read(0,&byt,1); /* get byte from terminal */
+ return(byt);
+ }
+
+/*
+ * scbr() Function to set cbreak -echo for the terminal
+ *
+ * like: system("stty cbreak -echo")
+ */
+scbr()
+ {
+ gtty(0,&ttx); doraw(ttx); stty(0,&ttx);
+ }
+
+/*
+ * sncbr() Function to set -cbreak echo for the terminal
+ *
+ * like: system("stty -cbreak echo")
+ */
+sncbr()
+ {
+ gtty(0,&ttx); unraw(ttx); stty(0,&ttx);
+ }
+
+/*
+ * newgame() Subroutine to save the initial time and seed rnd()
+ */
+newgame()
+ {
+ register long *p,*pe;
+ for (p=c,pe=c+100; p<pe; *p++ =0);
+ time(&initialtime); srand(initialtime);
+ lcreat((char*)0); /* open buffering for output to terminal */
+ }
+
+/*
+ * lprintf(format,args . . .) printf to the output buffer
+ * char *format;
+ * ??? args . . .
+ *
+ * Enter with the format string in "format", as per printf() usage
+ * and any needed arguments following it
+ * Note: lprintf() only supports %s, %c and %d, with width modifier and left
+ * or right justification.
+ * No correct checking for output buffer overflow is done, but flushes
+ * are done beforehand if needed.
+ * Returns nothing of value.
+ */
+#ifdef lint
+/*VARARGS*/
+lprintf(str)
+ char *str;
+ {
+ char *str2;
+ str2 = str;
+ str = str2; /* to make lint happy */
+ }
+/*VARARGS*/
+sprintf(str)
+ char *str;
+ {
+ char *str2;
+ str2 = str;
+ str = str2; /* to make lint happy */
+ }
+#else lint
+/*VARARGS*/
+lprintf(va_alist)
+va_dcl
+ {
+ va_list ap; /* pointer for variable argument list */
+ register char *fmt;
+ register char *outb,*tmpb;
+ register long wide,left,cont,n; /* data for lprintf */
+ char db[12]; /* %d buffer in lprintf */
+
+ va_start(ap); /* initialize the var args pointer */
+ fmt = va_arg(ap, char *); /* pointer to format string */
+ if (lpnt >= lpend) lflush();
+ outb = lpnt;
+ for ( ; ; )
+ {
+ while (*fmt != '%')
+ if (*fmt) *outb++ = *fmt++; else { lpnt=outb; return; }
+ wide = 0; left = 1; cont=1;
+ while (cont)
+ switch(*(++fmt))
+ {
+ case 'd': n = va_arg(ap, long);
+ if (n<0) { n = -n; *outb++ = '-'; if (wide) --wide; }
+ tmpb = db+11; *tmpb = (char)(n % 10 + '0');
+ while (n>9) *(--tmpb) = (char)((n /= 10) % 10 + '0');
+ if (wide==0) while (tmpb < db+12) *outb++ = *tmpb++;
+ else
+ {
+ wide -= db-tmpb+12;
+ if (left) while (wide-- > 0) *outb++ = ' ';
+ while (tmpb < db+12) *outb++ = *tmpb++;
+ if (left==0) while (wide-- > 0) *outb++ = ' ';
+ }
+ cont=0; break;
+
+ case 's': tmpb = va_arg(ap, char *);
+ if (wide==0) { while (*outb++ = *tmpb++); --outb; }
+ else
+ {
+ n = wide - strlen(tmpb);
+ if (left) while (n-- > 0) *outb++ = ' ';
+ while (*outb++ = *tmpb++); --outb;
+ if (left==0) while (n-- > 0) *outb++ = ' ';
+ }
+ cont=0; break;
+
+ case 'c': *outb++ = va_arg(ap, int); cont=0; break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': wide = 10*wide + *fmt - '0'; break;
+
+ case '-': left = 0; break;
+
+ default: *outb++ = *fmt; cont=0; break;
+ };
+ fmt++;
+ }
+ va_end(ap);
+ }
+#endif lint
+
+/*
+ * lprint(long-integer) send binary integer to output buffer
+ * long integer;
+ *
+ * +---------+---------+---------+---------+
+ * | high | | | low |
+ * | order | | | order |
+ * | byte | | | byte |
+ * +---------+---------+---------+---------+
+ * 31 --- 24 23 --- 16 15 --- 8 7 --- 0
+ *
+ * The save order is low order first, to high order (4 bytes total)
+ * and is written to be system independent.
+ * No checking for output buffer overflow is done, but flushes if needed!
+ * Returns nothing of value.
+ */
+lprint(x)
+ register long x;
+ {
+ if (lpnt >= lpend) lflush();
+ *lpnt++ = 255 & x; *lpnt++ = 255 & (x>>8);
+ *lpnt++ = 255 & (x>>16); *lpnt++ = 255 & (x>>24);
+ }
+
+/*
+ * lwrite(buf,len) write a buffer to the output buffer
+ * char *buf;
+ * int len;
+ *
+ * Enter with the address and number of bytes to write out
+ * Returns nothing of value
+ */
+lwrite(buf,len)
+ register char *buf;
+ int len;
+ {
+ register char *str;
+ register int num2;
+ if (len > 399) /* don't copy data if can just write it */
+ {
+#ifdef EXTRA
+ c[BYTESOUT] += len;
+#endif
+
+#ifndef VT100
+ for (str=buf; len>0; --len)
+ lprc(*str++);
+#else VT100
+ lflush();
+ write(lfd,buf,len);
+#endif VT100
+ }
+ else while (len)
+ {
+ if (lpnt >= lpend) lflush(); /* if buffer is full flush it */
+ num2 = lpbuf+BUFBIG-lpnt; /* # bytes left in output buffer */
+ if (num2 > len) num2=len;
+ str = lpnt; len -= num2;
+ while (num2--) *str++ = *buf++; /* copy in the bytes */
+ lpnt = str;
+ }
+ }
+
+/*
+ * long lgetc() Read one character from input buffer
+ *
+ * Returns 0 if EOF, otherwise the character
+ */
+long lgetc()
+ {
+ register int i;
+ if (ipoint != iepoint) return(inbuffer[ipoint++]);
+ if (iepoint!=MAXIBUF) return(0);
+ if ((i=read(fd,inbuffer,MAXIBUF))<=0)
+ {
+ if (i!=0) write(1,"error reading from input file\n",30);
+ iepoint = ipoint = 0; return(0);
+ }
+ ipoint=1; iepoint=i; return(*inbuffer);
+ }
+
+/*
+ * long lrint() Read one integer from input buffer
+ *
+ * +---------+---------+---------+---------+
+ * | high | | | low |
+ * | order | | | order |
+ * | byte | | | byte |
+ * +---------+---------+---------+---------+
+ * 31 --- 24 23 --- 16 15 --- 8 7 --- 0
+ *
+ * The save order is low order first, to high order (4 bytes total)
+ * Returns the int read
+ */
+long lrint()
+ {
+ register unsigned long i;
+ i = 255 & lgetc(); i |= (255 & lgetc()) << 8;
+ i |= (255 & lgetc()) << 16; i |= (255 & lgetc()) << 24;
+ return(i);
+ }
+
+/*
+ * lrfill(address,number) put input bytes into a buffer
+ * char *address;
+ * int number;
+ *
+ * Reads "number" bytes into the buffer pointed to by "address".
+ * Returns nothing of value
+ */
+lrfill(adr,num)
+ register char *adr;
+ int num;
+ {
+ register char *pnt;
+ register int num2;
+ while (num)
+ {
+ if (iepoint == ipoint)
+ {
+ if (num>5) /* fast way */
+ {
+ if (read(fd,adr,num) != num)
+ write(2,"error reading from input file\n",30);
+ num=0;
+ }
+ else { *adr++ = lgetc(); --num; }
+ }
+ else
+ {
+ num2 = iepoint-ipoint; /* # of bytes left in the buffer */
+ if (num2 > num) num2=num;
+ pnt = inbuffer+ipoint; num -= num2; ipoint += num2;
+ while (num2--) *adr++ = *pnt++;
+ }
+ }
+ }
+
+/*
+ * char *lgetw() Get a whitespace ended word from input
+ *
+ * Returns pointer to a buffer that contains word. If EOF, returns a NULL
+ */
+char *lgetw()
+ {
+ register char *lgp,cc;
+ register int n=LINBUFSIZE,quote=0;
+ lgp = lgetwbuf;
+ do cc=lgetc(); while ((cc <= 32) && (cc > NULL)); /* eat whitespace */
+ for ( ; ; --n,cc=lgetc())
+ {
+ if ((cc==NULL) && (lgp==lgetwbuf)) return(NULL); /* EOF */
+ if ((n<=1) || ((cc<=32) && (quote==0))) { *lgp=NULL; return(lgetwbuf); }
+ if (cc != '"') *lgp++ = cc; else quote ^= 1;
+ }
+ }
+
+/*
+ * char *lgetl() Function to read in a line ended by newline or EOF
+ *
+ * Returns pointer to a buffer that contains the line. If EOF, returns NULL
+ */
+char *lgetl()
+ {
+ register int i=LINBUFSIZE,ch;
+ register char *str=lgetwbuf;
+ for ( ; ; --i)
+ {
+ if ((*str++ = ch = lgetc()) == NULL)
+ {
+ if (str == lgetwbuf+1) return(NULL); /* EOF */
+ ot: *str = NULL; return(lgetwbuf); /* line ended by EOF */
+ }
+ if ((ch=='\n') || (i<=1)) goto ot; /* line ended by \n */
+ }
+ }
+
+/*
+ * lcreat(filename) Create a new file for write
+ * char *filename;
+ *
+ * lcreat((char*)0); means to the terminal
+ * Returns -1 if error, otherwise the file descriptor opened.
+ */
+lcreat(str)
+ char *str;
+ {
+ lpnt = lpbuf; lpend = lpbuf+BUFBIG;
+ if (str==NULL) return(lfd=1);
+ if ((lfd=creat(str,0644)) < 0)
+ {
+ lfd=1; lprintf("error creating file <%s>\n",str); lflush(); return(-1);
+ }
+ return(lfd);
+ }
+
+/*
+ * lopen(filename) Open a file for read
+ * char *filename;
+ *
+ * lopen(0) means from the terminal
+ * Returns -1 if error, otherwise the file descriptor opened.
+ */
+lopen(str)
+ char *str;
+ {
+ ipoint = iepoint = MAXIBUF;
+ if (str==NULL) return(fd=0);
+ if ((fd=open(str,0)) < 0)
+ {
+ lwclose(); lfd=1; lpnt=lpbuf; return(-1);
+ }
+ return(fd);
+ }
+
+/*
+ * lappend(filename) Open for append to an existing file
+ * char *filename;
+ *
+ * lappend(0) means to the terminal
+ * Returns -1 if error, otherwise the file descriptor opened.
+ */
+lappend(str)
+ char *str;
+ {
+ lpnt = lpbuf; lpend = lpbuf+BUFBIG;
+ if (str==NULL) return(lfd=1);
+ if ((lfd=open(str,2)) < 0)
+ {
+ lfd=1; return(-1);
+ }
+ lseek(lfd,0,2); /* seek to end of file */
+ return(lfd);
+ }
+
+/*
+ * lrclose() close the input file
+ *
+ * Returns nothing of value.
+ */
+lrclose()
+ {
+ if (fd > 0) close(fd);
+ }
+
+/*
+ * lwclose() close output file flushing if needed
+ *
+ * Returns nothing of value.
+ */
+lwclose()
+ {
+ lflush(); if (lfd > 2) close(lfd);
+ }
+
+/*
+ * lprcat(string) append a string to the output buffer
+ * avoids calls to lprintf (time consuming)
+ */
+lprcat(str)
+ register char *str;
+ {
+ register char *str2;
+ if (lpnt >= lpend) lflush();
+ str2 = lpnt;
+ while (*str2++ = *str++);
+ lpnt = str2 - 1;
+ }
+
+#ifdef VT100
+/*
+ * cursor(x,y) Subroutine to set the cursor position
+ *
+ * x and y are the cursor coordinates, and lpbuff is the output buffer where
+ * escape sequence will be placed.
+ */
+static char *y_num[]= { "\33[","\33[","\33[2","\33[3","\33[4","\33[5","\33[6",
+ "\33[7","\33[8","\33[9","\33[10","\33[11","\33[12","\33[13","\33[14",
+ "\33[15","\33[16","\33[17","\33[18","\33[19","\33[20","\33[21","\33[22",
+ "\33[23","\33[24" };
+
+static char *x_num[]= { "H","H",";2H",";3H",";4H",";5H",";6H",";7H",";8H",";9H",
+ ";10H",";11H",";12H",";13H",";14H",";15H",";16H",";17H",";18H",";19H",
+ ";20H",";21H",";22H",";23H",";24H",";25H",";26H",";27H",";28H",";29H",
+ ";30H",";31H",";32H",";33H",";34H",";35H",";36H",";37H",";38H",";39H",
+ ";40H",";41H",";42H",";43H",";44H",";45H",";46H",";47H",";48H",";49H",
+ ";50H",";51H",";52H",";53H",";54H",";55H",";56H",";57H",";58H",";59H",
+ ";60H",";61H",";62H",";63H",";64H",";65H",";66H",";67H",";68H",";69H",
+ ";70H",";71H",";72H",";73H",";74H",";75H",";76H",";77H",";78H",";79H",
+ ";80H" };
+
+cursor(x,y)
+ int x,y;
+ {
+ register char *p;
+ if (lpnt >= lpend) lflush();
+
+ p = y_num[y]; /* get the string to print */
+ while (*p) *lpnt++ = *p++; /* print the string */
+
+ p = x_num[x]; /* get the string to print */
+ while (*p) *lpnt++ = *p++; /* print the string */
+ }
+#else VT100
+/*
+ * cursor(x,y) Put cursor at specified coordinates staring at [1,1] (termcap)
+ */
+cursor (x,y)
+ int x,y;
+ {
+ if (lpnt >= lpend) lflush ();
+
+ *lpnt++ = CURSOR; *lpnt++ = x; *lpnt++ = y;
+ }
+#endif VT100
+
+/*
+ * Routine to position cursor at beginning of 24th line
+ */
+cursors()
+ {
+ cursor(1,24);
+ }
+
+#ifndef VT100
+/*
+ * Warning: ringing the bell is control code 7. Don't use in defines.
+ * Don't change the order of these defines.
+ * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with
+ * obvious meanings.
+ */
+
+static char cap[256];
+char *CM, *CE, *CD, *CL, *SO, *SE, *AL, *DL;/* Termcap capabilities */
+static char *outbuf=0; /* translated output buffer */
+
+int putchar ();
+
+/*
+ * init_term() Terminal initialization -- setup termcap info
+ */
+init_term()
+ {
+ char termbuf[1024];
+ char *capptr = cap+10;
+ char *term;
+
+ switch (tgetent(termbuf, term = getenv("TERM")))
+ {
+ case -1:
+ write(2, "Cannot open termcap file.\n", 26); exit();
+ case 0:
+ write(2, "Cannot find entry of ", 21);
+ write(2, term, strlen (term));
+ write(2, " in termcap\n", 12);
+ exit();
+ };
+
+ CM = tgetstr("cm", &capptr); /* Cursor motion */
+ CE = tgetstr("ce", &capptr); /* Clear to eoln */
+ CL = tgetstr("cl", &capptr); /* Clear screen */
+
+/* OPTIONAL */
+ AL = tgetstr("al", &capptr); /* Insert line */
+ DL = tgetstr("dl", &capptr); /* Delete line */
+ SO = tgetstr("so", &capptr); /* Begin standout mode */
+ SE = tgetstr("se", &capptr); /* End standout mode */
+ CD = tgetstr("cd", &capptr); /* Clear to end of display */
+
+ if (!CM) /* can't find cursor motion entry */
+ {
+ write(2, "Sorry, for a ",13); write(2, term, strlen(term));
+ write(2, ", I can't find the cursor motion entry in termcap\n",50);
+ exit();
+ }
+ if (!CE) /* can't find clear to end of line entry */
+ {
+ write(2, "Sorry, for a ",13); write(2, term, strlen(term));
+ write(2,", I can't find the clear to end of line entry in termcap\n",57);
+ exit();
+ }
+ if (!CL) /* can't find clear entire screen entry */
+ {
+ write(2, "Sorry, for a ",13); write(2, term, strlen(term));
+ write(2, ", I can't find the clear entire screen entry in termcap\n",56);
+ exit();
+ }
+ if ((outbuf=malloc(BUFBIG+16))==0) /* get memory for decoded output buffer*/
+ {
+ write(2,"Error malloc'ing memory for decoded output buffer\n",50);
+ died(-285); /* malloc() failure */
+ }
+ }
+#endif VT100
+
+/*
+ * cl_line(x,y) Clear the whole line indicated by 'y' and leave cursor at [x,y]
+ */
+cl_line(x,y)
+ int x,y;
+ {
+#ifdef VT100
+ cursor(x,y); lprcat("\33[2K");
+#else VT100
+ cursor(1,y); *lpnt++ = CL_LINE; cursor(x,y);
+#endif VT100
+ }
+
+/*
+ * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
+ */
+cl_up(x,y)
+ register int x,y;
+ {
+#ifdef VT100
+ cursor(x,y); lprcat("\33[1J\33[2K");
+#else VT100
+ register int i;
+ cursor(1,1);
+ for (i=1; i<=y; i++) { *lpnt++ = CL_LINE; *lpnt++ = '\n'; }
+ cursor(x,y);
+#endif VT100
+ }
+
+/*
+ * cl_dn(x,y) Clear screen from [1,y] to end of display. Leave cursor at [x,y]
+ */
+cl_dn(x,y)
+ register int x,y;
+ {
+#ifdef VT100
+ cursor(x,y); lprcat("\33[J\33[2K");
+#else VT100
+ register int i;
+ cursor(1,y);
+ if (!CD)
+ {
+ *lpnt++ = CL_LINE;
+ for (i=y; i<=24; i++) { *lpnt++ = CL_LINE; if (i!=24) *lpnt++ = '\n'; }
+ cursor(x,y);
+ }
+ else
+ *lpnt++ = CL_DOWN;
+ cursor(x,y);
+#endif VT100
+ }
+
+/*
+ * standout(str) Print the argument string in inverse video (standout mode).
+ */
+standout(str)
+ register char *str;
+ {
+#ifdef VT100
+ setbold();
+ while (*str)
+ *lpnt++ = *str++;
+ resetbold();
+#else VT100
+ *lpnt++ = ST_START;
+ while (*str)
+ *lpnt++ = *str++;
+ *lpnt++ = ST_END;
+#endif VT100
+ }
+
+/*
+ * set_score_output() Called when output should be literally printed.
+ */
+set_score_output()
+ {
+ enable_scroll = -1;
+ }
+
+/*
+ * lflush() Flush the output buffer
+ *
+ * Returns nothing of value.
+ * for termcap version: Flush output in output buffer according to output
+ * status as indicated by `enable_scroll'
+ */
+#ifndef VT100
+static int scrline=18; /* line # for wraparound instead of scrolling if no DL */
+lflush ()
+ {
+ register int lpoint;
+ register char *str;
+ static int curx = 0;
+ static int cury = 0;
+
+ if ((lpoint = lpnt - lpbuf) > 0)
+ {
+#ifdef EXTRA
+ c[BYTESOUT] += lpoint;
+#endif
+ if (enable_scroll <= -1)
+ {
+ flush_buf();
+ if (write(lfd,lpbuf,lpoint) != lpoint)
+ write(2,"error writing to output file\n",29);
+ lpnt = lpbuf; /* point back to beginning of buffer */
+ return;
+ }
+ for (str = lpbuf; str < lpnt; str++)
+ {
+ if (*str>=32) { putchar (*str); curx++; }
+ else switch (*str)
+ {
+ case CLEAR: tputs (CL, 0, putchar); curx = cury = 0;
+ break;
+
+ case CL_LINE: tputs (CE, 0, putchar);
+ break;
+
+ case CL_DOWN: tputs (CD, 0, putchar);
+ break;
+
+ case ST_START: tputs (SO, 0, putchar);
+ break;
+
+ case ST_END: tputs (SE, 0, putchar);
+ break;
+
+ case CURSOR: curx = *++str - 1; cury = *++str - 1;
+ tputs (tgoto (CM, curx, cury), 0, putchar);
+ break;
+
+ case '\n': if ((cury == 23) && enable_scroll)
+ {
+ if (!DL || !AL) /* wraparound or scroll? */
+ {
+ if (++scrline > 23) scrline=19;
+
+ if (++scrline > 23) scrline=19;
+ tputs (tgoto (CM, 0, scrline), 0, putchar);
+ tputs (CE, 0, putchar);
+
+ if (--scrline < 19) scrline=23;
+ tputs (tgoto (CM, 0, scrline), 0, putchar);
+ tputs (CE, 0, putchar);
+ }
+ else
+ {
+ tputs (tgoto (CM, 0, 19), 0, putchar);
+ tputs (DL, 0, putchar);
+ tputs (tgoto (CM, 0, 23), 0, putchar);
+ /* tputs (AL, 0, putchar); */
+ }
+ }
+ else
+ {
+ putchar ('\n'); cury++;
+ }
+ curx = 0;
+ break;
+
+ default: putchar (*str); curx++;
+ };
+ }
+ }
+ lpnt = lpbuf;
+ flush_buf(); /* flush real output buffer now */
+ }
+#else VT100
+/*
+ * lflush() flush the output buffer
+ *
+ * Returns nothing of value.
+ */
+lflush()
+ {
+ register int lpoint;
+ if ((lpoint = lpnt - lpbuf) > 0)
+ {
+#ifdef EXTRA
+ c[BYTESOUT] += lpoint;
+#endif
+ if (write(lfd,lpbuf,lpoint) != lpoint)
+ write(2,"error writing to output file\n",29);
+ }
+ lpnt = lpbuf; /* point back to beginning of buffer */
+ }
+#endif VT100
+
+#ifndef VT100
+static int index=0;
+/*
+ * putchar(ch) Print one character in decoded output buffer.
+ */
+int putchar(c)
+int c;
+ {
+ outbuf[index++] = c;
+ if (index >= BUFBIG) flush_buf();
+ }
+
+/*
+ * flush_buf() Flush buffer with decoded output.
+ */
+flush_buf()
+ {
+ if (index) write(lfd, outbuf, index);
+ index = 0;
+ }
+
+/*
+ * char *tmcapcnv(sd,ss) Routine to convert VT100 escapes to termcap format
+ *
+ * Processes only the \33[#m sequence (converts . files for termcap use
+ */
+char *tmcapcnv(sd,ss)
+ register char *sd,*ss;
+ {
+ register int tmstate=0; /* 0=normal, 1=\33 2=[ 3=# */
+ char tmdigit=0; /* the # in \33[#m */
+ while (*ss)
+ {
+ switch(tmstate)
+ {
+ case 0: if (*ss=='\33') { tmstate++; break; }
+ ign: *sd++ = *ss;
+ ign2: tmstate = 0;
+ break;
+ case 1: if (*ss!='[') goto ign;
+ tmstate++;
+ break;
+ case 2: if (isdigit(*ss)) { tmdigit= *ss-'0'; tmstate++; break; }
+ if (*ss == 'm') { *sd++ = ST_END; goto ign2; }
+ goto ign;
+ case 3: if (*ss == 'm')
+ {
+ if (tmdigit) *sd++ = ST_START;
+ else *sd++ = ST_END;
+ goto ign2;
+ }
+ default: goto ign;
+ };
+ ss++;
+ }
+ *sd=0; /* NULL terminator */
+ return(sd);
+ }
+#endif VT100
+
+/*
+ * beep() Routine to emit a beep if enabled (see no-beep in .larnopts)
+ */
+beep()
+ {
+ if (!nobeep) *lpnt++ = '\7';
+ }
diff --git a/games/larn/larn.6 b/games/larn/larn.6
new file mode 100644
index 0000000..6b47281
--- /dev/null
+++ b/games/larn/larn.6
@@ -0,0 +1,158 @@
+.\" Copyright (c) 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)larn.6 5.5 (Berkeley) 12/30/93
+.\"
+.Dd December 30, 1993
+.Dt LARN 6
+.Os
+.Sh NAME
+.Nm larn
+.Nd exploring the caverns of Larn
+.Sh SYNOPSIS
+.Nm larn
+.Op Fl r
+.Op Fl H Ar number
+.Op Fl n
+.Op Fl h
+.Op Fl o Ar optsfile
+.Sh DESCRIPTION
+.Nm Larn
+is a fantasy games in which your child has contracted
+a strange disease, and none of your home remedies
+seem to have any effect. You set out to find a remedy in a limited
+amount of time, and to collect gold along the way of course!
+.Pp
+The options are:
+.Pp
+.Bl -tag -width flag
+.It Fl r
+The
+.Fl r
+option restores a checkpointed game after it has died.
+.It Fl H
+The
+.Fl H
+option sets the hardness of the game.
+.It Fl n
+The
+.Fl n
+option suppresses the welcome message at start up, putting you directly
+into the game.
+.It Fl h
+The
+.Fl h
+option prints the command line options.
+.It Fl o
+The
+.Fl o
+option specifies a different options file than
+.Pa ~/.larnopts .
+.Sh COMMANDS
+.Pp
+These are the movement commands:
+.Bl -column " print program version" " give present pack weight"
+h move to the left H run left . stay here
+j move down J run down Z teleport yourself
+k move up K run up c cast a spell
+l move to the right L run right r read a scroll
+y move northwest Y run northwest q quaff a potion
+u move northeast U run northeast W wear armor
+b move southwest B run southwest T take off armor
+n move southeast N run southeast w wield a weapon
+^ identify a trap g give present pack weight P give tax status
+d drop an item i inventory your pockets Q quit the game
+v print program version S save the game D list all items found
+? this help screen A create diagnostic file e eat something
+ (wizards only)
+.El
+.Sh OPTIONS FILE
+.Pp
+The file
+.Pa ~/.larnopts
+may be used to set a few options for
+.Nm Larn.
+A sequence of words terminated by whitespace is used to specify options.
+.Pp
+.Bl -tag -width "savefile: xsave-file-namex" -compact
+.It Sy Word
+.Sy Meaning
+.Pp
+.It bold-objects
+Select bold display of objects.
+.It inverse-objects
+Select inverse video display of objects.
+.It no-introduction
+Do not display intro message.
+.It enable-checkpointing
+Turn on periodic checkpointing.
+.It no-beep
+Disable beeping of the terminal.
+.It male
+Choose your sex to be a man.
+.It female
+Choose your sex to be a woman.
+.It name: \*qyour name\*q
+Choose your playing name.
+.It monster: \*qmonst name\*q
+Choose a name for a monster.
+.It savefile: \*qsave-file-name\*q
+Define what the savegame filename will be.
+.El
+.Pp
+Your name and monster names must be enclosed in double quotation marks and may
+be up to 34 characters long. Longer names are truncated.
+Anything enclosed in quotation marks is considered one word, and must be
+separated from other words by whitespace.
+.Sh SPECIAL NOTES
+.Pp
+When
+.Sy dropping gold ,
+if you type '*' as your amount, all your gold gets dropped.
+In general, typing in '*' means all of what you are interested in.
+This is true when visiting the bank, or when contributing at altars.
+.Pp
+You can get out of the store, trading post, school, or home by hitting
+.Sy <esc> .
+.Pp
+When casting a spell, if you need a list of spells you can cast, type \fBD\fP
+as the first letter of your spell. The available list of spells will be shown,
+after which you may enter the spell code. This only works on the 1st letter
+of the spell you are casting.
+.Sh AUTHOR
+Noah Morgan
+.Sh FILES
+.Bl -tag -width "/var/games/larn.scores" -compact
+.It Pa /var/games/larn.scores
+Score file.
+.It Pa ~/.larnopts
+Options file.
+.El
diff --git a/games/larn/main.c b/games/larn/main.c
new file mode 100644
index 0000000..dbe0c89
--- /dev/null
+++ b/games/larn/main.c
@@ -0,0 +1,878 @@
+/* main.c */
+#include <sys/types.h>
+#include "header.h"
+#include <pwd.h>
+static char copyright[]="\nLarn is copyrighted 1986 by Noah Morgan.\n";
+int srcount=0; /* line counter for showstr() */
+int dropflag=0; /* if 1 then don't lookforobject() next round */
+int rmst=80; /* random monster creation counter */
+int userid; /* the players login user id number */
+char nowelcome=0,nomove=0; /* if (nomove) then don't count next iteration as a move */
+static char viewflag=0;
+ /* if viewflag then we have done a 99 stay here and don't showcell in the main loop */
+char restorflag=0; /* 1 means restore has been done */
+static char cmdhelp[] = "\
+Cmd line format: larn [-slicnh] [-o<optsifle>] [-##] [++]\n\
+ -s show the scoreboard\n\
+ -l show the logfile (wizard id only)\n\
+ -i show scoreboard with inventories of dead characters\n\
+ -c create new scoreboard (wizard id only)\n\
+ -n suppress welcome message on starting game\n\
+ -## specify level of difficulty (example: -5)\n\
+ -h print this help text\n\
+ ++ restore game from checkpoint file\n\
+ -o<optsfile> specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
+";
+#ifdef VT100
+static char *termtypes[] = { "vt100", "vt101", "vt102", "vt103", "vt125",
+ "vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
+ "vt341" };
+#endif VT100
+/*
+ ************
+ MAIN PROGRAM
+ ************
+ */
+main(argc,argv)
+ int argc;
+ char **argv;
+ {
+ register int i,j;
+ int hard;
+ char *ptr=0,*ttype;
+ struct passwd *pwe;
+
+/*
+ * first task is to identify the player
+ */
+#ifndef VT100
+ init_term(); /* setup the terminal (find out what type) for termcap */
+#endif VT100
+ if (((ptr = getlogin()) == 0) || (*ptr==0)) /* try to get login name */
+ if (pwe=getpwuid(getuid())) /* can we get it from /etc/passwd? */
+ ptr = pwe->pw_name;
+ else
+ if ((ptr = getenv("USER")) == 0)
+ if ((ptr = getenv("LOGNAME")) == 0)
+ {
+ noone: write(2, "Can't find your logname. Who Are You?\n",39);
+ exit();
+ }
+ if (ptr==0) goto noone;
+ if (strlen(ptr)==0) goto noone;
+/*
+ * second task is to prepare the pathnames the player will need
+ */
+ strcpy(loginname,ptr); /* save loginname of the user for logging purposes */
+ strcpy(logname,ptr); /* this will be overwritten with the players name */
+ if ((ptr = getenv("HOME")) == 0) ptr = ".";
+ strcpy(savefilename, ptr);
+ strcat(savefilename, "/Larn.sav"); /* save file name in home directory */
+ sprintf(optsfile, "%s/.larnopts",ptr); /* the .larnopts filename */
+
+/*
+ * now malloc the memory for the dungeon
+ */
+ cell = (struct cel *)malloc(sizeof(struct cel)*(MAXLEVEL+MAXVLEVEL)*MAXX*MAXY);
+ if (cell == 0) died(-285); /* malloc failure */
+ lpbuf = malloc((5* BUFBIG)>>2); /* output buffer */
+ inbuffer = malloc((5*MAXIBUF)>>2); /* output buffer */
+ if ((lpbuf==0) || (inbuffer==0)) died(-285); /* malloc() failure */
+
+ lcreat((char*)0); newgame(); /* set the initial clock */ hard= -1;
+
+#ifdef VT100
+/*
+ * check terminal type to avoid users who have not vt100 type terminals
+ */
+ ttype = getenv("TERM");
+ for (j=1, i=0; i<sizeof(termtypes)/sizeof(char *); i++)
+ if (strcmp(ttype,termtypes[i]) == 0) { j=0; break; }
+ if (j)
+ {
+ lprcat("Sorry, Larn needs a VT100 family terminal for all it's features.\n"); lflush();
+ exit();
+ }
+#endif VT100
+
+/*
+ * now make scoreboard if it is not there (don't clear)
+ */
+ if (access(scorefile,0) == -1) /* not there */
+ makeboard();
+
+/*
+ * now process the command line arguments
+ */
+ for (i=1; i<argc; i++)
+ {
+ if (argv[i][0] == '-')
+ switch(argv[i][1])
+ {
+ case 's': showscores(); exit(); /* show scoreboard */
+
+ case 'l': /* show log file */
+ diedlog(); exit();
+
+ case 'i': showallscores(); exit(); /* show all scoreboard */
+
+ case 'c': /* anyone with password can create scoreboard */
+ lprcat("Preparing to initialize the scoreboard.\n");
+ if (getpassword() != 0) /*make new scoreboard*/
+ {
+ makeboard(); lprc('\n'); showscores();
+ }
+ exit();
+
+ case 'n': /* no welcome msg */ nowelcome=1; argv[i][0]=0; break;
+
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': /* for hardness */
+ sscanf(&argv[i][1],"%d",&hard);
+ break;
+
+ case 'h': /* print out command line arguments */
+ write(1,cmdhelp,sizeof(cmdhelp)); exit();
+
+ case 'o': /* specify a .larnopts filename */
+ strncpy(optsfile,argv[i]+2,127); break;
+
+ default: printf("Unknown option <%s>\n",argv[i]); exit();
+ };
+
+ if (argv[i][0] == '+')
+ {
+ clear(); restorflag = 1;
+ if (argv[i][1] == '+')
+ {
+ hitflag=1; restoregame(ckpfile); /* restore checkpointed game */
+ }
+ i = argc;
+ }
+ }
+
+ readopts(); /* read the options file if there is one */
+
+
+#ifdef UIDSCORE
+ userid = geteuid(); /* obtain the user's effective id number */
+#else UIDSCORE
+ userid = getplid(logname); /* obtain the players id number */
+#endif UIDSCORE
+ if (userid < 0) { write(2,"Can't obtain playerid\n",22); exit(); }
+
+#ifdef HIDEBYLINK
+/*
+ * this section of code causes the program to look like something else to ps
+ */
+ if (strcmp(psname,argv[0])) /* if a different process name only */
+ {
+ if ((i=access(psname,1)) < 0)
+ { /* link not there */
+ if (link(argv[0],psname)>=0)
+ {
+ argv[0] = psname; execv(psname,argv);
+ }
+ }
+ else
+ unlink(psname);
+ }
+
+ for (i=1; i<argc; i++)
+ {
+ szero(argv[i]); /* zero the argument to avoid ps snooping */
+ }
+#endif HIDEBYLINK
+
+ if (access(savefilename,0)==0) /* restore game if need to */
+ {
+ clear(); restorflag = 1;
+ hitflag=1; restoregame(savefilename); /* restore last game */
+ }
+ sigsetup(); /* trap all needed signals */
+ sethard(hard); /* set up the desired difficulty */
+ setupvt100(); /* setup the terminal special mode */
+ if (c[HP]==0) /* create new game */
+ {
+ makeplayer(); /* make the character that will play */
+ newcavelevel(0);/* make the dungeon */
+ predostuff = 1; /* tell signals that we are in the welcome screen */
+ if (nowelcome==0) welcome(); /* welcome the player to the game */
+ }
+ drawscreen(); /* show the initial dungeon */
+ predostuff = 2; /* tell the trap functions that they must do a showplayer()
+ from here on */
+ /* nice(1); /* games should be run niced */
+ yrepcount = hit2flag = 0;
+ while (1)
+ {
+ if (dropflag==0) lookforobject(); /* see if there is an object here */
+ else dropflag=0; /* don't show it just dropped an item */
+ if (hitflag==0) { if (c[HASTEMONST]) movemonst(); movemonst(); } /* move the monsters */
+ if (viewflag==0) showcell(playerx,playery); else viewflag=0; /* show stuff around player */
+ if (hit3flag) flushall();
+ hitflag=hit3flag=0; nomove=1;
+ bot_linex(); /* update bottom line */
+ while (nomove)
+ {
+ if (hit3flag) flushall();
+ nomove=0; parse();
+ } /* get commands and make moves */
+ regen(); /* regenerate hp and spells */
+ if (c[TIMESTOP]==0)
+ if (--rmst <= 0)
+ { rmst = 120-(level<<2); fillmonst(makemonst(level)); }
+ }
+ }
+
+/*
+ showstr()
+
+ show character's inventory
+ */
+showstr()
+ {
+ register int i,number;
+ for (number=3, i=0; i<26; i++)
+ if (iven[i]) number++; /* count items in inventory */
+ t_setup(number); qshowstr(); t_endup(number);
+ }
+
+qshowstr()
+ {
+ register int i,j,k,sigsav;
+ srcount=0; sigsav=nosignal; nosignal=1; /* don't allow ^c etc */
+ if (c[GOLD]) { lprintf(".) %d gold pieces",(long)c[GOLD]); srcount++; }
+ for (k=26; k>=0; k--)
+ if (iven[k])
+ { for (i=22; i<84; i++)
+ for (j=0; j<=k; j++) if (i==iven[j]) show3(j); k=0; }
+
+ lprintf("\nElapsed time is %d. You have %d mobuls left",(long)((gtime+99)/100+1),(long)((TIMELIMIT-gtime)/100));
+ more(); nosignal=sigsav;
+ }
+
+/*
+ * subroutine to clear screen depending on # lines to display
+ */
+t_setup(count)
+ register int count;
+ {
+ if (count<20) /* how do we clear the screen? */
+ {
+ cl_up(79,count); cursor(1,1);
+ }
+ else
+ {
+ resetscroll(); clear();
+ }
+ }
+
+/*
+ * subroutine to restore normal display screen depending on t_setup()
+ */
+t_endup(count)
+ register int count;
+ {
+ if (count<18) /* how did we clear the screen? */
+ draws(0,MAXX,0,(count>MAXY) ? MAXY : count);
+ else
+ {
+ drawscreen(); setscroll();
+ }
+ }
+
+/*
+ function to show the things player is wearing only
+ */
+showwear()
+ {
+ register int i,j,sigsav,count;
+ sigsav=nosignal; nosignal=1; /* don't allow ^c etc */
+ srcount=0;
+
+ for (count=2,j=0; j<=26; j++) /* count number of items we will display */
+ if (i=iven[j])
+ switch(i)
+ {
+ case OLEATHER: case OPLATE: case OCHAIN:
+ case ORING: case OSTUDLEATHER: case OSPLINT:
+ case OPLATEARMOR: case OSSPLATE: case OSHIELD:
+ count++;
+ };
+
+ t_setup(count);
+
+ for (i=22; i<84; i++)
+ for (j=0; j<=26; j++)
+ if (i==iven[j])
+ switch(i)
+ {
+ case OLEATHER: case OPLATE: case OCHAIN:
+ case ORING: case OSTUDLEATHER: case OSPLINT:
+ case OPLATEARMOR: case OSSPLATE: case OSHIELD:
+ show3(j);
+ };
+ more(); nosignal=sigsav; t_endup(count);
+ }
+
+/*
+ function to show the things player can wield only
+ */
+showwield()
+ {
+ register int i,j,sigsav,count;
+ sigsav=nosignal; nosignal=1; /* don't allow ^c etc */
+ srcount=0;
+
+ for (count=2,j=0; j<=26; j++) /* count how many items */
+ if (i=iven[j])
+ switch(i)
+ {
+ case ODIAMOND: case ORUBY: case OEMERALD: case OSAPPHIRE:
+ case OBOOK: case OCHEST: case OLARNEYE: case ONOTHEFT:
+ case OSPIRITSCARAB: case OCUBEofUNDEAD:
+ case OPOTION: case OSCROLL: break;
+ default: count++;
+ };
+
+ t_setup(count);
+
+ for (i=22; i<84; i++)
+ for (j=0; j<=26; j++)
+ if (i==iven[j])
+ switch(i)
+ {
+ case ODIAMOND: case ORUBY: case OEMERALD: case OSAPPHIRE:
+ case OBOOK: case OCHEST: case OLARNEYE: case ONOTHEFT:
+ case OSPIRITSCARAB: case OCUBEofUNDEAD:
+ case OPOTION: case OSCROLL: break;
+ default: show3(j);
+ };
+ more(); nosignal=sigsav; t_endup(count);
+ }
+
+/*
+ * function to show the things player can read only
+ */
+showread()
+ {
+ register int i,j,sigsav,count;
+ sigsav=nosignal; nosignal=1; /* don't allow ^c etc */
+ srcount=0;
+
+ for (count=2,j=0; j<=26; j++)
+ switch(iven[j])
+ {
+ case OBOOK: case OSCROLL: count++;
+ };
+ t_setup(count);
+
+ for (i=22; i<84; i++)
+ for (j=0; j<=26; j++)
+ if (i==iven[j])
+ switch(i)
+ {
+ case OBOOK: case OSCROLL: show3(j);
+ };
+ more(); nosignal=sigsav; t_endup(count);
+ }
+
+/*
+ * function to show the things player can eat only
+ */
+showeat()
+ {
+ register int i,j,sigsav,count;
+ sigsav=nosignal; nosignal=1; /* don't allow ^c etc */
+ srcount=0;
+
+ for (count=2,j=0; j<=26; j++)
+ switch(iven[j])
+ {
+ case OCOOKIE: count++;
+ };
+ t_setup(count);
+
+ for (i=22; i<84; i++)
+ for (j=0; j<=26; j++)
+ if (i==iven[j])
+ switch(i)
+ {
+ case OCOOKIE: show3(j);
+ };
+ more(); nosignal=sigsav; t_endup(count);
+ }
+
+/*
+ function to show the things player can quaff only
+ */
+showquaff()
+ {
+ register int i,j,sigsav,count;
+ sigsav=nosignal; nosignal=1; /* don't allow ^c etc */
+ srcount=0;
+
+ for (count=2,j=0; j<=26; j++)
+ switch(iven[j])
+ {
+ case OPOTION: count++;
+ };
+ t_setup(count);
+
+ for (i=22; i<84; i++)
+ for (j=0; j<=26; j++)
+ if (i==iven[j])
+ switch(i)
+ {
+ case OPOTION: show3(j);
+ };
+ more(); nosignal=sigsav; t_endup(count);
+ }
+
+show1(idx,str2)
+ register int idx;
+ register char *str2[];
+ {
+ if (str2==0) lprintf("\n%c) %s",idx+'a',objectname[iven[idx]]);
+ else if (*str2[ivenarg[idx]]==0) lprintf("\n%c) %s",idx+'a',objectname[iven[idx]]);
+ else lprintf("\n%c) %s of%s",idx+'a',objectname[iven[idx]],str2[ivenarg[idx]]);
+ }
+
+show3(index)
+ register int index;
+ {
+ switch(iven[index])
+ {
+ case OPOTION: show1(index,potionname); break;
+ case OSCROLL: show1(index,scrollname); break;
+
+ case OLARNEYE: case OBOOK: case OSPIRITSCARAB:
+ case ODIAMOND: case ORUBY: case OCUBEofUNDEAD:
+ case OEMERALD: case OCHEST: case OCOOKIE:
+ case OSAPPHIRE: case ONOTHEFT: show1(index,(char **)0); break;
+
+ default: lprintf("\n%c) %s",index+'a',objectname[iven[index]]);
+ if (ivenarg[index]>0) lprintf(" + %d",(long)ivenarg[index]);
+ else if (ivenarg[index]<0) lprintf(" %d",(long)ivenarg[index]);
+ break;
+ }
+ if (c[WIELD]==index) lprcat(" (weapon in hand)");
+ if ((c[WEAR]==index) || (c[SHIELD]==index)) lprcat(" (being worn)");
+ if (++srcount>=22) { srcount=0; more(); clear(); }
+ }
+
+/*
+ subroutine to randomly create monsters if needed
+ */
+randmonst()
+ {
+ if (c[TIMESTOP]) return; /* don't make monsters if time is stopped */
+ if (--rmst <= 0)
+ {
+ rmst = 120 - (level<<2); fillmonst(makemonst(level));
+ }
+ }
+
+
+/*
+ parse()
+
+ get and execute a command
+ */
+parse()
+ {
+ register int i,j,k,flag;
+ while (1)
+ {
+ k = yylex();
+ switch(k) /* get the token from the input and switch on it */
+ {
+ case 'h': moveplayer(4); return; /* west */
+ case 'H': run(4); return; /* west */
+ case 'l': moveplayer(2); return; /* east */
+ case 'L': run(2); return; /* east */
+ case 'j': moveplayer(1); return; /* south */
+ case 'J': run(1); return; /* south */
+ case 'k': moveplayer(3); return; /* north */
+ case 'K': run(3); return; /* north */
+ case 'u': moveplayer(5); return; /* northeast */
+ case 'U': run(5); return; /* northeast */
+ case 'y': moveplayer(6); return; /* northwest */
+ case 'Y': run(6); return; /* northwest */
+ case 'n': moveplayer(7); return; /* southeast */
+ case 'N': run(7); return; /* southeast */
+ case 'b': moveplayer(8); return; /* southwest */
+ case 'B': run(8); return; /* southwest */
+
+ case '.': if (yrepcount) viewflag=1; return; /* stay here */
+
+ case 'w': yrepcount=0; wield(); return; /* wield a weapon */
+
+ case 'W': yrepcount=0; wear(); return; /* wear armor */
+
+ case 'r': yrepcount=0;
+ if (c[BLINDCOUNT]) { cursors(); lprcat("\nYou can't read anything when you're blind!"); } else
+ if (c[TIMESTOP]==0) readscr(); return; /* to read a scroll */
+
+ case 'q': yrepcount=0; if (c[TIMESTOP]==0) quaff(); return; /* quaff a potion */
+
+ case 'd': yrepcount=0; if (c[TIMESTOP]==0) dropobj(); return; /* to drop an object */
+
+ case 'c': yrepcount=0; cast(); return; /* cast a spell */
+
+ case 'i': yrepcount=0; nomove=1; showstr(); return; /* status */
+
+ case 'e': yrepcount=0;
+ if (c[TIMESTOP]==0) eatcookie(); return; /* to eat a fortune cookie */
+
+ case 'D': yrepcount=0; seemagic(0); nomove=1; return; /* list spells and scrolls */
+
+ case '?': yrepcount=0; help(); nomove=1; return; /* give the help screen*/
+
+ case 'S': clear(); lprcat("Saving . . ."); lflush();
+ savegame(savefilename); wizard=1; died(-257); /* save the game - doesn't return */
+
+ case 'Z': yrepcount=0; if (c[LEVEL]>9) { oteleport(1); return; }
+ cursors(); lprcat("\nAs yet, you don't have enough experience to use teleportation");
+ return; /* teleport yourself */
+
+ case '^': /* identify traps */ flag=yrepcount=0; cursors();
+ lprc('\n'); for (j=playery-1; j<playery+2; j++)
+ {
+ if (j < 0) j=0; if (j >= MAXY) break;
+ for (i=playerx-1; i<playerx+2; i++)
+ {
+ if (i < 0) i=0; if (i >= MAXX) break;
+ switch(item[i][j])
+ {
+ case OTRAPDOOR: case ODARTRAP:
+ case OTRAPARROW: case OTELEPORTER:
+ lprcat("\nIts "); lprcat(objectname[item[i][j]]); flag++;
+ };
+ }
+ }
+ if (flag==0) lprcat("\nNo traps are visible");
+ return;
+
+#if WIZID
+ case '_': /* this is the fudge player password for wizard mode*/
+ yrepcount=0; cursors(); nomove=1;
+ if (userid!=wisid)
+ {
+ lprcat("Sorry, you are not empowered to be a wizard.\n");
+ scbr(); /* system("stty -echo cbreak"); */
+ lflush(); return;
+ }
+ if (getpassword()==0)
+ {
+ scbr(); /* system("stty -echo cbreak"); */ return;
+ }
+ wizard=1; scbr(); /* system("stty -echo cbreak"); */
+ for (i=0; i<6; i++) c[i]=70; iven[0]=iven[1]=0;
+ take(OPROTRING,50); take(OLANCE,25); c[WIELD]=1;
+ c[LANCEDEATH]=1; c[WEAR] = c[SHIELD] = -1;
+ raiseexperience(6000000L); c[AWARENESS] += 25000;
+ {
+ register int i,j;
+ for (i=0; i<MAXY; i++)
+ for (j=0; j<MAXX; j++) know[j][i]=1;
+ for (i=0; i<SPNUM; i++) spelknow[i]=1;
+ for (i=0; i<MAXSCROLL; i++) scrollname[i][0]=' ';
+ for (i=0; i<MAXPOTION; i++) potionname[i][0]=' ';
+ }
+ for (i=0; i<MAXSCROLL; i++)
+ if (strlen(scrollname[i])>2) /* no null items */
+ { item[i][0]=OSCROLL; iarg[i][0]=i; }
+ for (i=MAXX-1; i>MAXX-1-MAXPOTION; i--)
+ if (strlen(potionname[i-MAXX+MAXPOTION])>2) /* no null items */
+ { item[i][0]=OPOTION; iarg[i][0]=i-MAXX+MAXPOTION; }
+ for (i=1; i<MAXY; i++)
+ { item[0][i]=i; iarg[0][i]=0; }
+ for (i=MAXY; i<MAXY+MAXX; i++)
+ { item[i-MAXY][MAXY-1]=i; iarg[i-MAXY][MAXY-1]=0; }
+ for (i=MAXX+MAXY; i<MAXX+MAXY+MAXY; i++)
+ { item[MAXX-1][i-MAXX-MAXY]=i; iarg[MAXX-1][i-MAXX-MAXY]=0; }
+ c[GOLD]+=25000; drawscreen(); return;
+#endif
+
+ case 'T': yrepcount=0; cursors(); if (c[SHIELD] != -1) { c[SHIELD] = -1; lprcat("\nYour shield is off"); bottomline(); } else
+ if (c[WEAR] != -1) { c[WEAR] = -1; lprcat("\nYour armor is off"); bottomline(); }
+ else lprcat("\nYou aren't wearing anything");
+ return;
+
+ case 'g': cursors();
+ lprintf("\nThe stuff you are carrying presently weighs %d pounds",(long)packweight());
+ case ' ': yrepcount=0; nomove=1; return;
+
+ case 'v': yrepcount=0; cursors();
+ lprintf("\nCaverns of Larn, Version %d.%d, Diff=%d",(long)VERSION,(long)SUBVERSION,(long)c[HARDGAME]);
+ if (wizard) lprcat(" Wizard"); nomove=1;
+ if (cheat) lprcat(" Cheater");
+ lprcat(copyright);
+ return;
+
+ case 'Q': yrepcount=0; quit(); nomove=1; return; /* quit */
+
+ case 'L'-64: yrepcount=0; drawscreen(); nomove=1; return; /* look */
+
+#if WIZID
+#ifdef EXTRA
+ case 'A': yrepcount=0; nomove=1; if (wizard) { diag(); return; } /* create diagnostic file */
+ return;
+#endif
+#endif
+ case 'P': cursors();
+ if (outstanding_taxes>0)
+ lprintf("\nYou presently owe %d gp in taxes.",(long)outstanding_taxes);
+ else
+ lprcat("\nYou do not owe any taxes.");
+ return;
+ };
+ }
+ }
+
+parse2()
+ {
+ if (c[HASTEMONST]) movemonst(); movemonst(); /* move the monsters */
+ randmonst(); regen();
+ }
+
+run(dir)
+ int dir;
+ {
+ register int i;
+ i=1; while (i)
+ {
+ i=moveplayer(dir);
+ if (i>0) { if (c[HASTEMONST]) movemonst(); movemonst(); randmonst(); regen(); }
+ if (hitflag) i=0;
+ if (i!=0) showcell(playerx,playery);
+ }
+ }
+
+/*
+ function to wield a weapon
+ */
+wield()
+ {
+ register int i;
+ while (1)
+ {
+ if ((i = whatitem("wield"))=='\33') return;
+ if (i != '.')
+ {
+ if (i=='*') showwield();
+ else if (iven[i-'a']==0) { ydhi(i); return; }
+ else if (iven[i-'a']==OPOTION) { ycwi(i); return; }
+ else if (iven[i-'a']==OSCROLL) { ycwi(i); return; }
+ else if ((c[SHIELD]!= -1) && (iven[i-'a']==O2SWORD)) { lprcat("\nBut one arm is busy with your shield!"); return; }
+ else { c[WIELD]=i-'a'; if (iven[i-'a'] == OLANCE) c[LANCEDEATH]=1; else c[LANCEDEATH]=0; bottomline(); return; }
+ }
+ }
+ }
+
+/*
+ common routine to say you don't have an item
+ */
+ydhi(x)
+ int x;
+ { cursors(); lprintf("\nYou don't have item %c!",x); }
+ycwi(x)
+ int x;
+ { cursors(); lprintf("\nYou can't wield item %c!",x); }
+
+/*
+ function to wear armor
+ */
+wear()
+ {
+ register int i;
+ while (1)
+ {
+ if ((i = whatitem("wear"))=='\33') return;
+ if (i != '.')
+ {
+ if (i=='*') showwear(); else
+ switch(iven[i-'a'])
+ {
+ case 0: ydhi(i); return;
+ case OLEATHER: case OCHAIN: case OPLATE: case OSTUDLEATHER:
+ case ORING: case OSPLINT: case OPLATEARMOR: case OSSPLATE:
+ if (c[WEAR] != -1) { lprcat("\nYou're already wearing some armor"); return; }
+ c[WEAR]=i-'a'; bottomline(); return;
+ case OSHIELD: if (c[SHIELD] != -1) { lprcat("\nYou are already wearing a shield"); return; }
+ if (iven[c[WIELD]]==O2SWORD) { lprcat("\nYour hands are busy with the two handed sword!"); return; }
+ c[SHIELD] = i-'a'; bottomline(); return;
+ default: lprcat("\nYou can't wear that!");
+ };
+ }
+ }
+ }
+
+/*
+ function to drop an object
+ */
+dropobj()
+ {
+ register int i;
+ register char *p;
+ long amt;
+ p = &item[playerx][playery];
+ while (1)
+ {
+ if ((i = whatitem("drop"))=='\33') return;
+ if (i=='*') showstr(); else
+ {
+ if (i=='.') /* drop some gold */
+ {
+ if (*p) { lprcat("\nThere's something here already!"); return; }
+ lprcat("\n\n");
+ cl_dn(1,23);
+ lprcat("How much gold do you drop? ");
+ if ((amt=readnum((long)c[GOLD])) == 0) return;
+ if (amt>c[GOLD])
+ { lprcat("\nYou don't have that much!"); return; }
+ if (amt<=32767)
+ { *p=OGOLDPILE; i=amt; }
+ else if (amt<=327670L)
+ { *p=ODGOLD; i=amt/10; amt = 10*i; }
+ else if (amt<=3276700L)
+ { *p=OMAXGOLD; i=amt/100; amt = 100*i; }
+ else if (amt<=32767000L)
+ { *p=OKGOLD; i=amt/1000; amt = 1000*i; }
+ else
+ { *p=OKGOLD; i=32767; amt = 32767000L; }
+ c[GOLD] -= amt;
+ lprintf("You drop %d gold pieces",(long)amt);
+ iarg[playerx][playery]=i; bottomgold();
+ know[playerx][playery]=0; dropflag=1; return;
+ }
+ drop_object(i-'a');
+ return;
+ }
+ }
+ }
+
+/*
+ * readscr() Subroutine to read a scroll one is carrying
+ */
+readscr()
+ {
+ register int i;
+ while (1)
+ {
+ if ((i = whatitem("read"))=='\33') return;
+ if (i != '.')
+ {
+ if (i=='*') showread(); else
+ {
+ if (iven[i-'a']==OSCROLL) { read_scroll(ivenarg[i-'a']); iven[i-'a']=0; return; }
+ if (iven[i-'a']==OBOOK) { readbook(ivenarg[i-'a']); iven[i-'a']=0; return; }
+ if (iven[i-'a']==0) { ydhi(i); return; }
+ lprcat("\nThere's nothing on it to read"); return;
+ }
+ }
+ }
+ }
+
+/*
+ * subroutine to eat a cookie one is carrying
+ */
+eatcookie()
+{
+register int i;
+char *p;
+while (1)
+ {
+ if ((i = whatitem("eat"))=='\33') return;
+ if (i != '.')
+ if (i=='*') showeat(); else
+ {
+ if (iven[i-'a']==OCOOKIE)
+ {
+ lprcat("\nThe cookie was delicious.");
+ iven[i-'a']=0;
+ if (!c[BLINDCOUNT])
+ {
+ if (p=fortune(fortfile))
+ {
+ lprcat(" Inside you find a scrap of paper that says:\n");
+ lprcat(p);
+ }
+ }
+ return;
+ }
+ if (iven[i-'a']==0) { ydhi(i); return; }
+ lprcat("\nYou can't eat that!"); return;
+ }
+ }
+}
+
+/*
+ * subroutine to quaff a potion one is carrying
+ */
+quaff()
+ {
+ register int i;
+ while (1)
+ {
+ if ((i = whatitem("quaff"))=='\33') return;
+ if (i != '.')
+ {
+ if (i=='*') showquaff(); else
+ {
+ if (iven[i-'a']==OPOTION) { quaffpotion(ivenarg[i-'a']); iven[i-'a']=0; return; }
+ if (iven[i-'a']==0) { ydhi(i); return; }
+ lprcat("\nYou wouldn't want to quaff that, would you? "); return;
+ }
+ }
+ }
+ }
+
+/*
+ function to ask what player wants to do
+ */
+whatitem(str)
+ char *str;
+ {
+ int i;
+ cursors(); lprintf("\nWhat do you want to %s [* for all] ? ",str);
+ i=0; while (i>'z' || (i<'a' && i!='*' && i!='\33' && i!='.')) i=getchar();
+ if (i=='\33') lprcat(" aborted");
+ return(i);
+ }
+
+/*
+ subroutine to get a number from the player
+ and allow * to mean return amt, else return the number entered
+ */
+unsigned long readnum(mx)
+ long mx;
+ {
+ register int i;
+ register unsigned long amt=0;
+ sncbr();
+ if ((i=getchar()) == '*') amt = mx; /* allow him to say * for all gold */
+ else
+ while (i != '\n')
+ {
+ if (i=='\033') { scbr(); lprcat(" aborted"); return(0); }
+ if ((i <= '9') && (i >= '0') && (amt<99999999))
+ amt = amt*10+i-'0';
+ i = getchar();
+ }
+ scbr(); return(amt);
+ }
+
+#ifdef HIDEBYLINK
+/*
+ * routine to zero every byte in a string
+ */
+szero(str)
+ register char *str;
+ {
+ while (*str)
+ *str++ = 0;
+ }
+#endif HIDEBYLINK
diff --git a/games/larn/monster.c b/games/larn/monster.c
new file mode 100644
index 0000000..6ec0865
--- /dev/null
+++ b/games/larn/monster.c
@@ -0,0 +1,1387 @@
+/*
+ * monster.c Larn is copyrighted 1986 by Noah Morgan.
+ *
+ * This file contains the following functions:
+ * ----------------------------------------------------------------------------
+ *
+ * createmonster(monstno) Function to create a monster next to the player
+ * int monstno;
+ *
+ * int cgood(x,y,itm,monst) Function to check location for emptiness
+ * int x,y,itm,monst;
+ *
+ * createitem(it,arg) Routine to place an item next to the player
+ * int it,arg;
+ *
+ * cast() Subroutine called by parse to cast a spell for the user
+ *
+ * speldamage(x) Function to perform spell functions cast by the player
+ * int x;
+ *
+ * loseint() Routine to decrement your int (intelligence) if > 3
+ *
+ * isconfuse() Routine to check to see if player is confused
+ *
+ * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
+ * int x,monst;
+ *
+ * fullhit(xx) Function to return full damage against a monst (aka web)
+ * int xx;
+ *
+ * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
+ * int spnum,dam,arg;
+ * char *str;
+ *
+ * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
+ * int spnum,dam,delay;
+ * char *str,cshow;
+ *
+ * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
+ * int x,y;
+ *
+ * tdirect(spnum) Routine to teleport away a monster
+ * int spnum;
+ *
+ * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
+ * int sp,dam;
+ * char *str;
+ *
+ * dirsub(x,y) Routine to ask for direction, then modify x,y for it
+ * int *x,*y;
+ *
+ * vxy(x,y) Routine to verify/fix (*x,*y) for being within bounds
+ * int *x,*y;
+ *
+ * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
+ * int spnum;
+ *
+ * hitmonster(x,y) Function to hit a monster at the designated coordinates
+ * int x,y;
+ *
+ * hitm(x,y,amt) Function to just hit a monster at a given coordinates
+ * int x,y,amt;
+ *
+ * hitplayer(x,y) Function for the monster to hit the player from (x,y)
+ * int x,y;
+ *
+ * dropsomething(monst) Function to create an object when a monster dies
+ * int monst;
+ *
+ * dropgold(amount) Function to drop some gold around player
+ * int amount;
+ *
+ * something(level) Function to create a random item around player
+ * int level;
+ *
+ * newobject(lev,i) Routine to return a randomly selected new object
+ * int lev,*i;
+ *
+ * spattack(atckno,xx,yy) Function to process special attacks from monsters
+ * int atckno,xx,yy;
+ *
+ * checkloss(x) Routine to subtract hp from user and flag bottomline display
+ * int x;
+ *
+ * annihilate() Routine to annihilate monsters around player, playerx,playery
+ *
+ * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
+ * int x,y,dir,lifetime;
+ *
+ * rmsphere(x,y) Function to delete a sphere of annihilation from list
+ * int x,y;
+ *
+ * sphboom(x,y) Function to perform the effects of a sphere detonation
+ * int x,y;
+ *
+ * genmonst() Function to ask for monster and genocide from game
+ *
+ */
+#include "header.h"
+
+struct isave /* used for altar reality */
+ {
+ char type; /* 0=item, 1=monster */
+ char id; /* item number or monster number */
+ short arg; /* the type of item or hitpoints of monster */
+ };
+
+/*
+ * createmonster(monstno) Function to create a monster next to the player
+ * int monstno;
+ *
+ * Enter with the monster number (1 to MAXMONST+8)
+ * Returns no value.
+ */
+createmonster(mon)
+ int mon;
+ {
+ register int x,y,k,i;
+ if (mon<1 || mon>MAXMONST+8) /* check for monster number out of bounds */
+ {
+ beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon); nap(3000); return;
+ }
+ while (monster[mon].genocided && mon<MAXMONST) mon++; /* genocided? */
+ for (k=rnd(8), i= -8; i<0; i++,k++) /* choose direction, then try all */
+ {
+ if (k>8) k=1; /* wraparound the diroff arrays */
+ x = playerx + diroffx[k]; y = playery + diroffy[k];
+ if (cgood(x,y,0,1)) /* if we can create here */
+ {
+ mitem[x][y] = mon;
+ hitp[x][y] = monster[mon].hitpoints;
+ stealth[x][y]=know[x][y]=0;
+ switch(mon)
+ {
+ case ROTHE: case POLTERGEIST: case VAMPIRE: stealth[x][y]=1;
+ };
+ return;
+ }
+ }
+ }
+
+/*
+ * int cgood(x,y,itm,monst) Function to check location for emptiness
+ * int x,y,itm,monst;
+ *
+ * Routine to return TRUE if a location does not have itm or monst there
+ * returns FALSE (0) otherwise
+ * Enter with itm or monst TRUE or FALSE if checking it
+ * Example: if itm==TRUE check for no item at this location
+ * if monst==TRUE check for no monster at this location
+ * This routine will return FALSE if at a wall or the dungeon exit on level 1
+ */
+int cgood(x,y,itm,monst)
+ register int x,y;
+ int itm,monst;
+ {
+ if ((y>=0) && (y<=MAXY-1) && (x>=0) && (x<=MAXX-1)) /* within bounds? */
+ if (item[x][y]!=OWALL) /* can't make anything on walls */
+ if (itm==0 || (item[x][y]==0)) /* is it free of items? */
+ if (monst==0 || (mitem[x][y]==0)) /* is it free of monsters? */
+ if ((level!=1) || (x!=33) || (y!=MAXY-1)) /* not exit to level 1 */
+ return(1);
+ return(0);
+ }
+
+/*
+ * createitem(it,arg) Routine to place an item next to the player
+ * int it,arg;
+ *
+ * Enter with the item number and its argument (iven[], ivenarg[])
+ * Returns no value, thus we don't know about createitem() failures.
+ */
+createitem(it,arg)
+ int it,arg;
+ {
+ register int x,y,k,i;
+ if (it >= MAXOBJ) return; /* no such object */
+ for (k=rnd(8), i= -8; i<0; i++,k++) /* choose direction, then try all */
+ {
+ if (k>8) k=1; /* wraparound the diroff arrays */
+ x = playerx + diroffx[k]; y = playery + diroffy[k];
+ if (cgood(x,y,1,0)) /* if we can create here */
+ {
+ item[x][y] = it; know[x][y]=0; iarg[x][y]=arg; return;
+ }
+ }
+ }
+
+/*
+ * cast() Subroutine called by parse to cast a spell for the user
+ *
+ * No arguments and no return value.
+ */
+static char eys[] = "\nEnter your spell: ";
+cast()
+ {
+ register int i,j,a,b,d;
+ cursors();
+ if (c[SPELLS]<=0) { lprcat("\nYou don't have any spells!"); return; }
+ lprcat(eys); --c[SPELLS];
+ while ((a=getchar())=='D')
+ { seemagic(-1); cursors(); lprcat(eys); }
+ if (a=='\33') goto over; /* to escape casting a spell */
+ if ((b=getchar())=='\33') goto over; /* to escape casting a spell */
+ if ((d=getchar())=='\33')
+ { over: lprcat(aborted); c[SPELLS]++; return; } /* to escape casting a spell */
+#ifdef EXTRA
+ c[SPELLSCAST]++;
+#endif
+ for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
+ if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
+ if (spelknow[i])
+ { speldamage(i); j = 1; i=SPNUM; }
+
+ if (j == -1) lprcat(" Nothing Happened ");
+ bottomline();
+ }
+
+static int dirsub();
+
+/*
+ * speldamage(x) Function to perform spell functions cast by the player
+ * int x;
+ *
+ * Enter with the spell number, returns no value.
+ * Please insure that there are 2 spaces before all messages here
+ */
+speldamage(x)
+ int x;
+ {
+ register int i,j,clev;
+ int xl,xh,yl,yh;
+ register char *p,*kn,*pm;
+ if (x>=SPNUM) return; /* no such spell */
+ if (c[TIMESTOP]) { lprcat(" It didn't seem to work"); return; } /* not if time stopped */
+ clev = c[LEVEL];
+ if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
+ { lprcat(" It didn't work!"); return; }
+ if (clev*3+2 < x) { lprcat(" Nothing happens. You seem inexperienced at this"); return; }
+
+ switch(x)
+ {
+/* ----- LEVEL 1 SPELLS ----- */
+
+ case 0: if (c[PROTECTIONTIME]==0) c[MOREDEFENSES]+=2; /* protection field +2 */
+ c[PROTECTIONTIME] += 250; return;
+
+ case 1: i = rnd(((clev+1)<<1)) + clev + 3;
+ godirect(x,i,(clev>=2)?" Your missiles hit the %s":" Your missile hit the %s",100,'+'); /* magic missile */
+
+ return;
+
+ case 2: if (c[DEXCOUNT]==0) c[DEXTERITY]+=3; /* dexterity */
+ c[DEXCOUNT] += 400; return;
+
+ case 3: i=rnd(3)+1;
+ p=" While the %s slept, you smashed it %d times";
+ ws: direct(x,fullhit(i),p,i); /* sleep */ return;
+
+ case 4: /* charm monster */ c[CHARMCOUNT] += c[CHARISMA]<<1; return;
+
+ case 5: godirect(x,rnd(10)+15+clev," The sound damages the %s",70,'@'); /* sonic spear */
+ return;
+
+/* ----- LEVEL 2 SPELLS ----- */
+
+ case 6: i=rnd(3)+2; p=" While the %s is entangled, you hit %d times";
+ goto ws; /* web */
+
+ case 7: if (c[STRCOUNT]==0) c[STREXTRA]+=3; /* strength */
+ c[STRCOUNT] += 150+rnd(100); return;
+
+ case 8: yl = playery-5; /* enlightenment */
+ yh = playery+6; xl = playerx-15; xh = playerx+16;
+ vxy(&xl,&yl); vxy(&xh,&yh); /* check bounds */
+ for (i=yl; i<=yh; i++) /* enlightenment */
+ for (j=xl; j<=xh; j++) know[j][i]=1;
+ draws(xl,xh+1,yl,yh+1); return;
+
+ case 9: raisehp(20+(clev<<1)); return; /* healing */
+
+ case 10: c[BLINDCOUNT]=0; return; /* cure blindness */
+
+ case 11: createmonster(makemonst(level+1)+8); return;
+
+ case 12: if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev," The %s believed!",0);
+ else lprcat(" It didn't believe the illusions!");
+ return;
+
+ case 13: /* if he has the amulet of invisibility then add more time */
+ for (j=i=0; i<26; i++)
+ if (iven[i]==OAMULET) j+= 1+ivenarg[i];
+ c[INVISIBILITY] += (j<<7)+12; return;
+
+/* ----- LEVEL 3 SPELLS ----- */
+
+ case 14: godirect(x,rnd(25+clev)+25+clev," The fireball hits the %s",40,'*'); return; /* fireball */
+
+ case 15: godirect(x,rnd(25)+20+clev," Your cone of cold strikes the %s",60,'O'); /* cold */
+ return;
+
+ case 16: dirpoly(x); return; /* polymorph */
+
+ case 17: c[CANCELLATION]+= 5+clev; return; /* cancellation */
+
+ case 18: c[HASTESELF]+= 7+clev; return; /* haste self */
+
+ case 19: omnidirect(x,30+rnd(10)," The %s gasps for air"); /* cloud kill */
+ return;
+
+ case 20: xh = min(playerx+1,MAXX-2); yh = min(playery+1,MAXY-2);
+ for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
+ for (j=max(playery-1,1); j<=yh; j++)
+ {
+ kn = &know[i][j]; pm = &mitem[i][j];
+ switch(*(p= &item[i][j]))
+ {
+ case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
+ *p = *kn = 0;
+ break;
+
+ case OSTATUE: if (c[HARDGAME]<3)
+ {
+ *p=OBOOK; iarg[i][j]=level; *kn=0;
+ }
+ break;
+
+ case OTHRONE: *pm=GNOMEKING; *kn=0; *p= OTHRONE2;
+ hitp[i][j]=monster[GNOMEKING].hitpoints; break;
+
+ case OALTAR: *pm=DEMONPRINCE; *kn=0;
+ hitp[i][j]=monster[DEMONPRINCE].hitpoints; break;
+ };
+ switch(*pm)
+ {
+ case XORN: ifblind(i,j); hitm(i,j,200); break; /* Xorn takes damage from vpr */
+ }
+ }
+ return;
+
+/* ----- LEVEL 4 SPELLS ----- */
+
+ case 21: direct(x,100+clev," The %s shrivels up",0); /* dehydration */
+ return;
+
+ case 22: godirect(x,rnd(25)+20+(clev<<1)," A lightning bolt hits the %s",1,'~'); /* lightning */
+ return;
+
+ case 23: i=min(c[HP]-1,c[HPMAX]/2); /* drain life */
+ direct(x,i+i,"",0); c[HP] -= i; return;
+
+ case 24: if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
+ c[GLOBE] += 200; loseint(); /* globe of invulnerability */
+ return;
+
+ case 25: omnidirect(x,32+clev," The %s struggles for air in your flood!"); /* flood */
+ return;
+
+ case 26: if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000); died(270); return; }
+ if (c[WISDOM]>rnd(10)+10) direct(x,2000," The %s's heart stopped",0); /* finger of death */
+ else lprcat(" It didn't work"); return;
+
+/* ----- LEVEL 5 SPELLS ----- */
+
+ case 27: c[SCAREMONST] += rnd(10)+clev; return; /* scare monster */
+
+ case 28: c[HOLDMONST] += rnd(10)+clev; return; /* hold monster */
+
+ case 29: c[TIMESTOP] += rnd(20)+(clev<<1); return; /* time stop */
+
+ case 30: tdirect(x); return; /* teleport away */
+
+ case 31: omnidirect(x,35+rnd(10)+clev," The %s cringes from the flame"); /* magic fire */
+ return;
+
+/* ----- LEVEL 6 SPELLS ----- */
+
+ case 32: if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
+ {
+ beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
+ nap(4000); died(258); return;
+ }
+ xl=playerx; yl=playery;
+ loseint();
+ i=dirsub(&xl,&yl); /* get direction of sphere */
+ newsphere(xl,yl,i,rnd(20)+11); /* make a sphere */
+ return;
+
+ case 33: genmonst(); spelknow[33]=0; /* genocide */
+ loseint();
+ return;
+
+ case 34: /* summon demon */
+ if (rnd(100) > 30) { direct(x,150," The demon strikes at the %s",0); return; }
+ if (rnd(100) > 15) { lprcat(" Nothing seems to have happened"); return; }
+ lprcat(" The demon turned on you and vanished!"); beep();
+ i=rnd(40)+30; lastnum=277;
+ losehp(i); /* must say killed by a demon */ return;
+
+ case 35: /* walk through walls */
+ c[WTW] += rnd(10)+5; return;
+
+ case 36: /* alter reality */
+ {
+ struct isave *save; /* pointer to item save structure */
+ int sc; sc=0; /* # items saved */
+ save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
+ for (j=0; j<MAXY; j++)
+ for (i=0; i<MAXX; i++) /* save all items and monsters */
+ {
+ xl = item[i][j];
+ if (xl && xl!=OWALL && xl!=OANNIHILATION)
+ {
+ save[sc].type=0; save[sc].id=item[i][j];
+ save[sc++].arg=iarg[i][j];
+ }
+ if (mitem[i][j])
+ {
+ save[sc].type=1; save[sc].id=mitem[i][j];
+ save[sc++].arg=hitp[i][j];
+ }
+ item[i][j]=OWALL; mitem[i][j]=0;
+ if (wizard) know[i][j]=1; else know[i][j]=0;
+ }
+ eat(1,1); if (level==1) item[33][MAXY-1]=0;
+ for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
+ while (sc>0) /* put objects back in level */
+ {
+ --sc;
+ if (save[sc].type == 0)
+ {
+ int trys;
+ for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
+ if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
+ }
+ else
+ { /* put monsters back in */
+ int trys;
+ for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
+ if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
+ }
+ }
+ loseint();
+ draws(0,MAXX,0,MAXY); if (wizard==0) spelknow[36]=0;
+ free((char*)save); positionplayer(); return;
+ }
+
+ case 37: /* permanence */ adjtime(-99999L); spelknow[37]=0; /* forget */
+ loseint();
+ return;
+
+ default: lprintf(" spell %d not available!",(long)x); beep(); return;
+ };
+ }
+
+/*
+ * loseint() Routine to subtract 1 from your int (intelligence) if > 3
+ *
+ * No arguments and no return value
+ */
+loseint()
+ {
+ if (--c[INTELLIGENCE]<3) c[INTELLIGENCE]=3;
+ }
+
+/*
+ * isconfuse() Routine to check to see if player is confused
+ *
+ * This routine prints out a message saying "You can't aim your magic!"
+ * returns 0 if not confused, non-zero (time remaining confused) if confused
+ */
+isconfuse()
+ {
+ if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
+ return(c[CONFUSE]);
+ }
+
+/*
+ * nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
+ * int x,monst;
+ *
+ * Subroutine to return 1 if the spell can't affect the monster
+ * otherwise returns 0
+ * Enter with the spell number in x, and the monster number in monst.
+ */
+nospell(x,monst)
+ int x,monst;
+ {
+ register int tmp;
+ if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0); /* bad spell or monst */
+ if ((tmp=spelweird[monst-1][x])==0) return(0);
+ cursors(); lprc('\n'); lprintf(spelmes[tmp],monster[monst].name); return(1);
+ }
+
+/*
+ * fullhit(xx) Function to return full damage against a monster (aka web)
+ * int xx;
+ *
+ * Function to return hp damage to monster due to a number of full hits
+ * Enter with the number of full hits being done
+ */
+fullhit(xx)
+ int xx;
+ {
+ register int i;
+ if (xx<0 || xx>20) return(0); /* fullhits are out of range */
+ if (c[LANCEDEATH]) return(10000); /* lance of death */
+ i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]);
+ return( (i>=1) ? i : xx );
+ }
+
+/*
+ * direct(spnum,dam,str,arg) Routine to direct spell damage 1 square in 1 dir
+ * int spnum,dam,arg;
+ * char *str;
+ *
+ * Routine to ask for a direction to a spell and then hit the monster
+ * Enter with the spell number in spnum, the damage to be done in dam,
+ * lprintf format string in str, and lprintf's argument in arg.
+ * Returns no value.
+ */
+direct(spnum,dam,str,arg)
+ int spnum,dam,arg;
+ char *str;
+ {
+ int x,y;
+ register int m;
+ if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
+ if (isconfuse()) return;
+ dirsub(&x,&y);
+ m = mitem[x][y];
+ if (item[x][y]==OMIRROR)
+ {
+ if (spnum==3) /* sleep */
+ {
+ lprcat("You fall asleep! "); beep();
+ fool:
+ arg += 2;
+ while (arg-- > 0) { parse2(); nap(1000); }
+ return;
+ }
+ else if (spnum==6) /* web */
+ {
+ lprcat("You get stuck in your own web! "); beep();
+ goto fool;
+ }
+ else
+ {
+ lastnum=278;
+ lprintf(str,"spell caster (thats you)",(long)arg);
+ beep(); losehp(dam); return;
+ }
+ }
+ if (m==0)
+ { lprcat(" There wasn't anything there!"); return; }
+ ifblind(x,y);
+ if (nospell(spnum,m)) { lasthx=x; lasthy=y; return; }
+ lprintf(str,lastmonst,(long)arg); hitm(x,y,dam);
+ }
+
+/*
+ * godirect(spnum,dam,str,delay,cshow) Function to perform missile attacks
+ * int spnum,dam,delay;
+ * char *str,cshow;
+ *
+ * Function to hit in a direction from a missile weapon and have it keep
+ * on going in that direction until its power is exhausted
+ * Enter with the spell number in spnum, the power of the weapon in hp,
+ * lprintf format string in str, the # of milliseconds to delay between
+ * locations in delay, and the character to represent the weapon in cshow.
+ * Returns no value.
+ */
+godirect(spnum,dam,str,delay,cshow)
+ int spnum,dam,delay;
+ char *str,cshow;
+ {
+ register char *p;
+ register int x,y,m;
+ int dx,dy;
+ if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
+ if (isconfuse()) return;
+ dirsub(&dx,&dy); x=dx; y=dy;
+ dx = x-playerx; dy = y-playery; x = playerx; y = playery;
+ while (dam>0)
+ {
+ x += dx; y += dy;
+ if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
+ {
+ dam=0; break; /* out of bounds */
+ }
+ if ((x==playerx) && (y==playery)) /* if energy hits player */
+ {
+ cursors(); lprcat("\nYou are hit my your own magic!"); beep();
+ lastnum=278; losehp(dam); return;
+ }
+ if (c[BLINDCOUNT]==0) /* if not blind show effect */
+ {
+ cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
+ }
+ if ((m=mitem[x][y])) /* is there a monster there? */
+ {
+ ifblind(x,y);
+ if (nospell(spnum,m)) { lasthx=x; lasthy=y; return; }
+ cursors(); lprc('\n');
+ lprintf(str,lastmonst); dam -= hitm(x,y,dam);
+ show1cell(x,y); nap(1000); x -= dx; y -= dy;
+ }
+ else switch (*(p= &item[x][y]))
+ {
+ case OWALL: cursors(); lprc('\n'); lprintf(str,"wall");
+ if (dam>=50+c[HARDGAME]) /* enough damage? */
+ if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
+ if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
+ {
+ lprcat(" The wall crumbles");
+ god3: *p=0;
+ god: know[x][y]=0;
+ show1cell(x,y);
+ }
+ god2: dam = 0; break;
+
+ case OCLOSEDDOOR: cursors(); lprc('\n'); lprintf(str,"door");
+ if (dam>=40)
+ {
+ lprcat(" The door is blasted apart");
+ goto god3;
+ }
+ goto god2;
+
+ case OSTATUE: cursors(); lprc('\n'); lprintf(str,"statue");
+ if (c[HARDGAME]<3)
+ if (dam>44)
+ {
+ lprcat(" The statue crumbles");
+ *p=OBOOK; iarg[x][y]=level;
+ goto god;
+ }
+ goto god2;
+
+ case OTHRONE: cursors(); lprc('\n'); lprintf(str,"throne");
+ if (dam>39)
+ {
+ mitem[x][y]=GNOMEKING; hitp[x][y]=monster[GNOMEKING].hitpoints;
+ *p = OTHRONE2;
+ goto god;
+ }
+ goto god2;
+
+ case OMIRROR: dx *= -1; dy *= -1; break;
+ };
+ dam -= 3 + (c[HARDGAME]>>1);
+ }
+ }
+
+/*
+ * ifblind(x,y) Routine to put "monster" or the monster name into lastmosnt
+ * int x,y;
+ *
+ * Subroutine to copy the word "monster" into lastmonst if the player is blind
+ * Enter with the coordinates (x,y) of the monster
+ * Returns no value.
+ */
+ifblind(x,y)
+ int x,y;
+ {
+ char *p;
+ vxy(&x,&y); /* verify correct x,y coordinates */
+ if (c[BLINDCOUNT]) { lastnum=279; p="monster"; }
+ else { lastnum=mitem[x][y]; p=monster[lastnum].name; }
+ strcpy(lastmonst,p);
+ }
+
+/*
+ * tdirect(spnum) Routine to teleport away a monster
+ * int spnum;
+ *
+ * Routine to ask for a direction to a spell and then teleport away monster
+ * Enter with the spell number that wants to teleport away
+ * Returns no value.
+ */
+tdirect(spnum)
+ int spnum;
+ {
+ int x,y;
+ register int m;
+ if (spnum<0 || spnum>=SPNUM) return; /* bad args */
+ if (isconfuse()) return;
+ dirsub(&x,&y);
+ if ((m=mitem[x][y])==0)
+ { lprcat(" There wasn't anything there!"); return; }
+ ifblind(x,y);
+ if (nospell(spnum,m)) { lasthx=x; lasthy=y; return; }
+ fillmonst(m); mitem[x][y]=know[x][y]=0;
+ }
+
+/*
+ * omnidirect(sp,dam,str) Routine to damage all monsters 1 square from player
+ * int sp,dam;
+ * char *str;
+ *
+ * Routine to cast a spell and then hit the monster in all directions
+ * Enter with the spell number in sp, the damage done to wach square in dam,
+ * and the lprintf string to identify the spell in str.
+ * Returns no value.
+ */
+omnidirect(spnum,dam,str)
+ int spnum,dam;
+ char *str;
+ {
+ register int x,y,m;
+ if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
+ for (x=playerx-1; x<playerx+2; x++)
+ for (y=playery-1; y<playery+2; y++)
+ {
+ if (m=mitem[x][y])
+ if (nospell(spnum,m) == 0)
+ {
+ ifblind(x,y);
+ cursors(); lprc('\n'); lprintf(str,lastmonst);
+ hitm(x,y,dam); nap(800);
+ }
+ else { lasthx=x; lasthy=y; }
+ }
+ }
+
+/*
+ * static dirsub(x,y) Routine to ask for direction, then modify x,y for it
+ * int *x,*y;
+ *
+ * Function to ask for a direction and modify an x,y for that direction
+ * Enter with the origination coordinates in (x,y).
+ * Returns index into diroffx[] (0-8).
+ */
+static int
+dirsub(x,y)
+ int *x,*y;
+ {
+ register int i;
+ lprcat("\nIn What Direction? ");
+ for (i=0; ; )
+ switch(getchar())
+ {
+ case 'b': i++;
+ case 'n': i++;
+ case 'y': i++;
+ case 'u': i++;
+ case 'h': i++;
+ case 'k': i++;
+ case 'l': i++;
+ case 'j': i++; goto out;
+ };
+out:
+ *x = playerx+diroffx[i]; *y = playery+diroffy[i];
+ vxy(x,y); return(i);
+ }
+
+/*
+ * vxy(x,y) Routine to verify/fix coordinates for being within bounds
+ * int *x,*y;
+ *
+ * Function to verify x & y are within the bounds for a level
+ * If *x or *y is not within the absolute bounds for a level, fix them so that
+ * they are on the level.
+ * Returns TRUE if it was out of bounds, and the *x & *y in the calling
+ * routine are affected.
+ */
+vxy(x,y)
+ int *x,*y;
+ {
+ int flag=0;
+ if (*x<0) { *x=0; flag++; }
+ if (*y<0) { *y=0; flag++; }
+ if (*x>=MAXX) { *x=MAXX-1; flag++; }
+ if (*y>=MAXY) { *y=MAXY-1; flag++; }
+ return(flag);
+ }
+
+/*
+ * dirpoly(spnum) Routine to ask for a direction and polymorph a monst
+ * int spnum;
+ *
+ * Subroutine to polymorph a monster and ask for the direction its in
+ * Enter with the spell number in spmun.
+ * Returns no value.
+ */
+dirpoly(spnum)
+ int spnum;
+ {
+ int x,y,m;
+ if (spnum<0 || spnum>=SPNUM) return; /* bad args */
+ if (isconfuse()) return; /* if he is confused, he can't aim his magic */
+ dirsub(&x,&y);
+ if (mitem[x][y]==0)
+ { lprcat(" There wasn't anything there!"); return; }
+ ifblind(x,y);
+ if (nospell(spnum,mitem[x][y])) { lasthx=x; lasthy=y; return; }
+ while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
+ hitp[x][y] = monster[m].hitpoints;
+ show1cell(x,y); /* show the new monster */
+ }
+
+/*
+ * hitmonster(x,y) Function to hit a monster at the designated coordinates
+ * int x,y;
+ *
+ * This routine is used for a bash & slash type attack on a monster
+ * Enter with the coordinates of the monster in (x,y).
+ * Returns no value.
+ */
+hitmonster(x,y)
+ int x,y;
+ {
+ register int tmp,monst,damag,flag;
+ if (c[TIMESTOP]) return; /* not if time stopped */
+ vxy(&x,&y); /* verify coordinates are within range */
+ if ((monst = mitem[x][y]) == 0) return;
+ hit3flag=1; ifblind(x,y);
+ tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS]/4 - 12;
+ cursors();
+ if ((rnd(20) < tmp-c[HARDGAME]) || (rnd(71) < 5)) /* need at least random chance to hit */
+ {
+ lprcat("\nYou hit"); flag=1;
+ damag = fullhit(1);
+ if (damag<9999) damag=rnd(damag)+1;
+ }
+ else
+ {
+ lprcat("\nYou missed"); flag=0;
+ }
+ lprcat(" the "); lprcat(lastmonst);
+ if (flag) /* if the monster was hit */
+ if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
+ if (c[WIELD]>0)
+ if (ivenarg[c[WIELD]] > -10)
+ {
+ lprintf("\nYour weapon is dulled by the %s",lastmonst); beep();
+ --ivenarg[c[WIELD]];
+ }
+ if (flag) hitm(x,y,damag);
+ if (monst == VAMPIRE) if (hitp[x][y]<25) { mitem[x][y]=BAT; know[x][y]=0; }
+ }
+
+/*
+ * hitm(x,y,amt) Function to just hit a monster at a given coordinates
+ * int x,y,amt;
+ *
+ * Returns the number of hitpoints the monster absorbed
+ * This routine is used to specifically damage a monster at a location (x,y)
+ * Called by hitmonster(x,y)
+ */
+hitm(x,y,amt)
+ int x,y;
+ register amt;
+ {
+ register int monst;
+ int hpoints,amt2;
+ vxy(&x,&y); /* verify coordinates are within range */
+ amt2 = amt; /* save initial damage so we can return it */
+ monst = mitem[x][y];
+ if (c[HALFDAM]) amt >>= 1; /* if half damage curse adjust damage points */
+ if (amt<=0) amt2 = amt = 1;
+ lasthx=x; lasthy=y;
+ stealth[x][y]=1; /* make sure hitting monst breaks stealth condition */
+ c[HOLDMONST]=0; /* hit a monster breaks hold monster spell */
+ switch(monst) /* if a dragon and orb(s) of dragon slaying */
+ {
+ case WHITEDRAGON: case REDDRAGON: case GREENDRAGON:
+ case BRONZEDRAGON: case PLATINUMDRAGON: case SILVERDRAGON:
+ amt *= 1+(c[SLAYING]<<1); break;
+ }
+/* invincible monster fix is here */
+ if (hitp[x][y] > monster[monst].hitpoints)
+ hitp[x][y] = monster[monst].hitpoints;
+ if ((hpoints = hitp[x][y]) <= amt)
+ {
+#ifdef EXTRA
+ c[MONSTKILLED]++;
+#endif
+ lprintf("\nThe %s died!",lastmonst);
+ raiseexperience((long)monster[monst].experience);
+ amt = monster[monst].gold; if (amt>0) dropgold(rnd(amt)+amt);
+ dropsomething(monst); disappear(x,y); bottomline();
+ return(hpoints);
+ }
+ hitp[x][y] = hpoints-amt; return(amt2);
+ }
+
+/*
+ * hitplayer(x,y) Function for the monster to hit the player from (x,y)
+ * int x,y;
+ *
+ * Function for the monster to hit the player with monster at location x,y
+ * Returns nothing of value.
+ */
+hitplayer(x,y)
+ int x,y;
+ {
+ register int dam,tmp,mster,bias;
+ vxy(&x,&y); /* verify coordinates are within range */
+ lastnum = mster = mitem[x][y];
+/* spirit naga's and poltergeist's do nothing if scarab of negate spirit */
+ if (c[NEGATESPIRIT] || c[SPIRITPRO]) if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA)) return;
+/* if undead and cube of undead control */
+ if (c[CUBEofUNDEAD] || c[UNDEADPRO]) if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) return;
+ if ((know[x][y]&1) == 0)
+ {
+ know[x][y]=1; show1cell(x,y);
+ }
+ bias = (c[HARDGAME]) + 1;
+ hitflag = hit2flag = hit3flag = 1;
+ yrepcount=0;
+ cursors(); ifblind(x,y);
+ if (c[INVISIBILITY]) if (rnd(33)<20)
+ {
+ lprintf("\nThe %s misses wildly",lastmonst); return;
+ }
+ if (c[CHARMCOUNT]) if (rnd(30)+5*monster[mster].level-c[CHARISMA]<30)
+ {
+ lprintf("\nThe %s is awestruck at your magnificence!",lastmonst);
+ return;
+ }
+ if (mster==BAT) dam=1;
+ else
+ {
+ dam = monster[mster].damage;
+ dam += rnd((int)((dam<1)?1:dam)) + monster[mster].level;
+ }
+ tmp = 0;
+ if (monster[mster].attack>0)
+ if (((dam + bias + 8) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
+ { if (spattack(monster[mster].attack,x,y)) { flushall(); return; }
+ tmp = 1; bias -= 2; cursors(); }
+ if (((dam + bias) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
+ {
+ lprintf("\n The %s hit you ",lastmonst); tmp = 1;
+ if ((dam -= c[AC]) < 0) dam=0;
+ if (dam > 0) { losehp(dam); bottomhp(); flushall(); }
+ }
+ if (tmp == 0) lprintf("\n The %s missed ",lastmonst);
+ }
+
+/*
+ * dropsomething(monst) Function to create an object when a monster dies
+ * int monst;
+ *
+ * Function to create an object near the player when certain monsters are killed
+ * Enter with the monster number
+ * Returns nothing of value.
+ */
+dropsomething(monst)
+ int monst;
+ {
+ switch(monst)
+ {
+ case ORC: case NYMPH: case ELF: case TROGLODYTE:
+ case TROLL: case ROTHE: case VIOLETFUNGI:
+ case PLATINUMDRAGON: case GNOMEKING: case REDDRAGON:
+ something(level); return;
+
+ case LEPRECHAUN: if (rnd(101)>=75) creategem();
+ if (rnd(5)==1) dropsomething(LEPRECHAUN); return;
+ }
+ }
+
+/*
+ * dropgold(amount) Function to drop some gold around player
+ * int amount;
+ *
+ * Enter with the number of gold pieces to drop
+ * Returns nothing of value.
+ */
+dropgold(amount)
+ register int amount;
+ {
+ if (amount > 250) createitem(OMAXGOLD,amount/100); else createitem(OGOLDPILE,amount);
+ }
+
+/*
+ * something(level) Function to create a random item around player
+ * int level;
+ *
+ * Function to create an item from a designed probability around player
+ * Enter with the cave level on which something is to be dropped
+ * Returns nothing of value.
+ */
+something(level)
+ int level;
+ {
+ register int j;
+ int i;
+ if (level<0 || level>MAXLEVEL+MAXVLEVEL) return; /* correct level? */
+ if (rnd(101)<8) something(level); /* possibly more than one item */
+ j = newobject(level,&i); createitem(j,i);
+ }
+
+/*
+ * newobject(lev,i) Routine to return a randomly selected new object
+ * int lev,*i;
+ *
+ * Routine to return a randomly selected object to be created
+ * Returns the object number created, and sets *i for its argument
+ * Enter with the cave level and a pointer to the items arg
+ */
+static char nobjtab[] = { 0, OSCROLL, OSCROLL, OSCROLL, OSCROLL, OPOTION,
+ OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE,
+ OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, OLEATHER, OLEATHER,
+ OLEATHER, OREGENRING, OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR,
+ OBELT, ORING, OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
+ OLONGSWORD };
+
+newobject(lev,i)
+ register int lev,*i;
+ {
+ register int tmp=32,j;
+ if (level<0 || level>MAXLEVEL+MAXVLEVEL) return(0); /* correct level? */
+ if (lev>6) tmp=37; else if (lev>4) tmp=35;
+ j = nobjtab[tmp=rnd(tmp)]; /* the object type */
+ switch(tmp)
+ {
+ case 1: case 2: case 3: case 4: *i=newscroll(); break;
+ case 5: case 6: case 7: case 8: *i=newpotion(); break;
+ case 9: case 10: case 11: case 12: *i=rnd((lev+1)*10)+lev*10+10; break;
+ case 13: case 14: case 15: case 16: *i=lev; break;
+ case 17: case 18: case 19: if (!(*i=newdagger())) return(0); break;
+ case 20: case 21: case 22: if (!(*i=newleather())) return(0); break;
+ case 23: case 32: case 35: *i=rund(lev/3+1); break;
+ case 24: case 26: *i=rnd(lev/4+1); break;
+ case 25: *i=rund(lev/4+1); break;
+ case 27: *i=rnd(lev/2+1); break;
+ case 30: case 33: *i=rund(lev/2+1); break;
+ case 28: *i=rund(lev/3+1); if (*i==0) return(0); break;
+ case 29: case 31: *i=rund(lev/2+1); if (*i==0) return(0); break;
+ case 34: *i=newchain(); break;
+ case 36: *i=newplate(); break;
+ case 37: *i=newsword(); break;
+ }
+ return(j);
+ }
+
+/*
+ * spattack(atckno,xx,yy) Function to process special attacks from monsters
+ * int atckno,xx,yy;
+ *
+ * Enter with the special attack number, and the coordinates (xx,yy)
+ * of the monster that is special attacking
+ * Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
+ *
+ * atckno monster effect
+ * ---------------------------------------------------
+ * 0 none
+ * 1 rust monster eat armor
+ * 2 hell hound breathe light fire
+ * 3 dragon breathe fire
+ * 4 giant centipede weakening sing
+ * 5 white dragon cold breath
+ * 6 wraith drain level
+ * 7 waterlord water gusher
+ * 8 leprechaun steal gold
+ * 9 disenchantress disenchant weapon or armor
+ * 10 ice lizard hits with barbed tail
+ * 11 umber hulk confusion
+ * 12 spirit naga cast spells taken from special attacks
+ * 13 platinum dragon psionics
+ * 14 nymph steal objects
+ * 15 bugbear bite
+ * 16 osequip bite
+ *
+ * char rustarm[ARMORTYPES][2];
+ * special array for maximum rust damage to armor from rustmonster
+ * format is: { armor type , minimum attribute
+ */
+#define ARMORTYPES 6
+static char rustarm[ARMORTYPES][2] = { OSTUDLEATHER,-2, ORING,-4, OCHAIN,-5,
+ OSPLINT,-6, OPLATE,-8, OPLATEARMOR,-9 };
+static char spsel[] = { 1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
+spattack(x,xx,yy)
+ int x,xx,yy;
+ {
+ register int i,j=0,k,m;
+ register char *p=0;
+ if (c[CANCELLATION]) return(0);
+ vxy(&xx,&yy); /* verify x & y coordinates */
+ switch(x)
+ {
+ case 1: /* rust your armor, j=1 when rusting has occurred */
+ m = k = c[WEAR];
+ if ((i=c[SHIELD]) != -1)
+ if (--ivenarg[i] < -1) ivenarg[i]= -1; else j=1;
+ if ((j==0) && (k != -1))
+ {
+ m = iven[k];
+ for (i=0; i<ARMORTYPES; i++)
+ if (m == rustarm[i][0]) /* find his armor in table */
+ {
+ if (--ivenarg[k]< rustarm[i][1])
+ ivenarg[k]= rustarm[i][1]; else j=1;
+ break;
+ }
+ }
+ if (j==0) /* if rusting did not occur */
+ switch(m)
+ {
+ case OLEATHER: p = "\nThe %s hit you -- Your lucky you have leather on";
+ break;
+ case OSSPLATE: p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
+ break;
+ }
+ else { beep(); p = "\nThe %s hit you -- your armor feels weaker"; }
+ break;
+
+ case 2: i = rnd(15)+8-c[AC];
+ spout: p="\nThe %s breathes fire at you!";
+ if (c[FIRERESISTANCE])
+ p="\nThe %s's flame doesn't phase you!";
+ else
+ spout2: if (p) { lprintf(p,lastmonst); beep(); }
+ checkloss(i);
+ return(0);
+
+ case 3: i = rnd(20)+25-c[AC]; goto spout;
+
+ case 4: if (c[STRENGTH]>3)
+ {
+ p="\nThe %s stung you! You feel weaker"; beep();
+ --c[STRENGTH];
+ }
+ else p="\nThe %s stung you!";
+ break;
+
+ case 5: p="\nThe %s blasts you with his cold breath";
+ i = rnd(15)+18-c[AC]; goto spout2;
+
+ case 6: lprintf("\nThe %s drains you of your life energy!",lastmonst);
+ loselevel(); beep(); return(0);
+
+ case 7: p="\nThe %s got you with a gusher!";
+ i = rnd(15)+25-c[AC]; goto spout2;
+
+ case 8: if (c[NOTHEFT]) return(0); /* he has a device of no theft */
+ if (c[GOLD])
+ {
+ p="\nThe %s hit you -- Your purse feels lighter";
+ if (c[GOLD]>32767) c[GOLD]>>=1;
+ else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
+ if (c[GOLD] < 0) c[GOLD]=0;
+ }
+ else p="\nThe %s couldn't find any gold to steal";
+ lprintf(p,lastmonst); disappear(xx,yy); beep();
+ bottomgold(); return(1);
+
+ case 9: for(j=50; ; ) /* disenchant */
+ {
+ i=rund(26); m=iven[i]; /* randomly select item */
+ if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
+ {
+ if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
+ lprintf("\nThe %s hits you -- you feel a sense of loss",lastmonst);
+ srcount=0; beep(); show3(i); bottomline(); return(0);
+ }
+ if (--j<=0)
+ {
+ p="\nThe %s nearly misses"; break;
+ }
+ break;
+ }
+ break;
+
+ case 10: p="\nThe %s hit you with his barbed tail";
+ i = rnd(25)-c[AC]; goto spout2;
+
+ case 11: p="\nThe %s has confused you"; beep();
+ c[CONFUSE]+= 10+rnd(10); break;
+
+ case 12: /* performs any number of other special attacks */
+ return(spattack(spsel[rund(10)],xx,yy));
+
+ case 13: p="\nThe %s flattens you with his psionics!";
+ i = rnd(15)+30-c[AC]; goto spout2;
+
+ case 14: if (c[NOTHEFT]) return(0); /* he has device of no theft */
+ if (emptyhanded()==1)
+ {
+ p="\nThe %s couldn't find anything to steal";
+ break;
+ }
+ lprintf("\nThe %s picks your pocket and takes:",lastmonst);
+ beep();
+ if (stealsomething()==0) lprcat(" nothing"); disappear(xx,yy);
+ bottomline(); return(1);
+
+ case 15: i= rnd(10)+ 5-c[AC];
+ spout3: p="\nThe %s bit you!";
+ goto spout2;
+
+ case 16: i= rnd(15)+10-c[AC]; goto spout3;
+ };
+ if (p) { lprintf(p,lastmonst); bottomline(); }
+ return(0);
+ }
+
+/*
+ * checkloss(x) Routine to subtract hp from user and flag bottomline display
+ * int x;
+ *
+ * Routine to subtract hitpoints from the user and flag the bottomline display
+ * Enter with the number of hit points to lose
+ * Note: if x > c[HP] this routine could kill the player!
+ */
+checkloss(x)
+ int x;
+ {
+ if (x>0) { losehp(x); bottomhp(); }
+ }
+
+/*
+ * annihilate() Routine to annihilate all monsters around player (playerx,playery)
+ *
+ * Gives player experience, but no dropped objects
+ * Returns the experience gained from all monsters killed
+ */
+annihilate()
+ {
+ int i,j;
+ register long k;
+ register char *p;
+ for (k=0, i=playerx-1; i<=playerx+1; i++)
+ for (j=playery-1; j<=playery+1; j++)
+ if (!vxy(&i,&j)) /* if not out of bounds */
+ if (*(p= &mitem[i][j])) /* if a monster there */
+ if (*p<DEMONLORD+2)
+ {
+ k += monster[*p].experience; *p=know[i][j]=0;
+ }
+ else
+ {
+ lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
+ hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
+ }
+ if (k>0)
+ {
+ lprcat("\nYou hear loud screams of agony!"); raiseexperience((long)k);
+ }
+ return(k);
+ }
+
+/*
+ * newsphere(x,y,dir,lifetime) Function to create a new sphere of annihilation
+ * int x,y,dir,lifetime;
+ *
+ * Enter with the coordinates of the sphere in x,y
+ * the direction (0-8 diroffx format) in dir, and the lifespan of the
+ * sphere in lifetime (in turns)
+ * Returns the number of spheres currently in existence
+ */
+newsphere(x,y,dir,life)
+ int x,y,dir,life;
+ {
+ int m;
+ struct sphere *sp;
+ if (((sp=(struct sphere *)malloc(sizeof(struct sphere)))) == 0)
+ return(c[SPHCAST]); /* can't malloc, therefore failure */
+ if (dir>=9) dir=0; /* no movement if direction not found */
+ if (level==0) vxy(&x,&y); /* don't go out of bounds */
+ else
+ {
+ if (x<1) x=1; if (x>=MAXX-1) x=MAXX-2;
+ if (y<1) y=1; if (y>=MAXY-1) y=MAXY-2;
+ }
+ if ((m=mitem[x][y]) >= DEMONLORD+4) /* demons dispel spheres */
+ {
+ know[x][y]=1; show1cell(x,y); /* show the demon (ha ha) */
+ cursors(); lprintf("\nThe %s dispels the sphere!",monster[m].name);
+ beep(); rmsphere(x,y); /* remove any spheres that are here */
+ return(c[SPHCAST]);
+ }
+ if (m==DISENCHANTRESS) /* disenchantress cancels spheres */
+ {
+ cursors(); lprintf("\nThe %s causes cancellation of the sphere!",monster[m].name); beep();
+boom: sphboom(x,y); /* blow up stuff around sphere */
+ rmsphere(x,y); /* remove any spheres that are here */
+ return(c[SPHCAST]);
+ }
+ if (c[CANCELLATION]) /* cancellation cancels spheres */
+ {
+ cursors(); lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); beep();
+ goto boom;
+ }
+ if (item[x][y]==OANNIHILATION) /* collision of spheres detonates spheres */
+ {
+ cursors(); lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); beep();
+ rmsphere(x,y);
+ goto boom;
+ }
+ if (playerx==x && playery==y) /* collision of sphere and player! */
+ {
+ cursors();
+ lprcat("\nYou have been enveloped by the zone of nothingness!\n");
+ beep(); rmsphere(x,y); /* remove any spheres that are here */
+ nap(4000); died(258);
+ }
+ item[x][y]=OANNIHILATION; mitem[x][y]=0; know[x][y]=1;
+ show1cell(x,y); /* show the new sphere */
+ sp->x=x; sp->y=y; sp->lev=level; sp->dir=dir; sp->lifetime=life; sp->p=0;
+ if (spheres==0) spheres=sp; /* if first node in the sphere list */
+ else /* add sphere to beginning of linked list */
+ {
+ sp->p = spheres; spheres = sp;
+ }
+ return(++c[SPHCAST]); /* one more sphere in the world */
+ }
+
+/*
+ * rmsphere(x,y) Function to delete a sphere of annihilation from list
+ * int x,y;
+ *
+ * Enter with the coordinates of the sphere (on current level)
+ * Returns the number of spheres currently in existence
+ */
+rmsphere(x,y)
+ int x,y;
+ {
+ register struct sphere *sp,*sp2=0;
+ for (sp=spheres; sp; sp2=sp,sp=sp->p)
+ if (level==sp->lev) /* is sphere on this level? */
+ if ((x==sp->x) && (y==sp->y)) /* locate sphere at this location */
+ {
+ item[x][y]=mitem[x][y]=0; know[x][y]=1;
+ show1cell(x,y); /* show the now missing sphere */
+ --c[SPHCAST];
+ if (sp==spheres) { sp2=sp; spheres=sp->p; free((char*)sp2); }
+ else
+ { sp2->p = sp->p; free((char*)sp); }
+ break;
+ }
+ return(c[SPHCAST]); /* return number of spheres in the world */
+ }
+
+/*
+ * sphboom(x,y) Function to perform the effects of a sphere detonation
+ * int x,y;
+ *
+ * Enter with the coordinates of the blast, Returns no value
+ */
+sphboom(x,y)
+ int x,y;
+ {
+ register int i,j;
+ if (c[HOLDMONST]) c[HOLDMONST]=1;
+ if (c[CANCELLATION]) c[CANCELLATION]=1;
+ for (j=max(1,x-2); j<min(x+3,MAXX-1); j++)
+ for (i=max(1,y-2); i<min(y+3,MAXY-1); i++)
+ {
+ item[j][i]=mitem[j][i]=0;
+ show1cell(j,i);
+ if (playerx==j && playery==i)
+ {
+ cursors(); beep();
+ lprcat("\nYou were too close to the sphere!");
+ nap(3000);
+ died(283); /* player killed in explosion */
+ }
+ }
+ }
+
+/*
+ * genmonst() Function to ask for monster and genocide from game
+ *
+ * This is done by setting a flag in the monster[] structure
+ */
+genmonst()
+ {
+ register int i,j;
+ cursors(); lprcat("\nGenocide what monster? ");
+ for (i=0; (!isalpha(i)) && (i!=' '); i=getchar());
+ lprc(i);
+ for (j=0; j<MAXMONST; j++) /* search for the monster type */
+ if (monstnamelist[j]==i) /* have we found it? */
+ {
+ monster[j].genocided=1; /* genocided from game */
+ lprintf(" There will be no more %s's",monster[j].name);
+ /* now wipe out monsters on this level */
+ newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
+ return;
+ }
+ lprcat(" You sense failure!");
+ }
+
diff --git a/games/larn/moreobj.c b/games/larn/moreobj.c
new file mode 100644
index 0000000..f834b1a
--- /dev/null
+++ b/games/larn/moreobj.c
@@ -0,0 +1,372 @@
+/* moreobj.c Larn is copyrighted 1986 by Noah Morgan.
+ *
+ * Routines in this file:
+ *
+ * oaltar()
+ * othrone()
+ * ochest()
+ * ofountain()
+ */
+#include "header.h"
+
+static void ohear();
+
+/*
+ * ******
+ * OALTAR
+ * ******
+ *
+ * subroutine to process an altar object
+ */
+oaltar()
+ {
+ unsigned long k;
+
+ lprcat("\nDo you (p) pray (d) desecrate"); iopts();
+ while (1)
+ {
+ while (1) switch(getchar())
+ {
+ case 'p': lprcat(" pray\nDo you (m) give money or (j) just pray? ");
+ while (1) switch(getchar())
+ {
+ case 'j': if (rnd(100)<75)
+ lprcat("\nnothing happens");
+ else if (rnd(13)<4) ohear();
+ else if (rnd(43) == 10)
+ {
+ if (c[WEAR]) lprcat("\nYou feel your armor vibrate for a moment");
+ enchantarmor(); return;
+ }
+ else if (rnd(43) == 10)
+ {
+ if (c[WIELD]) lprcat("\nYou feel your weapon vibrate for a moment");
+ enchweapon(); return;
+ }
+ else createmonster(makemonst(level+1));
+ return;
+
+ case 'm': lprcat("\n\n"); cursor(1,24); cltoeoln();
+ cursor(1,23); cltoeoln();
+ lprcat("how much do you donate? ");
+ k = readnum((long)c[GOLD]);
+ if (c[GOLD]<k)
+ {
+ lprcat("\nYou don't have that much!");
+ return;
+ }
+ c[GOLD] -= k;
+ if (k < c[GOLD]/10 || k<rnd(50))
+ { createmonster(makemonst(level+1)); c[AGGRAVATE] += 200; }
+ else if (rnd(101) > 50) { ohear(); return; }
+ else if (rnd(43) == 5)
+ {
+ if (c[WEAR]) lprcat("\nYou feel your armor vibrate for a moment");
+ enchantarmor(); return;
+ }
+ else if (rnd(43) == 8)
+ {
+ if (c[WIELD]) lprcat("\nYou feel your weapon vibrate for a moment");
+ enchweapon(); return;
+ }
+ else lprcat("\nThank You.");
+ bottomline(); return;
+
+ case '\33': return;
+ };
+
+ case 'd': lprcat(" desecrate");
+ if (rnd(100)<60)
+ { createmonster(makemonst(level+2)+8); c[AGGRAVATE] += 2500; }
+ else
+ if (rnd(101)<30)
+ {
+ lprcat("\nThe altar crumbles into a pile of dust before your eyes");
+ forget(); /* remember to destroy the altar */
+ }
+ else
+ lprcat("\nnothing happens");
+ return;
+
+ case 'i':
+ case '\33': ignore();
+ if (rnd(100)<30) { createmonster(makemonst(level+1)); c[AGGRAVATE] += rnd(450); }
+ else lprcat("\nnothing happens");
+ return;
+ };
+ }
+ }
+
+/*
+ function to cast a +3 protection on the player
+ */
+static void
+ohear()
+ {
+ lprcat("\nYou have been heard!");
+ if (c[ALTPRO]==0) c[MOREDEFENSES]+=3;
+ c[ALTPRO] += 500; /* protection field */
+ bottomline();
+ }
+
+/*
+ *******
+ OTHRONE
+ *******
+
+ subroutine to process a throne object
+ */
+othrone(arg)
+ int arg;
+ {
+ register int i,k;
+
+ lprcat("\nDo you (p) pry off jewels, (s) sit down"); iopts();
+ while (1)
+ {
+ while (1) switch(getchar())
+ {
+ case 'p': lprcat(" pry off"); k=rnd(101);
+ if (k<25)
+ {
+ for (i=0; i<rnd(4); i++) creategem(); /* gems pop off the throne */
+ item[playerx][playery]=ODEADTHRONE;
+ know[playerx][playery]=0;
+ }
+ else if (k<40 && arg==0)
+ {
+ createmonster(GNOMEKING);
+ item[playerx][playery]=OTHRONE2;
+ know[playerx][playery]=0;
+ }
+ else lprcat("\nnothing happens");
+ return;
+
+ case 's': lprcat(" sit down"); k=rnd(101);
+ if (k<30 && arg==0)
+ {
+ createmonster(GNOMEKING);
+ item[playerx][playery]=OTHRONE2;
+ know[playerx][playery]=0;
+ }
+ else if (k<35) { lprcat("\nZaaaappp! You've been teleported!\n"); beep(); oteleport(0); }
+ else lprcat("\nnothing happens");
+ return;
+
+ case 'i':
+ case '\33': ignore(); return;
+ };
+ }
+ }
+
+odeadthrone()
+ {
+ register int k;
+
+ lprcat("\nDo you (s) sit down"); iopts();
+ while (1)
+ {
+ while (1) switch(getchar())
+ {
+ case 's': lprcat(" sit down"); k=rnd(101);
+ if (k<35) { lprcat("\nZaaaappp! You've been teleported!\n"); beep(); oteleport(0); }
+ else lprcat("\nnothing happens");
+ return;
+
+ case 'i':
+ case '\33': ignore(); return;
+ };
+ }
+ }
+
+/*
+ ******
+ OCHEST
+ ******
+
+ subroutine to process a throne object
+ */
+ochest()
+ {
+ register int i,k;
+ lprcat("\nDo you (t) take it, (o) try to open it"); iopts();
+ while (1)
+ {
+ while (1) switch(getchar())
+ {
+ case 'o': lprcat(" open it"); k=rnd(101);
+ if (k<40)
+ {
+ lprcat("\nThe chest explodes as you open it"); beep();
+ i = rnd(10); lastnum=281; /* in case he dies */
+ lprintf("\nYou suffer %d hit points damage!",(long)i);
+ checkloss(i);
+ switch(rnd(10)) /* see if he gets a curse */
+ {
+ case 1: c[ITCHING]+= rnd(1000)+100;
+ lprcat("\nYou feel an irritation spread over your skin!");
+ beep();
+ break;
+
+ case 2: c[CLUMSINESS]+= rnd(1600)+200;
+ lprcat("\nYou begin to lose hand to eye coordination!");
+ beep();
+ break;
+
+ case 3: c[HALFDAM]+= rnd(1600)+200;
+ beep();
+ lprcat("\nA sickness engulfs you!"); break;
+ };
+ item[playerx][playery]=know[playerx][playery]=0;
+ if (rnd(100)<69) creategem(); /* gems from the chest */
+ dropgold(rnd(110*iarg[playerx][playery]+200));
+ for (i=0; i<rnd(4); i++) something(iarg[playerx][playery]+2);
+ }
+ else lprcat("\nnothing happens");
+ return;
+
+ case 't': lprcat(" take");
+ if (take(OCHEST,iarg[playerx][playery])==0)
+ item[playerx][playery]=know[playerx][playery]=0;
+ return;
+
+ case 'i':
+ case '\33': ignore(); return;
+ };
+ }
+ }
+
+/*
+ *********
+ OFOUNTAIN
+ *********
+ */
+
+ofountain()
+ {
+ register int x;
+ cursors();
+ lprcat("\nDo you (d) drink, (w) wash yourself"); iopts();
+ while (1) switch(getchar())
+ {
+ case 'd': lprcat("drink");
+ if (rnd(1501)<2)
+ {
+ lprcat("\nOops! You seem to have caught the dreadful sleep!");
+ beep(); lflush(); sleep(3); died(280); return;
+ }
+ x = rnd(100);
+ if (x<7)
+ {
+ c[HALFDAM] += 200+rnd(200);
+ lprcat("\nYou feel a sickness coming on");
+ }
+ else if (x<13) quaffpotion(23); /* see invisible */
+ else if (x < 45)
+ lprcat("\nnothing seems to have happened");
+ else if (rnd(3) != 2)
+ fntchange(1); /* change char levels upward */
+ else
+ fntchange(-1); /* change char levels downward */
+ if (rnd(12)<3)
+ {
+ lprcat("\nThe fountains bubbling slowly quiets");
+ item[playerx][playery]=ODEADFOUNTAIN; /* dead fountain */
+ know[playerx][playery]=0;
+ }
+ return;
+
+ case '\33':
+ case 'i': ignore(); return;
+
+ case 'w': lprcat("wash yourself");
+ if (rnd(100) < 11)
+ {
+ x=rnd((level<<2)+2);
+ lprintf("\nOh no! The water was foul! You suffer %d hit points!",(long)x);
+ lastnum=273; losehp(x); bottomline(); cursors();
+ }
+ else
+ if (rnd(100) < 29)
+ lprcat("\nYou got the dirt off!");
+ else
+ if (rnd(100) < 31)
+ lprcat("\nThis water seems to be hard water! The dirt didn't come off!");
+ else
+ if (rnd(100) < 34)
+ createmonster(WATERLORD); /* make water lord */
+ else
+ lprcat("\nnothing seems to have happened");
+ return;
+ }
+ }
+
+/*
+ ***
+ FCH
+ ***
+
+ subroutine to process an up/down of a character attribute for ofountain
+ */
+static void
+fch(how,x)
+ int how;
+ long *x;
+ {
+ if (how < 0) { lprcat(" went down by one!"); --(*x); }
+ else { lprcat(" went up by one!"); (*x)++; }
+ bottomline();
+ }
+
+/*
+ a subroutine to raise or lower character levels
+ if x > 0 they are raised if x < 0 they are lowered
+ */
+fntchange(how)
+ int how;
+ {
+ register long j;
+ lprc('\n');
+ switch(rnd(9))
+ {
+ case 1: lprcat("Your strength"); fch(how,&c[0]); break;
+ case 2: lprcat("Your intelligence"); fch(how,&c[1]); break;
+ case 3: lprcat("Your wisdom"); fch(how,&c[2]); break;
+ case 4: lprcat("Your constitution"); fch(how,&c[3]); break;
+ case 5: lprcat("Your dexterity"); fch(how,&c[4]); break;
+ case 6: lprcat("Your charm"); fch(how,&c[5]); break;
+ case 7: j=rnd(level+1);
+ if (how < 0)
+ { lprintf("You lose %d hit point",(long)j); if (j>1) lprcat("s!"); else lprc('!'); losemhp((int)j); }
+ else
+ { lprintf("You gain %d hit point",(long)j); if (j>1) lprcat("s!"); else lprc('!'); raisemhp((int)j); }
+ bottomline(); break;
+
+ case 8: j=rnd(level+1);
+ if (how > 0)
+ {
+ lprintf("You just gained %d spell",(long)j); raisemspells((int)j);
+ if (j>1) lprcat("s!"); else lprc('!');
+ }
+ else
+ {
+ lprintf("You just lost %d spell",(long)j); losemspells((int)j);
+ if (j>1) lprcat("s!"); else lprc('!');
+ }
+ bottomline(); break;
+
+ case 9: j = 5*rnd((level+1)*(level+1));
+ if (how < 0)
+ {
+ lprintf("You just lost %d experience point",(long)j);
+ if (j>1) lprcat("s!"); else lprc('!'); loseexperience((long)j);
+ }
+ else
+ {
+ lprintf("You just gained %d experience point",(long)j);
+ if (j>1) lprcat("s!"); else lprc('!'); raiseexperience((long)j);
+ }
+ break;
+ }
+ cursors();
+ }
diff --git a/games/larn/movem.c b/games/larn/movem.c
new file mode 100644
index 0000000..7239a06
--- /dev/null
+++ b/games/larn/movem.c
@@ -0,0 +1,312 @@
+/*
+ * movem.c (move monster) Larn is copyrighted 1986 by Noah Morgan.
+ *
+ * Here are the functions in this file:
+ *
+ * movemonst() Routine to move the monsters toward the player
+ * movemt(x,y) Function to move a monster at (x,y) -- must determine where
+ * mmove(x,y,xd,yd) Function to actually perform the monster movement
+ * movsphere() Function to look for and move spheres of annihilation
+ */
+#include "header.h"
+
+/*
+ * movemonst() Routine to move the monsters toward the player
+ *
+ * This routine has the responsibility to determine which monsters are to
+ * move, and call movemt() to do the move.
+ * Returns no value.
+ */
+static short w1[9],w1x[9],w1y[9];
+static int tmp1,tmp2,tmp3,tmp4,distance;
+movemonst()
+ {
+ register int i,j;
+ if (c[TIMESTOP]) return; /* no action if time is stopped */
+ if (c[HASTESELF]) if ((c[HASTESELF]&1)==0) return;
+ if (spheres) movsphere(); /* move the spheres of annihilation if any */
+ if (c[HOLDMONST]) return; /* no action if monsters are held */
+
+ if (c[AGGRAVATE]) /* determine window of monsters to move */
+ {
+ tmp1=playery-5; tmp2=playery+6; tmp3=playerx-10; tmp4=playerx+11;
+ distance=40; /* depth of intelligent monster movement */
+ }
+ else
+ {
+ tmp1=playery-3; tmp2=playery+4; tmp3=playerx-5; tmp4=playerx+6;
+ distance=17; /* depth of intelligent monster movement */
+ }
+
+ if (level == 0) /* if on outside level monsters can move in perimeter */
+ {
+ if (tmp1 < 0) tmp1=0; if (tmp2 > MAXY) tmp2=MAXY;
+ if (tmp3 < 0) tmp3=0; if (tmp4 > MAXX) tmp4=MAXX;
+ }
+ else /* if in a dungeon monsters can't be on the perimeter (wall there) */
+ {
+ if (tmp1 < 1) tmp1=1; if (tmp2 > MAXY-1) tmp2=MAXY-1;
+ if (tmp3 < 1) tmp3=1; if (tmp4 > MAXX-1) tmp4=MAXX-1;
+ }
+
+ for (j=tmp1; j<tmp2; j++) /* now reset monster moved flags */
+ for (i=tmp3; i<tmp4; i++)
+ moved[i][j] = 0;
+ moved[lasthx][lasthy]=0;
+
+ if (c[AGGRAVATE] || !c[STEALTH]) /* who gets moved? split for efficiency */
+ {
+ for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
+ for (i=tmp3; i<tmp4; i++)
+ if (mitem[i][j]) /* if there is a monster to move */
+ if (moved[i][j]==0) /* if it has not already been moved */
+ movemt(i,j); /* go and move the monster */
+ }
+ else /* not aggravated and not stealth */
+ {
+ for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
+ for (i=tmp3; i<tmp4; i++)
+ if (mitem[i][j]) /* if there is a monster to move */
+ if (moved[i][j]==0) /* if it has not already been moved */
+ if (stealth[i][j]) /* if it is asleep due to stealth */
+ movemt(i,j); /* go and move the monster */
+ }
+
+ if (mitem[lasthx][lasthy]) /* now move monster last hit by player if not already moved */
+ {
+ if (moved[lasthx][lasthy]==0) /* if it has not already been moved */
+ {
+ movemt(lasthx,lasthy);
+ lasthx = w1x[0]; lasthy = w1y[0];
+ }
+ }
+ }
+
+/*
+ * movemt(x,y) Function to move a monster at (x,y) -- must determine where
+ * int x,y;
+ *
+ * This routine is responsible for determining where one monster at (x,y) will
+ * move to. Enter with the monsters coordinates in (x,y).
+ * Returns no value.
+ */
+static int tmpitem,xl,xh,yl,yh;
+movemt(i,j)
+ int i,j;
+ {
+ register int k,m,z,tmp,xtmp,ytmp,monst;
+ switch(monst=mitem[i][j]) /* for half speed monsters */
+ {
+ case TROGLODYTE: case HOBGOBLIN: case METAMORPH: case XVART:
+ case INVISIBLESTALKER: case ICELIZARD: if ((gtime & 1) == 1) return;
+ };
+
+ if (c[SCAREMONST]) /* choose destination randomly if scared */
+ {
+ if ((xl = i+rnd(3)-2) < 0) xl=0; if (xl >= MAXX) xl=MAXX-1;
+ if ((yl = j+rnd(3)-2) < 0) yl=0; if (yl >= MAXY) yl=MAXY-1;
+ if ((tmp=item[xl][yl]) != OWALL)
+ if (mitem[xl][yl] == 0)
+ if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
+ if (tmp != OCLOSEDDOOR) mmove(i,j,xl,yl);
+ return;
+ }
+
+ if (monster[monst].intelligence > 10-c[HARDGAME]) /* if smart monster */
+/* intelligent movement here -- first setup screen array */
+ {
+ xl=tmp3-2; yl=tmp1-2; xh=tmp4+2; yh=tmp2+2;
+ vxy(&xl,&yl); vxy(&xh,&yh);
+ for (k=yl; k<yh; k++)
+ for (m=xl; m<xh; m++)
+ {
+ switch(item[m][k])
+ {
+ case OWALL: case OPIT: case OTRAPARROW: case ODARTRAP:
+ case OCLOSEDDOOR: case OTRAPDOOR: case OTELEPORTER:
+ smm: screen[m][k]=127; break;
+ case OMIRROR: if (mitem[m][k]==VAMPIRE) goto smm;
+ default: screen[m][k]= 0; break;
+ };
+ }
+ screen[playerx][playery]=1;
+
+/* now perform proximity ripple from playerx,playery to monster */
+ xl=tmp3-1; yl=tmp1-1; xh=tmp4+1; yh=tmp2+1;
+ vxy(&xl,&yl); vxy(&xh,&yh);
+ for (tmp=1; tmp<distance; tmp++) /* only up to 20 squares away */
+ for (k=yl; k<yh; k++)
+ for (m=xl; m<xh; m++)
+ if (screen[m][k]==tmp) /* if find proximity n advance it */
+ for (z=1; z<9; z++) /* go around in a circle */
+ {
+ if (screen[xtmp=m+diroffx[z]][ytmp=k+diroffy[z]]==0)
+ screen[xtmp][ytmp]=tmp+1;
+ if (xtmp==i && ytmp==j) goto out;
+ }
+
+out: if (tmp<distance) /* did find connectivity */
+ /* now select lowest value around playerx,playery */
+ for (z=1; z<9; z++) /* go around in a circle */
+ if (screen[xl=i+diroffx[z]][yl=j+diroffy[z]]==tmp)
+ if (!mitem[xl][yl]) { mmove(i,j,w1x[0]=xl,w1y[0]=yl); return; }
+ }
+
+ /* dumb monsters move here */
+ xl=i-1; yl=j-1; xh=i+2; yh=j+2;
+ if (i<playerx) xl++; else if (i>playerx) --xh;
+ if (j<playery) yl++; else if (j>playery) --yh;
+ for (k=0; k<9; k++) w1[k] = 10000;
+
+ for (k=xl; k<xh; k++)
+ for (m=yl; m<yh; m++) /* for each square compute distance to player */
+ {
+ tmp = k-i+4+3*(m-j);
+ tmpitem = item[k][m];
+ if (tmpitem!=OWALL || (k==playerx && m==playery))
+ if (mitem[k][m]==0)
+ if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
+ if (tmpitem!=OCLOSEDDOOR)
+ {
+ w1[tmp] = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
+ w1x[tmp] = k; w1y[tmp] = m;
+ }
+ }
+
+ tmp = 0;
+ for (k=1; k<9; k++) if (w1[tmp] > w1[k]) tmp=k;
+
+ if (w1[tmp] < 10000)
+ if ((i!=w1x[tmp]) || (j!=w1y[tmp]))
+ mmove(i,j,w1x[tmp],w1y[tmp]);
+ }
+
+/*
+ * mmove(x,y,xd,yd) Function to actually perform the monster movement
+ * int x,y,xd,yd;
+ *
+ * Enter with the from coordinates in (x,y) and the destination coordinates
+ * in (xd,yd).
+ */
+mmove(aa,bb,cc,dd)
+ int aa,bb,cc,dd;
+ {
+ register int tmp,i,flag;
+ char *who,*p;
+ flag=0; /* set to 1 if monster hit by arrow trap */
+ if ((cc==playerx) && (dd==playery))
+ {
+ hitplayer(aa,bb); moved[aa][bb] = 1; return;
+ }
+ i=item[cc][dd];
+ if ((i==OPIT) || (i==OTRAPDOOR))
+ switch(mitem[aa][bb])
+ {
+ case SPIRITNAGA: case PLATINUMDRAGON: case WRAITH:
+ case VAMPIRE: case SILVERDRAGON: case POLTERGEIST:
+ case DEMONLORD: case DEMONLORD+1: case DEMONLORD+2:
+ case DEMONLORD+3: case DEMONLORD+4: case DEMONLORD+5:
+ case DEMONLORD+6: case DEMONPRINCE: break;
+
+ default: mitem[aa][bb]=0; /* fell in a pit or trapdoor */
+ };
+ tmp = mitem[cc][dd] = mitem[aa][bb];
+ if (i==OANNIHILATION)
+ {
+ if (tmp>=DEMONLORD+3) /* demons dispel spheres */
+ {
+ cursors();
+ lprintf("\nThe %s dispels the sphere!",monster[tmp].name);
+ rmsphere(cc,dd); /* delete the sphere */
+ }
+ else i=tmp=mitem[cc][dd]=0;
+ }
+ stealth[cc][dd]=1;
+ if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;
+ mitem[aa][bb] = 0; moved[cc][dd] = 1;
+ if (tmp == LEPRECHAUN)
+ switch(i)
+ {
+ case OGOLDPILE: case OMAXGOLD: case OKGOLD: case ODGOLD:
+ case ODIAMOND: case ORUBY: case OEMERALD: case OSAPPHIRE:
+ item[cc][dd] = 0; /* leprechaun takes gold */
+ };
+
+ if (tmp == TROLL) /* if a troll regenerate him */
+ if ((gtime & 1) == 0)
+ if (monster[tmp].hitpoints > hitp[cc][dd]) hitp[cc][dd]++;
+
+ if (i==OTRAPARROW) /* arrow hits monster */
+ { who = "An arrow"; if ((hitp[cc][dd] -= rnd(10)+level) <= 0)
+ { mitem[cc][dd]=0; flag=2; } else flag=1; }
+ if (i==ODARTRAP) /* dart hits monster */
+ { who = "A dart"; if ((hitp[cc][dd] -= rnd(6)) <= 0)
+ { mitem[cc][dd]=0; flag=2; } else flag=1; }
+ if (i==OTELEPORTER) /* monster hits teleport trap */
+ { flag=3; fillmonst(mitem[cc][dd]); mitem[cc][dd]=0; }
+ if (c[BLINDCOUNT]) return; /* if blind don't show where monsters are */
+ if (know[cc][dd] & 1)
+ {
+ p=0;
+ if (flag) cursors();
+ switch(flag)
+ {
+ case 1: p="\n%s hits the %s"; break;
+ case 2: p="\n%s hits and kills the %s"; break;
+ case 3: p="\nThe %s%s gets teleported"; who=""; break;
+ };
+ if (p) { lprintf(p,who,monster[tmp].name); beep(); }
+ }
+/* if (yrepcount>1) { know[aa][bb] &= 2; know[cc][dd] &= 2; return; } */
+ if (know[aa][bb] & 1) show1cell(aa,bb);
+ if (know[cc][dd] & 1) show1cell(cc,dd);
+ }
+
+/*
+ * movsphere() Function to look for and move spheres of annihilation
+ *
+ * This function works on the sphere linked list, first duplicating the list
+ * (the act of moving changes the list), then processing each sphere in order
+ * to move it. They eat anything in their way, including stairs, volcanic
+ * shafts, potions, etc, except for upper level demons, who can dispel
+ * spheres.
+ * No value is returned.
+ */
+#define SPHMAX 20 /* maximum number of spheres movsphere can handle */
+movsphere()
+ {
+ register int x,y,dir,len;
+ register struct sphere *sp,*sp2;
+ struct sphere sph[SPHMAX];
+
+ /* first duplicate sphere list */
+ for (sp=0,x=0,sp2=spheres; sp2; sp2=sp2->p) /* look through sphere list */
+ if (sp2->lev == level) /* only if this level */
+ {
+ sph[x] = *sp2; sph[x++].p = 0; /* copy the struct */
+ if (x>1) sph[x-2].p = &sph[x-1]; /* link pointers */
+ }
+ if (x) sp= sph; /* if any spheres, point to them */
+ else return; /* no spheres */
+
+ for (sp=sph; sp; sp=sp->p) /* look through sphere list */
+ {
+ x = sp->x; y = sp->y;
+ if (item[x][y]!=OANNIHILATION) continue; /* not really there */
+ if (--(sp->lifetime) < 0) /* has sphere run out of gas? */
+ {
+ rmsphere(x,y); /* delete sphere */
+ continue;
+ }
+ switch(rnd((int)max(7,c[INTELLIGENCE]>>1))) /* time to move the sphere */
+ {
+ case 1:
+ case 2: /* change direction to a random one */
+ sp->dir = rnd(8);
+ default: /* move in normal direction */
+ dir = sp->dir; len = sp->lifetime;
+ rmsphere(x,y);
+ newsphere(x+diroffx[dir],y+diroffy[dir],dir,len);
+ };
+ }
+ }
diff --git a/games/larn/nap.c b/games/larn/nap.c
new file mode 100644
index 0000000..b7a877d
--- /dev/null
+++ b/games/larn/nap.c
@@ -0,0 +1,116 @@
+/* nap.c Larn is copyrighted 1986 by Noah Morgan. */
+#include <signal.h>
+#include <sys/types.h>
+#ifdef SYSV
+#include <sys/times.h>
+#else
+#ifdef BSD
+#include <sys/timeb.h>
+#endif BSD
+#endif SYSV
+
+/*
+ * routine to take a nap for n milliseconds
+ */
+nap(x)
+ register int x;
+ {
+ if (x<=0) return; /* eliminate chance for infinite loop */
+ lflush();
+ if (x > 999) sleep(x/1000); else napms(x);
+ }
+
+#ifdef NONAP
+napms(x) /* do nothing */
+ int x;
+ {
+ }
+#else NONAP
+#ifdef SYSV
+/* napms - sleep for time milliseconds - uses times() */
+/* this assumes that times returns a relative time in 60ths of a second */
+/* this will do horrible things if your times() returns seconds! */
+napms(time)
+ int time;
+ {
+ long matchclock, times();
+ struct tms stats;
+
+ if (time<=0) time=1; /* eliminate chance for infinite loop */
+ if ((matchclock = times(&stats)) == -1 || matchclock == 0)
+ return; /* error, or BSD style times() */
+ matchclock += (time / 17); /*17 ms/tic is 1000 ms/sec / 60 tics/sec */
+
+ while(matchclock < times(&stats))
+ ;
+ }
+
+#else not SYSV
+#ifdef BSD
+#ifdef SIGVTALRM
+/* This must be BSD 4.2! */
+#include <sys/time.h>
+#define bit(_a) (1<<((_a)-1))
+
+static nullf()
+ {
+ }
+
+/* napms - sleep for time milliseconds - uses setitimer() */
+napms(time)
+ int time;
+ {
+ struct itimerval timeout;
+ int (*oldhandler) ();
+ int oldsig;
+
+ if (time <= 0) return;
+
+ timerclear(&timeout.it_interval);
+ timeout.it_value.tv_sec = time / 1000;
+ timeout.it_value.tv_usec = (time % 1000) * 1000;
+
+ oldsig = sigblock(bit(SIGALRM));
+ setitimer(ITIMER_REAL, &timeout, (struct itimerval *)0);
+ oldhandler = signal(SIGALRM, nullf);
+ sigpause(oldsig);
+ signal(SIGALRM, oldhandler);
+ sigsetmask(oldsig);
+ }
+
+#else
+/* napms - sleep for time milliseconds - uses ftime() */
+
+static napms(time)
+ int time;
+ {
+ /* assumed to be BSD UNIX */
+ struct timeb _gtime;
+ time_t matchtime;
+ unsigned short matchmilli;
+ register struct timeb *tp = & _gtime;
+
+ if (time <= 0) return;
+ ftime(tp);
+ matchmilli = tp->millitm + time;
+ matchtime = tp->time;
+ while (matchmilli >= 1000)
+ {
+ ++matchtime;
+ matchmilli -= 1000;
+ }
+
+ while(1)
+ {
+ ftime(tp);
+ if ((tp->time > matchtime) ||
+ ((tp->time == matchtime) && (tp->millitm >= matchmilli)))
+ break;
+ }
+ }
+#endif
+#else not BSD
+static napms(time) int time; {} /* do nothing, forget it */
+#endif BSD
+#endif SYSV
+#endif NONAP
diff --git a/games/larn/object.c b/games/larn/object.c
new file mode 100644
index 0000000..9bf7c3c
--- /dev/null
+++ b/games/larn/object.c
@@ -0,0 +1,807 @@
+/* object.c Larn is copyrighted 1986 by Noah Morgan. */
+#include "header.h"
+
+/*
+ ***************
+ LOOK_FOR_OBJECT
+ ***************
+
+ subroutine to look for an object and give the player his options
+ if an object was found.
+ */
+lookforobject()
+{
+register int i,j;
+if (c[TIMESTOP]) return; /* can't find objects is time is stopped */
+i=item[playerx][playery]; if (i==0) return;
+showcell(playerx,playery); cursors(); yrepcount=0;
+switch(i)
+ {
+ case OGOLDPILE: case OMAXGOLD:
+ case OKGOLD: case ODGOLD: lprcat("\n\nYou have found some gold!"); ogold(i); break;
+
+ case OPOTION: lprcat("\n\nYou have found a magic potion");
+ i = iarg[playerx][playery];
+ if (potionname[i][0]) lprintf(" of %s",&potionname[i][1]); opotion(i); break;
+
+ case OSCROLL: lprcat("\n\nYou have found a magic scroll");
+ i = iarg[playerx][playery];
+ if (scrollname[i][0]) lprintf(" of %s",&scrollname[i][1]);
+ oscroll(i); break;
+
+ case OALTAR: if (nearbymonst()) return;
+ lprcat("\n\nThere is a Holy Altar here!"); oaltar(); break;
+
+ case OBOOK: lprcat("\n\nYou have found a book."); obook(); break;
+
+ case OCOOKIE: lprcat("\n\nYou have found a fortune cookie."); ocookie(); break;
+
+ case OTHRONE: if (nearbymonst()) return;
+ lprintf("\n\nThere is %s here!",objectname[i]); othrone(0); break;
+
+ case OTHRONE2: if (nearbymonst()) return;
+ lprintf("\n\nThere is %s here!",objectname[i]); othrone(1); break;
+
+ case ODEADTHRONE: lprintf("\n\nThere is %s here!",objectname[i]); odeadthrone(); break;
+
+ case OORB: lprcat("\n\nYou have found the Orb!!!!!"); oorb(); break;
+
+ case OPIT: lprcat("\n\nYou're standing at the top of a pit."); opit(); break;
+
+ case OSTAIRSUP: lprcat("\n\nThere is a circular staircase here"); ostairs(1); /* up */ break;
+
+ case OELEVATORUP: lprcat("\n\nYou feel heavy for a moment, but the feeling disappears");
+ oelevator(1); /* up */ break;
+
+ case OFOUNTAIN: if (nearbymonst()) return;
+ lprcat("\n\nThere is a fountain here"); ofountain(); break;
+
+ case OSTATUE: if (nearbymonst()) return;
+ lprcat("\n\nYou are standing in front of a statue"); ostatue(); break;
+
+ case OCHEST: lprcat("\n\nThere is a chest here"); ochest(); break;
+
+ case OIVTELETRAP: if (rnd(11)<6) return;
+ item[playerx][playery] = OTELEPORTER;
+ know[playerx][playery] = 1;
+
+ case OTELEPORTER: lprcat("\nZaaaappp! You've been teleported!\n");
+ beep(); nap(3000); oteleport(0);
+ break;
+
+ case OSCHOOL: if (nearbymonst()) return;
+ lprcat("\n\nYou have found the College of Larn.");
+ lprcat("\nDo you (g) go inside, or (i) stay here? ");
+ i=0; while ((i!='g') && (i!='i') && (i!='\33')) i=getchar();
+ if (i == 'g') { oschool(); /* the college of larn */ }
+ else lprcat(" stay here");
+ break;
+
+ case OMIRROR: if (nearbymonst()) return;
+ lprcat("\n\nThere is a mirror here"); omirror(); break;
+
+ case OBANK2:
+ case OBANK: if (nearbymonst()) return;
+ if (i==OBANK) lprcat("\n\nYou have found the bank of Larn.");
+ else lprcat("\n\nYou have found a branch office of the bank of Larn.");
+ lprcat("\nDo you (g) go inside, or (i) stay here? ");
+ j=0; while ((j!='g') && (j!='i') && (j!='\33')) j=getchar();
+ if (j == 'g') { if (i==OBANK) obank(); else obank2(); /* the bank of larn */ }
+ else lprcat(" stay here");
+ break;
+
+ case ODEADFOUNTAIN: if (nearbymonst()) return;
+ lprcat("\n\nThere is a dead fountain here"); break;
+
+ case ODNDSTORE: if (nearbymonst()) return;
+ lprcat("\n\nThere is a DND store here.");
+ lprcat("\nDo you (g) go inside, or (i) stay here? ");
+ i=0; while ((i!='g') && (i!='i') && (i!='\33')) i=getchar();
+ if (i == 'g')
+ dndstore(); /* the dnd adventurers store */
+ else lprcat(" stay here");
+ break;
+
+ case OSTAIRSDOWN: lprcat("\n\nThere is a circular staircase here"); ostairs(-1); /* down */ break;
+
+ case OELEVATORDOWN: lprcat("\n\nYou feel light for a moment, but the feeling disappears");
+ oelevator(-1); /* down */
+ break;
+
+ case OOPENDOOR: lprintf("\n\nYou have found %s",objectname[i]);
+ lprcat("\nDo you (c) close it"); iopts();
+ i=0; while ((i!='c') && (i!='i') && (i!='\33')) i=getchar();
+ if ((i=='\33') || (i=='i')) { ignore(); break; }
+ lprcat("close"); forget();
+ item[playerx][playery]=OCLOSEDDOOR;
+ iarg[playerx][playery]=0;
+ playerx = lastpx; playery = lastpy;
+ break;
+
+ case OCLOSEDDOOR: lprintf("\n\nYou have found %s",objectname[i]);
+ lprcat("\nDo you (o) try to open it"); iopts();
+ i=0; while ((i!='o') && (i!='i') && (i!='\33')) i=getchar();
+ if ((i=='\33') || (i=='i'))
+ { ignore(); playerx = lastpx;
+ playery = lastpy; break; }
+ else
+ {
+ lprcat("open");
+ if (rnd(11)<7)
+ {
+ switch(iarg[playerx][playery])
+ {
+ case 6: c[AGGRAVATE] += rnd(400); break;
+
+ case 7: lprcat("\nYou are jolted by an electric shock ");
+ lastnum=274; losehp(rnd(20)); bottomline(); break;
+
+ case 8: loselevel(); break;
+
+ case 9: lprcat("\nYou suddenly feel weaker ");
+ if (c[STRENGTH]>3) c[STRENGTH]--;
+ bottomline(); break;
+
+ default: break;
+ }
+ playerx = lastpx; playery = lastpy;
+ }
+ else
+ {
+ forget(); item[playerx][playery]=OOPENDOOR;
+ }
+ }
+ break;
+
+ case OENTRANCE: lprcat("\nYou have found "); lprcat(objectname[OENTRANCE]);
+ lprcat("\nDo you (g) go inside"); iopts();
+ i=0; while ((i!='g') && (i!='i') && (i!='\33')) i=getchar();
+ if (i == 'g')
+ {
+ newcavelevel(1); playerx=33; playery=MAXY-2;
+ item[33][MAXY-1]=know[33][MAXY-1]=mitem[33][MAXY-1]=0;
+ draws(0,MAXX,0,MAXY); bot_linex(); return;
+ }
+ else ignore();
+ break;
+
+ case OVOLDOWN: lprcat("\nYou have found "); lprcat(objectname[OVOLDOWN]);
+ lprcat("\nDo you (c) climb down"); iopts();
+ i=0; while ((i!='c') && (i!='i') && (i!='\33')) i=getchar();
+ if ((i=='\33') || (i=='i')) { ignore(); break; }
+ if (level!=0) { lprcat("\nThe shaft only extends 5 feet downward!"); return; }
+ if (packweight() > 45+3*(c[STRENGTH]+c[STREXTRA])) { lprcat("\nYou slip and fall down the shaft"); beep();
+ lastnum=275; losehp(30+rnd(20)); bottomhp(); }
+
+ else lprcat("climb down"); nap(3000); newcavelevel(MAXLEVEL);
+ for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++) /* put player near volcano shaft */
+ if (item[j][i]==OVOLUP) { playerx=j; playery=i; j=MAXX; i=MAXY; positionplayer(); }
+ draws(0,MAXX,0,MAXY); bot_linex(); return;
+
+ case OVOLUP: lprcat("\nYou have found "); lprcat(objectname[OVOLUP]);
+ lprcat("\nDo you (c) climb up"); iopts();
+ i=0; while ((i!='c') && (i!='i') && (i!='\33')) i=getchar();
+ if ((i=='\33') || (i=='i')) { ignore(); break; }
+ if (level!=11) { lprcat("\nThe shaft only extends 8 feet upwards before you find a blockage!"); return; }
+ if (packweight() > 45+5*(c[STRENGTH]+c[STREXTRA])) { lprcat("\nYou slip and fall down the shaft"); beep();
+ lastnum=275; losehp(15+rnd(20)); bottomhp(); return; }
+ lprcat("climb up"); lflush(); nap(3000); newcavelevel(0);
+ for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++) /* put player near volcano shaft */
+ if (item[j][i]==OVOLDOWN) { playerx=j; playery=i; j=MAXX; i=MAXY; positionplayer(); }
+ draws(0,MAXX,0,MAXY); bot_linex(); return;
+
+ case OTRAPARROWIV: if (rnd(17)<13) return; /* for an arrow trap */
+ item[playerx][playery] = OTRAPARROW;
+ know[playerx][playery] = 0;
+
+ case OTRAPARROW: lprcat("\nYou are hit by an arrow"); beep(); /* for an arrow trap */
+ lastnum=259; losehp(rnd(10)+level);
+ bottomhp(); return;
+
+ case OIVDARTRAP: if (rnd(17)<13) return; /* for a dart trap */
+ item[playerx][playery] = ODARTRAP;
+ know[playerx][playery] = 0;
+
+ case ODARTRAP: lprcat("\nYou are hit by a dart"); beep(); /* for a dart trap */
+ lastnum=260; losehp(rnd(5));
+ if ((--c[STRENGTH]) < 3) c[STRENGTH] = 3;
+ bottomline(); return;
+
+ case OIVTRAPDOOR: if (rnd(17)<13) return; /* for a trap door */
+ item[playerx][playery] = OTRAPDOOR;
+ know[playerx][playery] = 1;
+
+ case OTRAPDOOR: lastnum = 272; /* a trap door */
+ if ((level==MAXLEVEL-1) || (level==MAXLEVEL+MAXVLEVEL-1))
+ { lprcat("\nYou fell through a bottomless trap door!"); beep(); nap(3000); died(271); }
+ lprcat("\nYou fall through a trap door!"); beep(); /* for a trap door */
+ losehp(rnd(5+level));
+ nap(2000); newcavelevel(level+1); draws(0,MAXX,0,MAXY); bot_linex();
+ return;
+
+
+ case OTRADEPOST: if (nearbymonst()) return;
+ lprcat("\nYou have found the Larn trading Post.");
+ lprcat("\nDo you (g) go inside, or (i) stay here? ");
+ i=0; while ((i!='g') && (i!='i') && (i!='\33')) i=getchar();
+ if (i == 'g') otradepost(); else lprcat("stay here");
+ return;
+
+ case OHOME: if (nearbymonst()) return;
+ lprcat("\nYou have found your way home.");
+ lprcat("\nDo you (g) go inside, or (i) stay here? ");
+ i=0; while ((i!='g') && (i!='i') && (i!='\33')) i=getchar();
+ if (i == 'g') ohome(); else lprcat("stay here");
+ return;
+
+ case OWALL: break;
+
+ case OANNIHILATION: died(283); return; /* annihilated by sphere of annihilation */
+
+ case OLRS: if (nearbymonst()) return;
+ lprcat("\n\nThere is an LRS office here.");
+ lprcat("\nDo you (g) go inside, or (i) stay here? ");
+ i=0; while ((i!='g') && (i!='i') && (i!='\33')) i=getchar();
+ if (i == 'g')
+ olrs(); /* the larn revenue service */
+ else lprcat(" stay here");
+ break;
+
+ default: finditem(i); break;
+ };
+}
+
+/*
+ function to say what object we found and ask if player wants to take it
+ */
+finditem(itm)
+ int itm;
+ {
+ int tmp,i;
+ lprintf("\n\nYou have found %s ",objectname[itm]);
+ tmp=iarg[playerx][playery];
+ switch(itm)
+ {
+ case ODIAMOND: case ORUBY: case OEMERALD:
+ case OSAPPHIRE: case OSPIRITSCARAB: case OORBOFDRAGON:
+ case OCUBEofUNDEAD: case ONOTHEFT: break;
+
+ default:
+ if (tmp>0) lprintf("+ %d",(long)tmp); else if (tmp<0) lprintf(" %d",(long)tmp);
+ }
+ lprcat("\nDo you want to (t) take it"); iopts();
+ i=0; while (i!='t' && i!='i' && i!='\33') i=getchar();
+ if (i == 't')
+ { lprcat("take"); if (take(itm,tmp)==0) forget(); return; }
+ ignore();
+ }
+
+
+/*
+ *******
+ OSTAIRS
+ *******
+
+ subroutine to process the stair cases
+ if dir > 0 the up else down
+ */
+ostairs(dir)
+ int dir;
+ {
+ register int k;
+ lprcat("\nDo you (s) stay here ");
+ if (dir > 0) lprcat("(u) go up "); else lprcat("(d) go down ");
+ lprcat("or (f) kick stairs? ");
+
+ while (1) switch(getchar())
+ {
+ case '\33':
+ case 's': case 'i': lprcat("stay here"); return;
+
+ case 'f': lprcat("kick stairs");
+ if (rnd(2) == 1)
+ lprcat("\nI hope you feel better. Showing anger rids you of frustration.");
+ else
+ {
+ k=rnd((level+1)<<1);
+ lprintf("\nYou hurt your foot dumb dumb! You suffer %d hit points",(long)k);
+ lastnum=276; losehp(k); bottomline();
+ }
+ return;
+
+ case 'u': lprcat("go up");
+ if (dir < 0) lprcat("\nThe stairs don't go up!");
+ else
+ if (level>=2 && level!=11)
+ {
+ k = level; newcavelevel(level-1);
+ draws(0,MAXX,0,MAXY); bot_linex();
+ }
+ else lprcat("\nThe stairs lead to a dead end!");
+ return;
+
+ case 'd': lprcat("go down");
+ if (dir > 0) lprcat("\nThe stairs don't go down!");
+ else
+ if (level!=0 && level!=10 && level!=13)
+ {
+ k = level; newcavelevel(level+1);
+ draws(0,MAXX,0,MAXY); bot_linex();
+ }
+ else lprcat("\nThe stairs lead to a dead end!");
+ return;
+ };
+ }
+
+
+/*
+ *********
+ OTELEPORTER
+ *********
+
+ subroutine to handle a teleport trap +/- 1 level maximum
+ */
+oteleport(err)
+ int err;
+ {
+ register int tmp;
+ if (err) if (rnd(151)<3) died(264); /* stuck in a rock */
+ c[TELEFLAG]=1; /* show ?? on bottomline if been teleported */
+ if (level==0) tmp=0;
+ else if (level < MAXLEVEL)
+ { tmp=rnd(5)+level-3; if (tmp>=MAXLEVEL) tmp=MAXLEVEL-1;
+ if (tmp<1) tmp=1; }
+ else
+ { tmp=rnd(3)+level-2; if (tmp>=MAXLEVEL+MAXVLEVEL) tmp=MAXLEVEL+MAXVLEVEL-1;
+ if (tmp<MAXLEVEL) tmp=MAXLEVEL; }
+ playerx = rnd(MAXX-2); playery = rnd(MAXY-2);
+ if (level != tmp) newcavelevel(tmp); positionplayer();
+ draws(0,MAXX,0,MAXY); bot_linex();
+ }
+
+/*
+ *******
+ OPOTION
+ *******
+
+ function to process a potion
+ */
+opotion(pot)
+ int pot;
+ {
+ lprcat("\nDo you (d) drink it, (t) take it"); iopts();
+ while (1) switch(getchar())
+ {
+ case '\33':
+ case 'i': ignore(); return;
+
+ case 'd': lprcat("drink\n"); forget(); /* destroy potion */
+ quaffpotion(pot); return;
+
+ case 't': lprcat("take\n"); if (take(OPOTION,pot)==0) forget();
+ return;
+ };
+ }
+
+/*
+ function to drink a potion
+ */
+quaffpotion(pot)
+ int pot;
+ {
+ register int i,j,k;
+ if (pot<0 || pot>=MAXPOTION) return; /* check for within bounds */
+ potionname[pot][0] = ' ';
+ switch(pot)
+ {
+ case 9: lprcat("\nYou feel greedy . . ."); nap(2000);
+ for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++)
+ if ((item[j][i]==OGOLDPILE) || (item[j][i]==OMAXGOLD))
+ {
+ know[j][i]=1; show1cell(j,i);
+ }
+ showplayer(); return;
+
+ case 19: lprcat("\nYou feel greedy . . ."); nap(2000);
+ for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++)
+ {
+ k=item[j][i];
+ if ((k==ODIAMOND) || (k==ORUBY) || (k==OEMERALD) || (k==OMAXGOLD)
+ || (k==OSAPPHIRE) || (k==OLARNEYE) || (k==OGOLDPILE))
+ {
+ know[j][i]=1; show1cell(j,i);
+ }
+ }
+ showplayer(); return;
+
+ case 20: c[HP] = c[HPMAX]; break; /* instant healing */
+
+ case 1: lprcat("\nYou feel better");
+ if (c[HP] == c[HPMAX]) raisemhp(1);
+ else if ((c[HP] += rnd(20)+20+c[LEVEL]) > c[HPMAX]) c[HP]=c[HPMAX]; break;
+
+ case 2: lprcat("\nSuddenly, you feel much more skillful!");
+ raiselevel(); raisemhp(1); return;
+
+ case 3: lprcat("\nYou feel strange for a moment");
+ c[rund(6)]++; break;
+
+ case 4: lprcat("\nYou feel more self confident!");
+ c[WISDOM] += rnd(2); break;
+
+ case 5: lprcat("\nWow! You feel great!");
+ if (c[STRENGTH]<12) c[STRENGTH]=12; else c[STRENGTH]++; break;
+
+ case 6: lprcat("\nYour charm went up by one!"); c[CHARISMA]++; break;
+
+ case 8: lprcat("\nYour intelligence went up by one!");
+ c[INTELLIGENCE]++; break;
+
+ case 10: for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++)
+ if (mitem[j][i])
+ {
+ know[j][i]=1; show1cell(j,i);
+ }
+ /* monster detection */ return;
+
+ case 12: lprcat("\nThis potion has no taste to it"); return;
+
+ case 15: lprcat("\nWOW!!! You feel Super-fantastic!!!");
+ if (c[HERO]==0) for (i=0; i<6; i++) c[i] += 11;
+ c[HERO] += 250; break;
+
+ case 16: lprcat("\nYou have a greater intestinal constitude!");
+ c[CONSTITUTION]++; break;
+
+ case 17: lprcat("\nYou now have incredibly bulging muscles!!!");
+ if (c[GIANTSTR]==0) c[STREXTRA] += 21;
+ c[GIANTSTR] += 700; break;
+
+ case 18: lprcat("\nYou feel a chill run up your spine!");
+ c[FIRERESISTANCE] += 1000; break;
+
+ case 0: lprcat("\nYou fall asleep. . .");
+ i=rnd(11)-(c[CONSTITUTION]>>2)+2; while(--i>0) { parse2(); nap(1000); }
+ cursors(); lprcat("\nYou woke up!"); return;
+
+ case 7: lprcat("\nYou become dizzy!");
+ if (--c[STRENGTH] < 3) c[STRENGTH]=3; break;
+
+ case 11: lprcat("\nYou stagger for a moment . .");
+ for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++)
+ know[j][i]=0;
+ nap(2000); draws(0,MAXX,0,MAXY); /* potion of forgetfulness */ return;
+
+ case 13: lprcat("\nYou can't see anything!"); /* blindness */
+ c[BLINDCOUNT]+=500; return;
+
+ case 14: lprcat("\nYou feel confused"); c[CONFUSE]+= 20+rnd(9); return;
+
+ case 21: lprcat("\nYou don't seem to be affected"); return; /* cure dianthroritis */
+
+ case 22: lprcat("\nYou feel a sickness engulf you"); /* poison */
+ c[HALFDAM] += 200 + rnd(200); return;
+
+ case 23: lprcat("\nYou feel your vision sharpen"); /* see invisible */
+ c[SEEINVISIBLE] += rnd(1000)+400;
+ monstnamelist[INVISIBLESTALKER] = 'I'; return;
+ };
+ bottomline(); /* show new stats */ return;
+ }
+
+/*
+ *******
+ OSCROLL
+ *******
+
+ function to process a magic scroll
+ */
+oscroll(typ)
+ int typ;
+ {
+ lprcat("\nDo you ");
+ if (c[BLINDCOUNT]==0) lprcat("(r) read it, "); lprcat("(t) take it"); iopts();
+ while (1) switch(getchar())
+ {
+ case '\33':
+ case 'i': ignore(); return;
+
+ case 'r': if (c[BLINDCOUNT]) break;
+ lprcat("read"); forget();
+ if (typ==2 || typ==15) { show1cell(playerx,playery); cursors(); }
+ /* destroy it */ read_scroll(typ); return;
+
+ case 't': lprcat("take"); if (take(OSCROLL,typ)==0) forget(); /* destroy it */
+ return;
+ };
+ }
+
+/*
+ data for the function to read a scroll
+ */
+static int xh,yh,yl,xl;
+static char curse[] = { BLINDCOUNT, CONFUSE, AGGRAVATE, HASTEMONST, ITCHING,
+ LAUGHING, DRAINSTRENGTH, CLUMSINESS, INFEEBLEMENT, HALFDAM };
+static char exten[] = { PROTECTIONTIME, DEXCOUNT, STRCOUNT, CHARMCOUNT,
+ INVISIBILITY, CANCELLATION, HASTESELF, GLOBE, SCAREMONST, HOLDMONST, TIMESTOP };
+char time_change[] = { HASTESELF,HERO,ALTPRO,PROTECTIONTIME,DEXCOUNT,
+ STRCOUNT,GIANTSTR,CHARMCOUNT,INVISIBILITY,CANCELLATION,
+ HASTESELF,AGGRAVATE,SCAREMONST,STEALTH,AWARENESS,HOLDMONST,HASTEMONST,
+ FIRERESISTANCE,GLOBE,SPIRITPRO,UNDEADPRO,HALFDAM,SEEINVISIBLE,
+ ITCHING,CLUMSINESS, WTW };
+/*
+ * function to adjust time when time warping and taking courses in school
+ */
+adjtime(tim)
+ register long tim;
+ {
+ register int j;
+ for (j=0; j<26; j++) /* adjust time related parameters */
+ if (c[time_change[j]])
+ if ((c[time_change[j]] -= tim) < 1) c[time_change[j]]=1;
+ regen();
+ }
+
+/*
+ function to read a scroll
+ */
+read_scroll(typ)
+ int typ;
+ {
+ register int i,j;
+ if (typ<0 || typ>=MAXSCROLL) return; /* be sure we are within bounds */
+ scrollname[typ][0] = ' ';
+ switch(typ)
+ {
+ case 0: lprcat("\nYour armor glows for a moment"); enchantarmor(); return;
+
+ case 1: lprcat("\nYour weapon glows for a moment"); enchweapon(); return; /* enchant weapon */
+
+ case 2: lprcat("\nYou have been granted enlightenment!");
+ yh = min(playery+7,MAXY); xh = min(playerx+25,MAXX);
+ yl = max(playery-7,0); xl = max(playerx-25,0);
+ for (i=yl; i<yh; i++) for (j=xl; j<xh; j++) know[j][i]=1;
+ nap(2000); draws(xl,xh,yl,yh); return;
+
+ case 3: lprcat("\nThis scroll seems to be blank"); return;
+
+ case 4: createmonster(makemonst(level+1)); return; /* this one creates a monster */
+
+ case 5: something(level); /* create artifact */ return;
+
+ case 6: c[AGGRAVATE]+=800; return; /* aggravate monsters */
+
+ case 7: gtime += (i = rnd(1000) - 850); /* time warp */
+ if (i>=0) lprintf("\nYou went forward in time by %d mobuls",(long)((i+99)/100));
+ else lprintf("\nYou went backward in time by %d mobuls",(long)(-(i+99)/100));
+ adjtime((long)i); /* adjust time for time warping */
+ return;
+
+ case 8: oteleport(0); return; /* teleportation */
+
+ case 9: c[AWARENESS] += 1800; return; /* expanded awareness */
+
+ case 10: c[HASTEMONST] += rnd(55)+12; return; /* haste monster */
+
+ case 11: for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++)
+ if (mitem[j][i])
+ hitp[j][i] = monster[mitem[j][i]].hitpoints;
+ return; /* monster healing */
+ case 12: c[SPIRITPRO] += 300 + rnd(200); bottomline(); return; /* spirit protection */
+
+ case 13: c[UNDEADPRO] += 300 + rnd(200); bottomline(); return; /* undead protection */
+
+ case 14: c[STEALTH] += 250 + rnd(250); bottomline(); return; /* stealth */
+
+ case 15: lprcat("\nYou have been granted enlightenment!"); /* magic mapping */
+ for (i=0; i<MAXY; i++) for (j=0; j<MAXX; j++) know[j][i]=1;
+ nap(2000); draws(0,MAXX,0,MAXY); return;
+
+ case 16: c[HOLDMONST] += 30; bottomline(); return; /* hold monster */
+
+ case 17: for (i=0; i<26; i++) /* gem perfection */
+ switch(iven[i])
+ {
+ case ODIAMOND: case ORUBY:
+ case OEMERALD: case OSAPPHIRE:
+ j = ivenarg[i]; j &= 255; j <<= 1;
+ if (j > 255) j=255; /* double value */
+ ivenarg[i] = j; break;
+ }
+ break;
+
+ case 18: for (i=0; i<11; i++) c[exten[i]] <<= 1; /* spell extension */
+ break;
+
+ case 19: for (i=0; i<26; i++) /* identify */
+ {
+ if (iven[i]==OPOTION) potionname[ivenarg[i]][0] = ' ';
+ if (iven[i]==OSCROLL) scrollname[ivenarg[i]][0] = ' ';
+ }
+ break;
+
+ case 20: for (i=0; i<10; i++) /* remove curse */
+ if (c[curse[i]]) c[curse[i]] = 1;
+ break;
+
+ case 21: annihilate(); break; /* scroll of annihilation */
+
+ case 22: godirect(22,150,"The ray hits the %s",0,' '); /* pulverization */
+ break;
+ case 23: c[LIFEPROT]++; break; /* life protection */
+ };
+ }
+
+
+oorb()
+ {
+ }
+
+opit()
+ {
+ register int i;
+ if (rnd(101)<81)
+ if (rnd(70) > 9*c[DEXTERITY]-packweight() || rnd(101)<5)
+ if (level==MAXLEVEL-1) obottomless(); else
+ if (level==MAXLEVEL+MAXVLEVEL-1) obottomless(); else
+ {
+ if (rnd(101)<20)
+ {
+ i=0; lprcat("\nYou fell into a pit! Your fall is cushioned by an unknown force\n");
+ }
+ else
+ {
+ i = rnd(level*3+3);
+ lprintf("\nYou fell into a pit! You suffer %d hit points damage",(long)i);
+ lastnum=261; /* if he dies scoreboard will say so */
+ }
+ losehp(i); nap(2000); newcavelevel(level+1); draws(0,MAXX,0,MAXY);
+ }
+ }
+
+obottomless()
+ {
+ lprcat("\nYou fell into a bottomless pit!"); beep(); nap(3000); died(262);
+ }
+oelevator(dir)
+ int dir;
+ {
+#ifdef lint
+ int x;
+ x=dir;
+ dir=x;
+#endif lint
+ }
+
+ostatue()
+ {
+ }
+
+omirror()
+ {
+ }
+
+obook()
+ {
+ lprcat("\nDo you ");
+ if (c[BLINDCOUNT]==0) lprcat("(r) read it, "); lprcat("(t) take it"); iopts();
+ while (1) switch(getchar())
+ {
+ case '\33':
+ case 'i': ignore(); return;
+
+ case 'r': if (c[BLINDCOUNT]) break;
+ lprcat("read");
+ /* no more book */ readbook(iarg[playerx][playery]); forget(); return;
+
+ case 't': lprcat("take"); if (take(OBOOK,iarg[playerx][playery])==0) forget(); /* no more book */
+ return;
+ };
+ }
+
+/*
+ function to read a book
+ */
+readbook(lev)
+ register int lev;
+ {
+ register int i,tmp;
+ if (lev<=3) i = rund((tmp=splev[lev])?tmp:1); else
+ i = rnd((tmp=splev[lev]-9)?tmp:1) + 9;
+ spelknow[i]=1;
+ lprintf("\nSpell \"%s\": %s\n%s",spelcode[i],spelname[i],speldescript[i]);
+ if (rnd(10)==4)
+ { lprcat("\nYour int went up by one!"); c[INTELLIGENCE]++; bottomline(); }
+ }
+
+ocookie()
+ {
+ char *p;
+ lprcat("\nDo you (e) eat it, (t) take it"); iopts();
+ while (1) switch(getchar())
+ {
+ case '\33':
+ case 'i': ignore(); return;
+
+ case 'e': lprcat("eat\nThe cookie tasted good.");
+ forget(); /* no more cookie */
+ if (c[BLINDCOUNT]) return;
+ if (!(p=fortune(fortfile))) return;
+ lprcat(" A message inside the cookie reads:\n"); lprcat(p);
+ return;
+
+ case 't': lprcat("take"); if (take(OCOOKIE,0)==0) forget(); /* no more book */
+ return;
+ };
+ }
+
+
+/* routine to pick up some gold -- if arg==OMAXGOLD then the pile is worth 100* the argument */
+ogold(arg)
+ int arg;
+ {
+ register long i;
+ i = iarg[playerx][playery];
+ if (arg==OMAXGOLD) i *= 100;
+ else if (arg==OKGOLD) i *= 1000;
+ else if (arg==ODGOLD) i *= 10;
+ lprintf("\nIt is worth %d!",(long)i); c[GOLD] += i; bottomgold();
+ item[playerx][playery] = know[playerx][playery] = 0; /* destroy gold */
+ }
+
+ohome()
+ {
+ register int i;
+ nosignal = 1; /* disable signals */
+ for (i=0; i<26; i++) if (iven[i]==OPOTION) if (ivenarg[i]==21)
+ {
+ iven[i]=0; /* remove the potion of cure dianthroritis from inventory */
+ clear(); lprcat("Congratulations. You found a potion of cure dianthroritis.\n");
+ lprcat("\nFrankly, No one thought you could do it. Boy! Did you surprise them!\n");
+ if (gtime>TIMELIMIT)
+ {
+ lprcat("\nThe doctor has the sad duty to inform you that your daughter died!\n");
+ lprcat("You didn't make it in time. In your agony, you kill the doctor,\nyour wife, and yourself! Too bad!\n");
+ nap(5000); died(269);
+ }
+ else
+ {
+ lprcat("\nThe doctor is now administering the potion, and in a few moments\n");
+ lprcat("Your daughter should be well on her way to recovery.\n");
+ nap(6000);
+ lprcat("\nThe potion is"); nap(3000); lprcat(" working! The doctor thinks that\n");
+ lprcat("your daughter will recover in a few days. Congratulations!\n");
+ beep(); nap(5000); died(263);
+ }
+ }
+
+ while (1)
+ {
+ clear(); lprintf("Welcome home %s. Latest word from the doctor is not good.\n",logname);
+
+ if (gtime>TIMELIMIT)
+ {
+ lprcat("\nThe doctor has the sad duty to inform you that your daughter died!\n");
+ lprcat("You didn't make it in time. In your agony, you kill the doctor,\nyour wife, and yourself! Too bad!\n");
+ nap(5000); died(269);
+ }
+
+ lprcat("\nThe diagnosis is confirmed as dianthroritis. He guesses that\n");
+ lprintf("your daughter has only %d mobuls left in this world. It's up to you,\n",(long)((TIMELIMIT-gtime+99)/100));
+ lprintf("%s, to find the only hope for your daughter, the very rare\n",logname);
+ lprcat("potion of cure dianthroritis. It is rumored that only deep in the\n");
+ lprcat("depths of the caves can this potion be found.\n\n\n");
+ lprcat("\n ----- press "); standout("return");
+ lprcat(" to continue, "); standout("escape");
+ lprcat(" to leave ----- ");
+ i=getchar(); while (i!='\33' && i!='\n') i=getchar();
+ if (i=='\33') { drawscreen(); nosignal = 0; /* enable signals */ return; }
+ }
+ }
+
+/* routine to save program space */
+iopts()
+ { lprcat(", or (i) ignore it? "); }
+ignore()
+ { lprcat("ignore\n"); }
+
diff --git a/games/larn/pathnames.h b/games/larn/pathnames.h
new file mode 100644
index 0000000..e398993
--- /dev/null
+++ b/games/larn/pathnames.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 5.1 (Berkeley) 5/2/90
+ */
+
+#define _PATH_LOG "/var/games/larn/llog12.0"
+#define _PATH_SCORE "/var/games/larn/lscore12.0"
+#define _PATH_HELP "/usr/share/games/larn/larn.help"
+#define _PATH_LEVELS "/usr/share/games/larn/larnmaze"
+#define _PATH_FORTS "/usr/share/games/larn/lfortune"
+#define _PATH_PLAYERIDS "/usr/share/games/larn/playerids"
diff --git a/games/larn/regen.c b/games/larn/regen.c
new file mode 100644
index 0000000..b9f7a0f
--- /dev/null
+++ b/games/larn/regen.c
@@ -0,0 +1,92 @@
+/* regen.c Larn is copyrighted 1986 by Noah Morgan. */
+#include "header.h"
+/*
+ *******
+ REGEN()
+ *******
+ regen()
+
+ subroutine to regenerate player hp and spells
+ */
+regen()
+ {
+ register int i,flag;
+ register long *d;
+ d = c;
+#ifdef EXTRA
+ d[MOVESMADE]++;
+#endif
+ if (d[TIMESTOP]) { if(--d[TIMESTOP]<=0) bottomline(); return; } /* for stop time spell */
+ flag=0;
+
+ if (d[STRENGTH]<3) { d[STRENGTH]=3; flag=1; }
+ if ((d[HASTESELF]==0) || ((d[HASTESELF] & 1) == 0))
+ gtime++;
+
+ if (d[HP] != d[HPMAX])
+ if (d[REGENCOUNTER]-- <= 0) /* regenerate hit points */
+ {
+ d[REGENCOUNTER] = 22 + (d[HARDGAME]<<1) - d[LEVEL];
+ if ((d[HP] += d[REGEN]) > d[HPMAX]) d[HP] = d[HPMAX];
+ bottomhp();
+ }
+
+ if (d[SPELLS] < d[SPELLMAX]) /* regenerate spells */
+ if (d[ECOUNTER]-- <= 0)
+ {
+ d[ECOUNTER] = 100+4*(d[HARDGAME]-d[LEVEL]-d[ENERGY]);
+ d[SPELLS]++; bottomspell();
+ }
+
+ if (d[HERO]) if (--d[HERO]<=0) { for (i=0; i<6; i++) d[i] -= 10; flag=1; }
+ if (d[ALTPRO]) if (--d[ALTPRO]<=0) { d[MOREDEFENSES]-=3; flag=1; }
+ if (d[PROTECTIONTIME]) if (--d[PROTECTIONTIME]<=0) { d[MOREDEFENSES]-=2; flag=1; }
+ if (d[DEXCOUNT]) if (--d[DEXCOUNT]<=0) { d[DEXTERITY]-=3; flag=1; }
+ if (d[STRCOUNT]) if (--d[STRCOUNT]<=0) { d[STREXTRA]-=3; flag=1; }
+ if (d[BLINDCOUNT]) if (--d[BLINDCOUNT]<=0) { cursors(); lprcat("\nThe blindness lifts "); beep(); }
+ if (d[CONFUSE]) if (--d[CONFUSE]<=0) { cursors(); lprcat("\nYou regain your senses"); beep(); }
+ if (d[GIANTSTR]) if (--d[GIANTSTR]<=0) { d[STREXTRA] -= 20; flag=1; }
+ if (d[CHARMCOUNT]) if ((--d[CHARMCOUNT]) <= 0) flag=1;
+ if (d[INVISIBILITY]) if ((--d[INVISIBILITY]) <= 0) flag=1;
+ if (d[CANCELLATION]) if ((--d[CANCELLATION]) <= 0) flag=1;
+ if (d[WTW]) if ((--d[WTW]) <= 0) flag=1;
+ if (d[HASTESELF]) if ((--d[HASTESELF]) <= 0) flag=1;
+ if (d[AGGRAVATE]) --d[AGGRAVATE];
+ if (d[SCAREMONST]) if ((--d[SCAREMONST]) <= 0) flag=1;
+ if (d[STEALTH]) if ((--d[STEALTH]) <= 0) flag=1;
+ if (d[AWARENESS]) --d[AWARENESS];
+ if (d[HOLDMONST]) if ((--d[HOLDMONST]) <= 0) flag=1;
+ if (d[HASTEMONST]) --d[HASTEMONST];
+ if (d[FIRERESISTANCE]) if ((--d[FIRERESISTANCE]) <= 0) flag=1;
+ if (d[GLOBE]) if (--d[GLOBE]<=0) { d[MOREDEFENSES]-=10; flag=1; }
+ if (d[SPIRITPRO]) if (--d[SPIRITPRO] <= 0) flag=1;
+ if (d[UNDEADPRO]) if (--d[UNDEADPRO] <= 0) flag=1;
+ if (d[HALFDAM]) if (--d[HALFDAM]<=0) { cursors(); lprcat("\nYou now feel better "); beep(); }
+ if (d[SEEINVISIBLE])
+ if (--d[SEEINVISIBLE]<=0)
+ { monstnamelist[INVISIBLESTALKER] = ' ';
+ cursors(); lprcat("\nYou feel your vision return to normal"); beep(); }
+ if (d[ITCHING])
+ {
+ if (d[ITCHING]>1)
+ if ((d[WEAR]!= -1) || (d[SHIELD]!= -1))
+ if (rnd(100)<50)
+ {
+ d[WEAR]=d[SHIELD]= -1; cursors();
+ lprcat("\nThe hysteria of itching forces you to remove your armor!");
+ beep(); recalc(); bottomline();
+ }
+ if (--d[ITCHING]<=0) { cursors(); lprcat("\nYou now feel the irritation subside!"); beep(); }
+ }
+ if (d[CLUMSINESS])
+ {
+ if (d[WIELD] != -1)
+ if (d[CLUMSINESS]>1)
+ if (item[playerx][playery]==0) /* only if nothing there */
+ if (rnd(100)<33) /* drop your weapon due to clumsiness */
+ drop_object((int)d[WIELD]);
+ if (--d[CLUMSINESS]<=0) { cursors(); lprcat("\nYou now feel less awkward!"); beep(); }
+ }
+ if (flag) bottomline();
+ }
+
diff --git a/games/larn/savelev.c b/games/larn/savelev.c
new file mode 100644
index 0000000..4419acb
--- /dev/null
+++ b/games/larn/savelev.c
@@ -0,0 +1,47 @@
+/* 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;
+ }
+ }
diff --git a/games/larn/scores.c b/games/larn/scores.c
new file mode 100644
index 0000000..f6cf15c
--- /dev/null
+++ b/games/larn/scores.c
@@ -0,0 +1,652 @@
+/* scores.c Larn is copyrighted 1986 by Noah Morgan.
+ *
+ * Functions in this file are:
+ *
+ * readboard() Function to read in the scoreboard into a static buffer
+ * writeboard() Function to write the scoreboard from readboard()'s buffer
+ * makeboard() Function to create a new scoreboard (wipe out old one)
+ * hashewon() Function to return 1 if player has won a game before, else 0
+ * long paytaxes(x) Function to pay taxes if any are due
+ * winshou() Subroutine to print out the winning scoreboard
+ * shou(x) Subroutine to print out the non-winners scoreboard
+ * showscores() Function to show the scoreboard on the terminal
+ * showallscores() Function to show scores and the iven lists that go with them
+ * sortboard() Function to sort the scoreboard
+ * newscore(score, whoo, whyded, winner) Function to add entry to scoreboard
+ * new1sub(score,i,whoo,taxes) Subroutine to put player into a
+ * new2sub(score,i,whoo,whyded) Subroutine to put player into a
+ * died(x) Subroutine to record who played larn, and what the score was
+ * diedsub(x) Subroutine to print out a line showing player when he is killed
+ * diedlog() Subroutine to read a log file and print it out in ascii format
+ * getplid(name) Function to get players id # from id file
+ *
+ */
+#include <sys/types.h>
+#include <sys/times.h>
+#include <sys/stat.h>
+#include "header.h"
+
+struct scofmt /* This is the structure for the scoreboard */
+ {
+ long score; /* the score of the player */
+ long suid; /* the user id number of the player */
+ short what; /* the number of the monster that killed player */
+ short level; /* the level player was on when he died */
+ short hardlev; /* the level of difficulty player played at */
+ short order; /* the relative ordering place of this entry */
+ char who[40]; /* the name of the character */
+ char sciv[26][2]; /* this is the inventory list of the character */
+ };
+struct wscofmt /* This is the structure for the winning scoreboard */
+ {
+ long score; /* the score of the player */
+ long timeused; /* the time used in mobuls to win the game */
+ long taxes; /* taxes he owes to LRS */
+ long suid; /* the user id number of the player */
+ short hardlev; /* the level of difficulty player played at */
+ short order; /* the relative ordering place of this entry */
+ char who[40]; /* the name of the character */
+ };
+
+struct log_fmt /* 102 bytes struct for the log file */
+ {
+ long score; /* the players score */
+ long diedtime; /* time when game was over */
+ short cavelev; /* level in caves */
+ short diff; /* difficulty player played at */
+#ifdef EXTRA
+ long elapsedtime; /* real time of game in seconds */
+ long bytout; /* bytes input and output */
+ long bytin;
+ long moves; /* number of moves made by player */
+ short ac; /* armor class of player */
+ short hp,hpmax; /* players hitpoints */
+ short cputime; /* cpu time needed in seconds */
+ short killed,spused;/* monsters killed and spells cast */
+ short usage; /* usage of the cpu in % */
+ short lev; /* player level */
+#endif
+ char who[12]; /* player name */
+ char what[46]; /* what happened to player */
+ };
+
+static struct scofmt sco[SCORESIZE]; /* the structure for the scoreboard */
+static struct wscofmt winr[SCORESIZE]; /* struct for the winning scoreboard */
+static struct log_fmt logg; /* structure for the log file */
+static char *whydead[] = {
+ "quit", "suspended", "self - annihilated", "shot by an arrow",
+ "hit by a dart", "fell into a pit", "fell into a bottomless pit",
+ "a winner", "trapped in solid rock", "killed by a missing save file",
+ "killed by an old save file", "caught by the greedy cheater checker trap",
+ "killed by a protected save file","killed his family and committed suicide",
+ "erased by a wayward finger", "fell through a bottomless trap door",
+ "fell through a trap door", "drank some poisonous water",
+ "fried by an electric shock", "slipped on a volcano shaft",
+ "killed by a stupid act of frustration", "attacked by a revolting demon",
+ "hit by his own magic", "demolished by an unseen attacker",
+ "fell into the dreadful sleep", "killed by an exploding chest",
+/*26*/ "killed by a missing maze data file", "annihilated in a sphere",
+ "died a post mortem death","wasted by a malloc() failure"
+ };
+
+/*
+ * readboard() Function to read in the scoreboard into a static buffer
+ *
+ * returns -1 if unable to read in the scoreboard, returns 0 if all is OK
+ */
+readboard()
+ {
+ if (lopen(scorefile)<0)
+ { lprcat("Can't read scoreboard\n"); lflush(); return(-1); }
+ lrfill((char*)sco,sizeof(sco)); lrfill((char*)winr,sizeof(winr));
+ lrclose(); lcreat((char*)0); return(0);
+ }
+
+/*
+ * writeboard() Function to write the scoreboard from readboard()'s buffer
+ *
+ * returns -1 if unable to write the scoreboard, returns 0 if all is OK
+ */
+writeboard()
+ {
+ set_score_output();
+ if (lcreat(scorefile)<0)
+ { lprcat("Can't write scoreboard\n"); lflush(); return(-1); }
+ lwrite((char*)sco,sizeof(sco)); lwrite((char*)winr,sizeof(winr));
+ lwclose(); lcreat((char*)0); return(0);
+ }
+
+/*
+ * makeboard() Function to create a new scoreboard (wipe out old one)
+ *
+ * returns -1 if unable to write the scoreboard, returns 0 if all is OK
+ */
+makeboard()
+ {
+ register int i;
+ for (i=0; i<SCORESIZE; i++)
+ {
+ winr[i].taxes = winr[i].score = sco[i].score = 0;
+ winr[i].order = sco[i].order = i;
+ }
+ if (writeboard()) return(-1);
+ chmod(scorefile,0660);
+ return(0);
+ }
+
+/*
+ * hashewon() Function to return 1 if player has won a game before, else 0
+ *
+ * This function also sets c[HARDGAME] to appropriate value -- 0 if not a
+ * winner, otherwise the next level of difficulty listed in the winners
+ * scoreboard. This function also sets outstanding_taxes to the value in
+ * the winners scoreboard.
+ */
+hashewon()
+ {
+ register int i;
+ c[HARDGAME] = 0;
+ if (readboard() < 0) return(0); /* can't find scoreboard */
+ for (i=0; i<SCORESIZE; i++) /* search through winners scoreboard */
+ if (winr[i].suid == userid)
+ if (winr[i].score > 0)
+ {
+ c[HARDGAME]=winr[i].hardlev+1; outstanding_taxes=winr[i].taxes;
+ return(1);
+ }
+ return(0);
+ }
+
+/*
+ * long paytaxes(x) Function to pay taxes if any are due
+ *
+ * Enter with the amount (in gp) to pay on the taxes.
+ * Returns amount actually paid.
+ */
+long paytaxes(x)
+ long x;
+ {
+ register int i;
+ register long amt;
+ if (x<0) return(0L);
+ if (readboard()<0) return(0L);
+ for (i=0; i<SCORESIZE; i++)
+ if (winr[i].suid == userid) /* look for players winning entry */
+ if (winr[i].score>0) /* search for a winning entry for the player */
+ {
+ amt = winr[i].taxes;
+ if (x < amt) amt=x; /* don't overpay taxes (Ughhhhh) */
+ winr[i].taxes -= amt;
+ outstanding_taxes -= amt;
+ if (writeboard()<0) return(0);
+ return(amt);
+ }
+ return(0L); /* couldn't find user on winning scoreboard */
+ }
+
+/*
+ * winshou() Subroutine to print out the winning scoreboard
+ *
+ * Returns the number of players on scoreboard that were shown
+ */
+winshou()
+ {
+ register struct wscofmt *p;
+ register int i,j,count;
+ for (count=j=i=0; i<SCORESIZE; i++) /* is there anyone on the scoreboard? */
+ if (winr[i].score != 0)
+ { j++; break; }
+ if (j)
+ {
+ lprcat("\n Score Difficulty Time Needed Larn Winners List\n");
+
+ for (i=0; i<SCORESIZE; i++) /* this loop is needed to print out the */
+ for (j=0; j<SCORESIZE; j++) /* winners in order */
+ {
+ p = &winr[j]; /* pointer to the scoreboard entry */
+ if (p->order == i)
+ {
+ if (p->score)
+ {
+ count++;
+ lprintf("%10d %2d %5d Mobuls %s \n",
+ (long)p->score,(long)p->hardlev,(long)p->timeused,p->who);
+ }
+ break;
+ }
+ }
+ }
+ return(count); /* return number of people on scoreboard */
+ }
+
+/*
+ * shou(x) Subroutine to print out the non-winners scoreboard
+ * int x;
+ *
+ * Enter with 0 to list the scores, enter with 1 to list inventories too
+ * Returns the number of players on scoreboard that were shown
+ */
+shou(x)
+ int x;
+ {
+ register int i,j,n,k;
+ int count;
+ for (count=j=i=0; i<SCORESIZE; i++) /* is the scoreboard empty? */
+ if (sco[i].score!= 0)
+ { j++; break; }
+ if (j)
+ {
+ lprcat("\n Score Difficulty Larn Visitor Log\n");
+ for (i=0; i<SCORESIZE; i++) /* be sure to print them out in order */
+ for (j=0; j<SCORESIZE; j++)
+ if (sco[j].order == i)
+ {
+ if (sco[j].score)
+ {
+ count++;
+ lprintf("%10d %2d %s ",
+ (long)sco[j].score,(long)sco[j].hardlev,sco[j].who);
+ if (sco[j].what < 256) lprintf("killed by a %s",monster[sco[j].what].name);
+ else lprintf("%s",whydead[sco[j].what - 256]);
+ if (x != 263) lprintf(" on %s",levelname[sco[j].level]);
+ if (x)
+ {
+ for (n=0; n<26; n++) { iven[n]=sco[j].sciv[n][0]; ivenarg[n]=sco[j].sciv[n][1]; }
+ for (k=1; k<99; k++)
+ for (n=0; n<26; n++)
+ if (k==iven[n]) { srcount=0; show3(n); }
+ lprcat("\n\n");
+ }
+ else lprc('\n');
+ }
+ j=SCORESIZE;
+ }
+ }
+ return(count); /* return the number of players just shown */
+ }
+
+/*
+ * showscores() Function to show the scoreboard on the terminal
+ *
+ * Returns nothing of value
+ */
+static char esb[] = "The scoreboard is empty.\n";
+showscores()
+ {
+ register int i,j;
+ lflush(); lcreat((char*)0); if (readboard()<0) return;
+ i=winshou(); j=shou(0);
+ if (i+j == 0) lprcat(esb); else lprc('\n');
+ lflush();
+ }
+
+/*
+ * showallscores() Function to show scores and the iven lists that go with them
+ *
+ * Returns nothing of value
+ */
+showallscores()
+ {
+ register int i,j;
+ lflush(); lcreat((char*)0); if (readboard()<0) return;
+ c[WEAR] = c[WIELD] = c[SHIELD] = -1; /* not wielding or wearing anything */
+ for (i=0; i<MAXPOTION; i++) potionname[i][0]=' ';
+ for (i=0; i<MAXSCROLL; i++) scrollname[i][0]=' ';
+ i=winshou(); j=shou(1);
+ if (i+j==0) lprcat(esb); else lprc('\n');
+ lflush();
+ }
+
+/*
+ * sortboard() Function to sort the scoreboard
+ *
+ * Returns 0 if no sorting done, else returns 1
+ */
+sortboard()
+ {
+ register int i,j,pos;
+ long jdat;
+ for (i=0; i<SCORESIZE; i++) sco[i].order = winr[i].order = -1;
+ pos=0; while (pos < SCORESIZE)
+ {
+ jdat=0;
+ for (i=0; i<SCORESIZE; i++)
+ if ((sco[i].order < 0) && (sco[i].score >= jdat))
+ { j=i; jdat=sco[i].score; }
+ sco[j].order = pos++;
+ }
+ pos=0; while (pos < SCORESIZE)
+ {
+ jdat=0;
+ for (i=0; i<SCORESIZE; i++)
+ if ((winr[i].order < 0) && (winr[i].score >= jdat))
+ { j=i; jdat=winr[i].score; }
+ winr[j].order = pos++;
+ }
+ return(1);
+ }
+
+/*
+ * newscore(score, whoo, whyded, winner) Function to add entry to scoreboard
+ * int score, winner, whyded;
+ * char *whoo;
+ *
+ * Enter with the total score in gp in score, players name in whoo,
+ * died() reason # in whyded, and TRUE/FALSE in winner if a winner
+ * ex. newscore(1000, "player 1", 32, 0);
+ */
+newscore(score, whoo, whyded, winner)
+ long score;
+ int winner, whyded;
+ char *whoo;
+ {
+ register int i;
+ long taxes;
+ if (readboard() < 0) return; /* do the scoreboard */
+ /* if a winner then delete all non-winning scores */
+ if (cheat) winner=0; /* if he cheated, don't let him win */
+ if (winner)
+ {
+ for (i=0; i<SCORESIZE; i++) if (sco[i].suid == userid) sco[i].score=0;
+ taxes = score*TAXRATE;
+ score += 100000*c[HARDGAME]; /* bonus for winning */
+ /* if he has a slot on the winning scoreboard update it if greater score */
+ for (i=0; i<SCORESIZE; i++) if (winr[i].suid == userid)
+ { new1sub(score,i,whoo,taxes); return; }
+ /* he had no entry. look for last entry and see if he has a greater score */
+ for (i=0; i<SCORESIZE; i++) if (winr[i].order == SCORESIZE-1)
+ { new1sub(score,i,whoo,taxes); return; }
+ }
+ else if (!cheat) /* for not winning scoreboard */
+ {
+ /* if he has a slot on the scoreboard update it if greater score */
+ for (i=0; i<SCORESIZE; i++) if (sco[i].suid == userid)
+ { new2sub(score,i,whoo,whyded); return; }
+ /* he had no entry. look for last entry and see if he has a greater score */
+ for (i=0; i<SCORESIZE; i++) if (sco[i].order == SCORESIZE-1)
+ { new2sub(score,i,whoo,whyded); return; }
+ }
+ }
+
+/*
+ * new1sub(score,i,whoo,taxes) Subroutine to put player into a
+ * int score,i,whyded,taxes; winning scoreboard entry if his score
+ * char *whoo; is high enough
+ *
+ * Enter with the total score in gp in score, players name in whoo,
+ * died() reason # in whyded, and TRUE/FALSE in winner if a winner
+ * slot in scoreboard in i, and the tax bill in taxes.
+ * Returns nothing of value
+ */
+new1sub(score,i,whoo,taxes)
+ long score,taxes;
+ int i;
+ char *whoo;
+ {
+ register struct wscofmt *p;
+ p = &winr[i];
+ p->taxes += taxes;
+ if ((score >= p->score) || (c[HARDGAME] > p->hardlev))
+ {
+ strcpy(p->who,whoo); p->score=score;
+ p->hardlev=c[HARDGAME]; p->suid=userid;
+ p->timeused=gtime/100;
+ }
+ }
+
+/*
+ * new2sub(score,i,whoo,whyded) Subroutine to put player into a
+ * int score,i,whyded,taxes; non-winning scoreboard entry if his
+ * char *whoo; score is high enough
+ *
+ * Enter with the total score in gp in score, players name in whoo,
+ * died() reason # in whyded, and slot in scoreboard in i.
+ * Returns nothing of value
+ */
+new2sub(score,i,whoo,whyded)
+ long score;
+ int i,whyded;
+ char *whoo;
+ {
+ register int j;
+ register struct scofmt *p;
+ p = &sco[i];
+ if ((score >= p->score) || (c[HARDGAME] > p->hardlev))
+ {
+ strcpy(p->who,whoo); p->score=score;
+ p->what=whyded; p->hardlev=c[HARDGAME];
+ p->suid=userid; p->level=level;
+ for (j=0; j<26; j++)
+ { p->sciv[j][0]=iven[j]; p->sciv[j][1]=ivenarg[j]; }
+ }
+ }
+
+/*
+ * died(x) Subroutine to record who played larn, and what the score was
+ * int x;
+ *
+ * if x < 0 then don't show scores
+ * died() never returns! (unless c[LIFEPROT] and a reincarnatable death!)
+ *
+ * < 256 killed by the monster number
+ * 256 quit
+ * 257 suspended
+ * 258 self - annihilated
+ * 259 shot by an arrow
+ * 260 hit by a dart
+ * 261 fell into a pit
+ * 262 fell into a bottomless pit
+ * 263 a winner
+ * 264 trapped in solid rock
+ * 265 killed by a missing save file
+ * 266 killed by an old save file
+ * 267 caught by the greedy cheater checker trap
+ * 268 killed by a protected save file
+ * 269 killed his family and killed himself
+ * 270 erased by a wayward finger
+ * 271 fell through a bottomless trap door
+ * 272 fell through a trap door
+ * 273 drank some poisonous water
+ * 274 fried by an electric shock
+ * 275 slipped on a volcano shaft
+ * 276 killed by a stupid act of frustration
+ * 277 attacked by a revolting demon
+ * 278 hit by his own magic
+ * 279 demolished by an unseen attacker
+ * 280 fell into the dreadful sleep
+ * 281 killed by an exploding chest
+ * 282 killed by a missing maze data file
+ * 283 killed by a sphere of annihilation
+ * 284 died a post mortem death
+ * 285 malloc() failure
+ * 300 quick quit -- don't put on scoreboard
+ */
+
+static int scorerror;
+died(x)
+ int x;
+ {
+ register int f,win;
+ char ch,*mod;
+ long zzz,i;
+ struct tms cputime;
+ if (c[LIFEPROT]>0) /* if life protection */
+ {
+ switch((x>0) ? x : -x)
+ {
+ case 256: case 257: case 262: case 263: case 265: case 266:
+ case 267: case 268: case 269: case 271: case 282: case 284:
+ case 285: case 300: goto invalid; /* can't be saved */
+ };
+ --c[LIFEPROT]; c[HP]=1; --c[CONSTITUTION];
+ cursors(); lprcat("\nYou feel wiiieeeeerrrrrd all over! "); beep();
+ lflush(); sleep(4);
+ return; /* only case where died() returns */
+ }
+invalid:
+ clearvt100(); lflush(); f=0;
+ if (ckpflag) unlink(ckpfile); /* remove checkpoint file if used */
+ if (x<0) { f++; x = -x; } /* if we are not to display the scores */
+ if ((x == 300) || (x == 257)) exit(); /* for quick exit or saved game */
+ if (x == 263) win = 1; else win = 0;
+ c[GOLD] += c[BANKACCOUNT]; c[BANKACCOUNT] = 0;
+ /* now enter the player at the end of the scoreboard */
+ newscore(c[GOLD], logname, x, win);
+ diedsub(x); /* print out the score line */ lflush();
+
+ set_score_output();
+ if ((wizard == 0) && (c[GOLD] > 0)) /* wizards can't score */
+ {
+#ifndef NOLOG
+ if (lappend(logfile)<0) /* append to file */
+ {
+ if (lcreat(logfile)<0) /* and can't create new log file */
+ {
+ lcreat((char*)0);
+ lprcat("\nCan't open record file: I can't post your score.\n");
+ sncbr(); resetscroll(); lflush(); exit();
+ }
+ chmod(logfile,0660);
+ }
+ strcpy(logg.who,loginname);
+ logg.score = c[GOLD]; logg.diff = c[HARDGAME];
+ if (x < 256)
+ {
+ ch = *monster[x].name;
+ if (ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u')
+ mod="an"; else mod="a";
+ sprintf(logg.what,"killed by %s %s",mod,monster[x].name);
+ }
+ else sprintf(logg.what,"%s",whydead[x - 256]);
+ logg.cavelev=level;
+ time(&zzz); /* get cpu time -- write out score info */
+ logg.diedtime=zzz;
+#ifdef EXTRA
+ times(&cputime); /* get cpu time -- write out score info */
+ logg.cputime = i = (cputime.tms_utime + cputime.tms_stime)/60 + c[CPUTIME];
+ logg.lev=c[LEVEL]; logg.ac=c[AC];
+ logg.hpmax=c[HPMAX]; logg.hp=c[HP];
+ logg.elapsedtime=(zzz-initialtime+59)/60;
+ logg.usage=(10000*i)/(zzz-initialtime);
+ logg.bytin=c[BYTESIN]; logg.bytout=c[BYTESOUT];
+ logg.moves=c[MOVESMADE]; logg.spused=c[SPELLSCAST];
+ logg.killed=c[MONSTKILLED];
+#endif
+ lwrite((char*)&logg,sizeof(struct log_fmt)); lwclose();
+#endif NOLOG
+
+/* now for the scoreboard maintenance -- not for a suspended game */
+ if (x != 257)
+ {
+ if (sortboard()) scorerror = writeboard();
+ }
+ }
+ if ((x==256) || (x==257) || (f != 0)) exit();
+ if (scorerror == 0) showscores(); /* if we updated the scoreboard */
+ if (x == 263) mailbill(); exit();
+ }
+
+/*
+ * diedsub(x) Subroutine to print out the line showing the player when he is killed
+ * int x;
+ */
+diedsub(x)
+int x;
+ {
+ register char ch,*mod;
+ lprintf("Score: %d, Diff: %d, %s ",(long)c[GOLD],(long)c[HARDGAME],logname);
+ if (x < 256)
+ {
+ ch = *monster[x].name;
+ if (ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u')
+ mod="an"; else mod="a";
+ lprintf("killed by %s %s",mod,monster[x].name);
+ }
+ else lprintf("%s",whydead[x - 256]);
+ if (x != 263) lprintf(" on %s\n",levelname[level]); else lprc('\n');
+ }
+
+/*
+ * diedlog() Subroutine to read a log file and print it out in ascii format
+ */
+diedlog()
+ {
+ register int n;
+ register char *p;
+ struct stat stbuf;
+ lcreat((char*)0);
+ if (lopen(logfile)<0)
+ {
+ lprintf("Can't locate log file <%s>\n",logfile);
+ return;
+ }
+ if (fstat(fd,&stbuf) < 0)
+ {
+ lprintf("Can't stat log file <%s>\n",logfile);
+ return;
+ }
+ for (n=stbuf.st_size/sizeof(struct log_fmt); n>0; --n)
+ {
+ lrfill((char*)&logg,sizeof(struct log_fmt));
+ p = ctime(&logg.diedtime); p[16]='\n'; p[17]=0;
+ lprintf("Score: %d, Diff: %d, %s %s on %d at %s",(long)(logg.score),(long)(logg.diff),logg.who,logg.what,(long)(logg.cavelev),p+4);
+#ifdef EXTRA
+ if (logg.moves<=0) logg.moves=1;
+ lprintf(" Experience Level: %d, AC: %d, HP: %d/%d, Elapsed Time: %d minutes\n",(long)(logg.lev),(long)(logg.ac),(long)(logg.hp),(long)(logg.hpmax),(long)(logg.elapsedtime));
+ lprintf(" CPU time used: %d seconds, Machine usage: %d.%02d%%\n",(long)(logg.cputime),(long)(logg.usage/100),(long)(logg.usage%100));
+ lprintf(" BYTES in: %d, out: %d, moves: %d, deaths: %d, spells cast: %d\n",(long)(logg.bytin),(long)(logg.bytout),(long)(logg.moves),(long)(logg.killed),(long)(logg.spused));
+ lprintf(" out bytes per move: %d, time per move: %d ms\n",(long)(logg.bytout/logg.moves),(long)((logg.cputime*1000)/logg.moves));
+#endif
+ }
+ lflush(); lrclose(); return;
+ }
+
+#ifndef UIDSCORE
+/*
+ * getplid(name) Function to get players id # from id file
+ *
+ * Enter with the name of the players character in name.
+ * Returns the id # of the players character, or -1 if failure.
+ * This routine will try to find the name in the id file, if its not there,
+ * it will try to make a new entry in the file. Only returns -1 if can't
+ * find him in the file, and can't make a new entry in the file.
+ * Format of playerids file:
+ * Id # in ascii \n character name \n
+ */
+static int havepid= -1; /* playerid # if previously done */
+getplid(nam)
+ char *nam;
+ {
+ int fd7,high=999,no;
+ register char *p,*p2;
+ char name[80];
+ if (havepid != -1) return(havepid); /* already did it */
+ lflush(); /* flush any pending I/O */
+ sprintf(name,"%s\n",nam); /* append a \n to name */
+ if (lopen(playerids) < 0) /* no file, make it */
+ {
+ if ((fd7=creat(playerids,0666)) < 0) return(-1); /* can't make it */
+ close(fd7); goto addone; /* now append new playerid record to file */
+ }
+ for (;;) /* now search for the name in the player id file */
+ {
+ p = lgetl(); if (p==NULL) break; /* EOF? */
+ no = atoi(p); /* the id # */
+ p2= lgetl(); if (p2==NULL) break; /* EOF? */
+ if (no>high) high=no; /* accumulate highest id # */
+ if (strcmp(p2,name)==0) /* we found him */
+ {
+ return(no); /* his id number */
+ }
+ }
+ lrclose();
+ /* if we get here, we didn't find him in the file -- put him there */
+addone:
+ if (lappend(playerids) < 0) return(-1); /* can't open file for append */
+ lprintf("%d\n%s",(long)++high,name); /* new id # and name */
+ lwclose();
+ lcreat((char*)0); /* re-open terminal channel */
+ return(high);
+ }
+#endif UIDSCORE
+
diff --git a/games/larn/signal.c b/games/larn/signal.c
new file mode 100644
index 0000000..60bd6ce
--- /dev/null
+++ b/games/larn/signal.c
@@ -0,0 +1,148 @@
+#include <signal.h>
+#include "header.h" /* "Larn is copyrighted 1986 by Noah Morgan.\n" */
+#define BIT(a) (1<<((a)-1))
+extern char savefilename[],wizard,predostuff,nosignal;
+static s2choose() /* text to be displayed if ^C during intro screen */
+ {
+ cursor(1,24); lprcat("Press "); setbold(); lprcat("return"); resetbold();
+ lprcat(" to continue: "); lflush();
+ }
+
+static void
+cntlc() /* what to do for a ^C */
+ {
+ if (nosignal) return; /* don't do anything if inhibited */
+ signal(SIGQUIT,SIG_IGN); signal(SIGINT,SIG_IGN);
+ quit(); if (predostuff==1) s2choose(); else showplayer();
+ lflush();
+ signal(SIGQUIT,cntlc); signal(SIGINT,cntlc);
+ }
+
+/*
+ * subroutine to save the game if a hangup signal
+ */
+static void
+sgam()
+ {
+ savegame(savefilename); wizard=1; died(-257); /* hangup signal */
+ }
+
+#ifdef SIGTSTP
+static void
+tstop() /* control Y */
+ {
+ if (nosignal) return; /* nothing if inhibited */
+ lcreat((char*)0); clearvt100(); lflush(); signal(SIGTSTP,SIG_DFL);
+#ifdef SIGVTALRM
+ /* looks like BSD4.2 or higher - must clr mask for signal to take effect*/
+ sigsetmask(sigblock(0)& ~BIT(SIGTSTP));
+#endif
+ kill(getpid(),SIGTSTP);
+
+ setupvt100(); signal(SIGTSTP,tstop);
+ if (predostuff==1) s2choose(); else drawscreen();
+ showplayer(); lflush();
+ }
+#endif SIGTSTP
+
+/*
+ * subroutine to issue the needed signal traps called from main()
+ */
+static void sigpanic();
+static void sigill() { sigpanic(SIGILL); }
+static void sigtrap() { sigpanic(SIGTRAP); }
+static void sigiot() { sigpanic(SIGIOT); }
+static void sigemt() { sigpanic(SIGEMT); }
+static void sigfpe() { sigpanic(SIGFPE); }
+static void sigbus() { sigpanic(SIGBUS); }
+static void sigsegv() { sigpanic(SIGSEGV); }
+static void sigsys() { sigpanic(SIGSYS); }
+static void sigpipe() { sigpanic(SIGPIPE); }
+static void sigterm() { sigpanic(SIGTERM); }
+sigsetup()
+ {
+ signal(SIGQUIT, cntlc); signal(SIGINT, cntlc);
+ signal(SIGKILL, SIG_IGN); signal(SIGHUP, sgam);
+ signal(SIGILL, sigill); signal(SIGTRAP, sigtrap);
+ signal(SIGIOT, sigiot); signal(SIGEMT, sigemt);
+ signal(SIGFPE, sigfpe); signal(SIGBUS, sigbus);
+ signal(SIGSEGV, sigsegv); signal(SIGSYS, sigsys);
+ signal(SIGPIPE, sigpipe); signal(SIGTERM, sigterm);
+#ifdef SIGTSTP
+ signal(SIGTSTP,tstop); signal(SIGSTOP,tstop);
+#endif SIGTSTP
+ }
+
+#ifdef BSD /* for BSD UNIX? */
+
+static char *signame[NSIG] = { "",
+"SIGHUP", /* 1 hangup */
+"SIGINT", /* 2 interrupt */
+"SIGQUIT", /* 3 quit */
+"SIGILL", /* 4 illegal instruction (not reset when caught) */
+"SIGTRAP", /* 5 trace trap (not reset when caught) */
+"SIGIOT", /* 6 IOT instruction */
+"SIGEMT", /* 7 EMT instruction */
+"SIGFPE", /* 8 floating point exception */
+"SIGKILL", /* 9 kill (cannot be caught or ignored) */
+"SIGBUS", /* 10 bus error */
+"SIGSEGV", /* 11 segmentation violation */
+"SIGSYS", /* 12 bad argument to system call */
+"SIGPIPE", /* 13 write on a pipe with no one to read it */
+"SIGALRM", /* 14 alarm clock */
+"SIGTERM", /* 15 software termination signal from kill */
+"SIGURG", /* 16 urgent condition on IO channel */
+"SIGSTOP", /* 17 sendable stop signal not from tty */
+"SIGTSTP", /* 18 stop signal from tty */
+"SIGCONT", /* 19 continue a stopped process */
+"SIGCHLD", /* 20 to parent on child stop or exit */
+"SIGTTIN", /* 21 to readers pgrp upon background tty read */
+"SIGTTOU", /* 22 like TTIN for output if (tp->t_local&LTOSTOP) */
+"SIGIO", /* 23 input/output possible signal */
+"SIGXCPU", /* 24 exceeded CPU time limit */
+"SIGXFSZ", /* 25 exceeded file size limit */
+"SIGVTALRM",/* 26 virtual time alarm */
+"SIGPROF", /* 27 profiling time alarm */
+"","","","" };
+
+#else BSD /* for system V? */
+
+static char *signame[NSIG] = { "",
+"SIGHUP", /* 1 hangup */
+"SIGINT", /* 2 interrupt */
+"SIGQUIT", /* 3 quit */
+"SIGILL", /* 4 illegal instruction (not reset when caught) */
+"SIGTRAP", /* 5 trace trap (not reset when caught) */
+"SIGIOT", /* 6 IOT instruction */
+"SIGEMT", /* 7 EMT instruction */
+"SIGFPE", /* 8 floating point exception */
+"SIGKILL", /* 9 kill (cannot be caught or ignored) */
+"SIGBUS", /* 10 bus error */
+"SIGSEGV", /* 11 segmentation violation */
+"SIGSYS", /* 12 bad argument to system call */
+"SIGPIPE", /* 13 write on a pipe with no one to read it */
+"SIGALRM", /* 14 alarm clock */
+"SIGTERM", /* 15 software termination signal from kill */
+"SIGUSR1", /* 16 user defines signal 1 */
+"SIGUSR2", /* 17 user defines signal 2 */
+"SIGCLD", /* 18 child death */
+"SIGPWR", /* 19 power fail */
+"","","","","","","","","","","","" };
+
+#endif BSD
+
+/*
+ * routine to process a fatal error signal
+ */
+static void
+sigpanic(sig)
+ int sig;
+ {
+ char buf[128];
+ signal(sig,SIG_DFL);
+ sprintf(buf,"\nLarn - Panic! Signal %d received [%s]",sig,signame[sig]);
+ write(2,buf,strlen(buf)); sleep(2);
+ sncbr();
+ savegame(savefilename);
+ kill(getpid(),sig); /* this will terminate us */
+ }
diff --git a/games/larn/store.c b/games/larn/store.c
new file mode 100644
index 0000000..904cfad
--- /dev/null
+++ b/games/larn/store.c
@@ -0,0 +1,691 @@
+/*-
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)store.c 5.4 (Berkeley) 5/13/91";
+#endif /* not lint */
+
+/* store.c Larn is copyrighted 1986 by Noah Morgan. */
+#include "header.h"
+static int dndcount=0,dnditm=0;
+
+/* this is the data for the stuff in the dnd store */
+int maxitm=83; /* number of items in the dnd inventory table */
+struct _itm itm[90] = {
+/*cost memory iven name iven arg how
+ gp pointer iven[] ivenarg[] many */
+
+{ 2, 0, OLEATHER, 0, 3 },
+{ 10, 0, OSTUDLEATHER, 0, 2 },
+{ 40, 0, ORING, 0, 2 },
+{ 85, 0, OCHAIN, 0, 2 },
+{ 220, 0, OSPLINT, 0, 1 },
+{ 400, 0, OPLATE, 0, 1 },
+{ 900, 0, OPLATEARMOR, 0, 1 },
+{ 2600, 0, OSSPLATE, 0, 1 },
+{ 150, 0, OSHIELD, 0, 1 },
+
+/*cost memory iven name iven arg how
+ gp pointer iven[] ivenarg[] many */
+
+{ 2, 0, ODAGGER, 0, 3 },
+{ 20, 0, OSPEAR, 0, 3 },
+{ 80, 0, OFLAIL, 0, 2 },
+{ 150, 0, OBATTLEAXE, 0, 2 },
+{ 450, 0, OLONGSWORD, 0, 2 },
+{ 1000, 0, O2SWORD, 0, 2 },
+{ 5000, 0, OSWORD, 0, 1 },
+{ 16500, 0, OLANCE, 0, 1 },
+{ 6000, 0, OSWORDofSLASHING, 0, 0 },
+{ 10000, 0, OHAMMER, 0, 0 },
+
+/*cost memory iven name iven arg how
+ gp pointer iven[] ivenarg[] many */
+
+{ 150, 0, OPROTRING, 1, 1 },
+{ 85, 0, OSTRRING, 1, 1 },
+{ 120, 0, ODEXRING, 1, 1 },
+{ 120, 0, OCLEVERRING, 1, 1 },
+{ 180, 0, OENERGYRING, 0, 1 },
+{ 125, 0, ODAMRING, 0, 1 },
+{ 220, 0, OREGENRING, 0, 1 },
+{ 1000, 0, ORINGOFEXTRA, 0, 1 },
+
+{ 280, 0, OBELT, 0, 1 },
+
+{ 400, 0, OAMULET, 0, 1 },
+
+{ 6500, 0, OORBOFDRAGON, 0, 0 },
+{ 5500, 0, OSPIRITSCARAB, 0, 0 },
+{ 5000, 0, OCUBEofUNDEAD, 0, 0 },
+{ 6000, 0, ONOTHEFT, 0, 0 },
+
+{ 590, 0, OCHEST, 6, 1 },
+{ 200, 0, OBOOK, 8, 1 },
+{ 10, 0, OCOOKIE, 0, 3 },
+
+/*cost memory iven name iven arg how
+ gp pointer iven[] ivenarg[] many */
+
+{ 20, potionname, OPOTION, 0, 6 },
+{ 90, potionname, OPOTION, 1, 5 },
+{ 520, potionname, OPOTION, 2, 1 },
+{ 100, potionname, OPOTION, 3, 2 },
+{ 50, potionname, OPOTION, 4, 2 },
+{ 150, potionname, OPOTION, 5, 2 },
+{ 70, potionname, OPOTION, 6, 1 },
+{ 30, potionname, OPOTION, 7, 7 },
+{ 200, potionname, OPOTION, 8, 1 },
+{ 50, potionname, OPOTION, 9, 1 },
+{ 80, potionname, OPOTION, 10, 1 },
+
+/*cost memory iven name iven arg how
+ gp pointer iven[] ivenarg[] many */
+
+{ 30, potionname, OPOTION, 11, 3 },
+{ 20, potionname, OPOTION, 12, 5 },
+{ 40, potionname, OPOTION, 13, 3 },
+{ 35, potionname, OPOTION, 14, 2 },
+{ 520, potionname, OPOTION, 15, 1 },
+{ 90, potionname, OPOTION, 16, 2 },
+{ 200, potionname, OPOTION, 17, 2 },
+{ 220, potionname, OPOTION, 18, 4 },
+{ 80, potionname, OPOTION, 19, 6 },
+{ 370, potionname, OPOTION, 20, 3 },
+{ 50, potionname, OPOTION, 22, 1 },
+{ 150, potionname, OPOTION, 23, 3 },
+
+/*cost memory iven name iven arg how
+ gp pointer iven[] ivenarg[] many */
+
+{ 100, scrollname, OSCROLL, 0, 2 },
+{ 125, scrollname, OSCROLL, 1, 2 },
+{ 60, scrollname, OSCROLL, 2, 4 },
+{ 10, scrollname, OSCROLL, 3, 4 },
+{ 100, scrollname, OSCROLL, 4, 3 },
+{ 200, scrollname, OSCROLL, 5, 2 },
+{ 110, scrollname, OSCROLL, 6, 1 },
+{ 500, scrollname, OSCROLL, 7, 2 },
+{ 200, scrollname, OSCROLL, 8, 2 },
+{ 250, scrollname, OSCROLL, 9, 4 },
+{ 20, scrollname, OSCROLL, 10, 5 },
+{ 30, scrollname, OSCROLL, 11, 3 },
+
+/*cost memory iven name iven arg how
+ gp pointer iven[] ivenarg[] many */
+
+{ 340, scrollname, OSCROLL, 12, 1 },
+{ 340, scrollname, OSCROLL, 13, 1 },
+{ 300, scrollname, OSCROLL, 14, 2 },
+{ 400, scrollname, OSCROLL, 15, 2 },
+{ 500, scrollname, OSCROLL, 16, 2 },
+{ 1000, scrollname, OSCROLL, 17, 1 },
+{ 500, scrollname, OSCROLL, 18, 1 },
+{ 340, scrollname, OSCROLL, 19, 2 },
+{ 220, scrollname, OSCROLL, 20, 3 },
+{ 3900, scrollname, OSCROLL, 21, 0 },
+{ 610, scrollname, OSCROLL, 22, 1 },
+{ 3000, scrollname, OSCROLL, 23, 0 }
+ };
+
+/*
+ function for the dnd store
+ */
+dnd_2hed()
+ {
+ lprcat("Welcome to the Larn Thrift Shoppe. We stock many items explorers find useful\n");
+ lprcat(" in their adventures. Feel free to browse to your hearts content.\n");
+ lprcat("Also be advised, if you break 'em, you pay for 'em.");
+ }
+
+static void dnditem();
+
+dnd_hed()
+ {
+ register int i;
+ for (i=dnditm; i<26+dnditm; i++) dnditem(i);
+ cursor(50,18); lprcat("You have ");
+ }
+
+static void
+handsfull()
+{
+ lprcat("\nYou can't carry anything more!");
+ lflush();
+ nap(2200);
+}
+
+static void
+outofstock()
+{
+ lprcat("\nSorry, but we are out of that item.");
+ lflush();
+ nap(2200);
+}
+
+static void nogold()
+{
+ lprcat("\nYou don't have enough gold to pay for that!");
+ lflush();
+ nap(2200);
+}
+
+dndstore()
+ {
+ register int i;
+ dnditm = 0;
+ nosignal = 1; /* disable signals */
+ clear(); dnd_2hed();
+ if (outstanding_taxes>0)
+ {
+ lprcat("\n\nThe Larn Revenue Service has ordered us to not do business with tax evaders.\n"); beep();
+ lprintf("They have also told us that you owe %d gp in back taxes, and as we must\n",(long)outstanding_taxes);
+ lprcat("comply with the law, we cannot serve you at this time. Soo Sorry.\n");
+ cursors();
+ lprcat("\nPress "); standout("escape"); lprcat(" to leave: "); lflush();
+ i=0;
+ while (i!='\33') i=getchar();
+ drawscreen(); nosignal = 0; /* enable signals */ return;
+ }
+
+ dnd_hed();
+ while (1)
+ {
+ cursor(59,18); lprintf("%d gold pieces",(long)c[GOLD]);
+ cltoeoln(); cl_dn(1,20); /* erase to eod */
+ lprcat("\nEnter your transaction ["); standout("space");
+ lprcat(" for more, "); standout("escape");
+ lprcat(" to leave]? ");
+ i=0;
+ while ((i<'a' || i>'z') && (i!=' ') && (i!='\33') && (i!=12)) i=getchar();
+ if (i==12) { clear(); dnd_2hed(); dnd_hed(); }
+ else if (i=='\33')
+ { drawscreen(); nosignal = 0; /* enable signals */ return; }
+ else if (i==' ')
+ {
+ cl_dn(1,4);
+ if ((dnditm += 26) >= maxitm) dnditm=0; dnd_hed();
+ }
+ else
+ { /* buy something */
+ lprc(i); /* echo the byte */
+ i += dnditm - 'a';
+ if (i>=maxitm) outofstock(); else
+ if (itm[i].qty <= 0) outofstock(); else
+ if (pocketfull()) handsfull(); else
+ if (c[GOLD] < itm[i].price*10) nogold(); else
+ {
+ if (itm[i].mem != 0) *itm[i].mem[itm[i].arg] = ' ';
+ c[GOLD] -= itm[i].price*10;
+ itm[i].qty--; take(itm[i].obj,itm[i].arg);
+ if (itm[i].qty==0) dnditem(i); nap(1001);
+ }
+ }
+
+ }
+ }
+
+/*
+ dnditem(index)
+
+ to print the item list; used in dndstore() enter with the index into itm
+ */
+static void
+dnditem(i)
+ register int i;
+ {
+ register int j,k;
+ if (i >= maxitm) return;
+ cursor( (j=(i&1)*40+1) , (k=((i%26)>>1)+5) );
+ if (itm[i].qty == 0) { lprintf("%39s",""); return; }
+ lprintf("%c) ",(i%26)+'a');
+ if (itm[i].obj == OPOTION)
+ { lprcat("potion of "); lprintf("%s",&potionname[itm[i].arg][1]); }
+ else if (itm[i].obj == OSCROLL)
+ { lprcat("scroll of "); lprintf("%s",&scrollname[itm[i].arg][1]); }
+ else lprintf("%s",objectname[itm[i].obj]);
+ cursor( j+31,k ); lprintf("%6d",(long)(itm[i].price*10));
+ }
+
+
+/*
+ for the college of larn
+ */
+char course[26]={0}; /* the list of courses taken */
+char coursetime[] = { 10, 15, 10, 20, 10, 10, 10, 5 };
+/*
+ function to display the header info for the school
+ */
+sch_hed()
+ {
+ clear();
+ lprcat("The College of Larn offers the exciting opportunity of higher education to\n");
+ lprcat("all inhabitants of the caves. Here is a list of the class schedule:\n\n\n");
+ lprcat("\t\t Course Name \t Time Needed\n\n");
+
+ if (course[0]==0) lprcat("\t\ta) Fighters Training I 10 mobuls"); /*line 7 of crt*/
+ lprc('\n');
+ if (course[1]==0) lprcat("\t\tb) Fighters Training II 15 mobuls");
+ lprc('\n');
+ if (course[2]==0) lprcat("\t\tc) Introduction to Wizardry 10 mobuls");
+ lprc('\n');
+ if (course[3]==0) lprcat("\t\td) Applied Wizardry 20 mobuls");
+ lprc('\n');
+ if (course[4]==0) lprcat("\t\te) Behavioral Psychology 10 mobuls");
+ lprc('\n');
+ if (course[5]==0) lprcat("\t\tf) Faith for Today 10 mobuls");
+ lprc('\n');
+ if (course[6]==0) lprcat("\t\tg) Contemporary Dance 10 mobuls");
+ lprc('\n');
+ if (course[7]==0) lprcat("\t\th) History of Larn 5 mobuls");
+
+ lprcat("\n\n\t\tAll courses cost 250 gold pieces.");
+ cursor(30,18);
+ lprcat("You are presently carrying ");
+ }
+
+oschool()
+ {
+ register int i;
+ long time_used;
+ nosignal = 1; /* disable signals */
+ sch_hed();
+ while (1)
+ {
+ cursor(57,18); lprintf("%d gold pieces. ",(long)c[GOLD]); cursors();
+ lprcat("\nWhat is your choice ["); standout("escape");
+ lprcat(" to leave] ? "); yrepcount=0;
+ i=0; while ((i<'a' || i>'h') && (i!='\33') && (i!=12)) i=getchar();
+ if (i==12) { sch_hed(); continue; }
+ else if (i=='\33')
+ { nosignal = 0; drawscreen(); /* enable signals */ return; }
+ lprc(i);
+ if (c[GOLD] < 250) nogold(); else
+ if (course[i-'a'])
+ { lprcat("\nSorry, but that class is filled."); nap(1000); }
+ else
+ if (i <= 'h')
+ {
+ c[GOLD] -= 250; time_used=0;
+ switch(i)
+ {
+ case 'a': c[STRENGTH] += 2; c[CONSTITUTION]++;
+ lprcat("\nYou feel stronger!");
+ cl_line(16,7);
+ break;
+
+ case 'b': if (course[0]==0)
+ {
+ lprcat("\nSorry, but this class has a prerequisite of Fighters Training I");
+ c[GOLD]+=250; time_used= -10000; break;
+ }
+ lprcat("\nYou feel much stronger!");
+ cl_line(16,8);
+ c[STRENGTH] += 2; c[CONSTITUTION] += 2; break;
+
+ case 'c': c[INTELLIGENCE] += 2;
+ lprcat("\nThe task before you now seems more attainable!");
+ cl_line(16,9); break;
+
+ case 'd': if (course[2]==0)
+ {
+ lprcat("\nSorry, but this class has a prerequisite of Introduction to Wizardry");
+ c[GOLD]+=250; time_used= -10000; break;
+ }
+ lprcat("\nThe task before you now seems very attainable!");
+ cl_line(16,10);
+ c[INTELLIGENCE] += 2; break;
+
+ case 'e': c[CHARISMA] += 3;
+ lprcat("\nYou now feel like a born leader!");
+ cl_line(16,11); break;
+
+ case 'f': c[WISDOM] += 2;
+ lprcat("\nYou now feel more confident that you can find the potion in time!");
+ cl_line(16,12); break;
+
+ case 'g': c[DEXTERITY] += 3;
+ lprcat("\nYou feel like dancing!");
+ cl_line(16,13); break;
+
+ case 'h': c[INTELLIGENCE]++;
+ lprcat("\nYour instructor told you that the Eye of Larn is rumored to be guarded\n");
+ lprcat("by a platinum dragon who possesses psionic abilities. ");
+ cl_line(16,14); break;
+ }
+ time_used += coursetime[i-'a']*100;
+ if (time_used > 0)
+ {
+ gtime += time_used;
+ course[i-'a']++; /* remember that he has taken that course */
+ c[HP] = c[HPMAX]; c[SPELLS] = c[SPELLMAX]; /* he regenerated */
+
+ if (c[BLINDCOUNT]) c[BLINDCOUNT]=1; /* cure blindness too! */
+ if (c[CONFUSE]) c[CONFUSE]=1; /* end confusion */
+ adjtime((long)time_used); /* adjust parameters for time change */
+ }
+ nap(1000);
+ }
+ }
+ }
+
+/*
+ * for the first national bank of Larn
+ */
+int lasttime=0; /* last time he was in bank */
+static void banktitle();
+
+obank()
+ {
+ banktitle(" Welcome to the First National Bank of Larn.");
+ }
+obank2()
+ {
+ banktitle("Welcome to the 5th level branch office of the First National Bank of Larn.");
+ }
+static void
+banktitle(str)
+ char *str;
+ {
+ nosignal = 1; /* disable signals */
+ clear(); lprcat(str);
+ if (outstanding_taxes>0)
+ {
+ register int i;
+ lprcat("\n\nThe Larn Revenue Service has ordered that your account be frozen until all\n"); beep();
+ lprintf("levied taxes have been paid. They have also told us that you owe %d gp in\n",(long)outstanding_taxes);
+ lprcat("taxes, and we must comply with them. We cannot serve you at this time. Sorry.\n");
+ lprcat("We suggest you go to the LRS office and pay your taxes.\n");
+ cursors();
+ lprcat("\nPress "); standout("escape"); lprcat(" to leave: "); lflush();
+ i=0;
+ while (i!='\33') i=getchar();
+ drawscreen(); nosignal = 0; /* enable signals */ return;
+ }
+ lprcat("\n\n\tGemstone\t Appraisal\t\tGemstone\t Appraisal");
+ obanksub(); nosignal = 0; /* enable signals */
+ drawscreen();
+ }
+
+/*
+ * function to put interest on your bank account
+ */
+ointerest()
+ {
+ register int i;
+ if (c[BANKACCOUNT]<0) c[BANKACCOUNT] = 0;
+ else if ((c[BANKACCOUNT]>0) && (c[BANKACCOUNT]<500000))
+ {
+ i = (gtime-lasttime)/100; /* # mobuls elapsed */
+ while ((i-- > 0) && (c[BANKACCOUNT]<500000))
+ c[BANKACCOUNT] += c[BANKACCOUNT]/250;
+ if (c[BANKACCOUNT]>500000) c[BANKACCOUNT]=500000; /* interest limit */
+ }
+ lasttime = (gtime/100)*100;
+ }
+
+static short gemorder[26]={0}; /* the reference to screen location for each */
+static long gemvalue[26]={0}; /* the appraisal of the gems */
+obanksub()
+ {
+ unsigned long amt;
+ register int i,k;
+ ointerest(); /* credit any needed interest */
+
+ for (k=i=0; i<26; i++)
+ switch(iven[i])
+ {
+ case OLARNEYE: case ODIAMOND: case OEMERALD:
+ case ORUBY: case OSAPPHIRE:
+
+ if (iven[i]==OLARNEYE)
+ {
+ gemvalue[i]=250000-((gtime*7)/100)*100;
+ if (gemvalue[i]<50000) gemvalue[i]=50000;
+ }
+ else gemvalue[i] = (255&ivenarg[i])*100;
+ gemorder[i]=k;
+ cursor( (k%2)*40+1 , (k>>1)+4 );
+ lprintf("%c) %s",i+'a',objectname[iven[i]]);
+ cursor( (k%2)*40+33 , (k>>1)+4 );
+ lprintf("%5d",(long)gemvalue[i]); k++;
+ };
+ cursor(31,17); lprintf("You have %8d gold pieces in the bank.",(long)c[BANKACCOUNT]);
+ cursor(40,18); lprintf("You have %8d gold pieces",(long)c[GOLD]);
+ if (c[BANKACCOUNT]+c[GOLD] >= 500000)
+ lprcat("\nNote: Larndom law states that only deposits under 500,000gp can earn interest.");
+ while (1)
+ {
+ cl_dn(1,20);
+ lprcat("\nYour wish? [("); standout("d"); lprcat(") deposit, (");
+ standout("w"); lprcat(") withdraw, ("); standout("s");
+ lprcat(") sell a stone, or "); standout("escape"); lprcat("] ");
+ yrepcount=0;
+ i=0; while (i!='d' && i!='w' && i!='s' && i!='\33') i=getchar();
+ switch(i)
+ {
+ case 'd': lprcat("deposit\nHow much? "); amt = readnum((long)c[GOLD]);
+ if (amt<0) { lprcat("\nSorry, but we can't take negative gold!"); nap(2000); amt=0; } else
+ if (amt>c[GOLD])
+ { lprcat(" You don't have that much."); nap(2000); }
+ else { c[GOLD] -= amt; c[BANKACCOUNT] += amt; }
+ break;
+
+ case 'w': lprcat("withdraw\nHow much? "); amt = readnum((long)c[BANKACCOUNT]);
+ if (amt<0) { lprcat("\nSorry, but we don't have any negative gold!"); nap(2000); amt=0; }
+ else if (amt > c[BANKACCOUNT])
+ { lprcat("\nYou don't have that much in the bank!"); nap(2000); }
+ else { c[GOLD] += amt; c[BANKACCOUNT] -= amt; }
+ break;
+
+ case 's': lprcat("\nWhich stone would you like to sell? ");
+ i=0; while ((i<'a' || i>'z') && i!='*') i=getchar();
+ if (i=='*')
+ for (i=0; i<26; i++)
+ {
+ if (gemvalue[i])
+ {
+ c[GOLD]+=gemvalue[i]; iven[i]=0;
+ gemvalue[i]=0; k = gemorder[i];
+ cursor( (k%2)*40+1 , (k>>1)+4 );
+ lprintf("%39s","");
+ }
+ }
+ else
+ {
+ if (gemvalue[i=i-'a']==0)
+ {
+ lprintf("\nItem %c is not a gemstone!",i+'a');
+ nap(2000); break;
+ }
+ c[GOLD]+=gemvalue[i]; iven[i]=0;
+ gemvalue[i]=0; k = gemorder[i];
+ cursor( (k%2)*40+1 , (k>>1)+4 ); lprintf("%39s","");
+ }
+ break;
+
+ case '\33': return;
+ };
+ cursor(40,17); lprintf("%8d",(long)c[BANKACCOUNT]);
+ cursor(49,18); lprintf("%8d",(long)c[GOLD]);
+ }
+ }
+
+/*
+ subroutine to appraise any stone for the bank
+ */
+appraise(gemstone)
+ register int gemstone;
+ {
+ register int j,amt;
+ for (j=0; j<26; j++)
+ if (iven[j]==gemstone)
+ {
+ lprintf("\nI see you have %s",objectname[gemstone]);
+ if (gemstone==OLARNEYE) lprcat(" I must commend you. I didn't think\nyou could get it.");
+ lprcat(" Shall I appraise it for you? "); yrepcount=0;
+ if (getyn()=='y')
+ {
+ lprcat("yes.\n Just one moment please \n"); nap(1000);
+ if (gemstone==OLARNEYE)
+ {
+ amt = 250000-((gtime*7)/100)*100;
+ if (amt<50000) amt=50000;
+ }
+ else amt = (255 & ivenarg[j]) * 100;
+ lprintf("\nI can see this is an excellent stone, It is worth %d",(long)amt);
+ lprcat("\nWould you like to sell it to us? "); yrepcount=0;
+ if (getyn()=='y') { lprcat("yes\n"); c[GOLD]+=amt; iven[j]=0; }
+ else lprcat("no thank you.\n");
+ if (gemstone==OLARNEYE) lprcat("It is, of course, your privilege to keep the stone\n");
+ }
+ else lprcat("no\nO. K.\n");
+ }
+ }
+/*
+ function for the trading post
+ */
+static otradhead()
+ {
+ clear();
+ lprcat("Welcome to the Larn Trading Post. We buy items that explorers no longer find\n");
+ lprcat("useful. Since the condition of the items you bring in is not certain,\n");
+ lprcat("and we incur great expense in reconditioning the items, we usually pay\n");
+ lprcat("only 20% of their value were they to be new. If the items are badly\n");
+ lprcat("damaged, we will pay only 10% of their new value.\n\n");
+ }
+
+otradepost()
+ {
+ register int i,j,value,isub,izarg;
+ dnditm = dndcount = 0;
+ nosignal = 1; /* disable signals */
+ resetscroll(); otradhead();
+ while (1)
+ {
+ lprcat("\nWhat item do you want to sell to us ["); standout("*");
+ lprcat(" for list, or "); standout("escape"); lprcat("] ? ");
+ i=0; while (i>'z' || (i<'a' && i!='*' && i!='\33' && i!='.')) i=getchar();
+ if (i == '\33')
+ { setscroll(); recalc(); drawscreen(); nosignal=0; /* enable signals */ return; }
+ isub = i - 'a'; j=0;
+ if (iven[isub]==OSCROLL) if (scrollname[ivenarg[isub]][0]==0)
+ { j=1; cnsitm(); } /* can't sell unidentified item */
+ if (iven[isub]==OPOTION) if (potionname[ivenarg[isub]][0]==0)
+ { j=1; cnsitm(); } /* can't sell unidentified item */
+ if (!j)
+ if (i=='*') { clear(); qshowstr(); otradhead(); }
+ else if (iven[isub]==0) lprintf("\nYou don't have item %c!",isub+'a');
+ else
+ {
+ for (j=0; j<maxitm; j++)
+ if ((itm[j].obj == iven[isub]) || (iven[isub] == ODIAMOND) || (iven[isub] == ORUBY) || (iven[isub] == OEMERALD) || (iven[isub] == OSAPPHIRE))
+ {
+ srcount=0; show3(isub); /* show what the item was */
+ if ((iven[isub] == ODIAMOND) || (iven[isub] == ORUBY)
+ || (iven[isub] == OEMERALD) || (iven[isub] == OSAPPHIRE))
+ value = 20*ivenarg[isub];
+ else
+ if ((itm[j].obj == OSCROLL) || (itm[j].obj == OPOTION)) value = 2*itm[j+ivenarg[isub]].price;
+ else
+ {
+ izarg=ivenarg[isub]; value = itm[j].price; /* appreciate if a +n object */
+ if (izarg >= 0) value *= 2;
+ while ((izarg-- > 0) && ((value=14*(67+value)/10) < 500000));
+ }
+ lprintf("\nItem (%c) is worth %d gold pieces to us. Do you want to sell it? ",i,(long)value);
+ yrepcount=0;
+ if (getyn()=='y')
+ {
+ lprcat("yes\n"); c[GOLD]+=value;
+ if (c[WEAR] == isub) c[WEAR] = -1;
+ if (c[WIELD] == isub) c[WIELD] = -1;
+ if (c[SHIELD] == isub) c[SHIELD] = -1;
+ adjustcvalues(iven[isub],ivenarg[isub]);
+ iven[isub]=0;
+ }
+ else lprcat("no thanks.\n");
+ j = maxitm+100; /* get out of the inner loop */
+ }
+ if (j <= maxitm+2) lprcat("\nSo sorry, but we are not authorized to accept that item.");
+ }
+ }
+ }
+
+cnsitm()
+ { lprcat("\nSorry, we can't accept unidentified objects."); }
+
+/*
+ * for the Larn Revenue Service
+ */
+olrs()
+ {
+ register int i,first;
+ unsigned long amt;
+ first = nosignal = 1; /* disable signals */
+ clear(); resetscroll(); cursor(1,4);
+ lprcat("Welcome to the Larn Revenue Service district office. How can we help you?");
+ while (1)
+ {
+ if (first) { first=0; goto nxt; }
+ cursors();
+ lprcat("\n\nYour wish? [(");
+ standout("p");
+ lprcat(") pay taxes, or ");
+ standout("escape");
+ lprcat("] "); yrepcount=0;
+ i=0; while (i!='p' && i!='\33') i=getchar();
+ switch(i)
+ {
+ case 'p': lprcat("pay taxes\nHow much? "); amt = readnum((long)c[GOLD]);
+ if (amt<0) { lprcat("\nSorry, but we can't take negative gold\n"); amt=0; } else
+ if (amt>c[GOLD]) lprcat(" You don't have that much.\n");
+ else c[GOLD] -= paytaxes((long)amt);
+ break;
+
+ case '\33': nosignal = 0; /* enable signals */
+ setscroll(); drawscreen(); return;
+ };
+
+nxt: cursor(1,6);
+ if (outstanding_taxes>0)
+ lprintf("You presently owe %d gp in taxes. ",(long)outstanding_taxes);
+ else
+ lprcat("You do not owe us any taxes. ");
+ cursor(1,8);
+ if (c[GOLD]>0)
+ lprintf("You have %6d gp. ",(long)c[GOLD]);
+ else
+ lprcat("You have no gold pieces. ");
+ }
+ }
diff --git a/games/larn/tok.c b/games/larn/tok.c
new file mode 100644
index 0000000..ee4039b
--- /dev/null
+++ b/games/larn/tok.c
@@ -0,0 +1,218 @@
+/* tok.c Larn is copyrighted 1986 by Noah Morgan. */
+#include <sys/types.h>
+#ifdef SYSV
+#include <fcntl.h>
+#include <termio.h>
+#else SYSV
+#include <sys/ioctl.h>
+#endif SYSV
+#include "header.h"
+
+static char lastok=0;
+int yrepcount=0,dayplay=0;
+#ifndef FLUSHNO
+#define FLUSHNO 5
+#endif FLUSHNO
+static int flushno=FLUSHNO; /* input queue flushing threshold */
+#define MAXUM 52 /* maximum number of user re-named monsters */
+#define MAXMNAME 40 /* max length of a monster re-name */
+static char usermonster[MAXUM][MAXMNAME]; /* the user named monster name goes here */
+static char usermpoint=0; /* the user monster pointer */
+
+/*
+ lexical analyzer for larn
+ */
+yylex()
+ {
+ char cc;
+ int ic;
+ if (hit2flag) { hit2flag=0; yrepcount=0; return(' '); }
+ if (yrepcount>0) { --yrepcount; return(lastok); } else yrepcount=0;
+ if (yrepcount==0) { bottomdo(); showplayer(); } /* show where the player is */
+ lflush();
+ while (1)
+ {
+ c[BYTESIN]++;
+ if (ckpflag)
+ if ((c[BYTESIN] % 400) == 0) /* check for periodic checkpointing */
+ {
+#ifndef DOCHECKPOINTS
+ savegame(ckpfile);
+#else
+ wait(0); /* wait for other forks to finish */
+ if (fork() == 0) { savegame(ckpfile); exit(); }
+#endif
+
+
+#ifdef TIMECHECK
+ if (dayplay==0)
+ if (playable())
+ {
+ cursor(1,19);
+ lprcat("\nSorry, but it is now time for work. Your game has been saved.\n"); beep();
+ lflush(); savegame(savefilename); wizard=nomove=1; sleep(4);
+ died(-257);
+ }
+#endif TIMECHECK
+
+ }
+
+ do /* if keyboard input buffer is too big, flush some of it */
+ {
+ ioctl(0,FIONREAD,&ic);
+ if (ic>flushno) read(0,&cc,1);
+ }
+ while (ic>flushno);
+
+ if (read(0,&cc,1) != 1) return(lastok = -1);
+
+ if (cc == 'Y'-64) /* control Y -- shell escape */
+ {
+ resetscroll(); clear(); /* scrolling region, home, clear, no attributes */
+ if ((ic=fork())==0) /* child */
+ {
+ execl("/bin/csh",0); exit();
+ }
+ wait(0);
+ if (ic<0) /* error */
+ {
+ write(2,"Can't fork off a shell!\n",25); sleep(2);
+ }
+
+ setscroll();
+ return(lastok = 'L'-64); /* redisplay screen */
+ }
+
+ if ((cc <= '9') && (cc >= '0'))
+ { yrepcount = yrepcount*10 + cc - '0'; }
+ else { if (yrepcount>0) --yrepcount; return(lastok = cc); }
+ }
+ }
+
+/*
+ * flushall() Function to flush all type-ahead in the input buffer
+ */
+flushall()
+ {
+ char cc;
+ int ic;
+ for (;;) /* if keyboard input buffer is too big, flush some of it */
+ {
+ ioctl(0,FIONREAD,&ic);
+ if (ic<=0) return;
+ while (ic>0) { read(0,&cc,1); --ic; } /* gobble up the byte */
+ }
+ }
+
+/*
+ function to set the desired hardness
+ enter with hard= -1 for default hardness, else any desired hardness
+ */
+sethard(hard)
+ int hard;
+ {
+ register int j,k,i;
+ j=c[HARDGAME]; hashewon();
+ if (restorflag==0) /* don't set c[HARDGAME] if restoring game */
+ {
+ if (hard >= 0) c[HARDGAME]= hard;
+ }
+ else c[HARDGAME]=j; /* set c[HARDGAME] to proper value if restoring game */
+
+ if (k=c[HARDGAME])
+ for (j=0; j<=MAXMONST+8; j++)
+ {
+ i = ((6+k)*monster[j].hitpoints+1)/6;
+ monster[j].hitpoints = (i<0) ? 32767 : i;
+ i = ((6+k)*monster[j].damage+1)/5;
+ monster[j].damage = (i>127) ? 127 : i;
+ i = (10*monster[j].gold)/(10+k);
+ monster[j].gold = (i>32767) ? 32767 : i;
+ i = monster[j].armorclass - k;
+ monster[j].armorclass = (i< -127) ? -127 : i;
+ i = (7*monster[j].experience)/(7+k) + 1;
+ monster[j].experience = (i<=0) ? 1 : i;
+ }
+ }
+
+/*
+ function to read and process the larn options file
+ */
+readopts()
+ {
+ register char *i;
+ register int j,k;
+ int flag;
+ flag=1; /* set to 0 if he specifies a name for his character */
+ if (lopen(optsfile) < 0)
+ {
+ strcpy(logname,loginname); return; /* user name if no character name */
+ }
+ i = " ";
+ while (*i)
+ {
+ if ((i=(char *)lgetw()) == 0) break; /* check for EOF */
+ while ((*i==' ') || (*i=='\t')) i++; /* eat leading whitespace */
+ switch(*i)
+ {
+ case 'b': if (strcmp(i,"bold-objects") == 0) boldon=1;
+ break;
+
+ case 'e': if (strcmp(i,"enable-checkpointing") == 0) ckpflag=1;
+ break;
+
+ case 'i': if (strcmp(i,"inverse-objects") == 0) boldon=0;
+ break;
+
+ case 'f': if (strcmp(i,"female") == 0) sex=0; /* male or female */
+ break;
+
+ case 'm': if (strcmp(i,"monster:")== 0) /* name favorite monster */
+ {
+ if ((i=lgetw())==0) break;
+ if (strlen(i)>=MAXMNAME) i[MAXMNAME-1]=0;
+ strcpy(usermonster[usermpoint],i);
+ if (usermpoint >= MAXUM) break; /* defined all of em */
+ if (isalpha(j=usermonster[usermpoint][0]))
+ {
+ for (k=1; k<MAXMONST+8; k++) /* find monster */
+ if (monstnamelist[k] == j)
+ {
+ monster[k].name = &usermonster[usermpoint++][0];
+ break;
+ }
+ }
+ }
+ else if (strcmp(i,"male") == 0) sex=1;
+ break;
+
+ case 'n': if (strcmp(i,"name:") == 0) /* defining players name */
+ {
+ if ((i=lgetw())==0) break;
+ if (strlen(i)>=LOGNAMESIZE) i[LOGNAMESIZE-1]=0;
+ strcpy(logname,i); flag=0;
+ }
+ else if (strcmp(i,"no-introduction") == 0) nowelcome=1;
+ else if (strcmp(i,"no-beep") == 0) nobeep=1;
+ break;
+
+ case 'p': if (strcmp(i,"process-name:")== 0)
+ {
+ if ((i=lgetw())==0) break;
+ if (strlen(i)>=PSNAMESIZE) i[PSNAMESIZE-1]=0;
+ strcpy(psname,i);
+ }
+ else if (strcmp(i,"play-day-play") == 0) dayplay=1;
+ break;
+
+ case 's': if (strcmp(i,"savefile:") == 0) /* defining savefilename */
+ {
+ if ((i=lgetw())==0) break;
+ strcpy(savefilename,i); flag=0;
+ }
+ break;
+ };
+ }
+ if (flag) strcpy(logname,loginname);
+ }
+
OpenPOWER on IntegriCloud