// First DC release of Wauters Kris - invesa@pandora.be
//
// This first release is mainly to test my development environment
// and to test the ability to develop software for the Dreamcast
//
// Started on sunday, april 15th - 2001
//
// And resurrected on saturday 25th - 2010 by Indiket (KOS)

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <kos.h>
KOS_INIT_FLAGS(INIT_DEFAULT);
#include "dbp_image.h"
#include "s3mlib.h"
#include "vmu_icon.h"

//--- via this define, it is possible to put 24-bit images on screen ---
#define RGB565(r, g, b) ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0);

typedef struct {
	unsigned short    *rect_data;
} Img;



//--- global variables ---
char *direction;
int button_a_or_b;          //---global variable to check if a or b is pressed
int button_a;               //---this will be "1" if button A is pressed
int button_b;               //---this will be "1" if button B is pressed
int selection;              //---variable for position location within menu
int buttonpressed;          //---variable to keep track if a button is pressed
int statbuf;                   //---status, used to keep track of return values

//--- vmu stuff ---
//--- VMU save not yet implemented, so var's are allways "1" at startup
int vmu_difficulty;         
int vmu_music;
int vmu_pictures;


//--- stuff related to create random numbers ---

int randnum(int limit) { return (rand() & 0x7fffffff) % limit; }

//---------------------------------------------------------------------
// copy rectangle area from screen
//---------------------------------------------------------------------
Img *copy_rectangle(int xpos,int ypos,int rect_pixels)
{
	short x,y;
	Img *rv;
	int count=0;

	rv = (Img *)malloc(sizeof(Img));
	rv->rect_data = (unsigned short *)malloc(rect_pixels*rect_pixels*2);
	for (y = ypos+1;y < (ypos+rect_pixels+1);y++)
		{
		for (x = xpos+1;x < (xpos+rect_pixels+1);x++)
			{
			rv->rect_data[count]=vram_s[x + (640*y)];
			count++;
			}
		}
	return rv;
}

//---------------------------------------------------------------------
// place rectangle area on screen
//---------------------------------------------------------------------
void put_rectangle(Img *rect,int xpos,int ypos,int rect_pixels)
{
	short x,y;
	int count;
	count = 0;

	for (y = ypos+1;y < (ypos+rect_pixels+1);y++)
		{
		for (x = xpos+1;x < (xpos+rect_pixels+1);x++)
			{
			vram_s[x + (640*y)] = rect->rect_data[count];
			count++;
			//vram_s[x + (640*y)] = RGB565(255,0,0);

			}
		}
}

//---------------------------------------------------------------------
// this will clear the menu and other regions on screen
// used to prevent "garbage" on screen
//---------------------------------------------------------------------
void clear_rectangle()
{
	int x,y,width,height,xmax,ymax,ytmp;

	x=199;
	y=119;
	width=420;
	height=318;

	//--- defines bottomright coördinates of rectangle ---
	xmax = x+width;
	ymax = y+height;
	ytmp = y;

	while (x!=xmax)
		{
		x++;
		y=ytmp;
		while (y!=ymax)
			{
			y++;
			vram_s[x + (640*y)] = RGB565(0,0,0);
			}
		}
	return;
}

//---------------------------------------------------------------------
// This function will display "shuffle" on the LCD of an inserted VMU
// the icon is in XPM format
//---------------------------------------------------------------------
void shuffle_icon()
{
	maple_device_t *mvmu;
	uint8 bitmap[48*32/8] = {0};
	int x, y, xi, xb;

	mvmu = maple_enum_type(0, MAPLE_FUNC_LCD);

	if(mvmu)
		{
		if (vmu_icon_xpm) 
			{
			for (y=0; y<32; y++)
				{
				for (x=0; x<48; x++) 
					{
					xi = x / 8;
					xb = 0x80 >> (x % 8);
					if (vmu_icon_xpm[(31-y)*48+(47-x)] == '.')
						bitmap[y*(48/8)+xi] |= xb;
					}
				}
			}
		vmu_draw_lcd(mvmu, bitmap);
		}
}

