// Code copied or derived from xasteroids Copyright Phil Goetz.
// See the file README.xast, which is the README file from the xasteroids
// distribution.
//
// All other code Copyright 1994 Brad Pitzel   pitzel@cs.sfu.ca
// Feel free to use/distribute/modify as long as credit/copyrights
// are included.
//
//
// sasteroids	Version 1.1 for Linux  (and linux only :)
// 		Released Feb 14/94
//		Requires svgalib v1.01 (super-vga graphics library)
//		earlier versions of svgalib might work, i haven't tested it
//		Developed with gcc 2.5.8


#include <stdio.h>
#include <vga.h>
#include <vgagl.h>
#include <math.h>
#include <iostream.h>

#include "bitmaps.h"		// bitmaps for asteroids, ship, etc...
#include "titleScn.h"		// bitmap for title screen
#include "backScn.h"		// bitmap for high scores backdrop
#include "Timer.h"
#include "sasteroids.h"
#include "HiScore.h"
#include "Ui.h"
#include "Obj.h"		// game objects
#include "FastMath.h"
#include "Explosion.h"
#include "Joystick.h"


#define VERSION "v1.1-beta-1"

#define FPS	20		// frames per second for the animation
				// play with this if you like

// I thought of changing from xasteroids method of putting objects in
// an array to using a nice C++ linked list, but I think that would only
// slow things down, so the following bit is straight from xasteroids
// source code. (BJP)

// Indexes for 1st dimension of obj	
// The order they are in is important	
#define	AST	0
#define	ENEMY	96
#define ENEMYBUL 97
#define	FBUL	98
#define	LASTBUL	102
#define	SHIP	103
#define LASTOBJ 103	// Must be ship!  See makeasts().	


// Shapes	
// Order is important!  See collide().	
#define	ASTSHAPE1	0
#define ASTSHAPE2	1
#define ASTSHAPE3	2
#define ENBULSH		3
#define	BULSHAPE	4
#define	SHIPSHAPE	5
#define SHIPTHRSHAPE	6
#define	ENEMYSHAPE	7
#define LASTSHAPE	7


// The following define 'masses' for the game objects.  From xasteroids
// source, this allows the cool bouncing/collision routines
// to work the way they do..
 
// Masses	
#define M_BIG	8.0
#define M_MED	4.0
#define M_SMALL	1.0
#define M_SHIP	1.5
#define M_ENEMY	1.0
#define M_BULLET 0.1

#define START_DIST 70		// when starting a level, place new asteroids
				// at least this far from your ship.


typedef struct {double x, y, mag;} Vector;

// Global variables:	

Joystick	Joy0(0);

typedef BitmapObj *ObjPtr;
ObjPtr	obj[SHIP+1];

// The player ship is an instance of the ship object, eh?
Ship	playerShip( SHIPSHAPE, M_SHIP );


// I've got to finish C++'ing this program and hide the rest
// of these global vars.
int	score,
	level,
	nextbul = FBUL,			// Obj# of next bullet fired	
	numasts, oldscore;


// I got lazy and didn't draw a bitmap for the smallest asteroid.
// Instead, I scale the medium sized asteroid down. The bitmaps.[ch] files
// contain the bitmaps that I did drawings for.  Since smallast wasn't
// drawn, we'll define it here. ('cause bitmaps.[ch] is code-generated
// from the bitmap files)
Bitmap smallast(10,10);


// do some work to get a few bitmaps ready for the game.
void setBits()
{

// make the small asteroid a scaled down version of the medium one.
smallast.copy( medast, 10, 10 );

if (smallast.map()==NULL) {
	cerr << "can't create small asteroid bitmap.\n";
	exit(-1);
	}
}

// ugly hack hack hack.  for convience, define wihte and red colors
// into the bitmap's color palette.
#define WHITE 255
#define RED   254
void setBPcolormap() {
    bitmaps.color[RED].red = 63;
    bitmaps.color[RED].green = 0;
    bitmaps.color[RED].blue = 0;
    		
    gl_setpalette(&bitmaps);
}

// set up the array of game objects.
void initObjArray()
{	int i;
	for (i = 0; i < ENEMY; i++)
		{	
		obj[i] = new BitmapObj( ASTSHAPE1, M_BIG, bigast );
		}

	obj[SHIP] = &playerShip;
		
	obj[ENEMYBUL] = new BitmapObj( ENBULSH, M_BULLET, bullet );
	obj[ENEMY] = new Enemy( ENEMYSHAPE, M_ENEMY, playerShip, *obj[ENEMYBUL] );
	
	obj[ENEMYBUL]->die();
	
	for (i = FBUL; i < LASTBUL+1; i++)
		{	
		obj[i] = new BitmapObj( BULSHAPE, M_BULLET, bullet );
		}	
}

