#include <XBApp.h>
#include <XBFont.h>
#include <XBHelp.h>
#include <xgraphics.h>
#include <assert.h>
#include <d3d8perf.h>
#include "SndXBOX.hxx"
#include <stdio.h>
#include <vector>
#include "zlib.h"
#include "unzip.h"
#include "debugclient.h"



#ifdef __cplusplus
extern "C" {
#endif

char *g_sramfile ;
char *g_statefile ;

#include "types.h"
#include "video.h"
#include "fce.h"
#include "svga.h"
#include "sound.h"
#include "state.h"
#include "fds.h"



char global_error_message[1024] ;

#ifdef __cplusplus
}
#endif

//WCHAR g_buf[1024];
// constants for controller dead zone / speed up banding etc.
const float GAMESEL_cfDeadZone = 0.3f;
const float GAMESEL_cfMaxThresh = 0.93f;
const float GAMESEL_cfMaxPossible = 1.0f;
const float GAMESEL_cfRectifyScale = GAMESEL_cfMaxPossible/(GAMESEL_cfMaxPossible-GAMESEL_cfDeadZone);
const float GAMESEL_cfSpeedBandFastest = 3.0f;	// seconds (don`t worry for PAL NTSC dif xbapp handles that)
const float GAMESEL_cfFastestScrollMult = 10.0f;
const float GAMESEL_cfSpeedBandMedium = 2.0f;	// if the pad is held at max for given seconds list will move faster
const float GAMESEL_cfMediumScrollMult = 5.0f;
const float GAMESEL_cfSpeedBandLowest = 1.0f;
const float GAMESEL_cfLowestScrollMult = 2.0f;


#define IN_GAME						0
#define IN_GAME_PAUSED				1
#define MAIN_MENU					2
#define INIT_SYSTEM					3
#define INIT_SYSTEM_SHOW_SCREEN     4

#define NAMES_PER_PAGE 25
#define MAX_RESIST 1000000.0


#define CONSOLE_MEMORY_SIZE 0x800


//-----------------------------------------------------------------------------
// Callouts for labelling the gamepad on the help screen
//-----------------------------------------------------------------------------
XBHELP_CALLOUT g_HelpCallouts[] = 
{
    { XBHELP_BACK_BUTTON,  XBHELP_PLACEMENT_2, L"Display help" },
    { XBHELP_A_BUTTON,     XBHELP_PLACEMENT_1, L"Play video" },
    { XBHELP_B_BUTTON,     XBHELP_PLACEMENT_1, L"Stop playback" },
};

#define NUM_HELP_CALLOUTS ( sizeof( g_HelpCallouts ) / sizeof( g_HelpCallouts[0] ) )

SoundXBOX *g_sound ;
float     *g_apptime ;
UINT32    *g_numframes ;
DWORD     g_dwStartTime ;
DWORD     g_dwTimePaused ;

//-----------------------------------------------------------------------------
// Name: class CXBoxSample
// Desc: Main class to run this application. Most functionality is inherited
//       from the CXBApplication base class.
//-----------------------------------------------------------------------------
class CXBoxSample : public CXBApplication
{
public:
    CXBoxSample();

    virtual HRESULT Initialize();
    virtual HRESULT InitializeWithScreen();
    virtual HRESULT Render();
    virtual HRESULT FrameMove();
	virtual void MoveCursor() ;
	virtual void    initConsole( UINT32 idx) ;
	virtual void    cleanupConsole( ) ;
	virtual void    handleEvents() ;
	virtual int     init_texture() ;
	virtual int		init_white_texture();
	virtual int		render_to_texture() ;
	virtual void	FindAvailRoms() ;
	virtual void    doStartSearchMenu() ;
	virtual void    doCodeListMenu() ;
	virtual void    doAddFoundCodes() ;
	virtual void    doContinueSearchMenu() ;
	virtual void    doCheatMenu() ;
	virtual void    updateCheats() ;
	virtual void    doFontSize() ;
	virtual void    doHostGame() ;
	virtual void    doJoinGame() ;
	virtual void    doSaveConfig() ;
	virtual void    doScreenSize() ;
	virtual void    doTextOffset() ;
	virtual void    doConfiguration() ;
	virtual void    processEmu( BOOL render ) ;
	virtual void    cht_load() ;
	virtual void    cht_save() ;
	virtual void    deleteSaveFiles( int which ) ;
	virtual void    doEditCode( int which ) ;
	virtual BOOL    hasFiles( int which ) ;
	virtual int     rom_load_zip() ;
	virtual void    GetPalette(uint8 i, uint8 *r, uint8 *g, uint8 *b);
	virtual void    SetPalette(uint8 index, uint8 r, uint8 g, uint8 b);
	virtual void    QuickSort( int start, int end ) ;
	void			MenuBar( int xpos, int ypos, int xlen, int ylen ) ;
	virtual void	processNetplay();
	

	float fGameSelect;
	float fCursorPos;
	float m_fFrameTime ;
	float fMaxCount;
	int   iGameSelect;
	int   iCursorPos;
	UINT32 m_numFrames ;


	UINT32 topIdx  ;
	UINT32 curr  ;

    CXBFont     m_Font;             // Font object
    CXBFont     m_FontSmall;             // Font object
    CXBHelp     m_Help;             // Help object
    BOOL        m_bDrawHelp;        // TRUE to draw help screen

	CDebugClient m_debugClient ;

    LPDIRECTSOUND8      m_pDSound;      // DirectSound object
    DWORD               m_dwCurrent;    // Current surface
	D3DPalette			*m_pd3dPalette ;
	DWORD				m_dwDroppedFrames ;
	int		m_nXOffset, m_nFontHeight ;
	int		m_namesPerPage ;
	int m_nScreenX ;
	int m_nScreenY ;
	int m_nScreenMaxX ;
	int m_nScreenMaxY ;
	int					m_lastPadValues[2] ;
	BOOL				m_bAmServer ;
	BOOL				m_bNetplay ;
	char                m_ipaddr[30] ;
	uint16				m_joyqueue[60] ;
	int					m_netbuflen ;
	int					m_netbufptr ;
	CDebugClient m_sockNetplay;
	CXBSocket m_sockListener ;

	byte *m_memBuf1, *m_memBuf2, *m_consoleMemory, *m_memMatches ;
	UINT32 m_currentMemMatches ;

	typedef struct _filenamestruct {
		WCHAR name[200] ;
		unsigned char filename[200] ;
	} FILENAME ;

	FILENAME *files ;
	unsigned long numfiles ;
	UINT32   m_iMaxWindowList;
	UINT32   m_iWindowMiddle ;
	UINT32   m_steps ;
	DWORD    m_dwStartPause ;

	LPDIRECT3DTEXTURE8	WhiteTexture;
	LPDIRECT3DTEXTURE8	Texture;
	LPD3DXSPRITE			Sprite;
	LPD3DXSPRITE			MenuSprite;
	byte*				g_pBlitBuff ;
	byte*				g_pAlignBuff ;
	D3DCOLOR			color_palette[256];
	int                 PaletteChanged ;	
	
	UINT32				m_state ;
    WCHAR      m_strMessage[80];
	UINT32              m_msgDelay ;
	uint16				m_joypadA ;
	uint16				m_joypadB ;

	SoundXBOX			m_sound;
	char				g_savePath[500] ;
	char				g_saveprefix[500] ;
	char				g_rtcfile[500] ;
	char				g_chtfile[500] ;
	char				g_stateFile[500] ;

// Indicates the width and height of the screen
	UINT32 theWidth;
	UINT32 theHeight;
    RECT SrcRect;
    RECT DestRect;

	typedef struct _cheat_code {
		char code[20] ;
		UINT32 adr ;
		UINT32 val ;
		byte   enabled ;
	} CHEAT_CODE;

	CHEAT_CODE *m_cheatCodes;

	UINT32 m_numCheats ;


};


CXBoxSample *g_app;

//-----------------------------------------------------------------------------
// Name: main()
// Desc: Entry point to the program.
//-----------------------------------------------------------------------------
VOID __cdecl main()
{
    CXBoxSample xbApp;

	//check for pal60 mode
	if(XGetVideoStandard() == XC_VIDEO_STANDARD_PAL_I)
	{
		//get supported video flags
		DWORD videoFlags = XGetVideoFlags();
		
		//set pal60 if available.
		if(videoFlags && XC_VIDEO_FLAGS_PAL_60Hz)
			xbApp.m_d3dpp.FullScreen_RefreshRateInHz = 60 ;
		else
			xbApp.m_d3dpp.FullScreen_RefreshRateInHz = 50 ;
	}

    if( FAILED( xbApp.Create() ) )
        return;
    xbApp.Run();
}



//-----------------------------------------------------------------------------
// Name: CXBoxSample (constructor)
// Desc: Constructor for CXBoxSample class
//-----------------------------------------------------------------------------
CXBoxSample::CXBoxSample() 
            :CXBApplication()
{
    m_bDrawHelp = FALSE;
	m_state = MAIN_MENU ;
	files = NULL ;
	global_error_message[0] = 0 ;
	g_sound = &m_sound ;
	g_apptime = &m_fAppTime ;
	g_numframes = &m_numFrames ;
	m_sound.m_ptrapp = this ;
	g_app = this ;
	g_sramfile = (char*)malloc(500) ;
	g_statefile = (char*)malloc(500) ;
}



int CXBoxSample::init_texture()
{
	D3DCOLOR *palette ;

	// Release any previous texture
	if (Texture) 
	{ 
		Texture->Release();
		Texture = NULL;
	}
	
	theWidth = 256 ;
	theHeight = 240 ;

	// Create the texture
	
	D3DXCreateTexture(m_pd3dDevice, theWidth, theHeight, 0, 0, D3DFMT_P8, D3DPOOL_DEFAULT, &Texture);
//	D3DXCreateTexture(m_pd3dDevice, theWidth, theHeight, 0, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &Texture);
//	D3DXCreateTexture(m_pd3dDevice, theWidth, theHeight, 0, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_DEFAULT, &Texture);
	
	D3DSURFACE_DESC desc;
    Texture->GetLevelDesc(0, &desc);

	if (g_pBlitBuff != NULL)
	{
		delete [] g_pBlitBuff;
		g_pBlitBuff = NULL;
	}
	
	// Allocate a buffer to blit our frames to
	g_pBlitBuff = new byte[desc.Size];

	XBuf = g_pBlitBuff ;


	if (g_pAlignBuff != NULL)
	{
		delete [] g_pAlignBuff;
		g_pAlignBuff = NULL;
	}
	
	// Allocate a buffer to blit our frames to
	g_pAlignBuff = new byte[desc.Size];

	
	RECT rectSource;
	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = theHeight-1 ;
	rectSource.right  = theWidth-1 ;

	D3DLOCKED_RECT d3dlr;
	Texture->LockRect(0, &d3dlr, &rectSource, 0);

	// Unlock our texture
	Texture->UnlockRect(0);

	m_pd3dDevice->CreatePalette( D3DPALETTE_256 , &m_pd3dPalette ) ;
	m_pd3dPalette->Lock( &palette, 0 ) ;
	memset( palette, 44, 256* sizeof( D3DCOLOR ) ) ;
	m_pd3dPalette->Unlock() ;

	m_pd3dDevice->SetPalette( 0, m_pd3dPalette ) ;

	return 0;
}


