warp distribution kit

utzoo!decvax!wivax!linus!allegra!eagle!harpo!floyd!cmcl2!philabs!sdcsvax!sdccsu3!sdcrdcf!lwall utzoo!decvax!wivax!linus!allegra!eagle!harpo!floyd!cmcl2!philabs!sdcsvax!sdccsu3!sdcrdcf!lwall
Thu May 5 18:49:24 AEST 1983


Relay-Version:version B 3/9/83; site harpo.UUCP
Posting-Version:version B 2.10 beta 3/9/83; site sdcrdcf.UUCP
Message-ID:<231 at sdcrdcf.UUCP>
Date:Thu, 5-May-83 18:49:24 EDT
Organization:System Development Corporation--a Burroughs Company

Installation procedure:

    1)	Decide what uid you want warp to setuid to (not root).  Choose a
	uid that nobody untrustworthy can log into, because warp uses
	only the setuid feature to protect its files--it does not encrypt
	anything, nor does it store anything in the user's directories.
	All of its files will be stored in the directory in which this
	distribution shell script is run, and will belong to the uid in
	force when the script is run.

    2)	Login to the uid you have chosen or created, and cd to a place where
	you don't mind creating a subdirectory, such as /usr/games.

    3)	Create a subdirectory called warplib, and cd to it.

    4)	Move everything after the line of asterisks below to a shell script
	file in warplib ("dist" would be a safe name), and chmod 700 dist.

    5)	Execute dist, or whatever you have called it.  It may ask you a few
	questions, depending on what it finds or doesn't find on your system.

    6)	Do a make.  (Dist will start it automatically if you tell it to.)

    7)	You should now have two executable files called warp and wscore.
	Link or copy them to wherever they will be executable by everyone,
	such as /usr/games.  Ensure that the setuid bit stays set and that
	the files still belong to the uid you originally selected.  Ensure
	that the files in warplib are NOT writeable by the world but warplib
	itself IS writeable by warp.

    8)	Play warp.  If it doesn't produce reasonable star distributions
	(sometimes uniformly random, sometimes clumped, sometimes a
	predefined scenario) then perhaps your random number generator
	is not what warp expects.  Ensure that warp has a random number
	generator that produces 31 bits worth of integer, i.e. numbers
	from 0 to 2**31-1.

    9)	The system administrator should feel free to edit the warp.news
	file, which is printed whenever anyone starts warp.

********************************************************************************
#!/bin/sh

if test -r /usr/lib/libjobs.a
then jbs='-ljobs'
fi

if test -r /usr/lib/libnm.a
then nm='-lnm'
fi

if test -f /usr/ucb/clear
then clr=/usr/ucb/clear
else
    echo -n "What shell command will clear the screen? "
    read clr
fi

echo -n "Does cat -n number the lines on your system? "
read ans
if test $ans = y
then
    catn='cat -n'
else
    catn="awk -f `pwd`/catn.awk"
fi

if test -f /bin/csh
then
    whichshell='csh -f'
    gettmp='set tmp = $<'
else
    whichshell='sh'
    gettmp='read tmp'
fi

# The make file
# (does variable, command substitution at installation time)

echo Installing Makefile
cat >Makefile <<!STUFFY!FUNK!
libs = -ltermlib $nm -lm $jbs

all: warp wscore smap.8 smap.9 smap.10 smap.11
	echo "Warp make finished"
warp: warp.c
	cc warp.c -o warp -n -O -DWARPDIR=\"`pwd` $(libs)
	chmod 4711 warp
wscore: wsc
	cp wsc wscore
	chmod 4711 wscore
smap.8: smp.8 sm
	sm <smp.8 >smap.8
smap.9: smp.9 sm
	sm <smp.9 >smap.9
smap.10: smp.10 sm
	sm <smp.10 >smap.10
smap.11: smp.11 sm
	sm <smp.11 >smap.11
sm: sm.c
	cc sm.c -o sm
!STUFFY!FUNK!

# The help file

echo Installing warp.doc
cat >warp.doc <<\!STUFFY!FUNK!
Warp is a real-time space war game.  This means that the enemies will keep
playing even when you sit still.  Another feature is that things which
blow up can damage other things around them.  Universes above a critical
density may chain react.

The game starts at difficulty 1, and gets more difficult with each
succeeding round, up to difficulty 50.  Invoking warp with a -b switch
causes the difficulty to increase more slowly, but games count only a
fifth as much.  One game consists of however many rounds you can last
with 5 Enterprises and 3 Bases.  (Rounds are also called waves.)

The object of the game is to get as many points as possible.  This is done
by shooting as many enemies as possible.  Each round starts with one Enterprise
and one Base, and continues until either the Enterprise and Base are
destroyed, or all the enemies (including any homing torpedoes) are
destroyed.  It is possible to abort a round, but you will be penalized
for it.  The game may be saved between rounds.

A -x switch causes any saved game to be ignored, and causes the new game
not to be savable.  Hence it is possible to run test games without invalidating
a currently saved game.

The game is played in a 23 x 40 double wrap-around universe.  Everybody
(both you and the enemies) gets the chance to move once every second,
unless a -l (low-speed) switch was given, in which case it's every two seconds.
The following symbols are displayed:

	E           Enterprise with shields
	e           Enterprise without shields
	B           Base with shields
	b           Base without shields
	K           Klingon
	R           Romulan
		    Romulan with cloaking device
	G           Gorn
	T           Tholian
	A           Apollo
	<           Planet crusher
	+           Friendly torpedo
	x,X         Hostile torpedo
	o,O         Homing torpedo
	*           Star
	@           Inhabited star
	|,-,/,\     Web

The following keys control the DIRECTION of your various actions:

	h or 4          left
	j or 2          down
	k or 8          up
	l or 6          right
	b or 1          down and left
	n or 3          down and right
	y or 7          up and left
	u or 9          up and right

(You will note that the letters are the same as rogue directions, and the
numbers are for use with a keypad.) By themselves, these keys move either
the Enterprise or the Base, whichever is the current vessel.  When shifted,
they fire photon torpedoes in the specified direction from the current
vessel.  When used with either the CTRL key or the FUNCT key, phasers
(turbo-lasers for the Base) are fired in the specified direction.  (CTRL
won't work with numbers, and FUNCT probably doesn't exist on non-TVI
terminals.)  When preceded by an 'a', an attractor beam is fired in the
specified direction, and when preceded by an 'r', a repulsor beam is fired.

These keys have special functions:

	del or %        fire photon torpedoes in every (reasonable) direction
	s               stop all friendly torpedoes
	S or 0          stop the Enterprise when in warp mode
	d               destruct all friendly torpedoes (quite useful)
	D               destruct the current vessel (commit suicide)
	i               put Enterprise into impulse mode (even while Base)
	w               put Enterprise into warp mode (even while Base)
	-               reverse the direction of Enterprise
	o               switch from Enterprise to Base, or vice versa

	^R              refresh the screen
	^Z              suspend the game (on a bsd system)
	^C or break     exit this round

	?               display a summary of these commands

Unrecognized keystrokes are ignored.  IF YOU FORGET ALL THE OTHER COMMANDS,
REMEMBER "?".

Commands for moving the Enterprise may operate in one of two ways.  If it
is in impulse mode, movement commands affect the position of the ship;
if it is in warp mode, movement commands affect the velocity instead.
The Base always moves in impulse mode.  Since multiple commands may be
entered in one turn (if you can type fast enough), it is possible to jump
over things even in impulse mode.  In a crowded universe this may be the
only way to go.

(Actually, motion commands always change the velocity--the actual motion
does not occur until the next turn.  Impulse mode simply causes the
velocity to be zeroed out at the end of every turn.  Phaser commands, on
the other hand, are executed immediately.  If you want to move and fire a
phaser, you must wait for the motion to actually occur before typing the
phaser command, or the phaser fires from your old position.  This is a
feature, not a bug, and is intended to reflect reality.)

If multiple torpedo launching commands are given in a turn, a single torpedo
is launched with extra velocity.  You can thus launch photon torpedoes over
objects in the way, and get them where you want them quickly.  This feature
works well with the destruct button.

NOTE:  Phasers destroy the target by blasting the projected next location of
the object hit.  This means that if the object hit, be it Klingon, Romulan or
Enterprise, changes velocity in the same turn, it can elude the effect of
the phaser.  (Note that this also means that if you phaser a Klingon or
torpedo that is about to ram you, you will be phasered as well as it.
This can be embarrassing, not to mention deadly.)  Smart players move
immediately upon phasering something at short range, or whenever they
think they might get phasered (in other words, most of the time).

Objects with larger mass can shove objects with smaller mass out of the way.
In a crowded universe the shovee can bounce quite a way before finding an
empty place to land.  If you let the Tholians fill up the universe with web,
so that there is no place to bounce to, the Tholians win that round.

The status line across the top gives the current mode, the number of
points accumulated so far, the Enterprise's energy and torpedoes, the
Base's energy and torpedoes, the number of stars, the number of enemies,
and the stardate.  You will note that nice things happen to your energy levels
when you put the Enterprise next to the Base, or the Base next to some stars.

An object is destroyed when its energy goes negative, either from a direct
hit, or from the blast of the previous turn's explosions.  Enemies and
stars start with random amounts of energy.  High energy enemies can go warp
2.  A Romulan with sufficient energy maintains a cloaking device.  Tholians
spin web, Gorns shoot homing torpedoes, and the Planet Crusher munches
anything in its way, even Apollo.  Apollo won't let you go unless you kill
him, but he loves you very much and beefs up your shields considerably.
Both Apollo and the Planet Crusher recharge themselves, so you must hit
them hard in a single turn to do them in. (Yes, the Planet Crusher must be
shot in the mouth--he can only die of gluttony--and he blasts out of his
mouth when he dies.)  Tholian web may be crossed only by coasting across it
in warp mode, or by blasting it (but web blasts extend twice as far as
normal blasts, so keep your distance).

Note that because of the size of the Base's turbo-lasers (the Base does not
have phasers) they cannot shoot anything next to the Base. (This is why the
Death Star died!)  In part, this is to protect the Enterprise.  It also lets
you shoot over one adjacent star.  The Enterprise's phasers will shoot over
a arbitrary number of adjacent, contiguous stars, including inhabited ones.
Phasers die away with distance, so don't expect them to kill everything with
one blow.

While the Enterprise's shields are up (when it is displayed as "E" rather
than "e"), hits on it count only a fifth as much (or even less if you are
moving in warp mode).  The shields are automatically maintained as long as
there are more than 500 units of energy for the Enterprise.  The Base also
has shields, which stay up as long as it has at least 1000 units of energy.

You get points for destroying enemies and hostile torpedoes.  At the end of
a round, you also get bonus points for saving stars, saving the Enterprise
and Base, and for having an efficiency rating higher that 0.8.  You get
negative bonus points for letting inhabited stars get destroyed, and for
giving up.  If you think you are done with a round, but it won't quit, there
may be Gorn torpedoes that you haven't destroyed--you must make the universe
safe for posterity, you know.

When you have used up your 5 Enterprises and 3 Bases, your score will be
posted to the scoreboard.  You may see the scoreboard outside of the game
simply by giving the command "wscore".
!STUFFY!FUNK!

# The program itself

echo Installing warp.c (the biggie)
cat >warp.c <<\!STUFFY!FUNK!
/*      warp -- a real-time space war program
 *      author: Larry Wall
 *      helpers: Jonathan and Mark Biggar
 *	special thanks to my sweetie Gloria who suggested the Planet Crusher
 *      and to Norman Azadian, who keeps asking embarrassing questions.
 *      Sept 15, 1982
 *
 * version 5.0  04/20/83
 * version 5.1  05/05/83	various tidbits
 */

#include <whoami.h>
#include <stdio.h>
#include <signal.h>
#include <sgtty.h>
#include <math.h>
#include <sys/types.h>
#include <sys/timeb.h>

#define bool char
#define TRUE (1)
#define FALSE (0)

#define HAVETERMLIB 1
#define TCSIZE 256

#define RNAMES 1

/* WARPDIR must be readable and writable by warp, but not by anyone who you
 * don't trust.  In other words, to set up warp so everyone can play and
 * no one can cheat, give warp a uid of its own and make warp setuid to
 * that uid.  WARPDIR must then NOT be made writable by the world,
 * since no attempt is made to encrypt saved games or anything.
 */
/* definition of WARPDIR comes from Makefile and must begin with " */

#define SAVEDIR WARPDIR/"
#define NEWSFILE WARPDIR/warp.news"
#define HELPFILE WARPDIR/warp.doc"
#define LOCKFILE WARPDIR/.warp.lock"
#define LOGFILE WARPDIR/warp.log"
#define SCOREBOARD WARPDIR/warp.top"
#define LSCOREBOARD WARPDIR/warplow.top"
#define TMPSCOREBOARD WARPDIR/warp.topnew"

#define OUTMAPS 8	/* how many old starmaps to overwrite */
#define INMAPS 12	/* how many starmaps to read in */
			/* (INMAPS - OUTMAPS is # of predefined scenarios) */
/*
 * Screen size info, minimum screen size is 23x40 (actually 24x80).
 * YSIZE and XSIZE should be relatively prime so that a torpedo launched
 * at an angle will eventually cover the whole screen.
 * To calculate a new position for something:
 * new_position = (current_position + delta + ?SIZE00) % ?SIZE
 * This allows for negative deltas of up to ?SIZE00 (% doesn't work right
 * on negative numbers).
 * ?SIZE01, etc. are fudges for efficiency--they already include a delta.
 */

#define XYSIZE 920
#define XYSIZEx4 3680

#define YSIZE   23
#define YSIZE00 2300
#define YSIZE01 2301
#define YSIZE99 2299

#define XSIZE   40
#define XSIZE00 4000
#define XSIZE01 4001
#define XSIZE99 3999
#define XSIZE02 4002
#define XSIZE98 3998
#define XSIZE03 4003
#define XSIZE97 3997
#define XSIZE08 4008
#define XSIZE92 3992

