
#include 	"ptk.h"
#include 	"KPTK.h"
#include	"KSound.h"

void			addALineOfBricks( void ) ;
void			displayWall( void ) ;
long			brickType  = 0 ;  //0 1 2 3  ( pattern )
long			ballColor = 0 ;

struct	sPreference	
{
long	score, play ;
};

sPreference	prefs={0,0} ;

KSound		*snd_down , *snd_break ,*snd_wheel , *snd_gameov ;
void		displayBat( void ) ;
void			resetBall( void ) ;
void			doBall( void ) ;
long			batX ;
void			doDifficulty( void )  ;

long			gScore, gHighscore ;

bool			gameOver = true ;
long			gameOverSteps = 0 ;
void			saveScores( void ) ;
void			loadScores( void ) ;

struct	sChiffre
{
char		c ;
short		x1,x2 ;
};

sChiffre  nombres[10]=
{
'0' , 10 ,23,
'1' , 28,35,
'2' , 41,52,
'3' , 55,67,
'4' , 70,81,
'5' , 85,96,
'6' , 99,111,
'7' , 115,125,
'8' , 128,140,
'9' , 143,155
};

void		displayValue( long value , long	x , long y ) ;

long		getCIndex( char c ) ;

long		getCIndex( char c )
{
long	i ;
	
	for ( i = 0 ; i <= 9 ; i++ )
	{
		if ( c == nombres[i].c )		return i;
	}
	
	return -1 ;
}

struct	sBall
{
	float		x1,y1 ;
};

//a blue ball and a red ball
sBall		ball[2] = { 173,126 , 230,126 } ;
float		ballX, ballY , speedX,speedY ;

struct	sBrick
{
	bool		alive ;
	short		type ;
	short		x1,y1,x2,y2 , dx, dy ;
	long		color ;
	float		alpha ;
};

sBrick		wallOfBricks[12*33] ;
void		resetWallOfBricks( void ) ;


KWindow	*gameWindow ;
KGraphic	*surf_panel = NULL , *surf_background , *surf_sprites;

void		displayTinyLogo( void ) ;
void		displayLogo( void ) ;

long		difficultyTimer = 0 ;
long		difficultyTimerStep = 0 ;
								
int WINAPI WinMain( HINSTANCE hInst, 	/*Win32 entry-point routine */
					HINSTANCE hPreInst, 
					LPSTR lpszCmdLine, 
					int nCmdShow )
{
hInst = hInst ;
hPreInst = hPreInst ;
lpszCmdLine = lpszCmdLine ;
nCmdShow = nCmdShow ;

	gameWindow = KPTK::createKWindow( K_OPENGL ) ;

	gameWindow->createGameWindow( 640,480,-1,true,"Nervous breakdown" );
	gHighscore = 0 ;
	loadScores( ) ;

	surf_panel = KPTK::createKGraphic( ) ;
	surf_panel->loadPicture( KMiscTools::makeFilePath( "data\\panel.tga" ) , true, true ) ;
	
	surf_sprites = KPTK::createKGraphic( ) ;
	surf_sprites->loadPicture( KMiscTools::makeFilePath( "data\\sprites.tga" ) , true, true ) ;
	
	srand( KMiscTools::getMilliseconds( ) ) ;
	
	surf_background = KPTK::createKGraphic( ) ;
	brickType = rand( ) % 4 ;
	
	if ( rand( ) % 2 )
	{
		surf_background->loadPicture( KMiscTools::makeFilePath( "data\\background1.tga" ) , true, true ) ;
		ballColor = 0 ;
	}
	else
	{
		surf_background->loadPicture( KMiscTools::makeFilePath( "data\\background2.tga" ) , true, true ) ;
		ballColor = 57 ;
	}

	snd_down = new KSound ;
	snd_down->loadSample( KMiscTools::makeFilePath( "data\\down.ogg" ) );
	snd_break  = new KSound ;
	snd_break->loadSample( KMiscTools::makeFilePath( "data\\break.ogg" ) );
	snd_break->setVolume( 50 ) ;
	snd_wheel = new KSound ;
	snd_wheel->loadSample( KMiscTools::makeFilePath( "data\\wall.ogg" ) );
	snd_gameov = new KSound ;
	snd_gameov->loadSample( KMiscTools::makeFilePath( "data\\gameover.ogg" ) );

	resetWallOfBricks(  ) ;
	resetBall( ) ;
	gScore = 0 ;

	gameOver = true ;
	gameOverSteps = 0 ;
	
	//main loop
	do
	{
		gameWindow->setDefaultWorldView( ) ;
		surf_background->blitAlphaRect( 0,0,surf_background->getWidth(),surf_background->getHeight(),20,23 ) ;

		//display the sprites behind the panel
		displayWall( ) ;
		doBall( ) ;
		displayBat( ) ;
	

		surf_panel->blitAlphaRect( 0,0,640,480,0,0 ) ;
		doDifficulty( ) ;
		displayValue( gScore , 635,333 ) ;
		displayValue( gHighscore , 635,259 ) ;
		displayLogo( )  ;
		displayTinyLogo( ) ;
		gameWindow->flipBackBuffer( ) ;
	}while( gameWindow->isQuit() == false ) ;
	
	saveScores( ) ;

	delete	snd_gameov ;
	delete	snd_wheel ;
	delete	snd_break ;
	delete	snd_down ;
	delete	surf_sprites ;
	delete	surf_panel ;
	delete	surf_background ;
	delete 	gameWindow ;

	return 0 ;
}

