Warp for folks w/o FIONREAD
estes at tty3b.UUCP
estes at tty3b.UUCP
Wed Aug 24 07:29:32 AEST 1983
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
}
More information about the Comp.sources.unix
mailing list