//---------------------------------------------------------------------
// function to retrieve data from controller (buttons)
//---------------------------------------------------------------------
int controller_button()
{
	maple_device_t *mcont;
	cont_state_t *cond;
	direction="";
	
	mcont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);

	//---no controller attached ---
	if (!mcont)
		{
		buttonpressed=0;
		return 1;
		}
	
	cond = (cont_state_t *)maple_dev_status(mcont);
	//--- error getting status ---
	if (!cond)
		{
		buttonpressed=0;
		return 1;
		}

	//--- start button pressed ---
	if (cond->buttons & CONT_START)
		{
		buttonpressed=CONT_START;
		direction="START";
		return 1;
		}

	//--- up button pressed ---
	if (cond->buttons & CONT_DPAD_UP) 
		{
		direction="UP";
		selection--;
		return 1;
		}

	//--- left button pressed ---
	if (cond->buttons & CONT_DPAD_LEFT)
		{
		direction="LEFT";
		selection--;
		return 1;
		}

	//--- down button pressed ---
	if (cond->buttons & CONT_DPAD_DOWN)
		{
		selection++;
		direction="DOWN";
		return 1;
		}

	//--- right button pressed ---
	if (cond->buttons & CONT_DPAD_RIGHT)
		{
		direction="RIGHT";
		selection++;
		return 1;
		}

	//--- A button pressed ---
	if (cond->buttons & CONT_A)
		{
		direction="A";
		button_a=1;
		button_a_or_b=1;
		return 1;
		}
	//--- B button pressed ---
	if (cond->buttons & CONT_B)
		{
		direction="B";
		button_b=1;
		button_a_or_b=1;
		return 1;
		}

	return 0;
}

//---------------------------------------------------------------------
// another version of selections within a menu
// this variety is used for the 3 horizontal "blocks"
//---------------------------------------------------------------------
int menu_selection_2(char *title,char *fn1_on,char *fn1_off,char *fn2_on,char *fn2_off,char *fn3_on,char *fn3_off)
{
	button_a_or_b = 0;
	button_a=0;
	button_b=0;	
	int noload=0;

	statbuf = dbp_load(title,55,160);

	clear_rectangle();
	statbuf=dbp_load("IFACE/AB_BUT.DBP",200,390);

	while (button_a_or_b==0)
	{
		if (selection==1 && noload==0)
			{
			statbuf = dbp_load(fn2_off,350,230);
			statbuf = dbp_load(fn3_off,440,230);
			statbuf = dbp_load(fn1_on,260,230);
			}
		if (selection==2 && noload==0)
			{            
			statbuf = dbp_load(fn1_off,260,230);
			statbuf = dbp_load(fn3_off,440,230);
			statbuf = dbp_load(fn2_on,350,230);
			}
		if (selection==3 && noload==0)
			{
			statbuf = dbp_load(fn1_off,260,230);
			statbuf = dbp_load(fn2_off,350,230);
			statbuf = dbp_load(fn3_on,440,230);
			}

		//KOS - Dreamcast is too fast ;)
		thd_sleep(200);
		
		//--- wachten op toetsindruk ---
		while (!controller_button())
			{
			thd_sleep(10);
			}
		//2010: Optimize selection: no move = no reload
		if (selection<1)
			{
			noload=1;
			selection=1;
			}
		else if (selection>3)
			{
			noload=1;
			selection=3;
			}
		else noload=0;
	}        
	if (button_b==1)
	{
		selection=-1;
	}

	clear_rectangle();
	return selection;
}

