#include <stdio.h>
#include <stdlib.h>

/*#define DEBUG*/

#ifndef FALSE
#define FALSE (0!=0)
#define TRUE (0==0)
#endif



static char msg[80];

#include "allegro.h"

static BITMAP *buffer;

void init_graph(void)
{
#ifndef DEBUG
  PALLETE pal;
  int c = 256;
  int w = 640;
  int h = 480;
  int bpp = 8;
  int last_retrace_count;
  int i;

  allegro_init();
  install_keyboard();
  install_mouse();
  install_timer();

  for (i=0; i<16; i++)
    pal[i].r = pal[i].g = pal[i].b = 0;

  /* greyscale */
  pal[16].r = pal[16].g = pal[16].b = 63;
  pal[17].r = pal[17].g = pal[17].b = 48;
  pal[18].r = pal[18].g = pal[18].b = 32;
  pal[19].r = pal[19].g = pal[19].b = 16;
  pal[20].r = pal[20].g = pal[20].b = 8;

  for (i=0; i<16; i++)   /* red range */
  {
    pal[i+32].r = 31+(i*2);
    pal[i+32].g = 15;
    pal[i+32].b = 7;
  }
  for (i=64; i<68; i++)
  {
    pal[i].r = 63;      /* a nice fire orange */
    pal[i].g = 17+((i-64)*3);
    pal[i].b = 0;
  }

  set_color_depth(bpp);

  if (set_gfx_mode(c, w, h, 0, 0) != 0) {
     allegro_exit();
     printf("Error setting graphics mode\n%s\n\n", allegro_error);
     return;
  }

//  if (gfx_driver->id == GFX_MODEX) {
//     allegro_exit();
//     printf("Can't draw 3d polygons in mode-X, sorry!\n\n");
//     return;
//  }

  /* Tailgunner: */
  for (i=1; i<8; i++)   /* normal */
  {
    pal[i].r = pal[i].g = pal[i].b = 48;
  }
  for (i=8; i<16; i++)  /* bright */
  {
    pal[i].r = pal[i].g = pal[i].b = 63;
  }

  set_palette (pal);

  /* double buffer the animation */
  buffer = create_bitmap(SCREEN_W, SCREEN_H);

  /* set up the viewport for the perspective projection */
  set_projection_viewport(0, 0, SCREEN_W, SCREEN_H);

  last_retrace_count = retrace_count;
  clear(buffer);
#endif
}

void end_graph(void)
{
#ifndef DEBUG
   destroy_bitmap(buffer);
#endif
}

void CinemaClearScreen(void)
{
#ifndef DEBUG
  vsync();
  /*textout(buffer, font, "Testing", 450, 460, 15);*/
  blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
  clear(buffer);
#endif
}

static int MinX=1000, MinY=1000, MaxX=0, MaxY=0;

void CinemaVectorData(int RCFromX, int RCFromY, int RCToX, int RCToY, int vgColour)
{
  /*Remove stars: if ((RCFromX == RCToX) && (RCFromY == RCToY)) return;*/
  RCFromX = (RCFromX * 2) / 3; RCToX = (RCToX * 2) / 3;
  RCFromY = (RCFromY * 2) / 3; RCToY = (RCToY * 2) / 3;
  RCFromX -= 32; RCToX -= 32;
  RCFromY = SCREEN_H-RCFromY; RCToY=SCREEN_H-RCToY;

/* HACK */ if (vgColour & 0x8) vgColour = 0xf; else vgColour = 0x7;

  if (RCFromX < MinX) MinX = RCFromX;
  if (RCToX < MinX) MinX = RCToX;
  if (RCFromY < MinY) MinY = RCFromY;
  if (RCToY < MinY) MinY = RCToY;
  if (RCFromX > MaxX) MaxX = RCFromX;
  if (RCToX > MaxX) MaxX = RCToX;
  if (RCFromY > MaxY) MaxY = RCFromY;
  if (RCToY > MaxY) MaxY = RCToY;
#ifndef DEBUG
  line(buffer,RCFromX,RCFromY,RCToX,RCToY,vgColour);
#endif
}

