/* 
**  bibleQuiz for Wii - Created by wplaat
**
**  BibleQuiz is an open-source quiz game. Test your knowlegde about the bible.
**  Special thanks to my family for their support during the development of this game. 
**
**  Copyright (C) 2008 
**  ==================
**
**  This program is free software; you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation, version 2.
**
**  This program is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this program; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**
**  Release Notes:
**  ==============
**
**  09/12/2008 Version 0.7
**  - Added release notes screen.
**  - Added functionality to fetch release notes from internet.
**  - Improve highscore information (Show maximun score pre topic).
**  - Improve IR pointer.
**  - Added google analytic http request (including highscore information).
**  - Improve result screen information.
** 
**  26/11/2008 Version 0.6
**  - All texts are now created with the freetype library (Thanks DrTwox) 
**
**  24/11/2008 Version 0.51
**  - Added check if new version is available.
**  - Added animated screen icons
**  - Solved some minor reported bugs
**  - Content update:
**  	- Added 100 english questions (4 topics).
**  	- Added 10 dutch questions (1 topic).
**  	- Added 10 german questions (1 topic).
**  	- Added france translation.
**      - Corrected some wrong answers.
**
**  19/11/2008 Version 0.4
**  - Added highscore screen.
**  - Highscore is stored (in xml format) on the SD card
**  - Added credits screen.
**  - Added help (minus button) screen.
**  - Added 10 music tracks.
**  - Use freetype library as font render engine for screen (sub)titles.
**  - Content update:
**  	- Added 170 english questions (8 topics).
**  	- Added 100 dutch questions (4 topics).
**  	- Added spanisch translation.
**
**  16/11/2008 Version 0.31
**  - Hotfix to prevent core dump with 60Hz (480i) Tv mode
**  - Donated the bibleQuiz source code to the community. Comments are welcome ;-} 
** 
**  15/11/2008 Version 0.3
**  - First release for the Wii HomeBrew community
**  - Complete rebuild from game engine
**  - Added language / topic select screen
**  - Added goodbye screen
**  - Added sound volume control screen
**  - Content Update:
**  	- Added German language
**		- Added 20 English question (1 topic)
**  	- Added 10 Dutch question (1 topic)
** 
**  08/11/2008 Version 0.2
**  - Added support for xml question files
**  - Added question result image with animation
**  - Added multi language support
**  - Added three hint buttons
**  - Added support for 60Hz (480i) TV mode
**  - Added score result screen
**  - Added sndlib module with some sound effects
**  - Added exit button
**  - Added question word wrap function 
** 
**  03/11/2008 Version 0.1
**  - Started programming
**  - Gameboard design
**  - Added WiiRemote IR control
**  - Added three welcome screens
**  - Added button rumble effect 
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include <ogcsys.h>
#include <gccore.h>
#include <gcmodplay.h> 
#include <wiiuse/wpad.h>
#include <jpeg/jpgogc.h>
#include <fat.h>
#include <mxml.h>
#include <snd.h>   
#include <fcntl.h>
#include <unistd.h>
#include <time.h> 
#include <ft2build.h> 
#include FT_FREETYPE_H 
 
#include "http.h"
#include "GRRLIB.h"
#include "track1_mod.h"
#include "track2_mod.h"
#include "track3_mod.h"
#include "track4_mod.h"
#include "track5_mod.h"
#include "track6_mod.h"
#include "track7_mod.h"
#include "track8_mod.h"
#include "track9_mod.h"
#include "effect1_wav.h"
#include "effect2_wav.h"
#include "effect3_wav.h"

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

#define PROGRAM_NAME	    "BibleQuiz"
#define PROGRAM_VERSION     "0.7"
#define RELEASE_DATE        "09-12-2008" 
#define FILENAME_LANGUAGES  "languages.xml"
#define DATA_DIRECTORY      "data"
#define HIGHSCORE_FILENAME  "highscore.xml"
#define URL1                "http://www.wiibrew.org/wiki/BibleQuiz"
#define URL2                "http://members.tele2.nl/wplaat/BibleQuiz.html"
#define URL_TOKEN           " Version "

#define COLOR_LIGHTBLUE     0xEBCE87
#define COLOR_WHITESMOKE    0xFFFFFF

#define WSP_POINTER_X       200
#define WSP_POINTER_Y       250
#define MAX_LANGUAGES		5
#define MAX_BUTTONS         10
#define MAX_TOPICS			20
#define MAX_HIGHSCORE		(MAX_LANGUAGES * MAX_TOPICS)
#define MAX_QUESTIONS		100
#define MAX_ANSWERS         4
#define MAX_RUMBLE			4
#define MAX_HORZ_PIXELS		640
#define MAX_SOUND_VOLUME	10
#define MAX_BUFFER_SIZE		4096

#define MUSIC_MULTIPLER		5
#define EFFECT_MULTIPLER	20
#define MAX_LEN			 	200
#define MAX_MUSIC_TRACK     10
#define MAX_ANGLE			360
#define MAX_ALFA			128
#define ICON_X				460
#define ICON_Y				-10
#define ICON_ZOOM			0.3

#define BUTTON_A            (WPAD_BUTTON_A     | WPAD_CLASSIC_BUTTON_A)
#define BUTTON_HOME         (WPAD_BUTTON_HOME  | WPAD_CLASSIC_BUTTON_HOME)
#define BUTTON_1            (WPAD_BUTTON_1     | WPAD_CLASSIC_BUTTON_X)
#define BUTTON_2            (WPAD_BUTTON_2     | WPAD_CLASSIC_BUTTON_Y)
#define BUTTON_MINUS        (WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS)

// -----------------------------------------------------------
// PROTOTYPES
// -----------------------------------------------------------
 
void freeTypePrintf(int pen_x, int pen_y, u32 color, int fontSize, char *text);
void drawJpegImage(char *pictureData, int pictureLength, int x, int y );
void buttonExit(int index);
void drawGoodbyeScreen1(int channel);
void drawText(int x, int y, int type, char *text,...);

// -----------------------------------------------------------
// TYPEDEFS and ENUMS
// -----------------------------------------------------------
 
typedef struct
{
    int  id;
	char name[MAX_LEN];
	char translation[MAX_LEN];
	char topics[MAX_LEN];
}
language;

language languages[MAX_LANGUAGES+1];

typedef struct
{
    int  id;
    char name[MAX_LEN];
	char filename[MAX_LEN];
}
topic;

typedef struct 
{
	char author[MAX_LEN];
	char topic[MAX_LEN];
	char timestamp[MAX_LEN];
	char note[MAX_LEN];
}
info;

info information;

topic topics[MAX_TOPICS];

typedef struct
{
   char question[MAX_LEN]; 
   char answerA[MAX_LEN]; 
   char answerB[MAX_LEN]; 
   char answerC[MAX_LEN]; 
   char answerD[MAX_LEN]; 
   int  answer;
   char explanation[MAX_LEN]; 
   bool played;
   bool enabled[4];
} 
question;

question questions[MAX_QUESTIONS+1];


typedef struct 
{
    char labelWelcome[MAX_LEN];
	char labelTopic[MAX_LEN];
	char labelScore[MAX_LEN];
	char labelCreated[MAX_LEN];
	char labelQuestion[MAX_LEN];
	char labelAnswers[MAX_LEN];
	char labelResult[MAX_LEN];
	char labelCategory1[MAX_LEN];
	char labelCategory2[MAX_LEN];
	char labelCategory3[MAX_LEN];
	char labelRight[MAX_LEN];
	char labelWrong[MAX_LEN];
	char labelAuthor[MAX_LEN];
	char labelGoodbye[MAX_LEN];
	char labelMusic[MAX_LEN];
	char labelEffects[MAX_LEN];
	char labelHighScore[MAX_LEN];
	char labelDate[MAX_LEN];
    char labelHints[MAX_LEN];
	char labelPlayTime[MAX_LEN];
	char labelResults[MAX_LEN];
	char labelHelp[MAX_LEN];
	char labelTrack[MAX_LEN];
	char labelNewVersion[MAX_LEN];
		
	char buttonAnswerA[MAX_LEN];
	char buttonAnswerB[MAX_LEN];
	char buttonAnswerC[MAX_LEN];
	char buttonAnswerD[MAX_LEN];
	char buttonHint[MAX_LEN];
	char buttonRetry[MAX_LEN];
	char buttonPlay[MAX_LEN];
	char buttonNext[MAX_LEN];
	char buttonStop[MAX_LEN];
	char buttonExit1[MAX_LEN];
	char buttonExit2[MAX_LEN];
	char buttonContinue[MAX_LEN];
	char buttonSound[MAX_LEN];
	char buttonBack[MAX_LEN];
	char buttonCredits[MAX_LEN];
	char buttonPrevious[MAX_LEN];
	char buttonReleaseNotes[MAX_LEN];
}
trans;

trans translation;


typedef struct
{
   u8 *image;
   u8 *imageSelect;
   char name[MAX_LEN]; 
   bool enabled;
   int x;
   int y;
   int xtext;
   int ytext;
   int width;
   int height;
} 
button;

button buttons[MAX_BUTTONS+1];


typedef struct 
{
  // Png Image index
  u8 *button1;
  u8 *button1select;
  u8 *button2;
  u8 *button2select;
  u8 *banner;
  u8 *panel1;
  u8 *panel2;
  u8 *english_flag;
  u8 *nederlands_flag;
  u8 *deutsch_flag;
  u8 *spanish_flag;
  u8 *france_flag;
  u8 *bar1;
  u8 *bar_cursor1;
  u8 *button3;
  u8 *button3select;
  u8 *help;
  u8 *right;
  u8 *wrong;
  u8 *sound;
  u8 *exit;
  u8 *info;
  u8 *question;
  u8 *background1;
  u8 *background2;
  u8 *background3;
  u8 *pointer;
} 
image;

image images;


typedef struct
{
  time_t startTime;
  time_t playTime;
  int    score;
  int    questions;
  int    hint;
  int    topicId;
  char   topic[MAX_LEN];
  int    languageId;
}
highscore;

highscore highscores[MAX_TOPICS+1];


enum
{
   stateWelcome=0,
   stateQuestion=1,
   stateAnswer=2,
   stateResult=3,
   stateGoodbye=4,
   stateSound=5,
   stateCredits=6,
   stateHighScore=7,
   stateHelp=8,
   stateReleaseNotes=9,
   stateNone=10 
};

enum
{
   fontTitle=0,
   fontSubTitle=1,
   fontParagraph=2,
   fontNormal=3,
   fontButton=4,
   fontNew=5,
   fontHead=6
};

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

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

static  MODPlay snd1;

int     yOffset;
int     yjpegOffset;
int     angle;
int     alfa;
boolean alfa_direction;

int     score;
int     hintCounter;
time_t  startTime;
time_t  playTime;
boolean correctAnswer;
int     rumbleCounter;

int     maxQuestions;
int     maxLanguages;
int     maxTopics;
int     maxButtons;
int     maxHighScores;

int     selectedLanguage;
int     selectedTopic;
int     selectedQuestion;
int     selectedMusic;

int     musicVolume;
int     effectVolume;
int     notesStartLine;
int     noteDelay;

int     stateMachine;
int     stateMachinePrev;
int     stateMachineStorage;
int     stateMachineStorage2;

FT_Library library=NULL;  
FT_Face face=NULL;              
FT_GlyphSlot slot;        
FT_Bitmap *FT_image;

// Banner Image
extern char     pic1data[];
extern int      pic1length;

// Button1 Image
extern char     pic2data[];
extern int      pic2length;

// Button1select Image
extern char     pic3data[];
extern int      pic3length;

// Button2 Image
extern char     pic4data[];
extern int      pic4length;

// Button2select Image
extern char     pic5data[];
extern int      pic5length;

// Panel1 Image
extern char     pic7data[];
extern int      pic7length;

// pionter Image
extern char     pic8data[];
extern int      pic8length;

// Welcome1 Image
extern char     pic9data[];
extern int      pic9length;

// Welcome2 Image
extern char     pic10data[];
extern int      pic10length;

// Welcome3 Image
extern char     pic11data[];
extern int      pic11length;

// welcome4 Image
extern char     pic12data[];
extern int      pic12length;

// english flag Image
extern char     pic13data[];
extern int      pic13length;

// nederlands flag Image
extern char     pic14data[];
extern int      pic14length;

// deutsch flag Image
extern char     pic15data[];
extern int      pic15length;

// bar1 Image
extern char     pic16data[];
extern int      pic16length;

// bar_cursor1 Image
extern char     pic17data[];
extern int      pic17length;

// button3 Image
extern char     pic18data[];
extern int      pic18length;

// button3select Image
extern char     pic19data[];
extern int      pic19length;

// Panel2 Image
extern char     pic21data[];
extern int      pic21length;

// Spanish flag Image
extern char     pic22data[];
extern int      pic22length;

// Help image
extern char     pic23data[];
extern int      pic23length;

// france flag image
extern char     pic24data[];
extern int      pic24length;

// right icon
extern char     pic25data[];
extern int      pic25length;

// wrong icon
extern char     pic26data[];
extern int      pic26length;

// sound icon 
extern char     pic28data[];
extern int      pic28length;

// exit icon 
extern char     pic29data[];
extern int      pic29length;

// Info icon 
extern char     pic30data[];
extern int      pic30length;

// Question icon 
extern char     pic31data[];
extern int      pic31length;

// Background1 icon
extern char     pic33data[];
extern int      pic33length;

// Background2 icon
extern char     pic34data[];
extern int      pic34length;

// Background3 icon
extern char     pic35data[];
extern int      pic35length;

// Language xml file.
extern char     xml1data[];
extern int      xml1length;

// English translation xml file.
extern char     xml2data[];
extern int      xml2length;

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

void saveHighScore(char* filename)
{
   int i;
   mxml_node_t *xml;
   mxml_node_t *group;
   mxml_node_t *data=NULL;   
   char tmp[100];
      
   xml = mxmlNewXML("1.0");   
   group = mxmlNewElement(xml, "bibleQuiz");
   for(i=0; i<maxHighScores; i++)
   {
      data = mxmlNewElement(group, "topic");
  
      //Create Some config value
	  sprintf(tmp, "%d", (int) highscores[i].startTime);
      mxmlElementSetAttr(data, "startTime", tmp);
	  
	  sprintf(tmp, "%d", (int) highscores[i].playTime);
	  mxmlElementSetAttr(data, "playTime", tmp);
	  
	  sprintf(tmp, "%d", highscores[i].score);
      mxmlElementSetAttr(data, "score", tmp);
	  
	  sprintf(tmp, "%d", highscores[i].questions);
      mxmlElementSetAttr(data, "questions", tmp);
	  
	  sprintf(tmp, "%d", highscores[i].hint);
      mxmlElementSetAttr(data, "hint", tmp);
	  
	  sprintf(tmp, "%d", highscores[i].topicId);
      mxmlElementSetAttr(data, "topicId", tmp);
	  
      sprintf(tmp, "%s", highscores[i].topic);
      mxmlElementSetAttr(data, "topic", tmp);
	  
	  sprintf(tmp, "%d", highscores[i].languageId);
      mxmlElementSetAttr(data, "languageId", 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 initHighScore(char* filename)
{
   maxHighScores=0;

   FILE *fp;
   mxml_node_t *tree=NULL;
   mxml_node_t *data=NULL;
   const char *tmp;
   
   /*Load our xml file! */
   fp = fopen(filename, "r");
   if (fp!=NULL)
   {
     tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
     fclose(fp);

     for (data = mxmlFindElement(tree, tree, "topic", NULL, NULL, MXML_DESCEND);
       data != NULL;
       data = mxmlFindElement(data, tree, "topic", NULL, NULL, MXML_DESCEND))
    {		   
        tmp=mxmlElementGetAttr(data,"startTime");   
        if (tmp!=NULL) highscores[maxHighScores].startTime=atoi(tmp); else highscores[maxHighScores].startTime=0;
		
		tmp=mxmlElementGetAttr(data,"playTime"); 
		if (tmp!=NULL) highscores[maxHighScores].playTime=atoi(tmp); else highscores[maxHighScores].playTime=0;
		
		tmp=mxmlElementGetAttr(data,"score"); 
		if (tmp!=NULL) highscores[maxHighScores].score=atoi(tmp); else highscores[maxHighScores].score=0;
		
		tmp=mxmlElementGetAttr(data,"questions"); 
		if (tmp!=NULL) highscores[maxHighScores].questions=atoi(tmp); else highscores[maxHighScores].questions=0;
				
		tmp=mxmlElementGetAttr(data,"hint"); 
		if (tmp!=NULL) highscores[maxHighScores].hint=atoi(tmp); else highscores[maxHighScores].hint=0;

		tmp=mxmlElementGetAttr(data,"topicId"); 
		if (tmp!=NULL) highscores[maxHighScores].topicId=atoi(tmp); else highscores[maxHighScores].topicId=0;

        tmp=mxmlElementGetAttr(data,"topic"); 
		if (tmp!=NULL) strcpy(highscores[maxHighScores].topic,tmp); else strcpy(highscores[maxHighScores].topic,"");
		
		tmp=mxmlElementGetAttr(data,"languageId"); 
		if (tmp!=NULL) highscores[maxHighScores].languageId=atoi(tmp); else highscores[maxHighScores].languageId=0;
		
		maxHighScores++;
	 } 
   }   
   mxmlDelete(data);
   mxmlDelete(tree);
}

