lwall (05/06/83)
Relay-Version:version B 3/9/83; site harpo.UUCP Posting-Version:version B 2.10 beta 3/9/83; site sdcrdcf.UUCP Message-ID:<231@sdcrdcf.UUCP> Date:Thu, 5-May-83 18:49:24 EDT Organization:System Development Corporation--a Burroughs Company 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. 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. 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. 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. 6) Do a make. (Dist will start it automatically if you tell it to.) 7) You should now have two executable files called warp and wscore. Link or copy them to wherever they will be executable by everyone, such as /usr/games. Ensure that the setuid bit stays set and that the files still belong to the uid you originally selected. Ensure that the files in warplib are NOT writeable by the world but warplib itself IS writeable by warp. 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. 9) The system administrator should feel free to edit the warp.news file, which is printed whenever anyone starts warp. ******************************************************************************** #!/bin/sh if test -r /usr/lib/libjobs.a then jbs='-ljobs' fi if test -r /usr/lib/libnm.a then nm='-lnm' fi if test -f /usr/ucb/clear then clr=/usr/ucb/clear else echo -n "What shell command will clear the screen? " read clr fi echo -n "Does cat -n number the lines on your system? " read ans if test $ans = y then catn='cat -n' else catn="awk -f `pwd`/catn.awk" fi if test -f /bin/csh then whichshell='csh -f' gettmp='set tmp = $<' else whichshell='sh' gettmp='read tmp' fi # The make file # (does variable, command substitution at installation time) echo Installing Makefile cat >Makefile <<!STUFFY!FUNK! libs = -ltermlib $nm -lm $jbs all: warp wscore smap.8 smap.9 smap.10 smap.11 echo "Warp make finished" warp: warp.c cc warp.c -o warp -n -O -DWARPDIR=\"`pwd` $(libs) chmod 4711 warp wscore: wsc cp wsc wscore chmod 4711 wscore smap.8: smp.8 sm sm <smp.8 >smap.8 smap.9: smp.9 sm sm <smp.9 >smap.9 smap.10: smp.10 sm sm <smp.10 >smap.10 smap.11: smp.11 sm sm <smp.11 >smap.11 sm: sm.c cc sm.c -o sm !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 feature 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 round, up to difficulty 50. Invoking warp with a -b switch causes the difficulty to increase more slowly, but games count only a fifth as much. One game consists of however many rounds you can last with 5 Enterprises and 3 Bases. (Rounds are also called waves.) The object of the game is to get as many points as possible. This is done by shooting as many enemies as possible. Each round starts with one Enterprise and one Base, and continues until either the Enterprise and Base are destroyed, or all the enemies (including any homing torpedoes) are destroyed. It is possible to abort a round, but you will be penalized for it. The game may be saved between rounds. A -x switch causes any saved game to be ignored, and causes the new game not to be savable. 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, in which case it's every two seconds. The following symbols are displayed: E Enterprise with shields e Enterprise without shields B Base with shields b Base 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 put Enterprise into impulse mode (even while Base) w put Enterprise into warp mode (even while Base) - reverse the direction of Enterprise o switch from Enterprise to Base, or vice versa ^R refresh the screen ^Z suspend the game (on a bsd system) ^C or break exit this round ? 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.) 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 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 shove objects with smaller mass out of the way. In a crowded universe the shovee 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 round. The status line across the top gives the current mode, the number of points accumulated so far, 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 round, 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. If you think you are done with a round, 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 5 Enterprises and 3 Bases, your score will be posted to the scoreboard. You may see the scoreboard outside of the game simply by giving the command "wscore". !STUFFY!FUNK! # The program itself echo Installing warp.c (the biggie) cat >warp.c <<\!STUFFY!FUNK! /* 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. * Sept 15, 1982 * * version 5.0 04/20/83 * version 5.1 05/05/83 various tidbits */ #include <whoami.h> #include <stdio.h> #include <signal.h> #include <sgtty.h> #include <math.h> #include <sys/types.h> #include <sys/timeb.h> #define bool char #define TRUE (1) #define FALSE (0) #define HAVETERMLIB 1 #define TCSIZE 256 #define RNAMES 1 /* WARPDIR must be readable and writable 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 writable by the world, * since no attempt is made to encrypt saved games or anything. */ /* 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/warplow.top" #define TMPSCOREBOARD WARPDIR/warp.topnew" #define OUTMAPS 8 /* how many old starmaps to overwrite */ #define INMAPS 12 /* how many starmaps to read in */ /* (INMAPS - OUTMAPS is # of predefined scenarios) */ /* * 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 ESCCH '\033' #define FUNCTCH '\01' char INTRCH = '\03'; long rand(); #define rand_mod(m) ((rand() / 37) % (m)) /* pick number in 0..m-1 */ /* NOTE: if your random number generator doesn't make 31 bits worth, you're in * trouble. Either come up with a rand() that does make 31 bits, or * modify the star distribution routines in initialize(), which currently * use magic numbers like 2**30 and 2**60. * rand_mod assumes that m is much less than the largest random number, or * if not, that it doesn't matter if it's slightly skewed. * The reason for the /37 above is that our random number generator yields * successive evens and odds, for some reason. */ /* we get fractions of seconds from calling ftime on timebuf */ struct timeb timebuf; #define roundsleep(x) (ftime(&timebuf),sleep(timebuf.millitm > 500?x+1:x)) int charsperhalfsec; long iocount; int real_y, real_x = -1; #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, tholspec = FALSE, gornspec = FALSE, keepgoing = TRUE, beginner = FALSE, massacre = FALSE, bombed_out, panic = FALSE, lowspeed = FALSE, debugging = FALSE, experimenting = FALSE; int inumstars, numstars, inumenemies, numenemies, inumroms, inumthols, inumapollos, numapollos, apolloflag, inumcrushes, numcrushes, inumgorns, smarts, ismarts = 0, numos = 0, numxes = 0, numents, numbases, inuminhab, numinhab, wave, cumsmarts, oldstatus, oldetorp, oldbtorp, oldstrs, oldenemies; 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 *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; main(argc,argv) int argc; char *argv[]; { char tmp, *s, *tmpaddr; int i; FILE *savfil; 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 > 50) ismarts = 50; if (ismarts > 40) massacre = TRUE; s += strlen(s)-1; break; case 'e': case 'k': 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 '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 't': tholspec = TRUE; beginner = TRUE; break; case 'x': experimenting = TRUE; break; default: fprintf(stderr,"warp: illegal option %c\n", *s); exit(1); } if (argc != 0) { fprintf(stderr, "Usage: warp -dn -b\n"); exit(1); } umask(022); /* mustn't rely on incoming umask--could be 033 which */ /* would disable people from running wscore */ strcpy(term,ttyname(2)); getpw(getuid(), spbuf); s = index(spbuf, ':'); /* find end of login name */ *s = '\0'; strcpy(loginname, spbuf); #ifdef RNAMES s = index(s+1, ':')+1; /* skip password */ s = index(s, ':')+1; /* skip uid */ s = index(s, ':')+1; /* skip gid */ spbuf[index(s, ':')-spbuf] = '\0'; strncpy(realname, s, 24); realname[24] = '\0'; if (s = index(realname, ',')) *s = '\0'; #else strcpy(realname,loginname); #endif for (i=strlen(realname); i<24; i++) realname[i] = ' '; sprintf(savefilename, "%ssave.%s", SAVEDIR, loginname); savfil = experimenting ? NULL : fopen(savefilename,"r"); if (savfil != NULL) { char tmpbuf[80]; fgets(spbuf,100,savfil); 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]"); gets(tmpbuf); } 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? "); gets(tmpbuf); 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 { kill(processnum, SIGCONT); 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); } } } } 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); if (smarts) { printf("\nSaved game: SCORE DIFF CUMDIFF ENTERPRISES BASES WAVE"); printf("\n %7d %2d %4d %1d %1d %3d", totalscore,smarts,cumsmarts,numents,numbases,wave); } printf("\nWould you like instructions? "); gets(buf); if (buf[0] == 'Y' || buf[0] == 'y') { page(HELPFILE); printf("\nWould you like to play easy games for a while? "); gets(buf); 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); 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 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 (!COLS) COLS = 80; free(tcbuf); /* recover 1024 bytes */ BCsize = comp_tc(bsptr,BC,1); BC = bsptr; if (!BCsize) no_can_do(); 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) gets(cmbuffer); CMsize = comp_tc(cmbuffer,tgoto(CM,10,10),0); if (!CMsize) /* not defined? */ no_can_do(); 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; raw(); noecho(); nonl(); if (totalscore) { clear(); mvaddstr(12,25,"*** restoring saved game ***"); roundsleep(1); } srand(getpid()); do { for (keepgoing = TRUE;;) { if (!experimenting) { savfil = fopen(savefilename,"w"); fprintf(savfil, "%-8s %10d, %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 (!keepgoing) break; do { if (experimenting) { mvaddstr(23,14, " [Hit space to continue, break to quit] "); } else { mvaddstr(23,14, "[Hit space to continue, break to quit, esc to save]"); } sleep(1); read(0, &tmp, 1); tmp &= 0177; if (tmp == BREAKCH || tmp == INTRCH) { mvaddstr(23,14, " "); mvaddstr(23,33, "Really quit? "); read(0, &tmp, 1); tmp &= 0177; if (tmp == 'y' || tmp == 'Y') tmp = 0; else tmp = 1; } } while (tmp != ' ' && tmp != INTRCH && tmp != ESCCH && tmp != BREAKCH); if (tmp != ' ' && tmp != ESCCH) break; if (!beginner && smarts < 20) smarts += 4; else if (!beginner && smarts < 35) smarts += 2; else if (smarts < 50) smarts++; if (tmp == ESCCH) 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; 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; register int i, x, y, dist, ydist, xdist; char ch; FILE *mapfp; curscore = possiblescore = 0L; clear(); while (root.next != &root) { root.next = root.next->next; free_object(root.next->prev); } root.prev = &root; enemies = movers = NULL; numos = numxes = 0; #ifdef VAX 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; if (!klingspec) { inumenemies = rand_mod((smarts+1)/2) + 1; if (massacre) 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; if (numstars > 550) dist = 0; else dist = rand_mod(3); switch (dist) { case 0: /* uniform random */ ydist = xdist = 0; break; case 1: /* clumped and maybe skewed */ ydist = rand_mod(4); xdist = rand_mod(4); if (ydist & 2) xdist &= 1; yoff = rand_mod(YSIZE); xoff = rand_mod(XSIZE); dist = (dist==2 ? numstars/2 : 0); break; case 2: /* predefined or residual */ dist = 0; sprintf(spbuf,"%ssmap.%d",SAVEDIR,rand_mod(INMAPS)); if ((mapfp = fopen(spbuf,"r")) != NULL) { fgets(spbuf,10,mapfp); 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(4); if (ydist & 2) xdist &= 1; 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)(rand()-0x40000000)) * ((double)(rand()-0x40000000))/1152921504606846976.0) * 20.0) + xoff; /* pick from -20..20, clumped */ break; case 4: if (fgets(spbuf,10,mapfp) == NULL) ydist = xdist = 0; x = atoi(spbuf) + xoff; break; case 5: if (fgets(spbuf,10,mapfp) == NULL) ydist = xdist = 0; x = -atoi(spbuf) + xoff; break; } switch (ydist) { case 0: y = rand_mod(YSIZE); break; case 1: y = (int)((((double)(rand()-0x40000000)) * ((double)(rand()-0x40000000))/1152921504606846976.0) * 12.0) + yoff; /* pick from -12..12, clumped */ break; case 2: y = (int)((((double)(rand()-0x40000000)) * ((double)(rand()-0x40000000))/1152921504606846976.0) * 12.0) + yoff + x*YSIZE/XSIZE; /* clumped & skewed */ break; case 3: y = (int)((((double)(rand()-0x40000000)) * ((double)(rand()-0x40000000))/1152921504606846976.0) * 12.0) + yoff - x*YSIZE/XSIZE; /* clumped & skewed */ break; case 4: if (fgets(spbuf,10,mapfp) == NULL) ydist = xdist = 0; y = atoi(spbuf) + yoff; break; case 5: if (fgets(spbuf,10,mapfp) == NULL) ydist = xdist = 0; y = -atoi(spbuf) + yoff; break; } switch (xdist) { case 2: x += y*XSIZE/YSIZE; break; case 3: x -= y*XSIZE/YSIZE; 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) ch = '*'; else { ch = '@'; inuminhab = ++numinhab; } make_object(Star,ch,y,x,0,0,e,e/4,&root); } if (xdist >= 4 && 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 (rand_mod(27-smarts/2) && !romspec && !gornspec) dist = 27-smarts/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 (rand_mod((inumstars*3)/smarts+2) && !tholspec) 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++; } } e = 250 + (smarts-1) * 30 * 20 / numenemies; e = exdis((int)e) + e - exdis((int)e); make_object(Enemy,ch,y,x,0,0,e,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]; } if (numents) { do { x = rand_mod(XSIZE); y = rand_mod(YSIZE); } while (occupant[y][x]); e = 2000; ent = make_object(Enterprise,'E',y,x,0,0,e,e/2,&root); if (!enemies) enemies = ent; 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 (!enemies) enemies = base; if (!movers) movers = base; } 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%9d 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(4); do { timer++; nxtbang = 0; 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 (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); } isatorp[i][y][x]=0; } } } move_universe(); if (finish) { finish--; if (!finish && (!(numenemies || numos) || (!ent && !base))) { done = TRUE; timer -= 5; } } else if (!nxtbang && (!(numenemies || numos) || (!ent && !base))) finish = 5; } while (!done); if (!numents && !numbases) keepgoing = FALSE; } 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, "%6d", 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, "%6d", 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, "%6d", tmp); mvaddstr( 7, 68, spbuf); if (bombed_out) { mvaddstr( 8,5, " For running away from reality:"); bonuses += tmp = (long) -possiblescore/2; sprintf(spbuf, "%6d", tmp); mvaddstr( 8, 68, spbuf); } sprintf(spbuf, "Enterprise: %-9s%5d remaining", ent?"saved":"destroyed", numents); mvaddstr( 9,5, spbuf); bonuses += tmp = ent?100:0; sprintf(spbuf, "%6d", tmp); mvaddstr( 9, 68, spbuf); sprintf(spbuf, "Base: %-9s %5d remaining", base?"saved":"destroyed", numbases); mvaddstr(10,5, spbuf); bonuses += tmp = base?200:0; sprintf(spbuf, "%6d", tmp); mvaddstr(10, 68, spbuf); if (beginner) { mvaddstr(12,19, "(Special games count only a fifth as much)"); curscore /= 5; bonuses /= 5; } sprintf(spbuf, "Previous point total:%10d",lastscore); mvaddstr(15,24, spbuf); sprintf(spbuf, "Points this round: %10d",curscore); mvaddstr(16,24, spbuf); sprintf(spbuf, "Bonuses: %10d",bonuses); mvaddstr(17,24, spbuf); totalscore = lastscore + curscore + bonuses; sprintf(spbuf, "New point total: %10d",totalscore); mvaddstr(18,24, spbuf); if (starscore < 0.8 && inumstars > 200 && numstars > 50) { sprintf(spbuf, "%ssmap.%d",SAVEDIR,rand_mod(OUTMAPS)); if (mapfp = fopen(spbuf,"w")) { register OBJECT *obj; fprintf(mapfp,"%d\n",numstars); for (obj = root.next; obj != &root; obj = obj->next) { if (obj->type == Star) { fprintf(mapfp,"%d\n",obj->posx); fprintf(mapfp,"%d\n",obj->posy); } } fclose(mapfp); } } } score() { char tmp, buf[100], *retval, cdate[30]; register FILE *logfd, *outfd; register int i; long nowtime, time(); for (i=0; creat(LOCKFILE, 0) == -1 && i<10; i++) sleep(1); nowtime = time((long *)0); strcpy(cdate,ctime(&nowtime)); if ((logfd = fopen(LOGFILE,"a")) != NULL) { fprintf(logfd, "%-24s%7d%c%2d %4d %s", realname, totalscore, c,smarts, cumsmarts, cdate); fclose(logfd); } strcpy(cdate+11,cdate+20); if (access(lowspeed?LSCOREBOARD:SCOREBOARD,0)) { logfd = fopen(lowspeed?LSCOREBOARD:SCOREBOARD,"w"); 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+24) < totalscore) break; if (!strncmp(buf,realname,24)) { 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%7d%c %2d %4d %s", realname, 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,realname,24)) { 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,realname,24)) { 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 log file, error %d)", errno); mvaddstr(20,20,spbuf); } move(23,0,(char*)0); erase_eol(); mvaddstr(23,28,"[Hit space to continue]"); unlink(LOCKFILE); do { read(0, &tmp, 1); tmp &= 0177; } while (tmp != ' ' && tmp != INTRCH && tmp != BREAKCH); 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,5,"RANK WHO 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,6, spbuf); } fclose(logfd); } roundsleep(1); mvaddstr(23,25,"Would you like to play again?"); do { read(0, &tmp, 1); 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; savfil = fopen(savefilename,"w"); fprintf(savfil, "%-8s %10d, %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 = TRUE; save_game(); exit(0); } exdis(maxnum) int maxnum; { double temp, temp2; temp = (double) maxnum; temp2 = rand(); return (int) exp(temp2 * log(temp)/0x7fffffff); /*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,"%9d",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) { 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) fire_phaser(ent, dy, dx); else if (status == 2) fire_phaser(base, dy, dx); } shift_direction(dy,dx) int dy, dx; { if (status < 2) 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; top: while (count = input_pending()) { for (i=0; i<count; i++) { read(0, &ch[i], 1); ch[i] &= 0177; if (ch[i] == BREAKCH || ch[i] == INTRCH) { int x; static char quest[] = "Do you wish to escape from reality? "; mvaddstr(12,22,quest); do { read(0, &ch[i], 1); 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(3); 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': mytstp(); sleep(4); ctrla = FALSE; goto top; #endif default: break; } ctrla = FALSE; } else { switch (ch[i]) { #ifdef SIGTSTP case 'q': clear(); mytstp(); sleep(4); goto top; #endif case 'i': if (ent) { entmode = 0; if (status < 2) status = 0; } break; case 'w': if (ent) { entmode = 1; if (status < 2) status = 1; } break; case 'o': if (status < 2) { if (base) status = 2; } else if (status == 2) { if (ent) status = entmode; } break; case 'D': if (status < 2) { make_blast(evely*2+ent->posy,evelx*2+ent->posx, 15000L, 3); ent->energy /= 2; } else if (status == 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) { setimage(curkl, ' '); } if (curkl->vely || curkl->velx) prob = 20; else prob = 4; count = 11; while (--count && (!(rand_mod(prob)) || occupant[y=(curkl->posy+curkl->vely+YSIZE00)%YSIZE] [x=(curkl->posx+curkl->velx+XSIZE00)%XSIZE] ->type == Star || (occupant[y][x]->type == Web && (curkl->image != 'T' || (count > 5 && occupant[y][x]->image == (curkl->vely? (curkl->velx? (curkl->velx==curkl->vely? '\\' : '/' ) : '|' ) : '-' ) ) ) ) ) ) { 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 == '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 = occupant[y][x]) && obj->type == Web) { unmake_object(obj); occupant[y][x] = 0; } } } /* klingon fighting */ attack(base); 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 != 'o' && curobj->image != 'O' && curobj->image != 'X')) { curobj->posy = y; curobj->posx = x; } 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') blast[y][x] += 500; else if (temp->image == 'O') blast[y][x] += 5000; } } 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; else if (curobj->image == 'O') blast[y][x] += 5000; } } 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 (massacre && curobj->type == Enemy) curobj->energy -= tmpblast / 10; 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; break; case 'E': case 'e': ent = 0; numents--; if (base) status = 2; else status = 3; break; case 'B': case 'b': base = 0; numbases--; if (ent) status = entmode; else status = 3; break; case '<': case '>': numenemies--; numcrushes = 0; curscore += 10000; if (curobj == enemies) enemies = curobj->next; break; case 'K': numenemies--; curscore += curobj->mass; if (curobj == enemies) enemies = curobj->next; break; case 'T': numenemies--; curscore += curobj->mass*3/2; if (curobj == enemies) enemies = curobj->next; break; case 'R': case ' ': numenemies--; curscore += curobj->mass*3; if (curobj == enemies) enemies = curobj->next; break; case 'G': numenemies--; 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)) fire_torp(curobj, yyy,xxx); } break; case '*': numstars--; break; case '@': numstars--; numinhab--; break; case 'x': curscore += 10; break; case 'X': curscore += 100; numxes--; break; case 'o': curscore += 100; numos--; break; case 'O': curscore += 200; numos--; 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 && !curobj->velx && !curobj->vely && lookfor(curobj->posy,curobj->posx,Base)) { int tmp; tmp = (int) (base->energy - 1000 < 2000 - curobj->energy ? base->energy - 1000 : 2000 - 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 = 'E'; else ch = '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, doing blasts on screen and updating 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]; } } } } bounce(obj) register OBJECT *obj; { register int x, y, count=0; y = (obj->posy - obj->vely + YSIZE00) % YSIZE; x = (obj->posx - 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; mvaddch(py+1, px*2, img); } 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 (rand_mod((massacre?52:53)-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((massacre?52:53)-smarts)) possiblescore += 10; else { possiblescore += 100; to->image = 'X'; to->mass = 1000; numxes++; } } } } } } attack(attackee) OBJECT *attackee; { register int dx, dy, curx, cury, prob; register OBJECT *obj; bool torps, webnear; 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 = FALSE; for (prob = (massacre?20:15);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 - smarts) <= prob) { switch (obj->strategy?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: obj->vely = -dy + attackee->vely; obj->velx = -dx + attackee->velx; break; case 0: if (!torps && obj->energy > 1000) { fire_phaser(obj, -dy, -dx); if (smarts == 50 && (prob < (massacre?15:10) || attackee==base) && (massacre || 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 (!ent && prob < 10 && !(rand_mod(52 - smarts)) ) obj->strategy = 1; break; } } goto bombout; case 'G': if (rand_mod(51 - smarts) <= 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 (webnear && prob < (massacre?15:10)) { if (massacre || !(rand_mod(52-smarts))){ if (!torps && obj->energy > 1000) { fire_phaser(obj, -dy, -dx); while (rand_mod(2)) fire_phaser(obj, -dy, -dx); } } } goto bombout; case '+': torps = FALSE; break; case 'x': torps = TRUE; break; case 'X': torps = TRUE; if (prob == (massacre?20:15)) { int y, x; blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE] [x=(obj->posx+obj->velx+XSIZE00)%XSIZE] += 100; yblasted[y] = TRUE; xblasted[x] = TRUE; blasted = TRUE; } break; case '|': case '-': case '/': case '\\': webnear = (prob > (massacre?17:13)); torps = FALSE; break; case 'o': case 'O': 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; } torps = TRUE; break; default: 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==ent), 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)) ) { move(y+1,x*2,(char*)0); beg_qwrite(); if (occupant[y][x]->image == ' ') { occupant[y][x]->image = 'R'; *filler = 'R'; qwrite(); qwrite(); } *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); qaddc(occupant[y][x]->image); 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; } blast[y][x] += (obj==base?10000:(obj==ent?size*4: (obj->image=='T'?10000: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() { noraw(); fprintf(stderr,"Sorry, your terminal is too dumb to play warp.\n"); 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,0," h or 4 left "); mvaddstr(1,0," j or 2 down Use with SHIFT to fire torpedoes. "); mvaddstr(2,0," k or 8 up Use with CTRL or FUNCT to fire "); mvaddstr(3,0," l or 6 right phasers or turbolasers. "); mvaddstr(4,0," b or 1 down and left Use preceded by 'a' or 'r' for "); mvaddstr(5,0," n or 3 down and right attractors or repulsors. "); mvaddstr(6,0," y or 7 up and left Use normally for E or B motion. "); mvaddstr(7,0," u or 9 up and right "); mvaddstr(8,0," "); mvaddstr(9,0," del or % fire photon torpedoes in every (reasonable) direction. "); mvaddstr(10,0," s stop all torpedoes. "); mvaddstr(11,0," S or 0 stop the Enterprise when in warp mode. "); mvaddstr(12,0," d destruct all torpedoes (quite useful). "); mvaddstr(13,0," D destruct the current vessel (commit suicide). "); mvaddstr(14,0," i put Enterprise into impulse mode. "); mvaddstr(15,0," w put Enterprise into warp mode. "); mvaddstr(16,0," - reverse the direction of Enterprise. "); mvaddstr(17,0," o switch from Enterprise to Base, or vice versa. "); mvaddstr(18,0," "); mvaddstr(19,0," ^R refresh the screen. "); mvaddstr(20,0," ^Z suspend the game. "); mvaddstr(21,0," ^C or break exit this round. "); mvaddstr(22,0," "); mvaddstr(23,0," [Hit space to continue] "); do { read(0, spbuf, 1); *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%9d 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 */ display_status(); } #ifdef SIGTSTP void cont_catcher() { savetty(); raw(); noecho(); nonl(); } mytstp() { resetty(); kill(0,SIGTSTP); 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) char *dest, *src; int len; #ifdef VAX { 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) char *filename; { FILE *tmpfp = fopen(filename,"r"); if (tmpfp != NULL) { while (fgets(spbuf,sizeof(spbuf),tmpfp) != NULL) { if (*spbuf == '\f') { printf("[Hit return to continue] "); gets(spbuf); } else printf("%s",spbuf); } fclose(tmpfp); } } !STUFFY!FUNK! # A program to print out the scoreboard # (does variable, command substitution at installation time) echo Installing wsc cat >wsc <<!STUFFY!FUNK! #!/bin/$whichshell $clr echo " TOP WARPISTS" echo "" echo " RANK WHO SCORE DIFF CUMDIFF WHEN" $catn `pwd`/warp.top echo -n " [hit return to continue]" $gettmp $clr echo " TOP (LOW-SPEED) WARPISTS" echo "" echo " RANK WHO SCORE DIFF CUMDIFF WHEN" $catn `pwd`/warplow.top echo -n " [hit return to continue]" $gettmp $clr echo " GAMES SAVED OR IN PROGRESS" echo "" echo "WHO SCORE DF CDF E B WV FLAGS" cat `pwd`/save.* !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; gets(screen[0]); 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--) { gets(buf); x = atoi(buf); gets(buf); y = atoi(buf); 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++) { gets(screen[y]); } for (y=0; y<23; y++) { for (x=0; x<80; x += 2) { if (screen[y][x] == '*') { numstars++; } } } printf("%d\n",numstars); for (y=0; y<23; y++) { for (x=0; x<80; x += 2) { if (screen[y][x] == '*') { printf("%d\n",x/2); printf("%d\n",y); } } } } exit(0); } !STUFFY!FUNK! # A scenario to encourage warp mode echo Installing smp.8 cat >smp.8 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # Another scenario to encourage warp mode echo Installing smp.9 cat >smp.9 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # A shooting gallery scenario echo Installing smp.10 cat >smp.10 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # A superfortress scenario echo Installing smp.11 cat >smp.11 <<\!STUFFY!FUNK! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * !STUFFY!FUNK! # awk script to simulate cat -n echo Installing catn.awk cat >catn.awk <<\!STUFFY!FUNK! BEGIN {OFS = "\t"} {print " " NR,$0} !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 'make.log'." make > make.log & fi