//---------------------------------------------------------------------
// primary version of selections within a menu
// this version is used for the 3 vertical menu-items
//---------------------------------------------------------------------
int menu_selection(char *title,char *fn1_on,char *fn1_off,char *fn2_on,char *fn2_off,char *fn3_on,char *fn3_off)
{
	int x,y;

	button_a_or_b = 0;
	button_a=0;
	button_b=0;
	int noload=0;

	if (title!="")
		{
		statbuf = dbp_load(title,55,160);
		}
	if (title=="")
		{
		x=54;
		y=159;
		while (x!=165)
			{
			x++;
			while (y!=205)
				{
				y++;
				vram_s[x + (640*y)] = RGB565(0,0,0);
				}
			}
		}

	while (button_a_or_b==0)
	{
		if (selection==1 && noload==0)
			{
			statbuf = dbp_load(fn2_off,300,240);
			statbuf = dbp_load(fn3_off,300,290);
			statbuf = dbp_load(fn1_on,300,190);
			}
		if (selection==2 && noload==0)
			{
			statbuf = dbp_load(fn1_off,300,190);
			statbuf = dbp_load(fn3_off,300,290);
			statbuf = dbp_load(fn2_on,300,240);
			}
		if (selection==3 && noload==0)
			{
			statbuf = dbp_load(fn1_off,300,190);
			statbuf = dbp_load(fn2_off,300,240);
			statbuf = dbp_load(fn3_on,300,290);
			}

		//KOS - Dreamcast is too fast ;)
		thd_sleep(200);
		
		//--- wait for keypress on controller ---
		while (!controller_button())
			{
			thd_sleep(10);
			}
		//2010: Optimize selection: no move = no reload
		if (selection<1)
			{
			noload=1;
			selection=1;
			}
		else if (selection>3)
			{
			noload=1;
			selection=3;
			}
		else noload=0;
	}        
	if (button_b==1)
	{
		selection=-1;
	}

	return selection;
}

//---------------------------------------------------------------------
// function that waits until START or A button is pressed
//---------------------------------------------------------------------
int wait_startbutton()
{
	maple_device_t *mcont;
	cont_state_t *cond;
	
	mcont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
	
	//---no controller attached ---
	if (!mcont)
		{
		return 1;
		}
	cond = (cont_state_t *)maple_dev_status(mcont);
	//--- error getting status ---
	if (!cond)
		{
		return 1;
		}
	//--- start button pressed ---
	if (cond->buttons & CONT_START)
		{
		return 1;
		}
	//--- A button pressed ---
	if (cond->buttons & CONT_A)
		{
		return 1;
		}

	return 0;
}

//---------------------------------------------------------------------
// show credits
//---------------------------------------------------------------------
void credits()
{
	statbuf = dbp_load("IFACE/T_CRED.DBP",55,160);
	statbuf = dbp_load("IFACE/CREDITS.DBP",260,160);
	
	//KOS - Dreamcast is too fast ;)
	thd_sleep(200);
	
	while (!wait_startbutton())
		{
		thd_sleep(10);
		}
	clear_rectangle();
	return;
}

//---------------------------------------------------------------------
// main-part to select the difficulty level
//---------------------------------------------------------------------
void options_difficulty()
{
	selection = vmu_difficulty;
	statbuf = menu_selection_2("IFACE/T_DIFF.DBP","IFACE/EASY_ON.DBP","IFACE/EASY_OFF.DBP","IFACE/MEDI_ON.DBP","IFACE/MEDI_OFF.DBP","IFACE/HARD_ON.DBP","IFACE/HARD_OFF.DBP");
	clear_rectangle();

	if (statbuf!=-1)
		{
		vmu_difficulty = selection;
		}
	//--- initialise data and prepare for return ---
	selection=1;
	statbuf=0;
	button_a=0;
	button_b=0;
	button_a_or_b=0;
	return;
}

