/* 
** Created by wplaat
**
** Release Notes:
**
**   12/11/2008 version 0.91
**   - Add high Score screen
**   - High scores are save (xml format) on sdcard.
**   - Add better game sound effects
**
**   02/11/2008 version 0.9
**   - Add three welcome screens
**   - Improve game images
**   - Add help screen (Minus button)
**   - Created new homebrew game logo
**
**   31/10/2008 version 0.8
**   - Add support for Wii Classic Controller 
**   - Add two bars on the gameboard.
**   - Add game level six
**
**   27/10/2008 version 0.7
**   - Improve Goodbye screen
**   - Add support for 60Hz screens
**
**   23/10/2008 version 0.6
**   - Fix two bugs in result screen.
**   - Improve game images.
**   - Replace two music tracks.
**   - Add sourcode to wiibrew project
**
**   22/10/2008 version 0.5
**   - Add game score overview screen
**   - Start ball position is random now.
**   - Add (impossible) level five.
**
**   21/10/2008 Version 0.4
**   - Add 4 game levels.
**   - Improve gameboard layout.
**   - Add game clock.
**   - Add pause (+) button.
**   - Add game jpg pictures.
**
**   20/10/2008 Version 0.3
**   - First release for public us.
**   - Add nice start screen.
**   - Ball speed can now be controlled by A and B buttons.
**   - 10 tracks of background music added and can be controlled by 1 and 2 buttons. 
**
**   16/10/2008 Version 0.2
**   - Improve paddle control.
**
**   10/10/2008 Version 0.1
**   - Start programming. 
**   - My first Wii Game.
*/

#include <stdio.h>
#include <gccore.h>
#include <ogcsys.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h> 
#include <wiiuse/wpad.h>
#include <gcmodplay.h> 
#include <jpeg/jpgogc.h>
#include <gccore.h>
#include <fat.h>
#include <mxml.h>
#include <snd.h> 

#include <ft2build.h> 
#include FT_FREETYPE_H 

#include "music0_mod.h"
#include "music1_mod.h"
#include "music2_mod.h"
#include "music3_mod.h"
#include "music4_mod.h"
#include "music5_mod.h"
#include "music6_mod.h"
#include "music7_mod.h"
#include "music8_mod.h"
#include "music9_mod.h"
#include "effect1_wav.h"
#include "effect2_wav.h"
#include "effect3_wav.h"
#include "light.h"
#include "network.h"

// -----------------------------------------------------------
// DEFINES
// -----------------------------------------------------------

#define VERSION            "Pong2 v0.91"
#define RELEASE_DATE       "12-11-2008" 
#define MAX_SCORE          10
#define MAX_LEVEL          5
#define START_DELAY        1
#define HIGHSCORE_FILENAME "highscore.xml"

#define BUTTON_ANY      (WPAD_BUTTON_A     | WPAD_BUTTON_B)
#define BUTTON_A        (WPAD_BUTTON_A     | WPAD_CLASSIC_BUTTON_A)
#define BUTTON_B        (WPAD_BUTTON_B     | WPAD_CLASSIC_BUTTON_B)
#define BUTTON_1        (WPAD_BUTTON_1     | WPAD_CLASSIC_BUTTON_X)
#define BUTTON_2        (WPAD_BUTTON_2     | WPAD_CLASSIC_BUTTON_Y)
#define BUTTON_HOME     (WPAD_BUTTON_HOME  | WPAD_CLASSIC_BUTTON_HOME)
#define BUTTON_UP       (WPAD_BUTTON_UP    | WPAD_CLASSIC_BUTTON_UP)
#define BUTTON_DOWN     (WPAD_BUTTON_DOWN  | WPAD_CLASSIC_BUTTON_DOWN)
#define BUTTON_LEFT     (WPAD_BUTTON_LEFT  | WPAD_CLASSIC_BUTTON_LEFT)
#define BUTTON_RIGHT    (WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT)
#define BUTTON_PLUS     (WPAD_BUTTON_PLUS  | WPAD_CLASSIC_BUTTON_PLUS)
#define BUTTON_MINUS    (WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS)

// -----------------------------------------------------------
// PROTYPES
// -----------------------------------------------------------

void initGame();
void button1x(int channel);
void button2y(int channel);
void buttonHome(int channel);
void musicSelect(int modCounter, bool show);
void initBall(boolean direction);
void initLevel(int gameLevel);
void storeScore(int gameLevel);
void screenScore(int channel);
void exitToHomebrewChannel(void);
void exitResetWii(void);
void screenHelp(int channel);
void loadHighScoreFile(char* filename);
void saveHighScoreFile(char* filename);
void freeTypePrintf(int pen_x, int pen_y, u32 color, int fontSize, char *text,...);

// -----------------------------------------------------------
// TYPEDEFS
// -----------------------------------------------------------

typedef struct
{
   time_t localTime;
   time_t levelTime; 
   int    player1Score; 
   int    player2Score;
} score;

score scores[MAX_LEVEL+1];
score highscores[MAX_LEVEL+1];

// -----------------------------------------------------------
// VARIABLES
// -----------------------------------------------------------

u32 *frameBuffer[1] = {NULL};
static GXRModeObj *rmode = NULL;

static MODPlay snd1;

int  xMin;
int  yMin;
int  xMax;
int  yMax;
int  offset = 1;
int  scrollRange=100;

int  xBal;
int  xBalPrev;
bool xBalMove; 
int  yBal;
int  yBalPrev;
bool yBalMove;    
int  balCounter;
int  lastSecond;

int  irX;
int  irY;
int  irXPrev;
int  irYPrev;
int  irFlag=true;
	
int  xPaddle[2];
int  xPaddlePrev[2];
int  yPaddle[2];
int  yPaddlePrev[2];
int  lPaddle[2];

int  delay;
int  leftScore;
int  rightScore;
int  gameLevel;
int  modCounter=0;
time_t startTime;

int  xBar[2];
int  yBar[2];
int  lBar[2];

// level0 image
extern char     pic0data[];
extern int      pic0length;

// level1 image
extern char     pic1data[];
extern int      pic1length;

// level2 image
extern char     pic2data[];
extern int      pic2length;

// level3 image
extern char     pic3data[];
extern int      pic3length;

// gameover image
extern char     pic4data[];
extern int      pic4length;

// goodbye image
extern char     pic5data[];
extern int      pic5length;

// game score image
extern char     pic6data[];
extern int      pic6length;

// level4 image
extern char     pic7data[];
extern int      pic7length;

// Welcome1 image
extern char     pic8data[];
extern int      pic8length;

// GetReady image
extern char     pic9data[];
extern int      pic9length;

// level5 image
extern char     pic10data[];
extern int      pic10length;

// help image
extern char     pic11data[];
extern int      pic11length;

