﻿//////////////////////////////////////////////////////////////////////////
//                                                                      //
//      NES Pad                                                         //
//                                                           Norix      //
//                                               written     2001/02/22 //
//                                               last modify ----/--/-- //
//////////////////////////////////////////////////////////////////////////
#define	WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "typedef.h"
#include "macro.h"
#include "DebugOut.h"
#include "Config.h"
#include "DirectDraw.h"
#include "DirectInput.h"
#include <sys/timeb.h>

#include "nes.h"
#include "mmu.h"
#include "cpu.h"
#include "ppu.h"
#include "PAD.h"
#include "rom.h"

lua_State* luaState = NULL;
PAD::PAD( NES* parent ) : nes( parent )
{
	excontroller_select = 0;
	expad = NULL;
	bStrobe = FALSE;
	bSwapButton = FALSE;
	bSwapPlayer = FALSE;
	bZapperMode = FALSE;
	nVSSwapType = VS_TYPE0;

	padbit[0] = padbit[1] = padbit[2] = padbit[3] = 0;
	micbit = 0;

	padbitsync[0] = padbitsync[1] = padbitsync[2] = padbitsync[3] = 0;
	micbitsync = 0;
	memset( sTmPad, 0x00, sizeof(sTmPad) );
	memset( sTmPadScript, 0x00, sizeof(sTmPadScript) );
	memset( lua_time, 0x00, sizeof(lua_time) );
}

PAD::~PAD()
{
	DirectDraw.SetZapperMode( FALSE );
	DirectDraw.SetZapperDrawMode( FALSE );

	DELETEPTR( expad );
}