void processHighScore(void)
{
   boolean found=false;
   int i;
   
   // Check if highscore is reached
   for (i=0; i<maxHighScores; i++)
   {
      if ( topics[selectedTopic].id==highscores[i].topicId )
	  {
	     // Update exiting entry, if needed
         if ( score>highscores[i].score)  
	     {
	       highscores[i].startTime=startTime;
	       highscores[i].playTime=playTime;
		   highscores[i].score=score;
		   highscores[i].questions=maxQuestions;
		   highscores[i].hint=hintCounter;
		   highscores[i].topicId=topics[selectedTopic].id;
		   strcpy(highscores[i].topic,topics[selectedTopic].name);
		   highscores[i].languageId=languages[selectedLanguage].id;
			   
		   // Store updated high score in file
		   saveHighScore(HIGHSCORE_FILENAME);
	     }
		 found=true;
	  }
   }
   
   // new entry in highscore 
   if (!found)
   {
      highscores[maxHighScores].startTime=startTime;
	  highscores[maxHighScores].playTime=playTime;
	  highscores[maxHighScores].score=score;
	  highscores[maxHighScores].questions=maxQuestions;
	  highscores[maxHighScores].hint=hintCounter;
	  highscores[maxHighScores].topicId=topics[selectedTopic].id;
	  strcpy(highscores[maxHighScores].topic,topics[selectedTopic].name);
	  highscores[maxHighScores].languageId=languages[selectedLanguage].id;
	  maxHighScores++;
	  
	  // Store new high score in file
	  saveHighScore(HIGHSCORE_FILENAME);
   }
}

void initThreads(void)
{ 
   char userData[MAX_LEN];

   // Get highest score   		 
   memset(userData,0x00,sizeof(userData));
   sprintf(userData,"%s=%s&highscore=%ld",PROGRAM_NAME,PROGRAM_VERSION,(long) highscores[0].playTime);
			   
   tcp_start_thread(PROGRAM_NAME, PROGRAM_VERSION, URL1, URL2, URL_TOKEN, userData);
}

void initGame()
{
   // Clear memory  
   memset(languages,0x00,sizeof(languages));
   memset(topics,0x00,sizeof(topics));
   memset(questions,0x00,sizeof(questions));
   memset(buttons,0x00,sizeof(buttons));
   memset(highscores,0x00,sizeof(highscores));   
   memset(&images,0x00,sizeof(images));
   memset(&information,0x00,sizeof(information));
   memset(&translation,0x00,sizeof(translation));
   
   // Set variables
   stateMachine=stateWelcome;    
   stateMachinePrev=stateNone; 
   
   selectedLanguage=0;
   selectedTopic=0;
   selectedQuestion=0;

   selectedMusic=1;
   musicVolume=5;
   effectVolume=8;
   
   notesStartLine=4;
   noteDelay=0;

   angle=0;
   alfa=0;
   alfa_direction=true;

   score=0;
   hintCounter=0;
   startTime=time(NULL);
   correctAnswer=false;
}

void initLanguages(char* filename)
{
   maxLanguages=0;

   FILE *fp;
   mxml_node_t *tree;
   mxml_node_t *group;   
   const char  *pointer;

   char tmp[MAX_LEN];
   sprintf(tmp,"%s/%s", DATA_DIRECTORY, filename);

   /*Load our xml file! */
   fp = fopen(tmp, "r");
   if (fp!=NULL)
   {   
      tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
      fclose(fp);
   }
   else
   {
      // If file is not found, us internal xml file.
      tree = mxmlLoadString(NULL, xml1data, MXML_TEXT_CALLBACK);
   }
    
   // Read Questions
   for (group = mxmlFindElement(tree, tree, "language", NULL, NULL, MXML_DESCEND);
        group != NULL;
        group = mxmlFindElement(group, tree, "language", NULL, NULL, MXML_DESCEND))
   {		  
      pointer=mxmlElementGetAttr(group,"name");
	  if (pointer!=NULL) strcpy(languages[maxLanguages].name,pointer); else strcpy(languages[maxLanguages].name,"");
	  	  
      pointer=mxmlElementGetAttr(group,"translation");
      if (pointer!=NULL) strcpy(languages[maxLanguages].translation,pointer); else strcpy(languages[maxLanguages].translation,"");
	  
      pointer=mxmlElementGetAttr(group,"topics");
      if (pointer!=NULL) strcpy(languages[maxLanguages].topics,pointer); else strcpy(languages[maxLanguages].topics,"");
	
      pointer=mxmlElementGetAttr(group,"id");
      if (pointer!=NULL) languages[maxLanguages].id=atoi(pointer); else languages[maxLanguages].id=0;
	 	  
	  maxLanguages++;	  
   }
   
   mxmlDelete(group);
   mxmlDelete(tree);
}