// welcome2 image
extern char     pic12data[];
extern int      pic12length;

// welcome3 image
extern char     pic13data[];
extern int      pic13length;

// high Score image
extern char     pic14data[];
extern int      pic14length;

// banner image
extern char     pic15data[];
extern int      pic15length;

// -----------------------------------------------------------
// IN CONCEPT VARIABLES
// -----------------------------------------------------------

// TryeType Library variables
FT_Library library=NULL;  /* handle to library */  
FT_Face face=NULL;        /* handle to face object */        
FT_GlyphSlot slot;        
FT_Bitmap *image;

// -----------------------------------------------------------
// SCREEN ACTIONS
// -----------------------------------------------------------

void screenClear()
{
   int x;
   int y;

   // Clear Screen
   for (x=xMin+offset; x<=xMax-offset; x++)
   {	
      for (y=yMin+2+offset; y<=yMax-offset; y++)
      {	
	     printf("\x1b[%d;%dH%c",y,x,255);	
      } 
   }
   
   // Clear bars
   printf("\x1b[%d;%dH%c",yBar[0],xBar[0],205);
   printf("\x1b[%d;%dH%c",yBar[1],xBar[1],205);		
}

void drawTime()
{
  struct tm *local;
  time_t currentTime = time(NULL)-startTime;  
  local = localtime(&currentTime);
  if (local->tm_sec!=lastSecond)
  {   
    printf("\x1b[%d;%dH%02d:%02d:%02d", yMax + offset, 53, local->tm_hour, local->tm_min, local->tm_sec);
	lastSecond=local->tm_sec;
  }
}

void drawScore(int right, int left)
{
   printf("\x1b[%d;%dH%03d", yMax + 1, 2, right);
   printf("\x1b[%d;%dH%03d", yMax + 1, 75, left); 
}

void drawGameLevel(int level)
{
   printf("\x1b[%d;%dH%d", yMax + offset, 25, level);
}

void drawMusicSelect(int modCOunter, bool show)
{
   if (show)
   {  
     if (modCounter==10)
     {
       printf("\x1b[%d;%dH  Music Off   ", yMax + offset, xMin+34);
     }
     else
     {
       printf("\x1b[%d;%dHMusic Track %d ", yMax + offset, xMin+34, modCounter+1);
     }  
   }
}


void drawPaddle(int yPos, int yPosPrev, int xPos, int xPosPrev, int padHeigth, int channel)
{
   int y;
   
   for (y=yPosPrev-padHeigth; y<=yPosPrev+padHeigth; y++)
   {	
	   printf("\x1b[%d;%dH%c",y,xPosPrev,255);	
   }  
	  
   for (y=yPos-padHeigth; y<=yPos+padHeigth; y++)
   {
	  printf("\x1b[%d;%dH%c",y,xPos,219);	
   }
   
   yPaddlePrev[channel]=yPos;
   xPaddlePrev[channel]=xPos;
}

void drawBar(void)
{
   int y=0;
   int bar=0;
   
   // Top bar
   if (lBar[bar]>0)
   {
     printf("\x1b[%d;%dH%c",yBar[bar],xBar[bar],203);	
     for (y=yBar[bar]+1; y<yBar[bar]+lBar[bar]; y++)
     {
        printf("\x1b[%d;%dH%c",y,xBar[bar],186);	
     }
   }
   
   // Bottom bar
   bar=1;
   if (lBar[bar]>0)
   {
      printf("\x1b[%d;%dH%c",yBar[bar],xBar[bar],202);	
      for (y=yBar[bar]-1; y>yBar[bar]-lBar[bar]; y--)
      {
         printf("\x1b[%d;%dH%c",y,xBar[bar],186);	
      }
   }
}

void drawBal(int x, int y, int xPrev, int yPrev)
{
   printf("\x1b[%d;%dH%c",y,x,48);	

   if ((y!=yPrev) || (x!=xPrev))
   {
      printf("\x1b[%d;%dH%c",yPrev,xPrev,255);
   }
}

void drawBoard(void)
{
	int x;
	int y;
	
	// The console understands VT terminal escape codes
	// This positions the cursor on row 2, column 0
	// we can use variables for this with format codes too
	// e.g. printf ("\x1b[%d;%dH", row, column );
	
	printf("\x1b[%d;%dH%c", yMin, xMin, 201);		   
	for (x=(xMin+offset); x<=(xMax-offset); x++) printf("\x1b[%d;%dH%c", yMin, x, 205);	
	printf("\x1b[%d;%dH%c", yMin, xMax, 187);
	
	printf("\x1b[%d;%dH%c", yMin+1, xMin, 186);	
	printf("\033[01;30;46m\x1b[%d;%dH%s%s", yMin+1, 2, VERSION,"                      ");
	printf("\033[01;30;46m\x1b[%d;%dH%s", yMin+1, 32, "Created by wplaat                   ");
	printf("\033[01;30;46m\x1b[%d;%dH%s%s", yMin+1, xMax-11, RELEASE_DATE, " ");
	printf("\x1b[%d;%dH%c", yMin+1, xMax, 186);
	   
	printf("\x1b[%d;%dH%c", yMin+2, xMin, 204);		   
	for (x=(xMin+offset); x<=(xMax-offset); x++) printf("\x1b[%d;%dH%c", yMin+2, x, 205);	
	printf("\x1b[%d;%dH%c", yMin+2, xMax, 185);
	
	for (y=(yMin+2+offset); y<=(yMax-offset); y++) printf("\x1b[%d;%dH%c", y, xMin, 186);	
	for (y=(yMin+2+offset); y<=(yMax-offset); y++) printf("\x1b[%d;%dH%c", y, xMax, 186);	
	
	printf("\x1b[%d;%dH%c", yMax, xMin, 204);	
	for (x=(xMin+offset); x<=(xMax-offset); x++) printf("\x1b[%d;%dH%c", yMax, x, 205);	
	printf("\x1b[%d;%dH%c", yMax, xMax, 185);	
		
	printf("\x1b[%d;%dH%c", yMax+offset, xMin, 186);	
	printf("\x1b[%d;%dH%03d Human         ", yMax + offset, 2, leftScore);
	printf("\x1b[%d;%dHLevel %d                                    ", yMax + offset, 19, gameLevel);
	printf("\x1b[%d;%dH00:00:00         ", yMax + offset, 53);
	printf("\x1b[%d;%dHComputer %03d", yMax + offset, xMax-13, rightScore);
	    
	printf("\x1b[%d;%dH%c", yMax+2, xMin, 200);	
	for (x=(xMin+offset); x<=(xMax-offset); x++) printf("\x1b[%d;%dH%c", yMax+2, x, 205);	
	printf("\x1b[%d;%dH%c", yMax+2, xMax, 188);	
	
	printf("\x1b[%d;%dH%c", yMax, 15, 203);	
	printf("\x1b[%d;%dH%c", yMax+offset, 15, 186);	
	printf("\x1b[%d;%dH%c", yMax+2, 15, 202);
	
	printf("\x1b[%d;%dH%c", yMax, 29, 203);	
	printf("\x1b[%d;%dH%c", yMax+offset, 29, 186);	
	printf("\x1b[%d;%dH%c", yMax+2, 29, 202);
	
	printf("\x1b[%d;%dH%c", yMax, 50, 203);	
	printf("\x1b[%d;%dH%c", yMax+offset, 50, 186);	
	printf("\x1b[%d;%dH%c", yMax+2, 50, 202);
	
	printf("\x1b[%d;%dH%c", yMax, 63, 203);	
	printf("\x1b[%d;%dH%c", yMax+offset, 63, 186);	
	printf("\x1b[%d;%dH%c", yMax+2, 63, 202);
	
	printf("\x1b[%d;%dH%c", yMax+offset, xMax, 186);    
}