#define BREAKCH '\0'
#define ESCCH '\033'
#define FUNCTCH '\01'

char INTRCH = '\03';

long rand();
#define rand_mod(m) ((rand() / 37) % (m)) /* pick number in 0..m-1 */

/* NOTE: if your random number generator doesn't make 31 bits worth, you're in
 * trouble.  Either come up with a rand() that does make 31 bits, or
 * modify the star distribution routines in initialize(), which currently
 * use magic numbers like 2**30 and 2**60.
 * rand_mod assumes that m is much less than the largest random number, or
 * if not, that it doesn't matter if it's slightly skewed.
 * The reason for the /37 above is that our random number generator yields
 * successive evens and odds, for some reason.
 */

    /* we get fractions of seconds from calling ftime on timebuf */

struct timeb timebuf;
#define roundsleep(x) (ftime(&timebuf),sleep(timebuf.millitm > 500?x+1:x))

int charsperhalfsec;

long iocount;

int real_y, real_x = -1;

#define input_pending() (ioctl(0, FIONREAD, &iocount),(int)iocount)

/* warp will still work without the following, but may get ahead at low speed */
#ifdef TIOCOUTQ		/* chars left in output queue */
#define output_pending() (ioctl(1, TIOCOUTQ, &iocount),iocount)
#endif

/* If some of the following look something like curses calls, it is because
 * warp used to use curses but doesn't now.  Warp was neither as efficient nor
 * as portable with curses, and since the program had to cheat on curses all
 * over the place anyway, we ripped it out.
 */
#define setimage(of,to) (mvaddch(of->posy+1,of->posx*2,of->image=(to)))

#define mvaddch(y,x,ch) (tmpchr=(ch), move((y),(x),&tmpchr))
#define addch(ch) (tmpchr=(ch), write(1,&tmpchr,1), real_x++)
#define mvaddc(y,x,ch) (move((y),(x),&(ch)))
#define addc(ch) (write(1,&(ch),1), real_x++)
#define addspace() (write(1," ",1), real_x++)
#define mvaddstr(y,x,s) (move((y),(x),(char*)0), tmpstr = (s), tmplen = strlen(tmpstr), write(1, tmpstr, tmplen), real_x += tmplen)

int tmplen;
char *tmpstr;
char tmpchr;

/* The following macros are like the pseudo-curses macros above, but do
 * certain amount of controlled output buffering.
 *
 * NOTE: a beg_qwrite()..end_qwrite() sequence must NOT contain a cursor
 * movement (move), because the move() routine uses beg_qwrite()..end_qwrite()
 * itself.
 */

#define beg_qwrite() (maxcmstring = cmbuffer)
#ifdef VAX
#define qwrite() asm("movc3 _gfillen,_filler,*_maxcmstring"); maxcmstring += gfillen
#else
#define qwrite() (movc3(gfillen,filler,maxcmstring), maxcmstring += gfillen)
#endif
#define qaddc(ch) (*maxcmstring++ = (ch), real_x++)
#define qaddch(ch) (*maxcmstring++ = (ch), real_x++)
#define qaddspace() (*maxcmstring++ = ' ', real_x++)
#define end_qwrite() (write(1,cmbuffer,maxcmstring-cmbuffer))

struct sgttyb _tty;
int _tty_ch = 2, _res_flg;

/* terminal mode diddling routines */

#define raw()	 (_tty.sg_flags|=RAW, stty(_tty_ch,&_tty))
#define noraw()	 (_tty.sg_flags&=~RAW,stty(_tty_ch,&_tty))
#define crmode() (_tty.sg_flags |= CBREAK, stty(_tty_ch,&_tty))
#define nocrmode() (_tty.sg_flags &= ~CBREAK,stty(_tty_ch,&_tty))
#define echo()	 (_tty.sg_flags |= ECHO, stty(_tty_ch, &_tty))
#define noecho() (_tty.sg_flags &= ~ECHO, stty(_tty_ch, &_tty))
#define nl()	 (_tty.sg_flags |= CRMOD,stty(_tty_ch, &_tty))
#define nonl()	 (_tty.sg_flags &= ~CRMOD, stty(_tty_ch, &_tty))
#define	savetty() (gtty(_tty_ch, &_tty), _res_flg = _tty.sg_flags)
#define	resetty() (_tty.sg_flags = _res_flg, stty(_tty_ch, &_tty))

/*
 * NOTE: if you don't have termlib you'll have to define these strings,
 *    the tputs routine, and the tgoto routine.
 * The tgoto routine simply produces a cursor addressing string for a given
 * x and y.  The 1st argument is a generic string to be interpreted.
 * If you are hardwiring it you might just ignore the 1st argument.
 * The tputs routine interprets any leading number as a padding factor, possibly
 * scaled by the number of lines (2nd argument), puts out the string (1st arg)
 * and the padding using the routine specified as the 3rd argument.
 */

#ifdef HAVETERMLIB
char *BC;		/* backspace character */
char *ND;		/* non-destructive cursor right */
char *DO;		/* move cursor down one line */
char *UP;		/* move cursor up one line */
char *CL;		/* home and clear screen */
char *CE;		/* clear to end of line */
char *CM;		/* cursor motion */
/* extern */ char PC;	/* pad character for use by tputs() */
short ospeed;		/* terminal output speed, for use by tputs() */
char *tcbuf;		/* temp area for "uncompiled" termcap entry */
char tcarea[TCSIZE];	/* area for "compiled" termcap strings */
int LINES, COLS;	/* size of screen */

/* define a few handy macros */

#define clear() (do_tc(CL,LINES),real_y=real_x=0)
#define erase_eol() do_tc(CE,1)

#else
  ????????		/* up to you */
#endif

/* setting a ??size to infinity forces cursor addressing in that direction */

int CMsize, BCsize = 1, DOsize = 1000, UPsize = 1000, NDsize = 1000;

void hangup_catcher();
#ifdef SIGTSTP
void cont_catcher();
#endif

extern int errno;

bool justonemoretime = TRUE, starspec = FALSE, klingspec = FALSE,
	apolspec = FALSE, crushspec = FALSE, romspec = FALSE,
	tholspec = FALSE, gornspec = FALSE, keepgoing = TRUE,
	beginner = FALSE, massacre = FALSE, bombed_out, panic = FALSE,
	lowspeed = FALSE, debugging = FALSE, experimenting = FALSE;

int inumstars, numstars, inumenemies, numenemies, inumroms, inumthols,
    inumapollos, numapollos, apolloflag, inumcrushes, numcrushes,
    inumgorns, smarts, ismarts = 0, numos = 0, numxes = 0,
    numents, numbases, inuminhab, numinhab, wave, cumsmarts,
    oldstatus, oldetorp, oldbtorp, oldstrs, oldenemies;

long totalscore, lastscore = 0, curscore, possiblescore,
    oldeenergy, oldbenergy, oldcurscore;