//the big logo
void		displayLogo( void )
{
static	float		fade = 0 ;
long	x , y ;

		if ( gameOver == false  && fade <= 0 )		
		{
			return ;
		}

		if ( gameOver == true )			
		{
				//first of all, scroll down
				for ( y = 0 ; y <=31 ; y++ )
				{
				for ( x = 0 ; x < 12 ; x++ )
				{
					if ( y == 31 )	wallOfBricks[x+y*12].alive= false ;					
					memcpy( &wallOfBricks[x+y*12] , &wallOfBricks[x+(y+1)*12] , sizeof( sBrick ) ) ;
				}
			}
		
			fade+=0.05f;
			if ( fade > 1) 	fade = 1 ;
		}
		else
		{
			fade-=0.1f;
			if ( fade < 0) 	fade = 0 ;
			
		}

		surf_sprites->blitAlphaRectFx( 0,174,289,262,130,150 ,0,1,fade) ;
		if ( KInput::isPressed( K_VK_ESCAPE )== ISDOWN	)
		{
			gameWindow->terminate( ) ;
		}
		
		if ( KInput::isPressed( K_VK_SPACE )== ISDOWN  || KInput::getLeftButtonState( ) )
		{
			if ( gameOver == true && snd_gameov->isPlaying() == false )
			{
				 KInput::waitForKeyRelease( K_VK_SPACE ) ;
			
				 resetWallOfBricks( ) ; 
				 resetBall( ) ;
				 gameOver = false ;
				 gScore = 0 ;
			}
		}
}


void		displayBat( void )
{
long	x,y ;

		x = KInput::getMouseX( ) ;
		y = KInput::getMouseY( ) ;
		if ( x < 17 )	x = 17 ;
		if ( x > 430 )	x = 430 ;
		batX = x ;
		
		surf_sprites->blitAlphaRect( 165,3,239,29 , x, 440 ) ;

}

void		displayTinyLogo( void )
{
//		surf_sprites->blitAlphaRect( 0,264,141,310,502,50 ) ;

}

//wall of bricks
void		resetWallOfBricks( void )
{
long		x , y ;

		difficultyTimer = 0 ;
		//every 500 add a line
		difficultyTimerStep = 500 ;


		for ( y = 0 ; y < 32 ; y++ )
		{
			for ( x = 0 ; x < 12 ; x++ )
			{
				wallOfBricks[x+y*12].alive = false ;
			}
		}

	addALineOfBricks( ) ;
	addALineOfBricks( ) ;
	addALineOfBricks( ) ;
	addALineOfBricks( ) ;
	addALineOfBricks( ) ;

}

//resets the ball
void			resetBall( void )
{
	ballX	= 280 ;
	ballY = 240 ;
	speedX = (rand() % 100) -50 ;
	speedX /= 20 ;
	speedY = -2 ;
}

void			doDifficulty( void ) 
{
float		ratio ;

	ratio = 	(float)difficultyTimer / (float)difficultyTimerStep ;

	surf_sprites->drawRect( 549,409,549+ratio*(float)(634-549),424,1,0.8f,0.8f,0.5f ) ;
	
//surf_sprites->drawRect( 549,407,549+ratio*(float)(634-549),425,1,1,1,0.8f ) ;
}


void			doBall( void ) 
{
sBall		*ballPtr ;	
	
	if ( gameOver == true )		return ;
	
	ballPtr = &ball[0] ;

	ballX += speedX ;
	if ( ballX <= 18 )
	{
		speedX *=  -1 ;	 
		snd_wheel->playSample(); 
		ballX = 18 ;
	}
	
	if ( ballX >= 487 )	
	{ 
		speedX *=  -1 ;	 
		snd_wheel->playSample(); 
		ballX = 487 ;
	}
	
	ballY += speedY ;
	if ( ballY <= 18 )	
	{
		ballY	 = 18 ;
		 speedY *=  -1  ;	 
		 snd_wheel->playSample();
	}
	
	//batX
	
	//dead
	if ( ballY >= 433 &&  ballY <= 450 && (ballX+8) >= batX  && ballX <=(batX+74)  )	
	{
		 snd_wheel->playSample();
		speedY *=  -1.05f ;
		//patch the weird bug
		if ( speedY > 0 ) speedY *=-1 ;
		
		speedX = ((ballX+8)-batX)-(74/2) ;
		speedX /= 37.0f ;
		speedX *= 5.0f ;
		
		if ( speedY > 7 ) speedY = 7;
		if ( speedX > 5 ) speedX = 5;
		if ( speedY < -7 ) speedY = -7;
		if ( speedX < -5 ) speedX = -5;
	}
	else
	{
		if ( ballY > 450 )
		{
			gameOver = true ;
			snd_gameov->playSample( ) ;
		}
	}
	
	surf_sprites->blitAlphaRect( 205+ballColor,132,222+ballColor,146 , ballX , ballY ) ;

}