char charvec[] = {
 '0', 4, 0xae, 0xe4, 0x40, 0x0a,
 '1', 1, 0x2c,
 '2', 5, 0xae, 0xe9, 0x95, 0x50, 0x04,
 '3', 4, 0x04, 0x79, 0x4e, 0xea,
#ifdef GTCHARS
 '4', 3, 0xa5, 0x59, 0x72, /* mine */
#else
 '4', 3, 0x5a, 0x59, 0x4e, /* orig */
#endif
 '5', 5, 0x04, 0x49, 0x95, 0x5a, 0xae,
 '6', 4, 0x59, 0x94, 0x40, 0x0a,
 '7', 2, 0x2e, 0xea,
 '8', 5, 0x04, 0xae, 0x59, 0xe4, 0xa0,
 '9', 4, 0xea, 0xa5, 0x59, 0xe4,
 'A', 4, 0x4e, 0xae, 0x59, 0xa0,
 'B', 5, 0x69, 0x04, 0x4e, 0xea, 0xb1,
 'C', 3, 0xae, 0x40, 0x0a,
#ifdef GTCHARS
 'D', 5, 0xad, 0xd9, 0x93, 0x30, 0x0a,
#else
 'D', 4, 0xae, 0xe4, 0x40, 0x1b,
#endif
 'E', 4, 0x40, 0x0a, 0x57, 0xae,
 'F', 3, 0x0a, 0x57, 0xae,
 'G', 5, 0x79, 0x94, 0x40, 0x0a, 0xae,
 'H', 3, 0x0a, 0x59, 0x4e,
 'I', 1, 0x2c,
 'J', 4, 0x50, 0x03, 0x3d, 0xbe,
 'K', 3, 0x0a, 0xe5, 0x54,
 'L', 2, 0x0a, 0x04,
 'M', 4, 0x0a, 0xa7, 0x7e, 0xe4,
 'N', 3, 0x0a, 0xa4, 0x4e,
 'O', 4, 0xae, 0xe4, 0x40, 0x0a,
 'P', 4, 0x0a, 0xae, 0xe9, 0x95,
 'Q', 5, 0x0a, 0xae, 0xe4, 0x40, 0x48,
 'R', 5, 0x48, 0x59, 0x9e, 0xea, 0xa0,
 'S', 5, 0x04, 0x49, 0x95, 0x5a, 0xae,
 'T', 2, 0xae, 0xc2,
 'U', 3, 0x0a, 0x04, 0x4e,
 'V', 2, 0xa2, 0x2e,
 'W', 4, 0xa1, 0x17, 0x73, 0x3e,
 'X', 2, 0x0e, 0xa4,
 'Y', 3, 0x27, 0x7a, 0x7e,
 'Z', 3, 0xae, 0xe0, 0x04,
 '\0'
};

char *nibbles[256];

void initchars()
{
  int i;
  char *s = charvec;
  for (i = 0; i < 256; i++) nibbles[i] = NULL;
  for (;;) {
    if (*s == '\0') break;
    nibbles[*s] = s+1;
#ifdef DEBUG
    fprintf(stdout,"nibbles[%c] = %d char string\n", *s, *(s+1));
#endif 
    s = s+1;
    s = s + (*s) + 1;
  }
};

int lookupx[16] = {
  0x00, 0x04, 0x08, 0x0c, 0x10,
  0x00, 0x04, 0x08, 0x0c, 0x10,
  0x00, 0x04, 0x08, 0x0c, 0x10,
  0
};

int lookupy[16] = {
  0x00, 0x00, 0x00, 0x00, 0x00,
  0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
  0x18, 0x18, 0x18, 0x18, 0x18,
  0
};

int curx = 0, cury = 0, curcol = 15;;

void vecmoveto(int x, int y)
{
  curx = x; cury = y;
}

void veccol(int col)
{
  curcol = col;
}

