#include "glover.h"
#include <convert.h>

long	LoadSaveScreen(long *res0,long *res1, int want_to_save);

#define BLOCK_MAX	(15)
#define	O_RDONLY	0x01
#define	O_WRONLY	0x02

#define	CARDLOAD	0
#define	CARDSAVE	1

#if (GOLDCD==NO) || (RELEASE==NO)
//#define CREATE_ISL_DONGLE
#endif

// okay, they work, but use memory
//#define DISPLAY_ANIMATIONS


#ifdef DISPLAY_ANIMATIONS
#define READ_HEADER_LENGTH 512
#else
#define READ_HEADER_LENGTH 256
#endif

// the "A" is the territory
// the "SLPS-00001" is the product ID to be supplied by Sony
// After the 1st 12 characters, there are 8 chars for our own use. Finish with a Null

// I'm writing "GL" followed by a 5 digit number

#if PALMODE==0
	#define PRODUCTCODE		"SLUS-00890"
	#define MEMORYCARDNAME	"BA" PRODUCTCODE "GL"
	#define PRODUCTCODE2		"SLES-02213"
	#define MEMORYCARDNAME2	"BE" PRODUCTCODE2 "GL"
#else
	#define PRODUCTCODE		"SLES-02213"
	#define MEMORYCARDNAME	"BE" PRODUCTCODE "GL"
	#define PRODUCTCODE2		"SLUS-00890"
	#define MEMORYCARDNAME2	"BA" PRODUCTCODE2 "GL"
#endif

/*
// from sony's stuff
struct DIRENTRY {
	char name[20];
	long attr;
	long size;
	struct DIRENTRY *next;
	long head;
	char system[4];
};
*/

// Values for "LoadGame"
enum
{
LOADSAVE_NOWT,
LOADSAVE_PRESSED,
LOADSAVE_LOAD,
LOADSAVE_SAVE,

LOADSAVE_OVERWRITECHECK,
LOADSAVE_OVERWRITE,

LOADSAVE_FORMATCHECK,
LOADSAVE_FORMAT0,
LOADSAVE_FORMAT1,
LOADSAVE_UNFORMAT,

LOADSAVE_LOADOK,
LOADSAVE_SAVEOK,
LOADSAVE_ERROR,

LOADSAVE_TYPES
};

char safe_to_quit[LOADSAVE_TYPES] =
{
	1,0,0,0,
	0,0,
	0,0,0,0,
	1,1,0
};

enum
{
	EXITFLAG_DONT,
	EXITFLAG_OK,
	EXITFLAG_ERROR
};

typedef struct
{
	struct DIRENTRY fileList[2][BLOCK_MAX];	// 40 bytes * 2 * 15

	UBYTE	cardData[2] [15] [READ_HEADER_LENGTH];
	UBYTE	filename[2] [15] [32];
	SPRITEX	icons[2] [15][3];
	int spriteFrame[2][15];

	long readingFile;	// used when loading or when scanning
	int readCard;
	long exitFlag;

	long channel;

	int check0,check1;

	int loadGame;

	long chosen_card;
	long chosen_slot;

	char datablock[8192];
	int errorcount;

	char save_failed;	// counts down from 50 or so
	char load_failed;
//	int loadsave_todo;

}CARD_INFOSTR;

// This should only be mallocced when it's being used
// (coz otherwise it's 10K that we could use for game data
CARD_INFOSTR *card_data = NULL;




static	long files[2];
long	cardAngle=0;
TEXT *globText;
/**************************************************************/
// This function should start up the memory card system
/**************************************************************/
void	InitCards(void)
{
	DB("init memory card\n");

	MemCardInit(1);

	DB("done\n");
} 


void cardGrabMem()
{
	if(!card_data)
		card_data = MALLOC(sizeof(CARD_INFOSTR),"card");
	FMEMZERO(card_data,sizeof(CARD_INFOSTR));	// we rely on the sprite pointers being initted to zero
}
void cardFreeMem()
{
	int card,slot,icon;
	if(card_data)
	{
		for(card = 0; card < 2; card++)
		for(slot = 0; slot < 15; slot++)
		for(icon = 0; icon < 3; icon++)
		{
			if(card_data->icons[card][slot][icon].handle)
			{
				textureUnload(&card_data->icons[card][slot][icon]);
			}
		}
		FREENULL(card_data);
	}
}

/**************************************************************/


// Scan through any Glover files on either memory card, and reserve ourselves a new filename
// (alternatively, we could do a crc of our data, & use that)
void cardCreateFileName(char *fname)
{
	int card;
	int slot;
	int highest;
	int current;

#ifdef CREATE_ISL_DONGLE
	sprintf(fname,"%s DONG",MEMORYCARDNAME);
	return;
#endif

	highest = 0;

	for(card = 0; card < 2; card ++)
	{
		for(slot = 0; slot < files[card]; slot++)
		{
			if(!memcmp(MEMORYCARDNAME,&card_data->fileList[card][slot].name[0],14))
			{
				current = atol(&card_data->fileList[card][slot].name[14]);
				if(current > highest)
					highest = current;
			}
		}
	}

// if some nobber manages 99999 saves, forget it
	if(highest >= 99999)
	{
		highest = 99998;
	}

	sprintf(fname,"%s%d",MEMORYCARDNAME,highest+1);
}



/*	--------------------------------------------------------------------------------
	Function 	: MemCardControl
	Purpose 	: Handles main memory card control
	Parameters 	: none
	Returns 	: none
	Info 		: Currently Pads must be dissabled for memory card system to work
	--------------------------------------------------------------------------------*/


// Convert a 0...15 block number to a 0...(15 max) file number,
// taking multi-block files into account
int BlocknoToFileno(int card, int block)
{
	int xslotCount;
	int loop;

	xslotCount=0;

//	DB("Finding name for slot %d\n",block);
	for(loop=0;loop<block;)
	{
//		DB(" Slotc = %d,fname %s, size = %d\n",
//			xslotCount,
//			&card_data->fileList[card][xslotCount].name[0],
//			card_data->fileList[card][xslotCount].size);

		if(card_data->fileList[card][xslotCount].size>8192)
		{
//			DB("    Adding %d blocks\n",card_data->fileList[card][xslotCount].size/8192);
			loop += (card_data->fileList[card][xslotCount].size  +8191) / 8192;	
		}
		else
		{
//			DB("    adding one block\n");
			loop+=1;
		}

		if(loop<=(block))
		{
//			DB("  Counting up one\n");
			xslotCount++;
		}
	}
//	DB("Final file number = %d\n",xslotCount);
	return xslotCount;
}


long	moveFlag=FALSE;
long	stepAdd,expandx,expandy;;
char slotx=0,sloty=0;
int fileSelectFrame=0;

void	fileSelection(long *card,long *slot,long *res0,long *res1,long typeFlag)
{
long	xpos,ypos,loop,draw0,draw1;
long	blockCount[15];
long	xslotCount=0;
char	slotname[33],buf[50];
UBYTE r=128,g=128,b=128;


	xpos=ypos=0;

	if ((( debounce[0]&PAD_RIGHT )||(nleftx[0]>100))&&(fileSelectFrame MOD 2 == 0))
	{
		if(slotx<5)
			slotx+=1;

		if (typeFlag==CARDSAVE)
		{
			if ( ( (*slot)<files[*card] ) && (*slot)<15 ) (*slot)++;
			else (*slot)=0;
		}
		else if (typeFlag==CARDLOAD)
		{
			if ( ( (*slot)<(files[*card]-1) ) && (*slot)<15 ) (*slot)++;
			else (*slot)=0;
		}

	}

	if ((( debounce[0]&PAD_LEFT )||(nleftx[0]<-100))&&(fileSelectFrame MOD 2 == 0))
	{
		if(slotx>0)
			slotx-=1;
		
		if (typeFlag==CARDSAVE)
		{
			if ( (*slot)==0 ) *slot=files[*card];
			else (*slot)--;
		}
		else if (typeFlag==CARDLOAD)
		{
			if ( (*slot)==0 ) *slot=files[*card]-1;
			else (*slot)--;
		}
	}

	if ((( debounce[0]&PAD_UP)||(nlefty[0]<0))&&(fileSelectFrame MOD 2 == 0))
	{
		if(sloty>0)
			sloty-=1;
	}
	if ((( debounce[0]&PAD_DOWN)||(nlefty[0]>0))&&(fileSelectFrame MOD 2 == 0))
	{
		if(sloty<4)
			sloty+=1;
	}

	if(slotx>2)
		(*card)=1;
	else
		(*card)=0;

	ASSERT(card_data);

	draw0=draw1=FALSE;	
	if (*card==0)
	{
	
		(*slot)=(sloty*3)+slotx;
		ypos=-55;
		if (*res0==McErrNone)
		{
			draw0=TRUE;

			xpos=-150+(slotx*39);
			ypos=-84+(sloty*26);

			xslotCount = BlocknoToFileno(0,*slot);

			JIS2Ascii((UBYTE*)&slotname,(UBYTE*)&card_data->cardData[*card][xslotCount][4]);
			for (loop=0;loop<32;loop++)	// temp to convert to upper case
			{
				if (slotname[loop]>=0x61) slotname[loop]-=0x20;
			}
		
			
			if ( (xslotCount)>=files[*card] )
			{
#ifdef MULTI_LANGUAGE
				strcpy((char*)&slotname, fontFindLangString(STR_FREEBLOCK));
#else
				strcpy((char*)&slotname, "FREE BLOCK");
#endif
			}

			slotname[32]=0;
//			sprintf(globText->message,"%s\n",slotname);
			sprintf(globText->message,"%s",slotname);
			//TEXTPRINTAT(240,200,buf);

		}
		if (*res0==McErrCardNotExist)
		{
			draw0=FALSE;
			*card=1;
			slotx=3;
		}
		if (*res0==McErrCardInvalid)
		{
			draw0=FALSE;
			slotx=3;
			*card=1;
		}

		if (*res0==McErrNotFormat)
		{
			draw0=FALSE;
			slotx=3;
			*card=1;

		}
	}



	if (*card==1)
	{
		(*slot)=(sloty*3)+(slotx-3);
		ypos=-55;
		if (*res1==McErrNone)
		{
			draw1=TRUE;

			xpos=48+((slotx-3)*39);
			ypos=-84+(sloty*26);
	
			expandx=0;

			xslotCount = BlocknoToFileno(1,*slot);
			
			JIS2Ascii((UBYTE*)&slotname,(UBYTE*)&card_data->cardData[*card][xslotCount][4]);
			for (loop=0;loop<32;loop++)	// temp to convert to upper case
			{
				if (slotname[loop]>=0x61) slotname[loop]-=0x20;
			}
			if ( (xslotCount)>=files[*card] ) 	
			{
#ifdef MULTI_LANGUAGE
				strcpy((char*)&slotname, fontFindLangString(STR_FREEBLOCK));
#else
				strcpy((char*)&slotname, "FREE BLOCK");
#endif
			}

			
			slotname[32]=0;
			sprintf(globText->message,"%s\n",slotname);
			
		//	TEXTPRINTAT(240,200,buf);
			
		}
		if (*res1==McErrCardNotExist)
		{
			draw1=FALSE;
			slotx=2;
			*card=0;
		}
		if (*res1==McErrCardInvalid)
		{
			draw1=FALSE;
			slotx=2;
			*card=0;
		}

		if (*res1==McErrNotFormat)
		{
			draw1=FALSE;
			slotx=2;
			*card=0;
		}
	}



	sprctrl.scalex=12288;
	sprctrl.scaley=8192;
			
	
	(*slot)=xslotCount;

	
			

	

	if ((draw1 && (*card==1))||(draw0 &&(*card==0)) )
	{
		if (xslotCount<files[(*card)])
		{
		
#ifdef DISPLAY_ANIMATIONS
			switch(card_data->cardData[(*card)][xslotCount][2])
			{
			case 0x13:
				spritePrint(&card_data->icons[(*card)][xslotCount][(frame>>2) % 3],-155,62,0);
				break;
			case 0x12:
				spritePrint(&card_data->icons[(*card)][xslotCount][(frame>>2) & 1],-155,62,0);
				break;

			case 0x10:
			default:
				spritePrint(&card_data->icons[(*card)][xslotCount][0],-155,62,0);
				break;
			}
#else
			spritePrint(&card_data->icons[(*card)][xslotCount][0],-155,62,0);
#endif
		}

		
		r=0;
		g=150+(rsin(((fileSelectFrame*200) MOD 4096))/41);
		b=250;
		drawLineRGB(xpos-19-expandx,ypos-13-expandy,xpos-expandx,ypos-13-expandy,r,g,b,2);	// top
		drawLineRGB(xpos+expandx,ypos-13-expandy,xpos+19+expandx,ypos-13-expandy,r,g,b,2);

		drawLineRGB(xpos-19-expandx,ypos+12+expandy,xpos-expandx,ypos+12+expandy,r,g,b,2);	// bottom
		drawLineRGB(xpos+expandx,ypos+12+expandy,xpos+18+expandx,ypos+12+expandy,r,g,b,2);

		drawLineRGB(xpos-19-expandx,ypos-13-expandy,xpos-19-expandx,ypos-expandy,r,g,b,2);	// left
		drawLineRGB(xpos-19-expandx,ypos+expandy,xpos-19-expandx,ypos+12+expandy,r,g,b,2);

		drawLineRGB(xpos+18+expandx,ypos-13-expandy,xpos+18+expandx,ypos-expandy,r,g,b,2);	// right
		drawLineRGB(xpos+18+expandx,ypos+expandy,xpos+18+expandx,ypos+12+expandy,r,g,b,2);
	}
	fileSelectFrame++;

}



