
int TargetFPS, ObservedFPS;
int millis_time;
unsigned char vectrex_beam_intensity;
unsigned char Pressed_Key;
int mouse_x, mouse_y;
unsigned char mouse_fire, mouse_shields;
int ScreenWidth, ScreenHeight;
int intro_x;
int intro_y;
void playTailgunner(void);

void graphics_initialisation(void)
{

  ScreenHeight = 800;
  ScreenWidth = 1024;
}

void Main_loop(void) {
  for (;;) {
    playTailgunner();

    millis_time += 1000/TargetFPS;
  }
}

void Display_Vectrex_vector(void)
{
  int from_x; int from_y; int to_x; int to_y;

}

void Display_Vectrex_point(void)
{
  int x; int y;
}

void startAsyncSound(void)
{
  unsigned char which;

}

int mouseX(void)
{
  return 0;
}

int mouseY(void)
{
  return 0;
}

int millis(void)
{






  return millis_time;
}

int rseed;
int urandom16(void)
{
  return (rseed = (rseed * 2053) + 13849);
}







unsigned char SCORE_STR96[] = {0};
unsigned char HIGH_SCORE_STR96[] = {0};
unsigned char CREDITS_STR128[] = {0};
unsigned char INSERT_COIN_STR128[] = {0};
unsigned char PRESS_START_STR128[] = {0};
int sine[] = {0};







int asintab[] = {0};

unsigned char tg_intro_placard[] = {0};

unsigned char font_points[] = {0};

unsigned char font_length[] = {0};

unsigned char font_index[] = {0};

unsigned char crosshair[40] = {0};

unsigned char shieldvec[26] = {0};

unsigned char ShipMeshPointers[] = {0};

char ShipMesh[] = {0};

unsigned char pen;
void putPenDown(void)
{
  pen = 1;
}

void putPenUp(void)
{
  pen = 0;
}

int last_x, last_y;
void gotoxy(void)
{
  int x; int y;



  if (pen == 1) Display_Vectrex_vector(last_x, last_y, x, y);
  last_x = x; last_y = y;
}

unsigned int irand(void)
{
  int max;
  return urandom16() % max;
}

int pickrandom(void)
{
  int low; int high;
  return (int)irand(high-low+1)+low;
}

void setintensity(void)
{
  unsigned char brightness;
  vectrex_beam_intensity = brightness&127;
}
unsigned int isqrt(void)
{
  unsigned int op;
  unsigned int res = 0;
  unsigned int one = 1<<14;
  unsigned int limit;


  while (one > op) one >>= 2;

  while (one != 0) {
    if (op >= (limit = res + one)) {
      op -= limit;
      res += one;
      res += one;
    }
    res >>= 1;
    one >>= 2;
  }
  return res;
}
int asin_of_fp2_14(void)
{
  int angle;
  if (angle > 128) return -(asintab[256-angle]>>6);
  return asintab[angle]>>6;
}
int s16_nabs(void)
{
  int j;
  return (j < 0 ? j : -j);
}




unsigned int muldiv(void)
{
  unsigned int a; unsigned int b; unsigned int c;


  unsigned int q = 0, r = 0, qn, rn;


  if (a < b) {
    qn = b / c;
    rn = b % c;
    while (a) {
      if (a&1) { q += qn; r += rn; if (r >= c) { q++; r -= c; } }
      a >>= 1; qn <<= 1; rn <<= 1; if (rn >= c) { qn++; rn -= c; }
    }
  } else {

    qn = a / c;
    rn = a % c;
    while (b) {
      if (b&1) { q += qn; r += rn; if (r >= c) { q++; r -= c; } }
      b >>= 1; qn <<= 1; rn <<= 1; if (rn >= c) { qn++; rn -= c; }
    }
  }
 return q;
}

int q15_mul(void)
{
  int j; int k;

  if (j<0 && k<0) return (int)muldiv(-j,-k,1<<15);
  if (j<0) return -(int)muldiv(-j,k,1<<15);
  if (k<0) return -(int)muldiv(j,-k,1<<15);
  return (int)muldiv(j, k, 1<<15);
}

int q15_div(void)
{
  int numer; int denom;

  if (numer<0 && denom<0) return (int)muldiv(-numer, 1<<15, -denom);
  if (numer<0) return -(int)muldiv(-numer, 1<<15, denom);
  if (denom<0) return -(int)muldiv(numer, 1<<15, -denom);
  return (int)muldiv(numer, 1<<15, denom);
}
unsigned int fxpt_atan2(void)
{
  int y; int x;
  if (x == y) {
    if (y > 0) {
      return 8192;
    } else if (y < 0) {
      return 40960;
    } else {
      return 0;
    }
  }
  int nabs_y = s16_nabs(y), nabs_x = s16_nabs(x);
  if (nabs_x < nabs_y) {
    int y_over_x = q15_div(y, x);
    int correction = q15_mul( 2847, s16_nabs(y_over_x));
    int unrotated = q15_mul( 11039 + correction, y_over_x);
    if (x > 0) {
      return unrotated;
    } else {
      return 32768 + unrotated;
    }
  } else {
    int x_over_y = q15_div(x, y);
    int correction = q15_mul( 2847, s16_nabs(x_over_y));
    int unrotated = q15_mul( 11039 + correction, x_over_y);
    if (y > 0) {
      return 16384 - unrotated;
    } else {
      return 49152 - unrotated;
    }
  }
}


