#define ZDEPTH 1024
//#define GTCHARS

/*
      We use OpenGL here but only to draw low-level vectors.  All other
    graphics is done by this code.  It should be easily portable to any
    other system, including, hopefully, the Vectrex, and Zonn Moore's Zektor.

    The original version of this code used the internal coord system of
    the TG rom.  This code is now being modified so that it uses a coord
    system with 0,0 at the center of the screen, so that translating
    to device coords is a simple scaling operation plus a translation.
    The only drawback of this is that we need to be careful with signs,
    especially for our fixed point arithetic.
 */

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

//----------------------------------------------------------- OPENGL
#ifdef OPENGL

#include <GL/glut.h>

#define COLORS 16
GLubyte colors[COLORS][3] = {
    0,0,0,
    1,1,1,
    3,3,3,
    7,7,7,
    15,15,15,
    31,31,31,
    63,63,63,
    127,127,127,
    0+128,0+128,0+128,
    1+128,1+128,1+128,
    3+128,3+128,3+128,
    7+128,7+128,7+128,
    15+128,15+128,15+128,
    31+128,31+128,31+128,
    63+128,63+128,63+128,
    127+128,127+128,127+128,
};
#endif
//------------------------------------------------------- END OPENGL

#ifndef FALSE


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

#define SCREEN_H 800
#define SCREEN_W 1023

void CinemaVectorData (int FromX, int FromY, int ToX, int ToY, int vgColour);
void cineExecuteFrame(void);

static int mouse_x = 350, mouse_y = 180, mouse_b = 0; // have not yet added mouse support!


//-------------------------------------------- FIXED POINT GRAPHICS PACKAGE

//
// fp14 code written by: Robert C. Pendleton
// 
// Copyright 1993 by Robert C. Pendleton, all right reserved
//
// Non-commercial use by individuals is permitted.
//
//


//----------------------------------------------
//
// Integer math
//

//----------------------------------------------
//
// fixed point math
//

typedef unsigned long long fp14; // THIS DOES NOT YET WORK IF CONVERTED TO SIMPLE long

//----------------------------------------------
//
// Add and subtract fixed point numbers. :-)
//

#define fpAdd(a1, a2) ((a1) + (a2))
#define fpSub(s1, s2) ((s1) - (s2))

//----------------------------------------------
//
// Convert an integer to n N.14 fixed point 
// number and back.
//

#define int2fp(x) ((x) << 14)
#define fp2int(x) ((x) >> 14)

//----------------------------------------------
//
// Get the fractional part of an N.14 fixed point
// number.

#define fpFract(x) ((x) & 0x3fff)

//----------------------------------------------
//
// Convert a N.14 fixed point number to a
// double and back. Handy for printing and for 
// those times when you really do want to work
// with floating point values.
//

#define fp2float(x) (((double)(x)) / (1 << 14))
#define float2fp(x) ((fp14) ((x) * (1 << 14)))

//----------------------------------------------
//
// Table based fixed point sine and cosine 
// functions.
//

#define fpSin(x) (sine[(x) & 0xff])
#define fpCos(x) (sine[((x)+64) & 0xff])

//----------------------------------------------
//
// 18.14 fixed point sine and cosine tables.
//
// These table assume that there are 256 angles
// in a circle.
//