// create asteroids for beginning of each level/game
// makeasts - modified from xasteroids
void makeasts()
{	int i;

	for (i = 0; i < SHIP; i++)
		obj[i]->die(); // Erase objs from last level except ship 

	for (i = 0; i < ((level > 10) ? 12 : level+2); i++) // Asteroids
	{
		obj[i]->shape = ASTSHAPE1;

		obj[i]->setPos( (rand()>>5)%WIDTH, (rand()>>5)%HEIGHT );

		// make sure new ast is not near player's ship
		if (playerShip.distance( *obj[i] ) > START_DIST)
			{
			obj[i]->randomDir( 1 );
			obj[i]->setBitmap(bigast);
			obj[i]->mass = M_BIG;
			obj[i]->revive();
			}
		else	i--;	// ast too close to player, try again
	}
	numasts = i;
}


// nextast - from xasteroids
int nextast()	// Find next unused asteroid object
{	
	register int i;
	for (i = 0; obj[i]->isAlive(); i++);	// guaranteed to find one
	return i;
}


// greatly simplified/dumb collision alg.  the original xasteroids used
// line intersection methods since the game used line graphics.
int collide(int i, int j)	// Returns non-zero if i collided with j
{	
	if ( obj[i]->distance(*obj[j]) < (obj[i]->size() + obj[j]->size()) )
		{   
		// round objects approximation
		//cout << "collide: " << obj[i]->size() << "," << obj[j]->size() << "," << diff << endl;
		return 1;
		}

	return 0;
}

void blastpair(int i, int j)	// Generate random velocity vector v.	
// Add v to i, -v to j.			
{
	unsigned int c;	// for rand	
	double vx, vy;
	c = (rand()>>2)%360;
	
	vx = FastMath::cos( c );
	vy = FastMath::sin( c );

	obj[i]->addVel( vx, vy );
	obj[j]->addVel( -vx, -vy );
}

// dot product of 2 vectors	
#define dot(i,j)	(i.x*j.x + i.y*j.y)

// bounce - from xasteroids
// cause two objects to collide elastically	
void bounce(int i, int j )
{
double	temp;
Vector	vi, vj,		// velocity of objs i, j		
	ij,		// vector from center of i to center of j 
	vi_ij, vj_ij,	// velocity of obj along vector ij	
	vipij, vjpij,	// velocity perpendicular to ij		
	vi_ijf, vj_ijf;	// post-collision velocity along ij	

vi.x = obj[i]->xvel(); vi.y = obj[i]->yvel();
vj.x = obj[j]->xvel(); vj.y = obj[j]->yvel();
ij.x = obj[j]->x() - obj[i]->x(); ij.y = obj[j]->y() - obj[i]->y();
ij.mag = sqrt(ij.x*ij.x + ij.y*ij.y);
/*
Calculate velocities projected onto ij;
	vi_ij = vi*cos(a) = (vi dot ij) / |ij|		*/
vi_ij.mag = dot(vi, ij) / ij.mag;
vi_ij.x = (ij.x * vi_ij.mag) / ij.mag;
vi_ij.y = (ij.y * vi_ij.mag) / ij.mag;
vj_ij.mag = dot(vj, ij) / ij.mag;
vj_ij.x = (ij.x * vj_ij.mag) / ij.mag;
vj_ij.y = (ij.y * vj_ij.mag) / ij.mag;
if (vi_ij.mag - vj_ij.mag < 0)	/* Objs moving away from each other -
	Since objs are round (at least when bouncing), this means
	they are moving away from each other already.	*/
	return;
/*
Calculate component of velocities perpendicular to ij:
	|vipij| = |vi|*sin(a) = |vi x ij| / |ij|
Same as
	|vipij| = |vi|*cos(M_PI/2 - a) = (vi dot (perp. to ij)) / |ij|	*/
temp = vi.y*ij.x - vi.x*ij.y;	// - (cross product when 3rd coord is 0)
temp /= (ij.mag*ij.mag);
vipij.x = -ij.y*temp; vipij.y = ij.x*temp;
temp = (vj.x*ij.y - vj.y*ij.x) / (ij.mag*ij.mag);
vjpij.x = -ij.y*temp; vjpij.y = ij.x*temp;
/*
Calculate the linear elastic collision along ij:
	mass(i)*vi_ij + mass(j)*vj_ij = mass(i)*vi_ijf + mass(j)*vj_ijf
	vi_ij + vi_ijf = vj_ij + vj_ijf	(derived by dividing equation
	for conservation of kinetic energy
	 by eq. for cons. of momentum) */
temp = obj[i]->mass/obj[j]->mass;
vj_ijf.x = (temp * (2*vi_ij.x - vj_ij.x) + vj_ij.x) / (1 + temp);
vj_ijf.y = (temp * (2*vi_ij.y - vj_ij.y) + vj_ij.y) / (1 + temp);
vi_ijf.x = vj_ijf.x + vj_ij.x - vi_ij.x;
vi_ijf.y = vj_ijf.y + vj_ij.y - vi_ij.y;

/*
Now, given vi_ijf and vj_ijf, add them to the perpendicular
	components to get final velocity vectors		*/
obj[i]->setVel( vi_ijf.x + vipij.x, vi_ijf.y + vipij.y );
obj[j]->setVel( vj_ijf.x + vjpij.x, vj_ijf.y + vjpij.y );

}


