#include <pspkernel.h>
#include <pspgu.h>
#include <pspgum.h>
#include <pspctrl.h>
#include <psprtc.h>
#include <psppower.h>

#ifdef MIKMOD_PLAYER
#include <mikmod.h>
#endif

#include "GUblit.h"
#include "game.h"
#include "subway.h"

PSP_MODULE_INFO("Last Call", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_VFPU);
//PSP_MODULE_INFO("Last Call", 0x1000, 1, 1);
//PSP_MAIN_THREAD_ATTR(0);

Image *spritesheet;

/* The screen surface */
#ifdef MIKMOD_PLAYER
SAMPLE *sfx[MAX_SFX];
SAMPLE *wav;
UNIMOD *song[MAX_MUSIC];
#endif

char *sfxfilename[]={	"data/locked.wav","data/opening.wav","data/drink.wav",
	"data/special.wav","data/gameover.wav","data/donelevel.wav",
	"data/readygo.wav" };
char *musicfilename[]={ "data/intro.mod", "data/even.xm", "data/odd.xm",
	"data/menu.xm" };

u64 songStart=0;

void playSfx(enum Sfx id)
{
#ifdef MIKMOD_PLAYER
	if(id>=0 && id<MAX_SFX && sfx[id]!=0) {
		int voice = MikMod_PlaySample(sfx[id],0,0);
		printf("playing %s on voice %d\n",sfxfilename[id],voice);
	} else {
		printf("Couldn't play %d sample.  Couldn't find it.\n",id);
	}
    if(id==S_LEVELSTART) {
		Player_Stop();
		MikMod_FreeSong(song[MUS_INTRO]);
		
		song[MUS_INTRO]=MikMod_LoadSong(musicfilename[MUS_INTRO],128);
		Player_Start(song[MUS_INTRO]);
		sceRtcGetCurrentTick(&songStart);
	}
#endif
}

static int exitRequest = 0;

int running()
{
	return !exitRequest;
}

int exitCallback(int arg1, int arg2, void *common)
{
	exitRequest = 1;
	return 0;
}

int callbackThread(SceSize args, void *argp)
{
	int cbid;

	cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL);
	sceKernelRegisterExitCallback(cbid);

	sceKernelSleepThreadCB();

	return 0;
}

int setupCallbacks(void)
{
	int thid = 0;

	thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0);
	if(thid >= 0)
	{
		sceKernelStartThread(thid, 0, 0);
	}

	return thid;
}

#ifdef MIKMOD_PLAYER
void mikmodErrorHandler(void)
{
        printf("_mm_critical %d\n", _mm_critical);
        printf("_mm_errno %d\n", _mm_errno);
        printf("%s\n", _mm_errmsg[_mm_errno]);
        return;
}
#endif

void playSound(int id)
{
        //if(game.muteSfx) return;
#ifdef MIKMOD_PLAYER
        if(id>=0 && id<MAX_SFX && sfx[id]!=0) {
                int voice = MikMod_PlaySample(sfx[id],0,0);
                printf("playing %s on voice %d\n",sfxfilename[id],voice);
        }
#endif
        return;
}

//#define Color unsigned long
/* tga header */
typedef struct
{
  unsigned char id_length;          /* size of image id */
  unsigned char colormap_type;      /* 1 is has a colormap */
  unsigned char image_type;         /* compression type */

  short	cm_first_entry;       /* colormap origin */
  short	cm_length;            /* colormap length */
  unsigned char cm_size;            /* colormap size */

  short	x_origin;             /* bottom left x coord origin */
  short	y_origin;             /* bottom left y coord origin */

  short	width;                /* picture width (in pixels) */
  short	height;               /* picture height (in pixels) */

  unsigned char pixel_depth;        /* bits per pixel: 8, 16, 24 or 32 */
  unsigned char image_descriptor;   /* 24 bits = 0x00; 32 bits = 0x80 */

} tga_header_t;