char filler[] = {0,'\b',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
     *bsptr = filler+1;

int tractor = 0;

char *maxcmstring, cmbuffer[512], spbuf[512];

char loginname[9], realname[25];

char *index(), *ttyname(), *malloc(), *ctime(), *strcpy(), *sprintf();
char *getenv(), cmstore(), *tgoto();
int comp_tc();

char savefilename[40];

char term[12];

char gfillen = 25;

main(argc,argv)
int argc;
char *argv[];
{
    char tmp, *s, *tmpaddr;

    int i;

    FILE *savfil;

    while (--argc > 0 && (*++argv)[0] == '-')
	for (s = argv[0]+1; *s != '\0'; s++)
	    switch (*s) {
	    case 'a':
		apolspec = TRUE;
		beginner = TRUE;
		break;
	    case 'b':
		beginner = TRUE;
		break;
	    case 'c':
		crushspec = TRUE;
		beginner = TRUE;
		break;
	    case 'D':
		debugging = TRUE;
		break;
	    case 'd':
		s++;
		if (*s == '=') s++;
		ismarts = atoi(s);
		if (ismarts <= 0)
		    ismarts = 1;
		if (ismarts > 50)
		    ismarts = 50;
		if (ismarts > 40)
		    massacre = TRUE;
		s += strlen(s)-1;
		break;
	    case 'e': case 'k':
		klingspec = TRUE;
		beginner = TRUE;
		s++;
		if (*s == '=') s++;
		inumenemies = atoi(s);
		s += strlen(s)-1;
		break;
	    case 'g':
		gornspec = TRUE;
		beginner = TRUE;
		break;
	    case 'l':
		lowspeed = TRUE;
		break;
	    case 'r':
		romspec = TRUE;
		beginner = TRUE;
		break;
	    case 's':
		starspec = TRUE;
		beginner = TRUE;
		s++;
		if (*s == '=') s++;
		inumstars = atoi(s);
		s += strlen(s)-1;
		break;
	    case 't':
		tholspec = TRUE;
		beginner = TRUE;
		break;
	    case 'x':
		experimenting = TRUE;
		break;
	    default:
		fprintf(stderr,"warp: illegal option %c\n", *s);
		exit(1);
	    }
    if (argc != 0) {
	fprintf(stderr, "Usage: warp -dn -b\n");
	exit(1);
    }

    umask(022);     /* mustn't rely on incoming umask--could be 033 which */
		    /* would disable people from running wscore */

    strcpy(term,ttyname(2));

    getpw(getuid(), spbuf);
    s = index(spbuf, ':');        /* find end of login name */
    *s = '\0';
    strcpy(loginname, spbuf);

#ifdef RNAMES
    s = index(s+1, ':')+1;        /* skip password */
    s = index(s, ':')+1;        /* skip uid */
    s = index(s, ':')+1;        /* skip gid */
    spbuf[index(s, ':')-spbuf] = '\0';
    strncpy(realname, s, 24);
    realname[24] = '\0';
    if (s = index(realname, ','))
	*s = '\0';
#else
    strcpy(realname,loginname);
#endif
    for (i=strlen(realname); i<24; i++)
	realname[i] = ' ';

    sprintf(savefilename, "%ssave.%s", SAVEDIR, loginname);

    savfil = experimenting ? NULL : fopen(savefilename,"r");
    if (savfil != NULL) {
	char tmpbuf[80];

	fgets(spbuf,100,savfil);
	spbuf[strlen(spbuf)-1] = '\0';
	if (fgets(tmpbuf,80,savfil) != NULL) {
	    int processnum;

	    tmpbuf[strlen(tmpbuf)-1] = '\0';
	    printf("You seem to have left a game %s.\n",tmpbuf+9);
	    s = index(tmpbuf+9, ',');
	    *s = '\0';
	    processnum = atoi(s+11);
	    if (kill(processnum, SIGINT)) {
					/* does process not exist? */
					/* (warp ignores SIGINT) */
		printf(
"\nThat process does not seem to exist anymore, so you'll have to start the\n");
		printf(
"last wave over.\n\n");
		printf(
"                      [press return to continue]");
		gets(tmpbuf);
	    }
	    else {
		if (strcmp(term+8,tmpbuf+23)) {
		    printf(
"That is not your current terminal--you are on %s.\n", term+5);
		    printf("\nYour options:\n");
		    printf("   1) Exit and find the terminal it's running on\n");
		}
		else {
		    printf("\nYour options:\n");
		    printf("   1) Exit and try to foreground it\n");
		}
		printf("   2) Let me terminate the other game\n\n");
		printf("What do you want to do? ");
		gets(tmpbuf);
		if (tmpbuf[0] == '1') {
		    printf(
"If you don't succeed, come back and do option 2 instead.  Good luck.\n");
		    exit(0);
		}
		printf(
"Ok, hang on a few moments \n");
		fclose(savfil);
		if (kill(processnum, SIGHUP)) {
		    printf("Unable to kill process #%d!\n",processnum);
		    roundsleep(2);
		}
		else {
		    kill(processnum, SIGCONT);
		    for (i=15; i; --i) {
			sleep(1);
			if (kill(processnum,SIGINT))
					/* does process not exist? */
					/* (warp ignores SIGINT) */
			    break;
		    }
		}
		savfil = fopen(savefilename,"r");
		if (savfil != NULL) {
		    fgets(spbuf,100,savfil);
		}
	    }
	}
    }
    if (savfil == NULL) {
	totalscore = smarts = cumsmarts = wave = 0;
	numents = 5;
	numbases = 3;
    }
    else {
	totalscore = atoi(spbuf+9);
	smarts = atoi(spbuf+20);
	cumsmarts = atoi(spbuf+24);
	numents = atoi(spbuf+30);
	numbases = atoi(spbuf+33);
	wave = atoi(spbuf+36);
	apolspec = (spbuf[40] == 'a');
	beginner   = (spbuf[41] == 'b');
	crushspec  = (spbuf[42] == 'c');
	gornspec   = (spbuf[43] == 'g');
	massacre   = (spbuf[44] == 'm');
	romspec    = (spbuf[45] == 'r');
	tholspec   = (spbuf[46] == 't');
	lowspeed   = (spbuf[47] == 'l') || lowspeed;
	fclose(savfil);
    }

    if (!ismarts) {
	char buf[10], cmd_buf[80];

	ismarts = 1;
	clear();
	page(NEWSFILE);
	if (smarts) {
	    printf("\nSaved game: SCORE DIFF CUMDIFF ENTERPRISES BASES WAVE");
	    printf("\n          %7d  %2d   %4d        %1d        %1d   %3d",
		totalscore,smarts,cumsmarts,numents,numbases,wave);
	}
	printf("\nWould you like instructions? ");
	gets(buf);
	if (buf[0] == 'Y' || buf[0] == 'y') {
	    page(HELPFILE);
	    printf("\nWould you like to play easy games for a while? ");
	    gets(buf);
	    if (buf[0] == 'Y' || buf[0] == 'y') {
		beginner = TRUE;
		lowspeed = TRUE;
	    }
	}
    }
    if (!smarts)
	smarts = ismarts;

#ifndef SIGTSTP
#define sigignore(sig) signal(sig,SIG_IGN)
#define sigset(sig,what) signal(sig,what)
#endif

    sigignore(SIGINT);  /* for inquiry of existence via kill call */
    sigignore(SIGTTOU);

    sigset(SIGHUP, hangup_catcher);
    sigset(SIGQUIT, hangup_catcher);
    sigset(SIGILL, hangup_catcher);
    sigset(SIGFPE, hangup_catcher);
    sigset(SIGBUS, hangup_catcher);
    sigset(SIGSEGV, hangup_catcher);
    sigset(SIGSYS, hangup_catcher);
    sigset(SIGTERM, hangup_catcher);
#ifdef SIGTSTP
    sigset(SIGXCPU, hangup_catcher);
    sigset(SIGCONT, cont_catcher);
#endif

    savetty();
    ospeed = _tty.sg_ospeed;

    /* get all that good termcap stuff */

    tcbuf = malloc(1024);		/* make place for termcap entry */
    tgetent(tcbuf,getenv("TERM"));	/* get termcap entry */
    tmpaddr = tcarea;			/* set up strange tgetstr pointer */
    tgetstr("pc",&tmpaddr);		/* get pad character */
    PC = *tcarea;			/* get it where tputs wants it */
    if (!tgetflag("bs")) {		/* is backspace not used? */
	BC = tmpaddr;			/* find out what is */
	tgetstr("bc",&tmpaddr);
    }
    else
	BC = "\b";			/* make a backspace handy */
    ND = tmpaddr;			/* non-destructive cursor right */
    tgetstr("nd",&tmpaddr);
    if (tmpaddr == ND)
	*tmpaddr++ = '\0';
    UP = tmpaddr;			/* move up a line */
    tgetstr("up",&tmpaddr);
    if (tmpaddr == UP)
	*tmpaddr++ = '\0';
    DO = tmpaddr;			/* move down a line */
    tgetstr("do",&tmpaddr);
    if (tmpaddr == DO)
	*tmpaddr++ = '\0';
    if (!*DO) {
	DO = tmpaddr;			/* move down a line */
	tgetstr("nl",&tmpaddr);
	if (tmpaddr == DO)
	    *tmpaddr++ = '\0';
    }
    CL = tmpaddr;			/* get clear string */
    tgetstr("cl",&tmpaddr);
    if (tmpaddr == CL)
	*tmpaddr++ = '\0';
    CE = tmpaddr;			/* clear to end of line string */
    tgetstr("ce",&tmpaddr);
    if (tmpaddr == CE)
	*tmpaddr++ = '\0';
    CM = tmpaddr;			/* cursor motion */
    tgetstr("cm",&tmpaddr);
    if (tmpaddr == CM)
	*tmpaddr++ = '\0';
    LINES = tgetnum("li");		/* lines per page */
    COLS = tgetnum("co");		/* columns on page */
    if (!COLS)
	COLS = 80;
    free(tcbuf);			/* recover 1024 bytes */

    BCsize = comp_tc(bsptr,BC,1);
    BC = bsptr;
    if (!BCsize)
	no_can_do();

    if (!*ND)				/* not defined? */
	NDsize = 1000;			/* force cursor addressing */
    else {
	NDsize = comp_tc(cmbuffer,ND,1);
	ND = malloc((unsigned)NDsize);
	movc3(NDsize,cmbuffer,ND);
	if (debugging) {
	    int scr;

	    printf("ND");
	    for (scr=0; scr<NDsize; scr++)
		printf(" %d",ND[scr]);
	    printf("\n");
	}
    }

    if (!*UP)				/* not defined? */
	UPsize = 1000;			/* force cursor addressing */
    else {
	UPsize = comp_tc(cmbuffer,UP,1);
	UP = malloc((unsigned)UPsize);
	movc3(UPsize,cmbuffer,UP);
	if (debugging) {
	    int scr;

	    printf("UP");
	    for (scr=0; scr<UPsize; scr++)
		printf(" %d",UP[scr]);
	    printf("\n");
	}
    }

    if (!*DO) {				/* not defined? */
	DO = "\n";			/* assume a newline */
	DOsize = 1;
    }
    else {
	DOsize = comp_tc(cmbuffer,DO,1);
	DO = malloc((unsigned)DOsize);
	movc3(DOsize,cmbuffer,DO);
	if (debugging) {
	    int scr;

	    printf("DO");
	    for (scr=0; scr<DOsize; scr++)
		printf(" %d",DO[scr]);
	    printf("\n");
	}
    }
    if (debugging)
	gets(cmbuffer);

    CMsize = comp_tc(cmbuffer,tgoto(CM,10,10),0);
    if (!CMsize)			/* not defined? */
	no_can_do();

    if (PC != '\0') {
	char *p;

	for (p=filler+sizeof(filler)-1;!*p;--p)
	    *p = PC;
    }
    charsperhalfsec = ospeed >= B9600 ? 480 :
		      ospeed == B4800 ? 240 :
		      ospeed == B2400 ? 120 :
		      ospeed == B1200 ? 60 :
		      ospeed == B600 ? 30 :
	      /* speed is 300 (?) */   15;

    gfillen = ospeed >= B9600 ? sizeof(filler) :
	      ospeed == B4800 ? 13 :
	      ospeed == B2400 ? 7 :
	      ospeed == B1200 ? 4 :
				1+BCsize;
    if (ospeed < B2400)
	lowspeed = TRUE;

    raw();
    noecho();
    nonl();
    if (totalscore) {
	clear();
	mvaddstr(12,25,"*** restoring saved game ***");
	roundsleep(1);
    }
    srand(getpid());

    do {
	for (keepgoing = TRUE;;) {
	    if (!experimenting) {
		savfil = fopen(savefilename,"w");
		fprintf(savfil,
		    "%-8s %10d, %2d,%5d,%2d,%2d,%3d %c%c%c%c%c%c%c%c\n",
		    loginname, totalscore, smarts, cumsmarts,
		    numents, numbases, wave,
		    apolspec ? 'a' : ' ',
		    beginner   ? 'b' : ' ',
		    crushspec  ? 'c' : ' ',
		    gornspec   ? 'g' : ' ',
		    massacre   ? 'm' : ' ',
		    romspec    ? 'r' : ' ',
		    tholspec   ? 't' : ' ',
		    lowspeed   ? 'l' : ' '
		);
		fprintf(savfil,"         running on %s, process #%d\n",
		    term+5,getpid());
		fclose(savfil);
	    }

	    lastscore = totalscore;
	    initialize();
	    play();
	    cumsmarts += smarts;
	    wavescore();
	  if (!keepgoing) break;
	    do {
		if (experimenting) {
		    mvaddstr(23,14,
		      "      [Hit space to continue, break to quit]       ");
		}
		else {
		    mvaddstr(23,14,
		      "[Hit space to continue, break to quit, esc to save]");
		}
		sleep(1);
		read(0, &tmp, 1);
		tmp &= 0177;
		if (tmp == BREAKCH || tmp == INTRCH) {
		    mvaddstr(23,14,
		      "                                                   ");
		    mvaddstr(23,33,
		      "Really quit? ");
		    read(0, &tmp, 1);
		    tmp &= 0177;
		    if (tmp == 'y' || tmp == 'Y')
			tmp = 0;
		    else
			tmp = 1;
		}
	    } while (tmp != ' ' && tmp != INTRCH && tmp != ESCCH &&
		tmp != BREAKCH);
	  if (tmp != ' ' && tmp != ESCCH) break;
	    if (!beginner && smarts < 20)
		smarts += 4;
	    else if (!beginner && smarts < 35)
		smarts += 2;
	    else if (smarts < 50)
		smarts++;
	  if (tmp == ESCCH) save_game();
	}
	score();

	smarts = ismarts;
	totalscore = cumsmarts = wave = 0;
	numents = 5;
	numbases = 3;
	apolspec = FALSE;
	beginner   = FALSE;
	crushspec  = FALSE;
	gornspec   = FALSE;
	massacre   = (ismarts >= 40);
	romspec    = FALSE;
	tholspec   = FALSE;

    } while (justonemoretime);

    if (!experimenting)
	unlink(savefilename);

    clear();
    resetty();
}

#define Root 0
#define Base 1
#define Enterprise 2
#define Star 3
#define Torp 4
#define Enemy 5
#define Web 6
#define Crusher 7

typedef struct object {
    char posx, posy;
    char velx, vely;
    struct object *next, *prev, *contend;
    long energy;
    long mass;
    char type;
    char image;
    char strategy;
} OBJECT;

OBJECT root = {0, 0, 0, 0, &root, &root, 0, 0, 0, Root, '?', 0};

OBJECT free_root = {0, 0, 0, 0, &free_root, &free_root, 0, 0, 0, Root, '?', 0};

OBJECT *ent, *base, *enemies, *movers, *realapollo, *make_object();

OBJECT *occupant[YSIZE][XSIZE];

int finish = 0;

long blast[YSIZE][XSIZE];
bool blasted, xblasted[XSIZE], yblasted[YSIZE];

char    bangy[YSIZE*XSIZE],
	bangx[YSIZE*XSIZE],
	bangs[YSIZE*XSIZE],
	c = ' ';

long    bangm[YSIZE*XSIZE];

int xx[20], yy[20];

int nxtbang;

int etorp, btorp;

int timer;

int status, entmode;

int evely, evelx, bvely, bvelx;

OBJECT *isatorp[2][3][3];

int aretorps;

char cmstore(ch)
register char ch;
{
    *maxcmstring++ = ch;
}

initialize()
{
    long e;
    int yoff, xoff;
    register int i, x, y, dist, ydist, xdist;
    char ch;
    FILE *mapfp;

    curscore = possiblescore = 0L;

    clear();
    while (root.next != &root) {
	root.next = root.next->next;
	free_object(root.next->prev);
    }
    root.prev = &root;
    enemies = movers = NULL;
    numos = numxes = 0;

#ifdef VAX
    asm("movc5 $0,_occupant,$0,$3680,_occupant");
    asm("movc5 $0,_blast,$0,$3680,_blast");	/* 3680 = XYSIZEx4 */
#else
    for (y=0;y<YSIZE;y++)
	for (x=0;x<XSIZE;x++) {
	    occupant[y][x] = 0;
	    blast[y][x] = 0;
	}
#endif
    for (y=0; y<YSIZE; y++)
	yblasted[y] = FALSE;
    for (x=0; x<XSIZE; x++)
	xblasted[x] = FALSE;
    blasted = FALSE;
    if (!starspec)
	if (smarts < 15)
	    inumstars = 50 + rand_mod(50);
	else
	    inumstars = exdis(800)+ rand_mod(100) + 1;
    if (!klingspec) {
	inumenemies = rand_mod((smarts+1)/2) + 1;
	if (massacre)
	    inumenemies += 10;
    }
    if (inumenemies+inumstars > YSIZE*XSIZE-20)
	inumstars = YSIZE*XSIZE-20 - inumenemies;
    if (inumstars < 0) {
	inumenemies += inumstars;
	inumstars = 0;
    }
    if (inumenemies < 0)
	inumenemies = 0;
    numstars = inumstars;
    inuminhab = numinhab = 0;
    inumroms = inumthols = inumgorns = 0;
    numapollos = apolspec || massacre ? 1 :
       ((!numstars || rand_mod(2) || smarts < 10) ? 0 : 1);
    inumapollos = apolloflag = 0;
    realapollo = NULL;
    inumcrushes = numcrushes =
	crushspec||massacre?1:(rand_mod(2000) < inumstars);
    inumenemies += inumcrushes;
    numenemies = inumenemies;
    if (numstars > 550)
	dist = 0;
    else
	dist = rand_mod(3);
    switch (dist) {
    case 0:				/* uniform random */
	ydist = xdist = 0;
	break;
    case 1:				/* clumped and maybe skewed */
	ydist = rand_mod(4);
	xdist = rand_mod(4);
	if (ydist & 2)
	    xdist &= 1;
	yoff = rand_mod(YSIZE);
	xoff = rand_mod(XSIZE);
	dist = (dist==2 ? numstars/2 : 0);
	break;
    case 2:				/* predefined or residual */
	dist = 0;
	sprintf(spbuf,"%ssmap.%d",SAVEDIR,rand_mod(INMAPS));
	if ((mapfp = fopen(spbuf,"r")) != NULL) {
	    fgets(spbuf,10,mapfp);
	    inumstars = numstars = atoi(spbuf);
	    if (inumenemies+inumstars > YSIZE*XSIZE-20)
		inumstars = numstars = YSIZE*XSIZE-20 - inumenemies;
	    ydist = rand_mod(2) + 4;	/* flip y axis? */
	    xdist = rand_mod(2) + 4;	/* flip x axis? */
	    yoff = rand_mod(YSIZE);	/* how much to shift y */
	    xoff = rand_mod(XSIZE);	/* how much to shift x */
	}
	else
	    ydist = xdist = 0;
	break;
    }
    for (i = 1; i <= numstars; i++) {
	if (dist && i == dist) {	/* flip to another skewing? */
	    ydist = rand_mod(4);
	    xdist = rand_mod(4);
	    if (ydist & 2)
		xdist &= 1;
	    yoff = rand_mod(YSIZE);
	    xoff = rand_mod(XSIZE);
	    dist = 0;
	}
	do {				/* until an open spot found */
	    switch (xdist) {
	    case 0:
		x = rand_mod(XSIZE);	/* pick from 0..39, uniform */
		break;
	    case 1: case 2: case 3:
		x = (int)((((double)(rand()-0x40000000)) *
		           ((double)(rand()-0x40000000))/1152921504606846976.0)
			  * 20.0) + xoff;	/* pick from -20..20, clumped */
		break;
	    case 4:
		if (fgets(spbuf,10,mapfp) == NULL)
		    ydist = xdist = 0;
		x = atoi(spbuf) + xoff;
		break;
	    case 5:
		if (fgets(spbuf,10,mapfp) == NULL)
		    ydist = xdist = 0;
		x = -atoi(spbuf) + xoff;
		break;
	    }
	    switch (ydist) {
	    case 0:
		y = rand_mod(YSIZE);
		break;
	    case 1:
		y = (int)((((double)(rand()-0x40000000)) *
		           ((double)(rand()-0x40000000))/1152921504606846976.0)
			  * 12.0) + yoff;	/* pick from -12..12, clumped */
		break;
	    case 2:
		y = (int)((((double)(rand()-0x40000000)) *
		           ((double)(rand()-0x40000000))/1152921504606846976.0)
			  * 12.0) + yoff + x*YSIZE/XSIZE;
				 		/* clumped & skewed */
		break;
	    case 3:
		y = (int)((((double)(rand()-0x40000000)) *
		           ((double)(rand()-0x40000000))/1152921504606846976.0)
			  * 12.0) + yoff - x*YSIZE/XSIZE;
						/* clumped & skewed */
		break;
	    case 4:
		if (fgets(spbuf,10,mapfp) == NULL)
		    ydist = xdist = 0;
		y = atoi(spbuf) + yoff;
		break;
	    case 5:
		if (fgets(spbuf,10,mapfp) == NULL)
		    ydist = xdist = 0;
		y = -atoi(spbuf) + yoff;
		break;
	    }
	    switch (xdist) {
	    case 2:
		x += y*XSIZE/YSIZE;
		break;
	    case 3:
		x -= y*XSIZE/YSIZE;
		break;
	    }
	    while (x<0) x += XSIZE00;
	    while (y<0) y += YSIZE00;
	    x %= XSIZE;
	    y %= YSIZE;
	} while (occupant[y][x]);
	e = rand_mod(32768);
	if (e<32000)
	    ch = '*';
	else {
	    ch = '@';
	    inuminhab = ++numinhab;
	}
	make_object(Star,ch,y,x,0,0,e,e/4,&root);
    }
    if (xdist >= 4 && mapfp != NULL)
	fclose(mapfp);
    if (numcrushes) {
	do {
	    x = rand_mod(XSIZE);
	    y = rand_mod(YSIZE);
	} while (occupant[y][x]);
	movers = make_object(Crusher,'<',y,x,0,1,32767L,32768,&root);
	possiblescore += 10000;
    }
    if (rand_mod(27-smarts/2) && !romspec && !gornspec)
	dist = 27-smarts/2;
    else
	dist = rand_mod(4) + 1;
    for (i = 1+inumcrushes; i <= numenemies; i++) {
	do {
	    x = rand_mod(XSIZE);
	    y = rand_mod(YSIZE);
	} while (occupant[y][x]);
	if (rand_mod(dist)) {
	    if (rand_mod((inumstars*3)/smarts+2) && !tholspec)
		ch = 'K';
	    else {
		ch = 'T';
		inumthols++;
	    }
	}
	else {
	    if (romspec == gornspec)
		e = 50;
	    else if (gornspec)
		e = 10;
	    else
		e = 90;
	    if (rand_mod(100) < e) {
		ch = 'R';
		inumroms++;
	    }
	    else {
		ch = 'G';
		inumgorns++;
	    }
	}
	e = 250 + (smarts-1) * 30 * 20 / numenemies;
	e = exdis((int)e) + e - exdis((int)e);
	make_object(Enemy,ch,y,x,0,0,e,e/4,&root);
	e /= 4;
	switch (ch) {
	case 'K':
	    possiblescore += e;
	    break;
	case 'T':
	    possiblescore += e*3/2;
	    break;
	case 'G':
	    possiblescore += e*2;
	    break;
	case 'R':
	    possiblescore += e*3;
	    break;
	}
	if (!enemies)
	    enemies = occupant[y][x];
	if (!movers)
	    movers = occupant[y][x];
    }
    if (numents) {
	do {
	    x = rand_mod(XSIZE);
	    y = rand_mod(YSIZE);
	} while (occupant[y][x]);
	e = 2000;
	ent = make_object(Enterprise,'E',y,x,0,0,e,e/2,&root);
	if (!enemies)
	    enemies = ent;
	if (!movers)
	    movers = ent;
    }
    if (numbases) {
	do {
	    x = rand_mod(XSIZE);
	    y = rand_mod(YSIZE);
	} while (occupant[y][x]);
	e = 10000;
	base = make_object(Base, 'B',y,x,0,0,e,e/4,&root);
	if (!enemies)
	    enemies = base;
	if (!movers)
	    movers = base;
    }

    for (i=0;i<2;i++) for (y=0;y<3;y++) for (x=0;x<3;x++)
    isatorp[i][y][x]=0;

    timer = 10000;
    finish = 0;
    bombed_out = FALSE;
    if (ent)
	entmode = status = 0;
    else
	if (base)
	    status = 2;
	else
	    status = 3;

    sprintf(spbuf,
    "%-4s%9d  E: %4d %2d B: %5d %3d Stars: %-3d Enemies: %-3d Stardate%5d.%1d",
	"   ", 0, 0, 0, 0, 0, 0, 0, timer/10, timer%10);
    mvaddstr(0,0,spbuf);
    oldeenergy = oldbenergy = oldcurscore =
    oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1;
					/* force everything to fill in */
    btorp = 500;
    etorp = 50;
}

play()
{
    bool done = FALSE;
    register OBJECT *curobj, *to;
    register int i, x, y;

    display_status();
#ifdef TIOCOUTQ
    while (output_pending() > charsperhalfsec)
	sleep(1);			 /* allow buffers to empty */
#endif
    sleep(4);
    do {
	timer++;
	nxtbang = 0;
	display_status();
#ifdef TIOCOUTQ
	while (output_pending() > charsperhalfsec)
	    sleep(1);
#endif
	if (lowspeed)
	    roundsleep(2);
	else
	    roundsleep(1);
	if (ent) {
	    evely = ent->vely;
	    evelx = ent->velx;
	}
	if (base) {
	    bvely = base->vely;
	    bvelx = base->velx;
	}
	get_commands(&done);
	if (done)
	    break;
	klingon_smarts();
	apolloflag = 0;
	if (ent) {
	    if (numapollos) {
		if (numstars) {
		    if (realapollo) {
			if (lookfor(realapollo->posy,realapollo->posx,
			    Enterprise)) {
			    apolloflag = 1;
			}
		    }
		    else if (lookfor(root.next->posy,root.next->posx,
			Enterprise)) {
			apolloflag = 1;
			realapollo = root.next;
			mvaddch(realapollo->posy+1,realapollo->posx*2,
			    'A');
			realapollo->image = 'A';
			realapollo->mass = 6000;
			inumapollos = 1;
			numenemies++;
			inumenemies++;
			possiblescore += 5000;
		    }
		    if (apolloflag) {
			if (blast[realapollo->posy][realapollo->posx] <= 32000)
			    evely = evelx = 0;
			realapollo->energy = 32000;
		    }
		}
		else
		    numapollos = 0;
	    }
	    ent->vely = evely;
	    ent->velx = evelx;
	}
	if (base) {
	    if (numapollos) {
		if (numstars) {
		    if (realapollo) {
			if (lookfor(realapollo->posy,realapollo->posx,
			    Base)) {
			    apolloflag |= 2;
			}
		    }
		    else if (lookfor(root.next->posy,root.next->posx,
			Base)) {
			apolloflag |= 2;
			realapollo = root.next;
			mvaddch(realapollo->posy+1,realapollo->posx*2,
			    'A');
			realapollo->image = 'A';
			realapollo->mass = 6000;
			inumapollos = 1;
			numenemies++;
			inumenemies++;
			possiblescore += 5000;
		    }
		    if (apolloflag & 2) {
			if (blast[realapollo->posy][realapollo->posx] <= 32000)
			    bvely = bvelx = 0;
			realapollo->energy = 32000;
		    }
		}
		else
		    numapollos = 0;
	    }
	    base->vely = bvely;
	    base->velx = bvelx;
	}
	if (aretorps) {
	    aretorps = 0;
	    for (i=0;i<2;i++) for (y=0;y<3;y++) for (x=0;x<3;x++) {
		if (curobj = isatorp[i][y][x]) {
		    to = occupant[(curobj->posy+curobj->vely+YSIZE00)%YSIZE]
				 [(curobj->posx+curobj->velx+XSIZE00)%XSIZE];
		    if (to && !to->vely && !to->velx) {
			unmake_object(curobj);
		    }
		    isatorp[i][y][x]=0;
		}
	    }
	}
	move_universe();
	if (finish) {
	    finish--;
	    if (!finish && (!(numenemies || numos) || (!ent && !base))) {
		done = TRUE;
		timer -= 5;
	    }
	}
	else if (!nxtbang && (!(numenemies || numos) || (!ent && !base)))
	    finish = 5;
    } while (!done);
    if (!numents && !numbases)
	keepgoing = FALSE;
}

wavescore()
{
    double power, effectscore, starscore, pi_over_2;
    long bonuses;
    long tmp;
    FILE *mapfp;

    clear();
    pi_over_2 = 3.14159265 / 2.0;
    power = pow((double)inumenemies+     /* total number of enemies */
			inumroms*2+      /* count roms 3 times */
			inumgorns+       /* count gorns 2 times */
			inumthols+       /* count thols 2 times */
			inumapollos*4+   /* count apollo 5 times */
			inumcrushes*3    /* count crushers 4 times */
	    , 0.50) *                    /* skew it a little */
	    (double)smarts;              /* average energy and intelligence */
    if (inumstars < 350 && inumenemies > 5)
	    power += (350.0 - (double)inumstars) * ((double)inumenemies - 5.0);
    if (inumstars > 850 && inumenemies > 2)
	    power += ((double)inumstars - 850.0) * ((double)inumenemies - 2.0);
    effectscore = ((double)curscore / possiblescore) *
	atan2(power, (double) timer - 9999.0) / pi_over_2;
    if (inumstars)
	starscore = (double) numstars / (double) inumstars;
    else
	starscore = 1.0;
    wave++;
    sprintf(spbuf,"Wave = %d, Difficulty = %d, cumulative difficulty = %d",
	 wave, smarts, cumsmarts);
    mvaddstr(1, 13+(smarts<10), spbuf);
    mvaddstr( 4, 68, " BONUS");
    sprintf(spbuf,"Efficiency rating:       %1.8f (diff=%0.2f,time=%d)",
	 effectscore, power, timer - 9999);
    mvaddstr( 5,5, spbuf);
    if (effectscore < 0.8)
	bonuses = tmp = 0;
    else
	bonuses = tmp = (long) ((effectscore-0.8) * smarts * 1000);
    sprintf(spbuf, "%6d", tmp);
    mvaddstr( 5, 68, spbuf);
    sprintf(spbuf,"Star save ratio:         %1.8f (%d/%d)",
	starscore, numstars, inumstars);
    mvaddstr( 6,5, spbuf);
    bonuses += tmp = (long) (((double)curscore / possiblescore) *
	(starscore*starscore) * smarts * 20);
    sprintf(spbuf, "%6d", tmp);
    mvaddstr( 6, 68, spbuf);
    sprintf(spbuf, "Inhabited stars destroyed:    %5d", inuminhab-numinhab);
    mvaddstr( 7,5, spbuf);
    bonuses += tmp = (long) (inuminhab-numinhab) * -500;
    sprintf(spbuf, "%6d", tmp);
    mvaddstr( 7, 68, spbuf);
    if (bombed_out) {
	mvaddstr( 8,5, "   For running away from reality:");
	bonuses += tmp = (long) -possiblescore/2;
	sprintf(spbuf, "%6d", tmp);
	mvaddstr( 8, 68,  spbuf);
    }
    sprintf(spbuf, "Enterprise: %-9s%5d remaining",
	ent?"saved":"destroyed", numents);
    mvaddstr( 9,5, spbuf);
    bonuses += tmp = ent?100:0;
    sprintf(spbuf, "%6d", tmp);
    mvaddstr( 9, 68, spbuf);
    sprintf(spbuf, "Base: %-9s      %5d remaining",
	base?"saved":"destroyed", numbases);
    mvaddstr(10,5, spbuf);
    bonuses += tmp = base?200:0;
    sprintf(spbuf, "%6d", tmp);
    mvaddstr(10, 68,  spbuf);
    if (beginner) {
	mvaddstr(12,19, "(Special games count only a fifth as much)");
	curscore /= 5;
	bonuses /= 5;
    }
    sprintf(spbuf, "Previous point total:%10d",lastscore);
    mvaddstr(15,24, spbuf);
    sprintf(spbuf, "Points this round:   %10d",curscore);
    mvaddstr(16,24, spbuf);
    sprintf(spbuf, "Bonuses:             %10d",bonuses);
    mvaddstr(17,24, spbuf);
    totalscore = lastscore + curscore + bonuses;
    sprintf(spbuf, "New point total:     %10d",totalscore);
    mvaddstr(18,24, spbuf);
    if (starscore < 0.8 && inumstars > 200 && numstars > 50) {
	sprintf(spbuf, "%ssmap.%d",SAVEDIR,rand_mod(OUTMAPS));
	if (mapfp = fopen(spbuf,"w")) {
	    register OBJECT *obj;

	    fprintf(mapfp,"%d\n",numstars);
	    for (obj = root.next; obj != &root; obj = obj->next) {
		if (obj->type == Star) {
		    fprintf(mapfp,"%d\n",obj->posx);
		    fprintf(mapfp,"%d\n",obj->posy);
		}
	    }
	    fclose(mapfp);
	}
    }
}

score()
{
    char tmp, buf[100], *retval, cdate[30];
    register FILE *logfd, *outfd;
    register int i;
    long nowtime, time();

    for (i=0; creat(LOCKFILE, 0) == -1 && i<10; i++)
	sleep(1);
    nowtime = time((long *)0);
    strcpy(cdate,ctime(&nowtime));
    if ((logfd = fopen(LOGFILE,"a")) != NULL) {
	fprintf(logfd,
	    "%-24s%7d%c%2d %4d %s",
	    realname, totalscore, c,smarts, cumsmarts, cdate);
	fclose(logfd);
    }
    strcpy(cdate+11,cdate+20);
    if (access(lowspeed?LSCOREBOARD:SCOREBOARD,0)) {
	logfd = fopen(lowspeed?LSCOREBOARD:SCOREBOARD,"w");
	fclose(logfd);
    }
    if ((logfd = fopen(lowspeed?LSCOREBOARD:SCOREBOARD,"r")) != NULL &&
	(outfd = fopen(TMPSCOREBOARD,"w")) != NULL) {
	for (i=0; i<20; i++) {
	    if ((retval = fgets(buf, 100, logfd)) == NULL)
		break;
	    if (atoi(buf+24) < totalscore)
		break;
	    if (!strncmp(buf,realname,24)) {
		i = 100;
		break;
	    }
	    fprintf(outfd, "%s", buf);
	}
	if (i == 100) {
	    mvaddstr(20,21, "You did not better your previous score");
	    fclose(outfd);
	    unlink(TMPSCOREBOARD);
	}
	else if (i < 20) {
	    fprintf(outfd, "%-24s%7d%c %2d    %4d    %s",
		realname, totalscore, c,smarts, cumsmarts, cdate);
	    i++;
	    sprintf(spbuf, "    Congratulations--you've placed %d%s",
	      i, i==1?"st":(i==2?"nd":(i==3?"rd":"th")));
	    if (retval != NULL) {
		if (strncmp(buf,realname,24)) {
		    fprintf(outfd, "%s", buf);
		    i++;
		}
		else
		    strcpy(spbuf,"Congratulations--you've bettered your score");
		while (i<20) {
		    if (fgets(buf, 100, logfd) == NULL)
			break;
		    if (strncmp(buf,realname,24)) {
			fprintf(outfd, "%s", buf);
			i++;
		    }
		}
	    }
	    mvaddstr(20,19, spbuf);
	    fclose(logfd);
	    fclose(outfd);
	    unlink(lowspeed?LSCOREBOARD:SCOREBOARD);
	    link(TMPSCOREBOARD,
		 lowspeed?LSCOREBOARD:SCOREBOARD);
	    unlink(TMPSCOREBOARD);
	    logfd = fopen(lowspeed?LSCOREBOARD:SCOREBOARD,"r");
	}
	else {
	    mvaddstr(20,22,"You did not place within the top 20");
	    fclose(outfd);
	}
    }
    else {
	sprintf(spbuf,"(Cannot access log file, error %d)", errno);
	mvaddstr(20,20,spbuf);
    }
    move(23,0,(char*)0);
    erase_eol();
    mvaddstr(23,28,"[Hit space to continue]");
    unlink(LOCKFILE);
    do {
	read(0, &tmp, 1);
	tmp &= 0177;
    } while (tmp != ' ' && tmp != INTRCH && tmp != BREAKCH);
    clear();
    if (logfd != NULL) {
	fseek(logfd, 0, 0);
	if (lowspeed)
	    mvaddstr(0,28,"TOP (LOW-SPEED) WARPISTS");
	else
	    mvaddstr(0,33,"TOP WARPISTS");
	mvaddstr(2,5,"RANK  WHO                       SCORE DIFF  CUMDIFF  WHEN");
	for (i=1; i<=20; i++) {
	    if (fgets(buf, 100, logfd) == NULL)
		break;
	    buf[strlen(buf)-1] = '\0';
	    sprintf(spbuf, "%2d   %s", i, buf);
	    mvaddstr(i+2,6, spbuf);
	}
	fclose(logfd);
    }
    roundsleep(1);
    mvaddstr(23,25,"Would you like to play again?");
    do {
	read(0, &tmp, 1);
	tmp &= 0177;
    } while (tmp != 'n' && tmp != 'N' && tmp != 'y' && tmp != INTRCH &&
	tmp != 'Y' && tmp != ' ' && tmp != '\n' && tmp != '\r' &&
	tmp != BREAKCH);
    if (tmp == 'n' || tmp == 'N' || tmp == INTRCH || tmp == BREAKCH)
	justonemoretime = FALSE;
}

save_game()
{
    FILE *savfil;

    if (experimenting)
	return;
    savfil = fopen(savefilename,"w");
    fprintf(savfil, "%-8s %10d, %2d,%5d,%2d,%2d,%3d %c%c%c%c%c%c%c%c\n",
	loginname, totalscore, smarts, cumsmarts, numents, numbases, wave,
	apolspec ? 'a' : ' ',
	beginner   ? 'b' : ' ',
	crushspec  ? 'c' : ' ',
	gornspec   ? 'g' : ' ',
	massacre   ? 'm' : ' ',
	romspec    ? 'r' : ' ',
	tholspec   ? 't' : ' ',
	lowspeed   ? 'l' : ' '
    );
    fclose(savfil);
    resetty();
    if (panic)
	exit(0);
    clear();
    exit(0);
}

void hangup_catcher()
{
    panic = TRUE;
    save_game();
    exit(0);
}

exdis(maxnum)
int maxnum;
{
    double temp, temp2;

    temp = (double) maxnum;
    temp2 = rand();
    return (int) exp(temp2 * log(temp)/0x7fffffff);
				       /*maxint*/
}

display_status()
{
    register int tmp;
    static char *status_names[] = {"Impl", "Warp", "Base", "****" };

    if (oldstatus != status) {
	sprintf(spbuf,"%-4s",status_names[status]);
	mvaddstr(0,0, spbuf);
	oldstatus = status;
    }
    if (curscore != oldcurscore) {
	sprintf(spbuf,"%9d",curscore);
	mvaddstr(0,4, spbuf);
	oldcurscore = curscore;
    }
    if (ent) {
	if (ent->energy != oldeenergy) {
	    oldeenergy = ent->energy;
	    sprintf(spbuf,"%4d",oldeenergy);
	    mvaddstr(0,18, spbuf);
	}
	if (etorp != oldetorp) {
	    sprintf(spbuf,"%2d",etorp);
	    mvaddstr(0,23, spbuf);
	    oldetorp = etorp;
	}
    }
    else {
	if (etorp >= 0) {
	    etorp = -1;
	    mvaddstr(0,18,"*******");
	}
    }
    if (base) {
	if (base->energy != oldbenergy) {
	    oldbenergy = base->energy;
	    sprintf(spbuf,"%5d",oldbenergy);
	    mvaddstr(0,29, spbuf);
	}
	if (btorp != oldbtorp) {
	    sprintf(spbuf,"%3d",btorp);
	    mvaddstr(0,35, spbuf);
	    oldbtorp = btorp;
	}
    }
    else {
	if (btorp >= 0) {
	    btorp = -1;
	    mvaddstr(0,29,"*********");
	}
    }
    if (numstars != oldstrs) {
	sprintf(spbuf,"%-3d",numstars);
	mvaddstr(0,46, spbuf);
	oldstrs = numstars;
    }
    if (numenemies != oldenemies) {
	sprintf(spbuf,"%-3d",numenemies);
	mvaddstr(0,59, spbuf);
	oldenemies = numenemies;
    }
    if (tmp = timer%10) {
	sprintf(spbuf,"%1d",tmp);
	mvaddstr(0,77, spbuf);
    }
    else {
	sprintf(spbuf,"%4d.%1d",timer/10,tmp);
	mvaddstr(0,72, spbuf);
    }
}

do_direction(dy,dx)
int dy, dx;
{
    register int decr;

    if (status < 2) {
	decr = 5+abs(evely)+abs(evelx)+tractor*tractor;
	if (ent->energy >= decr) {
	    ent->energy -= decr;
	    if (tractor) {
		if (tract(ent,dy,dx,tractor)) {
		    evely += tractor*dy;
		    evelx += tractor*dx;
		}
	    }
	    else {
		evely += dy;
		evelx += dx;
	    }
	    if (inumthols &&
	      occupant[(ent->posy+evely+YSIZE00)%YSIZE]
		      [(ent->posx+evelx+XSIZE00)%XSIZE]->type == Web)
		evely = evelx = 0;
	}
    }
    else if (status == 2) {
	decr = 500+abs(bvely)*5+abs(bvelx)*5+tractor*tractor*100;
	if (base->energy >= decr) {
	    base->energy -= decr;
	    if (tractor) {
		if (tract(base,dy,dx,tractor)) {
		    bvely += tractor*dy;
		    bvelx += tractor*dx;
		}
	    }
	    else {
		bvely += dy;
		bvelx += dx;
	    }
	    if (inumthols &&
	      occupant[(base->posy+bvely+YSIZE00)%YSIZE]
		      [(base->posx+bvelx+XSIZE00)%XSIZE]->type == Web)
		bvely = bvelx = 0;
	}
    }
    tractor = 0;
}

ctrl_direction(dy,dx)
int dy, dx;
{
    if (status < 2)
	fire_phaser(ent, dy, dx);
    else if (status == 2)
	fire_phaser(base, dy, dx);
}

shift_direction(dy,dx)
int dy, dx;
{
    if (status < 2)
	fire_torp(ent, dy, dx);
    else if (status == 2)
	fire_torp(base, dy, dx);
}

get_commands(done)
bool *done;
{
    char ch[80];
    register int i,count;
    register bool ctrla = FALSE;

top:
    while (count = input_pending()) {
	for (i=0; i<count; i++) {
	    read(0, &ch[i], 1);
	    ch[i] &= 0177;
	    if (ch[i] == BREAKCH || ch[i] == INTRCH) {
		int x;
		static char quest[] = "Do you wish to escape from reality? ";

		mvaddstr(12,22,quest);
		do {
		    read(0, &ch[i], 1);
		    ch[i] &= 0177;
		} while (ch[i] != 'y' && ch[i] != 'n');
		if (ch[i] == 'y') {
		    bombed_out = TRUE;
		    *done = TRUE;
		    return;
		}
		else {
		    for (x=11; x<=28; x++) {
			mvaddch(12,x*2,
			    occupant[11][x]?occupant[11][x]->image:' ');
			addspace();
		    }
		    roundsleep(3);
		    goto top;
		}
	    }
	}
	for (i=0; i<count; i++) {
	    if (ctrla) {
		switch (ch[i]) {
		case '1': case 'b':
		    ctrl_direction(1, -1);
		    break;
		case '2': case 'j':
		    ctrl_direction(1, 0);
		    break;
		case '3': case 'n':
		    ctrl_direction(1, 1);
		    break;
		case '4': case 'h':
		    ctrl_direction(0, -1);
		    break;
		case '6': case 'l':
		    ctrl_direction(0, 1);
		    break;
		case '7': case 'y':
		    ctrl_direction(-1, -1);
		    break;
		case '8': case 'k':
		    ctrl_direction(-1, 0);
		    break;
		case '9': case 'u':
		    ctrl_direction(-1, 1);
		    break;
		case 'r':
		    rewrite();
		    roundsleep(3);
		    ctrla = FALSE;
		    goto top;
		case 's':
		    clear();
		    while (!input_pending())
			sleep(1);
		    rewrite();
		    roundsleep(3);
		    ctrla = FALSE;
		    goto top;
#ifdef SIGTSTP
		case 'z':
		    mytstp();
		    sleep(4);
		    ctrla = FALSE;
		    goto top;
#endif
		default:
		    break;
		}
		ctrla = FALSE;
	    }
	    else {
		switch (ch[i]) {
#ifdef SIGTSTP
		case 'q':
		    clear();
		    mytstp();
		    sleep(4);
		    goto top;
#endif
		case 'i':
		    if (ent) {
			entmode = 0;
			if (status < 2)
			    status = 0;
		    }
		    break;
		case 'w':
		    if (ent) {
			entmode = 1;
			if (status < 2)
			    status = 1;
		    }
		    break;
		case 'o':
		    if (status < 2) {
			if (base)
			    status = 2;
		    }
		    else if (status == 2) {
			if (ent)
			    status = entmode;
		    }
		    break;
		case 'D':
		    if (status < 2) {
			make_blast(evely*2+ent->posy,evelx*2+ent->posx,
			    15000L, 3);
			ent->energy /= 2;
		    }
		    else if (status == 2) {
			make_blast(base->posy, base->posx, 15000L, 5);
		    }
		    break;
		case 'd':
		    {
			register OBJECT *obj;
			int x, y;

			for (obj = root.prev;
			  obj != &root;
			  obj = obj->prev) {
			    if (obj->image == '+') {
				blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE]
				     [x=(obj->posx+obj->velx+XSIZE00)%XSIZE]
				     += 1;
				yblasted[y] = TRUE;
				xblasted[x] = TRUE;
				blasted = TRUE;
				obj->mass = (massacre?3000:4000);
			    }
			}
		    }
		    break;
		case 's':
		    { register OBJECT *obj;
			for (obj = root.prev;
			  obj->type == Torp || obj->type == Web ||
			  obj->type == Star;
			  obj = obj->prev) {
			    if (obj->image == '+')
				obj->vely = obj->velx = 0;
			}
		    }
		    break;
		case '\001':
		    ctrla = TRUE;
		    break;
		case '\002':
		case '\003':
		case '\004':
		case '\005':
		case '\006':
		case '\007':
		case '\010':
		case '\011':
		case '\012':
		case '\013':
		case '\014':
		case '\015':
		case '\016':
		case '\017':
		case '\020':
		case '\021':
		case '\022':
		case '\023':
		case '\024':
		case '\025':
		case '\026':
		case '\027':
		case '\030':
		case '\031':
		case '\032':
		    ch[i] += 96;
		    i--;
		    ctrla = TRUE;
		    break;
		case '\033':
		    tractor = 0;
		    break;
		case 'a':
		    tractor++;
		    break;
		case 'r':
		    tractor--;
		    break;
		case '1': case 'b':
		    do_direction(1,-1);
		    break;
		case '2': case 'j':
		    do_direction(1,0);
		    break;
		case '3': case 'n':
		    do_direction(1,1);
		    break;
		case '4': case 'h':
		    do_direction(0,-1);
		    break;
		case '6': case 'l':
		    do_direction(0,1);
		    break;
		case '7': case 'y':
		    do_direction(-1,-1);
		    break;
		case '8': case 'k':
		    do_direction(-1,0);
		    break;
		case '9': case 'u':
		    do_direction(-1,1);
		    break;
		case '0': case 'S':
		    if (status < 2) {
			evely = 0;
			evelx = 0;
		    }
		    break;
		case '-':
		    if (status < 2 && ent->energy >= 10) {
			evely *= -1;
			evelx *= -1;
			ent->energy -= 10;
		    }
		    break;
		case '%': case '\177': case '_':
		    shift_direction(0, -1);
		    shift_direction(0, 1);
		    shift_direction(-1, 0);
		    shift_direction(1, 0);
		    shift_direction(-1, -1);
		    shift_direction(-1, 1);
		    shift_direction(1, -1);
		    shift_direction(1, 1);
		    break;
		case '!': case 'B':
		    shift_direction(1, -1);
		    break;
		case '@': case 'J':
		    shift_direction(1, 0);
		    break;
		case '#': case 'N':
		    shift_direction(1, 1);
		    break;
		case '$': case 'H':
		    shift_direction(0, -1);
		    break;
		case '^': case 'L':
		    shift_direction(0, 1);
		    break;
		case '&': case 'Y':
		    shift_direction(-1, -1);
		    break;
		case '*': case 'K':
		    shift_direction(-1, 0);
		    break;
		case '(': case 'U':
		    shift_direction(-1, 1);
		    break;
		case '?':
		    helper();
		    roundsleep(3);
		    goto top;
		default:
		    break;
		}
	    }
	}
    }
}