void initMusicTrack(void)
{
   switch (selectedMusic)
   {
      case 1 : MODPlay_SetMOD(&snd1, track1_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
      case 2 : MODPlay_SetMOD(&snd1, track2_mod);
			   MODPlay_Start(&snd1);	
			   break;
			   
      case 3 : MODPlay_SetMOD(&snd1, track3_mod);
			   MODPlay_Start(&snd1);	
			   break;
			   
      case 4 : MODPlay_SetMOD(&snd1, track4_mod);
			   MODPlay_Start(&snd1);	
			   break;
			   
      case 5 : MODPlay_SetMOD(&snd1, track5_mod);
			   MODPlay_Start(&snd1);	
			   break;	
		   
	  case 6 : MODPlay_SetMOD(&snd1, track6_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
	  case 7 : MODPlay_SetMOD(&snd1, track7_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
	  case 8 : MODPlay_SetMOD(&snd1, track8_mod);
			   MODPlay_Start(&snd1);	
			   break;	
			   
	  case 9 : MODPlay_SetMOD(&snd1, track9_mod);
			   MODPlay_Start(&snd1);	
			   break;
   } 
   MODPlay_SetVolume( &snd1, musicVolume*MUSIC_MULTIPLER,musicVolume*MUSIC_MULTIPLER); 
}


void storeXmlValue(mxml_node_t *tree, char *key, char *value)
{
  mxml_node_t *group;
  const char  *pointer;
  
  group = mxmlFindElement(tree, tree, key, NULL, NULL, MXML_DESCEND);  
  pointer=mxmlElementGetAttr(group,"value");
  
  if (pointer!=NULL) 
  {
     strcpy(value,pointer); 
  }
  else 
  {  
     strcpy(value,"");
  }

  mxmlDelete(group); 
}


void initTranslation(char* filename)
{	  
   FILE *fp;
   mxml_node_t *tree;
      
   char tmp[MAX_LEN];
   sprintf(tmp,"%s/%s", DATA_DIRECTORY, filename);
   
   /*Load our xml file! */
   fp = fopen(tmp, "r");
   if (fp!=NULL)
   {   
      tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
      fclose(fp);
   }
   else
   {
      // If file is not found, us internal xml files.	  
      tree = mxmlLoadString(NULL,xml2data, MXML_TEXT_CALLBACK);  
   }

   storeXmlValue(tree, "labelWelcome", translation.labelWelcome);
   storeXmlValue(tree, "labelTopic", translation.labelTopic);
   storeXmlValue(tree, "labelScore", translation.labelScore);
   storeXmlValue(tree, "labelCreated", translation.labelCreated);
   storeXmlValue(tree, "labelQuestion", translation.labelQuestion);
   storeXmlValue(tree, "labelAnswers", translation.labelAnswers);
   storeXmlValue(tree, "labelResult", translation.labelResult);
   storeXmlValue(tree, "labelCategory1", translation.labelCategory1);  
   storeXmlValue(tree, "labelCategory2", translation.labelCategory2);  
   storeXmlValue(tree, "labelCategory3", translation.labelCategory3);   
   storeXmlValue(tree, "labelRight", translation.labelRight); 
   storeXmlValue(tree, "labelWrong", translation.labelWrong);
   storeXmlValue(tree, "labelAuthor", translation.labelAuthor);
   storeXmlValue(tree, "labelGoodbye", translation.labelGoodbye);
   storeXmlValue(tree, "labelMusic", translation.labelMusic);
   storeXmlValue(tree, "labelEffects", translation.labelEffects);
   storeXmlValue(tree, "labelHighScore", translation.labelHighScore);
   storeXmlValue(tree, "labelDate", translation.labelDate);
   storeXmlValue(tree, "labelHints", translation.labelHints);
   storeXmlValue(tree, "labelPlayTime", translation.labelPlayTime);
   storeXmlValue(tree, "labelResults", translation.labelResults);   
   storeXmlValue(tree, "labelHelp", translation.labelHelp);
   storeXmlValue(tree, "labelTrack", translation.labelTrack);
   storeXmlValue(tree, "labelNewVersion", translation.labelNewVersion);
      
   storeXmlValue(tree, "buttonAnswerA", translation.buttonAnswerA);
   storeXmlValue(tree, "buttonAnswerB", translation.buttonAnswerB);
   storeXmlValue(tree, "buttonAnswerC", translation.buttonAnswerC);
   storeXmlValue(tree, "buttonAnswerD", translation.buttonAnswerD);
   storeXmlValue(tree, "buttonHint", translation.buttonHint);	  
   storeXmlValue(tree, "buttonRetry", translation.buttonRetry);	  
   storeXmlValue(tree, "buttonPlay", translation.buttonPlay);
   storeXmlValue(tree, "buttonNext", translation.buttonNext);
   storeXmlValue(tree, "buttonStop", translation.buttonStop);
   storeXmlValue(tree, "buttonExit1", translation.buttonExit1);
   storeXmlValue(tree, "buttonExit2", translation.buttonExit2);   
   storeXmlValue(tree, "buttonContinue", translation.buttonContinue);    
   storeXmlValue(tree, "buttonSound", translation.buttonSound); 
   storeXmlValue(tree, "buttonBack", translation.buttonBack);
   storeXmlValue(tree, "buttonCredits", translation.buttonCredits);
   storeXmlValue(tree, "buttonPrevious", translation.buttonPrevious);
   storeXmlValue(tree, "buttonReleaseNotes", translation.buttonReleaseNotes);
	
   mxmlDelete(tree);
}

void initTopics(char* filename)
{
   maxTopics=0;

   FILE *fp;
   mxml_node_t *tree;
   mxml_node_t *group;   
   const char  *pointer;
   char tmp[MAX_LEN];
   
   sprintf(tmp,"%s/%s", DATA_DIRECTORY, filename);
   
   /*Load our xml file! */
   fp = fopen(tmp, "r");
   if (fp!=NULL)
   {   
      tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
      fclose(fp);
   }
   else
   {
      // If file is not found, return direct
      maxTopics=-1;
      return;
   }
    
   // Read Questions
   for (group = mxmlFindElement(tree, tree, "topic", NULL, NULL, MXML_DESCEND);
        group != NULL;
       group = mxmlFindElement(group, tree, "topic", NULL, NULL, MXML_DESCEND))
   {		  
        pointer=mxmlElementGetAttr(group,"name");
	    if (pointer!=NULL) strcpy(topics[maxTopics].name,pointer); else strcpy(topics[maxTopics].name,"");
	  
        pointer=mxmlElementGetAttr(group,"filename");
        if (pointer!=NULL) strcpy(topics[maxTopics].filename,pointer); else strcpy(topics[maxTopics].filename,"");
   	  
        pointer=mxmlElementGetAttr(group,"id");
        if (pointer!=NULL) topics[maxTopics].id=atoi(pointer); else topics[maxTopics].id=0;
   
        maxTopics++;    
   }     
   mxmlDelete(group);
   mxmlDelete(tree);   
}

void initQuestions(char* filename)
{
   maxQuestions=0;
   
   FILE *fp;
   mxml_node_t *tree;
   mxml_node_t *group;   
   const char  *pointer;
   char tmp[MAX_LEN];
   
   sprintf(tmp,"%s/%s", DATA_DIRECTORY, filename);
   
   /*Load our xml file! */
   fp = fopen(tmp, "r");
   if (fp!=NULL)
   {   
      tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
      fclose(fp);
   }
   else
   {
      // If file is not found, return direct
	  maxQuestions=-1;
      return;
   }
   
   // Read General stuff of question xm file
   group = mxmlFindElement(tree, tree, "header", NULL, NULL, MXML_DESCEND);  
	 
   pointer=mxmlElementGetAttr(group,"topic");
   if (pointer!=NULL) strcpy(information.topic,pointer); else strcpy(information.topic,"");
	  
   pointer=mxmlElementGetAttr(group,"author");
   if (pointer!=NULL) strcpy(information.author,pointer); else strcpy(information.author,"");
   
   pointer=mxmlElementGetAttr(group,"created");
   if (pointer!=NULL) strcpy(information.timestamp,pointer); else strcpy(information.timestamp,"");

   pointer=mxmlElementGetAttr(group,"note");
   if (pointer!=NULL) strcpy(information.note,pointer); else strcpy(information.note,"");

   // Read Questions
   for (group = mxmlFindElement(tree, tree, "item", NULL, NULL, MXML_DESCEND);
        group != NULL;
        group = mxmlFindElement(group, tree, "item", NULL, NULL, MXML_DESCEND))
   {		  
      pointer=mxmlElementGetAttr(group,"question");
	  if ((pointer!=NULL) && (strlen(pointer)>0))
	  {
	      strcpy(questions[maxQuestions].question,pointer); 
	  }  
	  else 
	  {  
	     strcpy(questions[maxQuestions].question,"");
	  }
	  
      pointer=mxmlElementGetAttr(group,"answerA");
      if ((pointer!=NULL) && (strlen(pointer)>0))
	  {
	     strcpy(questions[maxQuestions].answerA,pointer);
		 questions[maxQuestions].enabled[0]=true; 
      }
      else 
	  {
	     strcpy(questions[maxQuestions].answerA,"");
		 questions[maxQuestions].enabled[0]=false;
	  }
  
      pointer=mxmlElementGetAttr(group,"answerB");
      if ((pointer!=NULL) && (strlen(pointer)>0))
      {  
	      questions[maxQuestions].enabled[1]=true;
          strcpy(questions[maxQuestions].answerB,pointer); 
	  }
	  else 
	  {
	      strcpy(questions[maxQuestions].answerB,"");
		  questions[maxQuestions].enabled[1]=false;
      }
  
      pointer=mxmlElementGetAttr(group,"answerC");
      if ((pointer!=NULL) && (strlen(pointer)>0))
	  {
	      questions[maxQuestions].enabled[2]=true;
	      strcpy(questions[maxQuestions].answerC,pointer); 
	  }
	  else 
	  {
	      strcpy(questions[maxQuestions].answerC,"");
		  questions[maxQuestions].enabled[2]=false;
	  }
  
      pointer=mxmlElementGetAttr(group,"answerD");
      if ((pointer!=NULL) && (strlen(pointer)>0))
      { 
	      questions[maxQuestions].enabled[3]=true;
	      strcpy(questions[maxQuestions].answerD,pointer);  
      }
      else 
	  { 
	      strcpy(questions[maxQuestions].answerD,"");
		  questions[maxQuestions].enabled[3]=false;
	  }
    
      pointer=mxmlElementGetAttr(group,"answer");
      if (pointer!=NULL) 
	  {
	     // Convert (A,B,C,D) to (1,2,3,4)
         questions[maxQuestions].answer=pointer[0]-64;  
	  }
	  else
	  {
	     questions[maxQuestions].answer=0;
	  }
		 
	  pointer=mxmlElementGetAttr(group,"explanation");	 
	  if (pointer!=NULL) strcpy(questions[maxQuestions].explanation,pointer); else strcpy(questions[maxQuestions].explanation,"");
		 		 
	  questions[maxQuestions].played=false;
	  
	  maxQuestions++;
   }
     
   mxmlDelete(group);
   mxmlDelete(tree);
}

void initImages(void)
{
   // Buttons & Panels
   images.pointer=GRRLIB_LoadTexture((unsigned char*) pic8data);
   images.button1=GRRLIB_LoadTexture((unsigned char*) pic2data);
   images.button1select=GRRLIB_LoadTexture((unsigned char*) pic3data);
   images.button2=GRRLIB_LoadTexture((unsigned char*) pic4data);
   images.button2select=GRRLIB_LoadTexture((unsigned char*) pic5data);
   images.banner=GRRLIB_LoadTexture((unsigned char*) pic1data);
   images.panel1=GRRLIB_LoadTexture((unsigned char*) pic7data);  
   images.bar1=GRRLIB_LoadTexture((unsigned char*) pic16data);
   images.bar_cursor1=GRRLIB_LoadTexture((unsigned char*) pic17data);
   images.button3=GRRLIB_LoadTexture((unsigned char*) pic18data);
   images.button3select=GRRLIB_LoadTexture((unsigned char*) pic19data);
   images.panel2=GRRLIB_LoadTexture((unsigned char*) pic21data);
   
   // Land flags
   images.spanish_flag=GRRLIB_LoadTexture((unsigned char*) pic22data);
   images.france_flag=GRRLIB_LoadTexture((unsigned char*) pic24data);
   images.english_flag=GRRLIB_LoadTexture((unsigned char*) pic13data);
   images.nederlands_flag=GRRLIB_LoadTexture((unsigned char*) pic14data);
   images.deutsch_flag=GRRLIB_LoadTexture((unsigned char*) pic15data);

   // icons
   images.help=GRRLIB_LoadTexture((unsigned char*) pic23data);   
   images.right=GRRLIB_LoadTexture((unsigned char*) pic25data);
   images.wrong=GRRLIB_LoadTexture((unsigned char*) pic26data);
   images.sound=GRRLIB_LoadTexture((unsigned char*) pic28data);
   images.exit=GRRLIB_LoadTexture((unsigned char*) pic29data);
   images.info=GRRLIB_LoadTexture((unsigned char*) pic30data);
   images.question=GRRLIB_LoadTexture((unsigned char*) pic31data);
   
   // backgrounds
   images.background1=GRRLIB_LoadTexture((unsigned char*) pic33data);
   images.background2=GRRLIB_LoadTexture((unsigned char*) pic34data);
   images.background3=GRRLIB_LoadTexture((unsigned char*) pic35data);   
}

void initButtonsQuestionScreen(void)
{
   maxButtons=7;
   angle=0;

   // Hint1 button 
   buttons[0].image=images.button2;
   buttons[0].imageSelect=images.button2select;
   strcpy(buttons[0].name,translation.buttonHint);
   buttons[0].x=380;
   buttons[0].y=350+yOffset;
   buttons[0].width=84;
   buttons[0].height=84;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+20;
   buttons[0].ytext=buttons[0].y+35;
   
   // Hint2 button 
   buttons[1].image=images.button2;
   buttons[1].imageSelect=images.button2select;
   strcpy(buttons[1].name,translation.buttonHint);   
   buttons[1].x=465;
   buttons[1].y=350+yOffset;
   buttons[1].width=84;
   buttons[1].height=84;
   buttons[1].enabled=true;
   buttons[1].xtext=buttons[1].x+20;
   buttons[1].ytext=buttons[1].y+35;
   
   // Hint3 button 
   buttons[2].image=images.button2;
   buttons[2].imageSelect=images.button2select;
   strcpy(buttons[2].name,translation.buttonHint);
   buttons[2].x=550;
   buttons[2].y=350+yOffset;
   buttons[2].width=84;
   buttons[2].height=84;
   buttons[2].enabled=true;
   buttons[2].xtext=buttons[2].x+20;
   buttons[2].ytext=buttons[2].y+35;
   
   // AnswerA button
   buttons[3].image=images.button1;
   buttons[3].imageSelect=images.button1select;
   strcpy(buttons[3].name,translation.buttonAnswerA);
   buttons[3].x=2;
   buttons[3].y=332+yOffset;
   buttons[3].width=184;
   buttons[3].height=60;
   if (questions[selectedQuestion].enabled[0]) buttons[3].enabled=true; else buttons[3].enabled=false;
   buttons[3].xtext=buttons[3].x+(buttons[3].width/2)-((strlen(buttons[3].name)*13)/2);
   buttons[3].ytext=buttons[3].y+25;
      
   // AnswerB button
   buttons[4].image=images.button1;
   buttons[4].imageSelect=images.button1select;
   strcpy(buttons[4].name,translation.buttonAnswerB);
   buttons[4].x=194;
   buttons[4].y=332+yOffset;
   buttons[4].width=184;
   buttons[4].height=60;
   if (questions[selectedQuestion].enabled[1]) buttons[4].enabled=true; else buttons[4].enabled=false;
   buttons[4].xtext=buttons[4].x+(buttons[4].width/2)-((strlen(buttons[4].name)*13)/2);
   buttons[4].ytext=buttons[4].y+25;
      
   // AnswerC button
   buttons[5].image=images.button1;
   buttons[5].imageSelect=images.button1select;
   strcpy(buttons[5].name,translation.buttonAnswerC);
   buttons[5].x=2;
   buttons[5].y=391+yOffset;
   buttons[5].width=184;
   buttons[5].height=60;
   if (questions[selectedQuestion].enabled[2]) buttons[5].enabled=true; else buttons[5].enabled=false; 
   buttons[5].xtext=buttons[5].x+(buttons[5].width/2)-((strlen(buttons[5].name)*13)/2);
   buttons[5].ytext=buttons[5].y+25;
   
   // AnswerD button
   buttons[6].image=images.button1;
   buttons[6].imageSelect=images.button1select;
   strcpy(buttons[6].name,translation.buttonAnswerD);
   buttons[6].x=194;
   buttons[6].y=391+yOffset;
   buttons[6].width=184;
   buttons[6].height=60;
   if (questions[selectedQuestion].enabled[3]) buttons[6].enabled=true; else buttons[6].enabled=false;
   buttons[6].xtext=buttons[6].x+(buttons[6].width/2)-((strlen(buttons[6].name)*13)/2);
   buttons[6].ytext=buttons[6].y+25;
}

void initButtonsAnswerScreen(void)
{
   maxButtons=1;
   angle=0;
   alfa=0;
   alfa_direction=true;
   
   // Next button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonNext);
   buttons[0].x=2;
   buttons[0].y=332+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
}

void initButtonsResultScreen(void)
{
   maxButtons=1;
   angle=0;
   alfa=0;
   alfa_direction=true;

   // Next button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonNext);
   buttons[0].x=2;
   buttons[0].y=391+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
}

void initButtonsWelcomeScreen(void)
{
   maxButtons=6;
   angle=0;
   alfa=0;
   alfa_direction=true;
   
   // Language button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,languages[selectedLanguage].name);
   buttons[0].x=2;
   buttons[0].y=332+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
  
   // Topic button
   buttons[1].image=images.button1;
   buttons[1].imageSelect=images.button1select;
   strcpy(buttons[1].name,topics[selectedTopic].name);
   buttons[1].x=2;
   buttons[1].y=391+yOffset;
   buttons[1].width=184;
   buttons[1].height=60;
   if (maxQuestions!=-1) buttons[1].enabled=true; else buttons[1].enabled=false;
   buttons[1].xtext=buttons[1].x+(buttons[1].width/2)-((strlen(buttons[1].name)*13)/2);
   buttons[1].ytext=buttons[1].y+25;
   
    // Sound button
   buttons[2].image=images.button1;
   buttons[2].imageSelect=images.button1select;
   strcpy(buttons[2].name,translation.buttonSound);
   buttons[2].x=194;
   buttons[2].y=332+yOffset;
   buttons[2].width=184;
   buttons[2].height=60;
   buttons[2].enabled=true;
   buttons[2].xtext=buttons[2].x+(buttons[2].width/2)-((strlen(buttons[2].name)*13)/2);
   buttons[2].ytext=buttons[2].y+25;
  
   // Play button
   buttons[3].image=images.button1;
   buttons[3].imageSelect=images.button1select;
   strcpy(buttons[3].name,translation.buttonPlay);
   buttons[3].x=(MAX_HORZ_PIXELS-184);
   buttons[3].y=332+yOffset;
   buttons[3].width=184;
   buttons[3].height=60;
   if (maxQuestions!=-1) buttons[3].enabled=true; else buttons[3].enabled=false;
   buttons[3].xtext=buttons[3].x+(buttons[3].width/2)-((strlen(buttons[3].name)*13)/2);
   buttons[3].ytext=buttons[3].y+25;
   
    // Stop button
   buttons[4].image=images.button1;
   buttons[4].imageSelect=images.button1select;
   strcpy(buttons[4].name,translation.buttonStop);
   buttons[4].x=(MAX_HORZ_PIXELS-184);
   buttons[4].y=391+yOffset;
   buttons[4].width=184;
   buttons[4].height=60;
   buttons[4].enabled=true;
   buttons[4].xtext=buttons[4].x+(buttons[4].width/2)-((strlen(buttons[4].name)*13)/2);
   buttons[4].ytext=buttons[4].y+25;
   
    // High Score button
   buttons[5].image=images.button1;
   buttons[5].imageSelect=images.button1select;
   strcpy(buttons[5].name,translation.labelHighScore);
   buttons[5].x=194;
   buttons[5].y=391+yOffset;
   buttons[5].width=184;
   buttons[5].height=60;
   if (maxQuestions!=-1) buttons[5].enabled=true; else buttons[5].enabled=false;
   buttons[5].xtext=buttons[5].x+(buttons[5].width/2)-((strlen(buttons[5].name)*13)/2);
   buttons[5].ytext=buttons[5].y+25;  
}

void initButtonsGoodbyeScreen(void)
{
   maxButtons=6;
   angle=0;
   alfa=0;
   alfa_direction=true;
   
   // Continue button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonContinue);
   buttons[0].x=2;
   buttons[0].y=332+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
  
   // Credits button
   buttons[1].image=images.button1;
   buttons[1].imageSelect=images.button1select;
   strcpy(buttons[1].name,translation.buttonCredits);
   buttons[1].x=2;
   buttons[1].y=391+yOffset;
   buttons[1].width=184;
   buttons[1].height=60;
   buttons[1].enabled=true;
   buttons[1].xtext=buttons[1].x+(buttons[1].width/2)-((strlen(buttons[1].name)*13)/2);
   buttons[1].ytext=buttons[1].y+25;
   
   // Exit1 (To HBC) button
   buttons[2].image=images.button1;
   buttons[2].imageSelect=images.button1select;
   strcpy(buttons[2].name,translation.buttonExit1);
   buttons[2].x=(MAX_HORZ_PIXELS-184);
   buttons[2].y=332+yOffset;
   buttons[2].width=184;
   buttons[2].height=60;
   buttons[2].enabled=true;
   buttons[2].xtext=buttons[2].x+(buttons[2].width/2)-((strlen(buttons[2].name)*13)/2);
   buttons[2].ytext=buttons[2].y+25;
   
   // Exit2 (Reset Wii) button
   buttons[3].image=images.button1;
   buttons[3].imageSelect=images.button1select;
   strcpy(buttons[3].name,translation.buttonExit2);
   buttons[3].x=(MAX_HORZ_PIXELS-184);
   buttons[3].y=391+yOffset;
   buttons[3].width=184;
   buttons[3].height=60;
   buttons[3].enabled=true;
   buttons[3].xtext=buttons[3].x+(buttons[3].width/2)-((strlen(buttons[3].name)*13)/2);
   buttons[3].ytext=buttons[3].y+25;  
         
   // Help button
   buttons[4].image=images.button1;
   buttons[4].imageSelect=images.button1select;
   strcpy(buttons[4].name,translation.labelHelp);
   buttons[4].x=194;
   buttons[4].y=332+yOffset;
   buttons[4].width=184;
   buttons[4].height=60;
   buttons[4].enabled=true;
   buttons[4].xtext=buttons[4].x+(buttons[4].width/2)-((strlen(buttons[4].name)*13)/2);
   buttons[4].ytext=buttons[4].y+25;
   
    // Credits button
   buttons[5].image=images.button1;
   buttons[5].imageSelect=images.button1select;
   strcpy(buttons[5].name,translation.buttonReleaseNotes);
   buttons[5].x=194;
   buttons[5].y=391+yOffset;
   buttons[5].width=184;
   buttons[5].height=60;
   buttons[5].enabled=true;
   buttons[5].xtext=buttons[5].x+10+(buttons[5].width/2)-((strlen(buttons[5].name)*13)/2);
   buttons[5].ytext=buttons[5].y+25;
}

void initButtonsSoundScreen(void)
{
   maxButtons=7;
   angle=0;
   alfa=0;
   alfa_direction=true;
 
   // Back button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonBack);
   buttons[0].x=2;
   buttons[0].y=391+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
   
   // - music volume button
   buttons[1].image=images.button3;
   buttons[1].imageSelect=images.button3select;
   strcpy(buttons[1].name,"-");
   buttons[1].x=40;
   buttons[1].y=110+yOffset;
   buttons[1].width=60;
   buttons[1].height=60;
   buttons[1].enabled=true;
   buttons[1].xtext=buttons[1].x+(buttons[1].width/2)-((strlen(buttons[1].name)*13)/2);
   buttons[1].ytext=buttons[1].y+25;
   
   // + music volume button
   buttons[2].image=images.button3;
   buttons[2].imageSelect=images.button3select;
   strcpy(buttons[2].name,"+");
   buttons[2].x=MAX_HORZ_PIXELS-100;
   buttons[2].y=110+yOffset;
   buttons[2].width=60;
   buttons[2].height=60;
   buttons[2].enabled=true;
   buttons[2].xtext=buttons[2].x+(buttons[2].width/2)-((strlen(buttons[2].name)*13)/2);
   buttons[2].ytext=buttons[2].y+25;
   
   // - effect volume button
   buttons[3].image=images.button3;
   buttons[3].imageSelect=images.button3select;
   strcpy(buttons[3].name,"-");
   buttons[3].x=40;
   buttons[3].y=210+yOffset;
   buttons[3].width=60;
   buttons[3].height=60;
   buttons[3].enabled=true;
   buttons[3].xtext=buttons[3].x+(buttons[3].width/2)-((strlen(buttons[3].name)*13)/2);
   buttons[3].ytext=buttons[3].y+25;
   
   // + effect volume button
   buttons[4].image=images.button3;
   buttons[4].imageSelect=images.button3select;
   strcpy(buttons[4].name,"+");
   buttons[4].x=MAX_HORZ_PIXELS-100;
   buttons[4].y=210+yOffset;
   buttons[4].width=60;
   buttons[4].height=60;
   buttons[4].enabled=true;
   buttons[4].xtext=buttons[4].x+(buttons[4].width/2)-((strlen(buttons[4].name)*13)/2);
   buttons[4].ytext=buttons[4].y+25;
   
   // - music track button
   buttons[5].image=images.button3;
   buttons[5].imageSelect=images.button3select;
   strcpy(buttons[5].name,"-");
   buttons[5].x=100;
   buttons[5].y=300+yOffset;
   buttons[5].width=60;
   buttons[5].height=60;
   buttons[5].enabled=true;
   buttons[5].xtext=buttons[5].x+(buttons[5].width/2)-((strlen(buttons[5].name)*13)/2);
   buttons[5].ytext=buttons[5].y+25;
   
   // + music track button
   buttons[6].image=images.button3;
   buttons[6].imageSelect=images.button3select;
   strcpy(buttons[6].name,"+");
   buttons[6].x=MAX_HORZ_PIXELS-150;
   buttons[6].y=300+yOffset;
   buttons[6].width=60;
   buttons[6].height=60;
   buttons[6].enabled=true;
   buttons[6].xtext=buttons[6].x+(buttons[6].width/2)-((strlen(buttons[6].name)*13)/2);
   buttons[6].ytext=buttons[6].y+25;
}
  
void initButtonsCreditsScreen(void)
{
   maxButtons=1;
   angle=0;
   alfa=0;
   alfa_direction=true;
   
   // Back button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonBack);
   buttons[0].x=2;
   buttons[0].y=391+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
}

void initButtonsHighScoreScreen(void)
{
   maxButtons=1;
   angle=0;
   alfa=0;
   alfa_direction=true;
      
   // Back button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonBack);
   buttons[0].x=2;
   buttons[0].y=391+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
}

void initButtonsHelpScreen(void)
{
   maxButtons=1;
   angle=0;
   alfa=0;
   alfa_direction=true;
   
   // Back button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonBack);
   buttons[0].x=2;
   buttons[0].y=391+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
}

void initButtonsReleaseNotes(void)
{
   maxButtons=1;
   angle=0;
   alfa=0;
   alfa_direction=true;
   
   // Back button
   buttons[0].image=images.button1;
   buttons[0].imageSelect=images.button1select;
   strcpy(buttons[0].name,translation.buttonBack);
   buttons[0].x=2;
   buttons[0].y=391+yOffset;
   buttons[0].width=184;
   buttons[0].height=60;
   buttons[0].enabled=true;
   buttons[0].xtext=buttons[0].x+(buttons[0].width/2)-((strlen(buttons[0].name)*13)/2);
   buttons[0].ytext=buttons[0].y+25;
}


void initStateMachine( void )
{	
    switch( stateMachine )
	{
	     case stateWelcome:	
				initButtonsWelcomeScreen();   	      
			    break;
			  
	     case stateQuestion:
				if (stateMachinePrev!=stateMachine) initButtonsQuestionScreen();  
		        break;
			  
	     case stateAnswer:
				if (stateMachinePrev!=stateMachine) initButtonsAnswerScreen(); 
		        break;
			  
		 case stateResult:
				if (stateMachinePrev!=stateMachine) initButtonsResultScreen();  
		        break;
				
		 case stateSound:
		        if (stateMachinePrev!=stateMachine) initButtonsSoundScreen();
				break;
				
		 case stateGoodbye:
				if (stateMachinePrev!=stateMachine) initButtonsGoodbyeScreen();  
		        break;		

		 case stateCredits:
				if (stateMachinePrev!=stateMachine) initButtonsCreditsScreen();  
		        break;			
				
		 case stateHighScore:
				if (stateMachinePrev!=stateMachine) initButtonsHighScoreScreen();  
		        break;	
				
		 case stateHelp:
				if (stateMachinePrev!=stateMachine) initButtonsHelpScreen();  
		        break;	
				
		 case stateReleaseNotes:
				if (stateMachinePrev!=stateMachine) initButtonsReleaseNotes();  
		        break;	
    }	
    stateMachinePrev=stateMachine;
}

// -----------------------------------------------------------
// BUTTON LOGIC
// -----------------------------------------------------------

int buttonSelected(int x, int y)
{
   int i;
   
   for (i=0; i<maxButtons; i++)
   {
       if ( buttons[i].enabled &&
	        (x>=buttons[i].x) && (x<=buttons[i].x+buttons[i].width) && 
	        (y>=buttons[i].y) && (y<=buttons[i].y+buttons[i].height) )
	   {
          SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_16BIT, 8000, 0, (char *) effect3_wav, effect3_wav_size, effectVolume*EFFECT_MULTIPLER, effectVolume*EFFECT_MULTIPLER, NULL);
	      return i;
	   }	   
   }
   return -1;
}

void buttonHint(int number)
{
   bool flag=true;
   int i=0;
   int count=0;
      
   // If more then one answer is possible continue
   for (i=0; i<MAX_ANSWERS; i++)
   {   
      if (questions[selectedQuestion].enabled[i]) count++;
   }
         
   if (count>1)
   {
     while (flag)
     {
       // Random disable answer
	   int number=rand() % 4;
	   if (((number+1)!=questions[selectedQuestion].answer) && questions[selectedQuestion].enabled[number]==true)
	   {
	     // Disable question answer
	     questions[selectedQuestion].enabled[number]=false;
		 
		 // Disable answer button
		 buttons[number+3].enabled=false;
		 hintCounter++;
		 
		 flag=false;
	    }
     }
     buttons[number].enabled=false;
   }
}

void buttonLanguage(void)
{
    if (++selectedLanguage>=maxLanguages) selectedLanguage=0;
	
	selectedTopic=0;
	selectedQuestion=0;
	score=0;
	hintCounter=0;
	   
	initTranslation(languages[selectedLanguage].translation);
	initTopics(languages[selectedLanguage].topics);
	initQuestions( topics[selectedTopic].filename );
}

void buttonTopic(void)
{
    if (++selectedTopic>=maxTopics) selectedTopic=0;

    score=0;
	selectedQuestion=0;
	hintCounter=0;
	
	initQuestions(topics[selectedTopic].filename);
}

void buttonPlay(void)
{
	selectedQuestion=0;
	score=0;
	hintCounter=0;
	startTime=time(NULL);
	
	correctAnswer=false;
    initQuestions( topics[selectedTopic].filename );
   
	stateMachine=stateQuestion;
}

void buttonAnswer(int number)
{
	stateMachine=stateAnswer;
  
	if (questions[selectedQuestion].answer==number)
	{
		score++;
		correctAnswer=true;	
		//SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_16BIT, 8000, 0, (char *) effect1_wav, effect1_wav_size, effectVolume*EFFECT_MULTIPLER, effectVolume*EFFECT_MULTIPLER, NULL);             
	}
	else
	{
	    correctAnswer=false;
		//SND_SetVoice(SND_GetFirstUnusedVoice(), VOICE_MONO_16BIT, 8000, 0, (char *) effect2_wav, effect2_wav_size, effectVolume*EFFECT_MULTIPLER, effectVolume*EFFECT_MULTIPLER, NULL);		
	}
}
			
void buttonExit(int index)
{    
   // Stop network thread
   tcp_stop_thread();

   //u8 *texture = GRRLIB_ScreenCap();
   //GRRLIB_DrawImg_FadeOut(0, yOffset, 640, 480, texture, 1, 0.90, 1);
   //free(texture);

   // Stop music track
   MODPlay_Stop(&snd1);
	
   if (index==0)
   {   
	   exit(0);
   }
   else
   {
	   SYS_ResetSystem(SYS_RESTART,0,0);	
   }
}

void buttonNext(void)
{
   if (++selectedQuestion>=maxQuestions)
   {	
      playTime = time(NULL)-startTime; 
      processHighScore();
      stateMachine=stateResult;
   }
   else
   {   
      stateMachine=stateQuestion;
   }
}
	  	 

void buttonMinus(void)
{
   if ((stateMachine!=stateGoodbye) && (stateMachine!=stateHelp) && (stateMachine!=stateCredits))
   {
	  stateMachineStorage2=stateMachine;
	  stateMachine=stateHelp;
   }
}
 
void buttonMinusVolume(int index)
{
   if (index==0)
   {
       // Music volume
	   if (musicVolume>0) musicVolume--;   
	   MODPlay_SetVolume( &snd1, musicVolume*MUSIC_MULTIPLER,musicVolume*MUSIC_MULTIPLER);
   }
   else if (index==1)
   {
       // Effect volume
       if (effectVolume>0) effectVolume--; 
   }
   else if (index==2)
   {
      MODPlay_Stop(&snd1);
      if (selectedMusic>1) selectedMusic--; else selectedMusic=(MAX_MUSIC_TRACK-1);
	  initMusicTrack();
   }
}

void buttonPlusVolume(int index)
{
   if (index==0)
   {
       // Music volume
	   if (musicVolume<MAX_SOUND_VOLUME) musicVolume++;   
	   MODPlay_SetVolume( &snd1, musicVolume*MUSIC_MULTIPLER,musicVolume*MUSIC_MULTIPLER); 
   }
   else if (index==1)
   {
       // Effect volume
       if (effectVolume<MAX_SOUND_VOLUME) effectVolume++; 
   }
   else if (index==2)
   {
      MODPlay_Stop(&snd1);
      if (selectedMusic<MAX_MUSIC_TRACK) selectedMusic++; else selectedMusic=1;
	  initMusicTrack();
   }
}

void buttonHome(void)
{
   if (stateMachine!=stateGoodbye)
   {
	  stateMachineStorage=stateMachine;
	  stateMachine=stateGoodbye;
   }
   else
   {      
      buttonExit(0);
   }
}

void button1x(void)
{
   boolean flag = true;
 
   MODPlay_Stop(&snd1);  
   if (selectedMusic<MAX_MUSIC_TRACK) selectedMusic++; else selectedMusic=1;   
   initMusicTrack();
      
   // Handle buttons events  
   while ( flag )
   {
      WPAD_ScanPads(); 	
      if (WPAD_ButtonsUp(0) & BUTTON_1) flag=false;
   }
}

void button2y(void)
{
   boolean flag = true;
 
   MODPlay_Stop(&snd1);
   if (selectedMusic>1) selectedMusic--; else selectedMusic=(MAX_MUSIC_TRACK-1);   
   initMusicTrack();
      
   // Handle buttons events  
   while ( flag )
   {
      WPAD_ScanPads(); 	
      if (WPAD_ButtonsUp(0) & BUTTON_2) flag=false;
   }
}

void buttonA(int x,int y)
{
  rumbleCounter=MAX_RUMBLE;

  switch (stateMachine)  
  {
     case stateWelcome:
     {
        switch (buttonSelected(x,y))
	    {
          case 0: // language button	
				  buttonLanguage();
			      break;
	  
	      case 1: // topic button
				  buttonTopic();
			      break;
				  
		  case 2: // sound button
				  stateMachine=stateSound;
			      break;
	  
	      case 3: // play button		 
				  buttonPlay();
			      break;
		  
		  case 4: // Stop button event	
				  stateMachineStorage=stateMachine;
			      stateMachine=stateGoodbye;
			      break;	
				  
		  case 5: // high Score button
				  stateMachine=stateHighScore;
			      break;
 
	    }
     }
	 break;
	 
     case stateQuestion:
	 {
	    switch (buttonSelected(x,y))
	    {
          case 0: // hint 1	button event	
		          buttonHint(0); 			 
			      break;
	  
	      case 1: // hint 2 button event
			      buttonHint(1);
			      break;
	  
	      case 2: // hint 3 button event
			      buttonHint(2);
			      break;
	  
	      case 3: // Answer A button event
			      buttonAnswer(1);
			      break;
	  
	      case 4: // Answer B button event
		      	  buttonAnswer(2);
			      break;
	  
		  case 5: // Answer C button event
			      buttonAnswer(3);
			      break;
	  
	      case 6: // Answer D button event
		    	  buttonAnswer(4);
			      break;
	    }
     }
     break;
	 
     case stateAnswer:
	 {
	    switch (buttonSelected(x,y))
	    { 
		  case 0: // Next button event	
		          buttonNext(); 			 
			      break;
	    }
				  
	 }	 
	 break;
	 
	 case stateResult:
	 {     
  	      switch (buttonSelected(x,y))
	      {
	         case 0: // Next button event	        
			         stateMachine=stateHighScore;
			         break;	   	 
		  }
	 }
	 break;
	 
	 case stateHighScore:
	 {     
  	      switch (buttonSelected(x,y))
	      {				 
		     case 0: // Back button event
			         stateMachine=stateWelcome;
			         break;
		  }
	 }
	 break;	
	 	 
	 case stateHelp:
	 {     
  	      switch (buttonSelected(x,y))
	      {				 
		     case 0: // Back button event
			         stateMachine=stateMachineStorage2;
			         break;
		  }
	 }
	 break;	
	 
	 case stateSound:
	 {     
  	      switch (buttonSelected(x,y))
	      {
	         case 0: // Back button event          
			         stateMachine=stateWelcome;
			         break;	   
					 
			 case 1: // - music volume button event	           
			         buttonMinusVolume(0);
			         break;	   
			 
			 case 2: // + music volume button event	           
			         buttonPlusVolume(0);
			         break;	 
					 
			 case 3: // - effect volume button event	           
			         buttonMinusVolume(1);
			         break;	   
			 
			 case 4: // + effect volume button event	           
			         buttonPlusVolume(1);
			         break;	 
					 
			 case 5: // - music track button event	           
			         buttonMinusVolume(2);
			         break;	   
			 
			 case 6: // + music track  button event	           
			         buttonPlusVolume(2);
			         break;
					 
		  }
	 }
	 break;
	 	 
	 case stateCredits:
	 {     
  	      switch (buttonSelected(x,y))
	      {
	         case 0: // back button event           
			         stateMachine=stateGoodbye;
			         break;	     
		  }
	 }	 
	 break;
	 
	 case stateGoodbye:
	 {     
  	      switch (buttonSelected(x,y))
	      {
	         case 0: // Continue button event	           
			         stateMachine=stateMachineStorage;
			         break;	   
			   
			 case 1: // Show Credit Screen	           
			         stateMachine=stateCredits;
			         break;	 
					 
	         case 2: // Exit (to HBC) button event	           
			         buttonExit(0);
			         break;	 
					 
		     case 3: // Exit (reset Wii) button event	           
			         buttonExit(1);
			         break;	
					 
			 case 4: // Help button event	           
			         stateMachineStorage2=stateMachine;
					 stateMachine=stateHelp;
			         break;	
					 
			 case 5: // ReleaseNotes button event	           
			         stateMachineStorage2=stateMachine;
					 stateMachine=stateReleaseNotes;
			         break;	
		  }
	 }
	 break;	 
	 
	 case stateReleaseNotes:
	 {     
  	      switch (buttonSelected(x,y))
	      {				 
		     case 0: // Back button event
			         stateMachine=stateMachineStorage2;
			         break;
		  }
	 }
	 break;	
   }         
}
 
// -----------------------------------------------------------
// SCREEN LOGIC
// -----------------------------------------------------------

void drawWordwrap(char *input, int x, int y, int maxLineWidth, int stepSize) 
{
   char tmp[MAX_LEN];
   int startIndex=0;
   int lastSpace=0;
   int endIndex=strlen(input);
   int ypos=y+yOffset;
   int i,z=0;

    // Make local copy   
   strcpy(tmp,input);
		
   for (i=0; i<endIndex; i++)
   {
      if (tmp[i]==' ') lastSpace=i;	 
	  if (z++>maxLineWidth)
	  {
	     tmp[lastSpace]=0x00;
	     drawText(x, ypos, fontNormal, tmp+startIndex);
	
		 startIndex=lastSpace+1;
		 ypos=ypos+stepSize;
		 z=0;
	  }
   }
   if (z<=maxLineWidth)
   {
	  drawText(x, ypos, fontNormal, tmp+startIndex);
   }
}

void drawButtons(int x, int y)
{
   int i;
   bool button=false;
   
   for (i=0; i<maxButtons; i++)
   {
      if ( buttons[i].enabled )
      {	 
	     if ((x>=buttons[i].x) && (x<=buttons[i].x+buttons[i].width) && 
	         (y>=buttons[i].y) && (y<=buttons[i].y+buttons[i].height) )			
	     {
		    // Draw selected button
	        GRRLIB_DrawImg(buttons[i].x, buttons[i].y, buttons[i].width, buttons[i].height, buttons[i].imageSelect, 0, 1, 1, 255 );		  
		    if (--rumbleCounter>0)  WPAD_Rumble(0,1); else WPAD_Rumble(0,0);
			button=true;
	     }
	     else
	     {
		    // Draw not selected button
	        GRRLIB_DrawImg(buttons[i].x, buttons[i].y, buttons[i].width, buttons[i].height, buttons[i].image, 0, 1, 1, 255 );
	     }
		 drawText(buttons[i].xtext,buttons[i].ytext, fontButton, buttons[i].name);
	  }
    }
	
	// If no button selected, stop rumble.
	if (!button) 
	{
	   WPAD_Rumble(0,0);
	   rumbleCounter=MAX_RUMBLE;
	}
}



void drawText(int x, int y, int type, char *text,...)
{
   char tmp[MAX_LEN];
   memset(tmp,0x00,sizeof(tmp));
   //void *string1;
   
   if (text!=NULL)
   {    		
     va_list argp;
     va_start(argp, text);
     vsprintf(tmp, text, argp);
     va_end(argp);
	 
     switch (type)
     {
       case fontTitle: 
	   {
	      if (x==0) x=320-((strlen(tmp)*33)/2);  
		  GRRLIB_Printf2(x, y-70, tmp, 72, COLOR_WHITESMOKE); 
	   }
	   break;
	   	   
	   case fontSubTitle:
	   {
	      if (x==0) x=320-((strlen(tmp)*12)/2);
		  GRRLIB_Printf2(x, y, tmp, 24, COLOR_WHITESMOKE);          
	   }
	   break;
	   
	   case fontParagraph:
	   {
	       if (x==0) x=320-((strlen(tmp)*8)/2);	   
		   GRRLIB_Printf2(x, y, tmp, 14, COLOR_LIGHTBLUE);            
	   }
	   break;
	   	   
	   case fontNormal:
	   {
	       if (x==0) x=320-((strlen(tmp)*7)/2);
		   GRRLIB_Printf2(x, y, tmp, 16, COLOR_WHITESMOKE);            
	   }
	   break;
	   
	   case fontButton:
	   {
		   GRRLIB_Printf2(x, y-13, tmp, 24, COLOR_WHITESMOKE);            
	   }
	   break;
	   
	   case fontHead:
	   {
		   GRRLIB_Printf2(x, y-13, tmp, 24, COLOR_LIGHTBLUE);            
	   }
	   break;
	   
	   case fontNew:
	   {
	       if (x==0) x=320-((strlen(tmp)*6)/2);	   
		   GRRLIB_Printf2(x, y, tmp, 14, COLOR_LIGHTBLUE);            
	   }
	   break;
	 }
   }
}

void drawWelcomeScreen()
{
    int ypos=130+yOffset;
	char *version;
    
	// Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 276, images.panel1, 0, 1, 1, 255 );

    // Draw title
    drawText(0, ypos, fontTitle, translation.labelWelcome);
		
	// Check is new bibleQuiz version is available
	version=tcp_get_version();
    if ( (version!=NULL) && (strlen(version)>0) && (strcmp(version,PROGRAM_VERSION)!=0) )
    {    
        char tmp[MAX_LEN];     	
	    sprintf(tmp,"%s [v%s]",translation.labelNewVersion,version);
	    drawText(0, ypos+5, fontNew, tmp);
    }
    
	// Draw content
	ypos+=20;
	drawText(40, ypos, fontParagraph, "%s:", translation.labelTopic);
	ypos+=12;
	if (maxQuestions!=-1) drawText(40, ypos, fontNormal, information.topic);
	
	ypos+=30;
	drawText(40, ypos, fontParagraph, "%s:", translation.labelCreated);
	ypos+=12;
	if (maxQuestions!=-1) drawText(40, ypos, fontNormal, information.timestamp);
	
	ypos+=30;
	drawText(40, ypos, fontParagraph, "%s:", translation.labelAuthor);
	ypos+=12;
	if (maxQuestions!=-1) drawText(40, ypos, fontNormal, information.author);
	
	ypos+=20;
	if (maxQuestions!=-1) drawWordwrap( information.note, 0, ypos-10, 70, 15);

		  
	switch (selectedLanguage)		  
	{  
		case 0: GRRLIB_DrawImg(460,160+yOffset,132, 88, images.english_flag, 0, 1, 1, 255 );
		        break;
					 
		case 1: GRRLIB_DrawImg(460,160+yOffset,132, 88, images.nederlands_flag, 0, 1, 1, 255 );
		        break;
					 
		case 2: GRRLIB_DrawImg(460,160+yOffset,132, 88, images.deutsch_flag, 0, 1, 1, 255 );
		        break;
		
		case 3: GRRLIB_DrawImg(460,160+yOffset,132, 88, images.spanish_flag, 0, 1, 1, 255 );
		        break;
				
		case 4: GRRLIB_DrawImg(460,160+yOffset,132, 88, images.france_flag, 0, 1, 1, 255 );
		        break;
	}
}

void drawQuestionScreen(void)
{ 
    int ypos=yOffset+85;
	
     // Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 276, images.panel1, 0, 1, 1, 255 );

    // Draw background1 icon
	GRRLIB_DrawImg(150,140+yOffset,128, 128, images.background1, 0, 2.8, 2.8, 128 );
	
	// Draw question icon
	GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256,  images.question, 0, ICON_ZOOM, ICON_ZOOM, 255 );
			
	// Draw title
	drawText(40, ypos, fontParagraph, "%s:", translation.labelTopic);
	
	// Draw Content
	ypos+=15;
	drawText(40, ypos, fontNormal, "%s:", information.topic);
	     
	ypos+=30;
    drawText(40, ypos, fontParagraph, "%s:", translation.labelQuestion);
	drawWordwrap( questions[selectedQuestion].question, 40, ypos-10, 70, 15);
    	
	ypos+=90;
    drawText(40, ypos, fontParagraph, "%s:", translation.labelAnswers);
	
	ypos+=15;
	if (questions[selectedQuestion].enabled[0])
	{	 
	  drawText(40, ypos, fontNormal, "A) %s", questions[selectedQuestion].answerA);
    }	

	ypos+=15;      
	if (questions[selectedQuestion].enabled[1])
	{
	  drawText(40, ypos, fontNormal, "B) %s", questions[selectedQuestion].answerB);
	}

    ypos+=15;    
	if (questions[selectedQuestion].enabled[2])
	{
	  drawText(40, ypos, fontNormal, "C) %s", questions[selectedQuestion].answerC);
	}
	 
    ypos+=15; 
	if (questions[selectedQuestion].enabled[3])
	{
	  drawText(40, ypos, fontNormal, "D) %s", questions[selectedQuestion].answerD);
	}
}

void drawResultScreen(void)
{  
	int  ypos=yOffset+140;
	float cat1=maxQuestions*0.6;
	float cat2=maxQuestions*0.8;
	
	 // Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 336, images.panel2, 0, 1, 1, 255 );
 	
    // Draw background2 icon
	GRRLIB_DrawImg(180,90+yOffset,256, 256, images.background2, 0, 1.4, 1.2, 128 );
	
	// Draw Info icon
	GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256,  images.info, 0, ICON_ZOOM, ICON_ZOOM, 255 );

   	// Show title
    drawText(0, ypos, fontTitle, translation.labelResults);
 
     // Show Content
	ypos+=40;
	drawText(0, ypos, fontSubTitle, translation.labelResult);
	
    ypos+=60;
	drawText(0, ypos, fontSubTitle, "%2.2f-%d.00 %s", cat2+1, maxQuestions, translation.labelCategory1);	
	
    ypos+=30;
	drawText(0, ypos, fontSubTitle, "%2.2f-%2.2f %s ", cat1+1, cat2, translation.labelCategory2);	

    ypos+=30;
	drawText(0, ypos, fontSubTitle, "0.00-%2.2f %s", cat1, translation.labelCategory3);
}