void saveImage(const char* filename, Color* data, int width, int height, int lineSize, int saveAlpha)
{
	FILE* fp;
	int x, y;
	tga_header_t head;
	
	if ((fp = fopen(filename, "wb")) == NULL) return;

	// Put the header.
	head.id_length=0;
	fwrite(&head.id_length,1,1,fp);
	head.colormap_type=0;
	fwrite(&head.colormap_type,1,1,fp);
	head.image_type=2;
	fwrite(&head.image_type,1,1,fp);
	head.cm_first_entry=0;
	fwrite(&head.cm_first_entry,2,1,fp);
	head.cm_length=0;
	fwrite(&head.cm_length,2,1,fp);
	head.cm_size=0;
	fwrite(&head.cm_size,1,1,fp);
	head.x_origin=0;
	fwrite(&head.x_origin,2,1,fp);
	head.y_origin=0;
	fwrite(&head.y_origin,2,1,fp);
	head.width=width;
	fwrite(&head.width,2,1,fp);
	head.height=height;
	fwrite(&head.height,2,1,fp);
	head.pixel_depth=24;
	fwrite(&head.pixel_depth,1,1,fp);
	head.image_descriptor=0x00;
	fwrite(&head.image_descriptor,1,1,fp);
	
	for(y=height-1;y>=0;y--) {
		for(x=0;x<width;x++) {
			fwrite((char *)(data+y*lineSize+x)+2,1,1,fp);
			fwrite((char *)(data+y*lineSize+x)+1,1,1,fp);
			fwrite((char *)(data+y*lineSize+x)+0,1,1,fp);
		}
	}
	
	fclose(fp);
}

struct FastFont {
	Image *texture;
	int height;
	struct Glyph {
		int active;
		int x,y,w,h;
		int kern_left,kern_right,kern_bottom;
	} glyph[256];
} fastFont[6];

int loadFastFont(struct FastFont *font,const char *filename)
{
	font->height=1;
	printf("Loading font '%s'\n",filename);
	if(font->texture) return 1;	// already loaded.
	FILE *file=fopen(filename,"r");
	if(!file) {
		font->texture=0;
		return 0;
	}
	font->texture=0;
	char line[256];
	line[255]=0;
	while( fgets(line,255,file) ) {
		if(strncmp(line,"Char=",5)==0) {
			int ch=0;
			int x=0,y=0,w=0,h=0,kern_left=0,kern_right=0,kern_bottom=0;
			// Char="z"; or Char=0020;
			char c=0;
			int res=sscanf(line,"Char=\"%c\"; %d,%d,%d,%d; %d,%d,%d;",&c,&x,&y,&w,&h,&kern_left,&kern_right,&kern_bottom);
			ch=c;
			if(res<5) {
				res=sscanf(line,"Char=%x; %d,%d,%d,%d; %d,%d,%d;",&ch,&x,&y,&w,&h,&kern_left,&kern_right,&kern_bottom);
			}
			if(res>=5) {
				font->glyph[(unsigned int)ch].active=1;
				font->glyph[(unsigned int)ch].x=x;
				font->glyph[(unsigned int)ch].y=y;
				font->glyph[(unsigned int)ch].w=w;
				font->glyph[(unsigned int)ch].h=h;
				font->glyph[(unsigned int)ch].kern_left=kern_left;
				font->glyph[(unsigned int)ch].kern_right=kern_right;
				font->glyph[(unsigned int)ch].kern_bottom=kern_bottom;
			}
		} else if(strncmp(line,"Height=",7)==0) {
			font->height=1;
			sscanf(line,"Height=%d",&font->height);
		} else if(strncmp(line,"Bitmap=",7)==0) {
			char imagePath[256];
			if(strstr(line,"\n")) strstr(line,"\n")[0]=0;
			if(strstr(line,"\r")) strstr(line,"\r")[0]=0;
			strcpy(imagePath,line+7);
			font->texture=loadPng(imagePath);
			if(!font->texture) {
				strcpy(imagePath,"data/");
				strcat(imagePath,line+7);
				font->texture=loadPng(imagePath);
			}
			if(font->texture) printf("Loaded %s\n",imagePath);
			else printf("Could not find '%s'\n",imagePath);
		}
	}
	if(!font->texture) return 0;
	printf("Success for font '%s'\n",filename);
	return 1;
}

void extentMessage(int *w,int *h, enum FontId fontId, const char *message)
{
	struct FastFont *font=&fastFont[fontId];
	unsigned int i;
	if(!font->texture) return;
	*w=0;
	for(i=0;i<strlen(message);i++) {
		int ch=(unsigned char)message[i];
		if(font->glyph[ch].active) {
			*w+=font->glyph[ch].w+font->glyph[ch].kern_right+1;
		} else {
			printf("Missing font char: '%c'\n",(char)ch);
			*w+=font->height;
		}
	}
	*h=fastFont[fontId].height;
}