klingon_smarts()
{
    register OBJECT *curkl,*obj;
    register int prob, count, y, x;

    if (numcrushes && movers->type == Crusher) {
	movers->vely += (rand_mod(222) - 111) / 100;
	if (!(rand_mod(100))) {
	    setimage(movers, (movers->velx *= -1) < 0 ? '>' : '<');
	}
    }
    for (curkl = enemies; curkl->type == Enemy; curkl = curkl->next) {
	if (curkl->image == 'R' && curkl->energy > 300) {
	    setimage(curkl, ' ');
	}
	if (curkl->vely || curkl->velx)
	    prob = 20;
	else
	    prob = 4;
	count = 11;
	while (--count &&
	       (!(rand_mod(prob)) ||
	        occupant[y=(curkl->posy+curkl->vely+YSIZE00)%YSIZE]
		        [x=(curkl->posx+curkl->velx+XSIZE00)%XSIZE]
		      ->type == Star ||
	        (occupant[y][x]->type == Web &&
	         (curkl->image != 'T' ||
	          (count > 5 && occupant[y][x]->image ==
		   (curkl->vely?
		    (curkl->velx?
		     (curkl->velx==curkl->vely?
		      '\\'
		     :
		      '/'
		     )
		    :
		     '|'
		    )
		   :
		    '-'
		   )
		  )
		 )
		)
	       )
	      ) {
	    if (curkl->energy >= 2500 && curkl->image != 'T') {
		curkl->vely = rand_mod(5) - 2;
		curkl->velx = rand_mod(5) - 2;
	    }
	    else {
		curkl->vely = rand_mod(3) - 1;
		curkl->velx = rand_mod(3) - 1;
	    }
	}
	if (count != 10) {
	    if (curkl->image == ' ') {
		setimage(curkl, 'R');
	    }
	    if (!count) {
		curkl->vely = 0;
		curkl->velx = 0;
	    }
	}
	if (curkl->image == 'T' && (curkl->velx || curkl->vely)) {
	    make_object(Web,
            curkl->vely?
	     (curkl->velx?
	      (curkl->velx==curkl->vely?
	       '\\'
	      :
	       '/'
	      )
	     :
	      '|'
	     )
	    :
	     '-',
	    curkl->posy,curkl->posx,0,0,32767L,32767L,&root);
	    if ((obj = occupant[y][x]) && obj->type == Web) {
		unmake_object(obj);
		occupant[y][x] = 0;
	    }
	}
    }
    /* klingon fighting */
    attack(base);
    attack(ent);
}