fp14 sine[] =
{
     0,    402,    803,   1205,   1605,   2005,   2404,   2801, 
  3196,   3589,   3980,   4369,   4756,   5139,   5519,   5896, 
  6269,   6639,   7005,   7366,   7723,   8075,   8423,   8765, 
  9102,   9434,   9759,  10079,  10393,  10701,  11002,  11297, 
 11585,  11866,  12139,  12406,  12665,  12916,  13159,  13395, 
 13622,  13842,  14053,  14255,  14449,  14634,  14810,  14978, 
 15136,  15286,  15426,  15557,  15678,  15790,  15892,  15985, 
 16069,  16142,  16206,  16260,  16305,  16339,  16364,  16379, 
 16384,  16379,  16364,  16339,  16305,  16260,  16206,  16142, 
 16069,  15985,  15892,  15790,  15678,  15557,  15426,  15286, 
 15136,  14978,  14810,  14634,  14449,  14255,  14053,  13842, 
 13622,  13395,  13159,  12916,  12665,  12406,  12139,  11866, 
 11585,  11297,  11002,  10701,  10393,  10079,   9759,   9434, 
  9102,   8765,   8423,   8075,   7723,   7366,   7005,   6639, 
  6269,   5896,   5519,   5139,   4756,   4369,   3980,   3589, 
  3196,   2801,   2404,   2005,   1605,   1205,    803,    402, 
     0,   -402,   -803,  -1205,  -1605,  -2005,  -2404,  -2801, 
 -3196,  -3589,  -3980,  -4369,  -4756,  -5139,  -5519,  -5896, 
 -6269,  -6639,  -7005,  -7366,  -7723,  -8075,  -8423,  -8765, 
 -9102,  -9434,  -9759, -10079, -10393, -10701, -11002, -11297, 
-11585, -11866, -12139, -12406, -12665, -12916, -13159, -13395, 
-13622, -13842, -14053, -14255, -14449, -14634, -14810, -14978, 
-15136, -15286, -15426, -15557, -15678, -15790, -15892, -15985, 
-16069, -16142, -16206, -16260, -16305, -16339, -16364, -16379, 
-16384, -16379, -16364, -16339, -16305, -16260, -16206, -16142, 
-16069, -15985, -15892, -15790, -15678, -15557, -15426, -15286, 
-15136, -14978, -14810, -14634, -14449, -14255, -14053, -13842, 
-13622, -13395, -13159, -12916, -12665, -12406, -12139, -11866, 
-11585, -11297, -11002, -10701, -10393, -10079,  -9759,  -9434, 
 -9102,  -8765,  -8423,  -8075,  -7723,  -7366,  -7005,  -6639, 
 -6269,  -5896,  -5519,  -5139,  -4756,  -4369,  -3980,  -3589, 
 -3196,  -2801,  -2404,  -2005,  -1605,  -1205,   -803,   -402, 
};


fp14
fpDiv(fp14 d1, fp14 d2)
{  // NEED SIMPLE LONG VERSION OF THESE!
  unsigned long long x = ((unsigned long long)d1<<14) / (unsigned long long)d2;
//  x = x << 14;
  return ((fp14)x);
}

fp14
fpMul(fp14 m1, fp14 m2)
{  // NEED SIMPLE LONG VERSION OF THESE!
  unsigned long long x = (unsigned long long)m1 * (unsigned long long)m2;
  x = x >> 14;
  return ((fp14)x);
}

typedef struct VERTEX
{
//	double x,y,z;
        double z,y,x; // hack because draw code uses different coord system
}VERTEX;

// for convenience and shorter code on Vectrex - need to do more of this...
int mult_sin(int coord, int angle)
{
  return fp2int(fpMul(int2fp(coord), fpSin(angle&255)));
}

int mult_cos(int coord, int angle)
{
  return fp2int(fpMul(int2fp(coord), fpCos(angle&255)));
}

//
// the drawing code has a different notion of x/y/z than I do, so some
// of the coords are shuffled around carelessly in places! (see VERTEX above)
//
// x,y,z - 'real' world (1024x1024x1024)
// xangle,yangle,zangle - rotate object around its own axis
// screenx, screeny, screenz - 'virtual pixel' offset in screen coords (1280x1024)