//---------------------------------------------------------------------
// main part for selecting a music categorie
//---------------------------------------------------------------------
void options_music()
{
	selection = vmu_music;
	statbuf = menu_selection_2("IFACE/T_MUSI.DBP","IFACE/SOFT_ON.DBP","IFACE/SOFT_OFF.DBP","IFACE/MEDI_ON.DBP","IFACE/MEDI_OFF.DBP","IFACE/FAST_ON.DBP","IFACE/FAST_OFF.DBP");
	clear_rectangle();

	if (statbuf!=-1)
		{
		vmu_music = selection;
		}
	//--- initialise data and prepare for return ---
	selection=2;
	statbuf=0;
	button_a=0;
	button_b=0;
	button_a_or_b=0;
	return;
}

//---------------------------------------------------------------------
//make picture selection 
//---------------------------------------------------------------------
int picture_menu()
{
	int old_selection, new_selection;

	new_selection = selection;
	old_selection = 0;
	button_a_or_b = 0;
	button_a=0;
	button_b=0;
	int noload=0;

	statbuf = dbp_load("IFACE/T_PICT.DBP",55,160);
	clear_rectangle();
	statbuf=dbp_load("IFACE/AB_BUT.DBP",200,390);

	//--- load all picture in OFF mode ---
	statbuf=dbp_load("TUMB/01_OFF.DBP",260,120);
	statbuf=dbp_load("TUMB/02_OFF.DBP",350,120);
	statbuf=dbp_load("TUMB/03_OFF.DBP",440,120);
	statbuf=dbp_load("TUMB/04_OFF.DBP",260,210);
	statbuf=dbp_load("TUMB/05_OFF.DBP",350,210);
	statbuf=dbp_load("TUMB/06_OFF.DBP",440,210);
	statbuf=dbp_load("TUMB/07_OFF.DBP",260,300);
	statbuf=dbp_load("TUMB/08_OFF.DBP",350,300);
	statbuf=dbp_load("TUMB/09_OFF.DBP",440,300);

	while (button_a_or_b==0)
	{
		//--- turn picture OFF for old selection ---
		if (old_selection==1 && noload==0)
				statbuf=dbp_load("TUMB/01_OFF.DBP",260,120);
		if (old_selection==2 && noload==0)
				statbuf=dbp_load("TUMB/02_OFF.DBP",350,120);
		if (old_selection==3 && noload==0)
				statbuf=dbp_load("TUMB/03_OFF.DBP",440,120);
		if (old_selection==4 && noload==0)
				statbuf=dbp_load("TUMB/04_OFF.DBP",260,210);
		if (old_selection==5 && noload==0)
				statbuf=dbp_load("TUMB/05_OFF.DBP",350,210);
		if (old_selection==6 && noload==0)
				statbuf=dbp_load("TUMB/06_OFF.DBP",440,210);
		if (old_selection==7 && noload==0)
				statbuf=dbp_load("TUMB/07_OFF.DBP",260,300);
		if (old_selection==8 && noload==0)
				statbuf=dbp_load("TUMB/08_OFF.DBP",350,300);
		if (old_selection==9 && noload==0)
				statbuf=dbp_load("TUMB/09_OFF.DBP",440,300);

		//--- turn picture ON for new selection ---
		if (new_selection==1 && noload==0)
				statbuf=dbp_load("TUMB/01_ON.DBP",260,120);
		if (new_selection==2 && noload==0)
				statbuf=dbp_load("TUMB/02_ON.DBP",350,120);
		if (new_selection==3 && noload==0)
				statbuf=dbp_load("TUMB/03_ON.DBP",440,120);
		if (new_selection==4 && noload==0)
				statbuf=dbp_load("TUMB/04_ON.DBP",260,210);
		if (new_selection==5 && noload==0)
				statbuf=dbp_load("TUMB/05_ON.DBP",350,210);
		if (new_selection==6 && noload==0)
				statbuf=dbp_load("TUMB/06_ON.DBP",440,210);
		if (new_selection==7 && noload==0)
				statbuf=dbp_load("TUMB/07_ON.DBP",260,300);
		if (new_selection==8 && noload==0)
				statbuf=dbp_load("TUMB/08_ON.DBP",350,300);
		if (new_selection==9 && noload==0)
				statbuf=dbp_load("TUMB/09_ON.DBP",440,300);

		//KOS - Dreamcast is too fast ;)
		thd_sleep(200);
		
		//--- wait for keypress on controller ---
		while (!controller_button())
			{
			thd_sleep(10);
			}
		//2010: Optimize selection: no move = no reload
		if (selection<1)
			{
			noload=1;
			selection=1;
			}
		else if (selection>9)
			{
			noload=1;
			selection=9;
			}
		else noload=0;

		old_selection = new_selection;
		new_selection = selection;
	}
	if (button_b==1)
	{
		selection=-1;
	}

	clear_rectangle();
	return selection;
}

