estes@tty3b.UUCP (08/24/83)
I've spent the past few lunch hours hacking on Warp 6.0 to compensate for the lack of "ioctl(fd,FIONREAD,&count)". The following is a modified source for warp.c. Make sure that -DSPEC is added to Makefile. I am assuming that interested parties already have the other parts of the distribution kit. Other parts fixed: #defined index(s,c) to strchr(s,c) for those on UNIX 4.0 and 5.0. Changed velx and vely in OBJECT to int's because on a 3B20 char is unsigned, which causes all sorts of problems. Changed the fullname routine to look for quotes around the name, since that's how things are in our /etc/passwd. Put in new macros using ioctl() with termio.h instead of stty()/ gtty() with sgtty.h. All changes are #ifdef'd and I suggest you peruse them. Please let me know about any other changes you find useful beyond these. Circumventing the FIONREAD problem produced a bit of a kluge, but I couldn't come up with a better fix. I cannot guarantee the results and resume no responsibility for anything. Ted Estes Teletype Corp, Skokie, IL {ihnp4, otuxa, we13}!tty3b!estes ********************** static char warpid[] = "Warp 6.0 (c) 1983 Larry Wall"; /* 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> #ifndef SPEC #include <sgtty.h> #else #include <sys/termio.h> #endif #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; #ifdef FIONREAD /* 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) #else #include <setjmp.h> int (*saveint)(); jmp_buf jmp; input_pending(ch) register char *ch; { register int num; int catch(); saveint = signal(SIGALRM,catch); alarm(1); /* set alarm */ if (!setjmp(jmp)) num = read(0,ch,1); else num = 0; alarm(0); /* cancel any outstanding alarm */ signal(SIGALRM,saveint); return(num); } catch() { longjmp(jmp,1); } #endif /* 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)) #ifndef SPEC 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)) #else struct termio _tty; int _tty_ch = 2, _res_iflg, _res_lflg; #define raw() (_tty.c_lflag &= ~(ICANON|ECHO|ISIG), _tty.c_iflag &= ~(BRKINT|IGNPAR|ICRNL|IXON),\ _tty.c_cc[4]=_tty.c_cc[5]=1, ioctl(_tty_ch,TCSETA,&_tty)) #define noraw() (_tty.c_lflag |= (ICANON|ECHO|ISIG), _tty.c_iflag |= (BRKINT|IGNPAR|ICRNL|IXON),\ _tty.c_cc[4]=4, _tty.c_cc[5]=0, ioctl(_tty_ch,TCSETA,&_tty)) #define crmode() (_tty.c_lflag &= ~(ICANON|ECHO), _tty.c_iflag |= (BRKINT|IGNPAR|ICRNL),\ _tty.c_cc[4]=_tty.c_cc[5]=1, ioctl(_tty_ch,TCSETA,&_tty)) #define nocrmode() (_tty.c_lflag |= (ICANON|ECHO|ISIG), _tty.c_iflag |= (BRKINT|IGNPAR|ICRNL|IXON),\ _tty.c_cc[4]=4, _tty.c_cc[5]=0, ioctl(_tty_ch,TCSETA,&_tty)) #define echo() (_tty.c_lflag |= ECHO, ioctl(_tty_ch, TCSETA,&_tty)) #define noecho() (_tty.c_lflag &= ~ECHO, ioctl(_tty_ch, TCSETA,&_tty)) #define nl() (_tty.c_oflag |= OCRNL, ioctl(_tty_ch, TCSETA,&_tty)) #define nonl() (_tty.c_oflag &= ~OCRNL, ioctl(_tty_ch, TCSETA, &_tty)) #define savetty() (ioctl(_tty_ch, TCGETA, &_tty), _res_lflg = _tty.c_lflag, _res_iflg = _tty.c_iflag) #define resetty() (_tty.c_lflag = _res_lflg, _tty.c_iflag = _res_iflg, _tty.c_cc[4]=4, _tty.c_cc[5]=0, ioctl(_tty_ch, TCSETA, &_tty)) #endif /* * 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 extern char *BC; /* backspace character */ char *ND; /* non-destructive cursor right */ char *DO; /* move cursor down one line */ extern 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() */ extern 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]; #ifdef SPEC #define index(s,c) strchr(s,c) char *strchr(); #else char *index(); #endif char *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(); #ifdef SPEC ospeed = _tty.c_cflag & CBAUD; #else ospeed = _tty.sg_ospeed; #endif /* 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 #ifdef SPEC if (tmpaddr = index(s, '"')) #else if (tmpaddr = index(s, '-')) #endif s = tmpaddr+1; strncpy(realname, s, 24); realname[24] = '\0'; #ifdef SPEC if (tmpaddr = index(s, '"')) #else if (s = index(realname, '(')) #endif *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 */ #ifdef SIGTTOU sigignore(SIGTTOU); #endif 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; #ifdef u3b int velx, vely; #else char velx, vely; #endif 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: #ifdef FIONREAD while (count = input_pending()) { for (i=0; i<count; i++) { if (read(0, &ch[i], 1) < 0) hangup_catcher(); #else while (count = input_pending(ch)) { if (count < 0) hangup_catcher(); for (i=0; i<count; i++) { #endif 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; #ifdef FIONREAD case 's': clear(); while (!input_pending()) sleep(1); rewrite(); roundsleep(3); ctrla = FALSE; goto top; #endif #ifdef SIGTSTP case 'z': clear(); mytstp(); sleep(4); ctrla = FALSE; goto top; #endif default: break; } ctrla = FALSE; } else { switch (ch[i]) { #ifdef SIGTSTP case 'Z': clear(); mytstp(); sleep(4); goto top; #endif 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() { #ifdef FIONREAD if (input_pending()) if (read(0, spbuf, sizeof(spbuf)) < 0) hangup_catcher(); #else if (input_pending(spbuf) < 0) hangup_catcher(); #endif }