//-----------------------------------------------------------------------------
// Name: Initialize
// Desc: Peforms initialization
//-----------------------------------------------------------------------------
HRESULT CXBoxSample::Initialize()
{
    // Create a font
    if( FAILED( m_Font.Create( m_pd3dDevice, "Font.xpr" ) ) )
        return XBAPPERR_MEDIANOTFOUND;

    // Create a font
    if( FAILED( m_FontSmall.Create( m_pd3dDevice, "Font12.xpr" ) ) )
        return XBAPPERR_MEDIANOTFOUND;

    // Create DirectSound
    if( FAILED( DirectSoundCreate( NULL, &(m_sound.dsound),  NULL ) ) )
        return E_FAIL;

	if ( ( XCreateSaveGame( "U:\\", L"NESSAV", OPEN_ALWAYS, 0, g_savePath, 500 ) ) != ERROR_SUCCESS )
        return E_FAIL;

	m_sound.dsound_init() ;

	m_sound.m_fps = m_d3dpp.FullScreen_RefreshRateInHz ;

	m_state = INIT_SYSTEM ;

	return S_OK ;
}

HRESULT CXBoxSample::InitializeWithScreen()
{
	FILE *inifile ;
	char initext[100] ;
	char *fpos, *epos ;
	int numread ;

	m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
						 0x00000000, 1.0f, 0L );
	RenderGradientBackground( 0xFF000000, 0xFF000000 );
	m_Font.Begin();
	m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Reading nesroms directory...please wait." ) ;
	m_Font.End();
	m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

	if ( m_sockNetplay.Init( ) == 0 )
	{
	}
	m_bNetplay = FALSE ;
	strcpy( m_ipaddr, "0.0.0.0" ) ;

    m_sockListener.Open( CXBSocket::Type_TCP );
    CXBSockAddr directAddr( INADDR_ANY, 8989 );
    INT iResult = m_sockListener.Bind( directAddr.GetPtr() );

	if ( iResult == SOCKET_ERROR )
	{
		return 0;
	}

    iResult = m_sockListener.Listen( 1 ) ;

	if ( iResult == SOCKET_ERROR )
	{
		return 0;
	}

	DWORD dwNonBlocking = 1 ;
	iResult = m_sockListener.IoCtlSocket( FIONBIO, &dwNonBlocking );

	m_netbuflen = 5 ;

	/*
	if ( m_debugClient.Init( "192.168.123.99", 7654, 1 ) == 0 )
	{
		strcpy( global_error_message, "*debugclientinit" ) ;
		return 0 ;
	}
*/

	int *iparams[6] ;

	m_nXOffset = 0 ;
	m_nFontHeight = 12 ;
	m_nScreenX = 50 ;
	m_nScreenY = 50 ;
	m_nScreenMaxX = 600 ;
	m_nScreenMaxY = 400 ;

	iparams[0] = &m_nXOffset ;
	iparams[1] = &m_nFontHeight ;
	iparams[2] = &m_nScreenX ;
	iparams[3] = &m_nScreenY ;
	iparams[4] = &m_nScreenMaxX ;
	iparams[5] = &m_nScreenMaxY ;

	int paramnum ;
	paramnum =0 ;
	
	inifile = fopen( "D:\\fceu.ini", "r" ) ;

	if ( inifile != NULL )
	{
		numread = fread( initext, sizeof(char), 100, inifile ) ;
		fclose( inifile ) ;

		fpos = initext ;

		while ( ( paramnum < 6 ) && ( ( epos = strchr( fpos, ' ' ) ) != NULL )  )
		{
			*epos = 0 ;

			*iparams[paramnum] = atoi( fpos ) ;

			fpos = epos + 1 ;

			if ( fpos - initext > 99 )
				break ;
			paramnum++ ;
		}

	}

	if ( m_nFontHeight < 1 )
		m_nFontHeight = 12 ;


	m_namesPerPage =  (25*14 ) / ( m_nFontHeight+2) ;

	
	
	
	
	
	
	fGameSelect = 0.0f;
	iGameSelect = 0;
	fCursorPos = 0.0f;
	iCursorPos = 0;
	fMaxCount = 0.0f;
	curr = 0 ;
	topIdx = 0 ;
	numfiles = 0 ;

	m_msgDelay = 0 ;
	wcscpy( m_strMessage, L" " ) ;
	
	g_pBlitBuff = NULL ;
	g_pAlignBuff = NULL ;


	WhiteTexture = NULL ;
	Texture = NULL ;
	Sprite = NULL ;
	MenuSprite = NULL ;
	m_cheatCodes = NULL ;
	m_numCheats = 0 ;

	init_white_texture();
	
	
	
	g_saveprefix[0] = 0 ;

	FindAvailRoms() ;


	m_memBuf1 = (byte*)malloc( CONSOLE_MEMORY_SIZE ) ;
	m_memBuf2 = (byte*)malloc( CONSOLE_MEMORY_SIZE ) ;
	m_memMatches = (byte*)malloc( CONSOLE_MEMORY_SIZE ) ;
	m_consoleMemory = RAM  ; //need to declare in initconsole in case RAM is NULL at this point


//BEGIN ONE TIME



//END ONE TIME	
	
	
	m_state = MAIN_MENU ;

    return S_OK;
}




void CXBoxSample::doStartSearchMenu()
{

	//copyConsoleMemory( m_memBuf1, CONSOLE_MEMORY_SIZE ) ;
	memcpy( m_memBuf1, m_consoleMemory, CONSOLE_MEMORY_SIZE ) ;
	memset( m_memMatches, 1, CONSOLE_MEMORY_SIZE ) ;
	m_currentMemMatches = CONSOLE_MEMORY_SIZE ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();
		m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"The search has begun.  " );
		m_Font.DrawText(m_nXOffset+  32, 16*4, 0xFFffffff, L"Press B to go back to the Options menu." );
		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
		{
			break ;
		}
	}
}

void CXBoxSample::doEditCode( int which )
{
	CHEAT_CODE code ;
	int curr_pos ;
	int val1, val2 ;

	if ( which < 0 )
	{
		strcpy( code.code, "01000000" ) ;
		code.enabled = 1 ;
		code.adr = 0x0000 ;
		code.val = 0 ;
	}
	else
	{
		memcpy( &code, &(m_cheatCodes[which]), sizeof(CHEAT_CODE) ) ;
	}


	curr_pos = 0 ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();

		if ( which < 0 )
			m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Add New Cheat Code" );
		else
			m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Edit Cheat Code" );

		m_Font.DrawText(m_nXOffset+  32, 16*4, 0xFFffffff, L"Press B to cancel." );
		m_Font.DrawText(m_nXOffset+  32, 16*5, 0xFFffffff, L"Press A to save." );
		m_Font.DrawText(m_nXOffset+  32, 16*6, 0xFFffffff, L"Use DPAD to select/change values." );

		WCHAR str[200];

		for ( int i = 0 ; i < 8 ; i++ )
		{
			swprintf( str, L"%c", (code.code)[i] ) ;
			if ( i == curr_pos+2 )
				m_Font.DrawText(m_nXOffset+  50 + ( i * 16 ), 16*9, 0xFF00FF00, str ) ;
			else
				m_Font.DrawText(m_nXOffset+  50 + ( i * 16 ), 16*9, 0xFFffffff, str ) ;
		}

		swprintf( str, L"Address : %04.4X", code.adr ) ;
		m_Font.DrawText(m_nXOffset+  50 , 16*11, 0xFFffffff, str ) ;
		swprintf( str, L"Value : %u", code.val ) ;
		m_Font.DrawText(m_nXOffset+  50 , 16*12, 0xFFffffff, str ) ;
		
		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
		{
			break ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_A ] ) 
		{
			if ( ( code.adr > 0x07FF ) )
			{
				while ( 1 )
				{
					m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
										 0x00000000, 1.0f, 0L );
					RenderGradientBackground( 0xFF000000, 0xFF000000 );

					m_Font.Begin();
					m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"The Address must be between 0x0000 and 0x07FF" );
					m_Font.DrawText(m_nXOffset+  32, 16*4, 0xFFffffff, L"Press B to try again." );
					m_Font.End();

					m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

					XBInput_GetInput();
					if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
					{
						break ;
					}
				}
			}
			else
			{
				if ( which < 0 )
				{
					m_cheatCodes = (CHEAT_CODE*)realloc( m_cheatCodes, sizeof(CHEAT_CODE) * ( m_numCheats  + 1 ) ) ;
					memcpy( &(m_cheatCodes[m_numCheats]),&code, sizeof(CHEAT_CODE) ) ;
					m_numCheats++ ;
				}
				else
				{
					memcpy( &(m_cheatCodes[which]), &code, sizeof(CHEAT_CODE) ) ;
				}
				break ;
			}
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			switch ( curr_pos )
			{
				case 0 :
				{
					if ( ( ( code.val >> 4 ) &  0x0F ) == 0 )
						code.val = 0xF0 + ( code.val & 0x0F ) ;
					else
						code.val = ( code.val - 0x10 ) & 0xFF ;
					break ;
				}
				case 1 :
				{
					if ( ( code.val & 0x0F ) == 0x00 )
						code.val = 0x0F + ( code.val & 0xF0 ) ;
					else
						code.val = ( code.val - 0x01 ) & 0xFF ;
					break ;
				}
				case 2 :
				{
					if ( ( ( code.adr >> 4 ) &  0x0F ) == 0 )
						code.adr = 0xF0 + ( code.adr & 0xFF0F ) ;
					else
						code.adr = ( code.adr - 0x10 ) & 0xFFFF ;
					break ;
				}
				case 3 :
				{
					if ( ( ( code.adr ) &  0x0F ) == 0 )
						code.adr = 0x0F + ( code.adr & 0xFFF0 ) ;
					else
						code.adr = ( code.adr - 0x01 ) & 0xFFFF ;
					break ;
				}
				case 4 :
				{
					if ( ( ( code.adr >> 12 ) &  0x0F ) == 0 )
						code.adr = 0xF000 + ( code.adr & 0x0FFF ) ;
					else
						code.adr = ( code.adr - 0x1000 ) & 0xFFFF ;
					break ;
				}
				case 5 :
				{
					if ( ( ( code.adr >> 8 ) &  0x0F ) == 0 )
						code.adr = 0x0F00 + ( code.adr & 0xF0FF ) ;
					else
						code.adr = ( code.adr - 0x100 ) & 0xFFFF ;
					break ;
				}
				default : break ;
			}
			sprintf( code.code, "01%02.2X%02.2X%02.2X", code.val, code.adr & 0xFF, (code.adr >> 8 ) & 0xFF ) ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			switch ( curr_pos )
			{
				case 0 :
				{
					if ( ( ( code.val >> 4 ) &  0x0F ) == 0x0F )
						code.val = 0x00 + ( code.val & 0x0F ) ;
					else
						code.val = ( code.val + 0x10 ) & 0xFF ;
					break ;
				}
				case 1 :
				{
					if ( ( code.val & 0x0F ) == 0x0F )
						code.val = 0x00 + ( code.val & 0xF0 ) ;
					else
						code.val = ( code.val + 0x01 ) & 0xFF ;
					break ;
				}
				case 2 :
				{
					if ( ( ( code.adr >> 4 ) &  0x0F ) == 0x0F )
						code.adr = 0x00 + ( code.adr & 0xFF0F ) ;
					else
						code.adr = ( code.adr + 0x10 ) & 0xFFFF ;
					break ;
				}
				case 3 :
				{
					if ( ( ( code.adr ) &  0x0F ) == 0x0F )
						code.adr = 0x00 + ( code.adr & 0xFFF0 ) ;
					else
						code.adr = ( code.adr + 0x01 ) & 0xFFFF ;
					break ;
				}
				case 4 :
				{
					if ( ( ( code.adr >> 12 ) &  0x0F ) == 0x0F )
						code.adr = 0x0000 + ( code.adr & 0x0FFF ) ;
					else
						code.adr = ( code.adr + 0x1000 ) & 0xFFFF ;
					break ;
				}
				case 5 :
				{
					if ( ( ( code.adr >> 8 ) &  0x0F ) == 0x0F )
						code.adr = 0x0000 + ( code.adr & 0xF0FF ) ;
					else
						code.adr = ( code.adr + 0x100 ) & 0xFFFF ;
					break ;
				}
				default : break ;
			}
			sprintf( code.code, "01%02.2X%02.2X%02.2X", code.val, code.adr & 0xFF, (code.adr >> 8 ) & 0xFF ) ;

		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		{
			if ( curr_pos == 0 )
				curr_pos = 5 ;
			else
				curr_pos-- ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		{
			if ( curr_pos == 5 )
				curr_pos = 0 ;
			else
				curr_pos++ ;
		}
	}


}