void	PAD::Reset()
{
	pad1bit = pad2bit = 0;
	bStrobe = FALSE;

//	if( !bZapperMode ) {
//		bZapperMode = FALSE;
//	}

	bBarcodeWorld = FALSE;

	ZEROMEMORY( padcnt, sizeof(padcnt) );

	// Select Extension Devices
	DWORD	crc = nes->rom->GetPROM_CRC();

	if( crc == 0xfbfc6a6c		// Adventures of Bayou Billy, The(E)
	 || crc == 0xcb275051		// Adventures of Bayou Billy, The(U)
	 || crc == 0xfb69c131		// Baby Boomer(Unl)(U)
	 || crc == 0xf2641ad0		// Barker Bill's Trick Shooting(U)
	 || crc == 0xbc1dce96		// Chiller (Unl)(U)
	 || crc == 0x90ca616d		// Duck Hunt(JUE)
	 || crc == 0x59e3343f		// Freedom Force(U)
	 || crc == 0x242a270c		// Gotcha!(U)
	 || crc == 0x7b5bd2de		// Gumshoe(UE)
	 || crc == 0x255b129c		// Gun Sight(J)
	 || crc == 0x8963ae6e		// Hogan's Alley(JU)
	 || crc == 0x51d2112f		// Laser Invasion(U)
	 || crc == 0x0a866c94		// Lone Ranger, The(U)
//	 || crc == 0xe4c04eea		// Mad City(J)
	 || crc == 0x9eef47aa		// Mechanized Attack(U)
	 || crc == 0xc2db7551		// Shooting Range(U)
	 || crc == 0x163e86c0		// To The Earth(U)
	 || crc == 0x42d893e4		// Operation Wolf(J)
	 || crc == 0x1388aeb9		// Operation Wolf(U)
	 || crc == 0x0d3cf705		// Wild Gunman(J)
	 || crc == 0x389960db ) {	// Wild Gunman(JUE)
		SetExController( EXCONTROLLER_ZAPPER );
	}
	if( crc == 0x35893b67		// Arkanoid(J)
	 || crc == 0x6267fbd1 ) {	// Arkanoid 2(J)
		SetExController( EXCONTROLLER_PADDLE );
	}
	if( crc == 0xff6621ce		// Hyper Olympic(J)
	 || crc == 0xdb9418e8		// Hyper Olympic(Tonosama Ban)(J)
	 || crc == 0xac98cd70 ) {	// Hyper Sports(J)
		SetExController( EXCONTROLLER_HYPERSHOT );
	}
	if( crc == 0xf9def527		// Family BASIC(Ver2.0)
	 || crc == 0xde34526e		// Family BASIC(Ver2.1a)
	 || crc == 0xf050b611		// Family BASIC(Ver3)
	 || crc == 0x3aaeed3f		// Family BASIC(Ver3)(Alt)
	 || crc == 0x868FCD89		// Family BASIC(Ver1.0)
	 || crc == 0x2D6B7E5A		// PLAYBOX BASIC(J) (Prototype_v0.0)
	 || crc == 0xDA03D908 ) {	// PLAYBOX BASIC (J)
		SetExController( EXCONTROLLER_KEYBOARD );
	}
	if( crc == 0x589b6b0d		// Supor Computer V3.0
	 || crc == 0x8b265862		// Supor English
	 || crc == 0x41401c6d		// Supor Computer V4.0
	 || crc == 0x82F1Fb96		// Supor Computer(Russia) V1.0
	 || crc == 0xd5d6eac4 ) {	// EDU(C) Computer
		SetExController( EXCONTROLLER_SUPOR_KEYBOARD );
		nes->SetVideoMode( TRUE );
	}
	if( crc == 0xc68363f6		// Crazy Climber(J)
	 || crc == 0x2989ead6		// Smash TV(U) [!]
	 || crc == 0x0b8f8128 ) {	// Smash TV(E) [!]
		SetExController( EXCONTROLLER_CRAZYCLIMBER );
	}
	if( crc == 0x20d22251 ) {	// Top rider(J)
		SetExController( EXCONTROLLER_TOPRIDER );
	}
	if( crc == 0x0cd00488 ) {	// Space Shadow(J)
		SetExController( EXCONTROLLER_SPACESHADOWGUN );
	}

	if( crc == 0x8c8fa83b		// Family Trainer - Athletic World (J)
	 || crc == 0x7e704a14		// Family Trainer - Jogging Race (J)
	 || crc == 0x2330a5d3 ) {	// Family Trainer - Rairai Kyonshiizu (J)
		SetExController( EXCONTROLLER_FAMILYTRAINER_A );
	}
	if( crc == 0xf8da2506		// Family Trainer - Aerobics Studio (J)
	 || crc == 0xca26a0f1		// Family Trainer - Dai Undoukai (J)
	 || crc == 0x28068b8c		// Family Trainer - Fuuun Takeshi Jou 2 (J)
	 || crc == 0x10bb8f9a		// Family Trainer - Manhattan Police (J)
	 || crc == 0xad3df455		// Family Trainer - Meiro Dai Sakusen (J)
	 || crc == 0x8a5b72c0		// Family Trainer - Running Stadium (J)
	 || crc == 0x59794f2d ) {	// Family Trainer - Totsugeki Fuuun Takeshi Jou (J)
		SetExController( EXCONTROLLER_FAMILYTRAINER_B );
	}
	if( crc == 0x9fae4d46		// Ide Yousuke Meijin no Jissen Mahjong (J)
	 || crc == 0x7b44fb2a ) {	// Ide Yousuke Meijin no Jissen Mahjong 2 (J)
		SetExController( EXCONTROLLER_MAHJANG );
	}
	if( crc == 0x786148b6 ) {	// Exciting Boxing (J)
		SetExController( EXCONTROLLER_EXCITINGBOXING );
	}
	if( crc == 0xc3c0811d		// Oeka Kids - Anpanman no Hiragana Daisuki (J)
	 || crc == 0x9d048ea4 ) {	// Oeka Kids - Anpanman to Oekaki Shiyou!! (J)
		SetExController( EXCONTROLLER_OEKAKIDS_TABLET );
	}
#if	0
	if( crc == 0xe792de94		// Best Play - Pro Yakyuu (New) (J)
	 || crc == 0xf79d684a		// Best Play - Pro Yakyuu (Old) (J)
	 || crc == 0xc2ef3422		// Best Play - Pro Yakyuu 2 (J)
	 || crc == 0x974e8840		// Best Play - Pro Yakyuu '90 (J)
	 || crc == 0xb8747abf		// Best Play - Pro Yakyuu Special (J)
	 || crc == 0x9fa1c11f		// Castle Excellent (J)
	 || crc == 0x0b0d4d1b		// Derby Stallion - Zenkoku Ban (J)
	 || crc == 0x728c3d98		// Downtown - Nekketsu Monogatari (J)
	 || crc == 0xd68a6f33		// Dungeon Kid (J)
	 || crc == 0x3a51eb04		// Fleet Commander (J)
	 || crc == 0x7c46998b		// Haja no Fuuin (J)
	 || crc == 0x7e5d2f1a		// Itadaki Street - Watashi no Mise ni Yottette (J)
	 || crc == 0xcee5857b		// Ninjara Hoi! (J)
	 || crc == 0x50ec5e8b		// Wizardry - Legacy of Llylgamyn (J)
	 || crc == 0x343e9146		// Wizardry - Proving Grounds of the Mad Overlord (J)
	 || crc == 0x33d07e45 ) {	// Wizardry - The Knight of Diamonds (J)
		SetExController( EXCONTROLLER_TURBOFILE );
	}
#endif

	if( crc == 0x67898319 ) {	// Barcode World (J)
		bBarcodeWorld = TRUE;
	}

	// VS-Unisystem
	if( nes->rom->IsVSUNISYSTEM() ) {
		if( crc == 0xff5135a3		// VS Hogan's Alley
		 || crc == 0xed588f00		// VS Duck Hunt
		 || crc == 0x17ae56be ) {	// VS Freedom Force
			SetExController( EXCONTROLLER_VSZAPPER );
		} else {
			SetExController( EXCONTROLLER_VSUNISYSTEM );
		}
	}

	if( crc == 0x21b099f3 ) {	// Gyromite (JUE)
		SetExController( EXCONTROLLER_GYROMITE );
	}

//	if( crc == 0x4ee735c1 ) {	// Stack-Up (JU)
//		SetExController( EXCONTROLLER_STACKUP );
//	}
}