void drawImage(char *pictureData, int pictureLength, int x, int y )
{
    JPEGIMG         jpeg;
    int             row,
                    col,
                    pix,
                    offset;
    unsigned int   *jpegout;

    memset(&jpeg, 0, sizeof(JPEGIMG));

    jpeg.inbuffer = pictureData;
    jpeg.inbufferlength = pictureLength;

    JPEG_Decompress(&jpeg);
	
    pix = 0;

    jpegout = (unsigned int *) jpeg.outbuffer;

    offset=y*320;
    for (row = 0; row < jpeg.height; row++)
    {
	    for (col = 0; col < (jpeg.width >> 1); col++)
		{
		   //if ((row==0) && (col==0)) printf("\x1b[%d;%dH   %x ", 1, 1,jpegout[pix]);
	       frameBuffer[0][offset + col + x] = jpegout[pix++];
		}
	    offset+=320;
    }

    free(jpeg.outbuffer);
}

void screenLevel(int level)
{
   int i;
   boolean flag = true;
		
   screenClear();  
    
   WIILIGHT_TurnOn();
   WIILIGHT_SetLevel(255);
		   		     
   switch (level)
   {
	   case 0: for (i=0; i<(scrollRange/2); i=i+4) 
	           {
			      drawImage(pic9data, pic9length, 10, 70+i );
				  //freeTypePrintf(20, 170+(scrollRange/2), 0x80ff80, 65, "Get Ready");
				  
			      drawImage(pic0data, pic0length, 10, 220+i);			
				  //freeTypePrintf(50, 320+(scrollRange/2), 0x80ff80, 65, "Level 0");
			   }
			   break;

	   case 1: for (i=0; i<(scrollRange/2); i=i+4) 
	           {
				  drawImage(pic9data, pic9length, 10, 70+i);
	              drawImage(pic1data, pic1length, 10, 220+i );			   
			   }
			   printf("\x1b[%d;%dH%s", 6, xMin+28, "PLAYER 1 (HUMAN) HAS WON!");
			   break;

	   case 2: for (i=0; i<(scrollRange/2); i=i+4) 
	           {
			      drawImage(pic9data, pic9length, 10, 70+i );
		          drawImage(pic2data, pic2length, 10, 220+i );
			   }
			   printf("\x1b[%d;%dH%s", 6, xMin+28, "PLAYER 1 (HUMAN) HAS WON!");
			   break;

	   case 3: for (i=0; i<(scrollRange/2); i=i+4) 
	           {
			      drawImage(pic9data, pic9length, 10, 70+i);
		          drawImage(pic3data, pic3length, 10, 220+i );
			   }
			   printf("\x1b[%d;%dH%s", 6, xMin+28, "PLAYER 1 (HUMAN) HAS WON!");
			   break;
			   
	   case 4: for (i=0; i<(scrollRange/2); i=i+4) 
	           {
			      drawImage(pic9data, pic9length, 10, 70+i );
		          drawImage(pic7data, pic7length, 10, 220+i );
			   }
			   printf("\x1b[%d;%dH%s", 6, xMin+28, "PLAYER 1 (HUMAN) HAS WON!");
			   break;
			   
	    case 5: for (i=0; i<(scrollRange/2); i=i+4) 
	           {
			      drawImage(pic9data, pic9length, 10, 70+i );
		          drawImage(pic10data, pic10length, 10, 220+i );
			   }
			   printf("\x1b[%d;%dH%s", 6, xMin+28, "PLAYER 1 (HUMAN) HAS WON!");
			   break;
   }			   
		
   // Handle button events	 
   while ( flag )
   {
      WPAD_ScanPads (); 
	
      if (WPAD_ButtonsDown(WPAD_CHAN_0) & BUTTON_A) flag=false; 	  
	  if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_1 ) button1x(WPAD_CHAN_0);	
	  if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_2 ) button2y(WPAD_CHAN_0);		  
	  if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_HOME ) buttonHome(WPAD_CHAN_0);
   }
  		
   WIILIGHT_SetLevel(1);
   WIILIGHT_TurnOn();
   WIILIGHT_TurnOff();
   
   startTime = time(NULL);
   
   screenClear();
   drawBar();
}

void screenGameOver(int channel, boolean player1Wins)
{
   int i;
   boolean flag = true;
   
   screenClear();	
   for (i=0; i<scrollRange; i=i+4) 
   {
      drawImage(pic4data, pic4length, 10, 70+i );
   }
   
   if (player1Wins)
   {	 
	  printf("\x1b[%d;%dH%s", 8, xMin+28, "PLAYER 1 (HUMAN) HAS WON!");
   }	 
   else
   {
      printf("\x1b[%d;%dH%s", 8, xMin+28, "PLAYER 2 (COMPUTER) HAS WON!");	
   }
			 
   storeScore(gameLevel);
  	
   // Handle buttons events
   while ( flag )
   {
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 
		if (WPAD_ButtonsHeld(channel) & BUTTON_HOME ) buttonHome(channel);
		if (WPAD_ButtonsHeld(channel) & BUTTON_1 ) button1x(channel);	
		if (WPAD_ButtonsHeld(channel) & BUTTON_2 ) button2y(channel);		
   }
	   
   screenScore(channel);	
}


void screenWelcome1(int channel)
{
   boolean flag = true;
   
   drawImage(pic8data, pic8length, 0, 0 );
   //openNetwork();
	   	
   // Handle buttons events
   while ( flag )
   {
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 	
   }
}

void screenWelcome2(int channel)
{
   boolean flag = true;
   
   drawImage(pic12data, pic12length, 0, 0 );
   	   	
   // Handle buttons events
   while ( flag )
   {
        //sendRequest();
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 	
   }
}