int Scratch_atan2_fakedegrees(void)
{
  int x; int y;
  int result = ((fxpt_atan2(x, y)>>8)-128);

  if (result <= -64) {
    return result + 128;
  } else if (result >= 64) {
    return result - 128;
  }
  return result;

}


unsigned char numdigits(void)
{
  int num;
  unsigned char result = 0;
  do {
    num = num / 10;
    result++;
  } while (num > 0);
  return result;
}
unsigned char Credits;

int intro_z;
unsigned char intro_rot;

int passing_mode_timer;

int flashing_intro_timer;
unsigned char global_flashing_intensity;
unsigned char flashingtexttimer;

int hide_intro_timer;


int Mode;



int mouseDownPrev;

unsigned char laserid;
int lasert;
int lastfiringtime;

int HighScore;
int LastScore;
int Score;

int UsingShields;
int Shields;
int shieldsegment;
int shieldsubticksleft;

int ShipsPassedThisWave;
int ShipsPassedTotal;

int cosX;
int cosY;
int cosZ;
int sinX;
int sinY;
int sinZ;

int stopintroflag;




int textx;
int texty;
int textz;

int tgi;
int tgx;
int tgy;
int tgz;

unsigned char nextwaveshiptype;





unsigned char this_status;
int this_scale_fp;


int this_ship_time;
unsigned char this_model;
int this_X;
int this_Y;
int this_Z;

int this_vel;

int this_X_destination;
int this_Y_destination;
int this_Z_destination;

int this_X_rotation;
int this_Y_rotation;
int this_Z_rotation;




int transformed_X;
int transformed_Y;
int transformed_Z;
int XY;
int XZ;
int YX;
int dirXZ;
int dirY;

int ships[3 * 14];





int sinsymmetry(void)
{
  unsigned char angle128;
  if (angle128 > 64) return sine[128-angle128]; else return sine[angle128];
}

int fp2_14_sin(void)
{
  int angle256;
  if ((unsigned char)angle256 >= 128) return -sinsymmetry((unsigned char)(angle256-128)&127); else return sinsymmetry((unsigned char)angle256&127);
}

int fp2_14_cos(void)
{
  int angle256;
  return fp2_14_sin(angle256+64);
}

int mul_short_by_fp2_14_returning_short(void)
{
  int num; int fp;
  int sign = 1;
  if (num < 0) { num = -num; sign = -sign; }
  if (fp < 0) { fp = -fp; sign = -sign; }
  return sign * muldiv(num, fp, ((int)(1<<14)));
}

int div_int_by_int_returning_fp2_14(void)
{
  int num; int den;
  int sign = 1;
  if (num < 0) { num = -num; sign = -sign; }
  if (den < 0) { den = -den; sign = -sign; }
  return sign * muldiv(num, ((int)(1<<14)), den);
}
void draw_tg_intro_with_rolling_rotation(void)
{
  int from_x; int from_y; int to_x; int to_y; unsigned char rot;
  if ((from_x != to_x) || (from_y != to_y)) {
    int PackX, PackY, PackZ;
    int screenx;
    int screeny;

    tgx = from_x; tgy = from_y; tgz = 0;

    PackX = to_x; PackY = to_y; PackZ = 0;
    PackZ += mul_short_by_fp2_14_returning_short(PackY, fp2_14_sin (rot));
    PackY = mul_short_by_fp2_14_returning_short(PackY, fp2_14_cos (rot));

    PackZ += intro_z;

    screenx = ((1024 * PackX) / (1024 + PackZ));
    screeny = ((1024 * PackY) / (1024 + PackZ));
    gotoxy (intro_x + screenx, intro_y + screeny);

    tgz += mul_short_by_fp2_14_returning_short(tgy, fp2_14_sin (rot));
    tgy = mul_short_by_fp2_14_returning_short(tgy, fp2_14_cos (rot));

    tgz += intro_z;

    screenx = ((1024 * tgx) / (1024 + tgz));
    screeny = ((1024 * tgy) / (1024 + tgz));


    putPenDown (); gotoxy (intro_x + screenx, intro_y + screeny); putPenUp ();
  }
}



void starplot(void)
{
  int x; int y;



  Display_Vectrex_point((ScreenWidth>>1)+x, (ScreenHeight>>1)+y);
}