move_universe()
{
    register OBJECT *curobj;
    register int x, y;
    register OBJECT *temp;
    OBJECT *thenext;

    for (curobj = movers; curobj != &root; curobj = curobj->next) {
	x = curobj->posx;
	y = curobj->posy;
	if (curobj == occupant[y][x]) {
	    occupant[y][x] = 0;
	}
	else if (curobj->type != Torp && curobj->type != Web) {
	    resetty();
	    abort();
	}
    }
    for (curobj = movers; curobj != &root; curobj = thenext) {
	thenext = curobj->next;
	if (curobj->vely || curobj->velx) {
	    y = curobj->posy;
	    x = curobj->posx;
	    if (curobj->image != ' ' &&
		(!occupant[y][x] || occupant[y][x]->image==' ') ) {
		move(y+1, x*2, " ");
	    }
	    y = (y + curobj->vely + YSIZE00) % YSIZE;
	    x = (x + curobj->velx + XSIZE00) % XSIZE;
	    if (occupant[y][x]->type != Star || curobj->type != Torp ||
	      (curobj->image != 'o' && curobj->image != 'O' &&
	       curobj->image != 'X')) {
		curobj->posy = y;
		curobj->posx = x;
	    }
	    else {
		curobj->vely = curobj->velx = 0;
		y = curobj->posy;
		x = curobj->posx;
	    }
	}
	else {
	    y = curobj->posy;
	    x = curobj->posx;
	    if (curobj->type == Web ||
		curobj->type == Star ||
		curobj->type == Torp) {
		curobj->strategy = 0;
		curobj->next->prev = curobj->prev;
		curobj->prev->next = curobj->next;
		curobj->prev = movers->prev;
		curobj->next = movers;
		movers->prev->next = curobj;
		movers->prev = curobj;
	    }
	}
	if (temp = occupant[y][x]) {
	    if (!temp->contend) {
		if (temp->type == Torp) {
		    if (temp->image == '+')
			blast[y][x] += 1250;
		    else if (temp->image == 'o')
			blast[y][x] += 500;
		    else if (temp->image == 'O')
			blast[y][x] += 5000;
		}
	    }
	    if (curobj->type != Enemy || temp->type != Enemy)
		blast[y][x] += rand_mod(751)+1;
	    else
		blast[y][x] += 10;
	    yblasted[y] = TRUE;
	    xblasted[x] = TRUE;
	    blasted = TRUE;
	    curobj->contend = temp;
	    occupant[y][x] = curobj;
	    if (curobj->type == Crusher)
		blast[y][x] += 100000;
	    else if (curobj->type == Torp) {
		if (curobj->image == '+')
		    blast[y][x] += 1250;
		else if (curobj->image == 'o')
		    blast[y][x] += 500;
		else if (curobj->image == 'O')
		    blast[y][x] += 5000;
	    }
	}
	else {
	    occupant[y][x] = curobj;
	    if (curobj->image != ' ' &&
	        (curobj->velx || curobj->vely ||
		 curobj->type == Torp || curobj->type == Web) ) {
		mvaddc(y+1, x*2, curobj->image);
	    }
	    if (curobj->type == Crusher) {
		blast[y][x] += 100000;
		yblasted[y] = TRUE;
		xblasted[x] = TRUE;
		blasted = TRUE;
	    }
	}
    }
    if (blasted) {
	int minxblast = -1, maxxblast = -2;
	long tmpblast;

	blasted = FALSE;
	for (x=0; x<XSIZE; x++) {
	    if (xblasted[x]) {
		xblasted[x] = FALSE;
		maxxblast = x;
		if (minxblast < 0)
		    minxblast = x;
	    }
	}
	for (y=0; y<YSIZE; y++) {
	    if (yblasted[y]) {
		yblasted[y] = FALSE;
		for (x=minxblast; x<=maxxblast; x++) {
		    if (tmpblast = blast[y][x]) {
			register OBJECT *biggie = 0;

			blast[y][x] = 0;
			if (temp = occupant[y][x]) {
			    if (tmpblast < 100000)
				make_plink(y,x);
			    for ( ;temp;
			      temp = curobj->contend,curobj->contend = 0){
				curobj = temp;
				if (curobj == ent &&
				   (ent->energy > 500 || apolloflag & 1))
				    curobj->energy -= tmpblast /
				       ((apolloflag & 1)?
					20: 5+abs(ent->velx)+abs(ent->vely));
				else if (curobj == base &&
				   (base->energy > 1000 || apolloflag & 2))
				    curobj->energy -= tmpblast /
				       ((apolloflag & 2)?20:5);
				else if (curobj->type == Crusher) {
				    if (tmpblast > 132767)
					curobj->energy -= (tmpblast - 100000);
				    else {
					curobj->energy += (tmpblast - 100000);
					if (curobj->energy > 32767)
					    curobj->energy = 32767;
				    }
				}
				else if (massacre && curobj->type == Enemy)
				    curobj->energy -= tmpblast / 10;
				else
				    curobj->energy -= tmpblast;
				if (curobj->energy < 0) {
				    if (tmpblast < 100000 &&
					curobj->image != 'G')
					make_blast(y,x,curobj->mass,
					   (curobj->type==Web?2:1));
				    else if (apolloflag && curobj->image == 'A')
					make_blast(y,x,8192L,1);
				    else if (curobj->type == Crusher) {
					int i;

					make_blast(y,(x+XSIZE00)%XSIZE,10000L,0);
					if (curobj->image == '<') {
					    for (i=XSIZE00; i<=XSIZE01; i++)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    for (i=XSIZE00; i<=XSIZE02; i++)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    make_blast(y,(x+XSIZE03)%XSIZE,
						10000L,1);
					    for (i=XSIZE00; i<=XSIZE08; i++)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					}
					else {
					    for (i=XSIZE00; i>=XSIZE99; i--)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    for (i=XSIZE00; i>=XSIZE98; i--)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    make_blast(y,(x+XSIZE97)%XSIZE,
						10000L,1);
					    for (i=XSIZE00; i>=XSIZE92; i--)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					}
				    }
				    switch (curobj->image) {
				    case 'A':
					numapollos = apolloflag = 0;
					numstars--;
					numenemies--;
					curscore += 5000;
					break;
				    case 'E': case 'e':
					ent = 0;
					numents--;
					if (base)
					    status = 2;
					else
					    status = 3;
					break;
				    case 'B': case 'b':
					base = 0;
					numbases--;
					if (ent)
					    status = entmode;
					else
					    status = 3;
					break;
				    case '<': case '>':
					numenemies--;
					numcrushes = 0;
					curscore += 10000;
					if (curobj == enemies)
					    enemies = curobj->next;
					break;
				    case 'K':
					numenemies--;
					curscore += curobj->mass;
					if (curobj == enemies)
					    enemies = curobj->next;
					break;
				    case 'T':
					numenemies--;
					curscore += curobj->mass*3/2;
					if (curobj == enemies)
					    enemies = curobj->next;
					break;
				    case 'R': case ' ':
					numenemies--;
					curscore += curobj->mass*3;
					if (curobj == enemies)
					    enemies = curobj->next;
					break;
				    case 'G':
					numenemies--;
					curscore += curobj->mass*2;
					if (curobj == enemies)
					    enemies = curobj->next;
					{
					    int xxx,yyy;

					    for (xxx = -1; xxx<=1; xxx++)
						for (yyy = -1; yyy<=1; yyy++)
						    if (rand_mod(2))
							fire_torp(curobj,
							    yyy,xxx);
					}
					break;
				    case '*':
					numstars--;
					break;
				    case '@':
					numstars--;
					numinhab--;
					break;
				    case 'x':
					curscore += 10;
					break;
				    case 'X':
					curscore += 100;
					numxes--;
					break;
				    case 'o':
					curscore += 100;
					numos--;
					break;
				    case 'O':
					curscore += 200;
					numos--;
					break;
				    }
				    unmake_object(curobj);
				}
				else {
				    if (!biggie)
					biggie = curobj;
				    else {
					if (biggie->mass > curobj->mass)
					    bounce(curobj);
					else {
					    bounce(biggie);
					    biggie = curobj;
					}
				    }
				}
			    }
			    if (biggie) {
				occupant[y][x] = biggie;
				mvaddch(y+1,x*2, biggie->image);
			    }
			    else {
				occupant[y][x] = 0;
				mvaddch(y+1, x*2, ' ');
			    }
			}
		    }
		}
	    }
	}
    }
    do_bangs();
    if (numcrushes && movers->type == Crusher)
	movers->vely = 0;
    if (curobj = base) {
	char ch;

	curobj->velx = 0;
	curobj->vely = 0;
	curobj->energy += 25*lookaround(curobj->posy,curobj->posx,Star);
	if (curobj->energy > 10000)
	    curobj->energy = 10000;
	if (curobj->energy >= 1000)
	    ch = 'B';
	else
	    ch = 'b';
	if (ch != curobj->image) {
	    setimage(curobj, ch);
	}
    }
    if (curobj = ent) {
	char ch;

	if (entmode == 0) {
	    curobj->velx = 0;
	    curobj->vely = 0;
	}
	if (base && !curobj->velx && !curobj->vely &&
	  lookfor(curobj->posy,curobj->posx,Base)) {
	    int tmp;

	    tmp = (int) (base->energy - 1000 < 2000 - curobj->energy ?
		         base->energy - 1000 : 2000 - curobj->energy);
	    if (tmp < 0)
		tmp = 0;
	    curobj->energy += tmp;
	    base->energy -= tmp;
	    tmp = (btorp < 50 - etorp ?
		   btorp : 50 - etorp);
	    etorp += tmp;
	    btorp -= tmp;
	}
	if (curobj->energy >= 500)
	    ch = 'E';
	else
	    ch = 'e';
	if (ch != curobj->image) {
	    setimage(curobj, ch);
	}
    }
}