// states for saveFlag

#define	NOTSELECTED		0
#define	SELECTED		1
#define	SAVEDATA		2
#define SAVEDATAOVER	3

/*	--------------------------------------------------------------------------------
	Function 	: MemCardControl
	Purpose 	: Handles main memory card control
	Parameters 	: none
	Returns 	: none
	Info 		: Currently Pads must be dissabled for memory card system to work
	--------------------------------------------------------------------------------*/
//struct DIRENTRY	*temppy;

/* get card information */

int MemCardControl(int flags)
{
	int rval;
	long	result0=0,result1=0,selection=2,loop,test;
//char dataBlock[8192];	// we *can't* have things eating 8K of stack
//	char *dataBlock;


// ========= Memory & Vram Leak test ========
//	DB(">>> Entry to MemCardControl\n");
//	textureVRAMcounter();
//	memoryShow();



//	dataBlock = MALLOC(8192,"card data");
//	ASSERT(dataBlock);
//	FMEMZERO(dataBlock,8192);
	
//	while (PadGetState(0)!=PadStateStable);
//	PadStopCom();	// Stop pad
//	VSync(0);		// Dos'nt work unless this is done (alway prints an error)

	MemCardStart();	// Start memory card file system
	cardGrabMem();

#if GOLDCD==NO
	no_pollhosts = 1;	// The debugger screws up the memory card access
#endif

	if(flags & MEMCARD_SAVE)
	{
		//load memcard savegame header 	(icon template)
		ULONG	*saveData;

		saveData=(ULONG *)fileLoad("TEST\\GLOVER.BIN",0);
		memcpy(&card_data->datablock[0],saveData,512);
		FREE(saveData);

#ifdef CREATE_ISL_DONGLE
		cardInitialGameState();
#endif

		cardBuildBlock((CARDSLOT *)(&card_data->datablock[0]));	// stick the current gamestate into the save block
		DB("Card block built\n");
	}

	textReset();				// Setup font scale ect
	messctrl.font=fontList[1];
	spriteReset();
	sprctrl.stretch=1;


	if(flags & MEMCARD_LOAD)
		selection=0; 
	else if(flags & MEMCARD_SAVE)
		selection=1;


	DB("Going to load-save screen\n");
	rval = LoadSaveScreen(&result0,&result1,selection);


	DB("exit\n");

	MemCardStop();	// Stop memory card file system
//	PadStartCom();	// Reenable pad
//	FREE(dataBlock);

#if GOLDCD==NO
	no_pollhosts = 0;	// The debugger screws up the memory card access
#endif

	cardFreeMem();
	ClearAllText();

// ========= Memory & Vram Leak test ========
//	DB(">>> Exit from MemCardControl\n");
//	textureVRAMcounter();
//	memoryShow();


	return rval;
}


/*	--------------------------------------------------------------------------------
	Function 	: JIS2Ascii
	Purpose 	: Converts shift JIS to ascii
	Parameters 	: output string inputstring
	Returns 	: 
	Info 		: 
	--------------------------------------------------------------------------------*/
void	JIS2Ascii(UBYTE	*outStr,UBYTE *inStr)
{
	long	loop,jisWord,outChar;
	
	for (loop=0;loop<31;loop++)
	{
		outChar=32;
		jisWord=inStr[loop*2]*256;
		jisWord+=inStr[(loop*2)+1];
		if (jisWord>=0x824f && jisWord<=0x825f)	// number
		{
			outChar=jisWord-0x821f;
		}
		if (jisWord>=0x8260 && jisWord<=0x8280)	// A to Z
		{
			outChar=jisWord-0x821f;
		}
		if (jisWord>=0x8281)	// a to z
		{
			outChar=jisWord-0x8220;
		}
		if(jisWord==0)
		{
			outChar = 0;
		}
		outStr[loop]=outChar;
	}
	outStr[31]=0;
}
void	Ascii2JIS(UBYTE	*outStr,UBYTE *inStr)
{
	long	loop,jisWord,inChar;
	
	for (loop=0;loop<31;loop++)
	{
		inChar = inStr[loop];
		if(inChar >= '0' && inChar <= '9')
		{
			jisWord = inChar+0x821f;
		}
		else if(inChar >= 'A' && inChar <= 'Z')
		{
			jisWord = inChar+0x821f;
		}
		else if(inChar >= 'a' && inChar <= 'z')
		{
			jisWord = inChar+0x8220;
		}
		else if(inChar == 0)
		{
			jisWord = 0;
		}
		else
		{
			jisWord = 0x8140;
		}

		outStr[loop*2] = jisWord>>8;
		outStr[loop*2+1] = jisWord & 255;
	}
}

// Build a savename based on the current game status
// (would be nicer to have a name-inputter)
void cardBuildFname(UBYTE *jstring, int jis)
{
	int i;
//	int world;
	int sub;
	static char string[50];	// safety margin for the score entry
	
//	world = 0;
//	sub = 0;


// Use "WORLD/SUB *COMPLETED* not what's open
	sub = level - ATLANTIS1;
	sub = sub - 5 * (world-ATLANTIS);

	if(world == SPACE && sub > 3)
		sub -= 1;	// spaceboss2, spacebonus

/*
// The "What's open?" version
	for(i = 0; i < 6; i++)
	{
		if(GameState.levels_open[i] & LEVOPEN_CRYSTAL_DELIVERED)
			continue;

		if(GameState.levels_open[i] & LEVOPEN_L1_OPEN)
		{
			if(sub<=0)
			{
				sub = 0;
				world = i+1;
			}
		}
		if(GameState.levels_open[i] & LEVOPEN_L2_OPEN)
		{
			if(sub<=1)
			{
				sub = 1;
				world = i+1;
			}
		}
		if(GameState.levels_open[i] & LEVOPEN_L3_OPEN)
		{
			if(sub<=2)
			{
				sub = 2;
				world = i+1;
			}
		}
		if(GameState.levels_open[i] & LEVOPEN_BOSS_OPEN)
		{
			if(sub<=3)
			{
				world = i+1;
				sub = 3;
			}
		}
		if(GameState.levels_open[i] & LEVOPEN_BOSS_BEATEN)
		{
			if(sub<=4)
			{
				world = i+1;
				sub = 4;
			}
		}
	}
*/
	FMEMZERO(string,32);
	if(world == 0)
	{
		sprintf(string,"GLOVER START");	// This never happens (!)
	}
	else
	{
#ifdef MULTI_LANGUAGE
		char *substr;
		char *mainstr;
		if(sub<3)
			substr = sSubLevelNames[sub];
		else
			substr = fontFindLangString(STR_ABBREV_BOSS+((sub-3)<<8));
		mainstr = fontFindLangString(STR_ABBREV_AT+((world-1)<<8));
		if(jis)
		{
			sprintf(string,"GLOVER %s %s %d",mainstr,substr,GameState.score);
		}
		else
		{
			sprintf(string,"%s %s %d",mainstr,substr,GameState.score);
		}

#else
		if(jis)
		{
			sprintf(string,"GLOVER %s %s %d",levelNames[world-1],sSubLevelNames[sub],GameState.score);
		}
		else
		{
			sprintf(string,"%s %s %d",levelNames[world-1],sSubLevelNames[sub],GameState.score);
		}
#endif
		string[31] = 0;
	}

#ifdef CREATE_ISL_DONGLE
	sprintf(string,"GLOVER DONGLE");
#endif

	if(jis)
		Ascii2JIS(jstring,&string[0]);
	else
		strcpy(jstring,&string[0]);
}