void drawAnswerScreen(void)
{		 
     int ypos=200+yOffset;
	
    // Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 276, images.panel1, 0, 1, 1, 255 );

    // Draw background1 icon
	GRRLIB_DrawImg(150,140+yOffset,128, 128, images.background1, 0, 2.8, 2.8, 128 );
		
	// Draw title
   	if ( correctAnswer )
	{
	    // Draw Right icon
	    GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256, images.right, 0, ICON_ZOOM, ICON_ZOOM, 255 );
		
		// Draw Righ label		
		drawText(0, ypos, fontTitle, translation.labelRight);
	}
	else
	{
	    // Draw Wrong Icon
	    GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256, images.wrong, 0, ICON_ZOOM, ICON_ZOOM, 255 );
		
		// Draw Wrong Label		
		drawText(0, ypos, fontTitle, translation.labelWrong);
	}
	
}

void drawSoundScreen(void)
{  
    int ypos=100+yOffset;
	
	// Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 336, images.panel2, 0, 1, 1, 255 );
	
	// Draw Sound icon
	GRRLIB_DrawImg((640/2)-128, ((480/2)-140)+yOffset,256, 256, images.sound, angle, 1, 1, 255 );
	
    // Draw content	
    drawText(0, ypos, fontSubTitle, translation.labelMusic);	
	ypos+=20;
    GRRLIB_DrawImg(104,ypos,432,60, images.bar1, 0, 1, 1, 255 );
	ypos+=10;
	GRRLIB_DrawImg(115+(musicVolume*40),ypos,8,24, images.bar_cursor1, 0, 1, 1, 255 );
  
    ypos+=80;
    drawText(0, ypos, fontSubTitle, translation.labelEffects);
	ypos+=20;	
	GRRLIB_DrawImg(104,ypos,432,60, images.bar1, 0, 1, 1, 255 );
	ypos+=10;
	GRRLIB_DrawImg(115+(effectVolume*40),ypos,8,24, images.bar_cursor1, 0, 1, 1, 255 );
	
	ypos+=70;
	drawText(0, ypos, fontSubTitle, "%s [%d]", translation.labelTrack, selectedMusic);		
}