void drawMessage(int x,int y, enum FontId fontId, const char *message)
{
#if 0
	sceGuFinish();
	sceGuSync(0,0);
	printAt(x+1,y+1,message,GU_RGBA(0,0,0,0xff));
	printAt(x,y,message,0xffffffff);
	guStart();
#else
	struct FastFont *font=&fastFont[fontId];
	unsigned int i;
	if(!font->texture) return;
	//printf("Message '%s'\n",message);
	for(i=0;i<strlen(message);i++) {
		int ch=(unsigned char)message[i];
		if(font->glyph[ch].active) {
			drawSprite(font->glyph[ch].x,
				font->glyph[ch].y,font->glyph[ch].w,
				font->glyph[ch].h,font->texture,
				x+font->glyph[ch].kern_left,
				y+font->glyph[ch].kern_bottom);
			x+=font->glyph[ch].w+font->glyph[ch].kern_right+1;
		} else {
			printf("Missing font char: '%c'\n",(char)ch);
			x+=font->height;
		}
	}
#endif
	//printf("Done '%s'\n",message);
}


void drawTile(int x, int y, struct Tile *tile, int frame){
	x-=game.viewLeft;
	y-=game.viewTop;
	if(!tile) {
		printf("missing tile at %d,%d\n",x,y);
		return;
	}
if(x+tile->w<0 || y+tile->h<0 || x>SCREEN_WIDTH || y>SCREEN_HEIGHT) return;
    if(!spritesheet)
		spritesheet=loadPng("data/gfx.png");
    int xs=tile->x+frame*(tile->w+2);
	int ys=tile->y;
	int w=tile->w;
	int h=tile->h;
    drawSprite(xs, ys, w, h, spritesheet, x, y);
}


struct ImageCache {
	char fname[256];
	Image *image;
} cell[32];

int cellNext=0;

void drawCell(int x,int y,const char *fname)
{
	Image *image=0;
	int i;
	
	for(i=0;i<cellNext;i++) {
		if(strcmp(cell[i].fname,fname)==0) {
			image=cell[i].image;
		}
	}
	
	if(!image) {
		image=loadPng(fname);
		if(!image) {
			char buf[256];
			strcpy(buf,"data/intro/");
			strcat(buf,fname);
			image=loadPng(buf);
		}
		if(image) {
			strcpy(cell[cellNext].fname,fname);
			cell[cellNext++].image=image;
		}
	}
	if(!image) printf("Could not load cell '%s'\n",fname);
	if(!image) return;
	if(x+image->imageWidth<0 || y+image->imageHeight<0 || x>SCREEN_WIDTH || y>SCREEN_HEIGHT) return;
	
	drawSprite(0,0,image->imageWidth,image->imageHeight,image,x,y);
}

void freeCells()
{
	int i;
	for(i=0;i<cellNext;i++) {
		freeImage(cell[i].image);
		cell[i].image=0;
		cell[i].fname[0]=0;
	}
	cellNext=0;
}

#ifdef MIKMOD_PLAYER
SAMPLE *wav=0;
#endif

void playWav(const char *fname)
{
#ifdef MIKMOD_PLAYER
	if(wav) {
		WAV_Free(wav);
		wav=0;
	}
    FILE *file=fopen(fname,"rb");
    if(file) {
        //printf("opening file %s\n",sfxfilename[i]);
        fclose(file);
		wav=WAV_LoadFN((char *)fname);
    }
	if(!wav) {
		char buf[256];
		strcpy(buf,"data/intro/");
		strcat(buf,fname);
	    FILE *file=fopen(buf,"rb");
	    if(file) {
	        //printf("opening file %s\n",sfxfilename[i]);
	        fclose(file);
			wav=WAV_LoadFN(buf);
	    }
	}
	if(!wav) return;
	int voice = MikMod_PlaySample(wav,0,0);
	printf("playing %s on voice %d\n",fname,voice);
#endif
}

void freeWavs()
{
	if(wav)	WAV_Free(wav);
	wav=0;
}

void drawSubwayLoading()
{
	guStart();
	drawCell(0,0,"data/intro/subwayloading.png");
	drawToScreen();
	freeCells();
}