unsigned char clipoff(void)
{
  int x; int y;

  return ( -50 <= x && x < 50 && -40 <= y && y < 40);
}

int px[16];
int py[16];

unsigned int star_x1(void)
{
  unsigned char idx;
  unsigned char xtype = (idx>>2)&3, ytype = idx&3;

  idx = xtype ^ ytype;
  if (idx == 0) {
    return -(ScreenWidth>>1);
  } else if (idx == 2) {
    return (ScreenWidth>>1)-1;
  } else {
    return pickrandom(-(ScreenWidth>>1), (ScreenWidth>>1)-1);
  }
}

unsigned int star_y1(void)
{
  unsigned char idx;
  unsigned char xtype = (idx>>2)&3, ytype = idx&3;

  idx = xtype ^ ytype;
  if (idx == 1) {
    return (ScreenHeight>>1)-1;
  } else if (idx == 3) {
    return -(ScreenHeight>>1);
  } else {
    return pickrandom(-(ScreenHeight>>1), (ScreenHeight>>1)-1);
  }
}
void move_star(void)
{
  unsigned char starno;
  int x = px[starno], y=py[starno];


  x = ((x<<6)-x)>>6; y = ((y<<6)-y)>>6;
  if (clipoff(x,y)) {
    x = star_x1(starno); y = star_y1(starno);
  }
  px[starno] = x; py[starno] = y;

}

void plot_star(void)
{
  unsigned int starno;
  starplot(px[starno],py[starno]);
}

void init_stars(void)
{
  unsigned char i, star;

  for (star = 0; star < 16; star++) {
    px[star] = star_x1(star); py[star] = star_y1(star);
    for (i=0; i < star*13; i++) move_star(star);
  }
}

void stars(void)
{
  unsigned char speed;
  unsigned char i, star;
  for (star = 0; star < 16; star++) {
    for (i = 0; i < speed; i++) move_star(star);
    plot_star(star);
  }
}
int firex[2];
int firey[2];

int abs(void)
{
  int x;
  return (((x)>=0)?(x):-(x));
}

int sgn(void)
{
  int x;
  return ((x<0)?-1:((x>0)?1:0));
}

unsigned char plot_fire(void)
{
  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;
  dy=y2-y1;
  dxabs=abs(dx);
  dyabs=abs(dy);
  sdx=sgn(dx);
  sdy=sgn(dy);
  x=dyabs>>1;
  y=dxabs>>1;
  px=x1;
  py=y1;
  Display_Vectrex_point(px, py);

  if (dxabs>=dyabs)
  {
    for(i=0;i<dxabs;i++)
    {
      y+=dyabs;
      if (y>=dxabs)
      {
        y-=dxabs;
        py+=sdy;
      }
      px+=sdx;
      if (i <= 25) {
        Display_Vectrex_point(px, py);
        firex[lr] = px; firey[lr] = py;
      }
      if (i == 50) {firex[lr] = px; firey[lr] = py;}
    }
  }
  else
  {
    for(i=0;i<dyabs;i++)
    {
      x+=dxabs;
      if (x>=dyabs)
      {
        x-=dyabs;
        px+=sdx;
      }
      py+=sdy;
      if (i <= 25) {
        Display_Vectrex_point(px, py);
        firex[lr] = px; firey[lr] = py;
      }
      if (i == 50) {firex[lr] = px; firey[lr] = py;}
    }
  }
  return(i <= 30);
}




void draw_shields(void)
{

  unsigned char i;
  if (pickrandom (0, 3) > 0) {

    setintensity((unsigned char)pickrandom (80, 127));
    for (i = 0; i < 12; i++) {

      Display_Vectrex_vector(((shieldvec[i*2]*ScreenWidth)/8),
                             (shieldvec[i*2+1]*ScreenHeight)/8,
                             ((shieldvec[i*2+2]*ScreenWidth)/8),
                             (shieldvec[i*2+3]*ScreenHeight)/8
                            );
    }
    setintensity(110);
  }
}

void draw_crosshair(void)
{
  int x; int y;
  unsigned char i;
  for (i = 0; i < 10; i++) {

    Display_Vectrex_vector(x + (crosshair[i*4]) - 80, y + crosshair[i*4+1] - 80,
                           x + (crosshair[i*4+2]) - 80, y + crosshair[i*4+3] - 80);
  }
}

void drawtgintro(void) {
  unsigned char objects;

  if (stopintroflag == 2) return;

  if (fp2_14_cos (intro_rot) > 0) {
    objects = ((sizeof (tg_intro_placard) / sizeof (tg_intro_placard[0])) / 4);
  } else {
    objects = 8;
  }

  {unsigned char i; int tgfrom_x, tgfrom_y, tgto_x, tgto_y;
    tgi = 0;
    for (i = 0; i < objects; i++) {
      tgfrom_x = tg_intro_placard[tgi++]-128;
      tgfrom_y = tg_intro_placard[tgi++]-128;
      tgto_x = tg_intro_placard[tgi++]-128;
      tgto_y = tg_intro_placard[tgi++]-128;

      draw_tg_intro_with_rolling_rotation (tgfrom_y, tgfrom_x, tgto_y, tgto_x, intro_rot);
    }
  }

  setintensity(110);
}

