[net.sources.games] Asteroids for the Sun.

richb@yarra.OZ (Rich Burridge) (12/04/86)

This is the game of asteroids for the Sun. Please read the README
just a little further on in this posting. Suggestions, improvements,
bugs (there's got to be at least a couple of these) and flames to me.

Regards Rich.

Rich Burridge            ISD:  +61 3 267-6222
Sun Australia            STD:  (03) 267-6222
14 Queens Rd,            ARPA: richb%yarra.oz@seismo.css.gov
Melbourne, VIC 3004.     UUCP: seismo!munnari!yarra.oz!richb
AUSTRALIA.               ACS:  richb@yarra.oz

---------CUT HERE----------CUT HERE-------------CUT HERE-------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	Makefile
#	asteroids.h
#	asteroids.help
#	asteroids.icon
#	ast_main.c
#	ast_stuff.c
#	ast_sun.c
# This archive created: Thu Dec  4 12:36:03 1986
# By:	Rich Burridge (Sun Computer Australia (Melbourne))
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'

                      ASTEROIDS.
                      ----------

This is the game of Asteroids for the Sun. The original version was
written in Pascal on an ICL Perq, by persons unknown, somewhere in
the North of England in 1982. This version is based on the conversion
of that program to C by Brian Rippon and Graham Underwood for the
ICL Perq PNX O/S in 1983.

This should work on a Sun 2, but I didn't have one, so perhaps
someone can let me know what changes if any were needed.

This has been put together for a release for Christmas. There are
still a couple of things which could be improved, but it is still
a very workable game. These are:

(1) You can be killed for no apparent reason.
(2) Needs a restart handler. This is currently handled poorly.
    **YOU MUST NOT ALTER THE ASTEROIDS WINDOW ONCE YOU'VE STARTED**

Hopefully these will be "fixed" in the next version.

Just type "asteroids", to start the game.

There are three command line switches:

-h         - Don't display the initial help message.
-xnnn      - Initial width of the asteroids window (default 768).
-ynnn      - Initial height of the asteroids window (default 900).

The smaller the window the higher the bonus scores.

Suggestions, flames, bugs, fixes and improvements to me.

Regards Rich.

SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
#  Makefile for the asteroids game.
#  Written by Rich Burridge - Sun Australia (Melbourne) - December 1986.
#
#  Version 2.0.
#
#  No responsibility is taken for any errors inherent either in the comments
#  or the code of this program, but if reported to me then an attempt will
#  be made to fix them.
#
BINARIES        = asteroids
BINDIR          = .
CFLAGS          = -O
LDFLAGS         =
OBJS            = ast_main.o ast_stuff.o ast_sun.o
SRCS            = ast_main.c ast_stuff.c ast_sun.c
LIBS            = -lsuntool -lsunwindow -lpixrect
HDRS            = asteroids.h
#
#  The following commands are declared:
#
all:            $(BINARIES)

backup:
		cp ast_main.c ast_main.c~
		cp ast_stuff.c ast_stuff.c~
		cp ast_sun.c ast_sun.c~

lint:
		lint $(SRCS) -lpixrect

clean:
		rm -f *.o core
#
#  General Makefile stuff.
#
asteroids:      $(OBJS)
		cc $(LDFLAGS) -o asteroids $(OBJS) $(LIBS)

ast_main.o:     ast_main.c $(HDRS)
ast_stuff.o:    ast_stuff.c $(HDRS)
ast_sun.o:      ast_sun.c $(HDRS)
SHAR_EOF
fi
if test -f 'asteroids.h'
then
	echo shar: "will not over-write existing file 'asteroids.h'"
else
cat << \SHAR_EOF > 'asteroids.h'
 
/*  asteroids.h
 *
 *  Definitions used by the asteroids game.
 *  Written by Rich Burridge - SUN Australia (Melbourne) - December 1986.
 *
 *  Version 2.0.
 *
 *  No responsibility is taken for any errors inherent either to the code
 *  or the comments of this program, but if reported to me then an attempt
 *  will be made to fix them.
 */

#include <pixrect/pixrect_hs.h>
#include <suntool/gfx_hs.h>
#include <setjmp.h>

#define  MAXEXLV  5     /* Maximum number of nested exceptions. */

typedef struct
          {   
            int cl ;
            jmp_buf jb[ MAXEXLV ] ;
          } exceptn ;

#define   exception(x)         exceptn x = { 0 } ;
#define exexception(x)  extern exceptn x  ;

/* x is of type exception */
#define when(x)   switch(setjmp(x.jb[x.cl++])) { \
                  default : (void) fprintf(stderr,"Unexpected exception raised") ; \
                            exit(1) ; \
                  case 0  : break ;

/* x is of type integer */
#define etype(x)  case x :

#define endwhen   }

#define forget(x)    x.cl--

/* x is of type exception and y is an integer */
#define raise(x,y)    longjmp(x.jb[x.cl - 1],y)

extern struct gfxsubwindow *gfx ;     /* Pointer to asteroids tool window. */
extern char *sprintf() ;

#define  BIND         (void) bind          /* To make lint happy. */
#define  CLOSE        (void) close
#define  CONNECT      (void) connect
#define  FCLOSE       (void) fclose
#define  FPRINTF      (void) fprintf
#define  KILL         (void) kill
#define  LISTEN       (void) listen
#define  NICE         (void) nice
#define  PRINTF       (void) printf
#define  READ         (void) read
#define  SCANF        (void) scanf
#define  SELECT       (void) select
#define  SIGNAL       (void) signal
#define  SPRINTF      (void) sprintf
#define  STRCPY       (void) strcpy
#define  UNLINK       (void) unlink
#define  WRITE        (void) write

#define  RRPL         PIX_SRC                  /* RASTEROP codes. */
#define  ROR          PIX_SRC | PIX_DST
#define  RXOR         PIX_SRC ^ PIX_DST
#define  RCLR         PIX_CLR
#define  RSET         PIX_SET
#define  RINV         PIX_NOT(PIX_DST)
#define  RXNOR        PIX_SRC ^ PIX_NOT(PIX_DST)
#define  RORNOT       PIX_NOT(PIX_SRC) | PIX_DST
#define  RANDNOT      PIX_NOT(PIX_SRC) & PIX_DST

#define  MAXLINE      80                   /* Maximum string length. */
#ifndef  CTRLQ
#define  CTRLQ        17                   /* Used to restart the asteroids game. */
#endif
#ifndef  CTRLS
#define  CTRLS        19                   /* Used to halt the asteroids game. */
#endif

#define  ESC          '\033'               /* Definitions of valid asteroid keys. */
#define  DEL          '\177'
#define  BACKSPACE    '\010'

#define  FLASHTIME    4                    /* Seconds */
#define  FLICKERTIME  20                   /* Jiffies */
#define  FONT_HEIGHT  16                   /* Height of font within asteroids. */
#define  FONT_WIDTH   8                    /* Width of standard character font. */
#define  FULLTANK     50000                /* Full fuel tanks */
#define  HELPNAME     "asteroids.help"     /* Name of the initial help file. */
#define  RETURN       13                   /* Certain useful ASCII constants. */
#define  SOCKNAME     "/tmp/astsocket"     /* Asteroids socket name. */

#define  OFFCURSOR    0                    /* Modes for the mouse cursor. */
#define  TRACKCURSOR  1

/* Asteroid event values. */
#define  LEFTUP       1                    /* Left mouse button up. */
#define  LEFTDOWN     2                    /* Left mouse button down. */
#define  BUTMIDDLE    3                    /* Middle mouse button. */
#define  RIGHTUP      4                    /* Right mouse button up. */
#define  RIGHTDOWN    5                    /* Right mouse button down. */
#define  WIN_DAMAGED  6                    /* Value returned on window damage. */

#define  SWIDTH     768                    /* Maximum screen width. */
#define  SHEIGHT    900                    /* Maximum screen height. */

#define  MASTER     0                      /* Server version of SID tool. */
#define  SLAVE      1                      /* Client version of SID tool. */

/* Set the function to be used for characters. */
#define  SCHRFUNC(f)  (sfunc = f)

/* Machine independent rasterop calls. */

/* Manipulate a portion of the screen with itself. */
#define  BLT_SCRN(sx,sy,w,h,op) \
         (pw_writebackground(gfx->gfx_pixwin,sx,sy,w,h,op))

/* Move a screen raster to an offscreen area. */
#define  BLT_SCRN_TO_MEM(mem,mx,my,w,h,op,sx,sy) \
         (pw_read(mem,mx,my,w,h,op,gfx->gfx_pixwin,sx,sy))

/* Move an offscreen raster area to the screen. */
#define  BLT_MEM_TO_SCRN(sx,sy,w,h,op,mem,mx,my) \
         (pw_write(gfx->gfx_pixwin,sx,sy,w,h,op,mem,mx,my))

/* Move an offscreen raster area to another offscreen raster area. */
#define  BLT_MEM(mem1,mx1,my1,w,h,op,mem2,mx2,my2) \
         (pr_rop(mem1,mx1,my1,w,h,op,mem2,mx2,my2))

/* Draw a line of type op,in a raster area. */
#define  LINE(area,x1,y1,x2,y2,op) \
         (pr_vector(area,x1,y1,x2,y2,op,1))
SHAR_EOF
fi
if test -f 'asteroids.help'
then
	echo shar: "will not over-write existing file 'asteroids.help'"
else
cat << \SHAR_EOF > 'asteroids.help'
            WELCOME TO THE GAME OF ASTEROIDS.

The object of the game, is to destroy the asteroids before
they destroy you.

You control the spaceship which initially starts in the
centre of the window.

Holding down the LEFT button of the mouse rotates the
spaceship anticlockwise.
Holding down the RIGHT button of the mouse rotates the
spaceship clockwise.
Pressing the MIDDLE button will fire a missile out of the
front of the spaceship.

You can enter hyperspace by pressing the BACKSPACE key. This
will return you to the screen in a random position.

You can turn your rocket motors on by pressing the ESC key.
Pressing the DELETE key will turn your rocket motors off.

To quit the game at any time, just press the q key.

Rotating the shapeship, moving or entering hyperspace uses up fuel.
Running out of fuel will eventually render you helpless.

Fuel tanks are refilled every 6000 points scored per spaceship,
and for each new spaceship.

You get a new spaceship every 10000 points. There are bonus
points for each set of asteroids you destroy. Also the smaller
your window, the more bonus you get.

You have three spaceships to start with. Good luck!!

Hit RETURN to start the game.
SHAR_EOF
fi
if test -f 'asteroids.icon'
then
	echo shar: "will not over-write existing file 'asteroids.icon'"
else
cat << \SHAR_EOF > 'asteroids.icon'
/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
 */
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x8000,0x0000,0x0000,0x0001,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFF7F,0xFEFF,0xFFFD,
	0xBFFF,0xFE3F,0xFC7F,0xFF3D,0xBFFF,0xFF7F,0xFEFF,0xFF3D,
	0xB3FF,0xFFBF,0xFDFF,0xFFFD,0xB3FF,0xFFDF,0xFBFF,0xFFFD,
	0xBFFF,0xFFDF,0xFBFF,0xFF3D,0xBFFF,0xFFEF,0xF7FF,0xFF3D,
	0xBFFF,0xFFEF,0xF7FF,0xFFFD,0xBFFF,0xFFF7,0xEFFF,0xFFFD,
	0xBFFF,0xFFC0,0x03FF,0xFFFD,0xBFFF,0xFF80,0x01FF,0xFFFD,
	0xBFFF,0xFF8F,0xF1FF,0xFFFD,0xBFFF,0xFF1F,0xF8FF,0xFFFD,
	0xBFFF,0xFF1F,0xF8FF,0xFFFD,0xBFFF,0xFE3F,0xFC7F,0xFFCD,
	0xBFFF,0xFE3F,0xFC7F,0xFFCD,0xBFFF,0x0000,0x0000,0xFFFD,
	0xB3FF,0x0000,0x0000,0xFFFD,0xB3FF,0x0000,0x0000,0xFFFD,
	0xBFFF,0xC7FF,0xFFE3,0xFFFD,0xBFFF,0xE3FF,0xFFC7,0xFFFD,
	0xBFFF,0xE3FF,0xFFC7,0xFFFD,0xBFFF,0xF1FF,0xFF8F,0xFFFD,
	0xBFFF,0xF1FF,0xFF8F,0xFFFD,0xBFFF,0xF8FF,0xFF1F,0xFFFD,
	0xBFFF,0xF8FF,0xFF1F,0xFFFD,0xBFFF,0xFC7F,0xFE3F,0xFFFD,
	0xBFFF,0xFC7F,0xFE3F,0xFFFD,0xBFFF,0xFE3F,0xFC7F,0xFFFD,
	0xBFFF,0xFE3F,0xFC7F,0xFFFD,0xBFFF,0xFF1F,0xF8FF,0xFFFD,
	0xBFFF,0xFF00,0x00FF,0xFFFD,0xBFFF,0xFF00,0x00FF,0xFFFD,
	0xBFFF,0xFF80,0x01FF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xF9FD,
	0xBFCF,0xFFFF,0xFFFF,0xF9FD,0xBFCF,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFF3F,0xFFFD,
	0xBFF9,0xFFFF,0xFF3F,0xFFFD,0xBFF9,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xF9FD,0xBFFF,0xFFFF,0xFFFF,0xF9FD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
	0xBFFF,0xFFFF,0xF9FF,0xFFFD,0xBFFF,0xFFFF,0xF9FF,0xFFFD,
	0xBFFF,0xFFFF,0xFFFF,0xFFFD,0xBFFF,0xFFFF,0xFFFF,0xFFFD,
	0x8000,0x0000,0x0000,0x0001,0xFFFF,0xFFFF,0xFFFF,0xFFFF
SHAR_EOF
fi
if test -f 'ast_main.c'
then
	echo shar: "will not over-write existing file 'ast_main.c'"
else
cat << \SHAR_EOF > 'ast_main.c'

/*  ast_main.c
 *
 *  The game of Asteroids.
 *  Written by Rich Burridge - SUN Australia (Melbourne) - December 1986.
 *
 *  Version 2.0.
 *
 *  No responsibility is taken for any errors or inaccuracies inherent
 *  either to the comments or the code of this program, but if reported
 *  to me then an attempt will be made to fix them.
 */

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <signal.h>
#include "asteroids.h"

extern etext() ;

exception(god) ;            /* Raised to create the slave asteroids process. */

#define  BYTESPERWORD  2
#define  bheight       15
#define  bsize         2*bheight+1

/*
 *   Macros to test and set bits.
 *   i,j are the x,y offsets from pointer.
 *   scan is the scan length of the area pointed at.
 */

#define SETON(i,j,scan,ptr)  (*(ptr+(scan*(j))+(i)/16) |= (1 << (017 - ((i) & 017))))
#define SETOFF(i,j,scan,ptr) (*(ptr+(scan*(j))+(i)/16) &= ~(1 << (017 - ((i) & 017))))
#define BITSET(i,j,scan,ptr) (((*(ptr+(scan*(j))+(i)/16)) &(1 << (017 - ((i) & 017)))) ? (1):(0))

#define  BIDLE     0
#define  BWAITING  1
#define  BACTIVE   2
#define  BDYING    3

#define  MAXHS     5      /* Max records held in high score file. */
#define  AFACTOR   120
#define  BFACTOR   256
#define  REFUEL    6000   /* fill up tanks every REFUEL points scored per ship */

#define  MAXDIFF   15000

short testarea[(bsize+1)*4*BYTESPERWORD] ;
mpr_static(test_pr,512,4,1,testarea) ;

short wrkarea[50*48*BYTESPERWORD] ;
mpr_static(wrk_pr,768,50,1,wrkarea) ;

struct timeb tlast,tnew,tstartflash,tlastflash ;

struct ainfo
         {
           struct ainfo *next ;
           int x,y,dx,dy,xp,yp,sx,sy,wx,wy ;
           int sizex,sizey,offx,offy,typ ;
         } ;

struct hscore
         {
           char who[MAXLINE] ;
           int score ;
         } ;

struct hscore highscore[MAXHS] ;

char progname[MAXLINE] ;          /* Name of this program. */
char titlestring[MAXLINE] ;
int c ;                           /* Value returned by wgread. */
int firsttime = 0 ;               /* Used for redrawing a damaged screen. */
int height ;                      /* Height of the asteroids window. */
int givehelp ;                    /* Set to 0, indicates no initial help. */
int prog_type ;                   /* Whether program is server or client. */
int orgx = 0 ;                    /* X origin of the asteroids window. */
int orgy = 0 ;                    /* Y origin of the asteroids window. */
int state = 0 ;                   /* Current button state. */
int width ;                       /* Width of the asteroids window. */

int xmax,xmin,ymax,ymin,mindimension ;
int score = 0 ;
int scorethistank = 0 ;

int enkey = 01652 ;      /* ENCODE key used in highscore file. */
int addbonus = 0 ;
int bonus ;              /* what bonus do we give for each set of asteroids */
int bonusship = 10000 ;  /* new ship every bonusship points. */

int flashbonus = 0 ;     /* flag for when to flash message. */
int bonusshown = 0 ;
int motoron ;
int fuel = FULLTANK ;    /* Amount of spaceship fuel left. */
int fuelxoffset ;        /* Start of fuel display bar. */
int fuelmaxlength ;      /* Maximum length of fuel bar. */
int fuellength ;         /* Current length of fuel bar. */

char bonusstr[80] ;

struct ainfo *freeap,*bplist,*waitlist,*aplist ;
int basestatus ;

int ax,ay,bx,by,bdx,bdy,bxp,byp,bxpd,bypd ;
int nummove,swcount,ssector,scount ;
int basecount,t3count,t1count,waitcount,rr,dummy ;
int keys = 0 ;

extern int sfunc ;           /* Rasterop code used by writeln. */
char *malloc() ;
extern int closedown(),rint() ;


checkscore()

{
  char buffer[MAXLINE] ;
  char me[MAXLINE] ;
  int i,j,len ;

  SCHRFUNC(RRPL) ;
  i = MAXHS - 1 ; 
  while ((score > highscore[i].score) && (i >= 0)) i-- ;

  if (++i < MAXHS)
    {
      clear_screen() ;
      SPRINTF(buffer,"Congratulations, you have one of the top %d scores\n",MAXHS) ;
      writeln(100,140,buffer) ;
      do
        {
          len = 1 ;
          writeln(100,200,"Please enter your name : ") ;
          if (!(len = getline(me,365,200)))
            writeln(100,220,"   ** No name given. **") ;
        }
      while (!len) ;

      j = MAXHS - 1 ;
      while (--j >= i)
        {
          highscore[j+1].score = highscore[j].score ;
          STRCPY(highscore[j+1].who,highscore[j].who) ;
        }
      highscore[i].score = score ;
      STRCPY(highscore[i].who,me) ;
      puthighscore() ;
    }
}


showhighscore()

{
  char buffer[MAXLINE] ;
  int i ;

  clear_screen() ;
  write_bold(220,200,"High Scores") ;
  SCHRFUNC(ROR) ;
  writeln(220,201,"___________") ;
  writeln(200,300," Score       Name") ;
  writeln(200,301," _____       ____") ;
  SCHRFUNC(RRPL) ;
  for (i = 0; i < MAXHS; i++)
    {
      SPRINTF(buffer,"%6d      %s",highscore[i].score,highscore[i].who) ;
      writeln(200,330+i*30,buffer) ;
    }
  SPRINTF(buffer,"Your score was %d",score) ;
  writeln(220,500,buffer) ;
  writeln(5,height-40,"Type RETURN to quit") ;
  while (wgread() != RETURN) ;
}


gethighscore()

{
  int hsfile,i ;
  struct hscore nullscore ;

  if ((hsfile = open("asteroids.hs",2)) == -1)
    {
      if ((hsfile = creat("asteroids.hs",0777)) == -1)
        {
          PRINTF("\nunable to create highscore file.\n") ;
          exit(1) ;
        }

      nullscore.score = 0 ;       /* file should be open. */
      STRCPY(nullscore.who," ") ;
      for (i = 0; i < MAXHS; i++)
        {
          puths(hsfile,&nullscore) ;
          STRCPY(highscore[i].who," ") ;
          highscore[i].score = 0 ;
        }
    }
  else
    for (i = 0; i < MAXHS; i++) geths(hsfile,&highscore[i]) ;
  CLOSE(hsfile) ;
}


puthighscore()

{
  int hsfile,i ;

  if ((hsfile = open("asteroids.hs",1)) == -1)
    PRINTF("Unable to open highscore file.\n") ;
  else
    {
      for (i = 0; i < MAXHS; i++) puths(hsfile,&highscore[i]) ;
      CLOSE(hsfile) ;
    }
}


puths(where,record)    /* put one hscore record out. */
struct hscore *record ;
int where ;

{
  char buffer[32],valuestr[7] ;
  int i,value ;

  for (i = 0; i < 16; i++) buffer[i] = record->who[i] ^ enkey ;
  value = record->score ;
  SPRINTF(valuestr,"%d",value) ;
  for (i = 0; i < 7; i++) buffer[i+16] = valuestr[i] ^ enkey ;
  WRITE(where,buffer,23) ;
}


geths(where,record)    /* get one hscore record in. */
struct hscore *record ;
int where ;

{
  char buffer[32],valuestr[7] ;
  int i ;

  i = read(where,buffer,23) ;
  for (i = 0; i < 16; i++) record->who[i] = buffer[i] ^ enkey ;
  for (i = 0; i < 7; i++) valuestr[i] = buffer[i+16] ^ enkey ;
  record->score = atoi(valuestr) ;
}


init()

{
  int i,j ;

  NICE(-20) ;                  /* High priority activity this game !!! */
  SIGNAL(SIGQUIT,closedown) ;
  SIGNAL(SIGHUP,closedown) ;
  SIGNAL(SIGINT,closedown) ;

  gethighscore() ;
  BLT_MEM(&wrk_pr,0,0,768,50,RXOR,&wrk_pr,0,0) ;    /* Clear work area. */
  rr = 1234 ;

  LINE(&wrk_pr,128,25,128,40,RSET) ;                /* BIG asteroid. */
  LINE(&wrk_pr,128,40,147,49,RSET) ;
  LINE(&wrk_pr,147,49,160,49,RSET) ;
  LINE(&wrk_pr,160,49,173,47,RSET) ;
  LINE(&wrk_pr,173,47,177,35,RSET) ;
  LINE(&wrk_pr,177,35,177,19,RSET) ;
  LINE(&wrk_pr,177,19,174,8,RSET) ;
  LINE(&wrk_pr,174,8,168,3,RSET) ;
  LINE(&wrk_pr,168,3,150,0,RSET) ;
  LINE(&wrk_pr,150,0,144,2,RSET) ;
  LINE(&wrk_pr,144,2,135,15,RSET) ;
  LINE(&wrk_pr,135,15,128,25,RSET) ;

  for (i = 1; i <= 48; i++)
    {
      j = 128 ;
      while (BITSET(j,i,48,wrkarea) == 0) j++ ;
      do
        j++ ;
      while (BITSET(j,i,48,wrkarea) != 0) ;
      while (BITSET(j,i,48,wrkarea) == 0)
        {
          if (rint(j-128) < 6) SETON(j,i,48,wrkarea) ;
                            else SETOFF(j,i,48,wrkarea) ;
          j++ ;
        }
    }

  LINE(&wrk_pr,192,10,192,20,RSET) ;    /* MEDIUM asteroid. */
  LINE(&wrk_pr,192,20,201,29,RSET) ;
  LINE(&wrk_pr,201,29,214,29,RSET) ;
  LINE(&wrk_pr,214,29,221,17,RSET) ;
  LINE(&wrk_pr,221,17,221,08,RSET) ;
  LINE(&wrk_pr,221,08,209, 0,RSET) ;
  LINE(&wrk_pr,209, 0,200, 0,RSET) ;
  LINE(&wrk_pr,200, 0,192,10,RSET) ;

  for (i = 1; i <= 28; i++)
    {
      j = 192 ;
      while (BITSET(j,i,48,wrkarea) == 0) j++ ;
      do
        j++ ;
      while (BITSET(j,i,48,wrkarea) != 0) ;
      while (BITSET(j,i,48,wrkarea) == 0)
        {
          if (rint(j-192) < 5) SETON(j,i,48,wrkarea) ;
                            else SETOFF(j,i,48,wrkarea) ;
          j++ ;
        }
    }

  LINE(&wrk_pr,261, 0,270, 0,RSET) ;  /* SMALL asteroid. */
  LINE(&wrk_pr,270, 0,270, 9,RSET) ;
  LINE(&wrk_pr,270, 9,263,14,RSET) ;
  LINE(&wrk_pr,263,14,256,14,RSET) ;
  LINE(&wrk_pr,256,14,256, 8,RSET) ;
  LINE(&wrk_pr,256, 8,261, 0,RSET) ;
  for (i = 1; i <= 13; i++)
    {
      j = 256 ;
      while (BITSET(j,i,48,wrkarea) == 0) j++ ;
      do
        j++ ;
      while (BITSET(j,i,48,wrkarea) != 0) ;
      while (BITSET(j,i,48,wrkarea) == 0)
        {
          if (rint(j-256) < 4) SETON(j,i,48,wrkarea) ;
          else SETOFF(j,i,48,wrkarea) ;
          j++ ;
        }
    }

  for (i = 0; i <= 3; i++)      /* spaceship */
    BLT_MEM(&wrk_pr,320+20-i/2,i+10,i+10,1,RXNOR,&wrk_pr,320+20-i/2,i+10) ;
  for (i = 4; i <= 15; i++)
    {
      BLT_MEM(&wrk_pr,320+20-i/2,i+10,4,1,RXNOR,&wrk_pr,320+20-i/2,i+10) ;
      BLT_MEM(&wrk_pr,320+26+(i+1)/2,i+10,4,1,RXNOR,&wrk_pr,320+26+(i+1)/2,i+10) ;
    }
  BLT_MEM(&wrk_pr,320,26,50,4,RXNOR,&wrk_pr,320,26) ;
  for (i = 0; i <= 3; i++)
    BLT_MEM(&wrk_pr,320+15-i/2,49-i,i+20,1,RXNOR,&wrk_pr,320+15-i/2,49-i) ;
  for (i = 4; i <= 19; i++)
    {
      BLT_MEM(&wrk_pr,320+15-i/2,49-i,4,1,RXNOR,&wrk_pr,320+15-i/2,49-i) ;
      BLT_MEM(&wrk_pr,320+31+(i+1)/2,49-i,4,1,RXNOR,&wrk_pr,320+31+(i+1)/2,49-i) ;
    }
  BLT_MEM(&wrk_pr,320+18,0,3,3,RXNOR,&wrk_pr,320+18,0) ;
  BLT_MEM(&wrk_pr,320+30,0,3,3,RXNOR,&wrk_pr,320+30,0) ;
  LINE(&wrk_pr,320+19,2,320+24,9,RSET) ;
  LINE(&wrk_pr,320+31,2,320+26,9,RSET) ;

  BLT_MEM(&wrk_pr,256,16,3,3,RXNOR,&wrk_pr,256,16) ;    /* Missiles. */

  aplist = NULL ;
  bplist = NULL ;
  freeap = NULL ;
  waitlist = NULL ;
  waitcount = rint(100) ;

  xmax = width - 4 ;
  xmin = 4 ;
  ymax = height - 4 - FONT_HEIGHT ;
  ymin = 4 + FONT_HEIGHT ;
  mindimension = (height < width) ? height : width ;
 
/* Calculate bonus payments, smaller window = LARGER bonus. */
  bonus = 80 - ((mindimension / 100) * 10) ;
 
  BLT_SCRN(0,0,width,height,RXOR) ;
 
/* Screen black except the border. */
  BLT_SCRN(xmin,ymin,xmax-xmin+1,ymax-ymin+1,RXNOR) ;
  SCHRFUNC(RRPL) ;
  writeln(xmin+2,height-5,"Fuel : ") ;

  fuelxoffset = xmin+58 ;
  fuelmaxlength = (xmax-xmin) - fuelxoffset ;
  fuellength = fuelmaxlength ;
 
  BLT_SCRN(fuelxoffset,height-FONT_HEIGHT,fuellength,FONT_HEIGHT-2,RXNOR) ;
  addscore(0) ;
}


cleara(a)
struct ainfo *a ;

{
  if (a->sizex > 0 && a->sizey > 0)
    BLT_MEM_TO_SCRN(a->x+a->offx,a->y+a->offy,a->sizex,a->sizey,RXOR,
                    &wrk_pr,a->wx+a->offx,a->wy+a->offy) ;
}


updatea(a)
struct ainfo *a ;

{
  int res,dx,dy ;
  int sizex,sizey,offx,offy ;

  res = 1 ;
  a->dx += a->xp*nummove ;
  dx = a->dx / AFACTOR ;
  a->dy += a->yp*nummove ;
  dy = a->dy / AFACTOR ;
  if (dx || dy)
    {
      sizex = a->sx ;
      sizey = a->sy ;
      offx = 0 ;
      offy = 0 ;
      a->x += dx ;
      a->y += dy ;
      if (a->x < xmin)
        {
          offx = xmin - a->x ;
          sizex -= offx ;
        }
      else if (a->x > xmax - a->sx) sizex = xmax - a->x + 1 ;
      if (a->y < ymin)
        {
          offy = ymin - a->y ;
          sizey -= offy ;
        }
      else if (a->y > ymax - a->sy) sizey = ymax - a->y + 1 ;
      if (sizex > 0 && sizey > 0)
        BLT_MEM_TO_SCRN(a->x+offx,a->y+offy,sizex,sizey,RXOR,
                        &wrk_pr,a->wx+offx,a->wy+offy) ;
      else res = 0 ;
      if (a->sizex > 0 && a->sizey > 0)
        BLT_MEM_TO_SCRN(a->x-dx+a->offx,a->y-dy+a->offy,a->sizex,a->sizey,RXOR,
                        &wrk_pr,a->wx+a->offx,a->wy+a->offy) ;
      a->sizex = sizex ;
      a->sizey = sizey ;
      a->offx = offx ;
      a->offy = offy ;
      a->dx -= AFACTOR * dx ;
      a->dy -= AFACTOR * dy ;
    }
  return(res) ;
}


starta(plist,typ,x,y,xp,yp)
struct ainfo **plist ;
int typ,x,y,xp,yp ;

{
  struct ainfo *newap ;

  if (freeap == NULL)
    newap = (struct ainfo *) malloc(sizeof(struct ainfo)) ;
  else
    {
      newap = freeap ;
      freeap = freeap->next ;
    }
  newap->next = *plist ;
  *plist = newap ;
  newap->typ = typ ;
  newap->x = x ;
  newap->dx = 0 ;
  newap->xp = xp ;
  newap->y = y ;
  newap->dy = 0 ;
  newap->yp = yp ;
  switch (typ)
    {
      case 0 : newap->sx = 3 ;
               newap->sy = 3 ;
               newap->wx = 256 ;
               newap->wy = 16 ;
               break ;

      case 1 : newap->sx = 50 ;
               newap->sy = 50 ;
               newap->wx = 128 ;
               newap->wy = 0 ;
               break ;

      case 2 : newap->sx = 30 ;
               newap->sy = 30 ;
               newap->wx = 192 ;
               newap->wy = 0 ;
               break ;

      case 3 : newap->sx = 15 ;
               newap->sy = 15 ;
               newap->wx = 256 ;
               newap->wy = 0 ;
               break ;

      case 5 : newap->sx = 50 ;
               newap->sy = 50 ;
               newap->wx = 320 ;
               newap->wy = 0 ;
               break ;
    }

  if (x == xmin) newap->x = xmin - newap->sx + 1 ;
  if (y == ymin) newap->y = ymin - newap->sy + 1 ;
  newap->sizex = 0 ;     /* initialise value while off screen. */
  if (*plist != waitlist)
    if (updatea(newap)) /* do nothing */ ;
}


updatelist(plist)
struct ainfo **plist ;

{
  struct ainfo *owner,*this,*del ;
  int nx,ny,s ;

  owner = NULL ;
  this = *plist ;
  while (this != NULL)
    {
      if (updatea(this))
        {
          if (this->typ >= 5)
            {
              if (scount > 0) scount -= nummove ;
              else
                {
                  scount = 100 / this->typ ;
                  scount += rint(scount) ;
                  ny = rint(71) ;
                  if (ny > 40) nx = 140 - ny ;
                  else nx = 100 ;
                  switch (ssector)
                    {
                      case 1 : s = nx ;
                               nx = ny ;
                               ny = s ;
                               break ;

                      case 2 : s = nx ;
                               nx = (-ny) ;
                               ny = s ;
                               break ;

                      case 3 : nx = (-nx) ;
                               break ;

                      case 4 : nx = (-nx) ;
                               ny = (-ny) ;
                               break ;

                      case 5 : s = (-nx) ;
                               nx = (-ny) ;
                               ny = s ;
                               break ;

                      case 6 : s = (-nx) ;
                               nx = ny ;
                               ny = s ;
                               break ;

                      case 7 : ny = (-ny) ;
                               break ;
                    }
                  ssector = (ssector + 1) % 8 ;
                  starta(plist,0,this->x+20,this->y+20,3*nx,3*ny) ;
                  if (owner == NULL) owner = *plist ;
                }
              this->typ += 1 ;
            }
          owner = this ;
          this = this->next ;
        }
      else if ((this->typ == 1 || this->typ == 2 || this->typ == 3)
                                 && basestatus == BACTIVE)
        {
          if (this->xp > 0)
            {
              if (this->x >= xmax) this->x = xmin - this->sx + 1 ;
            }
          else if (this->x <= xmin - this->sx + 1) this->x = xmax ;
          if (this->yp > 0)
            {
              if (this->y >= ymax) this->y = ymin - this->sy + 1 ;
            }
          else if (this->y <= ymin - this->sy + 1) this->y = ymax ;
          cleara(this) ;
        }
      else
        {
          del = this ;
          this = this->next ;
          if (owner == NULL) *plist = this ;
          else owner->next = this ;
          if ((del->typ == 1 || del->typ == 2 || del->typ == 3)
                               && basestatus != BIDLE)
            {
              del->next = waitlist ;
              waitlist = del ;
            }
          else
            {
              del->next = freeap ;
              freeap = del ;
            }
        }
    }
}


nextangle(cw,x,y,newx,newy)
int cw,x,y,*newx,*newy ;

{
  int inc ;

  if (cw) inc = 1 ;
  else inc = -1 ;
  *newx = x ;
  *newy = y ;
  if (x + ((y > 0) == cw) > 40) *newy = y - inc ;
  if (x - ((y < 0) == cw) < -40) *newy = y + inc ;
  if (y + ((x < 0) == cw) > 40) *newx = x + inc ;
  if (y - ((x > 0) == cw) < -40) *newx = x - inc ;
}


restore_screen()        /* Restore screen after window damage. */

{

/*
 *  Due to the inherent design of the game, it would appear not to
 *  be easily possible to restore a damaged screen. This is where it
 *  would be done if a neat way was found.
 *
 *  If you do find a way, please send your answer to the author for
 *  netwide distribution. Yes, this is a challenge!!
 */

  c = 0 ;
  if (++firsttime == 1) return ;
  exit(1) ;
}


diff()

{
  c = wgread() ;
  if (fuel <= 0) return(0) ;
  if (c == CTRLS)
    {
      do
        {
          c = wgread() ;
          if (c == WIN_DAMAGED) restore_screen() ;
        }
      while (c != CTRLQ) ;
      c = 0 ;
    }
  if (c == WIN_DAMAGED) restore_screen() ;
  if (c > WIN_DAMAGED) keys = 1 ;
  if (c == LEFTDOWN || c == RIGHTDOWN || c == LEFTUP || c == RIGHTUP) state = c ;
  if (state == LEFTDOWN)
    {
      fuel -= 1 ;
      return(MAXDIFF) ;
    }
  else if (state == RIGHTDOWN)
    {
      fuel -= 1 ;
      return(-MAXDIFF) ;
    }
  else return(0) ;
}


drawbase(x,y)
int x,y ;

{
  int t1,t2,i,dbmin,dbmax,ax,ay,bx,by,cx,cy,dx,dy ;

  BLT_MEM(&wrk_pr,0,0,64,bsize,RXOR,&wrk_pr,0,0) ;   /* clear work area. */
  ax = (14 * x + 50) / 100 + bheight ;
  ay = (14 * y + 50) / 100 + bheight ;
  cx = (-(5 * x + 50)) / 100 + bheight ;
  cy = (-(5 * y + 50)) / 100 + bheight ;
  t1 = (-10 * x) ;
  t2 = 6 * y ;
  bx = (t1 - t2 + 50) / 100 + bheight ;
  dx = (t1 + t2 + 50) / 100 + bheight ;
  t1 = (-10 * y) ;
  t2 = 6 * x ;
  by = (t1 + t2 + 50) / 100 + bheight ;
  dy = (t1 - t2 + 50) / 100 + bheight ;

  LINE(&wrk_pr,ax,ay,bx,by,RSET) ;
  LINE(&wrk_pr,bx,by,cx,cy,RSET) ;
  LINE(&wrk_pr,cx,cy,dx,dy,RSET) ;
  LINE(&wrk_pr,dx,dy,ax,ay,RSET) ;
  if (abs(x) > abs(y))
    {
      if (ay > by)
        {
          dbmax = ay ;
          dbmin = by ;
        }
      else
        {
          dbmax = by ;
          dbmin = ay ;
        } ;
      if (dy > dbmax) dbmax = dy ;
      if (dy < dbmin) dbmin = dy ;
      for (i = dbmin+1; i <= (dbmax-1); i++)
        {
          t1 = 0 ;
          while (BITSET(t1,i,48,wrkarea) == 0) t1++ ;
          t2 = bsize - 1 ;
          while (BITSET(t2,i,48,wrkarea) == 0) t2-- ;
          BLT_MEM(&wrk_pr,t1,i,t2-t1,1,RXNOR,&wrk_pr,t1,i) ;
        }
    }
  else
    {
      if (ax > bx)
        {
          dbmax = ax ;
          dbmin = bx ;
        }
      else
        {
          dbmax = bx ;
          dbmin = ax ;
        } ;
      if (dx > dbmax) dbmax = dx ;
      if (dx < dbmin) dbmin = dx ;
      for (i = dbmin+1; i <= (dbmax-1); i++)
        {
          t1 = 0 ;
          while (BITSET(i,t1,48,wrkarea) == 0) t1++ ;
          t2 = bsize - 1 ;
          while (BITSET(i,t2,48,wrkarea) == 0) t2-- ;
          BLT_MEM(&wrk_pr,i,t1,1,t2-t1,RXNOR,&wrk_pr,i,t1) ;
        }
    }
}


renewbase(dx,dy)
int dx,dy ;

{
  BLT_MEM_TO_SCRN(bx+dx-bheight,by+dy-bheight,bsize,bsize,RXOR,&wrk_pr,0,0) ;
  BLT_MEM_TO_SCRN(bx-bheight,by-bheight,bsize,bsize,RXOR,&wrk_pr,64,0) ;
  bx = bx + dx ;
  by = by + dy ;
  BLT_MEM(&wrk_pr,64,0,64,bsize,RRPL,&wrk_pr,0,0) ;
}


startlist()

{
  int i,ss,nx ;
  struct ainfo *ap ;

  t1count = 0 ;
  t3count = 0 ;

  if (waitlist != NULL)
    {
      ap = waitlist ;
      while (ap->next != NULL) ap = ap->next ;
      ap->next = freeap ;
      freeap = waitlist ;
      waitlist = NULL ;
    }

  for (i = 1; i <= 6; i++)
    {
      ss = (xmax - xmin) / 2 - 50 ;
      ss = xmin + rint(ss-150) + rint(ss+150) + 50 ;
      nx = rint(23) + rint(59) - 40 ;
      switch (rint(12) / 3)
        {
          case 0 : starta(&waitlist,1,xmin,ss,100,nx) ;
                   break ;

          case 1 : starta(&waitlist,1,xmax,ss,-100,nx) ;
                   break ;

          case 2 : starta(&waitlist,1,ss,ymin,nx,100) ;
                   break ;

          case 3 : starta(&waitlist,1,ss,ymax,nx,-100) ;
                   break ;
        }
    }

  if (addbonus)
    {
      SPRINTF(bonusstr," ** Bonus : %3d **         ",bonus*10) ;
      startflashbonus() ;
      addscore(bonus) ;
    }
  else addbonus = 1 ;    /* don't add bonus at start. */
}


matchlist(plist,test,tx,ty)
struct ainfo **plist,*test ;
int tx,ty ;

{
  struct ainfo *owner,*this ;
  int nx,ny,s ;

  owner = NULL ;
  this = *plist ;
  while (this != NULL)
    {
      if (this != test)
        {
          if ((tx >= this->x) && (tx < this->x + this->sx)
                              && (ty >= this->y)
                              && (ty < this->y + this->sy))
            if (BITSET(tx - this->x + this->wx,ty - this->y + this->wy,48,wrkarea) != 0)
              {
                cleara(this) ;
                addscore(this->typ) ;
                if ((scorethistank - REFUEL) >= 0)
                  {
                    fuel = FULLTANK ;                      /* refuel */
                    scorethistank = 0 ;
                  }
                if ((this->typ == 1) || (this->typ == 2))
                  {
                    nx = (rint(42) + 1) / 2 ;
                    if (nx > 12) ny = 42 - nx ;
                    else ny = 30 ;
                    switch (rint(4))
                      {
                        case 1 : ny = (-ny) ;
                                 break ;

                        case 2 : s = nx ;
                                 nx = ny ;
                                 ny = s ;
                                 break ;

                        case 3 : s = nx ;
                                 nx = ny ;
                                 ny = (-s) ;
                                 break ;
                      }
                    if (this->typ == 1) s = 10 ;
                    else s = 8 ;
                    starta(plist,this->typ+1,this->x+s,this->y+s,this->xp+nx,this->yp+ny) ;
                    starta(plist,this->typ+1,this->x+s,this->y+s,this->xp-nx,this->yp-ny) ;
                    if (owner == NULL) owner = (*plist)->next ;
                    if (this->typ == 1)
                      {
                        t1count++ ;
                        if (t1count == 6)
                          {
                            if (rint(2) == 0)
                              starta(&waitlist,5,xmin,ymin+1,100,0) ;
                            else starta(&waitlist,5,xmax,ymin+1,-100,0) ;
                            scount = 10 ;
                            ssector = rint(7) ;
                          }
                      }
                  }
                else if (this->typ == 3)
                  {
                    t3count++ ;
                    if (t3count == 24) startlist() ;
                  } ;
                if (owner == NULL) *plist = this->next ;
                else owner->next = this->next ;
                this->next = freeap ;
                freeap = this ;
                return(1) ;
              }
        }
      owner = this ;
      this = this->next ;
    }
  return(0) ;
}


checkhit()

{
  struct ainfo *owner,*this,*del ;
  int i,x,y ;

  owner = NULL ;
  this = bplist ;
  while (this != NULL)
    {
      BLT_MEM(&test_pr,0,0,64,3,RXOR,&test_pr,0,0) ;
      BLT_SCRN_TO_MEM(&test_pr,0,0,3,3,RRPL,this->x,this->y) ;
      y = -1 ;
      for (i = 0; i <= 2; i++)
        if (testarea[i*4] != 0) y = i ;   /* this checks to see if row <> zeros */
      if (y < 0)
        {
          owner = this ;
          this = this->next ;
        }
      else
        {
          x = 0 ;
          while (BITSET(x,y,4,testarea) == 0) x++ ;
          x += this->x ;
          y += this->y ;
          cleara(this) ;
          if (!matchlist(&aplist,(struct ainfo *) NULL,x,y))
            if (!matchlist(&bplist,this,x,y)) /* do nothing */ ;
          del = this ;
          this = this->next ;
          if (owner == NULL) bplist = this ;
          else
            {
              if (owner->next == del) owner->next = this ;
              else if (bplist == del) bplist = this ;
              else
                {
                  owner = bplist ;
                  while (owner->next != del) owner = owner->next ;
                  owner->next = this ;
                }
            }
          del->next = freeap ;
          freeap = del ;
        }
    }
}


disintgt(gone)
int *gone ;

{
  int x,y,xx,yy,countdown,gotone ;

  x = 0 ;
  y = 0 ;
  gotone = 0 ;
  countdown = rint(3) ;
  SETOFF(bheight,bheight,48,wrkarea) ;
  do
    {
      if (x > y)
        if (x > (-y)) y-- ;
        else x-- ;
      else if (x < (-y)) y++ ;
      else x++ ;
      if (BITSET(x + bheight,y + bheight,48,wrkarea) != 0)
        {
          gotone = 1 ;
          if (countdown > 0) countdown-- ;
          else
            {
              countdown = 5 ;
              xx = x ;
              yy = y ;
              if (abs(x) >= abs(y)) xx = xx - (2 * (x > 0) - 1) ;
              if (abs(x) <= abs(y)) yy = yy - (2 * (y > 0) - 1) ;
              SETOFF(x+bheight,y+bheight,48,wrkarea) ;
              SETON(xx+bheight,yy+bheight,48,wrkarea) ;
            }
        }
    }
    while (x + y != bheight + bheight) ;
    *gone = !gotone ;
}


updatebase()

{
  int count,d,dd,dx,dy,i,j,newx,newy ;
  int changed,gone ;
  struct ainfo *ap ;

  switch (basestatus)
    {
      case BWAITING : if ((aplist == NULL) && (bplist == NULL))
                        {
                          bx = (xmin + xmax + 1) / 2 ;
                          by = (ymin + ymax + 1) / 2 ;
                          ax = 100 ;
                          ay = 0 ;
                          bxp = 0 ;
                          byp = 0 ;
                          bdx = 0 ;
                          bdy = 0 ;
                          bxpd = 0 ;
                          bypd = 0 ;
                          motoron = 0 ;
                          drawbase(ax,ay) ;
                          renewbase(0,0) ;
                          swcount = 0 ;
                          basestatus = BACTIVE ;
                        }
                      break ;

      case BACTIVE  : if (waitlist != NULL)
                        if (waitcount > 0) waitcount-- ;
                        else
                          {
                            ap = waitlist ;
                            waitlist = ap->next ;
                            ap->next = aplist ;
                            aplist = ap ;
                            waitcount = rint(rint(20) * 10 + 10) + 10 ;
                          }
                      d = diff() ;
                      changed = 0 ;
                      count = nummove + nummove ;
                      while ((d != 0) && (count > 0))
                        {
                          nextangle((d > 0),ax,ay,&newx,&newy) ;
                          dd = diff() ;
                          if ((dd == 0) || ((d > 0) == (dd > 0)) || (abs(dd) < abs(d)))
                            {
                              ax = newx ;
                              ay = newy ;
                              changed = 1 ;
                            }
                          if ((d > 0) != (dd > 0)) d = 0 ;
                          else d = dd ;
                          count-- ;
                        }
                      if (changed) drawbase(ax,ay) ;
                      for (count = 1; count <= nummove; count++)
                        {
                          if (motoron)
                            {
                              fuel -= 10 ;    /* burn some fuel. */
                              if (fuel <= 0)
                                {
                                  fuel = 0 ;
                                  motoron = 0 ;
                                }
                              bxpd += ax ;
                              bypd += ay ;
                              dx = bxpd / BFACTOR ;
                              dy = bypd / BFACTOR ;
                              bxp += dx ;
                              byp += dy ;
                              bxpd -= dx * BFACTOR ;
                              bypd -= dy * BFACTOR ;
                            }
                          bdx += bxp ;
                          bdy += byp ;
                        }
                      dx = bdx / BFACTOR ;
                      dy = bdy / BFACTOR ;
                      bdx -= dx * BFACTOR ;
                      bdy -= dy * BFACTOR ;
                      if (changed || (dx != 0) || (dy != 0)) renewbase(dx,dy) ;
                      BLT_MEM(&test_pr,0,0,64,bsize,RRPL,&wrk_pr,64,0) ;
                      BLT_SCRN_TO_MEM(&test_pr,0,0,bsize,bsize,RXNOR,
                                      bx-bheight,by-bheight) ;
                      i = 0 ;
                      do
                        if ((testarea[i*4]   == 0) &&  /* Is row = zero? */
                            (testarea[i*4+1] == 0) &&
                            (testarea[i*4+2] == 0) &&
                            (testarea[i*4+3] == 0)) i++ ;
                        else
                          {
                            j = 0 ;
                            while (BITSET(j,i,4,testarea) == 0) j++ ;
                            i += bx - bheight ;
                            j += by - bheight ;
                            if (!matchlist(&aplist,(struct ainfo *) NULL,j,i))
                              if (!matchlist(&bplist,(struct ainfo *) NULL,j,i)) ;
                            basestatus = BDYING ;
                            return ;
                          }
                      while (i != bsize) ;
                      if (c == BUTMIDDLE)
                        if (swcount > 0) swcount -= nummove ;
                        else
                          {
                            swcount = 20 ;
                            starta(&bplist,0,bx-1+(17*ax)/100,by-1+(17*ay)/100,ax*5,ay*5) ;
                          }
                      else swcount = 0 ;
                      break ;

      case BDYING   : disintgt(&gone) ;
                      renewbase(0,0) ;
                      if (gone)
                        {
                          while (wgread() != 0) ; /* Flush some output. */
                          state = 0 ;             /* Clear previous button state. */
                          basecount-- ;
                          if (basecount == 0) basestatus = BIDLE ;
                          else
                            {
                              basestatus = BWAITING ;
                              scorethistank = 0 ;
                              fuel = FULLTANK ;
                            }
                        }
                      break ;
    }
}


checkkey()

{
  int nx,ny,ss ;

  if (keys)
    {
      keys = 0 ;
      switch (c)
        {
          case 'q'       :
          case 'Q'       : closedown() ;
                           break ;

          case ESC       : motoron = ((basestatus == BACTIVE) && (fuel > 0)) ;
                           break ;

          case DEL       : motoron = 0 ;
                           break ;

          case BACKSPACE : if (basestatus == BACTIVE)
                             if (fuel >= (FULLTANK / 5))
                               {
                                 fuel -= (FULLTANK / 5) ;  /* 20% loss each hyperspace. */
                                 ss = (xmax - xmin) / 2 - bsize ;
                                 nx = xmin + bheight + rint(ss-50) + rint(ss+50) ;
                                 ny = ymin + bheight + rint(ss-50) + rint(ss+50) ;
                                 if (nx < xmin + bheight) nx = xmin + bheight ;
                                 else if (nx > xmax - bheight) nx = xmax - bheight ;
                                 if (ny < ymin + bheight) ny = ymin + bheight ;
                                 else if (ny > ymax - bheight) ny = ymax - bheight ;
                                 renewbase(nx-bx,ny-by) ;
                               }
                            break ;
        }
    }
}


numticks(to,from)
struct timeb *to,*from ;

{
  return(((to->time - from->time) * 1000 + (to->millitm - from->millitm)) / 16) ;
}


/*ARGSUSED*/
main(argc,argv)
int argc ;
char *argv[] ;

{
  STRCPY(progname,argv[0]) ;
  prog_type = MASTER ;

  when(god)
    etype(1)
      prog_type = SLAVE ;
      break ;
  endwhen ;

  get_options(argc,argv) ;          /* Get users command line options. */
  STRCPY(titlestring,"Asteroids  V2.0.") ;
  if (prog_type == MASTER)
    {
      starttool(orgx,orgy,width,height,titlestring) ;
      exit(0) ;                     /* Slave is dead, master suicides. */
    }

  startup() ;
  clear_screen() ;                  /* Clear the asteroids window. */
  if (givehelp) do_help_screen() ;  /* Output initial help/start screen. */
  clear_screen() ;                  /* White background, before inversion. */
  init() ;
  basecount = 3 ;
  startlist() ;
  basestatus = BWAITING ;
  ftime(&tlast) ;
  nummove = 1 ;
  do
    {
      updatelist(&aplist) ;
      updatelist(&bplist) ;
      updatebase() ;
      checkhit() ;
      checkkey() ;
      showfuel() ;
      if (flashbonus) doflashbonus() ;
      do
        {
          dummy = rint(2) ;
          ftime(&tnew) ;
        } 
      while (tnew.millitm == tlast.millitm) ;
      nummove = numticks(&tnew,&tlast) ;
      if (nummove > 20) nummove = 20 ;
      tlast.time = tnew.time ;
      tlast.millitm = tnew.millitm ;
    } 
  while ((basestatus != BIDLE) || (aplist != NULL) || (bplist != NULL)) ;
  closedown() ;
}
SHAR_EOF
fi
if test -f 'ast_stuff.c'
then
	echo shar: "will not over-write existing file 'ast_stuff.c'"
else
cat << \SHAR_EOF > 'ast_stuff.c'
 
/*  ast_stuff.c
 *
 *  Various functions and procedures used by the asteroids game.
 *  Written by Rich Burridge - SUN Australia (Melbourne) - December 1986.
 *
 *  Version 2.0.
 *
 *  Routines:
 *
 *  addscore              - Add up current total score.
 *  clear_screen          - Clear the asteroid tool window.
 *  closedown             - Output high scores and exit cleanly.
 *  do_help_screen        - Output initial help/start screen.
 *  doflashbonus          - Display bonus message.
 *  draw_frame            - Create popup window for help message.
 *  getline               - Get characters from player until RETURN pressed.
 *  get_options           - Get user command line options.
 *  rint                  - Pseudo random number generator.
 *  showfuel              - Show how much fuel is left.
 *  showtitle             - Display titlestring or bonus message.
 *  startflashbonus       - Start bonus message flashing.
 *
 *  No responsibility is taken for any errors inherent either to the code
 *  or the comments of this program, but if reported to me then an attempt
 *  will be made to fix them.
 */

#include <stdio.h>
#include <strings.h>
#include "asteroids.h"
#include <sys/timeb.h>

extern char bonusstr[MAXLINE] ;      /* Bonus message. */
extern char progname[MAXLINE] ;      /* Name of this program. */
extern char titlestring[MAXLINE] ;   /* Title string for asteroids window. */

extern struct timeb tstartflash,tlastflash ;

extern int basecount ;               /* Number of spaceships left. */
extern int bonusship ;               /* New ship every bonusship points. */
extern int bonusshown ;              /* Set if bonus message to be displayed. */
extern int flashbonus ;              /* Flag for when to flash message. */
extern int fuel ;                    /* Amount of spaceship fuel left. */
extern int fuellength ;              /* Current length of fuel bar. */
extern int fuelmaxlength ;           /* Maximum length of fuel bar. */
extern int fuelxoffset ;             /* Start of fuel display bar. */
extern int givehelp ;                /* Set to 0, no initial help given. */
extern int height ;                  /* Window height. */
extern int orgx ;                    /* Window X origin. */
extern int orgy ;                    /* Window Y origin. */
extern int rr ;                      /* Used by rint for random numbers. */
extern int score ;                   /* Current score. */
extern int scorethistank ;           /* Score this spaceship. */
extern int sfunc ;                   /* Rasterop function used by writeln. */
extern int width ;                   /* Window width. */


addscore(s)       /* Add up current total score. */
int s ;

{
  int s10 ;
 
  s10 = s*10 ;
  score += s10 ;
  scorethistank += s10 ;
 
  if (score > bonusship)
    {
      SPRINTF(bonusstr," ** Bonus Spaceship **    ") ;
      startflashbonus() ;
      basecount += 1 ;
      bonusship *= 2 ;   /* double it. */
    }
  SPRINTF(titlestring," Score : %6d",score) ;
  showtitle() ;
}
 
 
clear_screen()

{
  getwindowparms(&orgx,&orgy,&width,&height) ;
  BLT_SCRN(orgx,orgy,width,height,RCLR) ;
}


closedown()         /* Output high scores and exit cleanly. */

{
  BLT_SCRN(0,0,width,height,RXOR) ;
  checkscore() ;
  showhighscore() ;
  exit(0) ;
}
 
 
do_help_screen()
 
{
  int x,y ;
  int length = 0 ;         /* Length of longest help line. */
  int nolines = 0 ;        /* Number of lines in help file. */
  char line[MAXLINE] ;     /* Current line read from help file. */
  FILE *tf ;               /* File descripter for help file. */
  int texty = 20 ;         /* Initial y coordinate for help message. */
 
  if ((tf = fopen(HELPNAME,"r")) == NULL)
    {
      FPRINTF(stderr,"%s: can't open %s for help information.\n",
              progname,HELPNAME) ;
      return ;
    }
  while (fgets(line,MAXLINE,tf) != NULL)
    {
      if (strlen(line) > length) length = strlen(line) ;
      nolines++ ;
    }
  FCLOSE(tf) ;

  x = (width - length*FONT_WIDTH - 20) / 2 ;
  y = (height - nolines*15+texty) / 2 ;
  draw_frame(x,y,length*FONT_WIDTH+20,nolines*15+texty) ;

  tf = fopen(HELPNAME,"r") ;
  while (fgets(line,MAXLINE,tf) != NULL)
    {
      line[strlen(line)-1] = '\0' ;
      SCHRFUNC(PIX_SRC) ;
      writeln(x+10,y+texty,line) ;
      texty += 15 ;
    }
  FCLOSE(tf) ;
  while (wgread() != RETURN) ;
}


doflashbonus()

{
  struct timeb tnow ;

  ftime(&tnow) ;
  if (numticks(&tnow,&tlastflash) > FLICKERTIME)
    {
      bonusshown = !bonusshown ;   /* on off on off every second. */
      SCHRFUNC(RXOR) ;
      writeln(orgx+6,orgy+FONT_HEIGHT-2,bonusstr) ;
      tlastflash.time = tnow.time ;
      tlastflash.millitm = tnow.millitm ;
    }
 
/* See if time out, if so stop flash */
  if (((tnow.time - tstartflash.time) > FLASHTIME) && !bonusshown)
    {
      flashbonus = 0 ;
      addscore(0) ;      /* to put score back on screen. */
    }
}
 

draw_frame(x,y,fr_width,fr_height)
int x,y,fr_width,fr_height ;

{
  BLT_SCRN(x,y,fr_width,fr_height,RSET) ;
  BLT_SCRN(x+1,y+1,fr_width-2,fr_height-2,RCLR) ;
  BLT_SCRN(x+3,y+3,fr_width-6,fr_height-6,RSET) ;
  BLT_SCRN(x+5,y+5,fr_width-10,fr_height-10,RCLR) ;
}


getline(s,x,y)                 /* Get characters from user until a RETURN. */
char s[MAXLINE] ;
int x,y ;
 
{
  int c,i ;
 
  SCHRFUNC(RRPL) ;
  i = 0 ;
  for (;;)
    {
      s[i] = '_' ;
      s[i+1] = '\0' ;
      writeln(x,y,s) ;
      do
        c = wgread() ;
      while (!c) ;
      switch (c)
        {
          case BACKSPACE :
          case DEL       : if (i)
                             {   
                               s[i] = ' ' ;
                               s[i+1] = '\0' ;
                               i-- ;
                               writeln(x,y,s) ;
                             }
                           break ;
          case RETURN    : s[i] = '\0' ;
                           return(i) ;
          default        : s[i++] = c ;
        }
    }
}
 
 
get_options(argc,argv)
int argc ;
char *argv[] ;

{
  char *arg ;
  char *p ;      /* Pointer to string following argument flag. */

  width = SWIDTH ;
  height = SHEIGHT ;
  givehelp = 1 ;
  while (argc > 1 && (arg = argv[1])[0] == '-')
    {
      p = arg + 2 ;
      switch (arg[1])
        {
          case 'h' : givehelp = 0 ;        /* Don't display help message. */
                     break ;
          case 'x' : width = atoi(p) ;     /* Width of asteroids window. */
                     if (width < 500) width = 500 ;
                     break ;
          case 'y' : height = atoi(p) ;    /* Height of asteroids window. */
                     if (height < 500) height = 500 ;
                     break ;
          default  : FPRINTF(stderr,"sidtool: USAGE %s [-d]\n",argv[0]) ;
                     exit(1) ;
        }
      argc-- ;
      argv++ ;
    }
}


rint(r)
int r ;
 
{
  rr = ((rr*4705 + 1) & 32767) ;
  if (!r) r = 1 ;
  return(rr % r) ;
}


showfuel()         /* Show how much fuel is left. */

{
  int howmuch ;

  howmuch = (int)(fuelmaxlength * ((double)fuel / (double)FULLTANK)) ;
  if (howmuch != fuellength)
    {
      BLT_SCRN(fuelxoffset,height-FONT_HEIGHT,fuelmaxlength,FONT_HEIGHT-2,RCLR) ;
      fuellength = howmuch ;
      BLT_SCRN(fuelxoffset,height-FONT_HEIGHT,fuellength,FONT_HEIGHT-2,RXNOR) ;
    }
}


showtitle()      /* Display titlestring or bonus message. */

{
  if (!flashbonus)
    {
      SCHRFUNC(RRPL) ;
      writeln(orgx+6,orgy+FONT_HEIGHT-2,titlestring) ;
    }
}


startflashbonus()   /* start bonus flashing. */

{
  flashbonus = 1 ;
  bonusshown = 1 ;
  SCHRFUNC(RRPL) ;
  writeln(orgx+6,orgy+FONT_HEIGHT-2,bonusstr) ;  /* Don't XOR the first one. */
  ftime(&tstartflash) ;                          /* Get the time start. */
  tlastflash.time = tstartflash.time ;
  tlastflash.millitm = tstartflash.millitm ;
}
SHAR_EOF
fi
if test -f 'ast_sun.c'
then
	echo shar: "will not over-write existing file 'ast_sun.c'"
else
cat << \SHAR_EOF > 'ast_sun.c'
 
/*  ast_sun.c
 *
 *  SUN dependent functions and procedures used by the asteroids game.
 *  Written by Rich Burridge - SUN Australia (Melbourne) - December 1986.
 *
 *  Version 2.0.
 *
 *  Routines.
 *  ---------
 *
 *  lose
 *  sigwinched
 *  sigchild
 *  toolsw_selected
 *  toolsw_sighandler
 *  starttool
 *  startup
 *  write_bold          - Output text item in pseudo bold.*  writeln
 *  getwindowparms      - Return window dimensions.
 *  wgread              - Check for button or key pressed.
 *
 *  No responsibility is taken for any errors inherent either to the code
 *  or the comments of this program, but if reported to me then an attempt
 *  will be made to fix them.
 */

#include <stdio.h>
#include <strings.h>
#include "asteroids.h"
#include <sys/timeb.h>
#include <suntool/tool_hs.h>
#include <suntool/emptysw.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <signal.h>
#include <errno.h>
 
exexception(god) ;
 
extern int errno ;
struct pixwin     *pixwin ;
struct tool       *tool ;
struct toolsw     *emptysw ;
struct inputevent ie ;
struct inputmask  im ;
sigwinched(),sigchild() ;
toolsw_selected(),toolsw_sighandler() ;

int pid ;                            /* Process id of slave program. */
int finished = 0 ;                   /* 1 -> socket no longer available. */
int sfunc ;
 
extern int c ;           /* Used by wgread for mouse and keyboard interaction. */
extern int width,height ;            /* Dimensions of the SID tool window. */
 
static short ast_image[256] = {
#include "asteroids.icon"
} ;
mpr_static(ast_mpr,64,64,1,ast_image) ;
  
static struct icon icon =
                     {
                       64,64,(struct pixrect *)NULL,0,0,64,64,
                       &ast_mpr,0,0,0,0,NULL,(struct pixfont *)NULL,
                       ICON_BKGRDCLR
                     } ;

extern struct pixfont *pw_pfsysopen() ;       /* GFX stuff. */
static struct pixfont *pixfont ;
struct gfxsubwindow *gfx ;
char name[WIN_NAMESIZE] ;

static struct cursor nullcur,syscur ;              /* Cursor stuff. */
static short  nullicon[CUR_MAXIMAGEWORDS],sysicon[CUR_MAXIMAGEWORDS] ;
mpr_static(nullpix,8*sizeof(nullicon[0]),
           sizeof(nullicon)/sizeof(nullicon[0]),1,nullicon) ;
mpr_static(syscurpix,8*sizeof(sysicon[0]),
           sizeof(sysicon)/sizeof(sysicon[0]),1,sysicon) ;
 
#define  TUNIT     0                               /* Socket stuff. */
static struct timeval timeout = {TUNIT,TUNIT} ;
static struct sockaddr_un client,server ;
static int mask,sin,sout,snew,slen ;


lose(str)
char *str ;

{
  FPRINTF(stderr,str) ;
  exit(1) ;
}


static sigwinched()
{
  tool_sigwinch(tool) ;
}


static sigchild()
{
  finished = 1 ;
  tool_sigchld(tool) ;
}


/*ARGSUSED*/
static toolsw_selected(sw,ibits,obits,ebits,timer)
caddr_t sw ;
int *ibits,*obits,*ebits ;
struct timeval **timer ;

{
  char c = '\0' ;
 
  if (*ibits & (1 << emptysw->ts_windowfd))
    {
      input_readevent(emptysw->ts_windowfd,&ie) ;
      switch (ie.ie_code)
        {
          case MS_LEFT   : if (ie.ie_flags & IE_NEGEVENT) c = LEFTUP ;
                           else if (!(ie.ie_flags & IE_NEGEVENT)) c = LEFTDOWN ;
                           break ;
          case MS_MIDDLE : if (!(ie.ie_flags & IE_NEGEVENT)) c = BUTMIDDLE ;
                           break ;
          case MS_RIGHT  : if (ie.ie_flags & IE_NEGEVENT) c = RIGHTUP ;
                           else if (!(ie.ie_flags & IE_NEGEVENT)) c = RIGHTDOWN ;
        }
      if ((ie.ie_code >= ASCII_FIRST) && (ie.ie_code <= ASCII_LAST))
        c = (char) ie.ie_code ;
      WRITE(snew,&c,1) ;
    }
  *ibits = 0 ;
}


static toolsw_sighandler()

{
  char c ;

  if (!finished)
    {
      c = WIN_DAMAGED ;
      WRITE(snew,&c,1) ;
      pw_damaged(pixwin) ;
      pw_donedamaged(pixwin) ;
    }
}


starttool(orgx,orgy,width,height,toolname)
int orgx,orgy,width,height ;
char *toolname ;

{
  char **tool_attrs = NULL ;

  UNLINK(SOCKNAME) ;
  sout = socket(AF_UNIX,SOCK_STREAM,0) ;      /* Create server socket. */
  server.sun_family = AF_UNIX ;
  STRCPY(server.sun_path,SOCKNAME) ;
  BIND(sout,(struct sockaddr *) &server,strlen(SOCKNAME)+2) ;
  LISTEN(sout,5) ;

  tool = tool_make(WIN_LABEL,     toolname,   WIN_ICON,      &icon,
                   WIN_LEFT,      orgx,       WIN_TOP,        orgy,
                   WIN_WIDTH,     width,      WIN_HEIGHT,     height,
                   WIN_ATTR_LIST, tool_attrs, 0) ;
  if (tool == (struct tool *)NULL) lose("Couldn't create tool") ;
  tool_free_attribute_list(tool_attrs) ;

  emptysw = esw_createtoolsubwindow(tool,"",TOOL_SWEXTENDTOEDGE,TOOL_SWEXTENDTOEDGE) ;  if (emptysw == (struct toolsw *)NULL) lose("Couldn't create empty subwindow") ;

  pixwin = pw_open(emptysw->ts_windowfd) ;
  if (pixwin == (struct pixwin *)NULL) lose("Couldn't create pixwin.") ;

  emptysw->ts_io.tio_handlesigwinch = toolsw_sighandler ;
  emptysw->ts_io.tio_selected = toolsw_selected ;

  input_imnull(&im) ;
  im.im_flags |= IM_ASCII ;
  im.im_flags |= IM_NEGEVENT ;
  win_setinputcodebit(&im,MS_LEFT) ;
  win_setinputcodebit(&im,MS_MIDDLE) ;
  win_setinputcodebit(&im,MS_RIGHT) ;
  win_setinputmask(emptysw->ts_windowfd,&im,(struct inputmask *)NULL,WIN_NULLLINK) ;

  (void) signal(SIGWINCH,sigwinched) ;
  tool_install(tool) ;                        /* Install the tool. */
  win_fdtoname(emptysw->ts_windowfd,name) ;   /* Make GFX window name. */
  we_setgfxwindow(name) ;

  if ((pid = fork()) == NULL) raise(god,1) ;  /* Fork graphics program. */

  slen = sizeof(server) ;
  snew = accept(sout,(struct sockaddr *) &server,&slen) ;   /* Accept client socket. */

  (void) signal(SIGCHLD,sigchild) ;
  tool_select(tool,1) ;                       /* Notification loop. */
  tool_destroy(tool) ;                        /* Die gracefully. */
  KILL(pid,SIGKILL) ;                         /* Murder the child !! */
  CLOSE(snew) ;
  CLOSE(sout) ;
}


startup()

{
  sfunc = PIX_SRC ;                           /* Used by writeln */
  sin = socket(AF_UNIX,SOCK_STREAM,0) ;       /* Create client socket. */

  client.sun_family = AF_UNIX ;
  STRCPY(client.sun_path,SOCKNAME) ;
  CONNECT(sin,(struct sockaddr *) &client,strlen(client.sun_path)+2) ;

  gfx = gfxsw_init(0,0) ;
  if (gfx == (struct gfxsubwindow *)NULL) lose("Couldn't create graphics window.") ;

  pixfont = pw_pfsysopen() ;
  if (pixfont == (struct pixfont *)NULL) lose("Couldn't create default font.") ;

  syscur.cur_shape = &syscurpix ;
  win_getcursor(gfx->gfx_windowfd,&syscur) ;
  syscur.cur_function = RXOR ;

  nullcur.cur_shape = &nullpix ;
  win_getcursor(gfx->gfx_windowfd,&nullcur) ;
  nullcur.cur_xhot = nullcur.cur_yhot = 0 ;
  nullcur.cur_function = RXOR ;
  nullcur.cur_shape->pr_size.x = 0 ;
  nullcur.cur_shape->pr_size.y = 0 ;
}


write_bold(x,y,text)
int x,y ;
char text[MAXLINE] ;

{
  pw_text(gfx->gfx_pixwin,x,y,ROR,pixfont,text) ;
  pw_text(gfx->gfx_pixwin,x+1,y,ROR,pixfont,text) ;
}


writeln(x,y,text)                 /* Write a line of text to the screen at x,y. */
int x,y ;
char *text ;
 
{
  pw_text(gfx->gfx_pixwin,x,y,sfunc,pixfont,text) ;
}
 
 
getwindowparms(orgx,orgy,width,height)           /* Return window dimensions. */
int *orgx,*orgy,*width,*height ;
 
{
  struct rect rect ;
 
  win_getsize(gfx->gfx_windowfd,&rect) ;
  *orgx = rect.r_left ;
  *orgy = rect.r_top ;
  *width = rect.r_width ;
  *height = rect.r_height ;
}
 
 
wgread()        /* Check for button or key pressed. */
 
{
  char c ;

  c = '\0' ;
  mask = 1 << sin ;
  SELECT(32,&mask,(int *) 0,(int *) 0,&timeout) ;
  if (mask & (1 << sin)) READ(sin,&c,1) ;
  return((int) c) ;
}
SHAR_EOF
fi
exit 0
#	End of shell archive
D
D