lwall@sdcrdcf.UUCP (Larry Wall) (08/13/83)
WARP 6.0 DISTRIBUTION KIT (The last line of the kit should say "end of warp distribution kit". If it doesn't, you haven't got the whole thing. This file is ~123000 bytes.) Installation procedure: 1) Decide what uid you want warp to setuid to (NOT root). Choose a uid that nobody untrustworthy can log into, because warp uses only the setuid feature to protect its files--it does not encrypt anything, nor does it store anything in the user's directories (with the possible exception of the full name of the player). All of its files will be stored in the directory in which this distribution shell script is run, and will belong to the uid in force when the script is run. 2) Login to the uid you have chosen or created, and cd to a place where you don't mind creating a subdirectory, such as /usr/games. 3) Create a subdirectory called warplib, and cd to it. If you already have a warplib, you may reuse it, because this shell script will create a subdirectory whose name will be the version number. 4) Move everything after the line of asterisks below to a shell script file in warplib ("dist" would be a safe name), and chmod 700 dist. (If your distribution came in more than one hunk, append the additional hunks to the end of dist. Be sure delete the header down to the row of asterisks on any subsequent hunks as well as the first, or you may end up with peculiar-looking C.) 5) Execute dist, or whatever you have called it. It may ask you a few questions, depending on what it finds or doesn't find on your system. If you aren't sure of an answer, it's worth stopping to find out. You MUST execute dist in order for things to get configured right. About 1.5 persons out of 100 will try to take it apart by hand and then wonder why WARPDIR isn't defined. If dist doesn't run right because of a brain-damaged shell: -- if your shell doesn't understand # comments, delete them. -- if your shell doesn't like the syntax of something, say, a conditional, delete the conditional and substitute the intelligent thing. -- if the `pwd` doesn't insert the current directory name, put that in, wherever `pwd` occurs. -- if all else fails, and you MUST tear it apart by hand, then be sure to make all the proper substitutions in those parts that do variable substitution. 6) Do a make. (Dist will start it automatically if you tell it to.) 7) You should now have an executable file called warp. Link or copy it to wherever it will be executable by everyone, such as /usr/games. (Saying "make install" will attempt to put warp into /usr/games.) Ensure that the setuid bit stays set and that the file still belongs to the uid you originally selected. Ensure that the files in WARPDIR are NOT writeable by the world but that WARPDIR itself is u+rw o+rx and belongs to the correct uid. Note that WARPDIR is a subdirectory of warplib. 8) Play warp. If it doesn't produce reasonable star distributions (sometimes uniformly random, sometimes clumped, sometimes a predefined scenario) then perhaps your random number generator is not what warp expects. Ensure that warp has a random number generator that produces 31 bits worth of integer, i.e. numbers from 0 to 2**31-1, or that you have defined the RAND16 flag. Any strange random number generators that produce 17..30 bits should work if RAND16 is defined, since higher bits are discarded. 9) The system administrator should feel free to edit the warp.news file, which is printed whenever anyone starts warp. 10) If you have to take heroic measures to get warp to work on your system, and if there are other systems in the wide wide world like yours, then drop me a line giving the gory details, and I will try to incorporate them in the distribution kit. ******************************************************************************** #! /bin/sh wv='6.0' echo "Beginning installation of warp version $wv into "`pwd`"/$wv." echo "" if mkdir $wv then cd $wv else echo "Cannot create subdirectory $wv." if test -f $wv -o -d $wv then echo "Please rename the current $wv to something else and re-run." else if test ! -w . then echo "You can't write this directory. Please fix the problem and re-run." else echo "I can't tell what's wrong. Please fix the problem and re-run." fi fi exit 1 fi if test -r /usr/lib/libjobs.a then echo 'Job control found' jbs='-ljobs' else echo 'Job control not found--subshell substituted' jbs='' fi if test -r /usr/lib/libnm.a then echo 'nm library found' nm='-lnm' else echo 'nm library not found--normal math library will have to do' nm='' fi if test -r /usr/include/sys/timeb.h then echo 'ftime routine found' ftim='D' else echo 'ftime routine not found--you may have to use -l at low baud rates' ftim='U' fi echo "" echo "Please type y or n to the following questions:" echo "" echo "Some random number generators produce 16 bits, others 31 bits." echo "(If yours does neither, pretend like it does 16 for the moment." echo "Likewise if you can't find out easily, assume 16 bits and it should work.)" echo -n "Does your random number generator produce exactly 31 bits like Berkeley's? " read ans if test "$ans" = y then rnd='RAND31' else rnd='RAND16' fi echo "" echo "Does your passwd file keep full names in Berkeley format (name first" echo -n "thing after ':')? " read ans if test "$ans" = y then namalg=1 else echo "" echo "Does your passwd file keep full names in USG format (name sandwiched" echo -n "between a '-' and a '(')? " read ans if test "$ans" = y then namalg=2 else echo "Full name will be kept in ~/.fullname" namalg=3 fi fi if test "$namalg" != 3 then echo "" echo "The scoreboard can be kept with one score per login name, or one score" echo "per full name. If users can change their full name, or if there is" echo "more than one person on your system with the same full name, you should" echo "keep the score by login name (the full name is still printed)." echo -n "Do you want the scoreboard kept by full name? " read ans if test "$ans" = y then fullnam='D' else fullnam='U' fi else fullnam='U' fi # The make file # (does variable, command substitution at installation time) echo Installing Makefile cat >Makefile <<!STUFFY!FUNK! flags = -ltermlib $nm -lm $jbs -DWARPDIR=\"`pwd` -${ftim}FTIMER -D${rnd} moreflags = -DFNAMEALG=${namalg} -${fullnam}BYFULLNAME all: warp smap.0 smap.1 smap.2 smap.3 smap.4 smap.5 smap.6 smap.7 warp.6 echo "Warp make finished" warp: wtmp cat </dev/null >>warp.log cat </dev/null >>warp.top cat </dev/null >>warp.lowtop cat </dev/null >wart chmod 600 war? rm -f wart oldwarp cat </dev/null >>warp # The above ritual is supposed to prevent the next line from blowing up mv warp oldwarp mv wtmp warp chmod 4711 warp chmod 000 oldwarp wtmp: warp.c cc warp.c -o wtmp -n -O $(flags) $(moreflags) # It is my belief that -n implies -i for those who need separate I and D. # If this isn't true, put a -i above and tell me I'm all wet. smap.0: smp.0 sm sm <smp.0 >smap.0 smap.1: smp.1 sm sm <smp.1 >smap.1 smap.2: smp.2 sm sm <smp.2 >smap.2 smap.3: smp.3 sm sm <smp.3 >smap.3 smap.4: smp.4 sm sm <smp.4 >smap.4 smap.5: smp.5 sm sm <smp.5 >smap.5 smap.6: smp.6 sm sm <smp.6 >smap.6 smap.7: smp.7 sm sm <smp.7 >smap.7 sm: sm.c cc sm.c -o sm warp.6: warp.man nroff -man warp.man >warp.6 install: ln warp extralink mv extralink /usr/games/warp # The above should conserve disk space if we are in same filesystem, but # not blow up if we aren't. Of course, if we can't write /usr/games... !STUFFY!FUNK! # The manual page echo Installing warp.man cat >warp.man <<\!STUFFY!FUNK! .TH WARP 6 .SH NAME warp - a real-time space war game .SH SYNOPSIS .B warp [options] .SH DESCRIPTION .I Warp is a real-time space war game that requires skill and quick thinking. "Real-time" in this context means that the enemies keep moving (and shooting) even if you don't. A unique feature of .I warp is that blast propagates; it is unhealthy to remain near things that are in the process of blowing up. If a given universe is above a critical density it may chain react. Scoring is like many popular arcade games--there are multiple waves which get harder and harder as you go along. Nobody has ever maxed out the scoreboard without cheating. .PP Unlike many space-war games, .I warp is not simply a shooting gallery. Along with phasers and photon torpedoes, you have tractor beams and a cloaking device. Skill in navigation is important. It helps to be schizophrenic, because you must manage an Enterprise and a Base simultaneously. And enemies do not simply shoot back. You can get tailed, snuck up upon, hemmed in, rammed, loved to death, and eaten. And if you should happen to get bored by the enemies (not bl**dy likely!), you can always watch the interesting star patterns. In fact, you have to, since your tactics will depend upon what kind of universe you find yourself in. .PP .I Warp is played in a double wraparound universe, i.e. the bottom is connected to the top, and the right is connected to the left. You need a crt with random cursor addressing and at least 24 lines by 80 columns. For more information about about how to play, simply run .I warp and say "y" when it asks if you want to see the instructions. There is also a single-page command summary that you can get while playing by typing a "?". .PP Command line options include: .TP 5 .B -b Put .I warp into beginner mode. Makes the difficulty increase more slowly, but penalizes you for it. .TP 5 .B -d<n> Sets the initial difficulty to .BR n . .TP 5 .B -l Play a low-speed game. Changes the basic cycle time from 1 second to 2 seconds. This switch is automatically set at baud rates below 2400. You may want to set it at higher speeds if your terminal cannot keep up with the output. (This should never happen on BSD systems, which have an IOCTL call to determine output queue length.) Because this makes the game easier, a separate scoreboard is kept for low-speed games. .TP 5 .B -s Just prints out the scoreboards and saved games and then exits. .TP 5 .B -v Prints out the version number. .TP 5 .B -x Play an experimental game. This causes .I warp to ignore any saved game, and disables the ability to save the current game. Thus you can play around with something or show .I warp to someone without jeopardizing a currently saved game. .SH AUTHOR Larry Wall <lwall@sdcrdcf.UUCP> .SH FILES ~/.fullname, if full names aren't in /etc/passwd .SH DIAGNOSTICS Generally self-documenting, as they say. .SH BUGS Addicting. At the end of a wave, all you have to do to keep going is hit a space. You see the message "Hit space to continue" and automatically hit space. About 2 seconds later you remember you wanted to go home, but by then it's too late to escape without penalty. .PP You can't kill a backgrounded .I warp process directly, because it is running setuid. You have to use the killer built in to .IR warp . .PP There ought to be a space amoeba. !STUFFY!FUNK! # The help file echo Installing warp.doc cat >warp.doc <<\!STUFFY!FUNK! Warp is a real-time space war game. This means that the enemies will keep playing even when you sit still. Another peculiarity is that things which blow up can damage other things around them. Universes above a critical density may chain react. The game starts at difficulty 1, and gets more difficult with each succeeding wave, up to difficulty 99. You're not likely to get that far. (Invoking warp with a -b switch causes the difficulty to increase more slowly, but games count only a tenth as much.) The game starts with 5 Enterprises and 3 Bases, and you get more for surviving long enough. The game is over when you run out of Enterprises and Bases. The object of the game is to get as many points as possible. This is done by destroying as many enemies as possible. This is not a trivial task. Each wave starts with one Enterprise and one Base, and continues until either both the Enterprise and Base are destroyed, or all the enemies (including any homing torpedoes) are destroyed. It is possible to abort a wave, but you will be penalized for it. The game may be saved between waves. A -x switch causes any saved game to be ignored, and causes the new game not to be saveable. Hence it is possible to run test games without invalidating a currently saved game. The game is played in a 23 x 40 double wrap-around universe. Everybody (both you and the enemies) gets the chance to move once every second, unless a -l (low-speed) switch was given or you are under 2400 baud, in which case it's every two seconds. The following symbols are displayed: E,e Enterprise with/without shields C,c Cloaked Enterprise with/without shields B,b Base with/without shields K Klingon R Romulan Romulan with cloaking device! G Gorn T Tholian A Apollo < Planet crusher + Friendly torpedo x,X Hostile torpedo o,O Homing torpedo * Star @ Inhabited star |,-,/,\ Web The following keys control the DIRECTION of your various actions: h or 4 left j or 2 down k or 8 up l or 6 right b or 1 down and left n or 3 down and right y or 7 up and left u or 9 up and right (You will note that the letters are the same as rogue directions, and the numbers are for use with a keypad.) By themselves, these keys move either the Enterprise or the Base, whichever is the current vessel. When shifted, they fire photon torpedoes in the specified direction from the current vessel. When used with either the CTRL key or the FUNCT key, phasers (turbo-lasers for the Base) are fired in the specified direction. (CTRL won't work with numbers, and FUNCT probably doesn't exist on non-TVI terminals.) When preceded by an 'a', an attractor beam is fired in the specified direction, and when preceded by an 'r', a repulsor beam is fired. These keys have special functions: del or % fire photon torpedoes in every (reasonable) direction s stop all friendly torpedoes S or 0 stop the Enterprise when in warp mode d destruct all friendly torpedoes (quite useful) D destruct the current vessel (commit suicide) i switch to Enterprise and put into impulse mode w switch to Enterprise and put into warp mode c switch to Enterprise and put into cloaking mode v switch to Enterprise and put into visible mode p switch to Base (not very mnemonic, but 'b' is taken) o switch from Enterprise to Base, or vice versa ^R refresh the screen ^Z suspend the game (on a bsd system) q asks if you want to exit this wave (will not work within 10 cycles of previous q command) Q exit this game ? display a summary of these commands Unrecognized keystrokes are ignored. IF YOU FORGET ALL THE OTHER COMMANDS, REMEMBER "?". Commands for moving the Enterprise may operate in one of two ways. If it is in impulse mode, movement commands affect the position of the ship; if it is in warp mode, movement commands affect the velocity instead. The Base always moves in impulse mode. Since multiple commands may be entered in one turn (if you can type fast enough), it is possible to jump over things even in impulse mode. In a crowded universe this may be the only way to go. (Actually, motion commands always change the velocity--the actual motion does not occur until the next turn. Impulse mode simply causes the velocity to be zeroed out at the end of every turn. Phaser commands, on the other hand, are executed immediately. If you want to move and fire a phaser, you must wait for the motion to actually occur before typing the phaser command, or the phaser fires from your old position. This is a feature, not a bug, and is intended to reflect reality. Really.) If multiple torpedo launching commands are given in a turn, a single torpedo is launched with extra velocity. You can thus launch photon torpedoes over objects in the way, and get them where you want them quickly. This feature works well with the destruct button. NOTE: Phasers destroy the target by blasting the projected next location of the object hit. This means that if the object hit, be it Klingon, Romulan or Enterprise, changes velocity in the same turn, it can elude the effect of the phaser! (Note that this also means that if you phaser a Klingon or torpedo that is about to ram you, you will be phasered as well as he/she/it. This can be embarrassing, not to mention deadly.) Smart players move immediately upon phasering something at short range, or whenever they think they might get phasered (in other words, most of the time). Objects with larger mass can bounce objects with smaller mass out of the way. In a crowded universe the bouncee can bounce quite a way before finding an empty place to land. If you let the Tholians fill up the universe with web, so that there is no place to bounce to, the Tholians win that wave. The status line across the top gives the current mode, the number of points accumulated this wave, the Enterprise's energy and torpedoes, the Base's energy and torpedoes, the number of stars, the number of enemies, and the stardate. You will note that nice things happen to your energy levels when you put the Enterprise next to the Base, or the Base next to some stars. An object is destroyed when its energy goes negative, either from a direct hit, or from the blast of the previous turn's explosions. Enemies and stars start with random amounts of energy. High energy enemies can go warp 2. A Romulan with sufficient energy maintains a cloaking device. Tholians spin web, Gorns shoot homing torpedoes, and the Planet Crusher munches anything in its way, even Apollo. Apollo won't let you go unless you kill him, but he loves you very much and beefs up your shields considerably. Both Apollo and the Planet Crusher recharge themselves, so you must hit them hard in a single turn to do them in. (Yes, the Planet Crusher must be shot in the mouth--he can only die of gluttony--and he blasts out of his mouth when he dies.) Tholian web may be crossed only by coasting across it in warp mode, or by blasting it (but web blasts extend twice as far as normal blasts, so keep your distance). Note that because of the size of the Base's turbo-lasers (the Base does not have phasers) they cannot shoot anything next to the Base. (This is why the Death Star died!) In part, this is to protect the Enterprise. It also lets you shoot over one adjacent star. The Enterprise's phasers will shoot over a arbitrary number of adjacent, contiguous stars, including inhabited ones. Phasers die away with distance, so don't expect them to kill everything with one blow. While the Enterprise's shields are up (when it is displayed as "E" rather than "e"), hits on it count only a fifth as much (or even less if you are moving in warp mode). The shields are automatically maintained as long as there are more than 500 units of energy for the Enterprise. The Base also has shields, which stay up as long as it has at least 1000 units of energy. You get points for destroying enemies and hostile torpedoes. At the end of a wave, you also get bonus points for saving stars, saving the Enterprise and Base, and for having an efficiency rating higher that 0.8. You get NEGATIVE bonus points for letting inhabited stars get destroyed, and for giving up. Bonuses tend to be scaled by the ratio of the number of points you got over the number of points you could have got. If you think you are done with a wave, but it won't quit, there may be Gorn torpedoes that you haven't destroyed--you must make the universe safe for posterity, you know. When you have used up your Enterprises and Bases (or quit), your score will be posted to the scoreboard. You may see the scoreboard outside of the game simply by giving the command "warp -s". !STUFFY!FUNK! # A sample warp news file. Feel free to edit. echo Installing warp.news cat >warp.news <<\!STUFFY!FUNK! *** WARP NEWS *** Welcome to warp! Please send any gripes, comments, fantastic ideas, etc. to lwall@sdcrdcf.uucp (Larry Wall). !STUFFY!FUNK! # A program to translate starmaps from one form to another echo Installing sm.c cat >sm.c <<\!STUFFY!FUNK! #include <stdio.h> #include <ctype.h> main() { char screen[23][90], buf[10]; register int y, x; int tmpy, tmpx; for (x=0; x<79; x++) screen[0][x] = ' '; screen[0][79] = '\0'; fgets(screen[0],90,stdin); if (isdigit(screen[0][0])) { int numstars = atoi(screen[0]); for (y=0; y<23; y++) { for (x=0; x<79; x++) screen[y][x] = ' '; screen[y][79] = '\0'; } for ( ; numstars; numstars--) { scanf("%d %d\n",&tmpy,&tmpx); y = tmpy; x = tmpx; screen[y][x+x] = '*'; } for (y=0; y<23; y++) { printf("%s\n",screen[y]); } } else { register int numstars = 0; for (y=1; y<23; y++) { for (x=0; x<79; x++) screen[y][x] = ' '; screen[y][79] = '\0'; } for (y=1; y<23; y++) { fgets(screen[y],90,stdin); } for (y=0; y<23; y++) { for (x=0; x<80; x += 2) { if (screen[y][x] == '*') { numstars++; } else if (screen[y][x] == '\t' || screen[y][x+1] == '\t') { fprintf(stderr,"Cannot have tabs in starmap--please expand.\n"); exit(1); } } } printf("%d\n",numstars); for (y=0; y<23; y++) { for (x=0; x<80; x += 2) { if (screen[y][x] == '*') { printf("%d %d\n",y,x/2); } } } } exit(0); } !STUFFY!FUNK! # A scenario to encourage warp mode echo Installing smp.0 cat >smp.0 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # Another scenario to encourage warp mode echo Installing smp.1 cat >smp.1 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # A shooting gallery scenario echo Installing smp.2 cat >smp.2 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # A superfortress scenario echo Installing smp.3 cat >smp.3 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # block world echo Installing smp.4 cat >smp.4 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # A double fortress scenario echo Installing smp.5 cat >smp.5 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * !STUFFY!FUNK! # Eternal strait echo Installing smp.6 cat >smp.6 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # Eternal isthmus echo Installing smp.7 cat >smp.7 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # The program itself echo "Installing warp.c (the biggie)" cat >warp.c <<\!STUFFY!FUNK! static char warpid[] = "@(#)$Header: /ea/lwall/src/warp/warp.c%v 6.0 83/08/08 17:09:26 lwall Exp $"; /* warp -- a real-time space war program * author: Larry Wall * helpers: Jonathan and Mark Biggar * special thanks to my sweetie Gloria who suggested the Planet Crusher * and to Norman Azadian, who keeps asking embarrassing questions. * * Thanks also to that wonderful parallel processor, Usenet. * * Copyright 1983, Larry Wall * * This program may be copied as long as this copyright notice is * included, and as long as it is not being copied for purposes * of profit. If you want to modify this program in any way other * than normal configuration changes, common decency would suggest * that you also modify the name of the program so that my good name * (what there is of it) is not impugned. (Calling it something like * "warpx" or "superwarp" would be fine.) Also, give it another * WARPDIR so that the scoreboards don't get confused. * * version 5.0 04/20/83 * 5.1 05/05/83 various tidbits * 5.2 05/12/83 VAX -> vax, ifdef'ed a SIGCONT * 5.3 05/24/83 RCS * * $Log: /ea/lwall/src/warp/warp.c%v $ * Revision 6.0 83/08/08 17:09:26 lwall * New baseline version for net release. * * Revision 5.5 83/08/01 10:59:56 lwall * Cloaking for the Enterprise. * Difficulty now goes to 99, and many activities depending on difficulty * have been adjusted in frequency. * Simplified exit sequence, and reduced dependencies on control * characters. You needn't see the scoreboard if you don't want to. * Hitting i,w,c, or v switches to Enterprise. Hitting p switches to Base. * Excessive use of q is not allowed. * Excessive use of D is not allowed. * Scoreboard may depend on either full name or login name. * Integrated scoreboard lister. Login name now shows up on scoreboard. * "Hidden" startup options are now upper case. * Checks upon startup for no cursor movement, or screen too small. * Checks upon startup that WARPDIR is correctly protected, and that warp * is running setuid. As an additional bonus this prevents root from * running warp, which mucks things up, UN*X be blessed. * All gets's turned into fgets's for safety. * Bonus Enterprises and Bases. * Escalating bonuses for saving Base and Enterprise. * Escalating Enterprise energy. * Turbolasers decrease with distance. * Really smart enemies can see through stars occasionally. * Occasional Tholian jackpot waves. Tholians are a trifle nastier. * Choleric Gorns. * An O or o can miss seeing you. Enemies can avoid a stationary O, o, or X. * Warp 3 enemies and other nastinesses are possible in massacre mode. * Enemies that decide to navigate when they see you can do other things than * just come toward you. * Gorns occasionally launch a salvo for the fun of it. * Only star and enemy explosions can keep the round going now. * Bounces don't always go back to starting spot now. * Better full name processing. USG quirks handled. & substitution also * handled now (whoever dreamed up that one must have been in the middle * of the night before the morning after). * Catch ^D on fgets. * Version number printer. * Less signal catching during debugging. * * Revision 5.4 83/06/24 09:28:38 lwall * 16 bit random number generators are now supported. * Made warp not blow up on a null save file. * Warp now prints E and B before the stars. * Fixed bug which caused torp count to get decremented even when no torp * was launched because of an obstacle. * Put %<n>ld formats where appropriate. * Fixed E: 0 0 bug on refresh. * * Revision 5.3 83/05/24 14:03:10 lwall * Starting RCS * */ #include <stdio.h> #include <signal.h> #include <sgtty.h> #include <math.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #define bool char #define TRUE (1) #define FALSE (0) /* machine dependent stuff starts here */ #define HAVETERMLIB 1 #define TCSIZE 256 #ifdef FTIMER #include <sys/timeb.h> #endif /* WARPDIR must be readable and writeable by warp, but not by anyone who you * don't trust. In other words, to set up warp so everyone can play and * no one can cheat, give warp a uid of its own and make warp setuid to * that uid. WARPDIR must then NOT be made writeable by the world, * since no attempt is made to encrypt saved games or anything. * (It must be readable by the world, however, due to a strangeness in * access.) */ /* definition of WARPDIR comes from Makefile and must begin with " */ #define SAVEDIR WARPDIR/" #define NEWSFILE WARPDIR/warp.news" #define HELPFILE WARPDIR/warp.doc" #define LOCKFILE WARPDIR/.warp.lock" #define LOGFILE WARPDIR/warp.log" #define SCOREBOARD WARPDIR/warp.top" #define LSCOREBOARD WARPDIR/warp.lowtop" #define TMPSCOREBOARD WARPDIR/warp.topnew" #define PERMMAPS 8 /* how many starmaps are permanent */ #define MAPS 20 /* how many starmaps to choose from */ /* (MAPS - PERMMAPS is # of half-gone universes) */ /* * Screen size info, minimum screen size is 23x40 (actually 24x80). * YSIZE and XSIZE should be relatively prime so that a torpedo launched * at an angle will eventually cover the whole screen. * To calculate a new position for something: * new_position = (current_position + delta + ?SIZE00) % ?SIZE * This allows for negative deltas of up to ?SIZE00 (% doesn't work right * on negative numbers). * ?SIZE01, etc. are fudges for efficiency--they already include a delta. */ #define XYSIZE 920 #define XYSIZEx4 3680 #define YSIZE 23 #define YSIZE00 2300 #define YSIZE01 2301 #define YSIZE99 2299 #define XSIZE 40 #define XSIZE00 4000 #define XSIZE01 4001 #define XSIZE99 3999 #define XSIZE02 4002 #define XSIZE98 3998 #define XSIZE03 4003 #define XSIZE97 3997 #define XSIZE08 4008 #define XSIZE92 3992 #define BREAKCH '\0' #define FUNCTCH '\01' #define ENTBOUNDARY 100000 /* point boundary across which a new E is awarded */ #define BASEBOUNDARY 250000 /* point boundary across which a new B is awarded */ char INTRCH = '\03'; /* if your rand() produces only 16 bits, define RAND16 */ #ifdef RAND16 /* 16 bits of rand()? */ #define RANDRAND 1073741824.0 /* that's 2**30 */ #define HALFRAND 0x8000 /* that's 2**15 */ unsigned rand(); #define myrand() (rand()&65535) #define rand_mod(m) ((int)((double)myrand() / 65536.0 * ((double)(m)))) /* pick number in 0..m-1 */ #else /* assume 31 bits */ #define RANDRAND 1152921504606846976.0 /* that's 2**60 */ #define HALFRAND 0x40000000 /* that's 2**30 */ long rand(); #define myrand() rand() #define rand_mod(m) ((myrand() / 37) % (m)) /* pick number in 0..m-1 */ /* * The reason for the /37 above is that our random number generator yields * successive evens and odds, for some reason. */ #endif /* we get fractions of seconds from calling ftime on timebuf */ #ifdef FTIMER struct timeb timebuf; #define roundsleep(x) (ftime(&timebuf),sleep(timebuf.millitm > 500?x+1:x)) #else #define roundsleep(x) sleep(x) #endif int charsperhalfsec; long iocount; struct stat filestat; int real_y = -100, real_x = -100; /* if you haven't got FIONREAD or a reasonable facsimile, you'll probably * have to root around in /dev/kmem. */ #define input_pending() (ioctl(0, FIONREAD, &iocount),(int)iocount) /* warp will still work without the following, but may get ahead at low speed */ #ifdef TIOCOUTQ /* chars left in output queue */ #define output_pending() (ioctl(1, TIOCOUTQ, &iocount),iocount) #endif /* If some of the following look something like curses calls, it is because * warp used to use curses but doesn't now. Warp was neither as efficient nor * as portable with curses, and since the program had to cheat on curses all * over the place anyway, we ripped it out. */ #define setimage(of,to) (mvaddch(of->posy+1,of->posx*2,of->image=(to))) #define mvaddch(y,x,ch) (tmpchr=(ch), move((y),(x),&tmpchr)) #define addch(ch) (tmpchr=(ch), write(1,&tmpchr,1), real_x++) #define mvaddc(y,x,ch) (move((y),(x),&(ch))) #define addc(ch) (write(1,&(ch),1), real_x++) #define addspace() (write(1," ",1), real_x++) #define mvaddstr(y,x,s) (move((y),(x),(char*)0), tmpstr = (s), tmplen = strlen(tmpstr), write(1, tmpstr, tmplen), real_x += tmplen) int tmplen; char *tmpstr; char tmpchr; /* The following macros are like the pseudo-curses macros above, but do * certain amount of controlled output buffering. * * NOTE: a beg_qwrite()..end_qwrite() sequence must NOT contain a cursor * movement (move), because the move() routine uses beg_qwrite()..end_qwrite() * itself. */ #define beg_qwrite() (maxcmstring = cmbuffer) #ifdef vax #define qwrite() asm("movc3 _gfillen,_filler,*_maxcmstring"); maxcmstring += gfillen #else #define qwrite() (movc3(gfillen,filler,maxcmstring), maxcmstring += gfillen) #endif #define qaddc(ch) (*maxcmstring++ = (ch), real_x++) #define qaddch(ch) (*maxcmstring++ = (ch), real_x++) #define qaddspace() (*maxcmstring++ = ' ', real_x++) #define end_qwrite() (write(1,cmbuffer,maxcmstring-cmbuffer)) struct sgttyb _tty; int _tty_ch = 2, _res_flg; /* terminal mode diddling routines */ #define raw() (_tty.sg_flags|=RAW, stty(_tty_ch,&_tty)) #define noraw() (_tty.sg_flags&=~RAW,stty(_tty_ch,&_tty)) #define crmode() (_tty.sg_flags |= CBREAK, stty(_tty_ch,&_tty)) #define nocrmode() (_tty.sg_flags &= ~CBREAK,stty(_tty_ch,&_tty)) #define echo() (_tty.sg_flags |= ECHO, stty(_tty_ch, &_tty)) #define noecho() (_tty.sg_flags &= ~ECHO, stty(_tty_ch, &_tty)) #define nl() (_tty.sg_flags |= CRMOD,stty(_tty_ch, &_tty)) #define nonl() (_tty.sg_flags &= ~CRMOD, stty(_tty_ch, &_tty)) #define savetty() (gtty(_tty_ch, &_tty), _res_flg = _tty.sg_flags) #define resetty() (_tty.sg_flags = _res_flg, stty(_tty_ch, &_tty)) /* * NOTE: if you don't have termlib you'll have to define these strings, * the tputs routine, and the tgoto routine. * The tgoto routine simply produces a cursor addressing string for a given * x and y. The 1st argument is a generic string to be interpreted. * If you are hardwiring it you might just ignore the 1st argument. * The tputs routine interprets any leading number as a padding factor, possibly * scaled by the number of lines (2nd argument), puts out the string (1st arg) * and the padding using the routine specified as the 3rd argument. */ #ifdef HAVETERMLIB char *BC; /* backspace character */ char *ND; /* non-destructive cursor right */ char *DO; /* move cursor down one line */ char *UP; /* move cursor up one line */ char *CL; /* home and clear screen */ char *CE; /* clear to end of line */ char *CM; /* cursor motion */ /* extern */ char PC; /* pad character for use by tputs() */ short ospeed; /* terminal output speed, for use by tputs() */ char *tcbuf; /* temp area for "uncompiled" termcap entry */ char tcarea[TCSIZE]; /* area for "compiled" termcap strings */ int LINES, COLS; /* size of screen */ /* define a few handy macros */ #define clear() (do_tc(CL,LINES),real_y=real_x=0) #define erase_eol() do_tc(CE,1) #else ???????? /* up to you */ #endif /* setting a ??size to infinity forces cursor addressing in that direction */ int CMsize, BCsize = 1, DOsize = 1000, UPsize = 1000, NDsize = 1000; void hangup_catcher(); #ifdef SIGTSTP void cont_catcher(); #endif extern int errno; bool justonemoretime = TRUE, starspec = FALSE, klingspec = FALSE, apolspec = FALSE, crushspec = FALSE, romspec = FALSE, prespec = FALSE, tholspec = FALSE, gornspec = FALSE, keepgoing = TRUE, beginner = FALSE, massacre = FALSE, bombed_out, panic = FALSE, lowspeed = FALSE, debugging = FALSE, experimenting = FALSE, scorespec = FALSE, cloaking, cloaked, madgorns; int inumstars, numstars, inumenemies, numenemies, inumroms, inumthols, inumapollos, numapollos, apolloflag, inumcrushes, numcrushes, inumgorns, numgorns, deados, smarts, ismarts = 0, numos = 0, numxes = 0, numents, numbases, inuminhab, numinhab, wave, cumsmarts, prescene = -1, oldstatus, oldetorp, oldbtorp, oldstrs, oldenemies, scandist, antibase, sm35, sm45, sm50, sm55, sm80, sm95, entmax, enemshields, super, whenok; long totalscore, lastscore = 0, curscore, possiblescore, oldeenergy, oldbenergy, oldcurscore; char filler[] = {0,'\b',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, *bsptr = filler+1; int tractor = 0; char *homedir, *maxcmstring, cmbuffer[512], spbuf[512]; char loginname[9], realname[25]; char *index(), *ttyname(), *malloc(), *ctime(), *strcpy(), *sprintf(); char *getenv(), cmstore(), *tgoto(); int comp_tc(); char savefilename[40]; char term[12]; char gfillen = 25; #ifdef BYFULLNAME #define COMPOFF 0 #define COMPNAME realname #define COMPLEN 24 #else #define COMPOFF 24 #define COMPNAME longlognam #define COMPLEN 8 char longlognam[9]; #endif main(argc,argv) int argc; char *argv[]; { char tmp, *s, *tmpaddr; int i; FILE *savfil, *tmpfil; #ifndef RAND16 for (i=100; i; i--) if (rand() >= 65536) goto rand_ok; printf("Recompile with RAND16 defined.\n"); exit(1); rand_ok: #endif while (--argc > 0 && (*++argv)[0] == '-') for (s = argv[0]+1; *s != '\0'; s++) switch (*s) { case 'A': apolspec = TRUE; beginner = TRUE; break; case 'b': beginner = TRUE; break; case 'C': crushspec = TRUE; beginner = TRUE; break; case 'D': debugging = TRUE; break; case 'd': s++; if (*s == '=') s++; ismarts = atoi(s); if (ismarts <= 0) ismarts = 1; if (ismarts > 99) ismarts = 99; if (ismarts > 40) massacre = TRUE; s += strlen(s)-1; break; case 'E': klingspec = TRUE; beginner = TRUE; s++; if (*s == '=') s++; inumenemies = atoi(s); s += strlen(s)-1; break; case 'G': gornspec = TRUE; beginner = TRUE; break; case 'l': lowspeed = TRUE; break; case 'P': prespec = TRUE; beginner = TRUE; s++; if (*s == '=') s++; if (*s) prescene = atoi(s); else prescene = -1; s += strlen(s)-1; break; case 'R': romspec = TRUE; beginner = TRUE; break; case 'S': starspec = TRUE; beginner = TRUE; s++; if (*s == '=') s++; inumstars = atoi(s); s += strlen(s)-1; break; case 's': scorespec = TRUE; break; case 'T': tholspec = TRUE; beginner = TRUE; break; case 'x': experimenting = TRUE; break; case 'v': printf("%s\n",warpid); break; default: fprintf(stderr,"warp: illegal option %c\n", *s); fprintf(stderr, "Usage: warp -dn -b -x -v -s\n"); exit(1); } if (argc != 0) { fprintf(stderr, "Usage: warp -dn -b -x -v -s\n"); exit(1); } savetty(); ospeed = _tty.sg_ospeed; /* get all that good termcap stuff */ tcbuf = malloc(1024); /* make place for termcap entry */ tgetent(tcbuf,getenv("TERM")); /* get termcap entry */ tmpaddr = tcarea; /* set up strange tgetstr pointer */ tgetstr("pc",&tmpaddr); /* get pad character */ PC = *tcarea; /* get it where tputs wants it */ if (!tgetflag("bs")) { /* is backspace not used? */ BC = tmpaddr; /* find out what is */ tgetstr("bc",&tmpaddr); } else BC = "\b"; /* make a backspace handy */ ND = tmpaddr; /* non-destructive cursor right */ tgetstr("nd",&tmpaddr); if (tmpaddr == ND) *tmpaddr++ = '\0'; UP = tmpaddr; /* move up a line */ tgetstr("up",&tmpaddr); if (tmpaddr == UP) *tmpaddr++ = '\0'; DO = tmpaddr; /* move down a line */ tgetstr("do",&tmpaddr); if (tmpaddr == DO) *tmpaddr++ = '\0'; if (!*DO) { DO = tmpaddr; /* move down a line */ tgetstr("nl",&tmpaddr); if (tmpaddr == DO) *tmpaddr++ = '\0'; } CL = tmpaddr; /* get clear string */ tgetstr("cl",&tmpaddr); if (tmpaddr == CL) *tmpaddr++ = '\0'; CE = tmpaddr; /* clear to end of line string */ tgetstr("ce",&tmpaddr); if (tmpaddr == CE) *tmpaddr++ = '\0'; CM = tmpaddr; /* cursor motion */ tgetstr("cm",&tmpaddr); if (tmpaddr == CM) *tmpaddr++ = '\0'; LINES = tgetnum("li"); /* lines per page */ COLS = tgetnum("co"); /* columns on page */ if (!LINES) LINES = 24; if (!COLS) COLS = 80; free(tcbuf); /* recover 1024 bytes */ BCsize = comp_tc(bsptr,BC,1); BC = bsptr; if (!*CM || !BCsize) no_can_do("dumb"); if (LINES < 24 || COLS < 80) no_can_do("puny"); if (!*ND) /* not defined? */ NDsize = 1000; /* force cursor addressing */ else { NDsize = comp_tc(cmbuffer,ND,1); ND = malloc((unsigned)NDsize); movc3(NDsize,cmbuffer,ND); if (debugging) { int scr; printf("ND"); for (scr=0; scr<NDsize; scr++) printf(" %d",ND[scr]); printf("\n"); } } if (!*UP) /* not defined? */ UPsize = 1000; /* force cursor addressing */ else { UPsize = comp_tc(cmbuffer,UP,1); UP = malloc((unsigned)UPsize); movc3(UPsize,cmbuffer,UP); if (debugging) { int scr; printf("UP"); for (scr=0; scr<UPsize; scr++) printf(" %d",UP[scr]); printf("\n"); } } if (!*DO) { /* not defined? */ DO = "\n"; /* assume a newline */ DOsize = 1; } else { DOsize = comp_tc(cmbuffer,DO,1); DO = malloc((unsigned)DOsize); movc3(DOsize,cmbuffer,DO); if (debugging) { int scr; printf("DO"); for (scr=0; scr<DOsize; scr++) printf(" %d",DO[scr]); printf("\n"); } } if (debugging) fgets(cmbuffer,sizeof(cmbuffer),stdin); CMsize = comp_tc(cmbuffer,tgoto(CM,10,10),0); if (PC != '\0') { char *p; for (p=filler+sizeof(filler)-1;!*p;--p) *p = PC; } charsperhalfsec = ospeed >= B9600 ? 480 : ospeed == B4800 ? 240 : ospeed == B2400 ? 120 : ospeed == B1200 ? 60 : ospeed == B600 ? 30 : /* speed is 300 (?) */ 15; gfillen = ospeed >= B9600 ? sizeof(filler) : ospeed == B4800 ? 13 : ospeed == B2400 ? 7 : ospeed == B1200 ? 4 : 1+BCsize; if (ospeed < B2400) lowspeed = TRUE; umask(022); /* mustn't rely on incoming umask--could be 033 which */ /* would disable people from running wscore */ strcpy(term,ttyname(2)); if (stat(SAVEDIR,&filestat)) { printf("Cannot access %s\n",SAVEDIR); exit(1); } if (filestat.st_uid != geteuid()) { getpw(filestat.st_uid, spbuf); s = index(spbuf, ':'); *s = '\0'; printf("Warp will not run right without being setuid to %s.\n",spbuf); exit(1); } if ((filestat.st_mode & 0605) != 0605) { printf("%s is not protected correctly (must be u+rw o+rx).\n",SAVEDIR); exit(1); } getpw(getuid(), spbuf); s = index(spbuf, ':'); /* find end of login name */ *s = '\0'; strncpy(loginname, spbuf, 8); loginname[8] = '\0'; #ifndef BYFULLNAME strcpy(longlognam, loginname); for (i=strlen(longlognam); i<8; i++) longlognam[i] = ' '; /* make sure it is 8 long for strncmp */ longlognam[8] = '\0'; #endif if (scorespec) wscore(); if (!CMsize) /* no cursor addressing? */ no_can_do("dumb"); /* get home directory */ homedir = getenv("HOME"); if (homedir == NULL) homedir = getenv("LOGDIR"); #if FNAMEALG == 1 || FNAMEALG == 2 s = index(s+1, ':')+1; /* skip password */ s = index(s, ':')+1; /* skip uid */ s = index(s, ':')+1; /* skip gid */ spbuf[index(s, ':')-spbuf] = '\0'; #if FNAMEALG == 1 for (tmpaddr=realname; *s && tmpaddr < realname+24; s++,tmpaddr++) { if (*s == '&') { *tmpaddr++ = islower(*loginname)?toupper(*loginname):*loginname; strcpy(tmpaddr,loginname+1); tmpaddr += strlen(tmpaddr)-1; } else *tmpaddr = *s; } *tmpaddr = '\0'; realname[24] = '\0'; if (s = index(realname, ',')) *s = '\0'; #else #if FNAMEALG == 2 if (tmpaddr = index(s, '-')) s = tmpaddr+1; strncpy(realname, s, 24); realname[24] = '\0'; if (s = index(realname, '(')) *s = '\0'; #endif #endif #else #if FNAMEALG == 3 sprintf(cmbuffer,"%s/.fullname",homedir); if ((tmpfil = fopen(cmbuffer,"r")) == NULL) { printf("What is your name? "); fgets(spbuf,sizeof(spbuf),stdin); if (fork()) wait(0); else { setuid(getuid()); if ((tmpfil = fopen(cmbuffer,"w")) == NULL) exit(1); fprintf(tmpfil, "%s\n", spbuf); fclose(tmpfil); exit(0); } } else { fgets(spbuf,100,tmpfil); spbuf[strlen(spbuf)-1] = '\0'; fclose(tmpfil); } strncpy(realname, spbuf, 24); realname[24] = '\0'; #else /* or substitute your favorite fullname algorithm here */ #endif #endif for (i=strlen(realname); i<24; i++) realname[i] = ' '; /* make sure it is 24 long for strncmp */ sprintf(savefilename, "%ssave.%s", SAVEDIR, loginname); savfil = experimenting ? NULL : fopen(savefilename,"r"); if (savfil != NULL && fgets(spbuf,100,savfil) != NULL) { char tmpbuf[80]; spbuf[strlen(spbuf)-1] = '\0'; if (fgets(tmpbuf,80,savfil) != NULL) { int processnum; tmpbuf[strlen(tmpbuf)-1] = '\0'; printf("You seem to have left a game %s.\n",tmpbuf+9); s = index(tmpbuf+9, ','); *s = '\0'; processnum = atoi(s+11); if (kill(processnum, SIGINT)) { /* does process not exist? */ /* (warp ignores SIGINT) */ printf( "\nThat process does not seem to exist anymore, so you'll have to start the\n"); printf( "last wave over.\n\n"); printf( " [press return to continue]"); if (fgets(tmpbuf,sizeof(tmpbuf),stdin) == NULL) { putchar('\n'); exit(1); } } else { if (strcmp(term+8,tmpbuf+23)) { printf( "That is not your current terminal--you are on %s.\n", term+5); printf("\nYour options:\n"); printf(" 1) Exit and find the terminal it's running on\n"); } else { printf("\nYour options:\n"); printf(" 1) Exit and try to foreground it\n"); } printf(" 2) Let me terminate the other game\n\n"); printf("What do you want to do? "); if (fgets(tmpbuf,sizeof(tmpbuf),stdin) == NULL) { putchar('\n'); exit(1); } if (tmpbuf[0] == '1') { printf( "If you don't succeed, come back and do option 2 instead. Good luck.\n"); exit(0); } printf( "Ok, hang on a few moments \n"); fclose(savfil); if (kill(processnum, SIGHUP)) { printf("Unable to kill process #%d!\n",processnum); roundsleep(2); } else { #ifdef SIGCONT kill(processnum, SIGCONT); #endif for (i=15; i; --i) { sleep(1); if (kill(processnum,SIGINT)) /* does process not exist? */ /* (warp ignores SIGINT) */ break; } } savfil = fopen(savefilename,"r"); if (savfil != NULL) { fgets(spbuf,100,savfil); } } } } else savfil = NULL; if (savfil == NULL) { totalscore = smarts = cumsmarts = wave = 0; numents = 5; numbases = 3; } else { totalscore = atoi(spbuf+9); smarts = atoi(spbuf+20); cumsmarts = atoi(spbuf+24); numents = atoi(spbuf+30); numbases = atoi(spbuf+33); wave = atoi(spbuf+36); apolspec = (spbuf[40] == 'a'); beginner = (spbuf[41] == 'b'); crushspec = (spbuf[42] == 'c'); gornspec = (spbuf[43] == 'g'); massacre = (spbuf[44] == 'm'); romspec = (spbuf[45] == 'r'); tholspec = (spbuf[46] == 't'); lowspeed = (spbuf[47] == 'l') || lowspeed; fclose(savfil); } if (!ismarts) { char buf[10], cmd_buf[80]; ismarts = 1; clear(); page(NEWSFILE,FALSE); if (smarts) { printf("\nSaved game: SCORE DIFF CUMDIFF ENTERPRISES BASES WAVE"); printf("\n %7ld %2d %4d %1d %1d %3d", totalscore,smarts,cumsmarts,numents,numbases,wave); } re_ask: printf("\nWould you like instructions? "); if (fgets(buf,sizeof(buf),stdin) == NULL) { putchar('\n'); exit(1); } if (buf[0] == 'v') { printf("%s\n",warpid); goto re_ask; } if (buf[0] == 'Y' || buf[0] == 'y') { page(HELPFILE,FALSE); printf("\nWould you like to play easy games for a while? "); if (fgets(buf,sizeof(buf),stdin) == NULL) { putchar('\n'); exit(0); } if (buf[0] == 'Y' || buf[0] == 'y') { beginner = TRUE; lowspeed = TRUE; } } } if (!smarts) smarts = ismarts; #ifndef SIGTSTP #define sigignore(sig) signal(sig,SIG_IGN) #define sigset(sig,what) signal(sig,what) #endif sigignore(SIGINT); /* for inquiry of existence via kill call */ sigignore(SIGTTOU); sigset(SIGHUP, hangup_catcher); if (!debugging) { sigset(SIGQUIT, hangup_catcher); sigset(SIGILL, hangup_catcher); sigset(SIGFPE, hangup_catcher); sigset(SIGBUS, hangup_catcher); sigset(SIGSEGV, hangup_catcher); sigset(SIGSYS, hangup_catcher); sigset(SIGTERM, hangup_catcher); } #ifdef SIGTSTP sigset(SIGXCPU, hangup_catcher); sigset(SIGCONT, cont_catcher); #endif raw(); noecho(); nonl(); if (totalscore) { clear(); mvaddstr(12,25,"*** restoring saved game ***"); roundsleep(1); } srand(getpid()); do { for (keepgoing = TRUE;;) { if (!experimenting) { if ((savfil = fopen(savefilename,"w")) == NULL) { resetty(); printf("Can't open savefile\n"); exit(1); } fprintf(savfil, "%-8s %10ld, %2d,%5d,%2d,%2d,%3d %c%c%c%c%c%c%c%c\n", loginname, totalscore, smarts, cumsmarts, numents, numbases, wave, apolspec ? 'a' : ' ', beginner ? 'b' : ' ', crushspec ? 'c' : ' ', gornspec ? 'g' : ' ', massacre ? 'm' : ' ', romspec ? 'r' : ' ', tholspec ? 't' : ' ', lowspeed ? 'l' : ' ' ); fprintf(savfil," running on %s, process #%d\n", term+5,getpid()); fclose(savfil); } lastscore = totalscore; initialize(); play(); cumsmarts += smarts; wavescore(); if (!numents && !numbases) keepgoing = FALSE; if (!keepgoing) break; do { if (experimenting) { mvaddstr(23,15, " [Hit space to continue, 'q' to quit] "); } else { mvaddstr(23,15, "[Hit space to continue, 's' to save, 'q' to quit]"); } sleep(1); eat_typeahead(); if (read(0, &tmp, 1) < 0) hangup_catcher(); tmp &= 0177; if (tmp == BREAKCH || tmp == INTRCH) { mvaddstr(23,15, " "); mvaddstr(23,33, "Really quit? "); if (read(0, &tmp, 1) < 0) hangup_catcher(); tmp &= 0177; if (tmp == 'y' || tmp == 'Y') tmp = 'q'; else tmp = 1; } } while (tmp != ' ' && tmp != 'q' && tmp != INTRCH && tmp != 's' && tmp != BREAKCH); if (tmp != ' ' && tmp != 's') break; if (!beginner && smarts < 20) smarts += 4; else if (!beginner && smarts < 35) smarts += 2; else if (smarts < 99) smarts++; if (tmp == 's') save_game(); } score(); smarts = ismarts; totalscore = cumsmarts = wave = 0; numents = 5; numbases = 3; apolspec = FALSE; beginner = FALSE; crushspec = FALSE; gornspec = FALSE; massacre = (ismarts >= 40); romspec = FALSE; tholspec = FALSE; } while (justonemoretime); if (!experimenting) unlink(savefilename); clear(); resetty(); } #define Root 0 #define Base 1 #define Enterprise 2 #define Star 3 #define Torp 4 #define Enemy 5 #define Web 6 #define Crusher 7 typedef struct object { char posx, posy; char velx, vely; struct object *next, *prev, *contend; long energy; long mass; char type; char image; char strategy; } OBJECT; OBJECT root = {0, 0, 0, 0, &root, &root, 0, 0, 0, Root, '?', 0}; OBJECT free_root = {0, 0, 0, 0, &free_root, &free_root, 0, 0, 0, Root, '?', 0}; OBJECT *ent, *base, *enemies, *movers, *realapollo, *make_object(); OBJECT *occupant[YSIZE][XSIZE]; int finish = 0; long blast[YSIZE][XSIZE]; bool blasted, xblasted[XSIZE], yblasted[YSIZE]; char bangy[YSIZE*XSIZE], bangx[YSIZE*XSIZE], bangs[YSIZE*XSIZE], c = ' '; long bangm[YSIZE*XSIZE]; int xx[20], yy[20]; int nxtbang; bool banging; int etorp, btorp; int timer; int status, entmode; int evely, evelx, bvely, bvelx; OBJECT *isatorp[2][3][3]; int aretorps; char cmstore(ch) register char ch; { *maxcmstring++ = ch; } initialize() { long e; int yoff, xoff, ypred, xpred; register int i, x, y, dist, ydist, xdist; char ch; FILE *mapfp = NULL; bool tmptholspec; static char *distname[] = {" #"," -"," \\"," /", " |"," *"," `"," '"}; whenok = 10000; cloaking = madgorns = FALSE; deados = 0; curscore = possiblescore = 0L; if (smarts >= 90) massacre = TRUE; scandist = (massacre?20:15); antibase = (smarts>60?1:(smarts>40?2:(smarts>25?4:100))); sm35 = (smarts>35?35:smarts); sm45 = (smarts>45?45:smarts); sm50 = (smarts>50?50:smarts); sm55 = (smarts>55?55:smarts); sm80 = (smarts>80?80:smarts); sm95 = (smarts>95?95:smarts); super = (smarts>50?smarts-50:0); enemshields = 1 + super/5; entmax = (smarts>=75?4000:(smarts>=50?3000:(smarts>=40?2500:2000))); clear(); while (root.next != &root) { root.next = root.next->next; free_object(root.next->prev); } root.prev = &root; enemies = movers = NULL; numos = numxes = 0; #if defined(vax) && XYSIZEx4 == 3680 asm("movc5 $0,_occupant,$0,$3680,_occupant"); asm("movc5 $0,_blast,$0,$3680,_blast"); /* 3680 = XYSIZEx4 */ #else for (y=0;y<YSIZE;y++) for (x=0;x<XSIZE;x++) { occupant[y][x] = 0; blast[y][x] = 0; } #endif for (y=0; y<YSIZE; y++) yblasted[y] = FALSE; for (x=0; x<XSIZE; x++) xblasted[x] = FALSE; blasted = FALSE; if (!starspec) if (smarts < 15) inumstars = 50 + rand_mod(50); else inumstars = exdis(800)+ rand_mod(100) + 1; tmptholspec = (inumstars < 450 && ! rand_mod(90-sm80)); if (!klingspec) { inumenemies = rand_mod((smarts+1)/2) + 1; if (massacre || tmptholspec) inumenemies += 10; } if (inumenemies+inumstars > YSIZE*XSIZE-20) inumstars = YSIZE*XSIZE-20 - inumenemies; if (inumstars < 0) { inumenemies += inumstars; inumstars = 0; } if (inumenemies < 0) inumenemies = 0; numstars = inumstars; inuminhab = numinhab = 0; inumroms = inumthols = inumgorns = 0; numapollos = apolspec || massacre ? 1 : ((!numstars || rand_mod(2) || smarts < 10) ? 0 : 1); inumapollos = apolloflag = 0; realapollo = NULL; inumcrushes = numcrushes = crushspec||massacre?1:(rand_mod(2000) < inumstars); inumenemies += inumcrushes; numenemies = inumenemies; /* do stars */ if (prespec) dist = 4; else if (numstars > 550) dist = 0; else dist = rand_mod(starspec||smarts<=5?3:5); if (debugging) { real_y = real_x = -100; putchar('\n'); } switch (dist) { case 0: /* uniform random */ ydist = xdist = 0; if (debugging) printf(" R\n"); break; case 1: case 2: /* clumped, maybe skewed, maybe superposed */ ydist = rand_mod(4); xdist = rand_mod(2); if (debugging) printf("%s\n\r",distname[ydist+4*xdist]); yoff = rand_mod(YSIZE); xoff = rand_mod(XSIZE); dist = (dist==2 ? numstars/2 : 0); break; case 3: case 4: /* predefined or residual */ if (debugging) printf(" P\n"); dist = 0; sprintf(spbuf,"%ssmap.%d",SAVEDIR, (prescene>=0?prescene:rand_mod(MAPS)) ); if ((mapfp = fopen(spbuf,"r")) != NULL && fgets(spbuf,10,mapfp) != NULL ) { inumstars = numstars = atoi(spbuf); if (inumenemies+inumstars > YSIZE*XSIZE-20) inumstars = numstars = YSIZE*XSIZE-20 - inumenemies; ydist = rand_mod(2) + 4; /* flip y axis? */ xdist = rand_mod(2) + 4; /* flip x axis? */ yoff = rand_mod(YSIZE); /* how much to shift y */ xoff = rand_mod(XSIZE); /* how much to shift x */ } else ydist = xdist = 0; break; } for (i = 1; i <= numstars; i++) { if (dist && i == dist) { /* flip to another skewing? */ ydist = rand_mod(4); xdist = rand_mod(2); if (debugging) printf("%s\n",distname[ydist+4*xdist]); yoff = rand_mod(YSIZE); xoff = rand_mod(XSIZE); dist = 0; } do { /* until an open spot found */ switch (xdist) { case 0: x = rand_mod(XSIZE); /* pick from 0..39, uniform */ break; case 1: case 2: case 3: x = (int)((((double)(myrand()-HALFRAND)) * ((double)(myrand()-HALFRAND))/RANDRAND) * 20.0) + xoff; /* pick from -20..20, clumped */ break; case 4: if (fscanf(mapfp,"%d %d\n",&ypred,&xpred) == EOF) ydist = xdist = 0; x = xpred + xoff; break; case 5: if (fscanf(mapfp,"%d %d\n",&ypred,&xpred) == EOF) ydist = xdist = 0; x = -xpred + xoff; break; } switch (ydist) { case 0: y = rand_mod(YSIZE); break; case 1: y = (int)((((double)(myrand()-HALFRAND)) * ((double)(myrand()-HALFRAND))/RANDRAND) * 12.0) + yoff; /* pick from -12..12, clumped */ break; case 2: y = (int)((((double)(myrand()-HALFRAND)) * ((double)(myrand()-HALFRAND))/RANDRAND) * 12.0) + yoff + x*YSIZE/XSIZE; /* clumped & skewed */ break; case 3: y = (int)((((double)(myrand()-HALFRAND)) * ((double)(myrand()-HALFRAND))/RANDRAND) * 12.0) + yoff - x*YSIZE/XSIZE; /* clumped & skewed */ break; case 4: y = ypred + yoff; break; case 5: y = -ypred + yoff; break; } while (x<0) x += XSIZE00; while (y<0) y += YSIZE00; x %= XSIZE; y %= YSIZE; } while (occupant[y][x]); e = rand_mod(32768); if (e<32000-super*150) ch = '*'; else { ch = '@'; inuminhab = ++numinhab; } make_object(Star,ch,y,x,0,0,e,e/4,&root); } if (mapfp != NULL) fclose(mapfp); if (numcrushes) { do { x = rand_mod(XSIZE); y = rand_mod(YSIZE); } while (occupant[y][x]); movers = make_object(Crusher,'<',y,x,0,1,32767L,32768,&root); possiblescore += 10000; } if (numents) { do { x = rand_mod(XSIZE); y = rand_mod(YSIZE); } while (occupant[y][x]); e = entmax; ent = make_object(Enterprise,'E',y,x,0,0,e,e/2,&root); if (!movers) movers = ent; } if (numbases) { do { x = rand_mod(XSIZE); y = rand_mod(YSIZE); } while (occupant[y][x]); e = 10000; base = make_object(Base, 'B',y,x,0,0,e,e/4,&root); if (!movers) movers = base; } if (rand_mod(27-sm50/2) && !romspec && !gornspec) dist = 27-sm50/2; else dist = rand_mod(4) + 1; for (i = 1+inumcrushes; i <= numenemies; i++) { do { x = rand_mod(XSIZE); y = rand_mod(YSIZE); } while (occupant[y][x]); if (rand_mod(dist)) { if (!tholspec && !tmptholspec && rand_mod((inumstars*3)/sm50+2)) ch = 'K'; else { ch = 'T'; inumthols++; } } else { if (romspec == gornspec) e = 50; else if (gornspec) e = 10; else e = 90; if (rand_mod(100) < e) { ch = 'R'; inumroms++; } else { ch = 'G'; inumgorns++; } } if (possiblescore > ENTBOUNDARY - 10000) e = (ENTBOUNDARY - possiblescore) / 5; else e = 250 + (sm50-1) * 30 * 20 / numenemies+1; e = exdis((int)e) + e - exdis((int)e); make_object(Enemy,ch,y,x,0,0, e + rand_mod(super*200+2) + 10000*massacre,e/4,&root); e /= 4; switch (ch) { case 'K': possiblescore += e; break; case 'T': possiblescore += e*3/2; break; case 'G': possiblescore += e*2; break; case 'R': possiblescore += e*3; break; } if (!enemies) enemies = occupant[y][x]; if (!movers) movers = occupant[y][x]; } numgorns = inumgorns; if (!movers) movers = &root; if (!enemies) enemies = &root; if (ent) mvaddch(ent->posy+1, ent->posx*2, ent->image); if (base) mvaddch(base->posy+1, base->posx*2, base->image); sleep(2); { register OBJECT *curobj; for (curobj = root.next; curobj != &root; curobj = curobj->next) { mvaddch(curobj->posy+1, curobj->posx*2, curobj->image); } } for (i=0;i<2;i++) for (y=0;y<3;y++) for (x=0;x<3;x++) isatorp[i][y][x]=0; timer = 10000; finish = 0; bombed_out = FALSE; if (ent) entmode = status = 0; else if (base) status = 2; else status = 3; sprintf(spbuf, "%-4s%9ld E: %4d %2d B: %5d %3d Stars: %-3d Enemies: %-3d Stardate%5d.%1d", " ", 0, 0, 0, 0, 0, 0, 0, timer/10, timer%10); mvaddstr(0,0,spbuf); oldeenergy = oldbenergy = oldcurscore = oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1; /* force everything to fill in */ btorp = 500; etorp = 50; } play() { bool done = FALSE; register OBJECT *curobj, *to; register int i, x, y; display_status(); #ifdef TIOCOUTQ while (output_pending() > charsperhalfsec) sleep(1); /* allow buffers to empty */ #endif sleep(3); do { timer++; nxtbang = 0; banging = FALSE; display_status(); #ifdef TIOCOUTQ while (output_pending() > charsperhalfsec) sleep(1); #endif if (lowspeed) roundsleep(2); else roundsleep(1); if (ent) { evely = ent->vely; evelx = ent->velx; if (cloaking && ent->energy >= 250) ent->energy -= ent->energy/35; else cloaking = FALSE; cloaked = cloaking; } if (base) { bvely = base->vely; bvelx = base->velx; } get_commands(&done); if (done) break; klingon_smarts(); apolloflag = 0; if (ent) { if (numapollos) { if (numstars) { if (realapollo) { if (lookfor(realapollo->posy,realapollo->posx, Enterprise)) { apolloflag = 1; } } else if (lookfor(root.next->posy,root.next->posx, Enterprise)) { apolloflag = 1; realapollo = root.next; mvaddch(realapollo->posy+1,realapollo->posx*2, 'A'); realapollo->image = 'A'; realapollo->mass = 6000; inumapollos = 1; numenemies++; inumenemies++; possiblescore += 5000; } if (apolloflag) { if (blast[realapollo->posy][realapollo->posx] <= 32000) evely = evelx = 0; realapollo->energy = 32000; } } else numapollos = 0; } ent->vely = evely; ent->velx = evelx; } if (base) { if (numapollos) { if (numstars) { if (realapollo) { if (lookfor(realapollo->posy,realapollo->posx, Base)) { apolloflag |= 2; } } else if (lookfor(root.next->posy,root.next->posx, Base)) { apolloflag |= 2; realapollo = root.next; mvaddch(realapollo->posy+1,realapollo->posx*2, 'A'); realapollo->image = 'A'; realapollo->mass = 6000; inumapollos = 1; numenemies++; inumenemies++; possiblescore += 5000; } if (apolloflag & 2) { if (blast[realapollo->posy][realapollo->posx] <= 32000) bvely = bvelx = 0; realapollo->energy = 32000; } } else numapollos = 0; } base->vely = bvely; base->velx = bvelx; } if (aretorps) { aretorps = 0; for (i=0;i<2;i++) for (y=0;y<3;y++) for (x=0;x<3;x++) { if (curobj = isatorp[i][y][x]) { to = occupant[(curobj->posy+curobj->vely+YSIZE00)%YSIZE] [(curobj->posx+curobj->velx+XSIZE00)%XSIZE]; if (to && !to->vely && !to->velx) { unmake_object(curobj); if (i) btorp++; else etorp++; } isatorp[i][y][x]=0; } } } move_universe(); if (finish) { finish--; if (!finish && (!(numenemies || numos) || (!ent && !base))) { done = TRUE; timer -= 5; } } else if (!banging && (!(numenemies || numos) || (!ent && !base))) finish = 5; } while (!done); } wavescore() { double power, effectscore, starscore, pi_over_2; long bonuses; long tmp; FILE *mapfp; clear(); pi_over_2 = 3.14159265 / 2.0; power = pow((double)inumenemies+ /* total number of enemies */ inumroms*2+ /* count roms 3 times */ inumgorns+ /* count gorns 2 times */ inumthols+ /* count thols 2 times */ inumapollos*4+ /* count apollo 5 times */ inumcrushes*3 /* count crushers 4 times */ , 0.50) * /* skew it a little */ (double)smarts; /* average energy and intelligence */ if (inumstars < 350 && inumenemies > 5) power += (350.0 - (double)inumstars) * ((double)inumenemies - 5.0); if (inumstars > 850 && inumenemies > 2) power += ((double)inumstars - 850.0) * ((double)inumenemies - 2.0); effectscore = ((double)curscore / possiblescore) * atan2(power, (double) timer - 9999.0) / pi_over_2; if (inumstars) starscore = (double) numstars / (double) inumstars; else starscore = 1.0; wave++; sprintf(spbuf,"Wave = %d, Difficulty = %d, cumulative difficulty = %d", wave, smarts, cumsmarts); mvaddstr(1, 13+(smarts<10), spbuf); mvaddstr( 4, 68, " BONUS"); sprintf(spbuf,"Efficiency rating: %1.8f (diff=%0.2f,time=%d)", effectscore, power, timer - 9999); mvaddstr( 5,5, spbuf); if (effectscore < 0.8) bonuses = tmp = 0; else bonuses = tmp = (long) ((effectscore-0.8) * smarts * 1000); sprintf(spbuf, "%6ld", tmp); mvaddstr( 5, 68, spbuf); sprintf(spbuf,"Star save ratio: %1.8f (%d/%d)", starscore, numstars, inumstars); mvaddstr( 6,5, spbuf); bonuses += tmp = (long) (((double)curscore / possiblescore) * (starscore*starscore) * smarts * 20); sprintf(spbuf, "%6ld", tmp); mvaddstr( 6, 68, spbuf); sprintf(spbuf, "Inhabited stars destroyed: %5d", inuminhab-numinhab); mvaddstr( 7,5, spbuf); bonuses += tmp = (long) (inuminhab-numinhab) * -500; sprintf(spbuf, "%6ld", tmp); mvaddstr( 7, 68, spbuf); if (bombed_out) { mvaddstr( 8,5, " For running away from reality:"); bonuses += tmp = (long) -possiblescore/2; sprintf(spbuf, "%6ld", tmp); mvaddstr( 8, 68, spbuf); } sprintf(spbuf, "Enterprise: %-9s%5d remaining", ent?"saved":"destroyed", numents); mvaddstr( 9,5, spbuf); bonuses += tmp = ent && !bombed_out ? (smarts+1)*15 : 0; sprintf(spbuf, "%6ld", tmp); mvaddstr( 9, 68, spbuf); sprintf(spbuf, "Base: %-9s %5d remaining", base?"saved":"destroyed", numbases); mvaddstr(10,5, spbuf); bonuses += tmp = base && !bombed_out ? (smarts+1)*10 : 0; sprintf(spbuf, "%6ld", tmp); mvaddstr(10, 68, spbuf); if (beginner) { mvaddstr(12,19, "(Special games count only a tenth as much)"); curscore /= 10; bonuses /= 10; } sprintf(spbuf, "Previous point total:%10ld",lastscore); mvaddstr(15,24, spbuf); sprintf(spbuf, "Points this round: %10ld",curscore); mvaddstr(16,24, spbuf); sprintf(spbuf, "Bonuses: %10ld",bonuses); mvaddstr(17,24, spbuf); totalscore = lastscore + curscore + bonuses; sprintf(spbuf, "New point total: %10ld",totalscore); mvaddstr(18,24, spbuf); if (lastscore / ENTBOUNDARY < totalscore / ENTBOUNDARY) { mvaddstr(9,42,"+ 1 new"); numents++; } else if (lastscore / ENTBOUNDARY > totalscore / ENTBOUNDARY) { mvaddstr(9,42,"- 1 obsolete"); if (numents) numents--; } if (lastscore / BASEBOUNDARY < totalscore / BASEBOUNDARY) { mvaddstr(10,42,"+ 1 new"); numbases++; } else if (lastscore / BASEBOUNDARY > totalscore / BASEBOUNDARY) { mvaddstr(10,42,"- 1 obsolete"); if (numbases) numbases--; } if (starscore < 0.8 && inumstars > 200 && numstars > 50) { sprintf(spbuf, "%ssmap.%d",SAVEDIR,rand_mod(MAPS-PERMMAPS)+PERMMAPS); if ((mapfp = fopen(spbuf,"w")) != NULL) { register OBJECT *obj; fprintf(mapfp,"%d\n",numstars); for (obj = root.next; obj != &root; obj = obj->next) { if (obj->type == Star) { fprintf(mapfp,"%d %d\n",obj->posy,obj->posx); } } fclose(mapfp); } } } score() { char tmp, buf[100], *retval, cdate[30]; register FILE *logfd, *outfd; register int i; long nowtime, time(); for (i=0; link(LOGFILE, LOCKFILE) == -1 && i<10; i++) sleep(1); nowtime = time((long *)0); strcpy(cdate,ctime(&nowtime)); if ((logfd = fopen(LOGFILE,"a")) != NULL) { fprintf(logfd, "%-24s%-9s%7ld%c%2d %4d %s", realname, loginname, totalscore, c,smarts, cumsmarts, cdate); fclose(logfd); } strcpy(cdate+11,cdate+20); if (access(lowspeed?LSCOREBOARD:SCOREBOARD,0)) { if ((logfd = fopen(lowspeed?LSCOREBOARD:SCOREBOARD,"w")) != NULL) fclose(logfd); } if ((logfd = fopen(lowspeed?LSCOREBOARD:SCOREBOARD,"r")) != NULL && (outfd = fopen(TMPSCOREBOARD,"w")) != NULL) { for (i=0; i<20; i++) { if ((retval = fgets(buf, 100, logfd)) == NULL) break; if (atoi(buf+32) < totalscore) break; if (!strncmp(buf+COMPOFF,COMPNAME,COMPLEN)) { i = 100; break; } fprintf(outfd, "%s", buf); } if (i == 100) { mvaddstr(20,21, "You did not better your previous score"); fclose(outfd); unlink(TMPSCOREBOARD); } else if (i < 20) { fprintf(outfd, "%-24s%-8s%8ld%c %2d %4d %s", realname, loginname, totalscore, c,smarts, cumsmarts, cdate); i++; sprintf(spbuf, " Congratulations--you've placed %d%s", i, i==1?"st":(i==2?"nd":(i==3?"rd":"th"))); if (retval != NULL) { if (strncmp(buf+COMPOFF,COMPNAME,COMPLEN)) { fprintf(outfd, "%s", buf); i++; } else strcpy(spbuf,"Congratulations--you've bettered your score"); while (i<20) { if (fgets(buf, 100, logfd) == NULL) break; if (strncmp(buf+COMPOFF,COMPNAME,COMPLEN)) { fprintf(outfd, "%s", buf); i++; } } } mvaddstr(20,19, spbuf); fclose(logfd); fclose(outfd); unlink(lowspeed?LSCOREBOARD:SCOREBOARD); link(TMPSCOREBOARD, lowspeed?LSCOREBOARD:SCOREBOARD); unlink(TMPSCOREBOARD); logfd = fopen(lowspeed?LSCOREBOARD:SCOREBOARD,"r"); } else { mvaddstr(20,22,"You did not place within the top 20"); fclose(outfd); } } else { sprintf(spbuf,"(Cannot access %s file, error %d)", (logfd==NULL?"log":"tmp"),errno); mvaddstr(20,22,spbuf); } move(23,0,(char*)0); erase_eol(); mvaddstr(23,11, "[Hit space for scoreboard, 'r' for new game, 'q' to quit]"); unlink(LOCKFILE); eat_typeahead(); do { if (read(0, &tmp, 1) < 0) hangup_catcher(); tmp &= 0177; } while (tmp != ' ' && tmp != 'r' && tmp != INTRCH && tmp != BREAKCH && tmp != 'q' && tmp != 'Q'); if (tmp == 'q' || tmp == 'Q' || tmp == 'r') { justonemoretime = (tmp == 'r'); if (logfd != NULL) fclose(logfd); } else { clear(); if (logfd != NULL) { fseek(logfd, 0, 0); if (lowspeed) mvaddstr(0,28,"TOP (LOW-SPEED) WARPISTS"); else mvaddstr(0,33,"TOP WARPISTS"); mvaddstr(2,0,"RANK WHO AKA SCORE DIFF CUMDIFF WHEN"); for (i=1; i<=20; i++) { if (fgets(buf, 100, logfd) == NULL) break; buf[strlen(buf)-1] = '\0'; sprintf(spbuf, " %2d %s", i, buf); mvaddstr(i+2,0, spbuf); } fclose(logfd); } roundsleep(1); mvaddstr(23,25,"Would you like to play again?"); eat_typeahead(); do { if (read(0, &tmp, 1) < 0) hangup_catcher(); tmp &= 0177; } while (tmp != 'n' && tmp != 'N' && tmp != 'y' && tmp != INTRCH && tmp != 'Y' && tmp != ' ' && tmp != '\n' && tmp != '\r' && tmp != BREAKCH); if (tmp == 'n' || tmp == 'N' || tmp == INTRCH || tmp == BREAKCH) justonemoretime = FALSE; } } save_game() { FILE *savfil; if (experimenting) return; if ((savfil = fopen(savefilename,"w")) == NULL) { resetty(); printf("Cannot save game\n"); exit(1); } fprintf(savfil, "%-8s %10ld, %2d,%5d,%2d,%2d,%3d %c%c%c%c%c%c%c%c\n", loginname, totalscore, smarts, cumsmarts, numents, numbases, wave, apolspec ? 'a' : ' ', beginner ? 'b' : ' ', crushspec ? 'c' : ' ', gornspec ? 'g' : ' ', massacre ? 'm' : ' ', romspec ? 'r' : ' ', tholspec ? 't' : ' ', lowspeed ? 'l' : ' ' ); fclose(savfil); resetty(); if (panic) exit(0); clear(); exit(0); } void hangup_catcher() { panic++; if (panic >= 2) { if (panic >= 3) exit(1); chdir(SAVEDIR); kill(0,SIGIOT); } save_game(); exit(0); } exdis(maxnum) int maxnum; { double temp, temp2; temp = (double) maxnum; temp2 = (double) myrand(); #ifdef RAND16 return (int) exp(temp2 * log(temp)/0xffff); #else return (int) exp(temp2 * log(temp)/0x7fffffff); #endif /*maxint*/ } display_status() { register int tmp; static char *status_names[] = {"Impl", "Warp", "Base", "****" }; if (oldstatus != status) { sprintf(spbuf,"%-4s",status_names[status]); mvaddstr(0,0, spbuf); oldstatus = status; } if (curscore != oldcurscore) { sprintf(spbuf,"%9ld",curscore); mvaddstr(0,4, spbuf); oldcurscore = curscore; } if (ent) { if (ent->energy != oldeenergy) { oldeenergy = ent->energy; sprintf(spbuf,"%4d",oldeenergy); mvaddstr(0,18, spbuf); } if (etorp != oldetorp) { sprintf(spbuf,"%2d",etorp); mvaddstr(0,23, spbuf); oldetorp = etorp; } } else { if (etorp >= 0) { etorp = -1; mvaddstr(0,18,"*******"); } } if (base) { if (base->energy != oldbenergy) { oldbenergy = base->energy; sprintf(spbuf,"%5d",oldbenergy); mvaddstr(0,29, spbuf); } if (btorp != oldbtorp) { sprintf(spbuf,"%3d",btorp); mvaddstr(0,35, spbuf); oldbtorp = btorp; } } else { if (btorp >= 0) { btorp = -1; mvaddstr(0,29,"*********"); } } if (numstars != oldstrs) { sprintf(spbuf,"%-3d",numstars); mvaddstr(0,46, spbuf); oldstrs = numstars; } if (numenemies != oldenemies) { sprintf(spbuf,"%-3d",numenemies); mvaddstr(0,59, spbuf); oldenemies = numenemies; } if (tmp = timer%10) { sprintf(spbuf,"%1d",tmp); mvaddstr(0,77, spbuf); } else { sprintf(spbuf,"%4d.%1d",timer/10,tmp); mvaddstr(0,72, spbuf); } } do_direction(dy,dx) int dy, dx; { register int decr; if (status < 2) { if (cloaking) { char ch; cloaked = FALSE; ch = (ent->energy >= 500?'E':'e'); if (ch != ent->image) { setimage(ent, ch); } } decr = 5+abs(evely)+abs(evelx)+tractor*tractor; if (ent->energy >= decr) { ent->energy -= decr; if (tractor) { if (tract(ent,dy,dx,tractor)) { evely += tractor*dy; evelx += tractor*dx; } } else { evely += dy; evelx += dx; } if (inumthols && occupant[(ent->posy+evely+YSIZE00)%YSIZE] [(ent->posx+evelx+XSIZE00)%XSIZE]->type == Web) evely = evelx = 0; } } else if (status == 2) { decr = 500+abs(bvely)*5+abs(bvelx)*5+tractor*tractor*100; if (base->energy >= decr) { base->energy -= decr; if (tractor) { if (tract(base,dy,dx,tractor)) { bvely += tractor*dy; bvelx += tractor*dx; } } else { bvely += dy; bvelx += dx; } if (inumthols && occupant[(base->posy+bvely+YSIZE00)%YSIZE] [(base->posx+bvelx+XSIZE00)%XSIZE]->type == Web) bvely = bvelx = 0; } } tractor = 0; } ctrl_direction(dy,dx) int dy, dx; { if (status < 2) { if (cloaking) { char ch; cloaked = FALSE; ch = (ent->energy >= 500?'E':'e'); if (ch != ent->image) { setimage(ent, ch); } } fire_phaser(ent, dy, dx); } else if (status == 2) fire_phaser(base, dy, dx); } shift_direction(dy,dx) int dy, dx; { if (status < 2) { if (cloaking) { char ch; cloaked = FALSE; ch = (ent->energy >= 500?'E':'e'); if (ch != ent->image) { setimage(ent, ch); } } fire_torp(ent, dy, dx); } else if (status == 2) fire_torp(base, dy, dx); } get_commands(done) bool *done; { char ch[80]; register int i,count; register bool ctrla = FALSE; char numdestructs = 0; top: while (count = input_pending()) { for (i=0; i<count; i++) { if (read(0, &ch[i], 1) < 0) hangup_catcher(); ch[i] &= 0177; if (ch[i] == 'Q') { bombed_out = TRUE; *done = TRUE; keepgoing = FALSE; return; } if (ch[i] == 'q' || ch[i] == BREAKCH || ch[i] == INTRCH) { int x; static char quest[] = "Do you wish to escape from reality? "; if (timer >= whenok) { mvaddstr(12,22,quest); do { if (read(0, &ch[i], 1) < 0) hangup_catcher(); ch[i] &= 0177; } while (ch[i] != 'y' && ch[i] != 'n'); if (ch[i] == 'y') { bombed_out = TRUE; *done = TRUE; return; } else { for (x=11; x<=28; x++) { mvaddch(12,x*2, occupant[11][x]?occupant[11][x]->image:' '); addspace(); } roundsleep(2); whenok = timer + 10; goto top; } } else { write(1,"\07",1); goto top; } } } for (i=0; i<count; i++) { if (ctrla) { switch (ch[i]) { case '1': case 'b': ctrl_direction(1, -1); break; case '2': case 'j': ctrl_direction(1, 0); break; case '3': case 'n': ctrl_direction(1, 1); break; case '4': case 'h': ctrl_direction(0, -1); break; case '6': case 'l': ctrl_direction(0, 1); break; case '7': case 'y': ctrl_direction(-1, -1); break; case '8': case 'k': ctrl_direction(-1, 0); break; case '9': case 'u': ctrl_direction(-1, 1); break; case 'r': rewrite(); roundsleep(3); ctrla = FALSE; goto top; case 's': clear(); while (!input_pending()) sleep(1); rewrite(); roundsleep(3); ctrla = FALSE; goto top; #ifdef SIGTSTP case 'z': clear(); mytstp(); sleep(4); ctrla = FALSE; goto top; #endif default: break; } ctrla = FALSE; } else { switch (ch[i]) { case 'Z': clear(); mytstp(); sleep(4); goto top; case 'i': if (ent) { entmode = 0; status = 0; } break; case 'w': if (ent) { entmode = 1; status = 1; } break; case 'p': if (base) { status = 2; } break; case 'o': if (status < 2) { if (base) status = 2; } else if (status == 2) { if (ent) status = entmode; } break; case 'v': if (ent) { status = entmode; } cloaking=FALSE; cloaked=FALSE; break; case 'c': if (ent) { status = entmode; if (ent->energy >= 250) cloaking = TRUE; } break; case 'D': if (status < 2) { if (++numdestructs <= 2) make_blast(evely*2+ent->posy,evelx*2+ent->posx, 15000L, 3); ent->energy /= 2; } else if (status == 2) { if (++numdestructs <= 2) make_blast(base->posy, base->posx, 15000L, 5); } break; case 'd': { register OBJECT *obj; int x, y; for (obj = root.prev; obj != &root; obj = obj->prev) { if (obj->image == '+') { blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE] [x=(obj->posx+obj->velx+XSIZE00)%XSIZE] += 1; yblasted[y] = TRUE; xblasted[x] = TRUE; blasted = TRUE; obj->mass = (massacre?3000:4000); } } } break; case 's': { register OBJECT *obj; for (obj = root.prev; obj->type == Torp || obj->type == Web || obj->type == Star; obj = obj->prev) { if (obj->image == '+') obj->vely = obj->velx = 0; } } break; case '\001': ctrla = TRUE; break; case '\002': case '\003': case '\004': case '\005': case '\006': case '\007': case '\010': case '\011': case '\012': case '\013': case '\014': case '\015': case '\016': case '\017': case '\020': case '\021': case '\022': case '\023': case '\024': case '\025': case '\026': case '\027': case '\030': case '\031': case '\032': ch[i] += 96; i--; ctrla = TRUE; break; case '\033': tractor = 0; break; case 'a': tractor++; break; case 'r': tractor--; break; case '1': case 'b': do_direction(1,-1); break; case '2': case 'j': do_direction(1,0); break; case '3': case 'n': do_direction(1,1); break; case '4': case 'h': do_direction(0,-1); break; case '6': case 'l': do_direction(0,1); break; case '7': case 'y': do_direction(-1,-1); break; case '8': case 'k': do_direction(-1,0); break; case '9': case 'u': do_direction(-1,1); break; case '0': case 'S': if (status < 2) { evely = 0; evelx = 0; } break; case '-': if (status < 2 && ent->energy >= 10) { evely *= -1; evelx *= -1; ent->energy -= 10; } break; case '%': case '\177': case '_': shift_direction(0, -1); shift_direction(0, 1); shift_direction(-1, 0); shift_direction(1, 0); shift_direction(-1, -1); shift_direction(-1, 1); shift_direction(1, -1); shift_direction(1, 1); break; case '!': case 'B': shift_direction(1, -1); break; case '@': case 'J': shift_direction(1, 0); break; case '#': case 'N': shift_direction(1, 1); break; case '$': case 'H': shift_direction(0, -1); break; case '^': case 'L': shift_direction(0, 1); break; case '&': case 'Y': shift_direction(-1, -1); break; case '*': case 'K': shift_direction(-1, 0); break; case '(': case 'U': shift_direction(-1, 1); break; case '?': helper(); roundsleep(3); goto top; default: break; } } } } } klingon_smarts() { register OBJECT *curkl,*obj; register int prob, count, y, x; if (numcrushes && movers->type == Crusher) { movers->vely += (rand_mod(222) - 111) / 100; if (!(rand_mod(100))) { setimage(movers, (movers->velx *= -1) < 0 ? '>' : '<'); } } for (curkl = enemies; curkl->type == Enemy; curkl = curkl->next) { if (curkl->image == 'R' && (curkl->energy > 300 || massacre)) { setimage(curkl, ' '); } if (madgorns) prob = 3; else if (curkl->vely || curkl->velx) prob = massacre?10:20; else prob = 4; count = 11; while (--count && (!(rand_mod(prob)) || (obj = occupant[y=(curkl->posy+curkl->vely+YSIZE00)%YSIZE] [x=(curkl->posx+curkl->velx+XSIZE00)%XSIZE]) && (obj->type == Star || ((rand_mod(100) <= smarts) && !obj->vely && !obj->velx && (obj->image == 'o' || obj->image == 'O' || obj->image == 'X' ) ) || (obj->type == Web && (curkl->image != 'T' || (count > 5 && obj->image == (curkl->vely? (curkl->velx? (curkl->velx==curkl->vely? '\\' : '/' ) : '|' ) : '-' ) ) ) ) ) ) ) { if (massacre && curkl->image != 'T') { curkl->vely = rand_mod(7) - 3; curkl->velx = rand_mod(7) - 3; } else if (curkl->energy >= 2500 && curkl->image != 'T') { curkl->vely = rand_mod(5) - 2; curkl->velx = rand_mod(5) - 2; } else { curkl->vely = rand_mod(3) - 1; curkl->velx = rand_mod(3) - 1; } } if (count != 10) { if (curkl->image == ' ') { setimage(curkl, 'R'); } if (!count) { curkl->vely = 0; curkl->velx = 0; } } if (curkl->image == 'G' && (base||ent) && !rand_mod((103-smarts)*50) ) { int xxx,yyy; for (xxx = -1; xxx<=1; xxx++) for (yyy = -1; yyy<=1; yyy++) if ((xxx||yyy) && rand_mod(2)) fire_torp(curkl,yyy,xxx); } else if (curkl->image == 'T' && (curkl->velx || curkl->vely)) { make_object(Web, curkl->vely? (curkl->velx? (curkl->velx==curkl->vely? '\\' : '/' ) : '|' ) : '-', curkl->posy,curkl->posx,0,0,32767L,32767L,&root); if (obj && obj->type == Web) { unmake_object(obj); occupant[y][x] = 0; } } } /* klingon fighting */ attack(base); if (ent && (!cloaked || ent->image=='E' || ent->image=='e')) attack(ent); } move_universe() { register OBJECT *curobj; register int x, y; register OBJECT *temp; OBJECT *thenext; for (curobj = movers; curobj != &root; curobj = curobj->next) { x = curobj->posx; y = curobj->posy; if (curobj == occupant[y][x]) { occupant[y][x] = 0; } else if (curobj->type != Torp && curobj->type != Web) { resetty(); abort(); } } for (curobj = movers; curobj != &root; curobj = thenext) { thenext = curobj->next; if (curobj->vely || curobj->velx) { y = curobj->posy; x = curobj->posx; if (curobj->image != ' ' && (!occupant[y][x] || occupant[y][x]->image==' ') ) { move(y+1, x*2, " "); } y = (y + curobj->vely + YSIZE00) % YSIZE; x = (x + curobj->velx + XSIZE00) % XSIZE; if (occupant[y][x]->type != Star || curobj->type != Torp || (curobj->image == '+' || curobj->image == 'x')) { curobj->posy = y; curobj->posx = x; } else { if (curobj->image == '0') { curobj->vely = rand_mod(3)-1; curobj->velx = rand_mod(3)-1; } else curobj->vely = curobj->velx = 0; y = curobj->posy; x = curobj->posx; } } else { y = curobj->posy; x = curobj->posx; if (curobj->type == Web || curobj->type == Star || curobj->type == Torp) { curobj->strategy = 0; curobj->next->prev = curobj->prev; curobj->prev->next = curobj->next; curobj->prev = movers->prev; curobj->next = movers; movers->prev->next = curobj; movers->prev = curobj; } } if (temp = occupant[y][x]) { if (!temp->contend) { if (temp->type == Torp) { if (temp->image == '+') blast[y][x] += 1250; else if (temp->image == 'o' && (base||ent)) blast[y][x] += 500+super*20; else if (temp->image == 'O' && (base||ent)) blast[y][x] += 5000+super*100; } } if (curobj->type != Enemy || temp->type != Enemy) blast[y][x] += rand_mod(751)+1; else blast[y][x] += 10; yblasted[y] = TRUE; xblasted[x] = TRUE; blasted = TRUE; curobj->contend = temp; occupant[y][x] = curobj; if (curobj->type == Crusher) blast[y][x] += 100000; else if (curobj->type == Torp) { if (curobj->image == '+') blast[y][x] += 1250; else if (curobj->image == 'o') blast[y][x] += 500+super*20; else if (curobj->image == 'O') blast[y][x] += 5000+super*100; } } else { occupant[y][x] = curobj; if (curobj->image != ' ' && (curobj->velx || curobj->vely || curobj->type == Torp || curobj->type == Web) ) { mvaddc(y+1, x*2, curobj->image); } if (curobj->type == Crusher) { blast[y][x] += 100000; yblasted[y] = TRUE; xblasted[x] = TRUE; blasted = TRUE; } } } if (blasted) { int minxblast = -1, maxxblast = -2; long tmpblast; blasted = FALSE; for (x=0; x<XSIZE; x++) { if (xblasted[x]) { xblasted[x] = FALSE; maxxblast = x; if (minxblast < 0) minxblast = x; } } for (y=0; y<YSIZE; y++) { if (yblasted[y]) { yblasted[y] = FALSE; for (x=minxblast; x<=maxxblast; x++) { if (tmpblast = blast[y][x]) { register OBJECT *biggie = 0; blast[y][x] = 0; if (temp = occupant[y][x]) { if (tmpblast < 100000) make_plink(y,x); for ( ;temp; temp = curobj->contend,curobj->contend = 0){ curobj = temp; if (curobj == ent && (ent->energy > 500 || apolloflag & 1)) curobj->energy -= tmpblast / ((apolloflag & 1)? 20: 5+abs(ent->velx)+abs(ent->vely)); else if (curobj == base && (base->energy > 1000 || apolloflag & 2)) curobj->energy -= tmpblast / ((apolloflag & 2)?20:5); else if (curobj->type == Crusher) { if (tmpblast > 132767) curobj->energy -= (tmpblast - 100000); else { curobj->energy += (tmpblast - 100000); if (curobj->energy > 32767) curobj->energy = 32767; } } else if (curobj->type == Enemy) curobj->energy -= tmpblast / enemshields; else curobj->energy -= tmpblast; if (curobj->energy < 0) { if (tmpblast < 100000 && curobj->image != 'G') make_blast(y,x,curobj->mass, (curobj->type==Web?2:1)); else if (apolloflag && curobj->image == 'A') make_blast(y,x,8192L,1); else if (curobj->type == Crusher) { int i; make_blast(y,(x+XSIZE00)%XSIZE,10000L,0); if (curobj->image == '<') { for (i=XSIZE00; i<=XSIZE01; i++) make_blast(y,(x+i)%XSIZE, 10000L,0); for (i=XSIZE00; i<=XSIZE02; i++) make_blast(y,(x+i)%XSIZE, 10000L,0); make_blast(y,(x+XSIZE03)%XSIZE, 10000L,1); for (i=XSIZE00; i<=XSIZE08; i++) make_blast(y,(x+i)%XSIZE, 10000L,0); } else { for (i=XSIZE00; i>=XSIZE99; i--) make_blast(y,(x+i)%XSIZE, 10000L,0); for (i=XSIZE00; i>=XSIZE98; i--) make_blast(y,(x+i)%XSIZE, 10000L,0); make_blast(y,(x+XSIZE97)%XSIZE, 10000L,1); for (i=XSIZE00; i>=XSIZE92; i--) make_blast(y,(x+i)%XSIZE, 10000L,0); } } switch (curobj->image) { case 'A': numapollos = apolloflag = 0; numstars--; numenemies--; curscore += 5000; deados = 0; break; case 'E': case 'e': case 'C': case 'c': ent = 0; numents--; if (base) status = 2; else status = 3; deados = 0; break; case 'B': case 'b': base = 0; numbases--; if (ent) status = entmode; else status = 3; deados = 0; break; case '<': case '>': numenemies--; numcrushes = 0; curscore += 10000; if (curobj == enemies) enemies = curobj->next; deados = 0; break; case 'K': numenemies--; curscore += curobj->mass; if (curobj == enemies) enemies = curobj->next; deados = 0; break; case 'T': numenemies--; curscore += curobj->mass*3/2; if (curobj == enemies) enemies = curobj->next; deados = 0; break; case 'R': case ' ': numenemies--; curscore += curobj->mass*3; if (curobj == enemies) enemies = curobj->next; deados = 0; break; case 'G': numenemies--; numgorns--; if (madgorns) curscore += curobj->mass/2; else curscore += curobj->mass*2; if (curobj == enemies) enemies = curobj->next; { int xxx,yyy; for (xxx = -1; xxx<=1; xxx++) for (yyy = -1; yyy<=1; yyy++) if (rand_mod(2+massacre)) fire_torp(curobj, yyy,xxx); } deados = 0; break; case '*': banging = TRUE; numstars--; break; case '@': banging = TRUE; numstars--; numinhab--; break; case '|': case '-': case '/': case '\\': banging = TRUE; deados = 0; break; case 'x': curscore += 10; deados = 0; break; case 'X': curscore += 100; numxes--; deados = 0; break; case '0': curscore += 35; numos--; deados += 3; break; case 'o': curscore += 100; numos--; deados++; break; case 'O': curscore += 200; numos--; deados += 2; break; } unmake_object(curobj); } else { if (!biggie) biggie = curobj; else { if (biggie->mass > curobj->mass) bounce(curobj); else { bounce(biggie); biggie = curobj; } } } } if (biggie) { occupant[y][x] = biggie; mvaddch(y+1,x*2, biggie->image); } else { occupant[y][x] = 0; mvaddch(y+1, x*2, ' '); } } } } } } } do_bangs(); if (numcrushes && movers->type == Crusher) movers->vely = 0; if (curobj = base) { char ch; curobj->velx = 0; curobj->vely = 0; curobj->energy += 25*lookaround(curobj->posy,curobj->posx,Star); if (curobj->energy > 10000) curobj->energy = 10000; if (curobj->energy >= 1000) ch = 'B'; else ch = 'b'; if (ch != curobj->image) { setimage(curobj, ch); } } if (curobj = ent) { char ch; if (entmode == 0) { curobj->velx = 0; curobj->vely = 0; } if (base && !cloaking && !curobj->velx && !curobj->vely && lookfor(curobj->posy,curobj->posx,Base)) { int tmp; tmp = (int) (base->energy - 1000 < entmax - curobj->energy ? base->energy - 1000 : entmax - curobj->energy); if (tmp < 0) tmp = 0; curobj->energy += tmp; base->energy -= tmp; tmp = (btorp < 50 - etorp ? btorp : 50 - etorp); etorp += tmp; btorp -= tmp; } if (curobj->energy >= 500) ch = cloaked?'C':'E'; else ch = cloaked?'c':'e'; if (ch != curobj->image) { setimage(curobj, ch); } } } lookaround(y, x, what) register int y, x; register char what; { register count=0, xp, xm; if (occupant[y][xp=(x+XSIZE01)%XSIZE]->type == what) /* 0, 1 */ count++; if (occupant[y][xm=(x+XSIZE99)%XSIZE]->type == what) /* 0, -1 */ count++; if (occupant[y=(y+YSIZE99)%YSIZE][xp]->type == what) /* -1, 1 */ count++; if (occupant[y][x]->type == what) /* -1, 0 */ count++; if (occupant[y][xm]->type == what) /* -1, -1 */ count++; if (occupant[y=(y+2)%YSIZE][xp]->type == what) /* 1, 1 */ count++; if (occupant[y][x]->type == what) /* 1, 0 */ count++; if (occupant[y][xm]->type == what) /* 1, -1 */ count++; return (count); } lookfor(y, x, what) register int y, x; register char what; { register int xp, xm; if (occupant[y][xp=(x+XSIZE01)%XSIZE]->type == what || /* 0, 1 */ occupant[y][xm=(x+XSIZE99)%XSIZE]->type == what || /* 0, -1 */ occupant[y=(y+YSIZE99)%YSIZE][xp]->type == what || /* -1, 1 */ occupant[y][x]->type == what || /* -1, 0 */ occupant[y][xm]->type == what || /* -1, -1 */ occupant[y=(y+2)%YSIZE][xp]->type == what || /* 1, 1 */ occupant[y][x]->type == what || /* 1, 0 */ occupant[y][xm]->type == what) /* 1, -1 */ return(1); return (0); } make_plink(y,x) int x,y; { move(y+1,x*2,(char*)0); beg_qwrite(); *filler = '@'; qwrite(); if (occupant[y][x]) qaddc(occupant[y][x]->image); else qaddspace(); end_qwrite(); } make_blast(y,x,mass,size) int x,y,size; long mass; { bangy[nxtbang] = y; bangx[nxtbang] = x; bangm[nxtbang] = mass; bangs[nxtbang++] = size; move(y+1,x*2,(char*)0); beg_qwrite(); *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); if (occupant[y][x]) qaddc(occupant[y][x]->image); else qaddspace(); end_qwrite(); } do_bangs() { register int x, y, i, j; /* read blast list and update blast array */ for (i=0; i<nxtbang; i++) { if (bangm[i] != 32767) bangm[i] *= 4; for (y=bangy[i]-bangs[i],x=bangx[i]-bangs[i],j=bangs[i]<<1;j>=0; y++,x++,--j) { yblasted[yy[j] = (y+YSIZE00) % YSIZE] = TRUE; xblasted[xx[j] = (x+XSIZE00) % XSIZE] = TRUE; } blasted = TRUE; for (y=bangs[i]<<1;y>=0;--y) { for (x=bangs[i]<<1;x>=0;--x) { if (bangm[i] != 32767 || occupant[yy[y]][xx[x]]->type != Web) blast[yy[y]][xx[x]] += bangm[i]; } } } } sgn(x) int x; { return x ? (x>0 ? 1 : -1) : 0; } bounce(obj) register OBJECT *obj; { register int x, y, count=0; y = (obj->posy - sgn(obj->vely) + YSIZE00) % YSIZE; x = (obj->posx - sgn(obj->velx) + XSIZE00) % XSIZE; while (occupant[y][x]) { y = (y + rand_mod(3) - 1 + YSIZE00) % YSIZE; x = (x + rand_mod(3) - 1 + XSIZE00) % XSIZE; if (++count > 10000) { /* if universe full, get out of it fast */ unmake_object(obj); if (ent) unmake_object(ent); if (base) unmake_object(base); finish = 1; return; } } obj->posy = y; obj->posx = x; obj->vely = 0; obj->velx = 0; occupant[y][x] = obj; mvaddc(y+1, x*2, obj->image); } OBJECT * make_object(typ, img, py, px, vy, vx, energ, mas, where) char typ; char img; int px, py, vx, vy; long energ, mas; OBJECT *where; { register OBJECT *obj; if (free_root.next == &free_root) obj = (OBJECT *) malloc(sizeof(root)); else { obj = free_root.next; free_root.next = obj->next; obj->next->prev = &free_root; } obj->type = typ; obj->image = img; obj->next = where; obj->prev = where->prev; where->prev = obj; obj->prev->next = obj; obj->velx = vx; obj->vely = vy; obj->contend = 0; obj->strategy = 0; obj->posx = px; obj->posy = py; if (typ != Torp && typ != Web) { occupant[py][px] = obj; } obj->energy = energ; obj->mass = mas; return(obj); } unmake_object(curobj) register OBJECT *curobj; { curobj->prev->next = curobj->next; curobj->next->prev = curobj->prev; if (curobj == movers) { movers = curobj->next; } free_object(curobj); } free_object(curobj) register OBJECT *curobj; { curobj->next = free_root.next; curobj->prev = &free_root; free_root.next->prev = curobj; free_root.next = curobj; } fire_torp(from, ydir, xdir) register OBJECT *from; register int ydir, xdir; { register OBJECT *to; if (from->type == Enemy || (from == ent && etorp > 0) || (from == base && btorp > 0)) { to = occupant[(from->posy+from->vely+ydir+YSIZE00)%YSIZE] [(from->posx+from->velx+xdir+XSIZE00)%XSIZE]; if (from->type != Enemy || !to || to->vely || to->velx) { if (from->type != Enemy && (to = isatorp[from==base][ydir+1][xdir+1])) { to->vely += ydir; to->velx += xdir; } else { if (from == ent) { to = make_object(Torp, '+', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 0L, 1L,&root); to->strategy = 1; aretorps++; isatorp[0][ydir+1][xdir+1] = to; etorp--; } else if (from == base) { to = make_object(Torp, '+', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 0L, 1L,&root); to->strategy = 1; aretorps++; isatorp[1][ydir+1][xdir+1] = to; btorp--; } else if (from->image == 'G') { numos++; to = make_object(Torp, 'o', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 100L, 1L,&root); to->strategy = 1; if (madgorns) { possiblescore += 35; to->image = '0'; to->mass = 2000; to->energy = 2000; } else if (rand_mod(120)+10 > smarts) possiblescore += 100; else { possiblescore += 200; to->image = 'O'; } } else { to = make_object(Torp, 'x', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 0L, 1L,&root); to->strategy = 1; if (rand_mod(140)+10 > smarts) possiblescore += 10; else { possiblescore += 100; to->image = 'X'; to->mass = 1000+super*20; numxes++; } } } } } } attack(attackee) OBJECT *attackee; { register int dx, dy, curx, cury, prob; register OBJECT *obj; bool torps, webnear; bool thru_stars; if (attackee) { for (dx= -1; dx<=1 ; dx++) { for (dy= -1; dy<=1; dy++) { if (dx||dy) { cury = attackee->posy; curx = attackee->posx; torps = webnear = thru_stars = FALSE; for (prob = scandist;prob;prob--) { cury = (cury + dy + YSIZE00) % YSIZE; curx = (curx + dx + XSIZE00) % XSIZE; if (obj = occupant[cury][curx]) { switch (obj->image) { case 'K': case 'R': case ' ': if (rand_mod(51 - sm50) <= prob) { switch (obj->strategy||thru_stars?0: rand_mod(ent?4:2)) { case 1: case 2: if (-dy + attackee->vely == obj->vely && -dx + attackee->velx == obj->velx) fire_torp(obj, -dy + attackee->vely, -dx + attackee->velx); else fire_torp(obj, -dy + attackee->vely - obj->vely, -dx + attackee->velx - obj->velx); if (obj->image == ' ') setimage(obj, 'R'); break; case 3: { int newspeed = rand_mod(prob<5&&smarts>70?4:3)-1; obj->vely = -dy * newspeed; obj->velx = -dx * newspeed; if (newspeed >= 0 && !rand_mod(82-sm80)) { obj->vely += attackee->vely; obj->velx += attackee->velx; } break; } case 0: if (!torps && obj->energy > 1000) { fire_phaser(obj, -dy, -dx); if (smarts > 40 && (scandist-prob > 5 || attackee==base) && (massacre || obj->strategy || rand_mod(2))) while (rand_mod(2)) fire_phaser(obj, -dy, -dx); if (obj->image == ' ') setimage(obj, 'R'); } if (obj->strategy) { obj->velx = obj->vely = 0; if (obj->energy < 1000 || bvely || bvelx) obj->strategy = 0; } else if ((attackee==base||cloaking) && scandist-prob > 5 && !(rand_mod( ent?antibase*2:antibase)) ) obj->strategy = 1; break; } } goto bombout; case 'G': if (thru_stars && obj->strategy < 7) goto bombout; if (obj->strategy) { if (madgorns || !rand_mod(4)) { obj->vely = attackee->vely; obj->velx = attackee->velx; } obj->strategy += (!torps && deados > 10); if (obj->strategy > 4) madgorns = TRUE; if (!torps && obj->strategy > 5) { do { fire_phaser(obj, -dy, -dx); } while (rand_mod(2)); } } else if (numgorns >= numenemies-1 && deados > 15+numgorns*5) obj->strategy = 1; if (madgorns || rand_mod(51 - sm50) <= prob) { if (-dy + attackee->vely == obj->vely && -dx + attackee->velx == obj->velx) fire_torp(obj, -dy + attackee->vely, -dx + attackee->velx); else fire_torp(obj, -dy + attackee->vely - obj->vely, -dx + attackee->velx - obj->velx); } goto bombout; case 'T': if (thru_stars) goto bombout; if (massacre || smarts > 80 || madgorns) webnear += rand_mod(2); if (webnear && scandist-prob > 5) { if (massacre || rand_mod(50) < super) { if (!torps && obj->energy > 1000) { fire_phaser(obj, -dy, -dx); while (!rand_mod(57-sm55)) fire_phaser(obj, -dy, -dx); } } } goto bombout; case 'C': case 'c': if (thru_stars) goto bombout; break; case '+': torps = FALSE; thru_stars = FALSE; break; case '|': case '-': case '/': case '\\': if (thru_stars) goto bombout; webnear = (scandist-prob < 3); torps = FALSE; break; case 'x': if (thru_stars) goto bombout; torps = TRUE; break; case 'o': case 'O': case '0': if (thru_stars) goto bombout; torps = TRUE; if (rand_mod(99+3*scandist) < smarts+3*prob) { obj->vely = -dy + attackee->vely; obj->velx = -dx + attackee->velx; if (!obj->strategy) { /* not a mover? */ obj->strategy = 1; obj->prev->next = obj->next; obj->next->prev = obj->prev; root.prev->next = obj; obj->prev = root.prev; root.prev = obj; obj->next = &root; } } if (obj->image != '0') break; /* DROP THROUGH! */ case 'X': torps = TRUE; if (thru_stars) goto bombout; if (prob == scandist) { int y, x; blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE] [x=(obj->posx+obj->velx+XSIZE00)%XSIZE] += (obj->image == '0' ? 2000 : 200); yblasted[y] = TRUE; xblasted[x] = TRUE; blasted = TRUE; } break; case '*': case '@': if (!thru_stars) if (rand_mod(97-sm95)) goto bombout; else thru_stars = TRUE; break; default: goto bombout; } } else { if (thru_stars) goto bombout; } } bombout: ; /* end of loop */ } } } } } fire_phaser(obj, dy, dx) OBJECT *obj; int dy, dx; { register int y, x, skipping, size=5000; int decr = 50, oldy, oldx; static char curchar[] = "@* "; if (obj == ent) decr = 100; else if (obj == base) { decr = 1000; size = 200; } if (!dy) curchar[2] = '-'; else if (!dx) curchar[2] = '!'; else if (dy == dx) curchar[2] = '\\'; else curchar[2] = '/'; if (obj->energy >= decr) { obj->energy -= decr; for ( /* initialize */ skipping = (obj != base), y = (obj->posy+(obj==base?dy*2:dy)+YSIZE00)%YSIZE, x = (obj->posx+(obj==base?dx*2:dx)+XSIZE00)%XSIZE; /* while */ size && (!occupant[y][x]||(skipping && occupant[y][x]->type==Star)); /* at end of loop */ y = (y+dy+YSIZE00) % YSIZE, x = (x+dx+XSIZE00) % XSIZE, size = size * 3 / 4 ) { move(y+1,x*2,(char*)0); beg_qwrite(); if (obj == base || obj->image == 'T') { *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '~'; qwrite(); *filler = '%'; qwrite(); *filler = ':'; qwrite(); *filler = '@'; } else { *filler = size >= 500 ? *curchar : (size >= 50 ? curchar[1] : curchar[2]); } qwrite(); if (occupant[y][x]) qaddc(occupant[y][x]->image); else { qaddspace(); if (skipping) skipping = 0; } end_qwrite(); } if (size) { if (occupant[y][x]->type != Crusher || (dy==0 && dx==-(occupant[y][x]->velx)) ) { char img = occupant[y][x]->image; move(y+1,x*2,(char*)0); beg_qwrite(); if (img == ' ') { occupant[y][x]->image = 'R'; occupant[y][x]->strategy = 0; *filler = 'R'; qwrite(); qwrite(); } else if (img == 'C' || img == 'c') { cloaked = 0; img += 2; occupant[y][x]->image = img; *filler = img; qwrite(); qwrite(); } else if (img == 'K' && size > 50) occupant[y][x]->strategy = 0; *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); qaddc(img); end_qwrite(); oldy = y; oldx = x; y = (occupant[oldy][oldx]->posy + occupant[oldy][oldx]->vely + YSIZE00) % YSIZE; x = (occupant[oldy][oldx]->posx + occupant[oldy][oldx]->velx + XSIZE00) % XSIZE; if (occupant[y][x]->type == Star) { y = occupant[oldy][oldx]->posy; x = occupant[oldy][oldx]->posx; } if (obj==base) blast[y][x] += size>50 ? 15000 : (size>15 ? 1500 : 150); else if (obj==ent) blast[y][x] += size*4; else if (obj->image=='T') blast[y][x] += 15000; else blast[y][x] += size*smarts/25; yblasted[y] = TRUE; xblasted[x] = TRUE; blasted = TRUE; } else if (occupant[y][x]->type == Crusher && !dy && dx==occupant[y][x]->velx) { occupant[y][x]->image = (occupant[y][x]->velx *= -1) < 0 ? '>' : '<'; } } } } tract(obj, dy, dx, to_or_fro) OBJECT *obj; int dy, dx; { register int y, x, size=10; static char ch; OBJECT *tractee; if (!dy) ch = '|'; else if (!dx) ch = '-'; else if (dy == dx) ch = '/'; else ch = '\\'; { for ( y = (obj->posy+dy+YSIZE00)%YSIZE, x = (obj->posx+dx+XSIZE00)%XSIZE; size && (!occupant[y][x]); y = (y+dy+YSIZE00) % YSIZE, x = (x+dx+XSIZE00) % XSIZE, size--) { move(y+1,x*2,(char*)0); beg_qwrite(); *filler = ch; qwrite(); qwrite(); qaddspace(); end_qwrite(); } tractee = occupant[y][x]; if (size) { if (tractee->type != Web && (tractee->mass < obj->mass * 5 || (tractee->type == Crusher && !dx) ) ) { if (tractee == ent) { evely -= dy * to_or_fro; evelx -= dx * to_or_fro; } else if (tractee == base) { bvely -= dy * to_or_fro; bvelx -= dx * to_or_fro; } else { tractee->vely -= dy * to_or_fro; tractee->velx -= dx * to_or_fro; } if (tractee->type == Torp || tractee->type == Star) { if (!tractee->strategy) { /* not a mover? */ tractee->strategy = 1; tractee->prev->next = tractee->next; tractee->next->prev = tractee->prev; root.prev->next = tractee; tractee->prev = root.prev; root.prev = tractee; tractee->next = &root; } } } else if (tractee->type == Crusher && !dy && dx==tractee->velx) { setimage(tractee, (tractee->velx *= -1) < 0 ? '>' : '<'); } if (tractee->mass * 5 > obj->mass) return(1); } } return(0); } no_can_do(what) char *what; { noraw(); fprintf(stderr,"Sorry, your terminal is too %s to play warp.\n",what); exit(1); } do_tc(s,l) char *s; int l; { beg_qwrite(); tputs(s,l,cmstore); end_qwrite(); } int comp_tc(dest,s,l) char *dest; char *s; int l; { maxcmstring = dest; tputs(s,l,cmstore); return(maxcmstring-dest); } helper() { clear(); mvaddstr(0,4,"h or 4 left"); mvaddstr(1,4,"j or 2 down Use with SHIFT to fire torpedoes."); mvaddstr(2,4,"k or 8 up Use with CTRL or FUNCT to fire"); mvaddstr(3,4,"l or 6 right phasers or turbolasers."); mvaddstr(4,4,"b or 1 down and left Use preceded by 'a' or 'r' for"); mvaddstr(5,4,"n or 3 down and right attractors or repulsors."); mvaddstr(6,4,"y or 7 up and left Use normally for E or B motion."); mvaddstr(7,4,"u or 9 up and right"); mvaddstr(8,4,""); mvaddstr(9,4,"del or % fire photon torpedoes in every (reasonable) direction."); mvaddstr(10,4,"s stop all torpedoes."); mvaddstr(11,4,"S or 0 stop the Enterprise when in warp mode."); mvaddstr(12,4,"d destruct all torpedoes (quite useful)."); mvaddstr(13,4,"D destruct the current vessel (commit suicide)."); mvaddstr(14,4,"i/w switch to Enterprise & put into impulse/warp mode."); mvaddstr(15,4,"c/v switch to Enterprise & make cloaked/visible."); mvaddstr(16,4,"p switch to Base."); mvaddstr(17,4,"o toggle to other vessel (from E to B, or vice versa.)"); mvaddstr(18,4,""); mvaddstr(19,4,"^R refresh the screen. ^Z suspend the game."); mvaddstr(20,4,"q exit this round (if you haven't typed q within 10 cycles)."); mvaddstr(21,4,"Q exit this game."); mvaddstr(22,4,""); mvaddstr(23,4," [Hit space to continue]"); do { if (read(0, spbuf, 1) < 0) hangup_catcher(); *spbuf &= 0177; } while (*spbuf != ' '); rewrite(); } rewrite() { register int x, y; clear(); for (y=0; y<YSIZE; y++) { for (x=0; x<XSIZE; x++) { if (occupant[y][x]) { mvaddc(y+1,x*2,occupant[y][x]->image); } } } sprintf(spbuf, "%-4s%9ld E: %4d %2d B: %5d %3d Stars: %-3d Enemies: %-3d Stardate%5d.%1d", " ", 0L, 0, 0, 0, 0, 0, 0, timer/10, timer%10); mvaddstr(0,0,spbuf); oldeenergy = oldbenergy = oldcurscore = oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1; /* force everything to fill in */ if (!ent) etorp = 0; if (!base) btorp = 0; display_status(); } #ifdef SIGTSTP void cont_catcher() { savetty(); raw(); noecho(); nonl(); } mytstp() { resetty(); #ifdef SIGTSTP kill(0,SIGTSTP); #else if (fork()) wait(0); else { char *shell = getenv("SHELL"); setuid(getuid()); if (!*shell) shell = "/bin/sh"; execl(shell,shell,0); exit(1); } #endif rewrite(); } #endif move(y, x, chadd) int y, x; char *chadd; { register int ydist, xdist; register int i; register char *s; ydist = y - real_y; xdist = x - real_x; i = ydist * (ydist < 0 ? -UPsize : DOsize) + xdist * (xdist < 0 ? -BCsize : NDsize); beg_qwrite(); if (i <= CMsize) { if (ydist < 0) for (; ydist; ydist++) for (i=UPsize,s=UP; i; i--) qaddch(*s++); else for (; ydist; ydist--) for (i=DOsize,s=DO; i; i--) qaddch(*s++); if (xdist < 0) for (; xdist; xdist++) for (i=BCsize,s=BC; i; i--) qaddch(*s++); else for (; xdist; xdist--) for (i=NDsize,s=ND; i; i--) qaddch(*s++); } else { tputs(tgoto(CM,x,y),0,cmstore); } real_y = y; real_x = x; if (chadd) { qaddch(*chadd); } if (maxcmstring != cmbuffer) end_qwrite(); } movc3(len,src,dest) #ifdef vax char *dest, *src; int len; { asm("movc3 4(ap),*8(ap),*12(ap)"); } #else register char *dest, *src; register int len; { for (; len; len--) { *dest++ = *src++; } } #endif /* print out a file, stopping at form feeds */ page(filename,num) char *filename; bool num; { FILE *tmpfp = fopen(filename,"r"); int linenum = 1; if (tmpfp != NULL) { while (fgets(spbuf,sizeof(spbuf),tmpfp) != NULL) { if (*spbuf == '\f') { printf("[Hit return to continue] "); fgets(spbuf,sizeof(spbuf),stdin); } else { if (num) printf("%3d %s",linenum++,spbuf); else printf("%s",spbuf); } } fclose(tmpfp); } } wscore() { clear(); printf(" TOP WARPISTS\n\n"); printf("RANK WHO AKA SCORE DIFF CUMDIFF WHEN\n"); page(SCOREBOARD,TRUE); printf(" [hit return to continue]"); fgets(spbuf,sizeof(spbuf),stdin); clear(); printf(" TOP (LOW-SPEED) WARPISTS\n\n"); printf("RANK WHO AKA SCORE DIFF CUMDIFF WHEN\n"); page(LSCOREBOARD,TRUE); printf(" [hit return to continue]"); fgets(spbuf,sizeof(spbuf),stdin); clear(); printf(" GAMES SAVED OR IN PROGRESS\n\n"); printf("WHO SCORE DF CDF E B WV FLAGS\n"); sprintf(spbuf,"/bin/cat %ssave.*",SAVEDIR); execl("/bin/sh", "sh", "-c", spbuf, 0); exit(1); } eat_typeahead() { if (input_pending()) if (read(0, spbuf, sizeof(spbuf)) < 0) hangup_catcher(); } !STUFFY!FUNK! echo -n "Would you like me to start the make? " read ans if test "$ans" = y then echo "Make output will be found in file" `pwd`"/make.log, eventually." make 2>&1 make.log & else echo "You will need to do a make in directory" `pwd` fi # end of warp distribution kit