lookaround(y, x, what)
register int y, x;
register char what;
{
    register count=0, xp, xm;

    if (occupant[y][xp=(x+XSIZE01)%XSIZE]->type == what)  /* 0, 1 */
	count++;
    if (occupant[y][xm=(x+XSIZE99)%XSIZE]->type == what)  /* 0, -1 */
	count++;
    if (occupant[y=(y+YSIZE99)%YSIZE][xp]->type == what)  /* -1, 1 */
	count++;
    if (occupant[y][x]->type == what)                     /* -1, 0 */
	count++;
    if (occupant[y][xm]->type == what)                    /* -1, -1 */
	count++;
    if (occupant[y=(y+2)%YSIZE][xp]->type == what)        /* 1, 1 */
	count++;
    if (occupant[y][x]->type == what)                     /* 1, 0 */
	count++;
    if (occupant[y][xm]->type == what)                    /* 1, -1 */
	count++;
    return (count);
}

lookfor(y, x, what)
register int y, x;
register char what;
{
    register int xp, xm;

    if (occupant[y][xp=(x+XSIZE01)%XSIZE]->type == what ||  /* 0, 1 */
        occupant[y][xm=(x+XSIZE99)%XSIZE]->type == what ||  /* 0, -1 */
        occupant[y=(y+YSIZE99)%YSIZE][xp]->type == what ||  /* -1, 1 */
        occupant[y][x]->type == what                    ||  /* -1, 0 */
        occupant[y][xm]->type == what                   ||  /* -1, -1 */
        occupant[y=(y+2)%YSIZE][xp]->type == what       ||  /* 1, 1 */
        occupant[y][x]->type == what                    ||  /* 1, 0 */
        occupant[y][xm]->type == what)                      /* 1, -1 */
	return(1);
    return (0);
}