void screenWelcome3(int channel)
{
   boolean flag = true;
   
   drawImage(pic13data, pic13length, 0, 0 );
		   	
   // Handle buttons events
   while ( flag )
   {		
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 	
   }
   //closeNetwork();
}


void screenPause(int channel)
{
   boolean flag = true;

   printf("\x1b[%d;%dH%s", (yMax/2)+1, xMin+38, "PAUSE");  
 
   // Handle buttons events   
   while ( flag )
   {
		WPAD_ScanPads(); 
	
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 		
		if (WPAD_ButtonsHeld(channel) & BUTTON_1 ) button1x(channel);		
		if (WPAD_ButtonsHeld(channel) & BUTTON_2 ) button2y(channel);			
		if (WPAD_ButtonsHeld(channel) & BUTTON_HOME ) buttonHome(channel);
	  
		drawTime();
   }  
   screenClear();
   drawBar();
}

void screenHelp(int channel)
{
   boolean flag = true;
   
   screenClear();	
   drawImage(pic11data, pic11length, 10, 80 );
   			   	
   // Handle buttons events
   while ( flag )
   {
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 
		if (WPAD_ButtonsHeld(channel) & BUTTON_HOME ) buttonHome(channel);
		if (WPAD_ButtonsHeld(channel) & BUTTON_1 ) button1x(channel);	
		if (WPAD_ButtonsHeld(channel) & BUTTON_2 ) button2y(channel);		
		
		drawTime();
   }
   screenClear();
   drawBar();

}
   
void screenHighScore(int channel)
{
   int i;
   int yoffset=14;
   boolean flag = true;
   struct tm *local;
   struct tm *level;
   
   // Check if highscore is reached
   for (i=0; i<=MAX_LEVEL; i++)
   {
      if (
	        (scores[i].player1Score>scores[i].player2Score) &&
	        (  (highscores[i].levelTime==0) ||
	           (highscores[i].levelTime>scores[i].levelTime) ||
	           ((highscores[i].levelTime==scores[i].levelTime) && (highscores[i].player1Score>scores[i].player1Score))
			) 
		 )
	  {
	      highscores[i].localTime=scores[i].localTime;
	      highscores[i].levelTime=scores[i].levelTime;
		  highscores[i].player1Score=scores[i].player1Score;
		  highscores[i].player2Score=scores[i].player2Score;
	  }
   }
   saveHighScoreFile(HIGHSCORE_FILENAME);
   
   screenClear();
   drawImage(pic14data, pic14length, 10, 60 );
   
   printf("\x1b[%d;%dH%s", yoffset, 8,    "Level");
   printf("\x1b[%d;%dH%s", yoffset+1, 8,  "=====");
   printf("\x1b[%d;%dH%s", yoffset, 18,   "Current Date");
   printf("\x1b[%d;%dH%s", yoffset+1, 18, "============");
   printf("\x1b[%d;%dH%s", yoffset, 42,   "Level Time");
   printf("\x1b[%d;%dH%s", yoffset+1, 42, "==========");
   printf("\x1b[%d;%dH%s", yoffset, 55,   "Human");
   printf("\x1b[%d;%dH%s", yoffset+1, 55, "=====");
   printf("\x1b[%d;%dH%s", yoffset, 64,   "Computer");
   printf("\x1b[%d;%dH%s", yoffset+1, 64, "========");
	   
   for (i=0; i<=MAX_LEVEL; i++)
   {	   
	  //if (highscores[i].levelTime!=0)
	  {
		printf("\x1b[%d;%dH%d", yoffset+i+2, 8, i);
	   	   
		local = localtime(&highscores[i].localTime);
		if (local->tm_year+1900!=1970)
		{
		   printf("\x1b[%d;%dH%02d-%02d-%04d %02d:%02d:%02d", yoffset+i+2, 18, 
			  local->tm_mday, local->tm_mon+1, local->tm_year+1900, local->tm_hour, local->tm_min, local->tm_sec);
	    }
		else
		{
		   printf("\x1b[%d;%dH%02d-%02d-%04d %02d:%02d:%02d", yoffset+i+2, 18, 0, 0, 0, 0, 0, 0);	
		}

		level = localtime(&highscores[i].levelTime);
		printf("\x1b[%d;%dH%02d:%02d:%02d", yoffset+i+2, 42, level->tm_hour, level->tm_min, level->tm_sec);
		
		printf("\x1b[%d;%dH%d", yoffset+i+2, 55, highscores[i].player1Score);
		printf("\x1b[%d;%dH%d", yoffset+i+2, 64, highscores[i].player2Score);
	  }
   }
   
   printf("\x1b[%d;%dH%s", yoffset+i+4, 12, "    High scores can be posted on the following url     ");
   printf("\x1b[%d;%dH%s", yoffset+i+5, 12, "           http://wiibrew.org/wiki/Talk:Pong2          ");
      
   // Handle buttons events   
   while ( flag )
   {
		WPAD_ScanPads(); 
	
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 		
		if (WPAD_ButtonsHeld(channel) & BUTTON_1 ) button1x(channel);	
		if (WPAD_ButtonsHeld(channel) & BUTTON_2 ) button2y(channel);			
		if (WPAD_ButtonsHeld(channel) & BUTTON_HOME ) buttonHome(channel);
   }  
  	
   initGame();
   initLevel(gameLevel);
   initBall(true);
   drawScore(leftScore, rightScore);
   
   screenLevel(gameLevel);	
}

void screenScore(int channel)
{
   int i;
   int yoffset=14;
   boolean flag = true;
   struct tm *local;
   struct tm *level;

   screenClear();
   drawImage(pic6data, pic6length, 10, 60 );
   
   printf("\x1b[%d;%dH%s", yoffset, 8,    "Level");
   printf("\x1b[%d;%dH%s", yoffset+1, 8,  "=====");
   printf("\x1b[%d;%dH%s", yoffset, 18,   "Current Date");
   printf("\x1b[%d;%dH%s", yoffset+1, 18, "============");
   printf("\x1b[%d;%dH%s", yoffset, 42,   "Level Time");
   printf("\x1b[%d;%dH%s", yoffset+1, 42, "==========");
   printf("\x1b[%d;%dH%s", yoffset, 55,   "Human");
   printf("\x1b[%d;%dH%s", yoffset+1, 55, "=====");
   printf("\x1b[%d;%dH%s", yoffset, 64,   "Computer");
   printf("\x1b[%d;%dH%s", yoffset+1, 64, "========");
	   
   for (i=0; i<=gameLevel; i++)
   {	   
		printf("\x1b[%d;%dH%d", yoffset+i+2, 8, i);
	   
		local = localtime(&scores[i].localTime);
		printf("\x1b[%d;%dH%02d-%02d-%04d %02d:%02d:%02d", yoffset+i+2, 18, 
			local->tm_mday, local->tm_mon+1, local->tm_year+1900, local->tm_hour, local->tm_min, local->tm_sec);

		level = localtime(&scores[i].levelTime);
		printf("\x1b[%d;%dH%02d:%02d:%02d", yoffset+i+2, 42, level->tm_hour, level->tm_min, level->tm_sec);
		
		printf("\x1b[%d;%dH%d", yoffset+i+2, 55, scores[i].player1Score);
		printf("\x1b[%d;%dH%d", yoffset+i+2, 64, scores[i].player2Score);
   }
   
   // Handle buttons events   
   while ( flag )
   {
		WPAD_ScanPads(); 
	
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 		
		if (WPAD_ButtonsHeld(channel) & BUTTON_1 ) button1x(channel);	
		if (WPAD_ButtonsHeld(channel) & BUTTON_2 ) button2y(channel);			
		if (WPAD_ButtonsHeld(channel) & BUTTON_HOME ) buttonHome(channel);
   }  
  	
   screenHighScore(channel);
}