/////////////////////////////////////////////////////////////////////////////////

// send an 8K block address
void cardBuildBlock(CARDSLOT *block)
{
	int i;

#if PALMODE == YES
	block->type = 0x11;	// Sorry, but in EU, we're not allowed animating icons
#else
	block->type = 0x13;	// Hurrah! In the US and Japan, we are allowed animating icons!
#endif

	cardBuildFname((UBYTE *)&block->name[0],1);
	FMEMCPY(&block->data[0],&GameState,sizeof(GameState));
	DB("first byte of block->data = %d\n",block->data[0]);


	//save hiscores
	FMEMCPY(&block->data[0]+sizeof(GameState),&hiScoreNames,4*6);//6names - 4chars each
	FMEMCPY(&block->data[0]+sizeof(GameState)+(4*6),&hiScoreValues,sizeof(int)*6);//6scores - 4bytes each

	//save best times
	for(i=0;i<NUM_LEVELS;i++)
	{
		FMEMCPY(&block->data[0]+sizeof(GameState)+(4*6)+(sizeof(int)*6)+(i*sizeof(int)),&(hiScores[i].timeTook),sizeof(int));//best times - 4bytes each
	}

	*(unsigned long *)(&block->data[CARD_DATA_SIZE-4]) = mem2CRC((void *)block,sizeof(CARDSLOT)-4);
}


// Initialise the variables for starting a new game from Atlantis1, with 3 lives, etc
// This routine *doesn't* "zero high score / options" type data
void cardInitialGameState()
{
//	if(gameCtrl.previousLevel == TITLE)

//	{
	DB("Initialising game state\n");
	FMEMZERO(&GameState,sizeof(GAMESTATE));
	GameState.lives = 3;
	GameState.health = 3;
	GameState.maxhealth = 3;
	GameState.version = GAMESTATE_VERSION;
	gameCtrl.hub_to_use = 1;
	gameCtrl.wayroom_world = HUB;	// so the game will do a detect dependant on xtals
//	}


#ifdef CREATE_ISL_DONGLE
	GameState.version = GAMESTATE_VERSION | 128;	// Create ISL-dongled save
#endif
}



int cardHubDecide()
{
	int n_levs;
// open some levels
	n_levs = CaveCrystalsGot();

	switch(n_levs)
	{
		case 0:
			gameCtrl.hub_to_use = 1;
			break;
		case 1:
			gameCtrl.hub_to_use = 2;
			break;

		case 2:
		case 3:
			gameCtrl.hub_to_use = 3;
			break;

		case 4:
		case 5:
			gameCtrl.hub_to_use = 5;
			break;

		case 6:
		case 7:
			gameCtrl.hub_to_use = 8;
			gameCtrl.hub_to_use = 8;
			break;
	}
	if(gameCtrl.hub_to_use != 1)
		gameCtrl.port_with_ball = 1;

	gameCtrl.wayroom_world = HUB;	// so the game will do a detect dependant on xtals

	DB("decided to use hub %d\n",gameCtrl.hub_to_use);
	return n_levs;

}

int cardExtractBlock(CARDSLOT *block)
{
	int i;
	DB("Extracting Game State\n");
	DB("first byte of block->data = %d\n",block->data[0]);

// crc check the thing
	if(*(unsigned long *)(&block->data[CARD_DATA_SIZE-4]) != mem2CRC((void *)block,sizeof(CARDSLOT)-4))
	{
		cardInitialGameState();
		return 0;
	}




	FMEMCPY(&GameState,&block->data[0],sizeof(GameState));

	//load hiscores
	FMEMCPY(&hiScoreNames,&block->data[0]+sizeof(GameState),4*6);//6names - 4chars each
	FMEMCPY(&hiScoreValues,&block->data[0]+sizeof(GameState)+(4*6),sizeof(int)*6);//6scores - 4bytes each

	//just in case this is the old format - terminate all strings
	for(i = 0; i < 6; i++)
	{
		hiScoreNames[i][3]=0;
	}

	//load best times
	for(i=0;i<NUM_LEVELS;i++)
	{
		FMEMCPY(&(hiScores[i].timeTook),&block->data[0]+sizeof(GameState)+(4*6)+(sizeof(int)*6)+(i*sizeof(int)),sizeof(int));//best times - 4bytes each
	}

	for(i = 0; i < 6; i++)
	{
		DB("Level state from card %i = %x\n",i,GameState.levels_open[i]);
	}

	cardHubDecide();

// Flag the developer-only cheats as being enabled if it's an ISL-internal memory card
	if(GameState.version & 128)
		isl_dongle_used = 1;
	GameState.version &= ~128;


// This should only happen during development
	if(GameState.version != GAMESTATE_VERSION)
	{
		cardInitialGameState();
		return 0;
	}

	return 1;
}









void SaveBegin(long *res0, long *res1)
{
	int rval;
	int retry;
	char fname[34];

	card_data->readCard=card_data->chosen_card;
	DB("Opening card %d file %d for saving\n",card_data->chosen_card,card_data->readingFile);

	rval = -1;

	for(retry = 0; retry < 3 && rval != McErrNone; retry++)
	{
		rval = McErrNone;
		if(card_data->loadGame == LOADSAVE_OVERWRITE)	//if(flag == 2)
		{
			DB("Deleting card %d file %d (%s)\n",card_data->chosen_card,card_data->chosen_slot,&card_data->fileList[card_data->chosen_card][card_data->chosen_slot].name[0]);
			rval = MemCardDeleteFile(
				 ((card_data->chosen_card)?0x10:0x0),
				 &card_data->fileList[card_data->chosen_card][card_data->chosen_slot].name[0]
				 );
			DB("Delete Rval = %d\n",rval);
			if(card_data->readCard==0)
				(*res0)=rval;
			else
				(*res1)=rval;

		}
		if(rval == McErrNone)
		{
			card_data->loadGame = LOADSAVE_SAVE;
			cardCreateFileName(&fname[0]);

			rval = MemCardCreateFile( ((card_data->chosen_card)?0x10:0x0),fname,1);	// one block
			DB("Create Rval = %d\n",rval);
			if(card_data->readCard==0)
				(*res0)=rval;
			else
				(*res1)=rval;

		}
	}

	if(rval == McErrNone)
	{
		DB("Writing\n");
		rval = MemCardWriteFile( ((card_data->chosen_card)?0x10:0x0),fname,(ULONG*)&card_data->datablock[0],0,8192);
		if(rval == 0)
		{
			DB("Write init failed\n");
		}
		else
		{
			DB("Write init ok\n");
		}
	}
	else
	{
		card_data->save_failed = 50;
		card_data->readingFile = -1;
		DB("Save Failed on the delete/creation\n");
		card_data->loadGame = LOADSAVE_NOWT;
	}
}


void LoadBegin(long *res0, long *res1)
{
	int rval;
	int retry;


	card_data->readCard=card_data->chosen_card;
	DB("Opening card %d file %d (%s) for reading\n",card_data->chosen_card,card_data->chosen_slot,&card_data->fileList[card_data->chosen_card][card_data->chosen_slot].name[0]);

	rval = -1;

	for(retry = 0; retry < 3 && rval != McErrNone; retry++)
	{
		rval = MemCardOpen(((card_data->chosen_card)?0x10:0x0),&card_data->fileList[card_data->chosen_card][card_data->chosen_slot].name[0],O_RDONLY);
		DB("Open Rval = %d\n",rval);

	}
	if(rval==McErrNone)
	{
		rval = MemCardReadData((ULONG*)&card_data->datablock[0],0,8192);
		if(rval == 0)
		{
			DB("Read init failed\n");
		}
		else
		{
			DB("Read init ok\n");
		}
//			card_data->errorcount = 0;
	}
	else
	{
		DB("Load Failed on the openout\n");

		card_data->load_failed = 50;
		card_data->loadGame=0;
		card_data->readingFile=-1;
	}
}









TEXT *errorText;
TEXT *errorTextL1,*errorTextL2;
TEXT *yesText,*noText;


void SetL1Text(char *string, int font)
{
	int max;

	if (font == 1)
		max = 20;
	else
		max = 26;

	sprintf(errorTextL1->message,string);

	if(strlen(string) > max)
	{
		errorTextL1->scaleX = 4096 * max / strlen(string);
	}
	else
	{
		errorTextL1->scaleX = 4096;
	}

	SETRGBC(errorTextL1->r,128,128,0,FULLALPHA);
	SETRGBC(errorTextL1->r1,128,40,8,FULLALPHA);

	errorTextL1->font=fontList[font];
	errorText->message[0] = 0;
	globText->message[0] = 0;


}

void SetL2Text(char *string, int font)
{
	int max;
	if (font == 1)
		max = 20;
	else
		max = 26;

	sprintf(errorTextL2->message,string);

	if(strlen(string) > max)
	{
		errorTextL2->scaleX = 4096 * max / strlen(string);
	}
	else
	{
		errorTextL2->scaleX = 4096;
	}

	errorTextL2->font=fontList[font];
	SETRGBC(errorTextL2->r,128,128,0,FULLALPHA);
	SETRGBC(errorTextL2->r1,128,40,8,FULLALPHA);

	errorText->message[0] = 0;
	yesText->message[0] = 0;
	noText->message[0] = 0;
	globText->message[0] = 0;
}

void SetErrorText(char *string, int font)
{
	int max;
	if (font == 1)
		max = 20;
	else
		max = 26;

	sprintf(errorText->message,string);

	if(strlen(string) > max)
	{
		errorText->scaleX = 4096 * max / strlen(string);
	}
	else
	{
		errorText->scaleX = 4096;
	}

	errorText->font=fontList[font];
	SETRGBC(errorText->r,128,128,0,FULLALPHA);
	SETRGBC(errorText->r1,128,40,8,FULLALPHA);

	errorTextL1->message[0] = 0;
	errorTextL2->message[0] = 0;
	yesText->message[0] = 0;
	noText->message[0] = 0;
	globText->message[0] = 0;
}




// This is the a single pass of the memory card polling loop