// botline - modified from xasteroids
void botline() 
{	
	char text[70];
	int	y;
	
	y = HEIGHT-Ui::fontHeight();

	// new ship every 10000 points, weeee...
	if (score/10000 > oldscore/10000)
		{
		playerShip.addShip();
		oldscore = score;
		}
	
	sprintf(text, "Ships:%2d   Score:%6d   Shield:", 
	               playerShip.ships(), score );

	gl_setwritemode(WRITEMODE_MASKED);
	gl_write(0, y, text);
	gl_setwritemode(WRITEMODE_OVERWRITE);
	
	// show shield energy level if shield is on
	if (playerShip.shielded())
		{
		int l;
		l = (int)(30.0*playerShip.shieldPercent());
		
		gl_line( 262, y+3, 292   ,y+3, 254);
		gl_line( 262, y+4, 262+l ,y+4, 255);
		gl_line( 262, y+5, 262+l ,y+5, 255);
		gl_line( 262, y+6, 292   ,y+6, 254);
		}
}

void printss() {};

// upscore - from xasteroids
void upscore(int killer, int up)	// Only award score for things the player shot 
{	
	if (killer != ENEMYBUL && killer != SHIP)
		score = score + up;
}


// killast - modified from xasteroids
void killast(int killer, int i)
	// i = Asteroid # to kill	
{	

	int k=0, na=0, oldna=0;

	if (obj[i]->shape == ASTSHAPE1)
	{	na = nextast();		// Could put 6 lines in a sub 
		obj[na]->setPos( obj[i]->x(), obj[i]->y() );
		obj[na]->setVel( obj[i]->xvel(), obj[i]->yvel() );

		obj[na]->revive();
		obj[na]->shape = ASTSHAPE2;
		obj[na]->setBitmap(medast);
		obj[na]->mass = M_MED;
		
		obj[i]->shape = ASTSHAPE2;
		obj[i]->setBitmap(medast);
		obj[i]->mass = M_MED;
		blastpair(i, na);
		obj[i]->explode(30,12);
		numasts++;
		if (numasts == 2)	// Big asteroid was last remaining 
			upscore(killer, 25+level*2000);
		else	upscore(killer, 25);
	}
	else if (obj[i]->shape == ASTSHAPE2)
	{
		for (k = 0; k < 3; k++)
		{	oldna = na;
			na = nextast();
			obj[na]->setPos( obj[i]->x(), obj[i]->y() );
			obj[na]->setVel( obj[i]->xvel(), obj[i]->yvel() );

			obj[na]->revive();
			obj[na]->shape = ASTSHAPE3;
			obj[na]->setBitmap(smallast);
			obj[na]->mass = M_SMALL;
			if (k == 1) blastpair(oldna,na);
		}
		obj[i]->shape = ASTSHAPE3;
		obj[i]->setBitmap(smallast);
		obj[i]->mass = M_SMALL;
		blastpair(na, i);
		obj[i]->explode(20,10);
		if (numasts == 1) upscore(killer, 500*level);
		numasts = numasts + 3;
		upscore(killer, 50);
	}
	else if (obj[i]->shape == ASTSHAPE3)
	{	obj[i]->explode(10, 8);
		obj[i]->die(); numasts--; upscore(killer, 100);}
	else	// enemy {ship or bullet}	
	{	obj[i]->explode(9, 7);
		obj[i]->die(); upscore(killer, 500);}
}