void CXBoxSample::doCodeListMenu()
{

	int selected  ;
	int cheatTopIdx ;
	WCHAR str[400];
	CHEAT_CODE *tempbuf ;

	selected = cheatTopIdx = 0 ;

	if ( m_numCheats == 0 )
	{
		while ( 1 )
		{
			m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
								 0x00000000, 1.0f, 0L );
			RenderGradientBackground( 0xFF000000, 0xFF000000 );

			m_Font.Begin();
			m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Search Code List" );
			m_Font.DrawText(m_nXOffset+  32, 16*4, 0xFFffffff, L"Press B to go back to the Options menu." );
			m_Font.DrawText(m_nXOffset+  32, 16*6, 0xFFffffff, L"There are no cheat codes in the list." ) ;

			m_Font.End();

			m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

			XBInput_GetInput();
			if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
			{
				return ;
			}
		}
	}
	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();
		m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Search Code List" );
		m_Font.DrawText(m_nXOffset+  32, 16*4, 0xFFffffff, L"Press B to go back to the Options menu." );
		m_Font.DrawText(m_nXOffset+  32, 16*5, 0xFFffffff, L"Press A to add a new code." );
		m_Font.DrawText(m_nXOffset+  32, 16*6, 0xFFffffff, L"Press X to edit the selected code." );
		m_Font.DrawText(m_nXOffset+  32, 16*7, 0xFFffffff, L"Press Y to enable/disable the selected code." );
		m_Font.DrawText(m_nXOffset+  32, 16*8, 0xFFffffff, L"Press BLACK to delete the selected code." );
		m_Font.DrawText(m_nXOffset+  32, 16*9, 0xFFffffff, L"Press UP/DOWN/LS/RS to select code." );

		MenuBar( m_nXOffset+32, 16*(11+selected) + 3, 600, 19 ) ;

		for ( unsigned int idx = cheatTopIdx ; ( idx < m_numCheats ) && ( idx < cheatTopIdx+10) ; idx++ )
		{
			CHEAT_CODE *code = &(m_cheatCodes[idx]) ;

			swprintf( str, L"%S Adr:0x%04.4X val:%u %S", code->code, code->adr, code->val, code->enabled ? "ON" : "OFF" ) ;
			
			if ( selected == idx )
				m_Font.DrawText(m_nXOffset+32, 16*(11+idx), 0xff000000, str );
			else
				m_Font.DrawText(m_nXOffset+32, 16*(11+idx), 0xFFffffff, str );
		}
		
		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			break ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_A])
		{
			doEditCode( -1 ) ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_X])
		{
			doEditCode( selected ) ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			if ( m_cheatCodes[selected].enabled )
				m_cheatCodes[selected].enabled = 0 ;
			else
				m_cheatCodes[selected].enabled = 1 ;
		}
		else if (g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK]) 
		{
			tempbuf = (CHEAT_CODE*)malloc( sizeof(CHEAT_CODE) * ( m_numCheats - 1 ) ) ;

			memcpy( tempbuf, m_cheatCodes, sizeof(CHEAT_CODE) * selected ) ;

			if ( selected < m_numCheats-1 )
			{
				memcpy( &(tempbuf[selected]), &(m_cheatCodes[selected+1]), sizeof(CHEAT_CODE) * ( (m_numCheats - selected ) - 1) ) ;
			}

			free( m_cheatCodes ) ;

			m_cheatCodes = tempbuf ;
			m_numCheats-- ;
			if ( m_numCheats == 0 )
				break ;

			if ( selected >= (m_numCheats) )
				selected = m_numCheats - 1 ;

		}
		if (g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER])
		{
			if ( cheatTopIdx + 10 < m_numCheats )
			{
				cheatTopIdx += 10 ;
				selected = cheatTopIdx ;
			}
		}
		else if (g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER])
		{
			if ( cheatTopIdx >= 10 )
			{
				cheatTopIdx -= 10 ;
				selected = cheatTopIdx ;
			}
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			if ( selected == cheatTopIdx + (10-1) )
			{
				if ( selected < m_numCheats - 1 )
				{
					cheatTopIdx++ ;
					selected++ ;
				}
			}
			else
			{
				if ( selected < m_numCheats-1 )
					selected++ ;
			}
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			if ( selected == cheatTopIdx )
			{
				if ( selected > 0 )
				{
					cheatTopIdx-- ;
					selected-- ;
				}
			}
			else
			{
				if ( selected > 0 )
					selected-- ;
			}
		}

		
		
		
		
	}
}

void CXBoxSample::doAddFoundCodes()
{
	CHEAT_CODE code ;

	for ( int i = 0 ; i < CONSOLE_MEMORY_SIZE ; i++ )
	{
		if ( m_memMatches[i] )
		{
			code.adr = i ;
			code.val = m_memBuf1[i] ;
			code.enabled = 0 ;
			sprintf( code.code, "01%02.2X%02.2X%02.2X", code.val, code.adr & 0xFF, (code.adr >> 8 ) & 0xFF ) ;

			m_cheatCodes = (CHEAT_CODE*)realloc( m_cheatCodes, sizeof(CHEAT_CODE) * ( m_numCheats  + 1 ) ) ;

			memcpy( &(m_cheatCodes[m_numCheats]),&code, sizeof(CHEAT_CODE) ) ;
			m_numCheats++ ;

		}
	}

	memset( m_memMatches, 0, CONSOLE_MEMORY_SIZE ) ;
	m_currentMemMatches = 0 ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();
		m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"The search found 1 to 4 possible matches for your search." );
		m_Font.DrawText(m_nXOffset+  32, 16*3, 0xFFffffff, L"They have been added to your list." );
		m_Font.DrawText(m_nXOffset+  32, 16*5, 0xFFffffff, L"Press B to go back to the Options menu." );
		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			break ;
		}
	}
}

void CXBoxSample::doContinueSearchMenu()
{

	WCHAR str[200];
	int value ;

	//copyConsoleMemory( m_memBuf2, CONSOLE_MEMORY_SIZE ) ;
	memcpy( m_memBuf2, m_consoleMemory, CONSOLE_MEMORY_SIZE ) ;
	value = 0 ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();
		m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Search Options" );
		m_Font.DrawText(m_nXOffset+  32, 16*4, 0xFFffffff, L"Press B to go back to the Options menu." );

		swprintf( str, L"Press X to search for this value : %u", value );
		m_Font.DrawText(m_nXOffset+  32, 16*5, 0xFFffffff, str );

		m_Font.DrawText(m_nXOffset+  32, 16*6, 0xFFffffff, L"Press Y to search for values less than before." );
		m_Font.DrawText(m_nXOffset+  32, 16*7, 0xFFffffff, L"Press A to search for values greater than before." );
		m_Font.DrawText(m_nXOffset+  32, 16*8, 0xFFffffff, L"Press BLACK to search for values equal to before." );
		m_Font.DrawText(m_nXOffset+  32, 16*9, 0xFFffffff, L"Press WHITE to search for values not equal to before." );
		m_Font.DrawText(m_nXOffset+  32, 16*10, 0xFFffffff, L"Press DPAD-UP to add 1 to the value" ) ;
		m_Font.DrawText(m_nXOffset+  32, 16*11, 0xFFffffff, L"Press DPAD-DOWN to subtract 1 from the value" ) ;
		m_Font.DrawText(m_nXOffset+  32, 16*12, 0xFFffffff, L"Press DPAD-RIGHT to add 10 to the value" ) ;
		m_Font.DrawText(m_nXOffset+  32, 16*13, 0xFFffffff, L"Press DPAD-LEFT to subtract 10 from the value" ) ;
		m_Font.DrawText(m_nXOffset+  32, 16*14, 0xFFffffff, L"Press LS+RS to add the found codes to your list" ) ;

		swprintf( str, L"Number of hits from last search : %u", m_currentMemMatches );
		m_Font.DrawText(m_nXOffset+  32, 16*16, 0xFFffffff, str );

		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			break ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_A])
		{
			m_currentMemMatches = 0 ;
			for ( int i = 0 ; i < CONSOLE_MEMORY_SIZE ; i++ )
			{
				if ( m_memMatches[i] )
					if ( m_memBuf1[i] < m_memBuf2[i] )
					{
						m_memMatches[i] = 1 ;
						m_currentMemMatches++ ;
					}
					else
						m_memMatches[i] = 0 ;
			}

			if ( m_currentMemMatches == 1 )
			{
				doAddFoundCodes() ;
				break ;
			}
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_X])
		{
			m_currentMemMatches = 0 ;
			for ( int i = 0 ; i < CONSOLE_MEMORY_SIZE ; i++ )
			{
				if ( m_memMatches[i] )
					if ( m_memBuf2[i] == value )
					{
						m_memMatches[i] = 1 ;
						m_currentMemMatches++ ;
					}
					else
						m_memMatches[i] = 0 ;
			}
			if ( m_currentMemMatches == 1 )
			{
				doAddFoundCodes() ;
				break ;
			}
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			m_currentMemMatches = 0 ;
			for ( int i = 0 ; i < CONSOLE_MEMORY_SIZE ; i++ )
			{
				if ( m_memMatches[i] )
					if ( m_memBuf1[i] > m_memBuf2[i] )
					{
						m_memMatches[i] = 1 ;
						m_currentMemMatches++ ;
					}
					else
						m_memMatches[i] = 0 ;
			}
			if ( m_currentMemMatches == 1 )
			{
				doAddFoundCodes() ;
				break ;
			}
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK])
		{
			m_currentMemMatches = 0 ;
			for ( int i = 0 ; i < CONSOLE_MEMORY_SIZE ; i++ )
			{
				if ( m_memMatches[i] )
					if ( m_memBuf1[i] == m_memBuf2[i] )
					{
						m_memMatches[i] = 1 ;
						m_currentMemMatches++ ;
					}
					else
						m_memMatches[i] = 0 ;
			}
			if ( m_currentMemMatches == 1 )
			{
				doAddFoundCodes() ;
				break ;
			}
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE])
		{
			m_currentMemMatches = 0 ;
			for ( int i = 0 ; i < CONSOLE_MEMORY_SIZE ; i++ )
			{
				if ( m_memMatches[i] )
					if ( m_memBuf1[i] != m_memBuf2[i] )
					{
						m_memMatches[i] = 1 ;
						m_currentMemMatches++ ;
					}
					else
						m_memMatches[i] = 0 ;
			}
			if ( m_currentMemMatches == 1 )
			{
				doAddFoundCodes() ;
				break ;
			}
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			value = ( value - 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			value = ( value + 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		{
			value = ( value - 10 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		{
			value = ( value + 10  ) & 0xFF ;
		}
		else if ( (g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) && (g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER]) )
		{
			if ( ( m_currentMemMatches > 0 ) && ( m_currentMemMatches < 5 ) )
			{
				doAddFoundCodes() ;
				break ;
			}
			else
			{
				while ( 1 )
				{
					m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
										 0x00000000, 1.0f, 0L );
					RenderGradientBackground( 0xFF000000, 0xFF000000 );

					m_Font.Begin();
					m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"You can only add when you have narrowed " ) ;
					m_Font.DrawText(m_nXOffset+  32, 16*3, 0xFFffffff, L"it down to less than 5 matches." );
					m_Font.DrawText(m_nXOffset+  32, 16*5, 0xFFffffff, L"Press B to go back." );
					m_Font.End();

					m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

					XBInput_GetInput();
					if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
					{
						break ;
					}
				}
			}
		}
	}
	memcpy( m_memBuf1, m_memBuf2, CONSOLE_MEMORY_SIZE ) ;
}