void MemcardProcess(long *res0, long *res1, int want_to_save)
{
	long syncval;
	long cmds;
	long result;

//continually check for presence of memory cards
	syncval = MemCardSync(1,&cmds,&result);
	switch(syncval)
	{
		case -1:	// if no commands are currently running (never do this if still reading(shouldn't occur))
			if(!card_data->exitFlag && card_data->readingFile==-1)
			{
				DB("Sending accept command for channel %d\n",card_data->channel);
				MemCardAccept(card_data->channel);	// test to make sure cards exist 
			}
			break;

		case 0:		// Async command in progress
			break;

		case 1:		// Async command finished
			if(card_data->readCard==0)
				(*res0)=result;
			else
				(*res1)=result;
			
			if(card_data->exitFlag)
				break;
			
			switch(cmds)
			{
				case McFuncAccept:

//					DB("accept: loadGame = %d\n",card_data->loadGame);

					if(card_data->channel==0)
					{
						card_data->readCard=0;
						card_data->check0=1;
					}
					else 
					{
						card_data->readCard=1;
						card_data->check1=1;
					}

					//if we need to load a game then load it now
					if(card_data->loadGame == LOADSAVE_LOAD || card_data->loadGame == LOADSAVE_SAVE || card_data->loadGame == LOADSAVE_OVERWRITE)
					{
						DB("Load/Save/Overwrite code\n");
						//if somthing has gone wrong since just before trying to load

						if((card_data->readCard==card_data->chosen_card) && (result!=McErrNone))
						{
							card_data->loadGame=0;
							card_data->readingFile=-1;
							if(want_to_save)
							{
								card_data->save_failed = 50;
								card_data->readingFile = -1;
								card_data->loadGame = LOADSAVE_NOWT;
							}
							else
							{
								card_data->load_failed = 50;
								card_data->readingFile = -1;
								card_data->loadGame = LOADSAVE_NOWT;
							}
							DB("Error: cant load/save. Please try again\n");
							break;
						}

						// This is where we do the actual process of loading / saving
						card_data->errorcount = 0;
						if(want_to_save)
						{
							SaveBegin(res0,res1);
						}
						else
						{
							LoadBegin(res0,res1);
						}
						break;
					}


					//format card 0 if necessary
					if(card_data->loadGame == LOADSAVE_FORMAT0)
					{
						DB("Formatting card 0\n");
						MemCardFormat(0x0);
						DB("done\n");
						card_data->loadGame = LOADSAVE_NOWT;
						card_data->check0=0;

//						MemCardAccept(0x0);
//						card_data->channel = 0;

//						card_data->check0=0;
//						card_data->check1=0;
//						card_data->readingFile==-1;
						break;
					}
					//format card 1 if necessary
					if(card_data->loadGame == LOADSAVE_FORMAT1)
					{
						DB("Formatting card 1\n");
						MemCardFormat(0x10);
						DB("done\n");
						card_data->loadGame = LOADSAVE_NOWT;
						card_data->check1=0;

//						MemCardAccept(0x10);
//						card_data->channel = 0x10;

//						card_data->readingFile==-1;
						break;
					}
#if GOLDCD == NO
					//unformat card if necessary
					if(card_data->loadGame == LOADSAVE_UNFORMAT)
					{
						DB("Unformatting card 0\n");
						MemCardUnformat(0x0);
						DB("done\n");
						card_data->loadGame = LOADSAVE_NOWT;
						card_data->check0=0;

						break;
					}
#endif

/*					DB("new card %d, channel %d, checks %d%d, result ok %d",
						(result==McErrNewCard),card_data->channel,
						card_data->check0,card_data->check1,
						(result==McErrNone)
						);
*/


					if((result==McErrNewCard)
						|| ((card_data->channel==0   )&&(!card_data->check0)&&(result==McErrNone))
						|| ((card_data->channel==0x10)&&(!card_data->check1)&&(result==McErrNone))
						)
					{
/*
						if(result==McErrNewCard)
							DB("New card A\n");

						if((card_data->channel==0   )&&(!card_data->check0)&&(result==McErrNone))
							DB("New card B\n");
						if((card_data->channel==0x10)&&(!card_data->check1)&&(result==McErrNone))
							DB("New card C\n");
*/
//						DB("channel %d. cent %8x\n",card_data->channel,card_data);

						if(card_data->loadGame == LOADSAVE_OVERWRITECHECK)
							card_data->loadGame = LOADSAVE_NOWT;

						MemCardGetDirentry( card_data->channel, "*", card_data->fileList[card_data->readCard], &files[card_data->readCard], 0, BLOCK_MAX );

						DB("dir entry got\n");

						if(files[card_data->readCard]>0)
						{
							DB("readingFile initted to zero to scan card\n");
							card_data->readingFile=0;

							if(MemCardOpen(card_data->channel,&card_data->fileList[card_data->readCard][0].name[0],O_RDONLY)==McErrNone)
							{
								MemCardReadData((ULONG*)&card_data->cardData[card_data->readCard][0],0,READ_HEADER_LENGTH);	// returns later
							}
							else
							{
								card_data->readingFile=-1;
							}
						}

					
						break;
					}


					
					
					if(card_data->channel==0)
					{
						//now check other slot
						card_data->channel=0x10;
						card_data->readCard=1;
					}
					else
					{					
						//now check other slot
						card_data->channel=0x0;
						card_data->readCard=0;
					}
					MemCardAccept(card_data->channel);
					break;



				case McFuncWriteFile:
					if(card_data->loadGame == LOADSAVE_OVERWRITE || card_data->loadGame == LOADSAVE_SAVE)
					{
						if(result==McErrNone)
						{
							MemCardClose();
							card_data->loadGame=LOADSAVE_SAVEOK;
							card_data->readingFile=-1;
							DB("saved file\n");
							MenuFadeOut();
							card_data->exitFlag = EXITFLAG_OK;
						}
						else
						{
							DB("Write failed. Result = %d. Closing\n",result);

							MemCardClose();

							card_data->errorcount++;	// TRC stuff by Fred
							if(card_data->errorcount < 5)
							{
								DB("retry\n");

								SaveBegin(res0,res1);

/*
								if(MemCardCreateFile( ((card_data->chosen_card)?0x10:0x0),fname,1)==McErrNone)   // one block
								{
									DB("Create worked\n");
									MemCardWriteFile( ((card_data->chosen_card)?0x10:0x0),fname,(ULONG*)&card_data->datablock[0],0,8192);
								}
								else
								{
									DB("Create failed\n");
									//can't create file - card has probably been removed
									//give up now!
									card_data->loadGame = 0;
									card_data->readingFile=-1;

								}
*/
							}
							else
							{
								card_data->loadGame = 0;
								card_data->readingFile=-1;
								card_data->save_failed = 50;
								DB("Save Failed during the save\n");

								card_data->errorcount = 0;
							}
						}
					}
					else
					{
						MemCardClose();	// finished writing a file we didn't start writing !?
						card_data->readingFile=-1;
					}
					break;


				case McFuncReadData:
					DB("mcFuncReadData ok. loadgame = %d\n",card_data->loadGame);
	// this is the return from both reading our file in, and also from reading the "JIS text" header names
					if(card_data->loadGame == LOADSAVE_LOAD)
					{
						if(result==McErrNone)
						{
							MemCardClose();

							if(!cardExtractBlock((CARDSLOT *)&card_data->datablock[0]))
							{
								card_data->load_failed = 50;
								card_data->readingFile = -1;
								DB("Load Failed on the final CRC check\n");
								card_data->loadGame = LOADSAVE_NOWT;
							}
							else
							{
								card_data->loadGame=LOADSAVE_LOADOK;
								card_data->readingFile=-1;
								DB("read file\n");
								MenuFadeOut();
								card_data->exitFlag = EXITFLAG_OK;
							}
						}
						else
						{
							DB("Read Failed. Result = %d. Closing\n",result);
							MemCardClose();

							card_data->errorcount++;	// TRC stuff by Fred
							if(card_data->errorcount < 5)
							{
								DB("retry\n");
								LoadBegin(res0,res1);
							}
							else
							{
								card_data->loadGame = 0;
								card_data->readingFile=-1;
								card_data->load_failed = 50;
								DB("Load failed during the load\n");
								card_data->errorcount = 0;
							}
						}
					}
					else if(result==McErrNone)
					{
						int loop;
						DB("read data returns ok\n");
						MemCardClose();

	#ifdef DISPLAY_ANIMATIONS
						for(loop = 0; loop < card_data->cardData[card_data->readCard][card_data->readingFile][2] - 0x10; loop++)
	#else
						loop = 0;
	#endif
						{
							if(card_data->icons[card_data->readCard][card_data->readingFile][loop].handle)	// yes, they are initialised to zero
							{
								textureUnload(&card_data->icons[card_data->readCard][card_data->readingFile][loop]);
							}

							textureCreate(
								&card_data->icons[card_data->readCard][card_data->readingFile][loop],
								&card_data->cardData[card_data->readCard][card_data->readingFile][128 + 128 * loop],
								(short*)&card_data->cardData[card_data->readCard][card_data->readingFile][96],
								16, 16);
						}

						
	#if (GOLDCD == NO) && (RELEASE == NO)
	// Routine to print the low-level filenames (12 chars of licence data, 8 chars of "user", as well as the full ones
	// Note - games which allow multiple saves from one game, need to store a different 8-char text string
	// (eg - Driver uses a number "@nn", MGS uses a text-ified crc of the data, I think)
						{
							char buf[34];

							JIS2Ascii((UBYTE*)&buf,(UBYTE*)&card_data->cardData[card_data->readCard][card_data->readingFile][4]);
							buf[32] = 0;
							DB("card %d, file %i = %s (%s)\n",card_data->readCard,card_data->readingFile,&card_data->fileList[card_data->readCard][card_data->readingFile].name[0], buf);
						}
	#endif

						DB("readingFile incremented\n");
						card_data->readingFile++;
						if(card_data->readingFile<files[card_data->readCard])
						{
							if(MemCardOpen(card_data->channel,&card_data->fileList[card_data->readCard][card_data->readingFile].name[0],O_RDONLY)==McErrNone)
							{
								MemCardReadData((ULONG*)&card_data->cardData[card_data->readCard][card_data->readingFile],0,READ_HEADER_LENGTH);
							}
							else
							{
								card_data->readingFile=-1;
							}
						}
						else
						{
							card_data->readingFile=-1;
						}
			
					}
					else
					{
						DB("read data returns error\n");
						MemCardClose();
						card_data->readingFile=-1;
					}
					break;
				default:
					DB("Default command cmd = %d\n",cmds);
					break;

			}
			break;

		default:
			DB("Default code sync = %d\n",syncval);
			break;
	}
}