void printchar(int c)
{
  char *nibblep = nibbles[c&255];
  int i, nibble, from, to, len;

  if (nibblep == NULL) {
    curx += 0x18; /* space */
    return;
  }
  len = *nibblep++;
  for (i = 0; i < len; i++) {
    nibble = *nibblep++;
    to = nibble&15; from = (nibble>>4)&15;

    CinemaVectorData(curx+lookupx[from], cury+lookupy[from],
                     curx+lookupx[to],   cury+lookupy[to],
                     curcol);
#ifdef DEBUG
    fprintf(stdout, "%01x to %01x\n", from, to);
    fprintf(stdout, "(%d,%d) to (%d,%d) at %d\n", curx+lookupx[from], cury+lookupy[from],
                     curx+lookupx[to],   cury+lookupy[to],
                     7);
#endif
  }
  curx += 0x18;
  /* at current x y and do implicit move */
}

void printstring(char *s)
{
  while (*s != '\0') printchar(*s++);
}

unsigned char rectangle_lookup_x[8] = {
 0x47, 0xb9, 0xb9, 0x47, 0x3f, 0xc1, 0xc1, 0x3f
};

unsigned char rectangle_lookup_y[8] = {
 0x9b, 0x9b, 0x65, 0x65, 0xa3, 0xa3, 0x5d, 0x5d
};

unsigned char rectangle_lookup_z[8] = {
 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
};

unsigned char rectangles[] = {
  0x01, 0x12, 0x23, 0x30, 0x45, 0x56, 0x67, 0x74, 0xff
};

void print_rectangles_seg(int c)
{
  unsigned char *coords = rectangles;
  int fromx, fromy, fromz, tox, toy, toz;
  int nib1 = c >> 4, nib2 = c&7;
  fromx = rectangle_lookup_x[nib1];
  fromy = rectangle_lookup_y[nib1];
  fromz = rectangle_lookup_z[nib1];
  tox = rectangle_lookup_x[nib2];
  toy = rectangle_lookup_y[nib2];
  toz = rectangle_lookup_z[nib2];
  CinemaVectorData(curx+fromx, cury+fromy,
                   curx+tox,   cury+toy,
                   15);
}

void print_rectangles(void)
{
  char *s = rectangles;
  unsigned char ch = *s;
  while (ch != 0xff) {
    print_rectangles_seg(ch);
    s += 1;
    ch = *s;
  }
}

unsigned char tg1_lookup_x[16] = {
 0x5d, 0x6d, 0x65, 0x65, 0x71, 0x77, 0x7d, 0x74, 0x7a, 0x89, 0x89, 0x95, 0x95, 0xa1, 0xa7, 0xa7
};

unsigned char tg1_lookup_y[16] = {
 0x95, 0x95, 0x95, 0x83, 0x83, 0x95, 0x83, 0x8c, 0x8c, 0x83, 0x95, 0x95, 0x83, 0x83, 0x7d, 0x6b
};

unsigned char tg1_lookup_z[16] = {
 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
};

unsigned char tg1[] = {
  0x01, 0x23, 0x45, 0x56, 0x78, 0x9a, 0xbc, 0xcd, 0xef, 0xff
};

unsigned char tg2_lookup_x[16] = {
 0xa7, 0xb3, 0xb3, 0xb0, 0xb3, 0xa7, 0xa1, 0x95, 0x95, 0xa1, 0x9b, 0x95, 0x8f, 0x8f, 0x83, 0x83
};

unsigned char tg2_lookup_y[16] = {
 0x7d, 0x7d, 0x74, 0x74, 0x6b, 0x74, 0x6b, 0x6b, 0x7d, 0x7d, 0x74, 0x74, 0x7d, 0x6b, 0x7d, 0x6b
};

unsigned char tg2_lookup_z[16] = {
 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
};

unsigned char tg2[] = {
  0x01, 0x12, 0x34, 0x25, 0x67, 0x78, 0x89, 0xab, 0xcd, 0xde, 0xef, 0xff
};

unsigned char tg3_lookup_x[16] = {
 0x7d, 0x7d, 0x71, 0x71, 0x6b, 0x6b, 0x5f, 0x5f, 0x5c, 0x56, 0x59, 0x59, 0x4d, 0x4d, 0x59
};

unsigned char tg3_lookup_y[16] = {
 0x7d, 0x6b, 0x7d, 0x6b, 0x7d, 0x6b, 0x6b, 0x7d, 0x72, 0x72, 0x72, 0x6b, 0x6b, 0x7d, 0x7d
};