void CXBoxSample::doCheatMenu()
{

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();
		m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"OPTIONS MENU" );
		m_Font.DrawText(m_nXOffset+  32, 16*4, 0xFFffffff, L"B - Return to Game" );
		m_Font.DrawText(m_nXOffset+  32, 16*5, 0xFFffffff, L"START+BACK - Quit Game" );
		m_Font.DrawText(m_nXOffset+  32, 16*6, 0xFFffffff, L"BLACK - Start Search for Cheat Code" );
		m_Font.DrawText(m_nXOffset+  32, 16*7, 0xFFffffff, L"A - Continue Cheat Search" );
		m_Font.DrawText(m_nXOffset+  32, 16*8, 0xFFffffff, L"RS+LS - Cheat Code List" );
		m_Font.DrawText( m_nXOffset+  32, 16*9, 0xffffffff, L"X - Host a network game" );
		m_Font.DrawText( m_nXOffset+  32, 16*10, 0xffffffff, L"Y - Join a network game" );
		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

		if ( m_bNetplay)
		{
			processNetplay() ;
			if ( m_state == IN_GAME )
			{

				if ( m_bAmServer )
				{
					uint16 val2 ;
					char ipaddr[30] ;

					val2 = 0 ;
					strcpy(ipaddr, "J" ) ;
					memcpy( ipaddr+1, &val2, sizeof(val2) ) ;

					char buflen ;

					buflen = m_netbuflen ;

					m_sockNetplay.Send( &buflen, 1 ) ;

					for ( int i = 0 ; i < m_netbuflen ; i++ )
					{
						m_sockNetplay.Send( ipaddr, 1+sizeof(val2) ) ;
						m_joyqueue[i] = val2 ;
					}

					m_netbufptr = 0 ;
				}
				else
				{
					char buflen ;
					int val2 ;

					while ( m_sockNetplay.Recv( &buflen, 1 ) <= 0 ) ; //empty loop


					m_netbuflen = buflen ;

					val2 = 0 ;

					//strcpy(ipaddr, "J" ) ;
					//memcpy( ipaddr+1, &val2, sizeof(val2) ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;

					for ( int i = 0 ; i < m_netbuflen ; i++ )
						m_joyqueue[i] = val2 ;

					m_netbufptr = 0 ;
				}
				
				
				
				m_sound.pause( FALSE ) ;
				break ;
			}
		}

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			m_sound.pause( FALSE ) ;
			m_state = IN_GAME ;

			if ( m_bNetplay )
			{
				m_sockNetplay.Send( "U", 1 ) ;

				if ( m_bAmServer )
				{
					int val2 ;
					char ipaddr[30] ;

					val2 = 0 ;
					strcpy(ipaddr, "J" ) ;
					memcpy( ipaddr+1, &val2, sizeof(val2) ) ;

					char buflen ;

					buflen = m_netbuflen ;

					m_sockNetplay.Send( &buflen, 1 ) ;

					for ( int i = 0 ; i < m_netbuflen ; i++ )
					{
						m_sockNetplay.Send( ipaddr, 1+sizeof(val2) ) ;
						m_joyqueue[i] = val2 ;
					}

					m_netbufptr = 0 ;
				}
				else
				{
					char buflen ;
					int val2 ;

					while ( m_sockNetplay.Recv( &buflen, 1 ) <= 0 ) ; //empty loop


					m_netbuflen = buflen ;

					val2 = 0 ;

					//strcpy(ipaddr, "J" ) ;
					//memcpy( ipaddr+1, &val2, sizeof(val2) ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;
					//m_sockNetplay.Send( ipaddr, 5 ) ;

					for ( int i = 0 ; i < m_netbuflen ; i++ )
						m_joyqueue[i] = val2 ;

					m_netbufptr = 0 ;
				}

			}
			
			break ;
		}
		else if ( ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_START )  &&
			      ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_BACK )  )
		{
			m_sound.cleanup() ;
			cleanupConsole() ;
			m_state = MAIN_MENU ;
			break ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_A])
		{
			doContinueSearchMenu() ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK])
		{
			doStartSearchMenu() ;
		}
		else if ( (g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) && (g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER]) )
		{
			doCodeListMenu() ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_X])
		{
			doHostGame() ;
			if ( m_state == IN_GAME )
			{
				m_sound.pause( FALSE ) ;
				break ;
			}
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			doJoinGame() ;

			if ( m_state == IN_GAME )
			{
				m_sound.pause( FALSE ) ;
				break ;
			}
		}


	}

}


//-----------------------------------------------------------------------------
// Name: FrameMove
// Desc: Performs per-frame updates
//-----------------------------------------------------------------------------
HRESULT CXBoxSample::FrameMove()
{

	m_bPaused =  ( m_state != IN_GAME ) ;

	if ( m_state == IN_GAME )
	{
		if ( m_dwStartPause > 0 )
		{
			g_dwTimePaused += ( GetTickCount() - m_dwStartPause ) ;
			m_dwStartPause = 0;
		}

		if(m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			m_sound.pause( TRUE ) ;
			m_state = IN_GAME_PAUSED ;
			m_dwStartPause = GetTickCount();
			return S_OK ;
		}
	}
	else if ( m_state == MAIN_MENU )
	{
		if(m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_Y])
		{
		}
		else if ( ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_START )  &&
			      ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_BACK )  &&
				  ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER]) &&
				  ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) )
		{
			LD_LAUNCH_DASHBOARD LaunchData = { XLD_LAUNCH_DASHBOARD_MAIN_MENU };
			XLaunchNewImage( NULL, (LAUNCH_DATA*)&LaunchData );
		}
		else if ( (m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_X]) && (m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_B]) )
		{
			m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
								 0x00000000, 1.0f, 0L );
			RenderGradientBackground( 0xFF000000, 0xFF000000 );
			m_Font.Begin();
			m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Reloading game list..." ) ;
			m_Font.End();
			m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

			if ( numfiles > 0 )
			{
				delete [] files;
				files = NULL;
			}

			numfiles = 0 ;
			FindAvailRoms() ;
		}
		else if(m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_LEFT_THUMB )
		{
			doConfiguration() ;
			return S_OK ;
		}
		else
		{
			// check for cursor select movement and move
			MoveCursor();

			// check for selection of game and do something (anything!)
			if(m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_A])
			{
				m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
									 0x00000000, 1.0f, 0L );
				RenderGradientBackground( 0xFF000000, 0xFF000000 );
				m_Font.Begin();
				m_Font.DrawText(m_nXOffset+  32, 16*2, 0xFFffffff, L"Loading game...please wait." ) ;
				m_Font.End();
				m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
				initConsole(curr) ;
				m_state = IN_GAME ;
				return S_OK ;
			}
		}
	}
	else if ( m_state == IN_GAME_PAUSED )
	{
		m_sound.pause( TRUE ) ;
		m_bPaused =  TRUE ;
		doCheatMenu() ;

		return S_OK ;
	}
	else
	{
	}

    return S_OK;
}


int CXBoxSample::render_to_texture()
{
	RECT src, dst;
	byte *curr1, *curr2 ;
	D3DCOLOR *palette ;
	char palstr[200] ;

	if ( PaletteChanged != 0 )
	{
		m_pd3dDevice->GetPalette( 0, &m_pd3dPalette ) ;
		m_pd3dPalette->Lock( &palette, 0 ) ;
		memcpy( palette, color_palette, 256* sizeof( D3DCOLOR ) ) ;
		m_pd3dPalette->Unlock() ;
		PaletteChanged = 0 ;
	}

	// Get a description of our level 0 texture so we can figure
	// out the pitch of the texture
	D3DSURFACE_DESC desc;
    Texture->GetLevelDesc(0, &desc);
	
	
	// Allocate a buffer to blit our frames to

	// Figure out how big of a rect to lock in our texture
	RECT rectSource;
	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = theHeight-1 ;
	rectSource.right  = theWidth-1 ;

	// Lock the rect in our texture
	D3DLOCKED_RECT d3dlr;
	Texture->LockRect(0, &d3dlr, &rectSource, 0);

	
	curr1 = g_pAlignBuff ;
	curr2 = g_pBlitBuff ;

	for ( int y = 0 ; y < theHeight ; y++ )
	{
		curr1 = ((byte*)g_pAlignBuff) + ( y*d3dlr.Pitch ) ;
		curr2 = ((byte*)g_pBlitBuff) + ( y*272 ) + 16 ;
		memcpy( curr1, curr2, 256 ) ;
	}
	
	// Swizzle the blittled surface back to the texture
	XGSwizzleRect(g_pAlignBuff, 0, NULL, d3dlr.pBits, desc.Width, desc.Height, NULL, 1);


	// Swizzle the blittled surface back to the texture
//	XGSwizzleRect(XBuf+8, 0, NULL, d3dlr.pBits, desc.Width, desc.Height, NULL, 1);
	//XGSwizzleRect(g_pBlitBuff, 0, NULL, d3dlr.pBits, desc.Width, desc.Height, NULL, 4);

	// Unlock our texture
	Texture->UnlockRect(0);

	//delete [] g_pBlitBuff;
	//g_pBlitBuff = NULL;


	src.left   = 0;
	src.top    = 0;
	src.right  = theWidth  + 0;
	src.bottom = theHeight + 1;

	UINT iWidth  = theWidth;
	UINT iHeight = theHeight;
	
	// win_start_maximized the rect, constraining to the aspect ratio
	dst.left   = dst.top = 0;
	dst.right  = iWidth;
	dst.bottom = iHeight;
	
	// center
	//dst.left   += ((iWidth - (dst.right - dst.left)) / 2)  + ((640-iWidth)/2);
	//dst.top    += ((iHeight - (dst.bottom - dst.top)) / 2) + ((480-iHeight)/2);
	//dst.right  += dst.left;
	//dst.bottom += dst.top;
	
    // Clear the viewport
//	if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_A ] ) || ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_X ] ) )  
	    g_pd3dDevice->Clear(0L, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0L);
	
	// Begin the Scene
	g_pd3dDevice->BeginScene();

	// Compute the source and dest image sizes
	const float dw = dst.right-dst.left;
	const float dh = dst.bottom-dst.top;
	const float sw = src.right-src.left;
	const float sh = src.bottom-src.top;


	float mx, my ;

	mx = (float)m_nScreenMaxX / (float)theWidth ;
	my = (float)m_nScreenMaxY / (float)theHeight ;

	// Compute the scale and transform vectors
	//D3DXVECTOR2 vecScale(dw/sw, dh/sh);
	D3DXVECTOR2 vecScale(mx, my);
	D3DXVECTOR2 vecTranslate(m_nScreenX, m_nScreenY );


	// Compute the scale and transform vectors
	//D3DXVECTOR2 vecScale(dw/sw, dh/sh);
	//D3DXVECTOR2 vecScale(2, 2);
	//D3DXVECTOR2 vecTranslate(56, 0 );
	//D3DXVECTOR2 vecTranslate(dst.left, dst.top);
	
	D3DXCOLOR d3color(1.0, 1.0, 1.0, 1.0);
	
	// Draw the sprite
	//if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_A ] ) || ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_Y ] ) )  
		Sprite->Draw(Texture, &rectSource, &vecScale, NULL, 0, &vecTranslate, d3color);
	
	// End the scene.
	g_pd3dDevice->EndScene();
	
	// Present the scene
	//if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_A ] ) || ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_BLACK ] ) )  
		//g_pd3dDevice->Present(NULL, NULL, NULL, NULL);

	return 1;
}