void DrawShip(int ship, int x, int y, int z, int xangle, int yangle, int zangle, int screenx, int screeny)
{
int i;

// Ships coded by Peter Hirschberger.  Great work, Peter!
// these numbers are scaled, so we should pre-scale and convert
// to int.  They're only reals because Peter's graphics package
// uses reals.

#define QUICK_HACK 1
#ifdef QUICK_HACK
#define nNumVectors0 20
	VERTEX vectors0[nNumVectors0*2] = 
	{
		// front of ship - horizontal plane
		// vector 1
		{ -5.0, 0.0, 0.0 },
		{ -3.0, 0.0, 2.0 },
		// vector 2
		{ -3.0, 0.0, 2.0 },
		{ -1.0, 0.0, 0.0 },
		// vector 3
		{ -1.0, 0.0, 0.0 },
		{ -3.0, 0.0, -2.0 },
		// vector 4
		{ -3.0, 0.0, -2.0 },
		{ -5.0, 0.0, 0.0 },

		// front of ship - vertical plane
		// vector 5
		{ -5.0, 0.0, 0.0 },
		{ -3.0, 2.0, 0.0 },
		// vector 6
		{ -3.0, 2.0, 0.0 },
		{ -1.0, 0.0, 0.0 },
		// vector 7
		{ -1.0, 0.0, 0.0 },
		{ -3.0, -2.0, 0.0 },
		// vector 8
		{ -3.0, -2.0, 0.0 },
		{ -5.0, 0.0, 0.0 },

		// top of fuselage
		// vector 9
		{ -1.0, 0.0, 0.0 },
		{ 6.0, 0.0, 1.5 },
		// vector 10
		{ -1.0, 0.0, 0.0 },
		{ 6.0, 1.0, 1.0 },
		// vector 11
		{ -1.0, 0.0, 0.0 },
		{ 6.0, 1.0, -1.0 },
		// vector 12
		{ -1.0, 0.0, 0.0 },
		{ 6.0, 0.0, -1.5 },

		// rear of fuselage
		// vector 13
		{ 6.0, 0.0, 1.5 },
		{ 6.0, 1.0, 1.0 },
		// vector 14
		{ 6.0, 1.0, 1.0 },
		{ 6.0, 1.0, -1.0 },
		// vector 15
		{ 6.0, 1.0, -1.0 },
		{ 6.0, 0.0, -1.5 },
		// vector 16
		{ 6.0, 0.0, -1.5 },
		{ 6.0, 0.0, 1.5 },

		// right wing
		// vector 17
		{ 6.0, 0.0, 1.5 },
		{ 4.0, -2.0, 5.0 }, //4->7
		// vector 18
		{ 4.0, -2.0, 5.0 }, //4->7
		{ -1.0, 0.0, 0.0 },

		// left wing
		// vector 19
		{ 6.0, 0.0, -1.5 },
		{ 4.0, -2.0, -5.0 }, //4->7
		// vector 20
		{ 4.0, -2.0, -5.0 }, //4->7
		{ -1.0, 0.0, 0.0 }

	};
#else
// a square - simple object for debugging
// next test would have been a cube but since it
// worked OK we went straight to the ships
#define nNumVectors0 4
	VERTEX vectors0[nNumVectors0*2] = 
	{
		// front of ship - horizontal plane
		// vector 1
		{ -5.0, -5.0, 0.0 },
		{ -5.0,  5.0, 0.0 },
		// vector 2
		{ -5.0, 5.0, 0.0 },
		{  5.0, 5.0, 0.0 },
		// vector 3
		{  5.0,  5.0, 0.0 },
		{  5.0, -5.0, 0.0 },
		// vector 4
		{  5.0, -5.0, 0.0 },
		{ -5.0, -5.0, 0.0 }
        };
#endif


#define nNumVectors1 21
	VERTEX vectors1[nNumVectors1*2] = 
	{
		// top of fuselage
		// vector 1
		{ -3.0, 0.0, 0.0 },
		{ -2.0, 0.0, 1.5 },
		// vector 2
		{ -2.0, 0.0, 1.5 },
		{ 2.0, 0.0, 1.5 },
		// vector 3
		{ 2.0, 0.0, 1.5 },
		{ 3.0, 0.0, 0.0 },
		// vector 4
		{ 3.0, 0.0, 0.0 },
		{ 2.0, 0.0, -1.5 },
		// vector 5
		{ 2.0, 0.0, -1.5 },
		{ -2.0, 0.0, -1.5 },
		// vector 6
		{ -2.0, 0.0, -1.5 },
		{ -3.0, 0.0, 0.0 },

		// right wing
		// vector 7
		{ 2.0, 0.0, 1.5 },
		{ 2.0, 0.8, 2.0 },
		// vector 8
		{ 2.0, 0.8, 2.0 },
		{ 5.0, 0.8, 2.0 },
		// vector 9
		{ 5.0, 0.8, 2.0 },
		{ 5.0, 0.0, 1.5 },
		// vector 10
		{ 5.0, 0.0, 1.5 },
		{ 2.0, 0.0, 1.5 },

		// left wing
		// vector 11
		{ 2.0, 0.0, -1.5 },
		{ 2.0, 0.8, -2.0 },
		// vector 12
		{ 2.0, 0.8, -2.0 },
		{ 5.0, 0.8, -2.0 },
		// vector 13
		{ 5.0, 0.8, -2.0 },
		{ 5.0, 0.0, -1.5 },
		// vector 14
		{ 5.0, 0.0, -1.5 },
		{ 2.0, 0.0, -1.5 },

		// bottom fuselage outline
		// vector 15
		{ 2.0, 0.0, -1.5 },
		{ -3.0, -0.9, -2.0 },
		// vector 16
		{ -3.0, -0.9, -2.0 },
		{ -4.3, -1.16, 0.0 },
		// vector 17
		{ -4.3, -1.16, 0.0 },
		{ -3.0, -0.9, 2.0 },
		// vector 18
		{ -3.0, -0.9, 2.0 },
		{ 2.0, 0.0, 1.5 },

		// window corner lines
		// vector 19
		{ -3.0, 0.0, 0.0 },
		{ -4.3, -1.16, 0.0 },
		// vector 20
		{ -2.0, 0.0, 1.5 },
		{ -3.0, -0.9, 2.0 },
		// vector 21
		{ -2.0, 0.0, -1.5 },
		{ -3.0, -0.9, -2.0 }

	};

#define nNumVectors2 17
	VERTEX vectors2[nNumVectors2*2] = 
	{
		// main fuselage
		// vector 1
		{ -5.0, 0.0, 0.0 },
		{ -2.0, 0.0, 3.0 },
		// vector 2
		{ -2.0, 0.0, 3.0 },
		{ 1.0, 0.0, 0.0 },
		// vector 3
		{ 1.0, 0.0, 0.0 },
		{ -2.0, 0.0, -3.0 },
		// vector 4
		{ -2.0, 0.0, -3.0 },
		{ -5.0, 0.0, 0.0 },
		// vector 5
		{ -5.0, 0.0, 0.0 },
		{ -2.0, 2.0, 0.0 },
		// vector 6
		{ -2.0, 2.0, 0.0 },
		{ 1.0, 0.0, 0.0 },
		// vector 7
		{ -2.0, 0.0, 3.0 },
		{ -2.0, 2.0, 0.0 },
		// vector 8
		{ -2.0, 2.0, 0.0 },
		{ -2.0, 0.0, -3.0 },

		// top fin
		// vector 9
		{ 1.0, 0.0, 0.0 },
		{ 5.0, 4.0, 0.0 },
		// vector 10
		{ 5.0, 4.0, 0.0 },
		{ 5.0, 2.0, 0.0 },
		// vector 11
		{ 5.0, 2.0, 0.0 },
		{ 1.0, 0.0, 0.0 },

		// right fin
		// vector 12
		{ 1.0, 0.0, 0.0 },
		{ 5.0, -2.0, 5.0 },
		// vector 13
		{ 5.0, -2.0, 5.0 },
		{ 5.0, -1.0, 2.0 },
		// vector 14
		{ 5.0, -1.0, 2.0 },
		{ 1.0, 0.0, 0.0 },

		// left fin
		// vector 15
		{ 1.0, 0.0, 0.0 },
		{ 5.0, -2.0, -5.0 },
		// vector 16
		{ 5.0, -2.0, -5.0 },
		{ 5.0, -1.0, -2.0 },
		// vector 17
		{ 5.0, -1.0, -2.0 },
		{ 1.0, 0.0, 0.0 }

	};

#define nNumVectors3 23
#define KEELX	-4.5
#define KEELY	-2.5
	VERTEX vectors3[nNumVectors3*2] = 
	{
		// cockpit
		// vector 1
		{ -9.25, 0.25, 0.0 },
		{ -7.0, 0.25, 3.0 },
		// vector 2
		{ -7.0, 0.25, 3.0 },
		{ -2.0, 1.0, 0.0 },
		// vector 3
		{ -2.0, 1.0, 0.0 },
		{ -7.0, 0.25, -3.0 },
		// vector 4
		{ -7.0, 0.25, -3.0 },
		{ -9.25, 0.25, 0.0 },
		// vector 5
		{ -9.25, 0.25, 0.0 },
		{ KEELX, KEELY, 0.0 },
		// vector 6
		{ KEELX, KEELY, 0.0 },
		{ -2.0, 1.0, 0.0 },
		// vector 7
		{ -7.0, 0.25, 3.0 },
		{ -6.0, 1.5, 2.25 },
		// vector 8
		{ -7.0, 0.25, -3.0 },
		{ -6.0, 1.5, -2.25 },
		// vector 9
		{ -7.0, 0.25, 3.0 },
		{ KEELX, KEELY, 0.0 },
		// vector 10
		{ -7.0, 0.25, -3.0 },
		{ KEELX, KEELY, 0.0 },
		// vector 11
		{ -6.0, 1.5, 2.25 },
		{ -6.0, 1.5, -2.25 },
		// vector 12
		{ -6.0, 1.5, 2.25 },
		{ -2.0, 1.0, 0.0 },
		// vector 13
		{ -6.0, 1.5, -2.25 },
		{ -2.0, 1.0, 0.0 },
		// vector 14
		{ -7.0, 0.25, 3.0 },
		{ -7.0, 0.25, -3.0 },

		// main fusalage
		// vector 15
		{ -2.0, 1.0, 0.0 },
		{ 11.0, -1.0, -2.0 },
		// vector 16
		{ -2.0, 1.0, 0.0 },
		{ 11.0, -1.0, 2.0 },
		// vector 17
		{ 11.0, -1.0, -2.0 },
		{ 11.0, -1.0, 2.0 },
		// vector 18
		{ KEELX, KEELY, 0.0 },
		{ 11.0, -1.0, -2.0 },
		// vector 19
		{ KEELX, KEELY, 0.0 },
		{ 11.0, -1.0, 2.0 },

		// left wing
		// vector 20
		{ -2.0, 1.0, 0.0 },
		{ 9.0, 2.0, -9.0 },
		// vector 21
		{ 9.0, 2.0, -9.0 },
		{ 11.0, -1.0, -2.0 },

		// right wing
		// vector 22
		{ -2.0, 1.0, 0.0 },
		{ 9.0, 2.0, 9.0 },
		// vector 23
		{ 9.0, 2.0, 9.0 },
		{ 11.0, -1.0, 2.0 },
	};

int nvec[4] = {nNumVectors0,nNumVectors1,nNumVectors2,nNumVectors3}; 
VERTEX *pvec[4] = {vectors0, vectors1, vectors2, vectors3};
int     nNumVectors = nvec[ship];
int     nSCALE[4] = {20, 30, 20, 10};
int     SCALE=nSCALE[ship];

	for (i=0; i<nNumVectors*2; i+=2)
	{
#define TWEAK 1024

          int x0, y0, z0, x1, y1, z1, tx0, ty0, tz0, tx1, ty1, tz1, xa, ya, xb, yb;

          x0 = (int)(pvec[ship][i].x*SCALE);
          y0 = (int)(pvec[ship][i].y*SCALE);
          z0 = (int)(pvec[ship][i].z*SCALE);

          x1 = (int)(pvec[ship][i+1].x*SCALE);
          y1 = (int)(pvec[ship][i+1].y*SCALE);
          z1 = (int)(pvec[ship][i+1].z*SCALE);

#define NAIVE
#ifdef NAIVE
          // rotate around z
          tx0 = mult_cos(x0, zangle)-mult_sin(y0, zangle);
          ty0 = mult_sin(x0, zangle)+mult_cos(y0, zangle);
          tz0 = z0;

          tx1 = mult_cos(x1, zangle)-mult_sin(y1, zangle);
          ty1 = mult_sin(x1, zangle)+mult_cos(y1, zangle);
          tz1 = z1;
          x0=tx0;y0=ty0;z0=tz0; x1=tx1;y1=ty1;z1=tz1;

          // rotate around y
          tz0 = mult_cos(z0, yangle)-mult_sin(x0, yangle);
          tx0 = mult_sin(z0, yangle)+mult_cos(x0, yangle);
          ty0 = y0;

          tz1 = mult_cos(z1, yangle)-mult_sin(x1, yangle);
          tx1 = mult_sin(z1, yangle)+mult_cos(x1, yangle);
          ty1 = y1;
          x0=tx0;y0=ty0;z0=tz0; x1=tx1;y1=ty1;z1=tz1;

          // rotate around x
          ty0 = mult_cos(y0, xangle)-mult_sin(z0, xangle);
          tz0 = mult_sin(y0, xangle)+mult_cos(z0, xangle);
          tx0 = x0;

          ty1 = mult_cos(y1, xangle)-mult_sin(z1, xangle);
          tz1 = mult_sin(y1, xangle)+mult_cos(z1, xangle);
          tx1 = x1;
#else
// new code to be added here ... UNDER CONSTRUCTION
          tx0 = fpMul(x0, fpMul(fpCos(yangle), fpCos(zangle))) + 
                fpMul(y0, fpMul(fpMul(int2fp(-1), fpCos(yangle)), fpSin(zangle))) + 
                fpMul(z0, fpSin(yangle));
          ty0 = fpMul(x0, fpAdd(fpMul(fpMul(fpSin(xangle),fpSin(yangle)),fpCos(zangle)),
                                fpMul(fpCos(xangle),fpSin(zangle)))) +
                fpMul(y0, fpAdd(,)) +
                fpMul(z0, fpMul());
#endif
          // treat 512,340 as 0,0 for perspective purposes
          tx0 = tx0+x; ty0 = ty0+y; tx1 = tx1+x; ty1 = ty1+y;

          xa = ((TWEAK*tx0) / (TWEAK+tz0));
          ya = ((TWEAK*ty0) / (TWEAK+tz0));
          xb = ((TWEAK*tx1) / (TWEAK+tz1));
          yb = ((TWEAK*ty1) / (TWEAK+tz1));

          // scale by depth
          xa = (xa*(z+200))/ZDEPTH; ya=(ya*(z+200))/ZDEPTH; xb=(xb*(z+200))/ZDEPTH; yb=(yb*(z+200))/ZDEPTH;

          // then re-correct back to center of screen at 512,400
          CinemaVectorData(xa+512+screenx,ya+400+screeny,xb+512+screenx,yb+400+screeny, 7);

//#undef TWEAK
	}

#undef nNumVectors0
#undef nNumVectors1
#undef nNumVectors2
#undef nNumVectors3
#undef SCALE
}

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