void	PAD::SetExController( INT type )
{
	excontroller_select = type;

	DELETEPTR( expad );

	bZapperMode = FALSE;
	DirectDraw.SetZapperMode( FALSE );
	DirectDraw.SetZapperDrawMode( FALSE );

	// ExPad Instance create
	switch( type ) {
		case	EXCONTROLLER_ZAPPER:
			expad = new EXPAD_Zapper( nes );
			bZapperMode = TRUE;
			DirectDraw.SetZapperMode( TRUE );
			DirectDraw.SetZapperDrawMode( TRUE );
			break;
		case	EXCONTROLLER_PADDLE:
			expad = new EXPAD_Paddle( nes );
			DirectDraw.SetZapperMode( TRUE );
			break;
		case	EXCONTROLLER_HYPERSHOT:
			expad = new EXPAD_HyperShot( nes );
			break;
		case	EXCONTROLLER_KEYBOARD:
			expad = new EXPAD_Keyboard( nes );
			break;
		case	EXCONTROLLER_SUPOR_KEYBOARD:
			expad = new EXPAD_Supor_Keyboard( nes );
			break;
		case	EXCONTROLLER_CRAZYCLIMBER:
			expad = new EXPAD_CrazyClimber( nes );
			break;
		case	EXCONTROLLER_TOPRIDER:
			expad = new EXPAD_Toprider( nes );
			break;
		case	EXCONTROLLER_SPACESHADOWGUN:
			expad = new EXPAD_SpaceShadowGun( nes );
			bZapperMode = TRUE;
			DirectDraw.SetZapperMode( TRUE );
			DirectDraw.SetZapperDrawMode( TRUE );
			break;

		case	EXCONTROLLER_FAMILYTRAINER_A:
		case	EXCONTROLLER_FAMILYTRAINER_B:
			expad = new EXPAD_FamlyTrainer( nes );
			break;
		case	EXCONTROLLER_EXCITINGBOXING:
			expad = new EXPAD_ExcitingBoxing( nes );
			break;
		case	EXCONTROLLER_MAHJANG:
			expad = new EXPAD_Mahjang( nes );
			break;
		case	EXCONTROLLER_OEKAKIDS_TABLET:
			expad = new EXPAD_OekakidsTablet( nes );
			DirectDraw.SetZapperMode( TRUE );
			DirectDraw.SetZapperDrawMode( FALSE );
			break;
		case	EXCONTROLLER_TURBOFILE:
			expad = new EXPAD_TurboFile( nes );
			break;

		case	EXCONTROLLER_VSUNISYSTEM:
			expad = new EXPAD_VSUnisystem( nes );
			break;
		case	EXCONTROLLER_VSZAPPER:
			expad = new EXPAD_VSZapper( nes );
			bZapperMode = TRUE;
			DirectDraw.SetZapperMode( TRUE );
			DirectDraw.SetZapperDrawMode( TRUE );
			break;

		case	EXCONTROLLER_GYROMITE:
			expad = new EXPAD_Gyromite( nes );
			break;

// Buggy:(
//		case	EXCONTROLLER_STACKUP:
//			expad = new EXPAD_StackUp( nes );
//			break;

		default:
			break;
	}

	if( expad ) {
		expad->Reset();
	}
}