//-----------------------------------------------------------------------------
// Name: Render
// Desc: Renders the scene
//-----------------------------------------------------------------------------
HRESULT CXBoxSample::Render()
{
	m_bPaused =  ( m_state != IN_GAME ) ;


	if ( m_state == IN_GAME )
	{
		if ( m_dwStartPause > 0 )
		{
			g_dwTimePaused += ( GetTickCount() - m_dwStartPause ) ;
			m_dwStartPause = 0;
		}

		// Clear the zbuffer
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );

		// Draw a gradient filled background
		//RenderGradientBackground( 0xff404040, 0xff404080 );

		if ( global_error_message[0] != 0 )
		{
			WCHAR str[5000];

			m_Font.Begin();
			wprintf( str, L"%S", global_error_message );
			m_Font.DrawText(m_nXOffset+ 32, 48, 0xFF00ff00, str );
			//m_Font.DrawText(m_nXOffset+ 32, 48, 0xFFffffff, L"ERROR" );
			m_Font.End();
		}
		else
		{

			processEmu( TRUE ) ;

			if ( m_msgDelay > 0 )
			{
				m_msgDelay-- ;
				m_Font.Begin();
				m_Font.DrawText(m_nXOffset+  32, 32, 0xff00ff00, m_strMessage );
				m_Font.End();
			}
			else
			{
				float elapsedTime ;
				//m_Font.Begin();
				//WCHAR str[2000];
				//swprintf( str, L"fps = %f, dropped=%u", m_fFPS, m_dwDroppedFrames ) ;
				//m_Font.DrawText(m_nXOffset+ 20, 320, 0xFFffffff, str );
				//m_Font.End();
			}
		}
		
		// Present the scene
		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
	}
	else if ( m_state == IN_GAME_PAUSED )
	{
	}
	else if ( m_state == MAIN_MENU )
	{
		// Clear the zbuffer
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		if(m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			m_Font.Begin(); 
			m_Font.DrawText(m_nXOffset+32, 16*3,  0xFFffffff, L"FCEUltra for XBOX");
			m_Font.DrawText(m_nXOffset+32, 16*5,  0xFFffffff, L"Main Menu Controls");
			m_Font.DrawText(m_nXOffset+32, 16*6,  0xFFffffff, L"A - Play Selected Game");
			m_Font.DrawText(m_nXOffset+32, 16*7,  0xFFffffff, L"Y - Show This Help Screen");
			m_Font.DrawText(m_nXOffset+32, 16*8,  0xFFffffff, L"UP/DOWN - Select Game");
			m_Font.DrawText(m_nXOffset+32, 16*9,  0xFFffffff, L"RIGHT/LEFT - Next/Prev Page");
			m_Font.DrawText(m_nXOffset+32, 16*10,  0xFFffffff, L"LS/RS - Next/Prev Letter");
			m_Font.DrawText(m_nXOffset+32, 16*11,  0xFFffffff, L"START+BACK+LS+RS - Exit to dashboard");
			m_Font.DrawText(m_nXOffset+32, 16*12,  0xFFffffff, L"X+B - Reload list");
			m_Font.DrawText(m_nXOffset+32, 16*13,  0xFFffffff, L"LThumb - Configuration");
			m_Font.DrawText(m_nXOffset+32, 16*14,  0xFFffffff, L"BLACK+WHITE - Delete save files");
			m_Font.DrawText(m_nXOffset+32, 16*15,  0xFF00ff00, L"Lines colored like this have save files on the HD.");

			m_Font.DrawText(m_nXOffset+32, 16*16, 0xFFffffff, L"In-Game Controls");
			m_Font.DrawText(m_nXOffset+32, 16*17, 0xFFffffff, L"A/X - A/B Buttons");
			m_Font.DrawText(m_nXOffset+32, 16*18, 0xFFffffff, L"DPAD - Joystick Movement");
			m_Font.DrawText(m_nXOffset+32, 16*19, 0xFFffffff, L"START/BACK - Start/Select");
			m_Font.DrawText(m_nXOffset+32, 16*20, 0xFFffffff, L"WHITE - Insert FDS Disk");
			m_Font.DrawText(m_nXOffset+32, 16*21, 0xFFffffff, L"BLACK - Eject FDS Disk");
			m_Font.DrawText(m_nXOffset+32, 16*22, 0xFFffffff, L"B - Select FDS Disk");
			m_Font.DrawText(m_nXOffset+32, 16*23, 0xFFffffff, L"LS+BLACK - Save state");
			m_Font.DrawText(m_nXOffset+32, 16*24, 0xFFffffff, L"LS+WHITE - Load state");
			m_Font.DrawText(m_nXOffset+32, 16*25, 0xFFffffff, L"Y - Options Menu");
			m_Font.End();
		}
		else if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_BLACK ] ) &&
				  ( m_DefaultGamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ) &&
				  ( m_DefaultGamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ) )
		{
			m_Font.Begin(); 
			m_Font.DrawText(m_nXOffset+48, 32, 0xFFffffff, L"FCEUltra for XBOX - made by me");
			m_Font.End();
		}
		else if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_BLACK ] ) &&
				  ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_WHITE ] ) )
		{
			deleteSaveFiles( curr ) ;
		}
		else
		{
			WCHAR str[2000];
			swprintf( str, L"FCEUltra for XBOX  Y-Help Screen  Found %u games", numfiles);

			m_Font.Begin(); 
			m_FontSmall.Begin(); 
			m_Font.DrawText(m_nXOffset+ 48, 32, 0xFFffffff, str );
			//m_Font.DrawText(m_nXOffset+48, 32, 0xFFffffff, L"Gnuboy for XBOX  Y-Help Screen");


			
			
			float fWinX = 32, fWinY = 64;

			MenuBar( m_nXOffset+fWinX, fWinY+ (( m_nFontHeight+2)*(curr-topIdx)) + 3, 600, m_nFontHeight+3 ) ;

			for ( unsigned int idx = topIdx ; ( idx < numfiles ) && ( idx < topIdx+m_namesPerPage) ; idx++ )
			{
				if ( curr == idx )
				{
					if ( hasFiles( idx ) )
						m_FontSmall.DrawText(m_nXOffset+fWinX  , fWinY, 0xffff00ff, files[idx].name );
					else
						m_FontSmall.DrawText(m_nXOffset+fWinX , fWinY, 0xff000000, files[idx].name );
				}
				else
				{
					if ( hasFiles( idx ) )
						m_FontSmall.DrawText(m_nXOffset+fWinX, fWinY, 0xFF00ff00, files[idx].name );
					else
						m_FontSmall.DrawText(m_nXOffset+fWinX, fWinY, 0xFFffffff, files[idx].name );
				}
				fWinY += m_nFontHeight+2;
			}
			

			// end font drawing
			m_Font.End();
			m_FontSmall.End();


		}

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
	}
	else if ( m_state == INIT_SYSTEM )
	{
		InitializeWithScreen() ;
	}
	else if ( m_state == INIT_SYSTEM_SHOW_SCREEN )
	{
	}
	else
	{
	}



    return S_OK;
}

/**
  This routine should be called regularly to handle events
*/