//static int debounce_oneshots = 0, debounce_shields = 0;



// This is the low-level vector (line) drawing routine.  It uses
// the original ROM version coordinate space and maps to the local
// hardware.  Clipping is crude but doesn't appear to hurt in
// this application.  Ideally this code should be trivially short
// and fast.
void
CinemaVectorData (int FromX, int FromY, int ToX, int ToY, int vgColour)
{

  /* TWEAK THESE TO MAKE THEM FIT... */

  ToX = ToX << 16;  // sign extend short to long
  ToX = ToX >> 16;
  FromX = FromX << 16;
  FromX = FromX >> 16;

// global adjustments
  FromX -= 32; ToX -= 32;

  if (FromX < MinX)
    MinX = FromX;
  if (ToX < MinX)
    MinX = ToX;
  if (FromY < MinY)
    MinY = FromY;
  if (ToY < MinY)
    MinY = ToY;
  if (FromX > MaxX)
    MaxX = FromX;
  if (ToX > MaxX)
    MaxX = ToX;
  if (FromY > MaxY)
    MaxY = FromY;
  if (ToY > MaxY)
    MaxY = ToY;

#ifdef OPENGL
//fprintf (stdout, "Line: %d %d -> %d %d (%d)\n", FromX, FromY, ToX, ToY, vgColour);
  glColor3ubv(colors[vgColour % COLORS]);
  glVertex2i(FromX, FromY);
  glVertex2i(ToX, ToY);
#endif

}