DWORD	PAD::GetSyncData()
{
DWORD	ret;

	ret = (DWORD)padbit[0]|((DWORD)padbit[1]<<8)|((DWORD)padbit[2]<<16)|((DWORD)padbit[3]<<24);
	ret |= (DWORD)micbit<<8;

	return	ret;
}

void	PAD::SetSyncData( DWORD data )
{
	micbit = (BYTE)((data&0x00000400)>>8);
	padbit[0] = (BYTE) data;
	padbit[1] = (BYTE)(data>> 8);
	padbit[2] = (BYTE)(data>>16);
	padbit[3] = (BYTE)(data>>24);
}

DWORD	PAD::GetSyncExData()
{
DWORD	data = 0;

	switch( excontroller_select ) {
		case	EXCONTROLLER_ZAPPER:
		case	EXCONTROLLER_PADDLE:
		case	EXCONTROLLER_SPACESHADOWGUN:
		case	EXCONTROLLER_OEKAKIDS_TABLET:
		case	EXCONTROLLER_VSZAPPER:
			{
			LONG	x, y;
				x = expad->GetSyncData( 0 );
				y = expad->GetSyncData( 1 );
				if( x == -1 || y == -1 ) {
					data = 0x80000000;
				} else {
					data = (x&0xFF)|((y&0xFF)<<8);
				}
			}
			if( excontroller_select != EXCONTROLLER_SPACESHADOWGUN ) {
				if( expad->GetSyncData( 2 ) )
					data |= 0x0010000;
			} else {
				data |= (DWORD)expad->GetSyncData( 2 )<<16;
			}
			break;
		case	EXCONTROLLER_CRAZYCLIMBER:
			data = (DWORD)expad->GetSyncData( 0 );
			break;
		case	EXCONTROLLER_TOPRIDER:
			data = (DWORD)expad->GetSyncData( 0 );
			break;
		case	EXCONTROLLER_FAMILYTRAINER_A:
		case	EXCONTROLLER_FAMILYTRAINER_B:
			data = (DWORD)expad->GetSyncData( 0 );
			break;
		case	EXCONTROLLER_EXCITINGBOXING:
			data = (DWORD)expad->GetSyncData( 0 );
			break;
		case	EXCONTROLLER_MAHJANG:
			data = (DWORD)expad->GetSyncData( 0 );
			break;

		default:
			break;
	}
	return	data;
}

void	PAD::SetSyncExData( DWORD data )
{
//DEBUGOUT( "PAD::SetSyncExData\n" );
	switch( excontroller_select ) {
		case	EXCONTROLLER_ZAPPER:
		case	EXCONTROLLER_PADDLE:
		case	EXCONTROLLER_SPACESHADOWGUN:
		case	EXCONTROLLER_OEKAKIDS_TABLET:
		case	EXCONTROLLER_VSZAPPER:
			{
			LONG	x, y;
				if( data & 0x80000000 ) {
					x = -1;
					y = -1;
				} else {
					x = data & 0xFF;
					y = (data&0xFF00)>>8;
				}
				expad->SetSyncData( 0, x );
				expad->SetSyncData( 1, y );
				nes->SetZapperPos( x, y );
				DirectDraw.SetZapperPos( x, y );
			}
			if( excontroller_select != EXCONTROLLER_SPACESHADOWGUN ) {
				if( data & 0x0010000 )
					expad->SetSyncData( 2, 1 );
				else
					expad->SetSyncData( 2, 0 );
			} else {
				expad->SetSyncData( 2, (BYTE)(data>>16) );
			}
			break;
		case	EXCONTROLLER_CRAZYCLIMBER:
			expad->SetSyncData( 0, (LONG)data );
			break;
		case	EXCONTROLLER_TOPRIDER:
			expad->SetSyncData( 0, (LONG)data );
			break;
		case	EXCONTROLLER_FAMILYTRAINER_A:
		case	EXCONTROLLER_FAMILYTRAINER_B:
			expad->SetSyncData( 0, (LONG)data );
			break;
		case	EXCONTROLLER_EXCITINGBOXING:
			expad->SetSyncData( 0, (LONG)data );
			break;
		case	EXCONTROLLER_MAHJANG:
			expad->SetSyncData( 0, (LONG)data );
			break;
		default:
			break;
	}
}