void drawGoodbyeScreen(void)
{
    int ypos=220+yOffset;
	
	 // Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 276, images.panel1, 0, 1, 1, 255 );

    // Draw Exit icon
	GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256, images.exit, 0, ICON_ZOOM, ICON_ZOOM, 255 );
 	
    // Draw title
	drawText(0, ypos, fontTitle, translation.labelGoodbye);		
}

void drawCreditsScreen(void)
{
    int  ypos=yOffset+80;

    // Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 336, images.panel2, 0, 1, 1, 255 );
	
    // Draw background3 icon
	GRRLIB_DrawImg(190,95+yOffset,256, 256, images.background3, 0, 1.3, 1.3, alfa );

	// Draw Credits icon
	GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256, images.info, 0, ICON_ZOOM, ICON_ZOOM, 255 );
		
    // Show Content
	drawText(0, ypos, fontParagraph, "GAME LOGIC");
	ypos+=15;
	drawText(0, ypos, fontNormal, "wplaat");

	ypos+=25;
	drawText(0, ypos, fontParagraph, "GAME GRAPHICS");
  	ypos+=15;
	drawText(0, ypos, fontNormal, "wplaat");
  	ypos+=15;
	drawText(0, ypos, fontNormal, "DrTwox");
	
	ypos+=25;
	drawText(0, ypos, fontParagraph, "MUSIC & SOUND EFFECTS");
	ypos+=15;
	drawText(0, ypos, fontNormal, "wplaat");
  
  	ypos+=25;
	drawText(0, ypos, fontParagraph, "TESTERS");
	ypos+=15;
	drawText(0, ypos, fontNormal, "wplaat");	  
	ypos+=15;
	drawText(0, ypos, fontNormal, "zouzzz");
		  		  	  
	ypos+=25;
	drawText(0, ypos, fontParagraph, "CONTENT PROVIDERS");
	ypos+=15;
	drawText(0, ypos, fontNormal, "wplaat");	 
	ypos+=15;
	drawText(0, ypos, fontNormal, "Rhoderik");
	ypos+=15;
	drawText(0, ypos, fontNormal, "Flark");
	ypos+=15;
	drawText(0, ypos, fontNormal, "www.biblequizzes.com");
	
	ypos+=25;
	drawText(0, ypos, fontNormal,"Greetings to everybody in the Wii homebrew scene");
}		 