void Playintro(void)
{
  intro_z = 206; intro_rot = 64;
  flashing_intro_timer = 0; hide_intro_timer = 0;
  stopintroflag = 0;
}

void initialise_ship(void)
{
  unsigned char id; unsigned char model_type; int x; int y; int z; int Xrot; int Yrot; int Zrot; int scale_fp;
  unsigned char ship_next = id * 14;


  ships[ship_next++] = model_type;
  ships[ship_next++] = x;
  ships[ship_next++] = y;
  ships[ship_next++] = z;
  ships[ship_next++] = Xrot;
  ships[ship_next++] = Yrot;
  ships[ship_next++] = Zrot;
  ships[ship_next++] = scale_fp;
  ships[ship_next++] = ((20 * pickrandom (80, 120)) / 100);
  ships[ship_next++] = 0;
  ships[ship_next++] = pickrandom (-400, 400);
  ships[ship_next++] = pickrandom (-300, 300);
  ships[ship_next++] = z;



  ships[ship_next++] = 0;
}

void debug_ship(void)
{
  unsigned char id;
  int model_type, x, y, z, Xrot, Yrot, Zrot, scale_fp, speed, shiptime, tgx, tgy, tgz, status;
  int ship_next = id * 14;


  model_type = ships[ship_next++];
  x = ships[ship_next++];
  y = ships[ship_next++];
  z = ships[ship_next++];
  Xrot = ships[ship_next++];
  Yrot = ships[ship_next++];
  Zrot = ships[ship_next++];
  scale_fp = ships[ship_next++];
  speed = ships[ship_next++];
  shiptime = ships[ship_next++];
  tgx = ships[ship_next++];
  tgy = ships[ship_next++];
  tgz = ships[ship_next++];
  status = ships[ship_next++];


}

void Start_attack_wave(void)
{
  int randomedge, X, Y, Z = 2000, Zrot, scale_fp = div_int_by_int_returning_fp2_14(1999, 5000);

  unsigned char i;

  for (i = 0; i < 3; i++) {
    randomedge = pickrandom (1, 3);
    if (randomedge == 1) {
      X = -900; Y = pickrandom (-500, 500); Zrot = 64;
    } else if (randomedge == 2) {
      X = pickrandom (-500, 500); Y = 700; Zrot = 0;
    } else {
      X = 900; Y = pickrandom (-500, 500); Zrot = 128+64;
    }
    initialise_ship (i, nextwaveshiptype, X, Y, Z, 128+64 , 128 , Zrot, scale_fp);
  }



  nextwaveshiptype = (nextwaveshiptype + 1)&3;

  ShipsPassedThisWave = 0;
}

void Start_new_game (void)
{
  stopintroflag = 2;
  Score = 0;

  Shields = 80;
  ShipsPassedTotal = 0;

  nextwaveshiptype = 0;


  Start_attack_wave ();



  lastfiringtime = millis();
}

void draw_text_line(void)
{
  int fromx; int fromy; int tox; int toy;
  Display_Vectrex_vector(fromx + textx + ScreenWidth/2, fromy + texty + ScreenHeight/2, tox + textx + ScreenWidth/2, toy + texty + ScreenHeight/2);

}

void segment(void)
{
  unsigned char coords; int textscale;
  int fromx;
  int fromy;
  int tox;
  int toy;
  int from, to;


  to = coords & 15;
  tox = ((to % 5) * 4 * textscale) / 128;
  toy = ((to / 5) * 12 * textscale) / 128;

  from = coords >> 4;
  fromx = ((from % 5) * 4 * textscale) / 128;
  fromy = ((from / 5) * 12 * textscale) / 128;

  draw_text_line (fromx, fromy, tox, toy);
}

void ch(void)
{
  unsigned char charno; int textscale;
  if (charno ) {
    {unsigned char i;


      for (i = font_index[charno-1]; i < font_index[charno-1]+font_length[charno-1]; i++) {
        segment(font_points[i], textscale);
      }
    }
  }
  textx += (24 * textscale) / 128;
}


void ch96(void)
{
  unsigned char charno;
  ch(charno, 96);
}

void ch96str(void)
{
  unsigned char *text;
  unsigned char i;
  for (i = 1; i <= text[0]; i++) ch96(text[i]);
}

void ch128(void)
{
  unsigned char charno;
  ch(charno, 128);
}

void ch128str(void)
{
  unsigned char *text;
  unsigned char i;
  for (i = 1; i <= text[0]; i++) ch128(text[i]);
}