/////////////////////////////////////////////////////////////////////////////////
// This is the SAVE game loop

long	LoadSaveScreen(long *res0,long *res1,int want_to_save)
{
long	loop,test,selection;	//,flag;,waitCount
long	blockCount[15];
long	*res;
TEXT *text1,*text2;
int delay_processing = 0;

int yesno_value = 0;
int yesno_enabled = 0;

int menuFrame=0;
int xpos,ypos;
int error=0;
char buf[34];
// Flags so we don't repeatedly ask to format a card once the user's said "no"
char dontFormat0=0,dontFormat1=0;
int error_timer=0;



//	flag=0;
//	waitCount=50;
//	selection=0;

//	debounce[0]=0;

	ClearAllText(); // I moved this here in the never-ending search for a bit more memory

//	cardGrabMem();


	card_data->readingFile = -1;

	//ClearAllText();
	if(want_to_save)
	{
		char fname[34];

#ifdef MULTI_LANGUAGE
		{
			char *str;
			str = fontFindLangString(STR_SAVENAME);
			strcpy(fname,str);
			cardBuildFname((UBYTE *)&fname[strlen(str)+1],0);
			fname[strlen(str)] = 32;
		}
#else
		strcpy(&fname[0],"SAVE : ");
		cardBuildFname((UBYTE *)&fname[7],0);
#endif

		DB("fname %s\n",fname);

#if PALMODE==YES
//		NEW_TEXT(256, 15, 128,128,0,255, 4096,4096, TRUE,"SAVE GAME", TRUE);
		NEW_TEXT(256, 15, 128,128,0,255, 4096,4096, TRUE,fname, TRUE);
#else
//		NEW_TEXT(256, 20, 128,128,0,255, 4096,4096, TRUE,"SAVE GAME", TRUE);
		NEW_TEXT(256, 20, 128,128,0,255, 4096,4096, TRUE,fname, TRUE);
#endif
		mtext->flags=TEXT_SHADED;
		mtext->font=fontList[1];
		SETRGBC(mtext->r1,128,0,0,FULLALPHA);

#ifdef MULTI_LANGUAGE
	{
		int max = 26;
		if(strlen(mtext->message) > max)
		{
			mtext->scaleX = 4096 * max / strlen(mtext->message);
		}
		else
		{
			mtext->scaleX = 4096;
		}
	}




		NEW_TEXT(256, 220, 128,128,128,255, infoTextScale,infoTextScale, TRUE, fontFindLangString(STR_SAVECANCEL), TRUE);
#else
		NEW_TEXT(256, 220, 128,128,128,255, infoTextScale,infoTextScale, TRUE, "% SAVE    $ CANCEL", TRUE);
#endif
		mtext->flags=TEXT_SHADED;
		mtext->font=fontList[2];
		SETRGBC(mtext->r1,0,0,0,FULLALPHA);
	}
	else
	{
#if PALMODE==YES
	#ifdef MULTI_LANGUAGE
			NEW_TEXT(256, 15, 128,128,0,255, 4096,4096, TRUE,fontFindLangString(STR_LOADGAME), TRUE);
	#else
			NEW_TEXT(256, 15, 128,128,0,255, 4096,4096, TRUE,"LOAD GAME", TRUE);
	#endif
#else
	#ifdef MULTI_LANGUAGE
		NEW_TEXT(256, 20, 128,128,0,255, 4096,4096, TRUE,fontFindLangString(STR_LOADGAME), TRUE);
	#else
		NEW_TEXT(256, 20, 128,128,0,255, 4096,4096, TRUE,"LOAD GAME", TRUE);
	#endif
#endif
		mtext->flags=TEXT_SHADED;
		mtext->font=fontList[1];
		SETRGBC(mtext->r1,128,0,0,FULLALPHA);

#ifdef MULTI_LANGUAGE
		NEW_TEXT(256, 220, 128,128,128,255, infoTextScale,infoTextScale, TRUE, fontFindLangString(STR_LOADCANCEL), TRUE);
#else
		NEW_TEXT(256, 220, 128,128,128,255, infoTextScale,infoTextScale, TRUE, "% LOAD     $ CANCEL", TRUE);
#endif
		mtext->flags=TEXT_SHADED;
		mtext->font=fontList[2];
		SETRGBC(mtext->r1,0,0,0,FULLALPHA);
	}


	NEW_TEXT(136, 190, 128,128,0,255, 4096,4096, TRUE,"", FALSE);
	globText=mtext;
	mtext->flags=TEXT_SHADED;
	mtext->font=fontList[1];
	SETRGBC(mtext->r1,128,40,8,FULLALPHA);

//	NEW_TEXT(256, 189, 128,128,0,255, 4096,4096, TRUE,"PLEASE WAIT", TRUE);
	NEW_TEXT(256, 189, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
	errorText=mtext;
	mtext->flags=TEXT_SHADED;
	mtext->font=fontList[1];
	SETRGBC(mtext->r1,128,40,8,FULLALPHA);


// two-line errors
#if PALMODE==YES
	NEW_TEXT(256, 189-15+5, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#else
	NEW_TEXT(256, 189-15, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#endif
	errorTextL1=mtext;
	mtext->flags=TEXT_SHADED;
	mtext->font=fontList[1];
	SETRGBC(mtext->r1,128,40,8,FULLALPHA);
#if PALMODE==YES
	NEW_TEXT(256, 189+5+5, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#else
	NEW_TEXT(256, 189+5, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#endif
	errorTextL2=mtext;
	mtext->flags=TEXT_SHADED;
	mtext->font=fontList[1];
	SETRGBC(mtext->r1,128,40,8,FULLALPHA);




#if PALMODE==YES
	NEW_TEXT(256+40, 189+5+5, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#else
	NEW_TEXT(256+40, 189+5, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#endif
	yesText=mtext;
	mtext->flags=TEXT_SHADED;
	mtext->font=fontList[1];
	SETRGBC(mtext->r1,128,40,8,FULLALPHA);
#if PALMODE==YES
	NEW_TEXT(256-40, 189+5+5, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#else
	NEW_TEXT(256-40, 189+5, 128,128,0,255, 4096,4096, TRUE,"", TRUE);
#endif
	noText=mtext;
	mtext->flags=TEXT_SHADED;
	mtext->font=fontList[1];
	SETRGBC(mtext->r1,128,40,8,FULLALPHA);



	while(!card_data->exitFlag || (fadeout && (fader > 1)))
	{
	
		if(strlen(globText->message) > 18)
		{
			globText->scaleX = 4096 * 16 / strlen(globText->message);
		}
		else
		{
			globText->scaleX = 4096;
		}



//		if ( (!selection)&&(debounce[0]&PAD_TRIANGLE) && !card_data->exitFlag && safe_to_quit[card_data->loadGame])
		if ((debounce[0]&PAD_TRIANGLE) && !card_data->exitFlag && safe_to_quit[card_data->loadGame])
		{
			MenuFadeOut();
			card_data->exitFlag = EXITFLAG_ERROR;
		}
			


		Start_Loop();

		if(level==TITLE)
			menuPrintBack(1024);
		else
			menuPrintBackStatic();

		MenuDrawFade();
		ShowText();

//		if (!selection && !card_data->exitFlag && safe_to_quit[card_data->loadGame])
		if (!card_data->exitFlag
			&& safe_to_quit[card_data->loadGame]
			&& !card_data->load_failed && !card_data->save_failed
			)
		{
			if(card_data->check0 && card_data->check1 && (card_data->readingFile==-1) && (!error))
			{
				if(want_to_save)
				{
					fileSelection(&card_data->chosen_card,&card_data->chosen_slot,res0,res1,CARDSAVE);
				}
				else
				{
					fileSelection(&card_data->chosen_card,&card_data->chosen_slot,res0,res1,CARDLOAD);
				}
				if ((debounce[0]&PAD_CROSS) )
				{
//					selection=TRUE;
//					waitCount=50;
					card_data->loadGame=LOADSAVE_PRESSED;
				}
			}
		}


// x,y, w,h,  r,g,b,  thick, ot pos
		//draw translucent mem-card boxes
		DrawBox(-180,-99,140,138,50,50,70,1,5);
		DrawBox(20,-99,140,138,50,50,70,1,5);

		//Draw message box
		if(want_to_save)
		{
//			DrawBox(-220,41,420,40,0,0,90,0,3);
//			DrawBox(-216,45,420,40,0,0,0,0,4);
			DrawBox(-230,41,450,40,0,0,90,0,3);
			DrawBox(-226,45,450,40,0,0,0,0,4);
		}
		else
		{
//			DrawBox(-220,41,420,40,0,0,60,0,3);
//			DrawBox(-216,45,420,40,0,0,0,0,4);
			DrawBox(-230,41,450,40,0,0,60,0,3);
			DrawBox(-226,45,450,40,0,0,0,0,4);
		}
	


//-------------------------------------------------------

		if(!delay_processing)
		{
			MemcardProcess(res0,res1,want_to_save);
		}
		else
		{
			delay_processing--;
		}

//-------------------------------------------------------
// BOTTOM STATUS BAR DISPLAY

		if(card_data->check0 && card_data->check1)
			error=0;

		errorTextL1->message[0] = 0;
		errorTextL2->message[0] = 0;
		if(yesno_enabled)
			yesno_enabled--;

		if(!yesno_enabled)
		{
			yesText->message[0] = 0;
			noText->message[0] = 0;
		}

		if((card_data->readingFile>=0)&&(card_data->readCard==0)&&(!card_data->loadGame))
		{
#ifdef MULTI_LANGUAGE
			SetL1Text(fontFindLangString(STR_ACCESSING),1);
			sprintf(&errorTextL1->message[strlen(errorTextL1->message)]," 1");
			SetL2Text(fontFindLangString(STR_DONTREMOVE),1);
#else
			SetL1Text("ACCESSING MEMORY CARD IN MEMORY CARD SLOT 1",1);
			SetL2Text("DO NOT REMOVE MEMORY CARD",1);
#endif
			SETRGBC(errorTextL1->r,0,150+(rsin(((menuFrame*100) MOD 4096)+1024)/82),200,FULLALPHA);
			SETRGBC(errorTextL1->r1,0,75+(rsin((menuFrame*100) MOD 4096)/82),200,FULLALPHA);

		}
		else if((card_data->readingFile>=0)&&(card_data->readCard==1)&&(!card_data->loadGame))
		{
#ifdef MULTI_LANGUAGE
			SetL1Text(fontFindLangString(STR_ACCESSING),1);
			sprintf(&errorTextL1->message[strlen(errorTextL1->message)]," 2");
			SetL2Text(fontFindLangString(STR_DONTREMOVE),1);
#else
			SetL1Text("ACCESSING MEMORY CARD IN MEMORY CARD SLOT 2",1);
			SetL2Text("DO NOT REMOVE MEMORY CARD",1);
#endif
			SETRGBC(errorTextL1->r,0,150+(rsin(((menuFrame*100) MOD 4096)+1024)/82),200,FULLALPHA);
			SETRGBC(errorTextL1->r1,0,75+(rsin((menuFrame*100) MOD 4096)/82),200,FULLALPHA);
		}

		

		//if no cards
		if((card_data->check0 && card_data->check1)
			&& ((*res0 == McErrCardNotExist) || dontFormat0==1)
			&& ((*res1 == McErrCardNotExist) || dontFormat1==1)
			)
		{
#ifdef MULTI_LANGUAGE
			SetErrorText(fontFindLangString(STR_INSERTCARD),1);
#else
			SetErrorText("INSERT A MEMORY CARD",1);
#endif
//			sprintf(errorText->message,"INSERT A MEMORY CARD\n");
//			errorText->font=fontList[1];
			error=1;
		}



		//check for unformatted cards
        if(card_data->check0 && ((*res0)==McErrNotFormat)&&(!dontFormat0) && !card_data->exitFlag)
		{
			error=1;

//			selection=0;	// Turn off any loading/saving selection that was going on

			card_data->loadGame = LOADSAVE_FORMATCHECK;

#ifdef MULTI_LANGUAGE
			SetL1Text(fontFindLangString(STR_FORMATCARD),1);
			sprintf(&errorTextL1->message[strlen(errorTextL1->message)]," 1?");
#else
			SetL1Text("FORMAT MEMORY CARD IN MEMORY CARD SLOT 1?",2);
#endif
//			errorText->message[0]=0;
//			sprintf(errorTextL1->message,"FORMAT MEMORY CARD 1?");
//			errorTextL1->font=fontList[2];

#ifdef MULTI_LANGUAGE
			sprintf(yesText->message,fontFindLangString(STR_YES2));
			yesText->font=fontList[2];
			sprintf(noText->message,fontFindLangString(STR_NO2));
#else
			sprintf(yesText->message,"YES");
			yesText->font=fontList[2];
			sprintf(noText->message,"NO");
#endif
			noText->font=fontList[2];
			if(!yesno_enabled)
				yesno_value = 0;
			yesno_enabled = 2;

			if(debounce[0] & PAD_CROSS)	// Cross chooses, Traingle cancels the save/load
			{
				switch(yesno_value)
				{
				case 1:
					DB("Preparing to formatting card0....\n");
					card_data->loadGame = LOADSAVE_FORMAT0;
					delay_processing = 3;
					dontFormat0=2;
					yesno_enabled = 0;
//					debounce[0]=0;
					break;
				case 0:
				default:
					DB("Cancel format0\n");
					dontFormat0=1;
					yesno_enabled = 0;
					break;
				}
			}
		}
		else if(card_data->check1 && ((*res1)==McErrNotFormat) &&(!dontFormat1) && !card_data->exitFlag)
		{
			error=1;

//			selection=0;	// Turn off any loading/saving selection that was going on
			card_data->loadGame = LOADSAVE_FORMATCHECK;

//			errorText->message[0]=0;
//			sprintf(errorTextL1->message,"FORMAT MEMORY CARD 2?");
//			errorTextL1->font=fontList[2];
#ifdef MULTI_LANGUAGE
			SetL1Text(fontFindLangString(STR_FORMATCARD),1);
			sprintf(&errorTextL1->message[strlen(errorTextL1->message)]," 2?");
#else
			SetL1Text("FORMAT MEMORY CARD IN MEMORY CARD SLOT 2?",2);
#endif


//			sprintf(errorTextL2->message,"%% YES $ NO");
//			errorTextL2->font=fontList[2];
#ifdef MULTI_LANGUAGE
			sprintf(yesText->message,fontFindLangString(STR_YES2));
			yesText->font=fontList[2];
			sprintf(noText->message,fontFindLangString(STR_NO2));
#else
			sprintf(yesText->message,"YES");
			yesText->font=fontList[2];
			sprintf(noText->message,"NO");
#endif
			noText->font=fontList[2];
			if(!yesno_enabled)
				yesno_value = 0;
			yesno_enabled = 2;

			if(debounce[0] & PAD_CROSS)
			{
				switch(yesno_value)
				{
				case 1:
					DB("Formatting card1....\n");
					card_data->loadGame = LOADSAVE_FORMAT1;
					delay_processing = 3;
					dontFormat1=2;
					yesno_enabled = 0;
					break;
				case 0:
				default:
					DB("Cancel format1\n");
					dontFormat1=1;
					yesno_enabled = 0;
					break;
				}
			}
		}
		else if (card_data->loadGame == LOADSAVE_FORMATCHECK)
		{
			card_data->loadGame = LOADSAVE_NOWT;
		}


        //-----------------------------------------------------------
		//check for unformatting of cards - test stuff!
#if GOLDCD == NO
//        if(card_data->check0 && ((*res0)==McErrNone) && (debounce[0] & PAD_SQUARE))	
        if(card_data->check0 && ((*res0)==McErrNone)
			&& debounce[0]
			&& (pad[0] & (PAD_L1 + PAD_L2 + PAD_R1 + PAD_R2 + PAD_SQUARE)) == PAD_L1 + PAD_L2 + PAD_R1 + PAD_R2 + PAD_SQUARE)
		{
			DB("preparing to Unformat card0....\n");
//			MemCardUnformat(0x0);
			card_data->loadGame = LOADSAVE_UNFORMAT;
		}
#endif
		//-----------------------------------------------------------

// Concluding part of the TRC fun...

		if(card_data->errorcount >= 5)
		{
			card_data->errorcount++;

			if(want_to_save)
			{
//				SetErrorText("SAVE PAILED",2);
			}
			else
			{
//				sprintf(errorText->message,"LOAD FAILED");
//				errorText->font=fontList[2];	
#ifdef MULTI_LANGUAGE
				SetErrorText(fontFindLangString(STR_LOADFAIL),2);
#else
				SetErrorText("LOAD FAILED",2);
#endif
			}
			if(card_data->errorcount < 80)
				error=1;
		}


		if(card_data->save_failed)
		{
#ifdef MULTI_LANGUAGE
				SetErrorText(fontFindLangString(STR_SAVEFAIL),2);
#else
			SetErrorText("SAVE FAILED",2);
#endif
			card_data->save_failed--;
			error=1;

		}
		if(card_data->load_failed)
		{
#ifdef MULTI_LANGUAGE
				SetErrorText(fontFindLangString(STR_LOADFAIL),2);
#else
			SetErrorText("LOAD FAILED",2);
#endif
			card_data->load_failed--;
			error=1;

		}

//if something is selected
//		if (selection && !card_data->exitFlag)
		if (!card_data->exitFlag)
		{
	
			if (card_data->chosen_card==0)
				res=res0;
			else
				res=res1;

			if ( *res !=McErrNone )
			{
//				if ( waitCount )
//				{
//					TEXTPRINTAT(256,200,"MEMORY CARD INVALID");
//					waitCount--;
//				}
//				else
//				{
//					selection=FALSE;
//				}
			}
			else
			{

				if(want_to_save)
				{
					if(card_data->loadGame == LOADSAVE_PRESSED)
					{
						if(card_data->chosen_slot >= files[card_data->chosen_card])
						{
							card_data->loadGame = LOADSAVE_SAVE;
//							waitCount=0;
							card_data->readingFile=0;
						}
						else
						{
							card_data->loadGame = LOADSAVE_OVERWRITECHECK;
//							debounce[0]=0;
						}
					}
					else if (card_data->loadGame == LOADSAVE_OVERWRITECHECK)	// the else is so we get a new "debounce"
					{
//						waitCount=-1;

#ifdef MULTI_LANGUAGE
						sprintf(yesText->message,fontFindLangString(STR_YES2));
						yesText->font=fontList[2];
						sprintf(noText->message,fontFindLangString(STR_NO2));
#else
						sprintf(yesText->message,"YES");
						yesText->font=fontList[2];
						sprintf(noText->message,"NO");
#endif
						noText->font=fontList[2];
						if(!yesno_enabled)
							yesno_value = 0;

						error=1;
						yesno_enabled = 2;

//						errorText->message[0]=0;
//						sprintf(errorTextL1->message,"OVERWRITE EXISTING DATA?");
//						errorTextL1->font=fontList[2];	
#ifdef MULTI_LANGUAGE
						SetL1Text(fontFindLangString(STR_OVERWRITE),2);
#else
						SetL1Text("OVERWRITE EXISTING DATA?",2);
#endif

						if(debounce[0] & PAD_CROSS)
						{
							switch(yesno_value)
							{
							case 1:
								DB("Overwriting file....\n");
								card_data->loadGame = LOADSAVE_OVERWRITE;
								card_data->readingFile=0;
								yesno_enabled = 0;
//								waitCount=0;
//								debounce[0]=0;
								break;

							case 0:
							default:
								DB("Cancel overwrite\n");
								yesno_enabled = 0;
//								selection=0;
//								waitCount=0;
//								debounce[0]=0;
								card_data->loadGame = LOADSAVE_NOWT;

							}
						}
					}
				}
				else	// else of want_to_save. Ie, this is want_to_load
				{
					if (card_data->loadGame == LOADSAVE_PRESSED)	// just pressed
					{
						if(
						  (memcmp(MEMORYCARDNAME,&card_data->fileList[card_data->chosen_card][card_data->chosen_slot].name[0],14))
						&&(memcmp(MEMORYCARDNAME2,&card_data->fileList[card_data->chosen_card][card_data->chosen_slot].name[0],14)))

						{
//							DB("Setting flag to 2 - %s %s %s\n",MEMORYCARDNAME,MEMORYCARDNAME2,card_data->fileList[card_data->chosen_card][slot].name);
							card_data->loadGame == LOADSAVE_NOWT;
							DB("not glover file card:%d slot:%d %s\n",card_data->chosen_card,card_data->chosen_slot,card_data->fileList[card_data->chosen_card][card_data->chosen_slot].name); 

//							sprintf(errorText->message,"NOT A GLOVER SAVED GAME\n");
//							errorText->font=fontList[1];
#ifdef MULTI_LANGUAGE
							SetErrorText(fontFindLangString(STR_NOTGLOVER),1);
#else
							SetErrorText("NOT A GLOVER SAVED GAME",1);
#endif
							error=1;
							error_timer = 40;
							card_data->loadGame = LOADSAVE_ERROR;

//							waitCount--;
						}
						else
						{		   
//							DB("Setting flag to 1\n");
							DB("Preparing to load\n");
							card_data->loadGame = LOADSAVE_LOAD;
//							waitCount=0;
							card_data->readingFile=0;
						}
					}
				}	// end of want_to_save

//				if (waitCount==0)
//					selection=0;

			}	// end of res != / == McErrNone
		}	// end of "selection && !exitFlag


		

		if(error_timer)
		{
			error_timer--;
			error = 1;
			if(!error_timer)
				card_data->loadGame = LOADSAVE_NOWT;
		}


		if(
			   card_data->loadGame == LOADSAVE_LOAD
			|| card_data->loadGame == LOADSAVE_SAVE
			|| card_data->loadGame == LOADSAVE_OVERWRITE
			|| card_data->loadGame == LOADSAVE_FORMAT0
			|| card_data->loadGame == LOADSAVE_FORMAT1
			)
		{

			
// This is printed throughout the delay_processing loop, after which the format locks things up.
#ifdef MULTI_LANGUAGE
			switch(card_data->loadGame)
			{
				case LOADSAVE_FORMAT0:
					SetL1Text(fontFindLangString(STR_FORMATTING),1);
					sprintf(&errorTextL1->message[strlen(errorTextL1->message)]," 1");
					break;

				case LOADSAVE_FORMAT1:
					SetL1Text(fontFindLangString(STR_FORMATTING),1);
					sprintf(&errorTextL1->message[strlen(errorTextL1->message)]," 2");
					break;
				
				case LOADSAVE_SAVE:
				case LOADSAVE_OVERWRITE:
					SetL1Text(fontFindLangString(STR_SAVING),1);
					break;
				case LOADSAVE_LOAD:
					SetL1Text(fontFindLangString(STR_LOADING),1);
					break;
			}
			error=1;
			SetL2Text(fontFindLangString(STR_DONTREMOVE),1);
#else
			switch(card_data->loadGame)
			{
				case LOADSAVE_FORMAT0:
					SetL1Text("FORMATTING MEMORY CARD IN MEMORY CARD SLOT 1",1);
					break;

				case LOADSAVE_FORMAT1:
					SetL1Text("FORMATTING MEMORY CARD IN MEMORY CARD SLOT 2",1);
					break;
				
				case LOADSAVE_SAVE:
				case LOADSAVE_OVERWRITE:
					SetL1Text("SAVING",1);
					break;
				case LOADSAVE_LOAD:
					SetL1Text("LOADING",1);
					break;
			}
			error=1;
			SetL2Text("DO NOT REMOVE MEMORY CARD",1);
#endif

			SETRGBC(errorTextL1->r,0,150+(rsin(((menuFrame*100) MOD 4096)+1024)/82),200,FULLALPHA);
			SETRGBC(errorTextL1->r1,0,75+(rsin((menuFrame*100) MOD 4096)/82),200,FULLALPHA);
		}


#ifdef MULTI_LANGUAGE
		if(card_data->loadGame == LOADSAVE_LOADOK)
		{
			SetErrorText(fontFindLangString(STR_LOADOK),1);
			error = 1;
		}
		if(card_data->loadGame == LOADSAVE_SAVEOK)
		{
			SetErrorText(fontFindLangString(STR_SAVEOK),1);
			error = 1;
		}
#else
		if(card_data->loadGame == LOADSAVE_LOADOK)
		{
			SetErrorText("LOAD COMPLETED. OK",1);
			error = 1;
		}
		if(card_data->loadGame == LOADSAVE_SAVEOK)
		{
			SetErrorText("SAVE COMPLETED. OK",1);
			error = 1;
		}
#endif





		//deal with card 0
		if ((*res0==McErrNone)&&(!((card_data->readingFile>=0)&&(card_data->readCard==0)&&(!card_data->loadGame))) )
		{
		
			SETRGBC(sprctrl.r,128,128,128,0);
			for (loop=0;loop<15;loop++)
			{
				blockCount[loop]=card_data->fileList[0][loop].size/8192;
			}
			test=0;
			sprctrl.scalex=6144;
			sprctrl.scaley=4096;
			
			SETRGBC(sprctrl.r,128,128,128,0);
			SETRGBC(sprctrl.r1,128,128,128,0);
			sprctrl.shaded=FALSE;

			for (loop=0;loop<15;loop++)
			{
				xpos=-150+((loop MOD 3)*39);
				ypos=-84+((loop/3)*26);

				if (test<files[0])
				{
#ifdef DISPLAY_ANIMATIONS
					switch(card_data->cardData[0][test][2])
					{
					case 0x13:
						spritePrint(&card_data->icons[0][test][(frame>>2) % 3],xpos,ypos,0);
						break;
					case 0x12:
						spritePrint(&card_data->icons[0][test][(frame>>2) & 1],xpos,ypos,0);
						break;

					case 0x10:
					default:
						spritePrint(&card_data->icons[0][test][0],xpos,ypos,0);
						break;
					}
#else
					spritePrint(&card_data->icons[0] [test][0],xpos,ypos,0);
#endif
				}
				if (blockCount[test]>1) 
					blockCount[test]--;
				else test++;
			}
			sprctrl.scalex=6144;
		}
		else //if(!error) //don't print any messages if we have an error box up
		{
	
			SETRGBC(sprctrl.r,128,128,128,0);
			SETRGBC(sprctrl.r1,0,0,0,0);
			sprctrl.shaded=TRUE;

			sprctrl.scalex=4096;
			sprctrl.scaley=4096;
			if(!card_data->check0 || card_data->loadGame == LOADSAVE_FORMAT0)
			{
#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(150,100,fontFindLangString(STR_WAIT));
				TEXTPRINTAT(150,120,fontFindLangString(STR_WAIT+1));
#else
				TEXTPRINTAT(150,100,"PLEASE");
				TEXTPRINTAT(150,120,"WAIT");
#endif
			}
			else if((card_data->readingFile>=0)&&(card_data->readCard==0)&&(!card_data->loadGame))
			{
	/*
				TEXTPRINTAT(150,60,"NEW");
				TEXTPRINTAT(150,80,"MEMORY")
				TEXTPRINTAT(150,100,"CARD.");
				TEXTPRINTAT(150,120,"READING");
				TEXTPRINTAT(150,140,"DATA");
*/
#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(150,100,fontFindLangString(STR_WAIT));
				TEXTPRINTAT(150,120,fontFindLangString(STR_WAIT+1));
#else
				TEXTPRINTAT(150,100,"PLEASE");
				TEXTPRINTAT(150,120,"WAIT");
#endif
			
			}
			else if ((*res0)==McErrNotFormat)
			{
#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(150,100,fontFindLangString(STR_NOTFORMATTED));
				TEXTPRINTAT(150,120,fontFindLangString(STR_NOTFORMATTED+1));
#else
				TEXTPRINTAT(150,100,"NOT");
				TEXTPRINTAT(150,120,"FORMATTED");
#endif
			}
			else 
		    {
				//no card - make sure we ask to format next one (if necessary) 
			   	dontFormat0=0;

				
#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(150,50,fontFindLangString(STR_NOCARD));
				TEXTPRINTAT(150,70,fontFindLangString(STR_NOCARD+1));
				TEXTPRINTAT(150,90,fontFindLangString(STR_NOCARD+2));
				TEXTPRINTAT(150,110,fontFindLangString(STR_NOCARD+3));
				TEXTPRINTAT(150,130,fontFindLangString(STR_NOCARD+4));
				TEXTPRINTAT(150,150,fontFindLangString(STR_NOCARD+5));
#else
				TEXTPRINTAT(150,50,"NO");
				TEXTPRINTAT(150,70,"MEMORY");
				TEXTPRINTAT(150,90,"CARD IN");
				TEXTPRINTAT(150,110,"MEMORY");
				TEXTPRINTAT(150,130,"CARD SLOT");
				TEXTPRINTAT(150,150,"1");
#endif
			}  		
		}




		//deal with card 1
		if ((*res1==McErrNone)&&(!((card_data->readingFile>=0)&&(card_data->readCard==1)&&(!card_data->loadGame))) )
		{
			
			SETRGBC(sprctrl.r,128,128,128,0);
			for (loop=0;loop<15;loop++)
			{
				blockCount[loop]=card_data->fileList[1][loop].size/8192;
			}
			test=0;
			sprctrl.scalex=6144;
			sprctrl.scaley=4096;
			for (loop=0;loop<15;loop++)
			{
				xpos=48+((loop MOD 3)*39);
				ypos=-84+((loop/3)*26);

				SETRGBC(sprctrl.r,128,128,128,0);
				SETRGBC(sprctrl.r1,128,128,128,0);
				sprctrl.shaded=FALSE;

				if (test<files[1])
#ifdef DISPLAY_ANIMATIONS
					switch(card_data->cardData[1][test][2])
					{
					case 0x13:
						spritePrint(&card_data->icons[1][test][(frame>>2) % 3],xpos,ypos,0);
						break;
					case 0x12:
						spritePrint(&card_data->icons[1][test][(frame>>2) & 1],xpos,ypos,0);
						break;

					case 0x10:
					default:
						spritePrint(&card_data->icons[1][test][0],xpos,ypos,0);
						break;
					}
#else
					spritePrint(&card_data->icons[1] [test][0],xpos,ypos,0);
#endif
				if (blockCount[test]>1) 
					blockCount[test]--;
				else test++;
			}
			sprctrl.scalex=6144;
		}
		else //if(!error) //don't print any messages if we have an error box up
		{
	
			SETRGBC(sprctrl.r,128,128,128,0);
			SETRGBC(sprctrl.r1,0,0,0,0);
			sprctrl.shaded=TRUE;
			sprctrl.scalex=4096;
			sprctrl.scaley=4096;
			if(!card_data->check1 || card_data->loadGame == LOADSAVE_FORMAT1)
			{
#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(350,100,fontFindLangString(STR_WAIT));
				TEXTPRINTAT(350,120,fontFindLangString(STR_WAIT+1));
#else
				TEXTPRINTAT(350,100,"PLEASE");
				TEXTPRINTAT(350,120,"WAIT");
#endif
			}
			else if((card_data->readingFile>=0)&&(card_data->readCard==1)&&(!card_data->loadGame))
			{
#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(350,100,fontFindLangString(STR_WAIT));
				TEXTPRINTAT(350,120,fontFindLangString(STR_WAIT+1));
#else
				TEXTPRINTAT(350,100,"PLEASE");
				TEXTPRINTAT(350,120,"WAIT");
#endif
/*
		  		TEXTPRINTAT(350,60,"NEW");
				TEXTPRINTAT(350,80,"MEMORY")
				TEXTPRINTAT(350,100,"CARD.");
				TEXTPRINTAT(350,120,"READING");
				TEXTPRINTAT(350,140,"DATA");
*/
			}
			else if ((*res1)==McErrNotFormat)
			{
#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(350,100,fontFindLangString(STR_NOTFORMATTED));
				TEXTPRINTAT(350,120,fontFindLangString(STR_NOTFORMATTED+1));
#else
				TEXTPRINTAT(350,100,"NOT");
				TEXTPRINTAT(350,120,"FORMATTED");
#endif
			}
			else
			{
				//no card - make sure we ask to format next one (if necessary) 

				dontFormat1=0;

#ifdef MULTI_LANGUAGE
				TEXTPRINTAT(350,50,fontFindLangString(STR_NOCARD));
				TEXTPRINTAT(350,70,fontFindLangString(STR_NOCARD+1));
				TEXTPRINTAT(350,90,fontFindLangString(STR_NOCARD+2));
				TEXTPRINTAT(350,110,fontFindLangString(STR_NOCARD+3));
				TEXTPRINTAT(350,130,fontFindLangString(STR_NOCARD+4));
				TEXTPRINTAT(350,150,fontFindLangString(STR_NOCARD+6));	// other card
#else
				TEXTPRINTAT(350,50,"NO");
				TEXTPRINTAT(350,70,"MEMORY");
				TEXTPRINTAT(350,90,"CARD IN");
				TEXTPRINTAT(350,110,"MEMORY");
				TEXTPRINTAT(350,130,"CARD SLOT");
				TEXTPRINTAT(350,150,"2");
#endif
			}
		}

		if(yesno_enabled && !card_data->exitFlag)
		{
			unsigned int rgb,rgb1;

			if(card_data->loadGame == LOADSAVE_FORMATCHECK)
			{
				SETRGBC(rgb,150+(rsin(((menuFrame*100) MOD 4096)+1024)/82),100,0,FULLALPHA);
				SETRGBC(rgb1,75+(rsin((menuFrame*100) MOD 4096)/82),60,0,FULLALPHA);
			}
			else
			{
				SETRGBC(rgb,0,150+(rsin(((menuFrame*100) MOD 4096)+1024)/82),200,FULLALPHA);
				SETRGBC(rgb1,0,75+(rsin((menuFrame*100) MOD 4096)/82),200,FULLALPHA);
			}

			if(debounce[0] & PAD_LEFT ||(nleftx[0]<-100))
			{
				yesno_value = 0;
			}

			if(debounce[0] & PAD_RIGHT||(nleftx[0]>100))
			{
				yesno_value = 1;
			}

			switch(yesno_value)
			{
			case 1:
				yesText->flags |= TEXT_ANIMATED;
				yesText->font=fontList[0];
				*(unsigned int *)(&yesText->r) = rgb;
				*(unsigned int *)(&yesText->r1) = rgb1;

				noText->flags &= ~TEXT_ANIMATED;
				noText->font=fontList[1];
				SETRGBC(noText->r,128,128,0,FULLALPHA);
				SETRGBC(noText->r1,128,40,8,FULLALPHA);

				break;
			default:
			case 0:
				yesText->flags &= ~TEXT_ANIMATED;
				yesText->font=fontList[1];
				SETRGBC(yesText->r,128,128,0,FULLALPHA);
				SETRGBC(yesText->r1,128,40,8,FULLALPHA);

				noText->flags |= TEXT_ANIMATED;
				noText->font=fontList[0];
				*(unsigned int *)(&noText->r) = rgb;
				*(unsigned int *)(&noText->r1) = rgb1;

				break;
			}
		}

		//show any error messages
		if(error)
		{
			SETRGBC(errorText->r,0,150+(rsin(((menuFrame*100) MOD 4096)+1024)/82),200,FULLALPHA);
			SETRGBC(errorText->r1,0,75+(rsin((menuFrame*100) MOD 4096)/82),200,FULLALPHA);
	
			globText->message[0]=0;
			
		}
		else
			errorText->message[0]=0; //don't show error text if no error!

		menuFrame++; //increment frame counter


		End_Loop(framerate);
	}
	return (card_data->exitFlag == EXITFLAG_OK);
}

/*	--------------------------------------------------------------------------------
	Function 	: backDisplay
	Purpose 	: Displays something moving
	Parameters 	: none
	Returns 	: none
	Info 		: 
	--------------------------------------------------------------------------------*/
void	backDisplay(long	angle)
{
	POLY_G4 *si = (POLY_G4 *) GsOUT_PACKET_P; 
	register	GsOTA 	*otptr=(GsOTA*)(PolyList->org+MAXPOLYDEPTH);

  	if (TOOMANYPOLYS(sizeof(POLY_G4),"CLEAR SCREEN"))return;

	SETRGBC(si->r0, 127, 0, 0, GPU_COM_G4);
	SETRGBC(si->r1, 0, 0, 127, GPU_COM_G4);
	SETRGBC(si->r2, 0, 127, 0,GPU_COM_G4);
	SETRGBC(si->r3, 0, 0, 0,GPU_COM_G4);
	
/*	si->x0=si->x2=0-320;
	si->x1=si->x3=640-320;
	si->y0=si->y1=0-120-PALMODE*8;
	si->y2=si->y3=240+(PALMODE*8)-120;
*/
	si->x0=(rsin( (angle&4095) )*160)/4096;
	si->y0=(rcos( (angle&4095) )*160)/4096;

	si->x1=(rsin( ((angle+1024)&4095) )*160)/4096;
	si->y1=(rcos( ((angle+1024)&4095) )*160)/4096;

	si->x3=(rsin( ((angle+2048)&4095) )*160)/4096;
	si->y3=(rcos( ((angle+2048)&4095) )*160)/4096;

	si->x2=(rsin( ((angle+3072)&4095) )*160)/4096;
	si->y2=(rcos( ((angle+3072)&4095) )*160)/4096;

 	PUTPACKETINTABLE(si,otptr,POLYG4_LEN);
	GsOUT_PACKET_P+=sizeof(POLY_G4);

}



/*	--------------------------------------------------------------------------------
	Function 	: MemCardDisplay
	Purpose 	: Displays back picture
	Parameters 	: none
	Returns 	: none
	Info 		: 
	--------------------------------------------------------------------------------*/


void	MemCardDisplay(void)
{
	POLY_G4 *si = (POLY_G4 *) GsOUT_PACKET_P; 
	register	GsOTA 	*otptr=(GsOTA*)(PolyList->org+MAXPOLYDEPTH);

  	if (TOOMANYPOLYS(sizeof(POLY_G4),"CLEAR SCREEN"))return;

	SETRGBC(si->r0, 127, 0, 0, GPU_COM_G4);
	SETRGBC(si->r1, 0, 0, 127, GPU_COM_G4);
	SETRGBC(si->r2, 0, 127, 0,GPU_COM_G4);
	SETRGBC(si->r3, 0, 0, 0,GPU_COM_G4);
	
	si->x0=si->x2=0-320;
	si->x1=si->x3=640-320;
	si->y0=si->y1=0-120-PALMODE*8;
	si->y2=si->y3=240+(PALMODE*8)-120;
 	PUTPACKETINTABLE(si,otptr,POLYG4_LEN);
	GsOUT_PACKET_P+=sizeof(POLY_G4);

}


void	drawLine(long x1,long y1,long x2,long y2)
{
	POLY_G4 *si = (POLY_G4 *) GsOUT_PACKET_P; 
	register	GsOTA 	*otptr=(GsOTA*)(PolyList->org+MAXPOLYDEPTH);
//	register	GsOTA 	*otptr=(0);

  	if (TOOMANYPOLYS(sizeof(POLY_G4),"CLEAR SCREEN"))return;

	SETRGBC(si->r0, 128, 128, 128, GPU_COM_G4);
	SETRGBC(si->r1, 128, 128, 128, GPU_COM_G4);
	SETRGBC(si->r2, 128, 128, 128, GPU_COM_G4);
	SETRGBC(si->r3, 128, 128, 128, GPU_COM_G4);
	
	si->x0=x2;
	si->x1=x2+1;

	si->x2=x1;
	si->x3=x1+1;

	si->y0=y2;
	si->y1=y2+1;

	si->y2=y1;
	si->y3=y1+1;


  	otptr=(GsOTA*)(PolyList->org+((0 & MAXDEPTH)>>(PolyList->shift)));
 	PUTPACKETINTABLE(si,otptr,POLYG4_LEN);
	GsOUT_PACKET_P+=sizeof(POLY_G4);
}

void	drawLineRGB(long x1,long y1,long x2,long y2,UBYTE r,UBYTE g, UBYTE b,UBYTE thickness)
{
	POLY_G4 *si = (POLY_G4 *) GsOUT_PACKET_P; 
	register	GsOTA 	*otptr=(GsOTA*)(PolyList->org+MAXPOLYDEPTH);
//	register	GsOTA 	*otptr=(0);

  	if (TOOMANYPOLYS(sizeof(POLY_G4),"CLEAR SCREEN"))return;

	SETRGBC(si->r0, r, g, b, GPU_COM_G4);
	SETRGBC(si->r1, r, g, b, GPU_COM_G4);
	SETRGBC(si->r2, r, g, b, GPU_COM_G4);
	SETRGBC(si->r3, r, g, b, GPU_COM_G4);
	
	si->x0=x2;
	si->x1=x2+thickness;

	si->x2=x1;
	si->x3=x1+thickness;

	si->y0=y2;
	si->y1=y2+thickness;

	si->y2=y1;
	si->y3=y1+thickness;


  	otptr=(GsOTA*)(PolyList->org+((0 & MAXDEPTH)>>(PolyList->shift)));
 	PUTPACKETINTABLE(si,otptr,POLYG4_LEN);
	GsOUT_PACKET_P+=sizeof(POLY_G4);
}