void drawHighScoreScreen(void)
{
	int  ypos=yOffset+130;
	int  i;
	char tmp[MAX_LEN];
	struct tm *local;
	struct tm *level;

    // Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 336, images.panel2, 0, 1, 1, 255 );
 	
    // Draw background2 icon
	GRRLIB_DrawImg(180,90+yOffset,256, 256, images.background2, 0, 1.4, 1.2, 128 );
	
	// Draw Info icon
	GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256,  images.info, 0, ICON_ZOOM, ICON_ZOOM, 255 );
		
	// Draw title
	drawText(0, ypos, fontTitle, translation.labelHighScore);	

    // Show Content
    ypos+=30;
	drawText(30, ypos, fontParagraph, translation.labelDate);
	drawText(210, ypos, fontParagraph, translation.labelPlayTime);
	drawText(345, ypos, fontParagraph, translation.labelScore);
	drawText(420, ypos, fontParagraph, translation.labelHints);
	drawText(495, ypos, fontParagraph, translation.labelTopic);

    for (i=0; i<maxHighScores; i++)
	{
	   // Show only highscores from the seleceted language
       if ( languages[selectedLanguage].id==highscores[i].languageId )
	   {
	     ypos+=15;  
	   
	     local = localtime(&highscores[i].startTime);
	     sprintf(tmp,"%02d-%02d-%04d %02d:%02d:%02d", 
			  local->tm_mday, local->tm_mon+1, local->tm_year+1900, 
			  local->tm_hour, local->tm_min, local->tm_sec);
		 drawText(30, ypos, fontNormal, tmp);
	   
	     level = localtime(&highscores[i].playTime);
	     sprintf(tmp,"%02d:%02d:%02d", level->tm_hour, level->tm_min, level->tm_sec);
		 drawText(210, ypos, fontNormal, tmp);
 
         drawText(345, ypos, fontNormal, "%d / %d", highscores[i].score,highscores[i].questions);
         drawText(420, ypos, fontNormal, "%d", highscores[i].hint);
         drawText(495, ypos, fontNormal, highscores[i].topic);
       }	
	}	
}