/* main program loop body */


#ifdef OPENGL
// This code based on:
/* 
    qix.c
    Nate Robins, 1997

    An example of a 'qix'-like line demo, but without the traditional
    erase lines, and with anti-aliased lines.

 */


void
reshape(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width, 0, height, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glEnable(GL_BLEND);
    glEnable(GL_LINE_SMOOTH);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE/*GL_ONE_MINUS_SRC_ALPHA*/);
}

void
display(void)
{
    int i;
    static int color = 0;
    static int odd = 0;

    odd = (odd+1)&15; /* Can't remember why I did this.  Was it too fast? */
    if (odd == 0) {
      glClear(GL_COLOR_BUFFER_BIT);    
      glBegin(GL_LINES);
      cineExecuteFrame ();
      glEnd();
      glutSwapBuffers();
    }
}

/* This handles the unix/cygwin-style OpenGL main loop */
void
idle(void)
{
    glutPostRedisplay();
}

static int PENDING_KEY = -1;
void
keyboard(unsigned char key, int x, int y)
{
    static int old_x = 50;
    static int old_y = 50;
    static int old_width = SCREEN_W;
    static int old_height = SCREEN_H;

    if (key == 27) {
        exit(0);
    } else if (key == 'w') {
        glutPositionWindow(old_x, old_y);
        glutReshapeWindow(old_width, old_height);
    } else if (key == 'f') {
	if (glutGet(GLUT_WINDOW_WIDTH) != glutGet(GLUT_SCREEN_WIDTH)) {
	    old_x = glutGet(GLUT_WINDOW_X);
	    old_y = glutGet(GLUT_WINDOW_Y);
	    old_width = glutGet(GLUT_WINDOW_WIDTH);
	    old_height = glutGet(GLUT_WINDOW_HEIGHT);
	    glutFullScreen();
	}
    } else {
      PENDING_KEY = key;
    }
}
#endif