//---------------------------------------------------------------------
// main-part to select a picture for playing
//---------------------------------------------------------------------
void options_pictures()
{
	selection = vmu_pictures;
	statbuf = picture_menu();
	clear_rectangle();

	if (statbuf!=-1)
		{
		vmu_pictures = selection;
		}
	//--- initialise data and prepare for return ---
	selection=3;
	statbuf=0;
	button_a=0;
	button_b=0;
	button_a_or_b=0;
	return;
}

//---------------------------------------------------------------------
// main part to select options
//---------------------------------------------------------------------
void options()
{
	selection =1;

	while(1)
		{
		statbuf = menu_selection("IFACE/T_OPTI.DBP","IFACE/DIFF_ON.DBP","IFACE/DIFF_OFF.DBP","IFACE/MUSI_ON.DBP","IFACE/MUSI_OFF.DBP","IFACE/PICT_ON.DBP","IFACE/PICT_OFF.DBP");
		if (statbuf==-1)
				return;
		if (statbuf==1)
				options_difficulty();
		if (statbuf==2)
				options_music();
		if (statbuf==3)
			options_pictures();
		}
}

//---------------------------------------------------------------------
// select a random song (from within the selected song categorie
//---------------------------------------------------------------------
void game_song()
{
	int random_song;            //---pseudo-random for song selection   

	char *fn = "";
	
	//2010: Simplified the funcion and now loads the song perfectly :)
	
	random_song = (randnum(5)+1);
	
	if (vmu_music==1){
		sprintf( fn, "MUSIC/SOFT/SONG_%d.S3M", random_song );
	}
	else if (vmu_music==2){
		sprintf( fn, "MUSIC/MEDIUM/SONG_%d.S3M", random_song );
	}
	else if (vmu_music==3){
		sprintf( fn, "MUSIC/FAST/SONG_%d.S3M", random_song );
	}

	//bfont_draw_str(vram_s+20*640+20,640,fn);
	statbuf = s3m_play(fn);
	return;    
}

//---------------------------------------------------------------------
// load picture and show on screen
//---------------------------------------------------------------------
void game_picture()
{
	int x,y;
	char *fn="";

	x=254;
	while (x!=505)
		{
		x++;
		y=154;
		while (y!=405)
			{
			y++;
			vram_s[x + (640*y)] = RGB565(32,32,32);
			}
		}

	if (vmu_pictures==1)
			fn="PICT/01.DBP";
	if (vmu_pictures==2)
			fn="PICT/02.DBP";
	if (vmu_pictures==3)
			fn="PICT/03.DBP";
	if (vmu_pictures==4)
			fn="PICT/04.DBP";
	if (vmu_pictures==5)
			fn="PICT/05.DBP";
	if (vmu_pictures==6)
			fn="PICT/06.DBP";
	if (vmu_pictures==7)
			fn="PICT/07.DBP";
	if (vmu_pictures==8)
			fn="PICT/08.DBP";
	if (vmu_pictures==9)
			fn="PICT/09.DBP";

	dbp_load(fn,260,160);
}