/* This function draws to the screen; replace this with your own code! */
void draw ()
{
	struct Character *next;
	int x,y;

    guStart();

//	printf("Drawing...\n");   
  /* Create a black background */

	switch(drawMode) {
	case DM_NORMAL:
		clearScreen(0x000000);
		for(y=0;y<game.mapHeight;y++) {
			for(x=0;x<game.mapWidth;x++) {
				drawMap(x*TILE_WIDTH,y*TILE_HEIGHT,&game.map[y*game.mapWidth+x]);
			}
		}
		for(next=game.firstCharacter;next!=NULL;next=next->next) {
			drawCharacter(next);
		}
		
		// Finally draw the hud.
		drawHud();
		break;
	case DM_INTRO:
		drawIntro();
		break;
	case DM_SUBWAY:
		drawItems();
		FPS();		
		break;
	}
    /* Display frames per second*/
//    FPS();		

    drawToScreen();
//	printf("Draw done.\n");
}

int main (int argc, char *argv[])
{
    int done;   
    int i;
	SceCtrlData pad;
    SceCtrlData oldpad;
    oldpad.Buttons=0;
    oldpad.Lx=-1;
    oldpad.Ly=-1;

	// Register callbacks.
	setupCallbacks();

    /* Initialize GU */
    initGU();
    sceCtrlSetSamplingCycle(0);
    sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);

    Image *compo=loadPng("data/compo.png");
    if(compo) {
		int i;
		for(i=254;i>=0;i-=2) {
			guStart();
			drawSprite(0,0,480,272,compo,0,0);
			drawFilledRect(0,0,480,272,i<<24);
			drawToScreen();
			if(!running()) return 0;
		}
		for(i=0;i<256;i+=2) {
			guStart();
			drawSprite(0,0,480,272,compo,0,0);
			drawFilledRect(0,0,480,272,i<<24);
			drawToScreen();
			if(!running()) return 0;
		}
	
	freeImage(compo);
	compo=0;
    }
    
     Image *title=loadPng("data/title.png");
    
	if(title) {
//		fadeImage(IN, 2, 1,title);
		int i;
		for(i=254;i>=0;i-=2) {
			guStart();
			drawSprite(0,0,480,272,title,0,0);
			drawFilledRect(0,0,480,272,i<<24);
			drawToScreen();
			if(!running()) return 0;
		}
	}
#define TEST_SUBWAY 1
#ifdef TEST_SUBWAY
	done=0;
	loadItems();
	if(getItemCount()>0) {
		guStart();
		initItems();
		drawToScreen();

		u64 oldTick,newTick;
		sceRtcGetCurrentTick(&newTick);
		while(!done) {
			oldTick=newTick;
			sceRtcGetCurrentTick(&newTick);
			guStart();
			drawItems();
			FPS();		
			drawToScreen();
			done=updateItems((newTick-oldTick)/1000);
			if(!running()) return 0;
		}
		guStart();
		sceGuEnable(GU_BLEND);
		clearScreen(0xff006000);
		drawToScreen();
		guStart();
		clearScreen(0xff006000);
		drawSprite(0,0,480,272,title,0,0);
		drawToScreen();
	}
	freeItems();
#endif


#if 0
     Image *compo=loadPng("data/compo.png");
     if(compo) {
//		fadeImage(IN_OUT, 2, 1,compo);
		// Highly coveted fade to black goes here(i know how to do it).
		int i;
		for(i=254;i>=0;i-=2) {
			guStart();
			drawSprite(0,0,480,272,compo,0,0);
			drawFilledRect(0,0,480,272,i<<24);
			drawToScreen();
		}
		for(i=1;i<256;i+=2) {
			guStart();
			drawSprite(0,0,480,272,compo,0,0);
			drawFilledRect(0,0,480,272,i<<24);
			drawToScreen();
		}
		freeImage(compo);
		compo=0;
		}
#endif

	u64 oldTick;
	u64 newTick;
	sceRtcGetCurrentTick(&newTick);
     