char charvec[] = {
 /* Need to add two codes for '+' and '-' for debugging coord values! */
 '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;
    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; /* currently internal but on vectrex this may be a 'move abs' */
}

void veccol(int col)
/* Original tailgunner levels: 7=>medium 15=>bright - we don't use any others */
{
  curcol = col;
}

void printchar(int c) /* updating curx, cury */
{
  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);
  }
  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)
{
  /* Intro screen */
  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
};

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

  // quick hack while testing - change distance but don't roll

  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)
{
  /* The text inside the intro screen rotating box */
  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)
{
  /* Replace with a point call on other hardware */
  /* One-pixel line == one point */
  CinemaVectorData(x, y,
                   x+1, y+1,
                   /* 7 is too faint */ 15);
}


/* 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)
{
  /* Stars never reach center of screen */
  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 */
#define abs(x) (((x)>=0)?(x):-(x))

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)
{
  /* add rotation and scaling to simulate approach */
  int i;
  for (i = 0; i < 12; i++) {
    CinemaVectorData((shieldvec[i*2]<<2)+0x20, shieldvec[i*2+1]<<2,
                     (shieldvec[i*2+2]<<2)+0x20, 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);
  }
}

int
main(int argc, char** argv)
{

#ifdef OPENGL
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50, 50);
    glutInitWindowSize(SCREEN_W, SCREEN_H);
    glutInit(&argc, argv);

    glutCreateWindow("Tailgunner");
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
#endif

    initchars();