void			displayWall( void ) 
{
long	x,y ;
sBrick	*brickPtr ;
float		bx1, by1 ;

		if ( gameOver == false )
		{
			difficultyTimer++ ;
			if ( difficultyTimer > difficultyTimerStep  )
			{
				difficultyTimerStep-=10 ;
				if ( difficultyTimerStep <= 30 )difficultyTimerStep = 30 ;
				difficultyTimer = 0 ;
				addALineOfBricks( ) ;
			}
		}
		
		bx1 = (ballX+8)+speedX ;
		by1 = (ballY+7)+speedY ;
		
		//surf_sprites->drawRect( bx1,by1,bx2,by2 ,0,1,0,0.5f ) ;

		//first of all, scroll down
		for ( y = 0 ; y <32 ; y++ )
		{
			for ( x = 0 ; x < 12 ; x++ )
			{
				brickPtr = &wallOfBricks[x+y*12] ;
				if ( brickPtr->alive == false )		continue ;
				if ( y == 31 && gameOver == false )		
				{
					gameOver = true ;
				}
				
				brickPtr->dx = 	20+x*40 ;
				brickPtr->dy = 	20+y*15 ;
				surf_sprites->blitAlphaRect( brickPtr->x1, brickPtr->y1, brickPtr->x2 , brickPtr->y2 	 , 	brickPtr->dx  , 	brickPtr->dy ) ; 
				if ( bx1 < brickPtr->dx )			continue ;
				if ( bx1 > (brickPtr->dx+40) )		continue ;
				if ( by1 < brickPtr->dy )				continue ;
				if ( by1 > (brickPtr->dy+15) )		continue ;
				brickPtr->alive = false ;
				speedY *=-1 ; 
				snd_break->playSample( ) ;
				gScore++ ;
			}
		}
		
		if ( gScore > gHighscore )
		{
			gHighscore = gScore ;
		}
}



void		displayValue( long value , long	x , long y ) 
{
char		buffer[50] ;
long		i , l , w , idx;

	sprintf( buffer , "%d" , value ) ;
	l = strlen( buffer ) ;
	//calculates the width
	w = 0 ;
	for ( i = 0 ; i < l ; i++ )
	{
		idx = getCIndex( buffer[i] ) ;
		w+= (nombres[idx].x2-nombres[idx].x1) ;
	}
		
	x-=w ;	
	for ( i = 0 ; i < l ; i++ )
	{
		idx = getCIndex( buffer[i] ) ;
		surf_sprites->blitAlphaRect( nombres[idx].x1 , 154 , nombres[idx].x2 , 171, x , y ) ;
		x += (nombres[idx].x2-nombres[idx].x1) ;		
	}

		
}



void		addALineOfBricks( void )
{
long	x,y ;
sBrick	*brickPtr ;
long		color ;

	if ( snd_down->isPlaying() == false )
	{
		snd_down->playSample( ) ;
	}

		//first of all, scroll down
		for ( y = 32 ; y >= 1 ; y-- )
		{
			for ( x = 0 ; x < 12 ; x++ )
			{
				memcpy( &wallOfBricks[x+y*12] , &wallOfBricks[x+(y-1)*12] , sizeof( sBrick ) ) ;
			}
		}

	//add a line in 0
	color = rand( ) % 9 ;
	for ( x = 0 ; x < 12 ; x++ )
	{
		brickPtr = &wallOfBricks[x] ;
		brickPtr->alive = true ;
		brickPtr->x1 = 40*brickType ;
		brickPtr->x2 = 41+40*brickType ;
		brickPtr->y1 = 15*color ;
		brickPtr->y2 = 15+15*color ;
		brickPtr->alpha = 0 ;
	}

}

void		loadScores( void )
{
FILE	*f ;
	f= fopen( KMiscTools::makeFilePath( "scores.raw" ) , "rb" ) ;
	if ( f == NULL )	
	{
		prefs.score = 0 ;
		prefs.play = 0 ;
		return ;
	}
	if ( prefs.play  < 0 )	prefs.play  = 0 ;
	if ( prefs.play  > 10 )	prefs.play  = 10 ;
	fread( &prefs, 1 , sizeof ( sPreference ) , f ) ;
	gHighscore = prefs.score  ;

	fclose( f );
}

void		saveScores( void )
{
FILE	*f ;

	prefs.play++ ;

	f= fopen( KMiscTools::makeFilePath( "scores.raw" ) , "wb" ) ;
	if ( f == NULL )	return ;
	prefs.score = gHighscore ;
	if ( prefs.play  < 0 )	prefs.play  = 0 ;
	if ( prefs.play  > 10 )	prefs.play  = 10 ;

	fwrite( &prefs, 1 , sizeof ( sPreference ) , f ) ;
	fclose( f );
}