void screenGoodbye(int channel)
{
   boolean flag = true;
   int i;
    
   screenClear();
         
   for (i=0; i<(scrollRange/2); i=i+4) 
   {
      drawImage(pic5data, pic5length, 10, 70+i );	
   }
 
   printf("\x1b[%d;%dH%s", 18, 20, "Press 1 or X to return to the loader.");
   printf("\x1b[%d;%dH%s", 19, 20, "Press 2 or Y to reset system.");
   printf("\x1b[%d;%dH%s", 20, 20, "Press A to continue the current game.");
      
   // Handle buttons events  
   while ( flag )
   {
      WPAD_ScanPads(); 	
	  if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 
	  
      if (WPAD_ButtonsHeld(channel) & BUTTON_1) exitToHomebrewChannel();	  
      if (WPAD_ButtonsHeld(channel) & BUTTON_2) exitResetWii();
   }

   screenClear();
   drawBar();
   WIILIGHT_TurnOff();
}

// -----------------------------------------------------------
// BUTTONS ACTIONS
// -----------------------------------------------------------

void buttonDown(int channel)
{
   if (yPaddle[channel]<(yMax-lPaddle[channel]-offset)) 
   {
      yPaddle[channel]++;	
	  	  
	  // Bar1 Collesion
	  if (xPaddle[channel]==xBar[1])
	  {
	     if ((yPaddle[channel]+lPaddle[channel])>(yBar[1]-lBar[1]))
		 {
		    yPaddle[channel]--;
	     }
	  }
   }
}

void buttonUp(int channel)
{
   if (yPaddle[channel]>(yMin+lPaddle[channel]+2+offset)) 
   {
      yPaddle[channel]--;
	  
	  // Bar0 Collesion
	  if (xPaddle[channel]==xBar[0])
	  {
	     if ((yPaddle[channel]-lPaddle[channel])<(yBar[0]+lBar[0]))
		 {
		    yPaddle[channel]++;
	     }
	  }
	 
   }
}

void buttonRight(int channel)
{

   if (xPaddle[channel]<(xMax-offset)) 
   {
      xPaddle[channel]++;	
	  
	  // Ball Collesion
	  if (xBal==xPaddle[channel]) 
	  {
	     if ((yBal>=(yPaddle[channel]-lPaddle[channel]-offset)) && 
		     (yBal<=(yPaddle[channel]+lPaddle[channel]+offset)) )
		 {
		    xPaddle[channel]--;
		 }
	  }
	  
	  // Bar0 Collesion
	  if (xPaddle[channel]==xBar[0])
	  {
    	  if ((yPaddle[channel]-lPaddle[channel])<yBar[0]+lBar[0])
	      {
	         xPaddle[channel]--;
	      }
	  }	  
	  
	  // Bar1 Collesion
	  if (xPaddle[channel]==xBar[1])
	  {
    	  if ((yPaddle[channel]+lPaddle[channel])>yBar[1]-lBar[1])
	      {
	         xPaddle[channel]--;
	      }
	  }	  
   }
}

void buttonLeft(int channel)
{
   if (xPaddle[channel]>(xMin+offset)) 
   {
      xPaddle[channel]--;	
	 
	  // Ball Collesion
	  if (xBal==xPaddle[channel]) 
	  {
	     if ((yBal>=(yPaddle[channel]-lPaddle[channel]-offset)) && 
		     (yBal<=(yPaddle[channel]+lPaddle[channel]+offset)) )
		 {
		    xPaddle[channel]++;
		 }
	  }
	  
	  // Bar0 Collesion
	  if (xPaddle[channel]==xBar[0])
	  {
    	  if ((yPaddle[channel]-lPaddle[channel])<yBar[0]+lBar[0])
	      {
	         xPaddle[channel]++;
	      }
	  }	  
	  
	  // Bar1 Collesion
	  if (xPaddle[channel]==xBar[1])
	  {
    	  if ((yPaddle[channel]+lPaddle[channel])>yBar[1]-lBar[1])
	      {
	         xPaddle[channel]++;
	      }
	  }	  
   }
}

void buttonA(int channel)
{
  if (delay>1) delay-=1; else delay=0; 
}

void buttonB(int channel)
{  
  
  if (delay<100) delay+=1;
}

void button1x(int channel)
{
   boolean flag = true;
 
   MODPlay_Stop(&snd1);
  
   if (modCounter<10) modCounter++; else modCounter=0;
   
   musicSelect(modCounter, true);
      
   // Handle buttons events  
   while ( flag )
   {
      WPAD_ScanPads(); 	
      if (WPAD_ButtonsUp(channel) & BUTTON_1) flag=false;
   }
}


void button2y(int channel)
{
   boolean flag = true;
 
   MODPlay_Stop(&snd1);
   
   if (modCounter>0) modCounter--; else modCounter=10;
   
   musicSelect(modCounter, true);
      
   // Handle buttons events  
   while ( flag )
   {
      WPAD_ScanPads(); 	
      if (WPAD_ButtonsUp(channel) & BUTTON_2) flag=false;
   }
}

void buttonHome(int channel)
{
   screenGoodbye(channel);   
}

void buttonPlus(int channel)
{
   screenPause(channel);   
}

void buttonMinus(int channel)
{
   screenHelp(channel);   
}

// -----------------------------------------------------------
// GAME LOGIC
// -----------------------------------------------------------