#ifdef OPENGL
    glutIdleFunc(idle);
    glutMainLoop();
#endif

    exit(0);
    return 0;
}


void cineExecuteFrame(void) {

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

int k = 0;
static int tgstate = PREGAME;
static int credits = '0';
static int passed = '0';
static char shields[3] = { '8', '0', '\0'};
static int passing = 0;
static int firing = (0!=0);
static int reloaded = (0==0);
static int firedone1, firedone2;
static int start = 0;
static int shieldtick = 0;
static int state = 12, ship=0;
static int xa = 0, ya = 0, za = 0;
static int x = 0, y = 0, z = 0;
static int i = 0, angle = 0;

//-- pregame and playing
  if (tgstate != COINED) {
      vecmoveto(0x96, 0x28a); printstring("SCORE");
      vecmoveto(0xb8, 0x258); printstring(" 00");

      vecmoveto(0x2bc, 0x28a); printstring("HIGH[SCORE");
      vecmoveto(0x2f8, 0x258); printstring(" 00");
  } else {
//-- coined:

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

  if (tgstate == PREGAME) {
      vecmoveto(380,100); printstring("INSERT[COIN");
  }

  if (state == 0) {
//    vecmoveto(350,300); printstring("ROTATE AROUND Z");
    DrawShip((ship+0)&3, 0,0,0, 0,0,za, -30,-30);
    DrawShip((ship+1)&3, 0,0,0, 0,0,za, -30,30);
    DrawShip((ship+2)&3, 0,0,0, 0,0,za, 30,30);
    DrawShip((ship+3)&3, 0,0,0, 0,0,za, 30,-30);
    za = (za-1)&255;
    if (za == 0) i += 1; if (i == 1) {i = 0; state = 1;}
  } else if (state == 1) {
//    vecmoveto(350,300); printstring("ROTATE AROUND X");
    DrawShip((ship+0)&3, 0,0,0, xa,0,0, -30,-30);
    DrawShip((ship+1)&3, 0,0,0, xa,0,0, -30,30);
    DrawShip((ship+2)&3, 0,0,0, xa,0,0, 30,30);
    DrawShip((ship+3)&3, 0,0,0, xa,0,0, 30,-30);
    xa = (xa-1)&255;
    if (xa == 0) i += 1; if (i == 1) {i = 0; state = 2;}
  } else if (state == 2) {
//    vecmoveto(350,300); printstring("ROTATE AROUND Y");
    DrawShip((ship+0)&3, 0,0,0, 0,ya,0, -30,-30);
    DrawShip((ship+1)&3, 0,0,0, 0,ya,0, -30,30);
    DrawShip((ship+2)&3, 0,0,0, 0,ya,0, 30,30);
    DrawShip((ship+3)&3, 0,0,0, 0,ya,0, 30,-30);
    ya = (ya+1)&255;
    if (ya == 0) i += 1; if (i == 1) state = 3;
  } else if (state == 3) {
//    vecmoveto(250,300); printstring("INCREASE Z FROM 0 TO ZDEPTH");
    DrawShip((ship+0)&3, 0,-512,z, 0,0,0, 0,0);
    DrawShip((ship+1)&3, 0,511,z, 0,0,0, 0,0);
    DrawShip((ship+2)&3, -512,0,z, 0,0,0, 0,0);
    DrawShip((ship+3)&3, 511,0,z, 0,0,0, 0,0);
    z = (z+2)&(ZDEPTH-1); if (z == 0) {state = 7;}
  } else if (state == 7) {
    static int passingtime = 0;
    passing = 1;
    passingtime = (passingtime+1)&31;
    if (passingtime == 0) {passing = 0; tgstate = COINED; ; state = 8;}
  } else if (state == 8) {
    static int passingtime = 0;
    if (passingtime == 60) credits += 1;
    passingtime = (passingtime+1)&255;
    if (passingtime == 0) {credits -= 1; tgstate = PLAYING; state = 9;}
  } else if (state == 9) {
    int x2, y2;
    x = fp2int(fpMul(int2fp(511),fpSin(angle))); y = fp2int(fpMul(int2fp(511),fpCos(angle)));
    x2 = fp2int(fpMul(int2fp(511),fpSin((angle+10)&255))); y2 = fp2int(fpMul(int2fp(511),fpCos((angle+10)&255)));
    angle = (angle+1)&255;
    DrawShip(ship, x, y, z,
              0,0,0,
              0,0);
    z = (z+1)&(ZDEPTH-1);

      if (z == 64) {
        if (!firing && reloaded) {
          /* initiate fire */;

      vecmoveto((mouse_x*5)/4+0x30, 640-((mouse_y*10)/8)); draw_crosshair(curx, cury);
          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 {
      vecmoveto((mouse_x*5)/4+0x30, 640-((mouse_y*10)/8)); draw_crosshair(curx, cury);
          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 {
      vecmoveto((mouse_x*5)/4+0x30, 640-((mouse_y*10)/8)); draw_crosshair(curx, cury);
        if (firing) { /* Finish off the last shot */
          mouse_x += 4; mouse_y += 4;
          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);
      }


    if (z == (ZDEPTH*3/4)) {angle = 0; state = 10; z=0;mouse_x=350;mouse_y=180;}
  } else if (state == 10) {
    static int shieldtime = 0;
//    vecmoveto(400,300); printstring("SHIELD TEST");
    if (shieldtime&128) draw_shields();
    shieldtime = (shieldtime+1)&511;
    if (shieldtime == 0) {state = 11;}
  } else if (state == 11) {
    static int passingtime = 0;
    passing = 1;
    passingtime = (passingtime+1)&31;
    if (passingtime == 0) {tgstate = PREGAME; passing = 0; state = 12;}
  } else if (state == 12) {
    static int idletime = 0;
    idletime = (idletime+1)&255;
    if (idletime == 0) {state = 13;}

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


  } else if (state == 13) {
    state = 0; i = 0; ship = (ship+1)&3;
  }
  if (passing) {
    stars(2);
  } else {
    stars(1);
  }
}

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