//---------------------------------------------------------------------
// check to see if the prefered move is not out of boundaries
//---------------------------------------------------------------------
int check_valid_move(char *direction,int freeplace,int block_max)
{
	int returnvalue=1;
	//--------------------------------------
	if (direction=="UP")
		{
		if (block_max==9)
			{
			if (freeplace>6)
				{
				returnvalue=0;
				}
			}
		if (block_max==16)
			{
			if (freeplace>12)
				{
				returnvalue=0;
				}
			}
		if (block_max==25)
			{
			if (freeplace>20)
				{
				returnvalue=0;
				}
			}
		}
	//--------------------------------------
	if (direction=="DOWN")
		{
		if (block_max==9)
			{
			if (freeplace<4)
				{
				returnvalue=0;
				}
			}
		if (block_max==16)
			{
			if (freeplace<5)
				{
				returnvalue=0;
				}
			}
		if (block_max==25)
			{
			if (freeplace<6)
				{
				returnvalue=0;
				}
			}
		}
	//--------------------------------------
	if (direction=="RIGHT")
		{
		if (block_max==9)
			{
			if ((freeplace==1)||(freeplace==4)||(freeplace==7))
				{
				returnvalue=0;
				}
			}
		if (block_max==16)
			{
			if ((freeplace==1)||(freeplace==5)||(freeplace==9)||(freeplace==13))
				{
				returnvalue=0;
				}
			}
		if (block_max==25)
			{
			if ((freeplace==1)||(freeplace==6)||(freeplace==11)||(freeplace==16)||(freeplace==21))
				{
				returnvalue=0;
				}
			}
		}
	//--------------------------------------
	if (direction=="LEFT")
		{
		if (block_max==9)
			{
			if ((freeplace==3)||(freeplace==6)||(freeplace==9))
				{
				returnvalue=0;
				}
			}
		if (block_max==16)
			{
			if ((freeplace==4)||(freeplace==8)||(freeplace==12)||(freeplace==16))
				{
				returnvalue=0;
				}
			}
		if (block_max==25)
			{
			if ((freeplace==5)||(freeplace==10)||(freeplace==15)||(freeplace==20)||(freeplace==25))
				{
				returnvalue=0;
				}
			}
		}
	return returnvalue;
}
//----------------------------------------------------------------------------------
// calculate new position, relying on current position, maximum blocks and direction
//----------------------------------------------------------------------------------
int calculate(int freeplace,char *direction,int block_max)
{
	int returnvalue=0;
	int position=0;

	if (block_max==9)
		position=3;
	if (block_max==16)
		position=4;
	if (block_max==25)
		position=5;

	if (direction=="UP")
		returnvalue=freeplace+position;
	if (direction=="DOWN")
		returnvalue=freeplace-position;
	if (direction=="LEFT")
		returnvalue=freeplace+1;
	if (direction=="RIGHT")
		returnvalue=freeplace-1;

	return returnvalue;
}
//---------------------------------------------------------------------
// this function contains all activities and logic to "shuffle"
//---------------------------------------------------------------------
int game_play()
{
int block_x[25], block_y[25], block_order[25],count;
int times, counter,switch_from, switch_to,swap;
int block_max=0;
int block_pixels=0;
Img *block_black, *block_data[25];
int freeplace=0;
int tmp=0;
int oldfreeplace=0;
int newfreeplace=0;
int gamecomplete=0;


		//--- do initialisation before gameplay ---
	if (vmu_difficulty==1)
		{
		block_x[1]=260;
		block_x[4]=260;
		block_x[7]=260;
		block_x[2]=340;
		block_x[5]=340;
		block_x[8]=340;
		block_x[3]=420;
		block_x[6]=420;
		block_x[9]=420;
		block_y[1]=160;
		block_y[2]=160;
		block_y[3]=160;
		block_y[4]=240;
		block_y[5]=240;
		block_y[6]=240;
		block_y[7]=320;
		block_y[8]=320;
		block_y[9]=320;
		block_max = 9;
		block_pixels = 80;
		}
	if (vmu_difficulty==2)
		{
		block_x[1]=260;
		block_x[5]=260;
		block_x[9]=260;
		block_x[13]=260;
		block_x[2]=320;
		block_x[6]=320;
		block_x[10]=320;
		block_x[14]=320;
		block_x[3]=380;
		block_x[7]=380;
		block_x[11]=380;
		block_x[15]=380;
		block_x[4]=440;
		block_x[8]=440;
		block_x[12]=440;
		block_x[16]=440;
		block_y[1]=160;
		block_y[2]=160;
		block_y[3]=160;
		block_y[4]=160;
		block_y[5]=220;
		block_y[6]=220;
		block_y[7]=220;
		block_y[8]=220;
		block_y[9]=280;
		block_y[10]=280;
		block_y[11]=280;
		block_y[12]=280;
		block_y[13]=340;
		block_y[14]=340;
		block_y[15]=340;
		block_y[16]=340;
		block_max = 16;
		block_pixels = 60;
		}
	if (vmu_difficulty==3)
		{
		block_x[1]=260;
		block_x[6]=260;
		block_x[11]=260;
		block_x[16]=260;
		block_x[21]=260;
		block_x[2]=308;
		block_x[7]=308;
		block_x[12]=308;
		block_x[17]=308;
		block_x[22]=308;
		block_x[3]=356;
		block_x[8]=356;
		block_x[13]=356;
		block_x[18]=356;
		block_x[23]=356;
		block_x[4]=404;
		block_x[9]=404;
		block_x[14]=404;
		block_x[19]=404;
		block_x[24]=404;
		block_x[5]=452;
		block_x[10]=452;
		block_x[15]=452;
		block_x[20]=452;
		block_x[25]=452;
		block_y[1]=160;
		block_y[2]=160;
		block_y[3]=160;
		block_y[4]=160;
		block_y[5]=160;
		block_y[6]=208;
		block_y[7]=208;
		block_y[8]=208;
		block_y[9]=208;
		block_y[10]=208;
		block_y[11]=256;
		block_y[12]=256;
		block_y[13]=256;
		block_y[14]=256;
		block_y[15]=256;
		block_y[16]=304;
		block_y[17]=304;
		block_y[18]=304;
		block_y[19]=304;
		block_y[20]=304;
		block_y[21]=352;
		block_y[22]=352;
		block_y[23]=352;
		block_y[24]=352;
		block_y[25]=352;
		block_max = 25;
		block_pixels = 48;
		}
	//--- build block sequence ---
	counter = 0;
	while (counter!=block_max)
		{
		counter++;
		block_order[counter]=counter;        
		}

	//--- shuffle blocks in memory ---
	times = randnum(9999) + 1;
	counter = 0;
	while (counter!=times)
		{
		counter++;
		switch_from = randnum(block_max-1)+1;
		switch_to = randnum(block_max-1)+1;
		tmp = randnum(9999);
		swap = block_order[switch_from];
		block_order[switch_from] = block_order[switch_to];
		block_order[switch_to] = swap;
		}

	//---fill blocks with picture information ---
	counter = 0;
	while (counter!=block_max)
		{
		counter++;
		block_data[counter] = copy_rectangle(block_x[counter],block_y[counter],block_pixels-1);
		}

	//---put shuffled data on screen ---
	counter = 0;
	while (counter!=(block_max))
		{
		counter++;
		put_rectangle(block_data[block_order[counter]],block_x[counter],block_y[counter],block_pixels-1);
		}

	//---cut a piece out of the puzzle           ---
	//---otherwise you can't move any blocks ;-) ---
	block_black = copy_rectangle(530,160,block_pixels-1);
	put_rectangle(block_data[block_max],530,160,block_pixels-1);
	put_rectangle(block_black,block_x[block_max],block_y[block_max],(block_pixels-1));

	freeplace = block_max;
	
	//KOS - Free memory :)
	counter = 0;
	while (counter!=block_max)
		{
		counter++;
		free(block_data[counter]->rect_data);
		free(block_data[counter]);
		}
	free(block_black);

	//KOS - Dreamcast is too fast ;)
	thd_sleep(200);
		
	//--- do the actual playing ---

	while (gamecomplete==0)
		{
		//--- wait for keypress on controller ---
		direction="";
		while (!controller_button())
			{
			thd_sleep(10);
			}
		//--- do action, depending on direction ---
		statbuf = check_valid_move(direction,freeplace,block_max);
		if (statbuf == 1)
			{
			oldfreeplace = freeplace;
			newfreeplace = calculate(freeplace,direction,block_max);
			if ((newfreeplace>0) && (newfreeplace<block_max+1))
				{
				put_rectangle(block_black,block_x[newfreeplace],block_y[newfreeplace],(block_pixels-1));
				swap=block_order[newfreeplace];                
				block_order[newfreeplace] = block_order[oldfreeplace];
				block_order[oldfreeplace]=swap;
				put_rectangle(block_data[block_order[oldfreeplace]],block_x[oldfreeplace],block_y[oldfreeplace],(block_pixels-1));
				freeplace = newfreeplace;
				}
			}
		//--- controle to see if game is complete ---
		gamecomplete=1;
		count=0;
		while(count!=block_max)
			{
			count++;
			if (block_order[count]!=count)
				gamecomplete=0;
			}
		thd_sleep(300);
		if ((direction=="START")||(direction=="A"))
			return 0;
		}
	put_rectangle(block_black,530,160,(block_pixels-1));
	return 1;
}