void	PAD::Sync()
{
	padbit[0] = SyncSub( 0 );
	padbit[1] = SyncSub( 1 );
	padbit[2] = SyncSub( 2 );
	padbit[3] = SyncSub( 3 );

	// Mic
	micbit = 0;
	if( Config.ButtonCheck( 1, 10 ) ) micbit |= 4;

	// For Excontroller
	if( expad ) {
		expad->Sync();
	}

	// For NSF
	NsfSub();
}

void	PAD::VSync()
{
	padbitsync[0] = padbit[0];
	padbitsync[1] = padbit[1];
	padbitsync[2] = padbit[2];
	padbitsync[3] = padbit[3];
	micbitsync = micbit;
}

static	INT	ren30fps[] = {
	1, 0
};
static	INT	ren20fps[] = {
	1, 1, 0
};
static	INT	ren15fps[] = {
	1, 1, 0, 0
};
static	INT	ren10fps[] = {
	1, 1, 1, 0, 0, 0
};

static	INT	renmask[] = {
	6, 4, 3, 2,
};
static	INT*	rentbl[] = {
	ren10fps, ren15fps, ren20fps, ren30fps
};

BYTE	PAD::SyncSub( INT no )
{
WORD	bit = 0;

	// Up
if( Config.ButtonCheck( no, 0 ) ){
	bit |= 1<<4;
}
	// Down
	if( Config.ButtonCheck( no, 1 ) ) bit |= 1<<5;
	// Left
	if( Config.ButtonCheck( no, 2 ) ) bit |= 1<<6;
	// Right
	if( Config.ButtonCheck( no, 3 ) ) bit |= 1<<7;

	// A
	if( Config.ButtonCheck( no, 4 ) ) bit |= 1<<0;
	// B
	if( Config.ButtonCheck( no, 5 ) ) bit |= 1<<1;

	// A,B Rapid
	if( Config.ButtonCheck( no, 6 ) ) bit |= 1<<8;
	if( Config.ButtonCheck( no, 7 ) ) bit |= 1<<9;

	// Select
	if( Config.ButtonCheck( no, 8 ) ) bit |= 1<<2;
	// Start
	if( Config.ButtonCheck( no, 9 ) ) bit |= 1<<3;

	// COMLOGF(RT_D_DEBUG, "bit[%08X]",bit);
	// lua1
	if( Config.ButtonCheck( no, 32 ) ){
		bit |= 1<<10;
		// for( int i=0;i<64;i++){
		// 	COMLOGF(RT_D_DEBUG, "Config.controller.nButton[nNo][%d]=[%08X]",i,Config.controller.nButton[no][i]);
		// }
	}
	// lua2
	if( Config.ButtonCheck( no, 33 ) ) bit |= 1<<11;
	// lua3
	if( Config.ButtonCheck( no, 34 ) ) bit |= 1<<12;
	// lua4
	if( Config.ButtonCheck( no, 35 ) ) bit |= 1<<13;
	// COMLOGF(RT_D_DEBUG, "bit[%08X]",bit);
	lua_script(no,bit);

	logging(no,bit);

	// 同時入力を禁止する
//	if( (bit&((1<<4)|(1<<5))) == ((1<<4)|(1<<5)) )
//		bit &= ~((1<<4)|(1<<5));
	if( (bit&((1<<6)|(1<<7))) == ((1<<6)|(1<<7)) )
		bit &= ~((1<<6)|(1<<7));

	// A rapid setup
	if( bit&(1<<8) ) {
		INT	spd = Config.controller.nRapid[no][0];
		if( spd >= 3 ) spd = 3;
		INT*	tbl = rentbl[spd];

		if( padcnt[no][0] >= renmask[spd] )
			padcnt[no][0] = 0;

		if( tbl[padcnt[no][0]] )
			bit |= (1<<0);
		else
			bit &= ~(1<<0);

		padcnt[no][0]++;
	} else {
		padcnt[no][0] = 0;
	}
	// B rapid setup
	if( bit&(1<<9) ) {
		INT	spd = Config.controller.nRapid[no][1];
		if( spd >= 3 ) spd = 3;
		INT*	tbl = rentbl[spd];

		if( padcnt[no][1] >= renmask[spd] )
			padcnt[no][1] = 0;

		if( tbl[padcnt[no][1]] )
			bit |= (1<<1);
		else
			bit &= ~(1<<1);

		padcnt[no][1]++;
	} else {
		padcnt[no][1] = 0;
	}

	return	(BYTE)(bit&0xFF);
}