//	printf("Displayed the title (%dx%d; %dx%d)\n",title->imageWidth,title->imageHeight,title->textureWidth,title->textureHeight);

	loadFastFont(&fastFont[FONT_HEADLINE],"data/Headline32bluered.fnt");
	loadFastFont(&fastFont[FONT_BODY],"data/Body20blue.fnt");
	loadFastFont(&fastFont[FONT_BODYHIGHLIGHT],"data/Body20brown.fnt");
	loadFastFont(&fastFont[FONT_MESSAGE],"data/Body14blue.fnt");
	loadFastFont(&fastFont[FONT_SMALL],"data/Small10red.fnt");
	loadFastFont(&fastFont[FONT_SMALLHIGHLIGHT],"data/Small10black.fnt");

#ifdef MIKMOD_PLAYER
    _mm_RegisterErrorHandler(mikmodErrorHandler);
    MikMod_RegisterAllLoaders();
    MikMod_RegisterAllDrivers();
    md_mode = DMODE_16BITS|DMODE_STEREO|DMODE_SOFT_SNDFX|DMODE_SOFT_MUSIC;
    md_reverb = 0;
    md_pansep = 128;
    MikMod_Init();
    MikMod_SetNumVoices(-1, 8);

    song[MUS_INTRO]=MikMod_LoadSong(musicfilename[MUS_INTRO],128);
	sceRtcGetCurrentTick(&songStart);
    Player_Start(song[MUS_INTRO]);
	//song[MUS_EVEN]=MikMod_LoadSong(musicfilename[MUS_EVEN],128);
	//song[MUS_ODD]=MikMod_LoadSong(musicfilename[MUS_ODD],128);
	//song[MUS_MENU]=MikMod_LoadSong(filename[MUS_MENU],128);

    //int i;
    for(i=0;i<MAX_SFX;i++) {
        printf("reading sound file %d...\n",i);
        FILE *file=fopen(sfxfilename[i],"rb");
        if(file) {
            //printf("opening file %s\n",sfxfilename[i]);
            fclose(file);
            sfx[i]=WAV_LoadFN(sfxfilename[i]);
        }
        if(!sfx[i]) printf("Warning: missing sound file '%s'\n",sfxfilename[i]);
    }