void saveHighScoreFile(char* filename)
{
   int i;
   mxml_node_t *xml;
   mxml_node_t *group;
   mxml_node_t *data;   
   char tmp[100];
      
   xml = mxmlNewXML("1.0");
   
   group = mxmlNewElement(xml, "pong2");
   
   for(i=0; i<=MAX_LEVEL; i++)
   {
      sprintf(tmp, "level%d", i);
      data = mxmlNewElement(group, tmp);
  
      //Create Some config value
	  sprintf(tmp, "%d", (int) highscores[i].localTime);
      mxmlElementSetAttr(data, "localTime", tmp);
	  
	  sprintf(tmp, "%d", (int) highscores[i].levelTime);
	  mxmlElementSetAttr(data, "levelTime", tmp);
	  
	  sprintf(tmp, "%d", highscores[i].player1Score);
      mxmlElementSetAttr(data, "player1Score", tmp);
	  
	  sprintf(tmp, "%d", highscores[i].player2Score);
	  mxmlElementSetAttr(data, "player2Score", tmp);
   }
  
   /* now lets save the xml file to a file! */
   FILE *fp;
   fp = fopen(filename, "w");

   mxmlSaveFile(xml, fp, MXML_NO_CALLBACK);
   
   /*Time to clean up!*/
   fclose(fp);
   mxmlDelete(data);
   mxmlDelete(group);
   mxmlDelete(xml);
}


void loadHighScoreFile(char* filename)
{
   int i;
   FILE *fp;
   mxml_node_t *tree=NULL;
   mxml_node_t *data=NULL;
   const char *tmp;
   char temp[100];
   
   /*Load our xml file! */
   fp = fopen(filename, "r");
   if (fp!=NULL)
   {
     tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
     fclose(fp);

     for(i=0; i<=MAX_LEVEL; i++)
     {
	    sprintf(temp, "level%d", i);
        data = mxmlFindElement(tree, tree, temp, NULL, NULL, MXML_DESCEND);
  
        tmp=mxmlElementGetAttr(data,"localTime");   
        if (tmp!=NULL) highscores[i].localTime=atoi(tmp); else highscores[i].localTime=0;
		
		tmp=mxmlElementGetAttr(data,"levelTime"); 
		if (tmp!=NULL) highscores[i].levelTime=atoi(tmp); else highscores[i].levelTime=0;
		
		tmp=mxmlElementGetAttr(data,"player1Score"); 
		if (tmp!=NULL) highscores[i].player1Score=atoi(tmp); else highscores[i].player1Score=0;
		
		tmp=mxmlElementGetAttr(data,"player2Score"); 
		if (tmp!=NULL) highscores[i].player2Score=atoi(tmp); else highscores[i].player2Score=0;
	 } 
   }
   else
   {
     // If file not found, create empty highscore list.
     for(i=0; i<=MAX_LEVEL; i++)
     {
       	highscores[i].localTime=0;
		highscores[i].levelTime=0;
		highscores[i].player1Score=0;
		highscores[i].player2Score=0; 
	 } 
   }
   
   mxmlDelete(data);
   mxmlDelete(tree);
}



void exitToHomebrewChannel(void)
{
   WIILIGHT_TurnOff();
   MODPlay_Stop(&snd1);

   exit(0);
}

void exitResetWii(void)
{
   WIILIGHT_TurnOff();
   MODPlay_Stop(&snd1);

   SYS_ResetSystem(SYS_RESTART,0,0);
}


void storeScore(int gameLevel)
{
   scores[gameLevel].localTime=time(NULL);
   scores[gameLevel].levelTime=(time(NULL)-startTime); 
   scores[gameLevel].player1Score=leftScore;
   scores[gameLevel].player2Score=rightScore;
}
   
void musicSelect(int modCounter, bool show)
{
   drawMusicSelect(modCounter, show);

   switch (modCounter)
   {
      case 0 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music0_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
      case 1 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music1_mod);
			   MODPlay_Start(&snd1);	
			   break;
			   
      case 2 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music2_mod);
			   MODPlay_Start(&snd1);	
			   break;
			   
      case 3 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music3_mod);
			   MODPlay_Start(&snd1);	
			   break;
			   
      case 4 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music4_mod);
			   MODPlay_Start(&snd1);	
			   break;
			   
      case 5 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music5_mod);
			   MODPlay_Start(&snd1);	
			   break;	
		   
	  case 6 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music6_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
	  case 7 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music7_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
	  case 8 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music8_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
	  case 9 : MODPlay_SetVolume( &snd1, 32,32); 
	           MODPlay_SetMOD(&snd1, music9_mod);
			   MODPlay_Start(&snd1);	
			   break;
	
	  case 10: MODPlay_SetVolume( &snd1, 0,0); 
	           MODPlay_Stop(&snd1);			   
			   break;
   } 
}

void movePlayer2()
{
   if ((xBalMove) && (xBal>(xMax/2)))
   {
     if ((yBal>yPaddle[1]) && (yPaddle[1]+lPaddle[1]<(yMax-offset)))
     { 
	    yPaddlePrev[1]=yPaddle[1];
		if ((rand() % 3) == 1 )
		{
           yPaddle[1]++;
		}
     }
     if ((yBal<yPaddle[1]) && (yPaddle[1]-lPaddle[1]>(yMin+2+offset)))
     { 
	    yPaddlePrev[1]=yPaddle[1];
		if ((rand() % 3) == 1 )
		{
           yPaddle[1]--;
		}
     }
   }
}