void Drawnum(void)
{
  int num; unsigned char size;
  unsigned char i;
  int tens = 10000;

  i = 4;
  for (;;) {
    if ((num >= tens) || (i == 0)) {

      ch((unsigned char)(1+(num/tens)%10), size);
    }
    tens /= 10;
    if (i == 0) return;
    i -= 1;
  }
}



void Drawsmallnum(void)
{
  int num;
  Drawnum(num, 96);
}

void Drawbignum(void)
{
  int num;
  Drawnum(num, 128);
}

void Drawbignumat(void)
{
  int num; int x; int y;
  textx = x; texty = y;
  Drawbignum(num);
}

void Drawsmallnumat(void)
{
  int num; int x; int y;
  textx = x; texty = y;
  Drawsmallnum(num);
}

void Draw_shields_left(void)
{
  Drawbignumat (Shields, -10, 140);
}

void Draw_score(void)
{
  Drawbignumat (Score, -220, 130);
}

void Draw_highscore(void)
{
  textx = 42;
  texty = 130;

  ch96str(HIGH_SCORE_STR96);

  Drawsmallnumat (HighScore, ( 204 - ((24 * 96 * (numdigits (HighScore)-1)) / 128)), 105);
}

void InsertCoin(void)
{
  textx = -135;
  texty = -120;
  setintensity(global_flashing_intensity);
  ch128str(INSERT_COIN_STR128);
  setintensity(110);
}

void Draw_ShipsPassedTotal(void) {
  Drawbignumat (ShipsPassedTotal, 200, 130);
}

void Press_start(void)
{
  textx = -120;
  texty = -10;
  setintensity(global_flashing_intensity);
  ch128str(PRESS_START_STR128);
  setintensity(110);
}

void Draw_credits(void)
{
  textx = -100;
  texty = -120;
  ch128str(CREDITS_STR128);
  if (Credits > 9) {
    ch128 (10);
  } else {
    ch128 (Credits + 1);
  }
}

void Draw_last_game_score(void)
{
  textx = -220;
  texty = 130;
  ch96str(SCORE_STR96);
  Drawsmallnumat (LastScore, -220, 105);
}

void Shield(void)
{
  if (shieldsubticksleft == 0) {
    startAsyncSound(4);


    shieldsubticksleft = div_int_by_int_returning_fp2_14(10, 3);
    Shields -= 1;
  } else {
    shieldsubticksleft -= 1;
  }
  draw_shields();
}

void Get_ship_pos(void)
{
  unsigned char id;


  this_X = ships[((id * 14) + 1)];
  this_Y = ships[((id * 14) + 2)];
  this_Z = ships[((id * 14) + 3)];
}

void Get_ship_scale(void)
{
  unsigned char id;
  this_scale_fp = ships[((id * 14) + 7)];
}

void Get_ship_status(void)
{
  unsigned char id;
  this_status = (unsigned char)ships[((id * 14) + 13)];
}

int screen_x;
int screen_y;



void Get_screenpos(void)
{
  int x; int y; int z;
  screen_x = (1024 * x) / z; screen_y = (1024 * y) / z;






}

void Set_ship_status(void)
{
  unsigned char id; unsigned char NewStatus;
  ships[((id * 14) + 13)] = NewStatus;
}

void ship_hit_check(void)
{
  int x; int y;
  unsigned char this_ = 0;
  for (this_ = 0; this_ < 3; this_++) {
    Get_ship_status (this_);
    if (this_status == 0) {

      Get_ship_pos (this_);
      Get_ship_scale (this_);
      Get_screenpos (this_X, this_Y, this_Z);
      if (
           (unsigned int)(isqrt ((((x - screen_x) * (x - screen_x)) + ((y - screen_y) * (y - screen_y))))
          <
           (unsigned int)(mul_short_by_fp2_14_returning_short(15 * (1024 / this_Z), this_scale_fp) ))
         ) {






        Score += 5;
        startAsyncSound(2);
        Set_ship_status (this_, 1);
      }
    }
    this_ += 1;
  }
}

void Transform_point(void)
{
  int x; int y; int z;
  XY = (mul_short_by_fp2_14_returning_short(y, cosX) - mul_short_by_fp2_14_returning_short(z, sinX));
  XZ = (mul_short_by_fp2_14_returning_short(y, sinX) + mul_short_by_fp2_14_returning_short(z, cosX));
  transformed_Z = (mul_short_by_fp2_14_returning_short(XZ, cosY) - mul_short_by_fp2_14_returning_short(x, sinY));
  YX = (mul_short_by_fp2_14_returning_short(XZ, sinY) + mul_short_by_fp2_14_returning_short(x, cosY));
  transformed_X = (mul_short_by_fp2_14_returning_short(YX, cosZ) - mul_short_by_fp2_14_returning_short(XY, sinZ));
  transformed_Y = (mul_short_by_fp2_14_returning_short(YX, sinZ) + mul_short_by_fp2_14_returning_short(XY, cosZ));
}

