diff options
author | jkh <jkh@FreeBSD.org> | 1994-09-04 04:03:31 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1994-09-04 04:03:31 +0000 |
commit | 057afceb86e030ad65b0130436860d9a18066186 (patch) | |
tree | a0ced9c9b9278eb776d89cd2565c27ddcf020b51 /games/larn | |
parent | eedec95276cdb8aef98e92c5371000f10b8d6ba7 (diff) | |
download | FreeBSD-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')
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! + + + + + [4mHelp File for The Caverns of Larn[m + +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 + [7mSpecial Notes[m + +When [7mdropping gold[m, 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 [7mVT100[m to operate. A check is made of the environment variable +[7m"TERM"[m and it must be equal to [7m"vt100"[m. This only applies if +the game has been compiled with "VT100" defined in the Makefile. If compiled +to use [7mtermcap[m, there are no terminal restrictions, save needing cm, ce, & cl +termcap entries. + +When in the store, trading post, school, or home, an [7m<escape>[m 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 '[7mD[m' 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. + [7mBackground Information for Larn[m + + 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! + + + + [7mHow to use the .larnopts option file[m + +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. + + [7mExplanation of the Larn scoreboard facility[m + + 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<OSTOP) */ +"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); + } + |