void scoreDectection(int channel)
{
   // Right score detection
   if (xBal==(xMin+1))
   {
       SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 16000, 0, (u8 *) effect1_wav, effect1_wav_size, 255, 0, NULL);
       rightScore++;   
	   drawScore(leftScore, rightScore);	   
	   
	   initBall(!xBalMove);
      
       if  (rightScore>=MAX_SCORE)
	   {	 
	      storeScore(gameLevel);
		  
		  screenGameOver(channel,false);
       }	   
   }
   
   // Left score detection
   if (xBal==(xMax-1))
   {
       SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 16000, 0, (u8 *) effect2_wav, effect2_wav_size, 0, 255, NULL);
       leftScore++;
	   drawScore(leftScore, rightScore);
	   	   
	   initBall(!xBalMove);
	   	   
	   if  (leftScore>=MAX_SCORE) 
	   {	       
	       storeScore(gameLevel);
		   
	       if (gameLevel<MAX_LEVEL)
		   {		   
		       gameLevel++;
			   initLevel(gameLevel);
			   screenLevel(gameLevel);	
			   initBall(true);
			   drawScore(leftScore, rightScore);			 
		   }
		   else
		   {
   		       screenGameOver(channel,true);			   
		   }		   
       }	   
   }
}
   
   
void colisionDetect(int channel)
{   
   // Collion with Paddle
   if (  (xBalMove && (xBal==(xPaddle[channel]-offset))) || 		
		 (!xBalMove && (xBal==(xPaddle[channel]+offset))) )
   {
       if ( (yBal>=(yPaddle[channel]-lPaddle[channel]-offset)) &&
              (yBal<=(yPaddle[channel]+lPaddle[channel]+offset)) )
       {
	       xBalMove=!xBalMove;		

		   switch ( channel )
		   {
			 case 0: SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 8000, 0, (u8 *) effect3_wav, effect3_wav_size, 255, 255, NULL);
					 break;
						
			 case 1: SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 8000, 0, (u8 *) effect3_wav, effect3_wav_size, 255, 255, NULL);
					 break;
		   }   
	   }
   }
   
   // Collion with Bar
   if ( (xBalMove && (xBal==(xBar[channel])-1)) || (!xBalMove && (xBal==(xBar[channel]+1))) )
   {
     if ( (lBar[channel]>0) && (yBal>=(yBar[channel]-lBar[channel]-1)) && (yBal<=(yBar[channel]+lBar[channel]+1)) )
     {
	   SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 8000, 0, (u8 *) effect3_wav, effect3_wav_size, 255, 255, NULL);
       xBalMove=!xBalMove;	
 	 }	 
   }	
}

  
void moveBal(int channel)
{  
   if (balCounter++>delay)
   {
     // Dectection and draw current score
	 scoreDectection(channel);
		
	 balCounter=0;
   
     xBalPrev=xBal;
     yBalPrev=yBal;
        
     // Move the bal
     if (xBalMove)
     {
        // Move from left to right
	    if (xBal<(xMax-offset)) 
	    {
	       xBal++; 
	    }
	    else 
	    {
		   SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 8000, 0, (u8 *) effect3_wav, effect3_wav_size, 255, 255, NULL);
	       xBalMove=false;	  
		   xBal--;
	    }
     }
     else
     {
        // Move from right to left
        if (xBal>(xMin+offset)) 
	    {
	       xBal--; 
	    }
 	    else 
 	    {
		   SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 8000, 0, (u8 *) effect3_wav, effect3_wav_size, 255, 255, NULL);
	       xBalMove=true;	
		   xBal++;
	    }
     }
   
     if (yBalMove)
     {
        // Move from up to down
	    if (yBal<(yMax-offset)) 
	    {
	       yBal++; 
	    }
	    else 
	    {
		   SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 8000, 0, (u8 *) effect3_wav, effect3_wav_size, 255, 255, NULL);
	       yBalMove=false;	  
		   yBal--;
	    }
     }
     else
     {
        // Move from down to up
        if (yBal>(yMin+2+offset)) 
	    {
	       yBal--; 
	    }
	    else 
	    {
		   SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_8BIT, 8000, 0, (u8 *) effect3_wav, effect3_wav_size, 255, 255, NULL);
	       yBalMove=true;	
		   yBal++;
        }
	  }
   }
}
   	
void initGame()
{	
    int i;
	gameLevel=0;
	delay=START_DELAY;
	lastSecond=0;
	
	for (i=0; i<MAX_LEVEL;i++)
	{
	   scores[i].localTime=0;
	   scores[i].levelTime=0;
       scores[i].player1Score=0;
	   scores[i].player2Score=0;
	}
}

void initLevel(int gameLevel)
{
	// Reset First Paddle (Human)
	xPaddle[0]=xMin+3;
	xPaddlePrev[0]=xPaddle[0];
	yPaddle[0]=(yMax/2)+2;
	yPaddlePrev[0]=yPaddle[0];
				
	// Reset Second Paddle (Computer)
	xPaddle[1]=xMax-3;
	xPaddlePrev[1]=xPaddle[1];
	yPaddle[1]=(yMax/2)+2;
	yPaddlePrev[1]=yPaddle[1];
			
	xBar[0]=(xMax/2);
	yBar[0]=yMin+2;	
	xBar[1]=(xMax/2);
	yBar[1]=yMax;
				
	leftScore=0;
	rightScore=0;
	startTime = time(NULL);
	
	switch (gameLevel)
	{
	
	   case 0: 	// Paddle size
	            lPaddle[0]=4;
				lPaddle[1]=3;	
				
				// No bars 							
				lBar[0]=0;
				lBar[1]=0;
				break;

	   case 1:  // Decrees paddle size if player continue to next level
				lPaddle[0]=3;
				lPaddle[1]=3;
				
				// No bars
				lBar[0]=0;
				lBar[1]=0;
				break;
		
	   case 2:  // Decrees paddle size if player continue to next level
				lPaddle[0]=2;
				lPaddle[1]=3;
				
				// Increes bar size 
				lBar[0]=4;
				lBar[1]=4;
				break;
		
	   case 3:  // Decrees paddle size if player continue to next level
				lPaddle[0]=1;	
				lPaddle[1]=3;
				
				// Increes bar size 
				lBar[0]=6;
				lBar[1]=6;
				break;
				
	   case 4:  // Decrees paddle size if player continue to next level
				lPaddle[0]=1;	
				lPaddle[1]=3;
				
				// Increes bar size 
				lBar[0]=8;
				lBar[1]=8;
				break;
				
	   case 5:  // Decrees paddle size if player continue to next level
				lPaddle[0]=0;	
				lPaddle[1]=4;
				
				// Increes bar size 
				lBar[0]=8;
				lBar[1]=8;
				break;
	}	
				
	drawGameLevel(gameLevel);	
}

void initBall(boolean direction)
{
	if ((yBal!=yBalPrev) || (xBal!=xBalPrev))
	{
		// Cleanup old position of ball
		printf("\x1b[%d;%dH%c",yBal,xBal,255);
	}
      
	// Reset Ball
	xBal = (xMax/2);
	if (!direction) xBal=xBal+10+(rand() % 20) ; else xBal=xBal-10-(rand() % 20);
	xBalPrev= xBal;
	xBalMove = direction;   
	 
	yBal = yMin+2+offset;
	yBalPrev= yBal;    
	yBalMove = direction;   
	
	balCounter=0; 
}

// -----------------------------------------------------------
// CONCEPT STUFF
// -----------------------------------------------------------