unsigned char tg3_lookup_z[16] = {
 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
};

unsigned char tg3[] = {
  0x01, 0x12, 0x23, 0x45, 0x56, 0x67, 0x89, 0xab, 0xbc, 0xcd, 0xde, 0xff
};

void print_tg_seg(char c, unsigned char *tg_lookup_x, unsigned char *tg_lookup_y, unsigned char *tg_lookup_z) {
  char *coords = rectangles;
  int fromx, fromy, fromz, tox, toy, toz;
  int nib1 = (c >> 4)&15, nib2 = c&15;
  fromx = tg_lookup_x[nib1];
  fromy = tg_lookup_y[nib1];
  fromz = tg_lookup_z[nib1];
  tox = tg_lookup_x[nib2];
  toy = tg_lookup_y[nib2];
  toz = tg_lookup_z[nib2];
  CinemaVectorData(curx+fromx, cury+fromy,
                   curx+tox,   cury+toy,
                   15);
}

void print_tg_word(unsigned char *tg, unsigned char *tg_lookup_x, unsigned char *tg_lookup_y, unsigned char *tg_lookup_z)
{
  char *s = tg;
  unsigned char ch = *s;
  while (ch != 0xff) {
    print_tg_seg(ch, tg_lookup_x, tg_lookup_y, tg_lookup_z);
    s += 1;
    ch = *s;
  }
}

void print_tg(void)
{
   print_tg_word(tg1, tg1_lookup_x, tg1_lookup_y, tg1_lookup_z);
   print_tg_word(tg2, tg2_lookup_x, tg2_lookup_y, tg2_lookup_z);
   print_tg_word(tg3, tg3_lookup_x, tg3_lookup_y, tg3_lookup_z);
}

void starplot(int x, int y)
{
  CinemaVectorData(x, y,
                   x+1, y+1,
                   7);
}


/* The screen is divided up into 8 sectors:

          \ | /
           \|/
          --+--
           /|\
          / | \

   We want 16 stars on screen at all times.

   At any time, each sector must have 2 stars active in it.

   To provide variety, we will have 4 tracks through each sector, and
   cycle them as each star finishes its journey.

 */

int star_x1[32] = {
  0, 0, 0, 0,
  25, 125, 225, 325,
  425, 525, 625, 725,
  1000, 1000, 1000, 1000,
  0, 0, 0, 0,
  25, 125, 225, 325,
  425, 525, 625, 725,
  1000, 1000, 1000, 1000,
};

int star_y1[32] = {
  25, 125, 225, 325,
  0,0,0,0,
  0,0,0,0,
  35, 135, 235, 335,
  425,525,62,725,
  800,800,800,800,
  800,800,800,800,
  425,525,62,725,
};

int clipoff(int x, int y)
{
  return ((0x1b0 < x && x <= 0x250) && (0x140 <= y && y <= 0x1c0));
}

/**************************************************************************
 *  line_fast                                                             *
 *    draws a line using Bresenham's line-drawing algorithm, which uses   *
 *    no multiplication or division.                                      *
 **************************************************************************/

#define sgn(x) ((x<0)?-1:((x>0)?1:0)) /* macro to return the sign of a number */