//	Draw objects
void drawobjs()
	{
	int i;
	for (i = 0; i <= LASTOBJ; i++)
	if (obj[i]->isAlive())
		{
		obj[i]->draw();
		}
		
	Boom::draw();
	}	


// move all game objects, check for collisions
int moveobjs()
	{	
	int i, j, crash=0;	// Indexes

	Boom::tick();	// pass time for explosions

	// tell each object to pass 1 frame of time

	for (i = 0; i < LASTOBJ+1; i++)
		if (obj[i]->isAlive())
			obj[i]->tick();

	// check for collisions			
	
	for (i = 0; i < FBUL; i++)
	    if (obj[i]->isAlive())
	        {
		if (playerShip.isAlive() && collide(i, SHIP))
			{	
			if (playerShip.shielded()) 
				bounce(SHIP, i);
			else
				{	
				crash = 2;
				playerShip.explode(BMAX-1, 70);
				playerShip.die();
				killast(SHIP, i);
				continue;
				}	
			}
		for (j = ENEMYBUL; j < LASTBUL+1; j++)
			if (obj[j]->isAlive() && collide(i, j) &&
			   (j != ENEMYBUL || (i != ENEMYBUL && i != ENEMY)))
				{	
				obj[j]->die();	// Kill the bullet 
				// Don't have 2 bullets kill same asteroid
				if (obj[i]->isAlive()) killast(j,i);
				}
	        }
	 
	return crash;
	}



// fire - modified from xasteroids
void fire()
	{	
	double cosrot, sinrot;

	obj[nextbul]->revive();
	cosrot = FastMath::cos((int)playerShip.rot); 
	sinrot = FastMath::sin((int)playerShip.rot);
	obj[nextbul]->setPos( playerShip.x() + playerShip.size() * cosrot, 
	                      playerShip.y() + playerShip.size() * sinrot );
	                      
	obj[nextbul]->setVel( playerShip.xvel() + 10 * cosrot,
	                      playerShip.yvel() + 10 * sinrot );
	                      
	obj[nextbul]->rot = playerShip.rot;
	obj[nextbul]->setTime(WIDTH/11);	// loops before bullet expires	
	nextbul++; if (nextbul == LASTBUL+1) nextbul = FBUL;
	}

// return 1=easy, 4=medium, 8=hard
int selectLevel()
{
	Ui::drawToPhysical();
	gl_clearscreen(0);

	gl_write(24,25, "Please select starting skill level:");
	gl_write(128,80,"1 - Easy");
	gl_write(128,90,"2 - Medium");
	gl_write(128,100,"3 - Hard");
	
	while (1)
		switch (getchar()) {
			case '1': return 1;
			case '2': return 5;
			case '3': return 10;
			case 'q': return 0;
			case 'Q': return 0;
			}
return 0;
}

void showInfo() 
{
Ui::drawToPhysical();
gl_clearscreen(0);
gl_setpalette(&backScn);
back.put(0,0);

gl_setwritemode(WRITEMODE_MASKED);

gl_write(120,0,"Sasteroids");

gl_write(10,20,"Playing the game:");
gl_write(10,30,"");
gl_write(10,40,"   Key               Action");
gl_write(10,50,"  -----    --------------------------");
gl_write(10,60,"    z      turn ship left");
gl_write(10,70,"    x      turn ship right");
gl_write(10,80,"    m      fire");
gl_write(10,90,"    n      thrust");
gl_write(10,100,"    b      shield on, once per ship");
gl_write(10,110,"  SPACE    hyperspace, zap to another");
gl_write(10,120,"           part of the screen.");
gl_write(10,130,"    p      pause/resume");
gl_write(10,140,"    q      quit game");
gl_write(6,160,"Send bug reports, patches, sounds");
gl_write(6,170,"or cool bitmaps to pitzel@cs.sfu.ca");

gl_write(104,190,"(Press any key)");
gl_setwritemode(WRITEMODE_OVERWRITE);

};