void CXBoxSample::handleEvents()
{

    INT32 resistance ;
	float newRes ;

	m_joypadA = m_joypadB = 0 ;

  
	if ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[ XINPUT_GAMEPAD_A ] ) 
		m_joypadA |= JOY_A ;

	if ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[ XINPUT_GAMEPAD_X ] ) 
		m_joypadA |= JOY_B ;

	if ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		m_joypadA |= JOY_LEFT ;

	if ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		m_joypadA |= JOY_RIGHT ;

	if ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		m_joypadA |= JOY_UP ;
	
	if ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		m_joypadA |= JOY_DOWN ;
	
	if ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_START )  
		m_joypadA |= JOY_START ;

	if ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_BACK )  
		m_joypadA |= JOY_SELECT ;

	if ( ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) && 
		 (g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE]) )
	{
		LoadState() ;
	}
	else if ( ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) && 
		 (g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK]) )
	{
		SaveState() ;
	}
	else if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK]) 
	{
		FDSControl(FDS_EJECT);
		if ( m_bNetplay )
		{
			m_sockNetplay.Send( "E", 1 ) ;
		}
	}
	else if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE]) 
	{
		FDSControl(FDS_IDISK);
		if ( m_bNetplay )
		{
			m_sockNetplay.Send( "I", 1 ) ;
		}
	}
	else if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
	{
		FDSControl(FDS_SELECT);
		if ( m_bNetplay )
		{
			m_sockNetplay.Send( "S", 1 ) ;
		}

	}


	if ( g_Gamepads[1].hDevice && g_Gamepads[1].bAnalogButtons[ XINPUT_GAMEPAD_A ] ) 
		m_joypadB |= JOY_A ;

	if ( g_Gamepads[1].hDevice && g_Gamepads[1].bAnalogButtons[ XINPUT_GAMEPAD_X ] ) 
		m_joypadB |= JOY_B ;

	if ( g_Gamepads[1].hDevice && g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		m_joypadB |= JOY_LEFT ;

	if ( g_Gamepads[1].hDevice && g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		m_joypadB |= JOY_RIGHT ;

	if ( g_Gamepads[1].hDevice && g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		m_joypadB |= JOY_UP ;
	
	if ( g_Gamepads[1].hDevice && g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		m_joypadB |= JOY_DOWN ;
	
	if ( g_Gamepads[1].hDevice && g_Gamepads[1].wButtons & XINPUT_GAMEPAD_START )  
		m_joypadB |= JOY_START ;

	if ( g_Gamepads[1].hDevice && g_Gamepads[1].wButtons & XINPUT_GAMEPAD_BACK )  
		m_joypadB |= JOY_SELECT ;


	if ( m_bNetplay )
		processNetplay() ;
}


void CXBoxSample::FindAvailRoms()
{
	// Search for all files in our rom directory
	HANDLE hFind;	
	WIN32_FIND_DATAA oFindData;
	hFind = FindFirstFile( "D:\\nesroms\\*", &oFindData);
	
	// If we didn't find any just return
	if (hFind == INVALID_HANDLE_VALUE)
	{
		return;
	}
	
	do 
	{
		numfiles++ ;
	} while (FindNextFile(hFind, &oFindData));

	FindClose( hFind );

	if (files != NULL)
	{
		delete [] files;
		files = NULL;
	}
	
	// Allocate a buffer to blit our frames to
	files = new FILENAME[numfiles];

	numfiles = 0 ;

	hFind = FindFirstFile( "D:\\nesroms\\*", &oFindData);
	
	// If we didn't find any just return
	if (hFind == INVALID_HANDLE_VALUE)
	{
		return;
	}
	
	do 
	{
		// Mame's games are in 8-bit ansi convert them to unicode for display
		//WCHAR wcName[200];
		//mbsrtowcs(wcName, &pName, 200, NULL);

		files[numfiles].name[0] = 0 ;
		strcpy( (char*)(files[numfiles].filename), oFindData.cFileName ) ;
		strlwr( (char*)( files[numfiles].filename )) ;
        swprintf( files[numfiles].name, L"%S", files[numfiles].filename );
//		mbsrtowcs(files[numfiles].name, (const char**)( &(oFindData.cFileName) ), 30, NULL);
		numfiles++ ;
	} while (FindNextFile(hFind, &oFindData));

	FindClose( hFind );

	QuickSort( 0, numfiles-1 ) ;
}

// check for move cursor and move accordingly (with clamp etc)
void CXBoxSample::MoveCursor()
{
	char c ;
	int  lcv ;

		if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER])
		{
			c = tolower(files[curr].filename[0]) ;

			lcv = curr ;

			while ( ( lcv < numfiles ) && ( tolower(files[lcv].filename[0]) <= c ) )
				lcv++ ;

			if ( lcv < numfiles )
			{
				topIdx = lcv ;
				curr = lcv ;
			}
			else
			{
				topIdx = numfiles - 1 ;
				curr = numfiles - 1 ;
			}
		}
		else if (m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER])
		{
			c = tolower(files[curr].filename[0]) ;

			lcv = curr ;

			while ( ( lcv >= 0 ) && ( tolower(files[lcv].filename[0]) >= c ) )
				lcv-- ;

			if ( lcv >= 0 )
			{
				topIdx = lcv ;
				curr = lcv ;
			}
			else
			{
				topIdx = 0 ;
				curr = 0 ;
			}
		}
		else if ( m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		{
			if ( topIdx >= NAMES_PER_PAGE )
			{
				topIdx -= NAMES_PER_PAGE ;
				curr = topIdx ;
			}
			else
			{
				topIdx = 0 ;
				curr = 0 ;
			}
		}
		else if ( m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		{
			if ( topIdx + NAMES_PER_PAGE < numfiles )
			{
				topIdx += NAMES_PER_PAGE ;
				curr = topIdx ;
			}
			else
			{
				topIdx = numfiles - 1 ;
				curr = numfiles - 1 ;
			}
		}
		else if ( m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			if ( curr == topIdx + (NAMES_PER_PAGE-1) )
			{
				if ( curr < numfiles - 1 )
				{
					topIdx++ ;
					curr++ ;
				}
			}
			else
			{
				if ( curr < numfiles-1 )
					curr++ ;
			}
		}
		else if ( m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			if ( curr == topIdx )
			{
				if ( curr > 0 )
				{
					topIdx-- ;
					curr-- ;
				}
			}
			else
			{
				if ( curr > 0 )
					curr-- ;
			}
		}

}



void CXBoxSample::initConsole( UINT32 idx )
{
	char                filename[500] ;
	unsigned char       *gimage ;
	int                 ntsccol ;
	FILE				*infile ;
	UINT32				fsize ;
	char *forcebuf ;

	global_error_message[0] = 0 ;

	if ( m_bNetplay )
	{
		m_sockNetplay.Close() ;
	}

	m_lastPadValues[0] = m_lastPadValues[1] = 0 ;
	m_bAmServer = FALSE ;
	m_bNetplay = FALSE ;

	m_numFrames = 0 ;
	m_dwDroppedFrames = 0 ;

	memset( m_memMatches, 1, CONSOLE_MEMORY_SIZE ) ;
	m_currentMemMatches = CONSOLE_MEMORY_SIZE ;
	m_numCheats = 0 ;

	PaletteChanged = 0 ;


	strcpy((char*)filename, "D:\\nesroms\\" ) ;
	//wcsrtombs( (char*)gfilename, (const wchar_t**)(&(files[idx].name)), 100, NULL ) ;
	strcat( (char*)filename, (const char*)files[idx].filename ) ;

	m_sound.init() ;

	char *p;

	strcpy( g_saveprefix, g_savePath ) ;
	strcat( g_saveprefix, "\\" ) ;
	strcat( g_saveprefix, (const char*)(files[idx].filename) ) ;
	p = strchr(g_saveprefix, '.');
	if (p) *p = 0;

	strcpy(g_sramfile, g_saveprefix);
	strcat(g_sramfile, ".sav");

	strcpy(g_statefile, g_saveprefix);
	strcat(g_statefile, ".sta");

	strcpy(g_chtfile, g_saveprefix);
	strcat(g_chtfile, ".cht");
	

	// Create our texture
	init_texture();

	// Create our sprite driver
	if ( Sprite == NULL )
		D3DXCreateSprite(m_pd3dDevice, &Sprite);
	



	if(!(FCEUI_Initialize()))
	{
		strcpy(global_error_message, "*loadgame" ) ;
		return ;
	}

	m_consoleMemory = RAM ;

        //GetBaseDirectory(argv[0]);
		FCEUI_SetBaseDirectory(g_savePath);

//        LoadConfig();
//        DoArgs(argc-2,&argv[1]);
        FCEUI_DisableSpriteLimitation(1);
        FCEUI_SaveExtraDataUnderBase(1);
        FCEUI_SetSnapName(0);
        FCEUI_SetRenderedLines(8,239,0,239) ;
        FCEUI_SetSoundVolume(100);

		FCEUI_SetDirOverride(FCEUIOD_NV, g_savePath ) ;
		FCEUI_SetDirOverride(FCEUIOD_STATE, g_savePath ) ;
		FCEUI_SetDirOverride(FCEUIOD_CHEATS, g_savePath ) ;

		ntsccol = 1 ;

		DriverInterface(DES_NTSCCOL,&ntsccol);


         FCEUI_Sound(44100);

	if(!(FCEUI_LoadGame(filename)))
	{
		strcpy(global_error_message, "*loadgame" ) ;
		return ;
	}
    FCEUI_SetInput(0, SI_GAMEPAD,&m_joypadA,0);
    FCEUI_SetInput(1, SI_GAMEPAD,&m_joypadB,0);

	FCEU_ResetPalette() ;








	cht_load();

	m_fAppTime = 0.0f ;

	g_dwStartTime = GetTickCount() ;
	g_dwTimePaused = 0 ;
	m_dwStartPause = 0 ;

	m_steps = 0 ;

	//put 3 frames of data in the audio buffer
	processEmu(FALSE) ;
	processEmu(FALSE) ;
	processEmu(FALSE) ;

	PaletteChanged = 1 ;
	//Then start it up
	m_sound.pause( FALSE ) ;

}

void CXBoxSample::cleanupConsole( )
{
	cht_save() ;

	CloseGame() ;

	if (m_cheatCodes != NULL)
	{
		free(m_cheatCodes);
		m_cheatCodes = NULL;
	}
	//see loader_unload() for other things to free
}

void CXBoxSample::cht_load()
{
	FILE *f;
	CHEAT_CODE code ;
	int fsize ;
	int numread ;

	if (m_cheatCodes != NULL)
	{
		free(m_cheatCodes);
		m_cheatCodes = NULL;
	}
	

	f = fopen(g_chtfile, "rb");
	if (!f) return ;

	fseek( f, 0, SEEK_END ) ;
	fsize = ftell( f ) ;
	fseek( f, 0, SEEK_SET ) ;

	m_numCheats = fsize / sizeof(CHEAT_CODE) ;

	m_cheatCodes = (CHEAT_CODE*)malloc( sizeof(CHEAT_CODE) *  m_numCheats );


	numread = 0 ;
	fread(m_cheatCodes, sizeof(CHEAT_CODE), m_numCheats, f);

	fclose(f);
}

void CXBoxSample::cht_save()
{
	FILE *f;
	CHEAT_CODE code ;

	if ( m_numCheats == 0 )
	{
		DeleteFile( g_chtfile ) ;
		return ;
	}

	f = fopen(g_chtfile, "wb");
	if (!f) return ;

	fwrite(m_cheatCodes, sizeof(CHEAT_CODE), m_numCheats, f);

	fclose(f);
	
}

BOOL CXBoxSample::hasFiles( int idx )
{
	char                filename[500] ;
	unsigned char       *gimage ;
	FILE				*infile ;
	UINT32				fsize ;
	char *forcebuf ;
	char *p;


	strcpy( g_saveprefix, g_savePath ) ;
	strcat( g_saveprefix, "\\" ) ;
	strcat( g_saveprefix, (const char*)(files[idx].filename) ) ;
	//sprintf(saveprefix, "%s\\%s", savedir, (const char*)files[idx].filename);
	p = strchr(g_saveprefix, '.');
	if (p) *p = 0;

	strcpy(g_sramfile, g_saveprefix);
	strcat(g_sramfile, ".sav");

	strcpy(g_statefile, g_saveprefix);
	strcat(g_statefile, ".sta");

	strcpy(g_chtfile, g_saveprefix);
	strcat(g_chtfile, ".cht");

	infile = fopen( g_sramfile, "rb" ) ;

	if ( infile )
	{
		fclose(infile) ;
		return TRUE ;
	}

	infile = fopen( g_statefile, "rb" ) ;

	if ( infile )
	{
		fclose(infile) ;
		return TRUE ;
	}

	infile = fopen( g_chtfile, "rb" ) ;

	if ( infile )
	{
		fclose(infile) ;
		return TRUE ;
	}

	return FALSE ;

}
void CXBoxSample::updateCheats( )
{
	for ( int i = 0 ; i < m_numCheats ; i++ )
	{
		if ( m_cheatCodes[i].enabled )
			//updateConsoleMemory( m_cheatCodes[i].adr, m_cheatCodes[i].val & 0xFF ) ;
			m_consoleMemory[ m_cheatCodes[i].adr ] = ( m_cheatCodes[i].val & 0xFF ) ;
	}
}

void CXBoxSample::deleteSaveFiles( int idx )
{
	char                filename[500] ;
	unsigned char       *gimage ;
	FILE				*infile ;
	UINT32				fsize ;
	char *forcebuf ;
	char *p;


	strcpy( g_saveprefix, g_savePath ) ;
	strcat( g_saveprefix, "\\" ) ;
	strcat( g_saveprefix, (const char*)(files[idx].filename) ) ;
	//sprintf(saveprefix, "%s\\%s", savedir, (const char*)files[idx].filename);
	p = strchr(g_saveprefix, '.');
	if (p) *p = 0;

	strcpy(g_sramfile, g_saveprefix);
	strcat(g_sramfile, ".sav");

	strcpy(g_statefile, g_saveprefix);
	strcat(g_statefile, ".sta");

	strcpy(g_chtfile, g_saveprefix);
	strcat(g_chtfile, ".cht");

	DeleteFile( g_sramfile ) ;
	DeleteFile( g_statefile ) ;
	DeleteFile( g_chtfile ) ;

}


#ifdef __cplusplus
extern "C" {
#endif


void FCEUD_WriteSoundData(int32 *Buffer, int Count)
{
	g_app->m_dwDroppedFrames += ( g_sound->process( Buffer, Count ) ) ;
}

void FCEUD_PrintError(char *s)
{
	strcpy( global_error_message, s ) ;
}

void  FCEUD_PrintNotice( char *msg ) 
{
	g_app->m_msgDelay = 180 ;

	swprintf( g_app->m_strMessage, L"%S", msg ) ;
	
}

void FCEUD_UpdateInput(void)
{
}
void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
{
	g_app->SetPalette( index, r, g, b ) ;
}

void FCEUD_GetPalette(uint8 i, uint8 *r, uint8 *g, uint8 *b)
{
	g_app->GetPalette( i, r, g, b ) ;
}
void FCEUD_BlitScreen(uint8 *XBuf)
{
}

void audio_callback()
{
//	g_sound->process( *g_apptime, *g_numframes ) ;

}

#ifdef __cplusplus
}
#endif

void CXBoxSample::GetPalette(uint8 i, uint8 *r, uint8 *g, uint8 *b)
{
	*r=( color_palette[i] >> 16 ) & 0xFF ;
	*g=( color_palette[i] >> 8 ) & 0xFF ;
	*b=( color_palette[i]  ) & 0xFF ;
}

void CXBoxSample::SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
{

	color_palette[index] = ( 0xFF << 24 ) | ( r << 16 ) | ( g << 8 ) | (b)  ;
	PaletteChanged=1;
}

void CXBoxSample::processEmu( BOOL render )
{
		
			updateCheats() ;

			handleEvents();
			EmLoopOnce();  //makes callback to the audio

			if ( render )
			{
				render_to_texture();
				m_numFrames++ ;
			}

			while ( m_sound.m_bDanger )
			{
				handleEvents();
				EmLoopOnce();  //makes callback to the audio
			}
			//m_sound.process( m_fAppTime, m_numFrames ) ;
 			

}


int CXBoxSample::rom_load_zip()
{
	return 0;
}

//sometimes items are just gone
//re-load list
//pAL/ntsc
//quit app to return to dashboard

int CXBoxSample::init_white_texture()
{
	// Release any previous texture
	if (WhiteTexture) 
	{ 
		WhiteTexture->Release();
		WhiteTexture = NULL;
	}
	
	// Create the texture
	D3DXCreateTexture(m_pd3dDevice, 16, 16, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &WhiteTexture);
	
	D3DSURFACE_DESC desc;
    WhiteTexture->GetLevelDesc(0, &desc);


	RECT rectSource;
	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = 15;
	rectSource.right  = 15 ;

	D3DLOCKED_RECT d3dlr;
	WhiteTexture->LockRect(0, &d3dlr, &rectSource, 0);

	memset( d3dlr.pBits, 0xFF, desc.Size ) ;

	// Unlock our texture
	WhiteTexture->UnlockRect(0);

	if ( MenuSprite == NULL )
		D3DXCreateSprite(m_pd3dDevice, &MenuSprite);

	return 0;
}

void CXBoxSample::QuickSort( int lo, int hi )
{
	int i = lo;
	int j = hi;
	char partitionStr[200];
	FILENAME tmpf;

	strcpy( partitionStr, (const char*)files[(i+j)/2].filename ) ;
	do
	{
		while ( strcmp( (const char*)files[i].filename, partitionStr ) < 0 ) i++ ;
		while ( strcmp( partitionStr, (const char*)files[j].filename ) < 0 ) j-- ;

		if (i <= j)
		{
			memcpy( &tmpf, &(files[i]), sizeof(tmpf) ) ;
			memcpy( &(files[i]), &(files[j]), sizeof(tmpf) ) ;
			memcpy( &(files[j]), &tmpf, sizeof(tmpf) ) ;
			i++;
			j--;
		}
	} while (i <= j);

	if (lo < j) QuickSort(lo, j);
	if (i < hi) QuickSort(i, hi);

	
}

void CXBoxSample::MenuBar( int xpos, int ypos, int xlen, int ylen )
{
	D3DXVECTOR2 vecScale( 1, 1 ) ;
	D3DXVECTOR2 vecTranslate( xpos, ypos ) ;
	D3DXCOLOR d3color(1.0, 1.0, 1.0, 1.0);
	RECT rectSource;

	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = ylen - 1 ;
	rectSource.right  = xlen - 1;
	
	MenuSprite->Draw(WhiteTexture, &rectSource, &vecScale, NULL, 0, &vecTranslate, d3color);
}

void CXBoxSample::doConfiguration()
{

	int menuChoice = 0 ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		MenuBar( 32, 16*(6+menuChoice)+3, 600, 19 ) ;

		m_Font.Begin();
		m_Font.DrawText( m_nXOffset+  32, 16*4, 0xffffffff, L"CONFIGURATION" );
		m_Font.DrawText( m_nXOffset+  32, 16*6, menuChoice==0 ? 0xff000000 : 0xffffffff, L"Set Game List Font Size" );
		m_Font.DrawText( m_nXOffset+  32, 16*7, menuChoice==1 ? 0xff000000 : 0xffffffff, L"Set Text Offset (push menu text to the right)" );
		m_Font.DrawText( m_nXOffset+  32, 16*8, menuChoice==2 ? 0xff000000 : 0xffffffff, L"Set Game Screen Size/Position" );
		m_Font.DrawText( m_nXOffset+  32, 16*10, 0xffffffff, L"Press B to go back" );
		m_Font.End();

		
		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			break ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN )
		{
			menuChoice = (menuChoice+1)%3 ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP )
		{
			menuChoice = (menuChoice-1)%3 ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_A])
		{
			switch ( menuChoice )
			{
				case 0 : doFontSize() ; break ;
				case 1 : doTextOffset() ; break ;
				case 2 : doScreenSize() ; break ;
				default : break ;
			}
		}


	}

}