//---------------------------------------------------------------------
// main function to start a new game
//---------------------------------------------------------------------
void start_game()
{
	statbuf = dbp_load("IFACE/T_GAME.DBP",55,160);
	clear_rectangle();
	game_song();
	game_picture();
	statbuf = game_play();

	if (statbuf ==1)
		{
		game_picture();
		statbuf=dbp_load("IFACE/CONGRATS.DBP",250,405);
		
		//KOS - Dreamcast is too fast ;)
		thd_sleep(200);
		
		//--- wait for start button ---
		while (!wait_startbutton())
			{

			thd_sleep(10);
			}
		}
	statbuf = s3m_play("MUSIC/INTRO.S3M");
	clear_rectangle();
	return;
}

//---------------------------------------------------------------------
// main function, this is where all the fun starts ;-)
//---------------------------------------------------------------------
int main()
{
	//--- do lots of initialisations and show startupscreen ---
	vid_set_mode(DM_640x480_PAL_IL,PM_RGB565);
	printf("Starting...\n");
	//--- KOS function to redirect to CD ---
	fs_chdir("cd/shuffle");
	//-- Init random seed generator
	srand(time(NULL));
	
	shuffle_icon();
	vmu_difficulty=1;
	vmu_music=1;
	vmu_pictures=1;
	spu_init();
	statbuf = s3m_play("MUSIC/INTRO.S3M");
	statbuf = dbp_load("IFACE/INTRO.DBP",30,10);

	//--- wait for start button ---
	while (!wait_startbutton())
		{
			
		thd_sleep(10);
		}

	//--- show main menu ---
	statbuf = dbp_load("IFACE/BCKGRND.DBP",30,10);
	
	while(1)
	{
	selection = 1;
	statbuf = menu_selection("","IFACE/STAR_ON.DBP","IFACE/STAR_OFF.DBP","IFACE/OPTI_ON.DBP","IFACE/OPTI_OFF.DBP","IFACE/CRED_ON.DBP","IFACE/CRED_OFF.DBP");

	if (statbuf==1)
			start_game();
	if (statbuf==2)
			options();
	if (statbuf==3)
			credits();

	}

//--- this was used for testing when development was in progress ---
	spu_disable();
	return 0;
}