void showTitle()
{
	Ui::drawToPhysical();

	gl_clearscreen(0);
	gl_setpalette(&titleScn);
	title.put(0,0);

	gl_setwritemode(WRITEMODE_MASKED);

	gl_write(80 , 80, VERSION );
	gl_write(110,105,"'i' for information");
	gl_write(110,115,"'h' for high scores");
	gl_write(110,125,"'s' to start game");
	gl_write(110,135,"'q' to quit");
	gl_setwritemode(WRITEMODE_OVERWRITE);
}


// get name for high scores list
String getHighScoreName()
{
char buf[21];

for(int i=0; i<21; i++) buf[i]=' ';    

Ui::drawToPhysical();

gl_clearscreen(0);

gl_write( 20, 30, "Whooohoo!");
gl_write( 20, 40, "You made the high score list.");

gl_write( 20, 60, "Please enter your name :" );

Ui::input( 20, 80, buf, 20 );

return String(buf);
}


// show high scores screen
void showScores( HiScore &s )
{
int i;
char buf[10];
String line;

Ui::drawToPhysical();
gl_clearscreen(0);
gl_setpalette(&backScn);
back.put(0,0);

gl_setwritemode(WRITEMODE_MASKED);
gl_write(120,0,"HIGH SCORES");

for(i=0; i<HiScoreListSize; i++)
	{
	sprintf(buf,"%d.",i+1);
	gl_write(40,40+15*i,buf);
	
	line = s[i];
	gl_write(70,40+15*i, (char *)(const char*)line );
	}

gl_write(104,190,"(Press any key)");
gl_setwritemode(WRITEMODE_OVERWRITE);
}