void CXBoxSample::doFontSize()
{
	WCHAR str[200];
	int value ;

	value = m_nFontHeight ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		swprintf( str, L"Use DPAD to adjust current value : %u", value ) ;

		m_Font.Begin();
		m_Font.DrawText( m_nXOffset+  32, 16*4, 0xffffffff, L"Set Game List Font Size" );
		m_Font.DrawText( m_nXOffset+  32, 16*6, 0xffffffff, str) ;
		m_Font.DrawText( m_nXOffset+  32, 16*8, 0xffffffff, L"Press A to accept" );
		m_Font.DrawText( m_nXOffset+  32, 16*9, 0xffffffff, L"Press B to go back" );
		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			break ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			value = ( value - 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			value = ( value + 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		{
			value = ( value - 10 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		{
			value = ( value + 10  ) & 0xFF ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_A])
		{
			m_nFontHeight = value ;
			m_namesPerPage =  (25*14 ) / ( m_nFontHeight+2) ;
			doSaveConfig() ;
			break ;
		}


	}

}

void CXBoxSample::doScreenSize()
{
	WCHAR str[200];
	int x, y, maxx, maxy ;
	float fx, fy, fmaxx, fmaxy ;

	x = m_nScreenX ;
	y = m_nScreenY ;
	maxx = m_nScreenMaxX;
	maxy = m_nScreenMaxY ;

	fx = x ;
	fy = y ;
	fmaxx = maxx ;
	fmaxy = maxy ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		x = fx ;
		y = fy ;
		maxx = fmaxx ;
		maxy = fmaxy ;
		MenuBar( x, y, maxx, maxy ) ;

		m_Font.Begin();
		m_Font.DrawText( m_nXOffset+  132, 16*11, 0xff00ff00, L"Set Game Screen Size" );

		m_Font.DrawText( m_nXOffset+  132, 16*13, 0xff00ff00, L"Use RThumb and LThumb to adjust screen size/pos" );
		m_Font.DrawText( m_nXOffset+  132, 16*14, 0xff00ff00, L"Press A to accept" );
		m_Font.DrawText( m_nXOffset+  132, 16*15, 0xff00ff00, L"Press B to go back" );

		swprintf( str, L"X=%u Y=%u MAXX=%u MAXY=%u", x, y, maxx, maxy ) ;
		m_Font.DrawText( m_nXOffset+  132, 16*17, 0xff00ff00, str );

		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			break ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_A])
		{
			m_nScreenX = x ;
			m_nScreenY = y ;
			m_nScreenMaxX = maxx ;
			m_nScreenMaxY = maxy ;
			doSaveConfig() ;
			break ;
		}
		else
		{
			if ( g_Gamepads[0].hDevice )
			{
				fx += g_Gamepads[0].fX1 ;
				fy -= g_Gamepads[0].fY1 ;
				fmaxx += g_Gamepads[0].fX2 ;
				fmaxy -= g_Gamepads[0].fY2 ;
			}
		}
	}

}