void drawHelpScreen(void)
{
	int  ypos=yOffset+80;

    // Draw panel
    GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 336, images.panel2, 0, 1, 1, 255 );
 		
    // Draw Help icon
    GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256, images.question, 0, ICON_ZOOM, ICON_ZOOM, 255 );
	
	// Draw Image
	ypos+=25;
	GRRLIB_DrawImg(80,ypos,260,236, images.help, 0, 1, 1, 255 );
	
	ypos+=250;
	drawText(0, ypos, fontNormal, "Please visit http://www.wiibrew.org/wiki/BibleQuiz for more information");
}


void drawReleaseNotes(void)
{
   int  ypos=yOffset+75;
   int  i=0;
   int  len=0;
   int  lineCount=0;
   int  maxLines=0;
   char *buffer;
   char text[MAX_BUFFER_SIZE];
   char tmp[MAX_LEN];
		
   // Draw panel
   GRRLIB_DrawImg(0,58+yOffset,MAX_HORZ_PIXELS, 336, images.panel2, 0, 1, 1, 255 );
 
   // Draw Info icon
   GRRLIB_DrawImg(ICON_X,ICON_Y+yOffset,256, 256,  images.info, 0, ICON_ZOOM, ICON_ZOOM, 255 );
		 	      
   // Draw content	
   buffer=tcp_get_releasenote();
   if (buffer!=NULL) 
   {
	  strncpy(text,buffer,MAX_BUFFER_SIZE);
	  len=strlen(text);
	  for (i=0;i<len;i++) if (text[i]=='\n') maxLines++;
   }
	
   if (len!=0)
   {		  
	   int startpos=0;
  	   for (i=0; i<len; i++)
	   {
	      if (text[i]=='\n') 
		  {
		     text[i]=0x00;
		     if ((lineCount++)>notesStartLine+17) break;
		     if (lineCount>notesStartLine) 
			 {				   
		        ypos+=15;
			    sprintf(tmp,"%s",text+startpos);
		        drawText(40, ypos, fontNormal, tmp);	
			 }
			 
			 if (strcmp(text+startpos,"last update")==0) break;
			  
			 startpos=i+1;
						
			 if (noteDelay++>800)
		     {
			    if (notesStartLine++>maxLines) notesStartLine=4;
			    noteDelay=0;
			 }
		  }
	   }
	}
	else
	{
	   ypos+=60;
	   drawText(0, ypos, fontNormal, "No release notes information available" );	
	   ypos+=20;
	   drawText(0, ypos, fontNormal, "on this moment!" );		  
    }
}