void Change_ship_pos_by(void)
{
  unsigned char id; int dx; int dy; int dz;
  ships[((id * 14) + 1)] += dx;
  ships[((id * 14) + 2)] += dy;
  ships[((id * 14) + 3)] += dz;
}

void Change_ship_rotation_by(void)
{
  unsigned char id; int this_X_rotation; int this_Y_rotation; int this_Z_rotation;
  ships[((id * 14) + 4)] += this_X_rotation;
  ships[((id * 14) + 5)] += this_Y_rotation;
  ships[((id * 14) + 6)] += this_Z_rotation;
}

void Get_ship_rotation(void)
{
  unsigned char id;
  this_X_rotation = ships[((id * 14) + 4)];
  this_Y_rotation = ships[((id * 14) + 5)];
  this_Z_rotation = ships[((id * 14) + 6)];
}

void Get_ship_time(void)
{
  unsigned char id;
  this_ship_time = ships[((id * 14) + 9)];
}

void Get_ship_destination(void)
{
  unsigned char id;

               this_X_destination = ships[((id * 14) + 10)];
               this_Y_destination = ships[((id * 14) + 11)];
               this_Z_destination = ships[((id * 14) + 12)];
}

void Change_ship_velocity_by(void)
{
  unsigned char id; int accel;

  int this_speed = (id * 14) + 8;




  if (ships[this_speed] > 20) ships[this_speed] = 20;
}

void Set_rotation_vars(void)
{
  int Xrot; int Yrot; int Zrot;
  sinX = fp2_14_sin (Xrot);
  cosX = fp2_14_cos (Xrot);
  sinY = fp2_14_sin (Yrot);
  cosY = fp2_14_cos (Yrot);
  sinZ = fp2_14_sin (Zrot);
  cosZ = fp2_14_cos (Zrot);
}






void Draw_ship_at_rotated_scale(void)
{
  unsigned char model; int x; int y; int z; int Xrot; int Yrot; int Zrot; int scale_fp;
  unsigned char meshIndex;

  setintensity(85);



  Set_rotation_vars (Xrot, Yrot, Zrot);
  for (meshIndex = ShipMeshPointers[model]; meshIndex < ShipMeshPointers[model+1]; meshIndex++) {





    Transform_point (mul_short_by_fp2_14_returning_short(ShipMesh[((meshIndex * 6) + 0)], scale_fp),
                     mul_short_by_fp2_14_returning_short(ShipMesh[((meshIndex * 6) + 1)], scale_fp),
                     mul_short_by_fp2_14_returning_short(ShipMesh[((meshIndex * 6) + 2)], scale_fp));
    Get_screenpos (x + transformed_X, y + transformed_Y, z + transformed_Z);


    gotoxy (screen_x+ScreenWidth/2, screen_y+ScreenHeight/2);
    putPenDown ();

    Transform_point (mul_short_by_fp2_14_returning_short(ShipMesh[((meshIndex * 6) + 3)], scale_fp),
                     mul_short_by_fp2_14_returning_short(ShipMesh[((meshIndex * 6) + 4)], scale_fp),
                     mul_short_by_fp2_14_returning_short(ShipMesh[((meshIndex * 6) + 5)], scale_fp));
    Get_screenpos (x + transformed_X, y + transformed_Y, z + transformed_Z);


    gotoxy (screen_x+ScreenWidth/2, screen_y+ScreenHeight/2);

    putPenUp ();
  }

  setintensity(110);
}

void Change_ship_time_by(void)
{
  unsigned char id; int dt;
  ships[((id * 14) + 9)] += dt;
}

void Get_ship_vel(void)
{
  unsigned char id;
  this_vel = ships[((id * 14) + 8)];
}

void Apply_vel_to_ship_pos(void)
{
  unsigned char id;
  Get_ship_vel (id);
  Get_ship_rotation (id);
  Change_ship_pos_by (id,
        mul_short_by_fp2_14_returning_short(mul_short_by_fp2_14_returning_short(this_vel, fp2_14_sin (this_Y_rotation)), fp2_14_cos (this_X_rotation)),
        mul_short_by_fp2_14_returning_short(this_vel, fp2_14_sin (this_X_rotation)),
        mul_short_by_fp2_14_returning_short(mul_short_by_fp2_14_returning_short(this_vel, fp2_14_cos (this_Y_rotation)), fp2_14_cos (this_X_rotation)));
}

void Set_ship_posto(void)
{
  unsigned char id; int x; int y; int z;
  ships[((id * 14) + 1)] = x;
  ships[((id * 14) + 2)] = y;
  ships[((id * 14) + 3)] = z;
}

void Get_eigenvector_to(void)
{
  int dx; int dy; int dz;






  dirXZ = Scratch_atan2_fakedegrees(dx, dz);

  if (dz < 0) dirXZ += 128;


  dirY = asin_of_fp2_14( dy / isqrt(dx*dx + dy*dy + dz*dz) );
}