void CXBoxSample::doTextOffset()
{
	WCHAR str[200];
	int value ;

	value = m_nXOffset ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		swprintf( str, L"Use DPAD to adjust current value : %u", value ) ;

		m_Font.Begin();
		m_Font.DrawText( value+  32, 16*4, 0xffffffff, L"Set Menu Text Offset" );
		m_Font.DrawText( value+  32, 16*6, 0xffffffff, str) ;
		m_Font.DrawText( value+  32, 16*8, 0xffffffff, L"Press A to accept" );
		m_Font.DrawText( value+  32, 16*9, 0xffffffff, L"Press B to go back" );
		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			break ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			value = ( value - 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			value = ( value + 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		{
			value = ( value - 10 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		{
			value = ( value + 10  ) & 0xFF ;
		}
		else if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_A])
		{
			m_nXOffset = value ;
			break ;
		}


	}

}
void CXBoxSample::doSaveConfig()
{
	FILE *inifile ;

	inifile = fopen( "D:\\fceu.ini", "wb" ) ;

	if ( inifile != NULL )
	{
		fprintf( inifile, "%u %u %u %u %u %u  \r\n", m_nXOffset, m_nFontHeight, m_nScreenX, m_nScreenY, m_nScreenMaxX, m_nScreenMaxY ) ;
		fclose( inifile ) ;
	}

}

//recurse dirs

void CXBoxSample::doHostGame()
{
	char ipaddr[30] ;
	int curr_pos ;
	uint16 val1, val2 ;
	SOCKET connection ;
	WCHAR wstr[200] ;

	curr_pos = 0 ;
	strcpy( ipaddr, "000.000.000.000" ) ;


	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();

		m_Font.DrawText(m_nXOffset+  32, 16*2, 0xffffffff, L"Host a Network Game" );

		m_Font.DrawText( m_nXOffset+ 32, 16*4, 0xffffffff, L"Waiting for player to connect..." );
		m_Font.DrawText( m_nXOffset+ 32, 16*6, 0xffffffff, L"Press B to cancel" );

		m_Font.DrawText( m_nXOffset+ 32, 16*8, 0xffffffff, L"If your game stutters a lot, increase the lag factor" );

		swprintf( wstr, L"Lag factor : %u", m_netbuflen ) ;
		m_Font.DrawText( m_nXOffset+ 32, 16*10, 0xffffffff, wstr );
		m_Font.DrawText( m_nXOffset+ 32, 16*12, 0xffffffff, L"Use DPAD to change lag factor" );

		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

		if ( ( connection = m_sockListener.Accept( NULL ) ) != INVALID_SOCKET )
		{
			m_sockNetplay.m_debugClientSock.m_Socket = connection ;
			m_sound.cleanup() ;
			cleanupConsole() ;
			initConsole(curr) ;
			m_bNetplay = TRUE ;
			m_bAmServer = TRUE ;
			m_lastPadValues[0] = m_lastPadValues[1] = 0 ;
			val2 = 0 ;
			strcpy(ipaddr, "J" ) ;
			memcpy( ipaddr+1, &val2, sizeof(val2) ) ;

			char buflen ;

			buflen = m_netbuflen ;

			m_sockNetplay.Send( &buflen, 1 ) ;

			for ( int i = 0 ; i < m_netbuflen ; i++ )
			{
				m_sockNetplay.Send( ipaddr, 1+sizeof(val2) ) ;
				m_joyqueue[i] = val2 ;
			}

			m_netbufptr = 0 ;
			//padcapture = fopen( "d:\\joypad.raw", "wb" ) ;
			m_state = IN_GAME ;
			break ;
		}

        XBInput_GetInput();
		if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
		{
			break ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			m_netbuflen = ( m_netbuflen - 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			m_netbuflen = ( m_netbuflen + 1 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		{
			m_netbuflen = ( m_netbuflen - 10 ) & 0xFF ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		{
			m_netbuflen = ( m_netbuflen + 10  ) & 0xFF ;
		}

	}


}
void CXBoxSample::doJoinGame()
{
	char ipaddr[30] ;
	char ipaddrconv[30] ;
	char *fpos, *epos ;
	int curr_pos ;
	uint16 val1, val2 ;
	int ip1, ip2, ip3, ip4 ;

	curr_pos = 0 ;

	fpos = m_ipaddr ;
	epos = strchr( fpos, '.' ) ;
	*epos = 0 ;
	epos++ ;
	ip1 = atoi( fpos ) ;

	fpos = epos ;
	epos = strchr( fpos, '.' ) ;
	*epos = 0 ;
	epos++ ;
	ip2 = atoi( fpos ) ;

	fpos = epos ;
	epos = strchr( fpos, '.' ) ;
	*epos = 0 ;
	epos++ ;
	ip3 = atoi( fpos ) ;
	ip4 = atoi( epos ) ;

	sprintf( ipaddr, "%03.3u.%03.3u.%03.3u.%03.3u", ip1, ip2, ip3, ip4 ) ;

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();

		m_Font.DrawText(m_nXOffset+  32, 16*2, 0xffffffff, L"Join a Network Game" );

		m_Font.DrawText( m_nXOffset+ 32, 16*4, 0xffffffff, L"Enter the IP address of the game to join" );
		m_Font.DrawText( m_nXOffset+ 32, 16*5, 0xffffffff, L"Press A to accept" );
		m_Font.DrawText( m_nXOffset+ 32, 16*6, 0xffffffff, L"Press B to cancel" );

		WCHAR str[200];

		for ( int i = 0 ; i < 15 ; i++ )
		{
			swprintf( str, L"%c", ipaddr[i] ) ;
			if ( i == curr_pos )
				m_Font.DrawText( m_nXOffset+  50 + ( i * 16 ), 16*9, 0xff00ff00, str ) ;
			else
				m_Font.DrawText( m_nXOffset+  50 + ( i * 16 ), 16*9, 0xffffffff, str ) ;
		}

		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
		{
			break ;
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_A ] ) 
		{
			fpos = ipaddr ;
			epos = strchr( fpos, '.' ) ;
			*epos = 0 ;
			epos++ ;
			ip1 = atoi( fpos ) ;

			fpos = epos ;
			epos = strchr( fpos, '.' ) ;
			*epos = 0 ;
			epos++ ;
			ip2 = atoi( fpos ) ;

			fpos = epos ;
			epos = strchr( fpos, '.' ) ;
			*epos = 0 ;
			epos++ ;
			ip3 = atoi( fpos ) ;
			ip4 = atoi( epos ) ;

			sprintf( m_ipaddr, "%u.%u.%u.%u", ip1, ip2, ip3, ip4 ) ;


			//if ( m_sockNetplay.Connect( "192.168.123.99", 8989, 0 ) == 0 )
			if ( m_sockNetplay.Connect( m_ipaddr, 8989, 0 ) == 0 )
			{
				m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
									 0x00000000, 1.0f, 0L );
				RenderGradientBackground( 0xFF000000, 0xFF000000 );

				m_Font.Begin();

				m_Font.DrawText(m_nXOffset+  32, 16*3, 0xffffffff, L"Could not connect to that IP address." );

				m_Font.DrawText( m_nXOffset+ 32, 16*5, 0xffffffff, L"Press B to return" );
				m_Font.End();

				m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

				XBInput_GetInput();

				while ( ! ( g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[ XINPUT_GAMEPAD_B ] ) )
				{
					XBInput_GetInput();
				}

				m_sockNetplay.Close() ;
			}
			else
			{

				m_sound.cleanup() ;
				cleanupConsole() ;
				initConsole(curr) ;
				m_bNetplay = TRUE ;
				m_bAmServer = FALSE ;
				m_lastPadValues[0] = m_lastPadValues[1] = 0 ;


				char buflen ;

				while ( m_sockNetplay.Recv( &buflen, 1 ) <= 0 ) ; //empty loop


				m_netbuflen = buflen ;

				val2 = 0 ;

				//strcpy(ipaddr, "J" ) ;
				//memcpy( ipaddr+1, &val2, sizeof(val2) ) ;
				//m_sockNetplay.Send( ipaddr, 5 ) ;
				//m_sockNetplay.Send( ipaddr, 5 ) ;
				//m_sockNetplay.Send( ipaddr, 5 ) ;
				//m_sockNetplay.Send( ipaddr, 5 ) ;
				//m_sockNetplay.Send( ipaddr, 5 ) ;

				for ( int i = 0 ; i < m_netbuflen ; i++ )
					m_joyqueue[i] = val2 ;

				m_netbufptr = 0 ;
				//padcapture = fopen( "d:\\joypad.raw", "wb" ) ;
				m_state = IN_GAME ;

				break ;
			}
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
		{
			val1 = ipaddr[curr_pos] - '0' ;

			if ( val1 == 0 )
				val1 = 9 ;
			else
				val1-- ;

			ipaddr[curr_pos] = val1 + '0' ;

		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_UP ) 
		{
			val1 = ipaddr[curr_pos] - '0' ;

			if ( val1 == 9 )
				val1 = 0 ;
			else
				val1++ ;

			ipaddr[curr_pos] = val1 + '0' ;

		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
		{
			switch ( curr_pos )
			{
				case 0 : curr_pos = 14 ; break ;
				case  4 : curr_pos = 2 ; break ;
				case 8 : curr_pos = 6 ; break ;
				case 12 : curr_pos = 10 ; break ;
				default : curr_pos-- ;
			}
		}
		else if ( g_Gamepads[0].hDevice && g_Gamepads[0].wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
		{
			switch ( curr_pos )
			{
				case 14 : curr_pos = 0 ; break ;
				case  2 : curr_pos = 4 ; break ;
				case 6 : curr_pos = 8 ; break ;
				case 10 : curr_pos = 12 ; break ;
				default : curr_pos++ ;
			}
		}
	}


}
void CXBoxSample::processNetplay()
{
	char netbuf[1024] ;
	int  numread ;
	char *netptr ;
	int  numtries ;
	uint16  padval ;
	uint16  newpadval ;
	int  attempts ;

	newpadval = 0 ;
	numtries = 1024 ;

	if ( m_state == IN_GAME )
	{
		if ( m_bAmServer )
		{
			netbuf[0] = 'J' ;
			memcpy( netbuf+1, &(m_joypadA), sizeof( uint16 ) ) ;
			m_sockNetplay.Send( netbuf, 1+sizeof(uint16) ) ;

			padval = m_joyqueue[m_netbufptr] ;
			m_joyqueue[m_netbufptr] = m_joypadA ;
			m_joypadA = padval ;

			//padval = megad->pad[0] ;
			//megad->pad[0] = 
			//m_joyqueue[m_netbufptr] = padval ;

			m_netbufptr = ( m_netbufptr + 1 ) % m_netbuflen ;

			/*
			netbuf[0] = 'J' ;
			memcpy( netbuf+1, &(m_joyqueue[m_netbufptr]), sizeof( int ) ) ;
			m_sockNetplay.Send( netbuf, 1+sizeof(int) ) ;

			padval = megad->pad[0] ;
			megad->pad[0] = m_joyqueue[m_netbufptr] ;
			m_joyqueue[m_netbufptr] = padval ;

			m_netbufptr = ( m_netbufptr + 1 ) % m_netbuflen ;
			*/
		}
	}

	while ( ( newpadval == 0 ) )
	///while ( ( newpadval == 0 ) && ( numtries > 0 ) )
	{
		numread = m_sockNetplay.Recv( netbuf, 1 ) ;

		if ( numread < 1 )
		{
			if ( m_state != IN_GAME )
				break ;
			numtries-- ;
			continue ;
		}

		switch ( *netbuf )
		{
			case 'E' : FDSControl(FDS_EJECT); break ;
			case 'I' : FDSControl(FDS_IDISK); break ;
			case 'S' : FDSControl(FDS_SELECT); break ;

			case 'P' : m_state = IN_GAME_PAUSED ; netptr++ ; numread-- ; return ;
			case 'U' : 
			{
				if ( m_state == IN_GAME ) 
					break ;  //ignore it keep processing
				m_state = IN_GAME ; 
				netptr++ ; 
				numread-- ; 
				return ;
			}
			case 'J' : 
			{
				int readval ;
				numread = 0 ;
				attempts =1024 ;
				netptr = netbuf ;
				//while ( ( numread < 4 ) && ( attempts ) )
				while ( ( numread < sizeof(uint16) ) )
				{
					if ( ( readval = m_sockNetplay.Recv( netptr+numread, (sizeof(uint16))-numread ) ) > 0 )
					{
						numread += readval ;
					}
					attempts-- ;
				}

				if ( numread == sizeof(uint16) )
				{
					memcpy( &padval, netbuf, sizeof(padval) ) ;
					newpadval = 1 ;
				}

				break ; 
			}
			default :
			{
				netptr++ ; 
				numread-- ;
				break ;
			}
		}

	}

	if ( m_state == IN_GAME )
	{
		if ( m_bAmServer )
		{
			m_joypadB = padval ;
			//m_lastPadValues[1] = padval ;
		}
		else
		{

		
		
		
			netbuf[0] = 'J' ;
			memcpy( netbuf+1, &(m_joyqueue[m_netbufptr]), sizeof( uint16 ) ) ;
			m_sockNetplay.Send( netbuf, 1+sizeof(uint16) ) ;

			m_joypadB = m_joyqueue[m_netbufptr] ;

			m_joyqueue[m_netbufptr] = m_joypadA ;

			m_netbufptr = ( m_netbufptr + 1 ) % m_netbuflen ;

			
			//netbuf[0] = 'J' ;
			//memcpy( netbuf+1, &(megad->pad[0]), sizeof( int ) ) ;
			//*((int*)(netbuf+1)) = megad->pad[0] ;
			//m_sockNetplay.Send( netbuf, 1+sizeof(int) ) ;
			//megad->pad[1] = megad->pad[0] ;


			m_joypadA = padval ;
			

		}
	}

	//fwrite( &(megad->pad[0]), sizeof(int), 1, padcapture ) ;
	//fwrite( &(megad->pad[1]), sizeof(int), 1, padcapture ) ;
	//fflush( padcapture ) ;

}