void freeTypeInit(void)
{      
   bool error;
   
   if (library==NULL)
   {
     error = FT_Init_FreeType( &library ); 
     if ( error ) 
     { 
        printf("Init FT_Init_FreeType failed");
     }
   }
    
   if (face==NULL)
   {
     error = FT_New_Face( library, "hotpizza.ttf", 0, &face );    
     if ( error == FT_Err_Unknown_File_Format )    
     { 
       //printf("the font file could be opened and read, but it appears that its font format is unsupported\n");
     } 
     else if ( error ) 
     { 
       //printf("another error code means that the font file could not ... be opened or read, or simply that it is broken\n"); 
     }	     
   }
}

 void freeTypePrintf(int pen_x, int pen_y, u32 color, int fontSize, char *text,...)
{
   bool error;  
   int  n; 
   char tmp[512];
   int  size;
  
   // Color    
   // 0xff0000 Blue
   // 0x00ff00 Green
   // 0x0000ff Red
				  
   if (face!=NULL)
   {
     slot = face->glyph;
				 
     FT_Set_Pixel_Sizes(face, (fontSize/1.5), fontSize);
	    		
     va_list argp;
     va_start(argp, text);
     vsprintf(tmp, text, argp);
     va_end(argp);
   
     size = strlen(tmp);

     for ( n = 0; n < size; n++ ) 
     { 
       int pix = 0;
       int row, col;
       int offset;
	   u32 pixel;
   
       /* load glyph image into the slot (erase previous one) */  
	   error = FT_Load_Char( face, tmp[n], FT_LOAD_RENDER ); 
	   if ( error ) continue; /* ignore errors */  
	   
	   image=&slot->bitmap;
	  
	   /* now, draw to our target surface */ 
       offset=(pen_y-slot->bitmap_top)*320; 
       for (row=0; row<image->rows; row++)
       {
	      for (col=0; col<image->width; col++)
		  {  
		    if (image->buffer[pix]==255)
		    { 
			   // Set alpha and color (ARGB format) for pixel
		       pixel=(image->buffer[pix]<<24)+color;  			
			   //pixel=(image->buffer[pix]<<24)+0x0080ff80; 
		       frameBuffer[0][offset + pen_x + slot->bitmap_left +col] = pixel;
			}
			pix++;
		  }
		  offset+=320; 
       }
	     	 
	   /* increment pen position */  
	   pen_x += slot->advance.x >> 6; 
	 }
   } 
}

// -----------------------------------------------------------
// MAIN
// -----------------------------------------------------------

int main(int argc, char **argv) 
{	   	
	// Initialise the video system
	VIDEO_Init();
	
	// This function initialises the attached controllers
	WPAD_Init();
	
	// And this one gives us access to the accelerometers and infrared.
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
	
	// Wiimote is shutdown after 300 seconds of innactivity.
	WPAD_SetIdleTimeout(300); 
 
	// Obtain the preferred video mode from the system
	// This will correspond to the settings in the Wii menu
	rmode = VIDEO_GetPreferredMode(NULL);
	
	// allocate 2 framebuffers for double buffering
	frameBuffer[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
		
	// Initialise the console, required for printf
	console_init(frameBuffer[0],20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ);
	
	// Set up the video registers with the chosen mode
	VIDEO_Configure(rmode);
	
	if (rmode->xfbHeight==528)
	{
	    // TV mode PAL 50Hz
	    xMin = 0;
        yMin = 0;
		xMax = 79;
        yMax = 29;
		scrollRange=100;	   
	}
	else
	{      
	    // TV mode PAL 60Hz
	    xMin = 0;
        yMin = 1;
        xMax = 79;
        yMax = 26;
		scrollRange=80;
	}
	
	// Tell the video hardware where our display memory is
	VIDEO_SetNextFramebuffer(frameBuffer[0]);
	
	// Make the display visible
	VIDEO_SetBlack(FALSE);

	// Flush the video register changes to the hardware
	VIDEO_Flush();

	// Wait for Video setup to complete
	VIDEO_WaitVSync();
	if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
  
	// Init Wii DVD rom lights
	WIILIGHT_Init();	

    // Init Fat
    fatInitDefault();

    // Init Sound engine	
	SND_Init(INIT_RATE_48000); 
	MODPlay_Init(&snd1);
    SND_Pause(0);
		
	// Start music			
	musicSelect(modCounter, false);
	
	freeTypeInit();
		
    // show Welcome1 Screen
    screenWelcome1(WPAD_CHAN_0);
	
	// show Welcome2 Screen
	screenWelcome2(WPAD_CHAN_0);

    // show Welcome3 Screen
	screenWelcome3(WPAD_CHAN_0);
	
	// Load highscore xml file (if available)
	loadHighScoreFile(HIGHSCORE_FILENAME);
	
    // Init game settings	
	initGame();
	initLevel(gameLevel);
	initBall(true);
	
	// Draw game box
	drawBoard();	
	drawMusicSelect(modCounter, true);
	
	// Show level start screen			
	screenLevel(gameLevel);
					  	
	// Endless loop
	while(true) 
	{   			
		// Call WPAD_ScanPads each loop, this reads the latest controller states
		WPAD_ScanPads();

		// Player 1 move
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_ANY )  WPAD_Rumble(0,1); else WPAD_Rumble(0,0); 		 
						
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_HOME ) buttonHome(WPAD_CHAN_0);			
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_1 ) button1x(WPAD_CHAN_0);				
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_2 ) button2y(WPAD_CHAN_0);				   				
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_A ) buttonA(WPAD_CHAN_0);		
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_B ) buttonB(WPAD_CHAN_0);				
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_DOWN ) buttonDown(WPAD_CHAN_0);	
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_UP ) buttonUp(WPAD_CHAN_0);		
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_RIGHT ) buttonRight(WPAD_CHAN_0);		
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_LEFT ) buttonLeft(WPAD_CHAN_0);				
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_PLUS ) buttonPlus(WPAD_CHAN_0);
		if (WPAD_ButtonsHeld(WPAD_CHAN_0) & BUTTON_MINUS ) buttonMinus(WPAD_CHAN_0);
		
		// Infrared control disabled
		//ir_t ir; // The struct for infrared
		//WPAD_IR(WPAD_CHAN_0, &ir); // Let's get our infrared data		
		//irX=(ir.sx);
		//irY=(ir.sy); 
		//printf("\x1b[%d;%dHirX=%d   ",10,10,irX);
		//printf("\x1b[%d;%dHirY=%d   ",11,10,irY);
	    //if (irX>irXPrev) buttonRight(WPAD_CHAN_0);
		//if (irX<irXPrev) buttonLeft(WPAD_CHAN_0);
        //if (irY>irYPrev) buttonDown(WPAD_CHAN_0);
	    //if (irY<irYPrev) buttonUp(WPAD_CHAN_0);
		//irFlag=true;
		//irXPrev=irX;
		//irYPrev=irY;

						
		// Player 2 move
		movePlayer2();

		// Draw ball
		drawBal(xBal, yBal, xBalPrev, yBalPrev);
		    
		// Draw Paddles
		
		drawPaddle(yPaddle[0],yPaddlePrev[0],xPaddle[0],xPaddlePrev[0], lPaddle[0],0);
		drawPaddle(yPaddle[1],yPaddlePrev[1],xPaddle[1],xPaddlePrev[1], lPaddle[1],1);
		
		// Collision Detection
		colisionDetect(0);
		colisionDetect(1);
				
		// Move the ball
		moveBal(0);
		
		// Update game level time
		drawTime();
						   
	      // Flush and Wait for the next frame
      	VIDEO_SetNextFramebuffer(frameBuffer[0]); 
		VIDEO_Flush();
		VIDEO_WaitVSync();
	}
	return 0;
}