make_plink(y,x)
int x,y;
{
    move(y+1,x*2,(char*)0);
    beg_qwrite();
    *filler = '@';
    qwrite();
    if (occupant[y][x])
	qaddc(occupant[y][x]->image);
    else
	qaddspace();
    end_qwrite();
}

make_blast(y,x,mass,size)
int x,y,size;
long mass;
{
    bangy[nxtbang] = y;
    bangx[nxtbang] = x;
    bangm[nxtbang] = mass;
    bangs[nxtbang++] = size;
    move(y+1,x*2,(char*)0);
    beg_qwrite();
    *filler = '@';
    qwrite();
    *filler = '#';
    qwrite();
    *filler = '@';
    qwrite();
    *filler = '#';
    qwrite();
    *filler = '@';
    qwrite();
    if (occupant[y][x])
	qaddc(occupant[y][x]->image);
    else
	qaddspace();
    end_qwrite();
}

do_bangs()
{
    register int x, y, i, j;

    /* read blast list, doing blasts on screen and updating blast array */
    for (i=0; i<nxtbang; i++) {
	if (bangm[i] != 32767)
	    bangm[i] *= 4;
	for (y=bangy[i]-bangs[i],x=bangx[i]-bangs[i],j=bangs[i]<<1;j>=0;
	  y++,x++,--j) {
	    yblasted[yy[j] = (y+YSIZE00) % YSIZE] = TRUE;
	    xblasted[xx[j] = (x+XSIZE00) % XSIZE] = TRUE;
	}
	blasted = TRUE;
	for (y=bangs[i]<<1;y>=0;--y) {
	    for (x=bangs[i]<<1;x>=0;--x) {
		if (bangm[i] != 32767 ||
		  occupant[yy[y]][xx[x]]->type != Web)
		    blast[yy[y]][xx[x]] += bangm[i];
	    }
	}
    }
}

bounce(obj)
register OBJECT *obj;
{
    register int x, y, count=0;

    y = (obj->posy - obj->vely + YSIZE00) % YSIZE;
    x = (obj->posx - obj->velx + XSIZE00) % XSIZE;
    while (occupant[y][x]) {
	y = (y + rand_mod(3) - 1 + YSIZE00) % YSIZE;
	x = (x + rand_mod(3) - 1 + XSIZE00) % XSIZE;
	if (++count > 10000) {     /* if universe full, get out of it fast */
	    unmake_object(obj);
	    if (ent) unmake_object(ent);
	    if (base) unmake_object(base);
	    finish = 1;
	    return;
	}
    }
    obj->posy = y;
    obj->posx = x;
    obj->vely = 0;
    obj->velx = 0;
    occupant[y][x] = obj;
    mvaddc(y+1, x*2, obj->image);
}

OBJECT *
make_object(typ, img, py, px, vy, vx, energ, mas, where)
char typ;
char img;
int px, py, vx, vy;
long energ, mas;
OBJECT *where;
{
    register OBJECT *obj;

    if (free_root.next == &free_root)
	obj = (OBJECT *) malloc(sizeof(root));
    else {
	obj = free_root.next;
	free_root.next = obj->next;
	obj->next->prev = &free_root;
    }
    obj->type = typ;
    obj->image = img;
    obj->next = where;
    obj->prev = where->prev;
    where->prev = obj;
    obj->prev->next = obj;
    obj->velx = vx;
    obj->vely = vy;
    obj->contend = 0;
    obj->strategy = 0;
    obj->posx = px;
    obj->posy = py;
    if (typ != Torp && typ != Web) {
	occupant[py][px] = obj;
	mvaddch(py+1, px*2, img);
    }
    obj->energy = energ;
    obj->mass = mas;
    return(obj);
}

unmake_object(curobj)
register OBJECT *curobj;
{
    curobj->prev->next = curobj->next;
    curobj->next->prev = curobj->prev;
    if (curobj == movers) {
	movers = curobj->next;
    }
    free_object(curobj);
}

free_object(curobj)
register OBJECT *curobj;
{
    curobj->next = free_root.next;
    curobj->prev = &free_root;
    free_root.next->prev = curobj;
    free_root.next = curobj;
}

fire_torp(from, ydir, xdir)
register OBJECT *from;
register int ydir, xdir;
{
    register OBJECT *to;

    if (from->type == Enemy ||
       (from == ent && etorp > 0) ||
       (from == base && btorp > 0)) {
	to = occupant[(from->posy+from->vely+ydir+YSIZE00)%YSIZE]
		     [(from->posx+from->velx+xdir+XSIZE00)%XSIZE];
	if (from->type != Enemy || !to || to->vely || to->velx) {
	    if (from->type != Enemy &&
		 (to = isatorp[from==base][ydir+1][xdir+1])) {
		to->vely += ydir;
		to->velx += xdir;
	    }
	    else {
		if (from == ent) {
		    to = make_object(Torp, '+', from->posy,from->posx,
			from->vely+ydir,from->velx+xdir, 0L, 1L,&root);
		    to->strategy = 1;
		    aretorps++;
		    isatorp[0][ydir+1][xdir+1] = to;
		    etorp--;
		}
		else if (from == base) {
		    to = make_object(Torp, '+', from->posy,from->posx,
			from->vely+ydir,from->velx+xdir, 0L, 1L,&root);
		    to->strategy = 1;
		    aretorps++;
		    isatorp[1][ydir+1][xdir+1] = to;
		    btorp--;
		}
		else if (from->image == 'G') {
		    numos++;
		    to = make_object(Torp, 'o', from->posy,from->posx,
			from->vely+ydir,from->velx+xdir, 100L, 1L,&root);
		    to->strategy = 1;
		    if (rand_mod((massacre?52:53)-smarts))
			possiblescore += 100;
		    else {
			possiblescore += 200;
			to->image = 'O';
		    }
		}
		else {
		    to = make_object(Torp, 'x', from->posy,from->posx,
			from->vely+ydir,from->velx+xdir, 0L, 1L,&root);
		    to->strategy = 1;
		    if (rand_mod((massacre?52:53)-smarts))
			possiblescore += 10;
		    else {
			possiblescore += 100;
			to->image = 'X';
			to->mass = 1000;
			numxes++;
		    }
		}
	    }
	}
    }
}

attack(attackee)
OBJECT *attackee;
{
    register int dx, dy, curx, cury, prob;
    register OBJECT *obj;
    bool torps, webnear;

    if (attackee) {
	for (dx= -1; dx<=1 ; dx++) {
	    for (dy= -1; dy<=1; dy++) {
		if (dx||dy) {
		    cury = attackee->posy;
		    curx = attackee->posx;
		    torps = webnear = FALSE;
		    for (prob = (massacre?20:15);prob;prob--) {
			cury = (cury + dy + YSIZE00) % YSIZE;
			curx = (curx + dx + XSIZE00) % XSIZE;
			if (obj = occupant[cury][curx]) {
			    switch (obj->image) {
			    case 'K': case 'R': case ' ':
				if (rand_mod(51 - smarts) <= prob) {
				    switch (obj->strategy?0:
					  rand_mod(ent?4:2)) {
				    case 1: case 2:
					if (-dy + attackee->vely == obj->vely
					 && -dx + attackee->velx == obj->velx)
					    fire_torp(obj,
					     -dy + attackee->vely,
					     -dx + attackee->velx);
					else
					    fire_torp(obj,
					     -dy + attackee->vely - obj->vely,
					     -dx + attackee->velx - obj->velx);
					if (obj->image == ' ')
					    setimage(obj, 'R');
					break;
				    case 3:
					obj->vely = -dy + attackee->vely;
					obj->velx = -dx + attackee->velx;
					break;
				    case 0:
					if (!torps && obj->energy > 1000) {
					    fire_phaser(obj, -dy, -dx);
					    if (smarts == 50 &&
					       (prob < (massacre?15:10)
						|| attackee==base) &&
					       (massacre || rand_mod(2)))
						while (rand_mod(2))
						    fire_phaser(obj, -dy, -dx);
					    if (obj->image == ' ')
						setimage(obj, 'R');
					}
					if (obj->strategy) {
					    obj->velx = obj->vely = 0;
					    if (obj->energy < 1000 ||
						  bvely || bvelx)
						obj->strategy = 0;
					}
					else if (!ent && prob < 10 &&
					  !(rand_mod(52 - smarts)) )
					    obj->strategy = 1;
					break;
				    }
				}
				goto bombout;
			    case 'G':
				if (rand_mod(51 - smarts) <= prob) {
				    if (-dy + attackee->vely == obj->vely
				     && -dx + attackee->velx == obj->velx)
					fire_torp(obj,
					 -dy + attackee->vely,
					 -dx + attackee->velx);
				    else
					fire_torp(obj,
					 -dy + attackee->vely - obj->vely,
					 -dx + attackee->velx - obj->velx);
				}
				goto bombout;
			    case 'T':
				if (webnear && prob < (massacre?15:10)) {
				    if (massacre || !(rand_mod(52-smarts))){
					if (!torps && obj->energy > 1000) {
					    fire_phaser(obj, -dy, -dx);
					    while (rand_mod(2))
						fire_phaser(obj, -dy, -dx);
					}
				    }
				}
				goto bombout;
			    case '+':
				torps = FALSE;
				break;
			    case 'x':
				torps = TRUE;
				break;
			    case 'X':
				torps = TRUE;
				if (prob == (massacre?20:15)) {
				    int y, x;

				    blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE]
					 [x=(obj->posx+obj->velx+XSIZE00)%XSIZE]
				      += 100;
				    yblasted[y] = TRUE;
				    xblasted[x] = TRUE;
				    blasted = TRUE;
				}
				break;
			    case '|': case '-': case '/': case '\\':
				webnear = (prob > (massacre?17:13));
				torps = FALSE;
				break;
			    case 'o': case 'O':
				obj->vely = -dy + attackee->vely;
				obj->velx = -dx + attackee->velx;
				if (!obj->strategy) {  /* not a mover? */
				    obj->strategy = 1;
				    obj->prev->next = obj->next;
				    obj->next->prev = obj->prev;
				    root.prev->next = obj;
				    obj->prev = root.prev;
				    root.prev = obj;
				    obj->next = &root;
				}
				torps = TRUE;
				break;
			    default:
				goto bombout;
			    }
			}
		    }
bombout:            ; /* end of loop */
		}
	    }
	}
    }
}