#endif
	
	//	printf("Couldn't load the title screen.\n");
	
	
	// Load in the intro song
	/*if(Mix_OpenAudio(44100,AUDIO_S16SYS, 2, 2048)<0) {
		// no sound.  oh well.
		printf("Couldn't start sound.\n");
	}
	music[MUS_INTRO]=Mix_LoadMUS(musicfilename[MUS_INTRO]);
	if(music) Mix_PlayMusic(music[MUS_INTRO],1);
	for(i=1;i<MAX_MUSIC;i++) {
		music[i]=Mix_LoadMUS(musicfilename[MUS_INTRO]);
		if(music[i]==NULL) printf("Could not read '%s'\n",musicfilename[i]);
	}
	for(i=0;i<MAX_SFX;i++) {
		sfx[i]=Mix_LoadWAV(sfxfilename[i]);
		if(sfx[i]==NULL) printf("Could not read '%s'\n",sfxfilename[i]);
	}
	
	TTF_Init();
	font[FONT_SMALL]=TTF_OpenFont("data/arial.ttf",10);
	font[FONT_HEADLINE]=TTF_OpenFont("data/arial.ttf",32);
	font[FONT_BODY]=TTF_OpenFont("data/arial.ttf",15);*/

	spritesheet=loadPng("data/gfx.png");
	//swizzle_fast(&spritesheet);

	// Now we're actually ready to play, but maybe we could show a cool intro
	initGame();
	if(title) {
		
		sceRtcGetCurrentTick(&newTick);
		initTitle();
		done=0;
		do {
			guStart();
			drawSprite(0,0,480,272,title,0,0);

			oldTick=newTick;	
			sceRtcGetCurrentTick(&newTick);
			done=updateDrawTitle((newTick-oldTick)/1000);
			
			drawToScreen();
			sceCtrlReadBufferPositive(&pad,1);
			if(pad.Buttons & (PSP_CTRL_CROSS | PSP_CTRL_START | PSP_CTRL_CIRCLE)) done=1;
			if(!running()) return 0;
		} while(!done);

		while(pad.Buttons & (PSP_CTRL_CROSS | PSP_CTRL_START | PSP_CTRL_CIRCLE)) {
			sceCtrlReadBufferPositive(&pad,1);
		}
		
		for(i=1;i<256;i+=2) {
			guStart();
			drawSprite(0,0,480,272,title,0,0);
			drawFilledRect(0,0,480,272,i<<24);
			drawToScreen();
		}
		freeImage(title);
		title=0;
	}

	printf("intro\n");
	Player_SetVolume(32);
	sceRtcGetCurrentTick(&newTick);
	initIntro();
	done=0;
	do {
		guStart();

		oldTick=newTick;	
		sceRtcGetCurrentTick(&newTick);
		drawIntro();
		done=updateIntro((newTick-oldTick)/1000);
		drawToScreen();
		sceCtrlReadBufferPositive(&pad,1);
		if(pad.Buttons & (PSP_CTRL_CROSS | PSP_CTRL_START | PSP_CTRL_CIRCLE)) done=1;
		if(!running()) return 0;
	} while(!done);

	while(pad.Buttons & (PSP_CTRL_CROSS | PSP_CTRL_START | PSP_CTRL_CIRCLE)) {
		sceCtrlReadBufferPositive(&pad,1);
	}
	
	for(i=1;i<256;i+=2) {
		guStart();
		drawFilledRect(0,0,480,272,i<<24);
		drawToScreen();
	}
	Player_SetVolume(128);	// Full volume.
	
	printf("event loop\n");
    done = 0;
	sceCtrlReadBufferPositive(&pad,1);
	sceRtcGetCurrentTick(&newTick);
    while (running())
    {
		int changedButtons;
		
		oldpad.Buttons=pad.Buttons;
		oldpad.Lx=pad.Lx;
		oldpad.Ly=pad.Ly;
		sceCtrlReadBufferPositive(&pad,1);
		changedButtons=pad.Buttons^oldpad.Buttons;

#define handleJoyChange(from,to) if(changedButtons&from) done+=handleJoy(to,(pad.Buttons&from)==0?1:0)
		handleJoyChange(PSP_CTRL_UP,BT_UP);
		handleJoyChange(PSP_CTRL_DOWN,BT_DOWN);
		handleJoyChange(PSP_CTRL_LEFT,BT_LEFT);
		handleJoyChange(PSP_CTRL_RIGHT,BT_RIGHT);
		handleJoyChange(PSP_CTRL_TRIANGLE,BT_TRIANGLE);
		handleJoyChange(PSP_CTRL_SQUARE,BT_SQUARE);
		handleJoyChange(PSP_CTRL_CIRCLE,BT_CIRCLE);
		handleJoyChange(PSP_CTRL_CROSS,BT_CROSS);
		handleJoyChange(PSP_CTRL_LTRIGGER,BT_LTRIGGER);
		handleJoyChange(PSP_CTRL_RTRIGGER,BT_RTRIGGER);
		handleJoyChange(PSP_CTRL_START,BT_START);
		handleJoyChange(PSP_CTRL_SELECT,BT_SELECT);
		handleJoyChange(PSP_CTRL_HOLD,BT_HOLD);
		if(pad.Buttons & PSP_CTRL_SELECT && changedButtons & PSP_CTRL_SELECT) {
			char buf[64];
			static int cap=1;
			sprintf(buf,"lastcall%d.png",cap++);
			savePngImage(buf,(u32 *)(0x04000000),480,272,512,0);
		}

		if(pad.Lx!=oldpad.Lx) handleAnalog(0,pad.Lx);
		if(pad.Ly!=oldpad.Ly) handleAnalog(1,pad.Ly);

		/* Draw to screen */
		draw ();
	
		oldTick=newTick;	
		sceRtcGetCurrentTick(&newTick);

#ifdef MIKMOD_PLAYER
	    if(newTick-songStart>(4*60+3)*1000000) {
			Player_Stop();
			MikMod_FreeSong(song[MUS_INTRO]);
			
			song[MUS_INTRO]=MikMod_LoadSong(musicfilename[MUS_INTRO],128);
			Player_Start(song[MUS_INTRO]);
			sceRtcGetCurrentTick(&songStart);
		}
#endif

		// Now update the game state.
		int elapsed=(newTick-oldTick)/1000;
		scePowerSetClockFrequency(333, 333, 166);
		update(elapsed);
		scePowerSetClockFrequency(222, 222, 166);
		
		if(game.mode==GAME_QUIT) break;
    }
    printf("quit requested.\n");
    sceGuTerm();
    
    sceKernelExitGame();
    return 0;
}