// game over - keep animation going for either 5 secs or user hits 'q'
void gameOverLoop()
{
const int loops = 10 * Timer::FrameRate();
int j;

gl_setwritemode(WRITEMODE_MASKED);

for(j=0; j<loops; j++)
	{
	if ( (vga_getkey()!=0) && (j>Timer::FrameRate()) ) return;

	moveobjs();

	//	Draw objects
	drawobjs();

	gl_write(120,100,"Game  Over");
	botline();
	
	Ui::updateScreen();
	gl_clearscreen(0);
	Timer::sync();
	}

gl_setwritemode(WRITEMODE_OVERWRITE);
}

	
// play a game..
void playGame()
{
	int	keyHit,showTimings=0;	    	
	char	text[70];		// for showTimings mode
		
	int pause = 0, 
	    i;

	char GameOver = 0;
	
	Boom::die();

	playerShip.ships(3);	// start with 3 ships
	score = 0; oldscore = -1;

	// get starting skill level
	level = selectLevel();

	numasts = 0;
		
	unsigned char c=0;
	playerShip.newShip();
	
        setBPcolormap(); // set palette to game bitmaps' colors 

	// all drawing takes place on the virtual screen 
	Ui::drawToVirtual();
	gl_clearscreen(0);
		
	Timer::init();	// get animation timer ready

	while (!GameOver)
	    {   
	    if (numasts==0) 
		{
		if (level<15) level++;
		makeasts();
		}

	    // for testing, ignore:
	    //long int t1=0,t2=0,cnt=0;
	    //showTimings=1;
	    
	    while ( (numasts) && (!GameOver) )
	    {	
	    	if (Joy0.ok()) Joy0.eval();
		keyHit = vga_getkey();

		switch (keyHit) 
			{
			case 'p': // Pause
			case 'P':
				pause = 1 - pause; 
				break;
			    
			case 't': // toggle show timings mode
			case 'T':
				showTimings = 1 - showTimings; 
				break;
				    
			case '+':   // cheat
				playerShip.addShip(); 
				break;
				    
			case 'q':  // quit
			case 'Q':
				if (Ui::yesNo("End This Game"))
			    		{
			    		GameOver = 1;
			    		}
			    	break;
			}

	        if (playerShip.isAlive() & !pause)
	            {
		    if (Joy0.ok())
		    	{
		    	if (Joy0.up())
		    		playerShip.thrust(4.0/FPS);
		    	else if (Joy0.down())
		    		playerShip.shieldOn();
		    	else if (Joy0.left())
		    		playerShip.rotLeft(1);
		    	else if (Joy0.right())
		    		playerShip.rotRight(1);
		    	
		    	if (Joy0.aPressed()) fire();
		    	if (Joy0.bPressed()) playerShip.hyper();
		    	}
		    	
		    switch (keyHit)
			{	
			case 'z':
			case 'Z': // TURN COUNTER CLOCK WISE
			    	playerShip.rotLeft(2);
			    	break;

			case 'x':
			case 'X': // TURN CLOCK WISE
			    	playerShip.rotRight(2);
			    	break;

			case 'n':  // THRUST
			case 'N':
			    	playerShip.thrust();
			    	break;
				    
			case 'm':  // FIRE
			case 'M':
			    	fire(); 
			    	break;
				    
			case ' ': // POOF!
			    	playerShip.hyper();
			    	break;

			case 'b': // Shield on
			case 'B':
			    	playerShip.shieldOn();
			    	break;
					
		    	}
		    }
		    
		if (!playerShip.isAlive() & !pause)
		    {
		    switch (keyHit)
			{				    
			case 's':	// start new ship 
				playerShip.newShip();
		    		break;
			}

		    if (Joy0.ok())
		    	{
		    	if (Joy0.aPressed()||Joy0.bPressed()) 
		    		playerShip.newShip();
		    	}
			
		     }

		if (!pause)
			{   
			moveobjs();

		   	//if ( (playerShip.ships()) && (score>0) ) 
		   	//	score--;	// timer effect	

			if (!playerShip.ships()) 
				{
		   		GameOver = 1;
		   		gameOverLoop();
		   		}
		   		
			i = (rand()>>8) & 255;
			if (!obj[ENEMY]->isAlive())
				{   
				if (i < level)
			    		{
			    		c = rand();
					if (c < level * 10) 
						((Enemy*)(obj[ENEMY]))->newShip(level, 10);
					}
				}
			}

		if (!GameOver)
			{
			drawobjs();

			if (!playerShip.isAlive())
			    	{
			    	gl_setwritemode(WRITEMODE_MASKED);

			    	gl_write( (WIDTH>>1) - 8*11,
			    	           HEIGHT>>1,
			    	           "Press 's' for next ship");
				gl_setwritemode(WRITEMODE_OVERWRITE);
				}
			}
					
		// either show frame timings or game stats on bottom line
		if (!showTimings)
			{
			botline();
			Ui::updateScreen(); gl_clearscreen(0);
			Timer::sync();   
			}
		else
			{
			// time how long to create one frame of animation
			Ui::updateScreen(); 
			gl_clearscreen(0);
			sprintf(text,"usec per frame: %d",  Timer::sync() );
			gl_write(0, HEIGHT-Ui::fontHeight(), text);
			}

			/* for Timing tests, ignore:
			t1 = Timer::sync();
			if (t1<0)  cout << t1 << " ";
			else 
			    	{
			    	t2 += t1;
				cnt++;
				}
				
			if (cnt==100)
				{
				GameOver=1;
				cout << "!" << t2/cnt << endl;
				}
			*/
			
		} //while (numasts)
	} //for(level..
}


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

	HiScore	scores("sast.scores");

	// joystick calibration, if joystick working
	if (Joy0.ok())
		Joy0.calibrate();

	uid_t cur_uid=getuid(); // init vga, ui stuff
	setreuid(0,-1);	        // svga init routine restores euid to uid,   
	Ui::init();		// but we want to keep euid as root for      
	setreuid(cur_uid,-1);	// writing to the hi-score file, so we do this
				// little bit of uid save/restoring.   

	FastMath::init();	// sin/cos tables

	// randomize using timer
	srand( (unsigned int) time(NULL) );

	titleScnInit();	 // define title screen bitmaps, color map
	bitmapsInit();	 // define bitmaps, color map 
	backScnInit();
	setBits();	 // scale asteroid bitmap for small asteroids,

	Ship::init();	// setup up player's ship
	
	initObjArray();	// init game objects

	Timer::setFrameRate( FPS );

	int done=0;
	
	showTitle();
	
    while(!done)
        {
	switch(getchar())
		{
		case 'h':
		case 'H': 
			showScores(scores);
			getchar();
			showTitle();
			break;
			
		case 'i':
		case 'I':
			showInfo();
			getchar();
			showTitle();
			break;
			
		case 's':
		case 'S':
			playGame();
			
        		// if score was good enough, add to high score list
        		if (scores.isHigh(score) != -1)
        			{
        			scores.add( getHighScoreName() , score );
        			showScores(scores);
				getchar();
				showTitle();
        			}
        		else	showTitle();
			break;
			
		case 'q':
		case 'Q':
			if (Ui::yesNo("Do you wish to quit"))
	   			done=1;
	   		else	showTitle();
	   		break;
	   	}	
	}

	// shutdown & restore text mode
	Ui::restore();

	return 0;
}