fire_phaser(obj, dy, dx)
OBJECT *obj;
int dy, dx;
{
    register int y, x, skipping, size=5000;
    int decr = 50, oldy, oldx;
    static char curchar[] = "@* ";

    if (obj == ent)
	decr = 100;
    else if (obj == base) {
	decr = 1000;
	size = 200;
    }
    if (!dy)
	curchar[2] = '-';
    else if (!dx)
	curchar[2] = '!';
    else if (dy == dx)
	curchar[2] = '\\';
    else
	curchar[2] = '/';
    if (obj->energy >= decr) {
	obj->energy -= decr;
	for (
	  /* initialize */
	  skipping = (obj==ent),
	  y = (obj->posy+(obj==base?dy*2:dy)+YSIZE00)%YSIZE,
	  x = (obj->posx+(obj==base?dx*2:dx)+XSIZE00)%XSIZE;
	  /* while */
	  size && (!occupant[y][x]||(skipping && occupant[y][x]->type==Star));
	  /* at end of loop */
	  y = (y+dy+YSIZE00) % YSIZE,
	  x = (x+dx+XSIZE00) % XSIZE,
	  size = size * 3 / 4 ) {
	    move(y+1,x*2,(char*)0);
	    beg_qwrite();
	    if (obj == base || obj->image == 'T') {
		*filler = '@';
		qwrite();
		*filler = '#';
		qwrite();
		*filler = '~';
		qwrite();
		*filler = '%';
		qwrite();
		*filler = ':';
		qwrite();
		*filler = '@';
	    }
	    else {
		*filler = size >= 500 ?
			  *curchar : (size >= 50 ?
				     curchar[1] :
				     curchar[2]);
	    }
	    qwrite();
	    if (occupant[y][x])
		qaddc(occupant[y][x]->image);
	    else {
		qaddspace();
		if (skipping)
		    skipping = 0;
	    }
	    end_qwrite();
	}
	if (size) {
	    if (occupant[y][x]->type != Crusher ||
	        (dy==0 && dx==-(occupant[y][x]->velx))
	       ) {
		move(y+1,x*2,(char*)0);
		beg_qwrite();
		if (occupant[y][x]->image == ' ') {
		    occupant[y][x]->image = 'R';
		    *filler = 'R';
		    qwrite();
		    qwrite();
		}
		*filler = '@';
		qwrite();
		*filler = '#';
		qwrite();
		*filler = '@';
		qwrite();
		*filler = '#';
		qwrite();
		*filler = '@';
		qwrite();
		qaddc(occupant[y][x]->image);
		end_qwrite();
		oldy = y;
		oldx = x;
		y = (occupant[oldy][oldx]->posy + occupant[oldy][oldx]->vely +
			YSIZE00) % YSIZE;
		x = (occupant[oldy][oldx]->posx + occupant[oldy][oldx]->velx +
			XSIZE00) % XSIZE;
		if (occupant[y][x]->type == Star) {
		    y = occupant[oldy][oldx]->posy;
		    x = occupant[oldy][oldx]->posx;
		}
		blast[y][x] +=
			(obj==base?10000:(obj==ent?size*4:
			  (obj->image=='T'?10000:size*smarts/25)));
		yblasted[y] = TRUE;
		xblasted[x] = TRUE;
		blasted = TRUE;
	    }
	    else if (occupant[y][x]->type == Crusher &&
	      !dy && dx==occupant[y][x]->velx) {
		occupant[y][x]->image =
		    (occupant[y][x]->velx *= -1) < 0 ? '>' : '<';
	    }
	}
    }
}

tract(obj, dy, dx, to_or_fro)
OBJECT *obj;
int dy, dx;
{
    register int y, x, size=10;
    static char ch;
    OBJECT *tractee;

    if (!dy)
	ch = '|';
    else if (!dx)
	ch = '-';
    else if (dy == dx)
	ch = '/';
    else
	ch = '\\';
    {
	for (
	  y = (obj->posy+dy+YSIZE00)%YSIZE,
	  x = (obj->posx+dx+XSIZE00)%XSIZE;
	  size && (!occupant[y][x]);
	  y = (y+dy+YSIZE00) % YSIZE, x = (x+dx+XSIZE00) % XSIZE, size--) {
	    move(y+1,x*2,(char*)0);
	    beg_qwrite();
	    *filler = ch;
	    qwrite();
	    qwrite();
	    qaddspace();
	    end_qwrite();
	}
	tractee = occupant[y][x];
	if (size) {
	    if (tractee->type != Web &&
		(tractee->mass < obj->mass * 5 ||
		 (tractee->type == Crusher && !dx) ) ) {
		if (tractee == ent) {
		    evely -= dy * to_or_fro;
		    evelx -= dx * to_or_fro;
		}
		else if (tractee == base) {
		    bvely -= dy * to_or_fro;
		    bvelx -= dx * to_or_fro;
		}
		else {
		    tractee->vely -= dy * to_or_fro;
		    tractee->velx -= dx * to_or_fro;
		}
		if (tractee->type == Torp ||
		    tractee->type == Star) {
		    if (!tractee->strategy) {  /* not a mover? */
			tractee->strategy = 1;
			tractee->prev->next = tractee->next;
			tractee->next->prev = tractee->prev;
			root.prev->next = tractee;
			tractee->prev = root.prev;
			root.prev = tractee;
			tractee->next = &root;
		    }
		}
	    }
	    else if (tractee->type == Crusher && !dy && dx==tractee->velx) {
		setimage(tractee, (tractee->velx *= -1) < 0 ? '>' : '<');
	    }
	    if (tractee->mass * 5 > obj->mass)
		return(1);
	}
    }
    return(0);
}

no_can_do()
{
    noraw();
    fprintf(stderr,"Sorry, your terminal is too dumb to play warp.\n");
    exit(1);
}

do_tc(s,l)
char *s;
int l;
{
    beg_qwrite();
    tputs(s,l,cmstore);
    end_qwrite();
}

int
comp_tc(dest,s,l)
char *dest;
char *s;
int l;
{
    maxcmstring = dest;
    tputs(s,l,cmstore);
    return(maxcmstring-dest);
}

helper()
{
    clear();
    mvaddstr(0,0,"    h or 4          left                                                      ");
    mvaddstr(1,0,"    j or 2          down                Use with SHIFT to fire torpedoes.     ");
    mvaddstr(2,0,"    k or 8          up                  Use with CTRL or FUNCT to fire        ");
    mvaddstr(3,0,"    l or 6          right                   phasers or turbolasers.           ");
    mvaddstr(4,0,"    b or 1          down and left       Use preceded by 'a' or 'r' for        ");
    mvaddstr(5,0,"    n or 3          down and right          attractors or repulsors.          ");
    mvaddstr(6,0,"    y or 7          up and left         Use normally for E or B motion.       ");
    mvaddstr(7,0,"    u or 9          up and right                                              ");
    mvaddstr(8,0,"                                                                              ");
    mvaddstr(9,0,"    del or %        fire photon torpedoes in every (reasonable) direction.    ");
    mvaddstr(10,0,"    s               stop all torpedoes.                                       ");
    mvaddstr(11,0,"    S or 0          stop the Enterprise when in warp mode.                    ");
    mvaddstr(12,0,"    d               destruct all torpedoes (quite useful).                    ");
    mvaddstr(13,0,"    D               destruct the current vessel (commit suicide).             ");
    mvaddstr(14,0,"    i               put Enterprise into impulse mode.                         ");
    mvaddstr(15,0,"    w               put Enterprise into warp mode.                            ");
    mvaddstr(16,0,"    -               reverse the direction of Enterprise.                      ");
    mvaddstr(17,0,"    o               switch from Enterprise to Base, or vice versa.            ");
    mvaddstr(18,0,"                                                                              ");
    mvaddstr(19,0,"    ^R              refresh the screen.                                       ");
    mvaddstr(20,0,"    ^Z              suspend the game.                                         ");
    mvaddstr(21,0,"    ^C or break     exit this round.                                          ");
    mvaddstr(22,0,"                                                                              ");
    mvaddstr(23,0,"                       [Hit space to continue]                                ");
    do {
	read(0, spbuf, 1);
	*spbuf &= 0177;
    } while (*spbuf != ' ');
    rewrite();

}

rewrite()
{
    register int x, y;

    clear();
    for (y=0; y<YSIZE; y++) {
	for (x=0; x<XSIZE; x++) {
	    if (occupant[y][x]) {
		mvaddc(y+1,x*2,occupant[y][x]->image);
	    }
	}
    }
    sprintf(spbuf,
    "%-4s%9d  E: %4d %2d B: %5d %3d Stars: %-3d Enemies: %-3d Stardate%5d.%1d",
	"   ", 0, 0, 0, 0, 0, 0, 0, timer/10, timer%10);
    mvaddstr(0,0,spbuf);
    oldeenergy = oldbenergy = oldcurscore =
    oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1;
					/* force everything to fill in */
    display_status();
}

#ifdef SIGTSTP
void cont_catcher()
{
    savetty();
    raw();
    noecho();
    nonl();
}

mytstp()
{
    resetty();
    kill(0,SIGTSTP);
    rewrite();
}
#endif

move(y, x, chadd)
int y, x;
char *chadd;
{
    register int ydist, xdist;
    register int i;
    register char *s;

    ydist = y - real_y;
    xdist = x - real_x;
    i = ydist * (ydist < 0 ? -UPsize : DOsize) +
        xdist * (xdist < 0 ? -BCsize : NDsize);
    beg_qwrite();
    if (i <= CMsize) {
	if (ydist < 0)
	    for (; ydist; ydist++)
		for (i=UPsize,s=UP; i; i--)
		    qaddch(*s++);
	else
	    for (; ydist; ydist--)
		for (i=DOsize,s=DO; i; i--)
		    qaddch(*s++);
	if (xdist < 0)
	    for (; xdist; xdist++)
		for (i=BCsize,s=BC; i; i--)
		    qaddch(*s++);
	else
	    for (; xdist; xdist--)
		for (i=NDsize,s=ND; i; i--)
		    qaddch(*s++);
    }
    else {
	tputs(tgoto(CM,x,y),0,cmstore);
    }
    real_y = y;
    real_x = x;
    if (chadd) {
	qaddch(*chadd);
    }
    if (maxcmstring != cmbuffer)
	end_qwrite();
}

movc3(len,src,dest)
char *dest, *src;
int len;
#ifdef VAX
{
    asm("movc3 4(ap),*8(ap),*12(ap)");
}
#else
register char *dest, *src;
register int len;
{
    for (; len; len--) {
	*dest++ = *src++;
    }
}
#endif

/* print out a file, stopping at form feeds */

page(filename)
char *filename;
{
    FILE *tmpfp = fopen(filename,"r");

    if (tmpfp != NULL) {
	while (fgets(spbuf,sizeof(spbuf),tmpfp) != NULL) {
	    if (*spbuf == '\f') {
		printf("[Hit return to continue] ");
		gets(spbuf);
	    }
	    else
		printf("%s",spbuf);
	}
	fclose(tmpfp);
    }
}
!STUFFY!FUNK!

# A program to print out the scoreboard
# (does variable, command substitution at installation time)

echo Installing wsc
cat >wsc <<!STUFFY!FUNK!
#!/bin/$whichshell
$clr
echo "                             TOP WARPISTS"
echo ""
echo "   RANK WHO                       SCORE DIFF  CUMDIFF  WHEN"
$catn `pwd`/warp.top
echo -n "                     [hit return to continue]"
$gettmp

$clr
echo "                       TOP (LOW-SPEED) WARPISTS"
echo ""
echo "   RANK WHO                       SCORE DIFF  CUMDIFF  WHEN"
$catn `pwd`/warplow.top
echo -n "                    [hit return to continue]"
$gettmp

$clr
echo "          GAMES SAVED OR IN PROGRESS"
echo ""
echo "WHO           SCORE  DF   CDF  E  B  WV  FLAGS"
cat `pwd`/save.*
!STUFFY!FUNK!

# A sample warp news file.  Feel free to edit.

echo Installing warp.news
cat >warp.news <<\!STUFFY!FUNK!
			  ***  WARP NEWS  ***

Welcome to warp! Please send any gripes, comments, fantastic ideas, etc.
to lwall at sdcrdcf.uucp (Larry Wall).
!STUFFY!FUNK!

# A program to translate starmaps from one form to another

echo Installing sm.c
cat >sm.c <<\!STUFFY!FUNK!
#include <stdio.h>
#include <ctype.h>

main()
{
    char screen[23][90], buf[10];
    register int y, x;

    gets(screen[0]);
    if (isdigit(screen[0][0])) {
	int numstars = atoi(screen[0]);

	for (y=0; y<23; y++) {
	    for (x=0; x<79; x++)
		screen[y][x] = ' ';
	    screen[y][79] = '\0';
	}

	for ( ; numstars; numstars--) {
	    gets(buf);
	    x = atoi(buf);
	    gets(buf);
	    y = atoi(buf);
	    screen[y][x+x] = '*';
	}

	for (y=0; y<23; y++) {
	    printf("%s\n",screen[y]);
	}
    }
    else {
	register int numstars = 0;

	for (y=1; y<23; y++) {
	    gets(screen[y]);
	}

	for (y=0; y<23; y++) {
	    for (x=0; x<80; x += 2) {
		if (screen[y][x] == '*') {
		    numstars++;
		}
	    }
	}

	printf("%d\n",numstars);

	for (y=0; y<23; y++) {
	    for (x=0; x<80; x += 2) {
		if (screen[y][x] == '*') {
		    printf("%d\n",x/2);
		    printf("%d\n",y);
		}
	    }
	}
    }
    exit(0);
}
!STUFFY!FUNK!

# A scenario to encourage warp mode

echo Installing smp.8
cat >smp.8 <<\!STUFFY!FUNK!
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
!STUFFY!FUNK!

# Another scenario to encourage warp mode

echo Installing smp.9
cat >smp.9 <<\!STUFFY!FUNK!
  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
!STUFFY!FUNK!

# A shooting gallery scenario

echo Installing smp.10
cat >smp.10 <<\!STUFFY!FUNK!
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   * * * *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   * * * *   *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
*   * * * *   *
!STUFFY!FUNK!

# A superfortress scenario

echo Installing smp.11
cat >smp.11 <<\!STUFFY!FUNK!
        * * * *
    * * *     * * *
  * * *   * *   * * *
  * *   * * * *   * *
* *   * *     * *   * *
*   * *   * *   * *   *
*   * *   * *   * *   *
* *   * *     * *   * *
  * *   * * * *   * *
  * * *   * *   * * *
    * * *     * * *
        * * * *











!STUFFY!FUNK!

# awk script to simulate cat -n

echo Installing catn.awk
cat >catn.awk <<\!STUFFY!FUNK!
BEGIN {OFS = "\t"}
{print "    " NR,$0}
!STUFFY!FUNK!

echo -n "Would you like me to start the make? "
read ans
if test $ans = y
then
    echo "Make output will be found in file 'make.log'."
    make > make.log &
fi



More information about the Comp.sources.unix mailing list