void Set_ship_rotationto(void)
{
  unsigned char id; int this_X_rotation; int this_Y_rotation; int this_Z_rotation;
  ships[((id * 14) + 4)] = this_X_rotation;
  ships[((id * 14) + 5)] = this_Y_rotation;
  ships[((id * 14) + 6)] = this_Z_rotation;
}

void Rotate_ship_toward_by_fakepercent(void)
{
  unsigned char id; int x; int y; int z; int fakepercent;

  Get_ship_pos (id);
  Get_eigenvector_to ((x - this_X), (y - this_Y), (z - this_Z));
  Get_ship_rotation (id);


  Change_ship_rotation_by (id,
                        (fakepercent * ((((dirY - this_X_rotation) + 128) & 255) - 128)) / 128,
                        (fakepercent * ((((dirXZ - this_Y_rotation) + 128) & 255) - 128)) / 128,
                        (fakepercent * -this_Z_rotation) / 128);


}






void Head_ship_towards_destination(void)
{
  unsigned char id;
  Get_ship_pos (id);
  Get_ship_destination (id);

  Rotate_ship_toward_by_fakepercent(id, this_X_destination, this_Y_destination, this_Z_destination, 16);


}

void Set_ship_velocityto(void)
{
  unsigned char id; int vel;
  ships[((id * 14) + 8)] = vel;
}

void Set_ship_destinationto(void)
{
  unsigned char id; int x; int y; int z;
  ships[((id * 14) + 10)] = x;
  ships[((id * 14) + 11)] = y;
  ships[((id * 14) + 12)] = z;
}

void Update_ship(void)
{
  unsigned char id;
  Get_ship_pos (id);
  Apply_vel_to_ship_pos (id);

  Change_ship_velocity_by (id, div_int_by_int_returning_fp2_14(1, 10));
  if (((this_Z < 100) && (UsingShields == 1))) {
    startAsyncSound(1);
    Set_ship_destinationto (id,
                            pickrandom (-100, 100),
                            pickrandom (-100, 100),
                            (2000 + 1000));

    Get_ship_vel (id);
    Set_ship_velocityto (id, -this_vel);
    Apply_vel_to_ship_pos (id);
    Head_ship_towards_destination (id);
    Change_ship_time_by (id, 1);
    Get_ship_pos (id);
  }
  if ((this_Z > (2000 + 500))) {
    Set_ship_status (id, 2);
  } else {
    if ((this_Z < 30)) {
      Set_ship_status (id, 3);
      ShipsPassedThisWave += 1;
      ShipsPassedTotal += 1;
    } else {
      Get_ship_destination (id);
      if (! ((((this_X == 0) && (this_Y == 0)) && (this_Z > 2000)))) {

        Get_ship_time (id);
        if (((this_ship_time % 40) == 39)) {
          Get_ship_pos (id);
          if (this_Z < 1000) {
            Set_ship_destinationto (id, 0, 0, 0);
          } else {

            Set_ship_destinationto (id,
                                  pickrandom (((-300 * this_Z) / 2000), ((300 * this_Z) / 2000)),
                                  pickrandom (((-200 * this_Z) / 2000), ((200 * this_Z) / 2000)),
                                  -200);
          }
        }
      }
      Head_ship_towards_destination (id);
      Change_ship_time_by (id, 1);
    }
  }
}

unsigned char firing, firedone1, firedone2, reloaded;
void Render_lasers(void)
{

  if (Pressed_Key == '\n' || Pressed_Key == '\r' || mouse_fire) {
    Pressed_Key = 0;
    if (!firing && reloaded) {
                         ;
      firing = 1; reloaded = 0;
      firedone1 = plot_fire(0, 40,40, mouse_x, mouse_y);
      firedone2 = plot_fire(1, 1000,40, mouse_x, mouse_y);
    } else {
      if (!firedone1) {
        firedone1 = plot_fire(0, firex[0], firey[0], mouse_x, mouse_y);
      }
      if (!firedone2) {
        firedone2 = plot_fire(1, firex[1], firey[1], mouse_x, mouse_y);
      }
      firing = (!firedone1 || !firedone2);
    }
  } else {
    if (firing) {
      if (!firedone1) {
        firedone1 = plot_fire(0, firex[0], firey[0], mouse_x, mouse_y);
      }
      if (!firedone2) {
        firedone2 = plot_fire(1, firex[1], firey[1], mouse_x, mouse_y);
       }
      firing = !(firedone1 && firedone2);
    } else {reloaded = 1;}
  }
}

void Get_ship_type(void)
{
  unsigned char id;
  this_model = (unsigned char)ships[((id * 14) + 0)];
}