void	PAD::Strobe()
{
	// For VS-Unisystem
	if( nes->rom->IsVSUNISYSTEM() ) {
		DWORD	pad1 = (DWORD)padbitsync[0] & 0xF3;
		DWORD	pad2 = (DWORD)padbitsync[1] & 0xF3;
		DWORD	st1  = ((DWORD)padbitsync[0] & 0x08)>>3;
		DWORD	st2  = ((DWORD)padbitsync[1] & 0x08)>>3;

		switch( nVSSwapType ) {
			case	VS_TYPE0:
				pad1bit = pad1 | (st1<<2);
				pad2bit = pad2 | (st2<<2);
				break;
			case	VS_TYPE1:
				pad1bit = pad2 | (st1<<2);
				pad2bit = pad1 | (st2<<2);
				break;
			case	VS_TYPE2:
				pad1bit = pad1 | (st1<<2) | (st2<<3);
				pad2bit = pad2;
				break;
			case	VS_TYPE3:
				pad1bit = pad2 | (st1<<2) | (st2<<3);
				pad2bit = pad1;
				break;
			case	VS_TYPE4:
				pad1bit = pad1 | (st1<<2) | 0x08;	// 0x08=Start Protect
				pad2bit = pad2 | (st2<<2) | 0x08;	// 0x08=Start Protect
				break;
			case	VS_TYPE5:
				pad1bit = pad2 | (st1<<2) | 0x08;	// 0x08=Start Protect
				pad2bit = pad1 | (st2<<2) | 0x08;	// 0x08=Start Protect
				break;
			case	VS_TYPE6:
				pad1bit = pad1 | (st1<<2) | (((DWORD)padbitsync[0] & 0x04)<<1);
				pad2bit = pad2 | (st2<<2) | (((DWORD)padbitsync[1] & 0x04)<<1);
				break;
			case	VS_TYPEZ:
				pad1bit = 0;
				pad2bit = 0;
				break;
		}

		// Coin 2と被る為に消す
		micbit  = 0;
	} else {
		if( Config.emulator.bFourPlayer ) {
		// NES type
			pad1bit = (DWORD)padbitsync[0] | ((DWORD)padbitsync[2]<<8) | 0x00080000;
			pad2bit = (DWORD)padbitsync[1] | ((DWORD)padbitsync[3]<<8) | 0x00040000;
		} else {
		// Famicom type
			pad1bit = (DWORD)padbitsync[0];
			pad2bit = (DWORD)padbitsync[1];
		}
	}
	pad3bit = (DWORD)padbitsync[2];
	pad4bit = (DWORD)padbitsync[3];
}

BYTE	PAD::Read( WORD addr )
{
BYTE	data = 0x00;

	if( addr == 0x4016 ) {
		data = (BYTE)pad1bit&1;
		pad1bit>>=1;
		data |= ((BYTE)pad3bit&1)<<1;
		pad3bit>>=1;
		// Mic
		if( !nes->rom->IsVSUNISYSTEM() ) {
			data |= micbitsync;
		}
		if( expad ) {
			data |= expad->Read4016();
		}
	}
	if( addr == 0x4017 ) {
		data = (BYTE)pad2bit&1;
		pad2bit>>=1;
		data |= ((BYTE)pad4bit&1)<<1;
		pad4bit>>=1;

		if( expad ) {
			data |= expad->Read4017();
//DEBUGOUT( "4017:%02X\n", data );
		}

		if( bBarcodeWorld ) {
			data |= nes->Barcode2();
		}
	}

	return	data;
}