void drawGameboard(int x, int y)
{ 
   int max;
   int select;   
   char tmp[MAX_LEN];
	
   // Init text layer	  
   GRRLIB_initTexture();

   if (maxQuestions<0) max=0; else max=maxQuestions;
   if (selectedQuestion<max) select=selectedQuestion+1; else select=max;
   
   GRRLIB_DrawImg(0,yOffset,MAX_HORZ_PIXELS,60, images.banner, 0, 1, 1, 255 );
   
   sprintf(tmp,"%s v%s",PROGRAM_NAME,PROGRAM_VERSION);
   drawText(240, 25+yOffset, fontHead, tmp);
   	  
   sprintf(tmp,"%s %02d/%02d",translation.labelQuestion, select, max);
   drawText(115-((strlen(tmp)*14)/2), 25+yOffset, fontHead, tmp);

   sprintf(tmp,"%s %02d", translation.labelScore, score);
   drawText(445+(115-((strlen(tmp)*14)/2)), 25+yOffset, fontHead, tmp);
      
   switch (stateMachine)
   { 
       case stateWelcome:
	     		drawWelcomeScreen();  
	      	    break;
	   
       case stateQuestion:	   
	  			drawQuestionScreen();
                break;

       case stateAnswer:
	     		drawAnswerScreen();
	     	    break;
	   
       case stateResult:
       			drawResultScreen();
	     	    break;	
   	   
	   case stateHighScore:  
	     	    drawHighScoreScreen();
				break;
				
	   case stateSound:
				drawSoundScreen();
				break;
	   
	   case stateCredits:  
	   		    drawCreditsScreen();		   
				break;
				
	   case stateGoodbye:
				drawGoodbyeScreen();
				break;
				
	   case stateHelp:
				drawHelpScreen();
				break;
				
	   case stateReleaseNotes:
				drawReleaseNotes();
				break;
	}  
		
	// draw buttons
	drawButtons(x, y); 

    // Draw text layer on top of panels and buttons
    GRRLIB_DrawImg(0, 0, 640, 480, GRRLIB_GetTexture(), 0, 1.0, 1.0, 255);
}

void drawJpegImage(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+yjpegOffset)*320;
    for (row = 0; row < jpeg.height; row++)
    {
	    for (col = 0; col < (jpeg.width >> 1); col++)
		{
	       frameBuffer[0][offset + col + x] = jpegout[pix++];
		}
	    offset+=320;
    }

    free(jpeg.outbuffer);
}

void drawIntroScreen1(int channel)
{
   boolean flag = true;
   
   drawJpegImage(pic9data, pic9length, 0, 0 );
		   	
   // Handle buttons events
   while ( flag )
   {
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 	
		VIDEO_SetNextFramebuffer(frameBuffer[0]); 
		VIDEO_Flush();
		VIDEO_WaitVSync();
   }
}

void drawIntroScreen2(int channel)
{
   boolean flag = true;
   
   drawJpegImage(pic10data, pic10length, 0, 0 );
		   	
   // Handle buttons events
   while ( flag )
   {
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 	
		VIDEO_SetNextFramebuffer(frameBuffer[0]); 
		VIDEO_Flush();
		VIDEO_WaitVSync();
   }
}

void drawIntroScreen3(int channel)
{
   boolean flag = true;
   
   drawJpegImage(pic11data, pic11length, 0, 0 );
		   	
   // Handle buttons events
   while ( flag )
   {
		WPAD_ScanPads(); 
		if (WPAD_ButtonsDown(channel) & BUTTON_A) flag=false; 	
		VIDEO_SetNextFramebuffer(frameBuffer[0]); 
		VIDEO_Flush();
		VIDEO_WaitVSync();
   }
}

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

int main()
{
    int x=0, y=0;
		
    VIDEO_Init();
	
    WPAD_Init();
    WPAD_SetIdleTimeout(60); // Wiimote is shutdown after 60 seconds of innactivity.
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);	// enable accelerometers and IR
 
     // Init Sound engine			
	SND_Init(INIT_RATE_48000); 
	MODPlay_Init(&snd1);
    SND_Pause(0);

    // Obtain the preferred video mode from the system
	// This will correspond to the settings in the Wii menu
	rmode = VIDEO_GetPreferredMode(NULL);
	
	// allocate framebuffer (Needed for JPG welcome images)
	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
	    yOffset = 25;  
		yjpegOffset = 25;
	}
	else
	{      
	    // TV mode PAL 60Hz
	    yOffset = 25;
		yjpegOffset = 0;
	}

	// 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();

    // Init Fat
    fatInitDefault();

  	// Init game variables    
	initGame();
	
    // Init music track
    initMusicTrack();
			
	// Init Freetype font library
	GRRLIB_InitFreetype();

    // Init threads	
	initThreads();
		
    // Show Intro screens
    drawIntroScreen1(0);	
	drawIntroScreen2(0);
	drawIntroScreen3(0);
	
	// Load xml content files    
	initLanguages( FILENAME_LANGUAGES );
	initTranslation( languages[selectedLanguage].translation );
	initTopics( languages[selectedLanguage].topics );
	initQuestions( topics[selectedTopic].filename);
	initImages();
	
	// Load highscore xml file (if available)
	initHighScore(HIGHSCORE_FILENAME);

    // Init GRRLib graphics library
    GRRLIB_InitVideo();
    GRRLIB_Start();
    
	// Make screen black
	GRRLIB_FillScreen(0xFFFFFF);
    GRRLIB_Render();
			
	// Repeat forever
    while(1)
	{
	    // icon angle 
	    if (++angle>=MAX_ANGLE) angle=0;
		
		// icon alfa 
		if (alfa_direction)
		{
		   ++alfa;
		   if (++alfa>=MAX_ALFA) alfa_direction=false;
		}
		else
		{
		   --alfa;
		   if (--alfa<=0) alfa_direction=true;
		}
		
	    // Init (Update) state Machine
	    initStateMachine();
		
	    // Draw game board and other items
        drawGameboard(x+40, y+40);
	
	    // Scan for button events
		WPAD_SetVRes(0, MAX_HORZ_PIXELS, 480);
        WPAD_ScanPads();
        u32 wpaddown = WPAD_ButtonsDown(0);

        // Scan for ir events
        ir_t ir1; 
		WPAD_IR(WPAD_CHAN_0, &ir1); 
		x=ir1.sx-WSP_POINTER_X;
		y=ir1.sy-WSP_POINTER_Y;
					
		// handle button events
        if (wpaddown & BUTTON_A) buttonA(x+40,y+40);		
		if (wpaddown & BUTTON_MINUS ) buttonMinus();
		if (wpaddown & BUTTON_1 ) button1x();				
		if (wpaddown & BUTTON_2 ) button2y();		
		if (wpaddown & BUTTON_HOME) buttonHome();
		
     	// Draw wiiremote ir pointer
		GRRLIB_DrawImg( x, y, 96, 96, images.pointer, ir1.angle, 1, 1, 255 );
		GRRLIB_Render();
	}
    return 0;
}

// -----------------------------------------------------------
// THE END
// -----------------------------------------------------------
