DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T a

⟦c339a82ba⟧ TextFile

    Length: 36644 (0x8f24)
    Types: TextFile
    Names: »ast_main.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/Sun/Asteroids/ast_main.c« 

TextFile


/*  ast_main.c
 *
 *  The game of Asteroids.
 *  Written by Rich Burridge - SUN Microsystems Australia (Melbourne).
 *
 *  Version 3.0.  -  April 1987.
 *
 *  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/fcntl.h>
#include "bltstuff.h"
#include "asteroids.h"
#include <suntool/sunview.h>
#include <suntool/canvas.h>

#include <sys/types.h>
#include <sys/timeb.h>
#include <signal.h>

Canvas canvas ;
Frame base_frame ;
Pixfont *pf ;
Pixwin *pw ;

extern etext() ;

Notify_value main_loop() ;
void event_proc() ;

short ast_image[] = {
#include "asteroids.icon"
} ;
DEFINE_ICON_FROM_IMAGE(ast_icon,ast_image) ;

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 highscore[MAXHS] ;

int key_stations[3] = {21, 22, 23} ;  /* Station values for function keys R1-R3. */
char old_key_vals[3][MAXLINE] ;       /* Function key string values to save. */
char new_key_vals[3][MAXLINE] =       /* Function key values used by asteroids. */
     {
       "g",                  /* Motor on - Function key R1. */
       "s",                  /* Motor off - Function key R2. */
       "t"                   /* Hyperspace/teleport - Function key R3. */
     } ;

char path[MAXLINE] ;         /* Full path to the asteroids files. */
char progname[MAXLINE] ;     /* Name of this program. */
char thisscore[MAXLINE] ;    /* User name for new highscore. */
char titlestring[MAXLINE] ;  /* Displayed titleline for this program. */

int c ;                      /* Value returned by event_proc. */
int canvasfd ;               /* File descriptor for canvas subwindow. */
int canvasflags ;            /* Used to setup no delay for canvas. */
int csi,csj ;                /* Used to put the new highscore value. */
int height ;                 /* Height of the asteroids window. */
int givehelp ;               /* Set to 0, indicates no initial help. */
int orgx ;                   /* X origin of the asteroids window. */
int orgy ;                   /* Y origin of the asteroids window. */
int scorei ;                 /* Number of characters in highscore user name. */
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. */
int progstate ;          /* State machine for main loop. */
int savedstate ;         /* State machine value after Ctrl S. */

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 rint() ;


checkscore()

{
  char buffer[MAXLINE] ;

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

  if (++csi < MAXHS)
    {
      clear_screen() ;
      SPRINTF(buffer,"Congratulations, you have one of the top %d scores\n",MAXHS) ;
      WRITELN(100,140,buffer) ;
      WRITELN(100,200,"Please enter your name : ") ;
      scorei = 0 ;
      c = 0 ;
      thisscore[scorei] = '_' ;
      thisscore[scorei+1] = '\0' ;
      WRITELN(370,200,thisscore) ;
      progstate = NEXTLINE ;
    }
  else progstate = DOEND ;
}


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") ;
  progstate = SCORE ;
}


gethighscore()