void	PAD::Write( WORD addr, BYTE data )
{
	if( addr == 0x4016 ) {
		if( data&0x01 ) {
			bStrobe = TRUE;
		} else if( bStrobe ) {
			bStrobe = FALSE;

			Strobe();
			if( expad ) {
				expad->Strobe();
			}
		}

		if( expad ) {
			expad->Write4016( data );
		}
	}
	if( addr == 0x4017 ) {
		if( expad ) {
			expad->Write4017( data );
		}
	}
}

void	PAD::NsfSub()
{
	nsfbit = 0;

	// Play
	if( Config.ButtonCheck( 0, Config.controller.nNsfButton ) ) nsfbit |= 1<<0;
	// Stop
	if( Config.ButtonCheck( 1, Config.controller.nNsfButton ) ) nsfbit |= 1<<1;

	// Number -1
	if( Config.ButtonCheck( 2, Config.controller.nNsfButton ) ) nsfbit |= 1<<2;
	// Number +1
	if( Config.ButtonCheck( 3, Config.controller.nNsfButton ) ) nsfbit |= 1<<3;
	// Number -16
	if( Config.ButtonCheck( 4, Config.controller.nNsfButton ) ) nsfbit |= 1<<4;
	// Number +16
	if( Config.ButtonCheck( 5, Config.controller.nNsfButton ) ) nsfbit |= 1<<5;

	// 同時入力を禁止する
	if( (nsfbit&((1<<2)|(1<<3))) == ((1<<2)|(1<<3)) )
		nsfbit &= ~((1<<2)|(1<<3));
	if( (nsfbit&((1<<4)|(1<<5))) == ((1<<4)|(1<<5)) )
		nsfbit &= ~((1<<4)|(1<<5));
}

void	PAD::logging( INT no, WORD _bit )
{
	_timeb  curTime;
	_ftime(&curTime);
	DWORD ms_tmp= curTime.time*1000 + curTime.millitm;
	// COMLOGF(RT_D_DEBUG, "no(%d),_bit[%08X],ms_tmp(%u)",no,_bit,ms_tmp);
	WORD xor_bit=_bit^sTmPad[no].bit;
	if ( xor_bit ){

		//int milli = curTime.tv_usec / 1000;
		// int nMilli = curTime.millitm;
		// struct tm *pTm = localtime(&curTime.time);
		// COMLOGF(RT_D_DEBUG, "xor_bit[%08X],bit_bak[%08X],bit[%08X],",xor_bit,bit_bak,bit);
		for (int i=0;i<10; i++ ){
			if ( xor_bit&(1<<i) ){
				if ( _bit&(1<<i) ){
					sTmPad[no].dwMilliseconds[i]=ms_tmp;
					COMLOGF(RT_D_DEBUG, "pad no(%d) pos[%u]:(%u) xor_bit[%08X],bit_bak[%08X],_bit[%08X]  start",no,i,ms_tmp,xor_bit,sTmPad[no].bit,_bit);
				}
				else{
					DWORD delta=ms_tmp - sTmPad[no].dwMilliseconds[i];
					COMLOGF(RT_D_DEBUG, "pad no(%d) pos[%u]:(%u)-(%u)=time(%d) xor_bit[%08X],bit_bak[%08X],_bit[%08X] end",no,i,ms_tmp,sTmPad[no].dwMilliseconds[i],delta,xor_bit,sTmPad[no].bit,_bit);
				}
			}
		}
	}
	sTmPad[no].bit=_bit;
}