void plot_star(int starno)
{
  static int i[16],dx[16],dy[16],x[16],y[16],px[16],py[16],dxabs[16],dyabs[16],sdx[16],sdy[16];
  static int state[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  static int flip[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  static int maxspeed[16], ticks[16];
  int speed, done=(0!=0);
  int x1 = star_x1[(starno<<1)+flip[starno]], y1 = star_y1[(starno<<1)+flip[starno]],
      x2 = 0x200, y2 = 0x180;

  if (state[starno] == 0) { /* initialise */
    dx[starno]=x2-x1;      /* the horizontal distance of the line */
    dy[starno]=y2-y1;      /* the vertical distance of the line */
    dxabs[starno]=abs(dx[starno]);
    dyabs[starno]=abs(dy[starno]);
    sdx[starno]=sgn(dx[starno]);
    sdy[starno]=sgn(dy[starno]);
    x[starno]=dyabs[starno]>>1;
    y[starno]=dxabs[starno]>>1;
    px[starno]=x1;
    py[starno]=y1;
    state[starno] = 1; maxspeed[starno] = 9 /* critical, depends on vector length */;
    ticks[starno] = 0;
    /* and draw first pixel */
    starplot(px[starno],py[starno]);
    i[starno] = 0; /* initialise 'loop' counter */
    return;
  }

  if (dxabs[starno]>=dyabs[starno]) { /* the line is more horizontal than vertical */
    for (speed = 0; speed < maxspeed[starno]; speed++) {
      y[starno]+=dyabs[starno];
      if (y[starno]>=dxabs[starno])
      {
        y[starno]-=dxabs[starno];
        py[starno]+=sdy[starno];
      }
      px[starno]+=sdx[starno];
      i[starno] += 1;
      if (done = (i[starno] >= dxabs[starno])) {
        break;
      }
    }
  } else {  /* the line is more vertical than horizontal */
    for (speed = 0; speed < maxspeed[starno]; speed++) {
      x[starno]+=dxabs[starno];
      if (x[starno]>=dyabs[starno])
      {
        x[starno]-=dyabs[starno];
        px[starno]+=sdx[starno];
      }
      py[starno]+=sdy[starno];
      i[starno] += 1;
      if (done = (i[starno] >= dyabs[starno])) {
        break;
      }
    }
  }
  if (done) {
    state[starno] = 0; /* Done! */
    flip[starno] = 1-flip[starno];
  }
  ticks[starno] += 1;
  if (ticks[starno] == 12) {
    ticks[starno] = 0;
    maxspeed[starno] -= 1;
  }
  if (maxspeed[starno] <= 0) maxspeed[starno] = 1;
  if (clipoff(px[starno], py[starno])) {
    state[starno] = 0;
    flip[starno] = 1-flip[starno];
  } else {
    starplot(px[starno],py[starno]);
    /* for moving stars we just do one of these each time increment */
    /* this is in effect a very slow line draw */
  }
}

void stars(int speed)
{
  static int started = 0;
  int star;
  if (started == 0) {
    int laststar;
    for (laststar = 1; laststar <= 16; laststar++) { /* skew */
      int i;
      for (i = 0; i < 20; i++) { /* gap between skew */
        for (star = 0; star < laststar; star++) plot_star(star);
      }
    }
    started = 1;
  } else {
    int i;
    for (i = 0; i < speed; i++) {
      for (star = 0; star < 16; star++) plot_star(star);
    }
  }
}

static int firex[2];
static int firey[2];

/* MISTAKE HERE - we need a line drawing algorithm which increments in one
   Y unit each call, *NOT* one X unit. */

/* returns true if drawn to end of vector, false if should call again */
int plot_fire(int lr, int x1, int y1, int x2, int y2)
{
  int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
  dx=x2-x1;      /* the horizontal distance of the line */
  dy=y2-y1;      /* the vertical distance of the line */
  dxabs=abs(dx);
  dyabs=abs(dy);
  sdx=sgn(dx);
  sdy=sgn(dy);
  x=dyabs>>1;
  y=dxabs>>1;
  px=x1;
  py=y1;

  CinemaVectorData(px, py, px+1, py+1, 15);

  if (dxabs>=dyabs) /* the line is more horizontal than vertical */
  {
    for(i=0;i<dxabs;i++)
    {
      y+=dyabs;
      if (y>=dxabs)
      {
        y-=dxabs;
        py+=sdy;
      }
      px+=sdx;
      if (i <= 25) {
        CinemaVectorData(px, py, px+1, py+1, 15);
        firex[lr] = px; firey[lr] = py;
      }
      if (i == 50) {firex[lr] = px; firey[lr] = py;}  /* draw next line 100 pixels in from this one */
    }
  }
  else /* the line is more vertical than horizontal */
  {
    for(i=0;i<dyabs;i++)
    {
      x+=dxabs;
      if (x>=dyabs)
      {
        x-=dyabs;
        px+=sdx;
      }
      py+=sdy;
      if (i <= 25) {
        CinemaVectorData(px, py, px+1, py+1, 15);
        firex[lr] = px; firey[lr] = py;
      }
      if (i == 50) {firex[lr] = px; firey[lr] = py;}
    }
  }
  return(i <= 30);
}

static unsigned char crosshair[40] = {
 0x63, 0x80, 0x9e, 0x80,
 0x94, 0x76, 0x94, 0x8a,
 0x8a, 0x94, 0x76, 0x94,
 0x80, 0x9e, 0x80, 0x62,
 0x8a, 0x6c, 0x76, 0x6c,
 0x6c, 0x76, 0x6c, 0x8a,
 0x7b, 0x8a, 0x85, 0x8a,
 0x8a, 0x85, 0x8a, 0x7b,
 0x85, 0x76, 0x7b, 0x76,
 0x76, 0x7b, 0x76, 0x85,
};

static unsigned char shieldvec[26] = {
 0xc0, 0xa0,
 0xe0, 0x80,
 0x80, 0x20,
 0x20, 0x80,
 0x40, 0xa0,
 0x80, 0x60,
 0xc0, 0x20,
 0xe0, 0x40,
 0x80, 0xa0,
 0x20, 0x40,
 0x40, 0x20,
 0x80, 0x60,
 0xc0, 0xa0,
};

void draw_shields(void)
{
  int i;
  for (i = 0; i < 12; i++) {
    CinemaVectorData((shieldvec[i*2]<<2) - 0x30, shieldvec[i*2+1]<<2,
                     (shieldvec[i*2+2]<<2) - 0x30, shieldvec[i*2+3]<<2,
                     curcol);
  }
}

void draw_crosshair(int x, int y)
{
  int i;
  for (i = 0; i < 10; i++) {
    CinemaVectorData(x + (crosshair[i*4]) - 0x40,   y + crosshair[i*4+1] - 0x80,
                     x + (crosshair[i*4+2]) - 0x40, y + crosshair[i*4+3] - 0x80,
                     curcol);
  }
}

#define PREGAME 1
#define COINED 2
#define PLAYING 3

static int state = PREGAME;

static int credits = '0';
static int passed = '0';
static char shields[3] = { '8', '0', '\0'};

int main(int argc, char **argv) {
int i;
int start = 0;
int shieldtick = 0;
int firing = (0!=0);
int reloaded = (0==0);
int firedone1, firedone2;

  initchars();

  init_graph();

  CinemaClearScreen(); /* Initialise ioInputs etc before game starts */
  /* CinemaVectorData(50,50, 300,300, 7); */

  for (;;) {
    switch (state) {

    case PREGAME:

      /*vecmoveto(0x190, 210); for (i = '0'; i <= '9'; i++) printchar(i);
      vecmoveto(200, 270); for (i = 'A'; i <= 'Z'; i++) printchar(i);*/

      vecmoveto(0x96, 0x28a); printstring("SCORE");
      vecmoveto(0xb8, 0x258); printstring(" 00");

      vecmoveto(0x2bc, 0x28a); printstring("HIGH[SCORE");
      vecmoveto(0x2f8, 0x258); printstring(" 00");

      /* Display 'tailgunner' rectangle.
         Rotate it one increment.
         If it is facing away, discard the text, just keep the rectangles
       */

      /* do a cycle of : */

      vecmoveto(0x180, 0x100);  /* This will also need to be changed when applying scaling */
      print_rectangles();       /* needs rotation applied */
      print_tg();               /* identical matrix needed */

      /* when rectangle at maximum size, stop it and flash intensity */

      /* followed by a cycle of: move and show ships (quit when all 3 pass the screen) */

      /* move existing stars in by a time unit, remove old stars that
         hit internal rectangle, replace with new stars on outer border.
         This is independent of game state */

      stars(1);

      break;

    case COINED:

      /*vecmoveto(0x190, 210); for (i = '0'; i <= '9'; i++) printchar(i);
      vecmoveto(200, 270); for (i = 'A'; i <= 'Z'; i++) printchar(i);*/

      vecmoveto(0x96, 0x28a); printstring("SCORE");
      vecmoveto(0xb8, 0x258); printstring(" 00");

      vecmoveto(0x2bc, 0x28a); printstring("HIGH SCORE");
      vecmoveto(0x2f8, 0x258); printstring(" 00");

      start = (start + 1) & 31;
      veccol(start >= 16 ? 15 : 7);
      vecmoveto(0x190, 0x190);
      printstring("PUSH START");
      veccol(15);

      vecmoveto(0x190, 0x32); printstring("CREDITS");
      vecmoveto(0x258, 0x32); printstring("  "); printchar(credits > '9' ? '9' : credits);

      /* move existing stars in by a time unit, remove old stars that
         hit internal rectangle, replace with new stars on outer border.
         This is independent of game state */

      stars(1);


      break;

    case PLAYING:
      vecmoveto(0xb8, 0x258); printstring(" 00"); /* score */
      vecmoveto(0x2f8+0x18, 0x258); printchar(passed); /* ships passed */
      vecmoveto(0x1cc, 0x28a); printstring(shields);  /* shields value */

      /* PLAY ONE FRAME OF GAME HERE */

      /* move existing stars in by a time unit, remove old stars that
         hit internal rectangle, replace with new stars on outer border.
         This is independent of game state */

      {
        static int passing = 0;
        passing = passing + 1;
        if (passing >= 500) {
          if (passing == 500) {
            passed += 3;
            if (passed > '9') {
              passed = '0'; credits -= 1;
              if (credits == '0') state = PREGAME; else state = COINED;
              firing = (0!=0);
            }
          }
          stars(2);
        } else stars(1);
        if (passing == 540) passing = 0;
      }
      /* move and show ships */

      vecmoveto((mouse_x*5)/4+0x30, 640-((mouse_y*10)/8)); draw_crosshair(curx, cury);

      if (mouse_b & 1) {
        if (!firing && reloaded) {
          /* initiate fire */;
          firing = (0==0); reloaded = (0!=0);
          firedone1 = plot_fire(0, 40,40, (mouse_x*5)/4+0x70, 640-((mouse_y*10)/8));
          firedone2 = plot_fire(1, 1000,40, (mouse_x*5)/4+0x70, 640-((mouse_y*10)/8));
        } else {
          if (!firedone1) {
            firedone1 = plot_fire(0, firex[0], firey[0],
                                  (mouse_x*5)/4+0x70, 640-((mouse_y*10)/8));
          }
          if (!firedone2) {
            firedone2 = plot_fire(1, firex[1], firey[1],
                                  (mouse_x*5)/4+0x70, 640-((mouse_y*10)/8));
          }
          firing = (!firedone1 || !firedone2);
        }
      } else {
        if (firing) { /* Finish off the last shot */
          if (!firedone1) {
            firedone1 = plot_fire(0, firex[0], firey[0],
                                  (mouse_x*5)/4+0x70, 640-((mouse_y*10)/8));
          }
          if (!firedone2) {
            firedone2 = plot_fire(1, firex[1], firey[1],
                                  (mouse_x*5)/4+0x70, 640-((mouse_y*10)/8));
          }
          firing = !(firedone1 && firedone2);
        } else reloaded = (0==0);
      }

      /* we might need a debouncing algorithm here to match the bahaviour of the real game */
      if ((mouse_b & 2) && (shields[0] != '0' || shields[1] != '0')) {
        draw_shields();
        if (shieldtick == 0) {
          shields[1] -= 1;
          if (shields[1] < '0') {
            shields[1] = '9'; shields[0] -= 1;
            if (shields[0] < '0') {
              shields[0] = shields[1] = '0';
            }
          }
          shieldtick = 8;
        } else shieldtick -= 1;
      } else shieldtick = 0;

      break;
    }

    CinemaClearScreen();
    if (keypressed()) {
      int k = readkey() & 0x7f;
	if (k == 27) {
        end_graph();
        exit(0);
      } else if (k == '3') {
        state = COINED; credits += 1;
      } else if (k == '1') {
        if (state == COINED) state = PLAYING;
      } else if (k == ' ') {
        if (state == PLAYING) {
          credits -= 1;
          if (credits == '0') state = PREGAME; else state = COINED;
        } 
      }
    }
  }

  exit(0);
  return(0);
}