void Render_ships(void)
{
  unsigned char id = 0;
  for (id = 0; id < 3; id++) {
    Get_ship_status (id);
    if (this_status == 0) {
      Get_ship_type (id);
      Get_ship_pos (id);
      Get_ship_rotation (id);
      Get_ship_scale (id);
      Draw_ship_at_rotated_scale (this_model, this_X, this_Y, this_Z, -this_X_rotation, this_Y_rotation, this_Z_rotation, this_scale_fp);
    }
  }
}

void Update_ships(void)
{
  unsigned char shipid = 0;
  for (shipid = 0; shipid < 3; shipid++) {
    Get_ship_status(shipid);
    if (this_status < 2) {
      Update_ship (shipid);
    }
  }
}


void playTailgunner(void) {






  global_flashing_intensity = (unsigned char)(95+(fp2_14_sin(flashingtexttimer)>>9));
  flashingtexttimer = flashingtexttimer + 8;


  if (Pressed_Key == '3') {
    Pressed_Key = 0;
    Credits += 1;
    startAsyncSound(6);
    if (Mode < 4) {
      Mode = 4;
    }
  }

  if (Mode == 6) {
    stars(2);
  } else {
    stars(1);
  }
  if (Mode == 0) {
    Playintro();





    Mode = 1;

  } else if (Mode == 1) {



    Draw_highscore ();
    Draw_last_game_score ();

    if (flashing_intro_timer > 0) {
      flashing_intro_timer -= 1;
      setintensity(global_flashing_intensity);
      if (flashing_intro_timer == 0) {
        intro_rot = 64;
        intro_z = 206;
        hide_intro_timer = 60;
      }
    }

    if (hide_intro_timer == 0) {

      drawtgintro ();
      if (flashing_intro_timer == 0) {
        intro_rot -= 2;
        intro_z -= 1;
        if (intro_z < -199) {

          if (stopintroflag == 1) {
            return;
          }
          flashing_intro_timer = 129;
          intro_rot = 0;
        }
      }
    } else {
      setintensity(110);
      hide_intro_timer -= 1;
      if (hide_intro_timer == 0) {
 Start_new_game ();
        Mode = 2;
      }
    }

  } else if (Mode == 2) {
    Update_ships ();
    Render_ships ();
    Draw_highscore ();
    Draw_last_game_score ();

  } else if (Mode == 3) {




    Draw_highscore ();
    Draw_last_game_score ();
    InsertCoin();

  } else if (Mode == 4) {



    Draw_highscore ();
    Draw_last_game_score ();

    if (Credits ) {
      stopintroflag = 2;
      Draw_credits ();
      Press_start ();

      if (Pressed_Key == '1') {
        Pressed_Key = 0;
        Credits -= 1;
 Start_new_game();
        Mode = 5;




      }

    } else {

    }

  } else if (Mode == 5) {

    draw_crosshair(mouseX(), mouseY());

    if (((Pressed_Key == ' ') || (Pressed_Key == '\t') || mouse_shields) && (Shields > 0)) {
      Pressed_Key = 0;
      UsingShields = 1;
    } else {
      UsingShields = 0;
    }


    if (UsingShields == 1) {
      Shield();
    } else {
      shieldsubticksleft = 0;
    }

    Update_ships ();

    if (Score > HighScore) HighScore = Score;
    Render_ships ();
    Render_lasers ();

    Draw_score ();
    Draw_ShipsPassedTotal ();
    Draw_shields_left ();


    if ( (unsigned char)ships[((0 * 14) + 13)] >= 2
 && (unsigned char)ships[((1 * 14) + 13)] >= 2
 && (unsigned char)ships[((2 * 14) + 13)] >= 2 ) {


      if (ShipsPassedThisWave > 0) {
        passing_mode_timer = 200;
        Mode = 6;
      } else {
        if (ShipsPassedTotal < 10) {
          Start_attack_wave ();
          Mode = 5;
        } else {
          if (Credits ) {
            Mode = 4;
          } else {
            Mode = 0;
            LastScore = Score;
          }
        }
      }
    }

  } else if (Mode == 6) {



    if (passing_mode_timer > 0) {
      passing_mode_timer -= 1;
      if (passing_mode_timer == 0) {
        if (ShipsPassedTotal < 10) {
          Start_attack_wave ();
          Mode = 5;
        } else {
          if (Credits ) {
            Mode = 4;
          } else {
            Mode = 0;
            LastScore = Score;
          }
        }
      }
    }
  } else {



  }
  debug_ship(0);debug_ship(1);debug_ship(2);
}

void pre_graphics_initialisation(void)
{
  reloaded = 1;




  vectrex_beam_intensity = 110;
  ObservedFPS = TargetFPS = 30;


}

void post_graphics_initialisation(void)
{
  intro_x = ScreenWidth/2; intro_y = ScreenHeight/2;
  putPenUp ();
  init_stars();
}

int main (void)
{

  pre_graphics_initialisation();

  graphics_initialisation();

  post_graphics_initialisation();

  Main_loop();

  return(0);
}