{
  int hsfile,i ;
  struct hscore nullscore ;
  char highscname[MAXLINE] ;   /* Full path name of the high score file. */

  SPRINTF(highscname,"%sasteroids.hs",path) ;
  if ((hsfile = open(highscname,2)) == -1)
    {
      if ((hsfile = creat(highscname,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 ;
  char highscname[MAXLINE] ;   /* Full path name of the high score file. */ 

  SPRINTF(highscname,"%sasteroids.hs",path) ;
  if ((hsfile = open(highscname,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 !!! */
  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. */
  FPRINTF(stderr,"%d %d %d %d\n",xmin,ymin,xmax-xmin+1,ymax-ymin+1) ;
  BLT_SCRN(xmin,ymin,xmax-xmin+1,ymax-ymin+1,RXNOR) ;
  SCHRFUNC(RRPL) ;
  WRITELN(xmin+2,height-5,"Fuel : ") ;
  FPRINTF(stderr,"%d %d\n",xmin+2,height-5) ;

  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 ;
}


diff()

{
  if (fuel <= 0) return(0) ;
  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) ;
                            }
                          c = 0 ;
                        }
                      else swcount = 0 ;
                      break ;

      case BDYING   : disintgt(&gone) ;
                      renewbase(0,0) ;
                      if (gone)
                        {
                          state = 0 ;             /* Clear previous button state. */
                          basecount-- ;
                          addscore(0) ;           /* Correct number of ships left. */
                          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 K_QUIT    : progstate = EXPIRED ;
                           break ;

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

          case K_STOP    : motoron = 0 ;
                           break ;

          case K_TELEPORT: 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) ;
}


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

{
  get_options(argc,argv) ;          /* Get users command line options. */
  function_keys(KEY_SET) ;          /* Set asteroid commands function keys. */

  base_frame = window_create(NULL, FRAME,
                             FRAME_LABEL, titlestring,
                             FRAME_ICON, &ast_icon,
                             WIN_X, orgx,
                             WIN_Y, orgy,
                             WIN_WIDTH, width,
                             WIN_HEIGHT, height,
                             FRAME_ARGS, argc, argv,
                             0) ;
  width = width - 10 ;
  height = height - 25 ;

  canvas = window_create(base_frame, CANVAS,
                         CANVAS_RETAINED, TRUE,
                         CANVAS_FAST_MONO, TRUE,
                         WIN_EVENT_PROC, event_proc,
                         0) ;

  window_set(canvas, WIN_CONSUME_KBD_EVENTS, WIN_ASCII_EVENTS, 0) ;
  window_set(canvas, WIN_CONSUME_KBD_EVENTS, WIN_LEFT_KEYS, 0) ;

  pf = pf_default() ;
  pw = canvas_pixwin(canvas) ;

/* Set up no delay for events within the canvas. */
  canvasfd = (int) window_get(canvas,WIN_FD) ;
  canvasflags = fcntl(canvasfd,F_GETFL,0) ;
  canvasflags |= FNDELAY ;
  FCNTL(canvasfd,F_SETFL,canvasflags) ;

  sfunc = PIX_SRC ;                 /* Used by WRITELN. */
  iocursormode(OFFCURSOR) ;
  progstate = HELP ;

  (void) notify_set_itimer_func(base_frame, main_loop, ITIMER_REAL,
                        &NOTIFY_POLLING_ITIMER, ((struct itimerval *) 0)) ;
  window_main_loop(base_frame) ;
  exit(0) ;
}


/*ARGSUSED*/
void
event_proc(window,event,arg)
Window *window ;
Event *event ;
caddr_t arg ;

{
  if (event_is_button(event))
    {
      switch (event_id(event))
        {
          case MS_LEFT   : if (event_is_down(event)) c = LEFTDOWN ;
                           else c = LEFTUP ;
                           break ;
          case MS_MIDDLE : if (event_is_down(event)) c = BUTMIDDLE ;
                           break ;
          case MS_RIGHT  : if (event_is_down(event)) c = RIGHTDOWN ;
                           else c = RIGHTUP ;
        }
    }
  else if (event_is_ascii(event)) c = event_id(event) ;

  if (c == CTRLS)
    {
      if (progstate != CTRLSHIT) savedstate = progstate ;
      progstate = CTRLSHIT ;
      return ;
    }
  else if (c == CTRLQ)
    {
      progstate = savedstate ;
      return ;
    }
  else if (c > RIGHTDOWN) keys = 1 ;
  if (c == LEFTDOWN || c == RIGHTDOWN || c == LEFTUP || c == RIGHTUP) state = c ;
}


/*ARGSUSED*/
static Notify_value
main_loop(client, itimer_type)
Notify_client client ;
int itimer_type ;

{
  switch (progstate)
    {
      case HELP     : clear_screen() ;    /* Clear the asteroids window. */
                      if (givehelp) do_help_screen() ;  /* Output help screen. */
                      progstate = GETRET ;
                      break ;
      case GETRET   : if (c == RETURN) progstate = STARTUP ;
                      break ;
      case STARTUP  : clear_screen() ;   /* White background, before inversion. */
                      basecount = 3 ;
                      init() ;
                      startlist() ;
                      basestatus = BWAITING ;
                      ftime(&tlast) ;
                      nummove = 1 ;
                      progstate = UPDATE ;
                      break ;
      case UPDATE   : update() ;
                      break ;
      case EXPIRED  : function_keys(KEY_RESET) ;
                      BLT_SCRN(0,0,width,height,RXOR) ;
                      checkscore() ;
      case NEXTLINE : getnewscore(365,200) ;
                      break ;
      case DOEND    : showhighscore() ;
                      break ;
      case SCORE    : if (c == RETURN) exit(0) ;
                      break ;
      case CTRLSHIT : break ;
    }
}


update()

{
  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 ;
  if ((basestatus == BIDLE) && (aplist == NULL) && (bplist == NULL))
    progstate = EXPIRED ;
}