BYTE	PAD::SyncSubLogging( INT no )
{
WORD	bit = 0;

	// Up
if( Config.ButtonCheckLogging( no, 0 ) ){
	bit |= 1<<4;
}
	// Down
	if( Config.ButtonCheckLogging( no, 1 ) ) bit |= 1<<5;
	// Left
	if( Config.ButtonCheckLogging( no, 2 ) ) bit |= 1<<6;
	// Right
	if( Config.ButtonCheckLogging( no, 3 ) ) bit |= 1<<7;

	// A
	if( Config.ButtonCheckLogging( no, 4 ) ) bit |= 1<<0;
	// B
	if( Config.ButtonCheckLogging( no, 5 ) ) bit |= 1<<1;

	// A,B Rapid
	if( Config.ButtonCheckLogging( no, 6 ) ) bit |= 1<<8;
	if( Config.ButtonCheckLogging( no, 7 ) ) bit |= 1<<9;

	// Select
	if( Config.ButtonCheckLogging( no, 8 ) ) bit |= 1<<2;
	// Start
	if( Config.ButtonCheckLogging( no, 9 ) ) bit |= 1<<3;

	logging(no,bit);

	return	(BYTE)(bit&0xFF);
}

void	PAD::lua_script( INT no, WORD &_bit )
{

	DWORD ms_tmp= ::timeGetTime() ;
	// COMLOGF(RT_D_DEBUG, "no(%d),_bit[%08X],ms_tmp(%u)",no,_bit,ms_tmp);
	if ( (sTmPadScript[no].dwMilliseconds[10]<ms_tmp)&& oPadProg[no].size()==0  ){
		for (int i=10;i<14; i++ ){
			// if ( (ms_tmp - lua_time[i-10]) > 300  ){
				if ( _bit&(1<<i) ){
					lua_time[i-10]=ms_tmp;
					oPadProg[no].insert( oPadProg[no].end(),Config.controller.oAllPadProg[no][i-10].begin(), Config.controller.oAllPadProg[no][i-10].end() );
					COMLOGF(RT_D_DEBUG, "no(%d),i(%d),ms_tmp(%u),oPadProg[no].size()=(%d)",no,i,ms_tmp,oPadProg[no].size());
					break;
				}
			// }
		}
	}

	if ( sTmPadScript[no].dwMilliseconds[10] < ms_tmp  ){
		while ( oPadProg[no].size() > 0 ){
			int pos = oPadProg[no][0].pos;
			pos = pos < 10 ? pos : 10;
			sTmPadScript[no].bit |= (1<<pos);
			sTmPadScript[no].dwMilliseconds[pos]= ms_tmp + oPadProg[no][0].dwMilliseconds;
			COMLOGF(RT_D_DEBUG, "no(%d),pos(%d),bit[%08X],dwMilliseconds[pos](%u),ms_tmp(%u),dwMilliseconds(%u)",no,pos,sTmPadScript[no].bit,sTmPadScript[no].dwMilliseconds[pos],ms_tmp,oPadProg[no][0].dwMilliseconds);
			oPadProg[no].erase (oPadProg[no].begin());
			if ( pos > 9 ){
				break;
			}
		}
	}
	
	for (int j=0;j<10; j++ ) {
		if ( sTmPadScript[no].bit & (1<<j) ){
			if ( sTmPadScript[no].dwMilliseconds[j] < ms_tmp ){
				sTmPadScript[no].bit &= ~(1<<j) ;
				_bit &= ~(1<<j) ;
				sTmPadScript[no].dwMilliseconds[j] =0;
			}
		}
	}
	
	if ( sTmPadScript[no].bit ){
		_bit |= sTmPadScript[no].bit ;
		_bit &= 0x3FF ;
		// COMLOGF(RT_D_DEBUG, "no(%d),_bit[%08X],ms_tmp(%u)",no,_bit,ms_tmp);
	}
	return;
}

// void	PAD::SetPadProg( INT no){
// 	oPadProg[no].erase (oPadProg[no].begin());
// }

#include "EXPAD_Zapper.cpp"
#include "EXPAD_Paddle.cpp"
#include "EXPAD_HyperShot.cpp"
#include "EXPAD_Keyboard.cpp"
#include "EXPAD_Supor_Keyboard.cpp"
#include "EXPAD_CrazyClimber.cpp"
#include "EXPAD_Toprider.cpp"
#include "EXPAD_SpaceShadowGun.cpp"

#include "EXPAD_FamlyTrainer.cpp"
#include "EXPAD_ExcitingBoxing.cpp"
#include "EXPAD_Mahjang.cpp"
#include "EXPAD_OekakidsTablet.cpp"
#include "EXPAD_TurboFile.cpp"

#include "EXPAD_VSUnisystem.cpp"
#include "EXPAD_VSZapper.cpp"

#include "EXPAD_Gyromite.cpp"
