AxibugEmuOnline/virtuanessrc097-master/CheatDlg.cpp

1566 lines
75 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// チートダイアログクラス
//
//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <commdlg.h>
#include <mbstring.h>
#include <string>
using namespace std;
#include "VirtuaNESres.h"
#include "DebugOut.h"
#include "App.h"
#include "Pathlib.h"
#include "Config.h"
#include "Wnd.h"
#include "CheatDlg.h"
#include "EmuThread.h"
//
// サーチダイアログ
//
DLG_MESSAGE_BEGIN(CSearchDlg)
DLG_ON_MESSAGE( WM_INITDIALOG, OnInitDialog )
DLG_ON_MESSAGE( WM_ACTIVATE, OnActivate )
DLG_ON_MESSAGE( WM_CLOSE, OnClose )
DLG_ON_MESSAGE( WM_CONTEXTMENU, OnContextMenu )
DLG_COMMAND_BEGIN()
//DLG_ON_COMMAND( IDOK, OnOK )
//DLG_ON_COMMAND( IDCANCEL, OnCancel )
DLG_ON_COMMAND( IDC_SCH_START, OnStart )
DLG_ON_COMMAND( IDC_SCH_UPDATE, OnUpdate )
DLG_ON_COMMAND( IDC_SCH_UNDO, OnUndo )
DLG_ON_COMMAND_RANGE( IDC_SCH_RADIX_DEC, IDC_SCH_RADIX_HEX, OnRadixCommand )
DLG_ON_COMMAND_RANGE( IDC_SCH_LENGTH_1BYTE, IDC_SCH_LENGTH_4BYTE, OnLengthCommand )
DLG_ON_COMMAND_RANGE( IDC_SCH_EQUAL, IDC_SCH_GRATEREQUAL, OnSearchCommand )
DLG_ON_COMMAND( IDC_SCH_SEARCH, OnSearchData )
DLG_ON_COMMAND( IDC_SCH_WRITE, OnWriteData )
DLG_ON_COMMAND( ID_SCH_APPEND, OnCodeAppend )
//DLG_ON_COMMAND( IDC_VER_WEBSITE, OnWebsite )
DLG_COMMAND_END()
// Notify メッセージ
DLG_NOTIFY_BEGIN()
DLG_ON_NOTIFY( IDC_SCH_RESULT_LIST, NM_DBLCLK, OnDoubleClickListView )
DLG_NOTIFY_END()
DLG_MESSAGE_END()
BOOL CSearchDlg::Create( HWND hWndParent )
{
m_hMenu = NULL;
m_bShortCutDisable = FALSE;
m_hWnd = ::CreateDialogParam( CApp::GetPlugin(), MAKEINTRESOURCE(IDD_SEARCH),
hWndParent, g_DlgProc, (LPARAM)this );
if( !m_hWnd )
return FALSE;
// モードレスダイアログリストに加える
CWndList::Add( this );
return TRUE;
}
void CSearchDlg::Destroy()
{
if( m_hWnd ) {
// 位置保存
::GetWindowRect( m_hWnd, &Config.general.rcSearchDlgPos );
// メニュー削除
if( m_hMenu )
::DestroyMenu( m_hMenu );
m_hMenu = NULL;
// モードレスダイアログリストから削除
CWndList::Del( this );
::DestroyWindow( m_hWnd );
m_hWnd = NULL;
}
}
void CSearchDlg::OnListUpdate()
{
HWND hWndCtrl = ::GetDlgItem( m_hWnd, IDC_SCH_RESULT_LIST );
ListView_DeleteAllItems( hWndCtrl );
INT i;
DWORD data;
CHAR szStr[256], szTemp[256];
INT index;
LVITEM lvitem;
lvitem.mask = LVIF_TEXT|LVIF_PARAM;
lvitem.iSubItem = 0;
index = 0;
if( m_nRadix == 10 ) {
::wsprintf( szTemp, "%%lu" );
} else {
::wsprintf( szTemp, "%%0%dX", (m_nLength+1)*2 );
}
::SendMessage( hWndCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0 );
if( IsBTNCHECK( IDC_SCH_AREA_RAM ) ) {
for( i = 0; i < 0x0800-m_nLength; i++ ) {
if( m_Result.RAM_F[i] ) {
// Address
::wsprintf( szStr, "%04X", i );
lvitem.pszText = szStr;
lvitem.iItem = index;
lvitem.lParam = (LPARAM)i;
ListView_InsertItem( hWndCtrl, &lvitem );
// OLD
data = GetSearchMemoryOld( m_nLength, i );
::wsprintf( szStr, szTemp, data );
ListView_SetItemText( hWndCtrl, index, 1, (LPSTR)szStr );
// NEW
data = GetSearchMemory( m_nLength, i );
::wsprintf( szStr, szTemp, data );
ListView_SetItemText( hWndCtrl, index, 2, (LPSTR)szStr );
index++;
}
}
}
if( IsBTNCHECK( IDC_SCH_AREA_SRAM ) ) {
for( i = 0; i < 0x2000-m_nLength; i++ ) {
if( m_Result.SRAM_F[i] ) {
// Address
::wsprintf( szStr, "%04X", i+0x6000 );
lvitem.pszText = szStr;
lvitem.iItem = index;
lvitem.lParam = (LPARAM)(i+0x6000);
ListView_InsertItem( hWndCtrl, &lvitem );
// OLD
data = GetSearchMemoryOld( m_nLength, i+0x6000 );
::wsprintf( szStr, szTemp, data );
ListView_SetItemText( hWndCtrl, index, 1, (LPSTR)szStr );
// NEW
data = GetSearchMemory( m_nLength, i+0x6000 );
::wsprintf( szStr, szTemp, data );
ListView_SetItemText( hWndCtrl, index, 2, (LPSTR)szStr );
index++;
}
}
}
::SendMessage( hWndCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0 );
::InvalidateRect( hWndCtrl, NULL, TRUE );
}
DWORD CSearchDlg::GetNesMemory( INT length, DWORD addr )
{
DWORD data = 0;
for( INT i = 0; i <= length; i++ ) {
data |= (DWORD)Emu.GetNES()->Read( (WORD)addr+i )*(1<<(i*8));
}
return data;
}
DWORD CSearchDlg::GetSearchMemory( INT length, DWORD addr )
{
BYTE* lpRAM;
if( addr < 0x0800 ) {
lpRAM = m_Result.RAM_N;
} else if( addr < 0x8000 ) {
lpRAM = m_Result.SRAM_N - 0x6000;
}
DWORD data = 0;
for( INT i = 0; i <= length; i++ ) {
data |= (DWORD)lpRAM[ (WORD)addr+i ]*(1<<(i*8));
}
return data;
}
DWORD CSearchDlg::GetSearchMemoryOld( INT length, DWORD addr )
{
BYTE* lpRAM;
if( addr < 0x0800 ) {
lpRAM = m_Result.RAM_O;
} else if( addr < 0x8000 ) {
lpRAM = m_Result.SRAM_O - 0x6000;
}
DWORD data = 0;
for( INT i = 0; i <= length; i++ ) {
data |= (DWORD)lpRAM[ (WORD)addr+i ]*(1<<(i*8));
}
return data;
}
BOOL CSearchDlg::CompareData( INT type, DWORD dataA, DWORD dataB )
{
switch( type ) {
case 0: // EQUAL
if( dataA == dataB )
return TRUE;
break;
case 1: // NOTEQUAL
if( dataA != dataB )
return TRUE;
break;
case 2: // LESS
if( dataA < dataB )
return TRUE;
break;
case 3: // GRATER
if( dataA > dataB )
return TRUE;
break;
case 4: // LESSEQUAL
if( dataA <= dataB )
return TRUE;
break;
case 5: // GRATEREQUAL
if( dataA >= dataB )
return TRUE;
break;
}
return FALSE;
}
BOOL CSearchDlg::CompareRange( INT length, DWORD dataA, DWORD dataB, DWORD range )
{
DWORD dmin, dmax;
switch( length ) {
case 0: // 1byte
dataA &= 0x000000FF;
dataB &= 0x000000FF;
range &= 0x000000FF;
dmin = dataB-range;
dmax = dataB+range;
if( dataB < dmin )
dmin = 0;
if( dataB > dmax )
dmax = 0xFF;
break;
case 1: // 2byte
dataA &= 0x0000FFFF;
dataB &= 0x0000FFFF;
range &= 0x0000FFFF;
dmin = dataB-range;
dmax = dataB+range;
if( dataB < dmin )
dmin = 0;
if( dataB > dmax )
dmax = 0xFFFF;
break;
case 2: // 3byte
dataA &= 0x00FFFFFF;
dataB &= 0x00FFFFFF;
range &= 0x00FFFFFF;
dmin = dataB-range;
dmax = dataB+range;
if( dataB < dmin )
dmin = 0;
if( dataB > dmax )
dmax = 0xFFFFFF;
break;
case 3: // 4byte
// dataA &= 0xFFFFFFFF;
// dataB &= 0xFFFFFFFF;
// range &= 0xFFFFFFFF;
dmin = dataB-range;
dmax = dataB+range;
if( dataB < dmin )
dmin = 0;
if( dataB > dmax )
dmax = 0xFFFFFFFF;
break;
}
if( dataA >= dmin && dataA <= dmax )
return TRUE;
return FALSE;
}
DLGMSG CSearchDlg::OnInitDialog( DLGMSGPARAM )
{
// DEBUGOUT( "CSearchDlg::OnInitDialog\n" );
m_nRadix = 10;
m_nLength = 0;
HWND hWndCtrl;
INT i, j;
CHAR szStr[256];
// 位置修正
if( Config.general.rcSearchDlgPos.right-Config.general.rcSearchDlgPos.left != 0
&& Config.general.rcSearchDlgPos.bottom-Config.general.rcSearchDlgPos.top != 0 ) {
::SetWindowPos( m_hWnd, HWND_NOTOPMOST, Config.general.rcSearchDlgPos.left, Config.general.rcSearchDlgPos.top,
0, 0, SWP_NOSIZE | SWP_NOZORDER );
}
// サーチ結果初期化
::memset( &m_Result, 0, sizeof(m_Result) );
::memset( &m_ResultOld, 0, sizeof(m_ResultOld) );
// 基数ラジオボタン
BTNCHECK( IDC_SCH_RADIX_DEC, TRUE );
// BTNCHECK( IDC_SCH_RADIX_HEX, FALSE );
// データ長ラジオボタン
BTNCHECK( IDC_SCH_LENGTH_1BYTE, TRUE );
// BTNCHECK( IDC_SCH_LENGTH_2BYTE, FALSE );
// BTNCHECK( IDC_SCH_LENGTH_3BYTE, FALSE );
// BTNCHECK( IDC_SCH_LENGTH_4BYTE, FALSE );
// 検索範囲チェックボックス
BTNCHECK( IDC_SCH_AREA_RAM, TRUE );
BTNCHECK( IDC_SCH_AREA_SRAM, FALSE );
BTNCHECK( IDC_SCH_AREA_EXRAM, FALSE );
// リストビュー
hWndCtrl = ::GetDlgItem( m_hWnd, IDC_SCH_RESULT_LIST );
ListView_SetExtendedListViewStyle( hWndCtrl, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES );
ListView_DeleteAllItems( hWndCtrl );
ListView_SetItemCount( hWndCtrl, 16384 );
// ヘッダコントロールの設定
LVCOLUMN lvColumn;
lvColumn.mask = LVCF_FMT|LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH;
lvColumn.fmt = LVCFMT_RIGHT;
lvColumn.pszText = szStr;
RECT rc;
::GetClientRect( hWndCtrl, &rc );
INT nWidth = RCWIDTH(rc) - ::GetSystemMetrics( SM_CXVSCROLL );
CApp::LoadString( IDS_CHT_ADDRESS, szStr, sizeof(szStr) );
lvColumn.iSubItem = 0;
lvColumn.cx = nWidth*2/8;
ListView_InsertColumn( hWndCtrl, 0, &lvColumn );
CApp::LoadString( IDS_CHT_DATA_OLD, szStr, sizeof(szStr) );
lvColumn.iSubItem = 1;
lvColumn.cx = nWidth*3/8;
ListView_InsertColumn( hWndCtrl, 1, &lvColumn );
CApp::LoadString( IDS_CHT_DATA_NOW, szStr, sizeof(szStr) );
lvColumn.iSubItem = 2;
lvColumn.cx = nWidth*3/8;
ListView_InsertColumn( hWndCtrl, 2, &lvColumn );
// データ等設定
::SetDlgItemText( m_hWnd, IDC_SCH_DATA_EDIT, "0" );
::SetDlgItemText( m_hWnd, IDC_SCH_WADDR_EDIT, "0000" );
::SetDlgItemText( m_hWnd, IDC_SCH_WDATA_EDIT, "0" );
// Undoボタンをディセーブル
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_SCH_UNDO ), FALSE );
// 初期データ設定
for( i = 0; i < 0x0800; i++ ) {
m_Result.RAM_N[i] = m_Result.RAM_O[i] = Emu.GetNES()->Read( (WORD)i );
m_Result.RAM_F[i] = 1;
}
j = 0;
BYTE da = Emu.GetNES()->Read( 0x6000 );
for( i = 0; i < 0x2000; i++ ) {
m_Result.SRAM_N[i] = m_Result.SRAM_O[i] = Emu.GetNES()->Read( (WORD)i+0x6000 );
m_Result.SRAM_F[i] = 1;
if( m_Result.SRAM_N[i] != da )
j = 1;
}
// SRAMが使用されていたら自動でONに
if( j ) {
BTNCHECK( IDC_SCH_AREA_SRAM, TRUE );
}
// メニュー
m_hMenu = CApp::LoadMenu( IDR_SCH_MENU );
m_hSubMenu = ::GetSubMenu( m_hMenu, 0 );
OnListUpdate();
return TRUE;
}
DLGMSG CSearchDlg::OnActivate( DLGMSGPARAM )
{
// DEBUGOUT( "CSearchDlg::OnActivate\n" );
if( LOWORD(wParam) == WA_INACTIVE ) {
DEBUGOUT( "CSearchDlg::OnActivate:Inactive\n" );
if( !m_bShortCutDisable )
::PostMessage( CApp::GetHWnd(), WM_VNS_SHORTCUTENABLE, (WPARAM)TRUE, 0 );
if( Emu.IsRunning() )
Emu.Resume();
} else {
DEBUGOUT( "CSearchDlg::OnActivate:Active\n" );
::PostMessage( CApp::GetHWnd(), WM_VNS_SHORTCUTENABLE, (WPARAM)FALSE, 0 );
if( Emu.IsRunning() )
Emu.Pause();
}
return FALSE;
}
DLGMSG CSearchDlg::OnClose( DLGMSGPARAM )
{
// DEBUGOUT( "CSearchDlg::OnClose\n" );
::ShowWindow( m_hWnd, SW_HIDE ); // 非表示にするだけ
return TRUE;
}
DLGMSG CSearchDlg::OnContextMenu( DLGMSGPARAM )
{
// DEBUGOUT( "CSearchDlg::OnContextMenu\n" );
HWND hWndCtrl = ::GetDlgItem( m_hWnd, IDC_SCH_RESULT_LIST );
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
LVHITTESTINFO lvhti;
lvhti.pt = pt;
::ScreenToClient( hWndCtrl, &lvhti.pt );
INT nItem = ListView_HitTest( hWndCtrl, &lvhti );
//DEBUGOUT( "OnContextMenu nItem=%d\n", nItem );
if( nItem >= 0 ) {
CHAR szStr[256];
ListView_GetItemText( hWndCtrl, nItem, 0, szStr, sizeof(szStr) );
m_Address = (WORD)::strtoul( szStr, NULL, 16 );
::TrackPopupMenu( m_hSubMenu, TPM_LEFTALIGN|TPM_TOPALIGN, pt.x, pt.y, 0, m_hWnd, NULL );
}
return TRUE;
}
DLGCMD CSearchDlg::OnOK( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnOK\n" );
// ::EndDialog( m_hWnd, IDOK );
}
DLGCMD CSearchDlg::OnCancel( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnCancel\n" );
::ShowWindow( m_hWnd, SW_HIDE ); // 非表示にするだけ
}
DLGCMD CSearchDlg::OnRadixCommand( DLGCMDPARAM )
{
if( uID == IDC_SCH_RADIX_DEC )
m_nRadix = 10;
if( uID == IDC_SCH_RADIX_HEX )
m_nRadix = 16;
OnListUpdate();
}
DLGCMD CSearchDlg::OnLengthCommand( DLGCMDPARAM )
{
m_nLength = (INT)uID - IDC_SCH_LENGTH_1BYTE;
OnListUpdate();
}
DLGCMD CSearchDlg::OnStart( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnStart\n" );
INT i;
// Undoバッファにセーブ
m_ResultOld = m_Result;
// 今回データの初期化
::memset( &m_Result, 0, sizeof(m_Result) );
// データ検索候補の設定
if( IsBTNCHECK( IDC_SCH_AREA_RAM ) ) {
for( i = 0; i < 0x0800; i++ ) {
m_Result.RAM_N[i] = m_Result.RAM_O[i] = Emu.GetNES()->Read( (WORD)i );
m_Result.RAM_F[i] = 1;
}
}
if( IsBTNCHECK( IDC_SCH_AREA_SRAM ) ) {
for( i = 0; i < 0x2000; i++ ) {
m_Result.SRAM_N[i] = m_Result.SRAM_O[i] = Emu.GetNES()->Read( (WORD)i+0x6000 );
m_Result.SRAM_F[i] = 1;
}
}
OnListUpdate();
// Undoボタンをイネーブル
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_SCH_UNDO ), TRUE );
}
DLGCMD CSearchDlg::OnUpdate( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnUpdate\n" );
INT i;
// Undoバッファにセーブ
m_ResultOld = m_Result;
// データの更新
if( IsBTNCHECK( IDC_SCH_AREA_RAM ) ) {
for( i = 0; i < 0x0800; i++ ) {
m_Result.RAM_O[i] = m_Result.RAM_N[i];
m_Result.RAM_N[i] = Emu.GetNES()->Read( (WORD)i );
}
}
if( IsBTNCHECK( IDC_SCH_AREA_SRAM ) ) {
for( i = 0; i < 0x2000; i++ ) {
m_Result.SRAM_N[i] = m_Result.SRAM_O[i];
m_Result.SRAM_N[i] = Emu.GetNES()->Read( (WORD)i+0x6000 );
}
}
OnListUpdate();
// Undoボタンをイネーブル
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_SCH_UNDO ), TRUE );
}
DLGCMD CSearchDlg::OnUndo( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnUndo\n" );
// // Undo
m_Result = m_ResultOld;
OnListUpdate();
// Undoボタンをディセーブル
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_SCH_UNDO ), FALSE );
}
DLGCMD CSearchDlg::OnSearchCommand( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnSearchCommand\n" );
INT i;
INT type = (INT)uID - IDC_SCH_EQUAL;
// Undoバッファにセーブ
m_ResultOld = m_Result;
// テンポラリ
struct RESULT ResultTemp;
::memset( &ResultTemp, 0, sizeof(ResultTemp) );
// 候補の中から条件で検索する
if( IsBTNCHECK( IDC_SCH_AREA_RAM ) ) {
for( i = 0; i < 0x0800-m_nLength; i++ ) {
if( m_Result.RAM_F[i] ) {
if( CompareData( type, GetNesMemory( m_nLength, i ), GetSearchMemory( m_nLength, i ) ) ) {
ResultTemp.RAM_F[i] = 1;
}
}
}
// RAMの状態をコピー
for( i = 0; i < 0x0800; i++ ) {
ResultTemp.RAM_O[i] = m_Result.RAM_N[i];
ResultTemp.RAM_N[i] = Emu.GetNES()->Read( (WORD)i );
}
}
if( IsBTNCHECK( IDC_SCH_AREA_SRAM ) ) {
for( i = 0; i < 0x2000-m_nLength; i++ ) {
if( m_Result.SRAM_F[i] ) {
if( CompareData( type, GetNesMemory( m_nLength, i+0x6000 ), GetSearchMemory( m_nLength, i+0x6000 ) ) ) {
ResultTemp.SRAM_F[i] = 1;
}
}
}
// RAMの状態をコピー
for( i = 0; i < 0x2000; i++ ) {
ResultTemp.SRAM_O[i] = m_Result.SRAM_N[i];
ResultTemp.SRAM_N[i] = Emu.GetNES()->Read( (WORD)i+0x6000 );
}
}
// テンポラリデータをコピー
m_Result = ResultTemp;
OnListUpdate();
// Undoボタンをイネーブル
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_SCH_UNDO ), TRUE );
}
DLGCMD CSearchDlg::OnSearchData( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnSearchData\n" );
INT i;
DWORD data;
CHAR szStr[256];
// Undoバッファにセーブ
m_ResultOld = m_Result;
// データ/レンジの取得
::GetDlgItemText( m_hWnd, IDC_SCH_DATA_EDIT, szStr, sizeof(szStr) );
if( m_nRadix == 10 ) {
::GetDlgItemText( m_hWnd, IDC_SCH_DATA_EDIT, szStr, sizeof(szStr) );
data = (DWORD)::strtoul( szStr, NULL, 10 );
} else {
::GetDlgItemText( m_hWnd, IDC_SCH_DATA_EDIT, szStr, sizeof(szStr) );
data = (DWORD)::strtoul( szStr, NULL, 16 );
}
// テンポラリ
struct RESULT ResultTemp;
::memset( &ResultTemp, 0, sizeof(ResultTemp) );
// 候補の中からデータと範囲で検索する
if( IsBTNCHECK( IDC_SCH_AREA_RAM ) ) {
for( i = 0; i < 0x0800-m_nLength; i++ ) {
if( m_Result.RAM_F[i] ) {
if( CompareData( 0, GetNesMemory( m_nLength, i ), data ) ) {
ResultTemp.RAM_F[i] = 1;
}
}
}
// RAMの状態をコピー
for( i = 0; i < 0x0800; i++ ) {
ResultTemp.RAM_O[i] = m_Result.RAM_O[i];
ResultTemp.RAM_N[i] = Emu.GetNES()->Read( (WORD)i );
}
}
if( IsBTNCHECK( IDC_SCH_AREA_SRAM ) ) {
for( i = 0; i < 0x2000-m_nLength; i++ ) {
if( m_Result.SRAM_F[i] ) {
if( CompareData( 0, GetNesMemory( m_nLength, i+0x6000 ), data ) ) {
ResultTemp.SRAM_F[i] = 1;
}
}
}
// RAMの状態をコピー
for( i = 0; i < 0x2000; i++ ) {
ResultTemp.SRAM_O[i] = m_Result.SRAM_O[i];
ResultTemp.SRAM_N[i] = Emu.GetNES()->Read( (WORD)i+0x6000 );
}
}
// テンポラリデータをコピー
m_Result = ResultTemp;
OnListUpdate();
// Undoボタンをイネーブル
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_SCH_UNDO ), TRUE );
}
DLGCMD CSearchDlg::OnWriteData( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnWriteData\n" );
DWORD addr, data;
CHAR szStr[256];
// アドレス/データの取得
::GetDlgItemText( m_hWnd, IDC_SCH_WADDR_EDIT, szStr, sizeof(szStr) );
addr = (DWORD)::strtoul( szStr, NULL, 16 );
if( m_nRadix == 10 ) {
::GetDlgItemText( m_hWnd, IDC_SCH_WDATA_EDIT, szStr, sizeof(szStr) );
data = (DWORD)::strtoul( szStr, NULL, 10 );
} else {
::GetDlgItemText( m_hWnd, IDC_SCH_WDATA_EDIT, szStr, sizeof(szStr) );
data = (DWORD)::strtoul( szStr, NULL, 16 );
}
for( INT i = 0; i <= m_nLength; i++ ) {
Emu.GetNES()->Write( (WORD)(addr+i), data&0xFF );
data >>= 8;
}
}
DLGCMD CSearchDlg::OnCodeAppend( DLGCMDPARAM )
{
// DEBUGOUT( "CSearchDlg::OnCodeAppend\n" );
if( Emu.IsRunning() )
Emu.Pause();
CCheatCodeEditDlg dlg;
dlg.m_Code.enable = 1;
dlg.m_Code.address = m_Address;
dlg.m_Code.data = 0;
dlg.m_Code.length = m_nLength;
dlg.m_Code.type = CHEAT_TYPE_ALWAYS;
dlg.m_nRadix = m_nRadix;
m_bShortCutDisable = TRUE;
if( dlg.DoModal( m_hWnd ) == IDOK ) {
Emu.GetNES()->AddCheatCode( dlg.m_Code );
}
m_bShortCutDisable = FALSE;
if( Emu.IsRunning() )
Emu.Resume();
}
DLGNOTIFY CSearchDlg::OnDoubleClickListView( DLGNOTIFYPARAM )
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
//DEBUGOUT( "Column click!! I:%d S:%d\n", pNMListView->iItem, pNMListView->iSubItem );
CHAR szStr[256];
ListView_GetItemText( pNMHDR->hwndFrom, pNMListView->iItem, 0, szStr, sizeof(szStr) );
::SetDlgItemText( m_hWnd, IDC_SCH_WADDR_EDIT, szStr );
}
//
// チートコード編集ダイアログ
//
DLG_MESSAGE_BEGIN(CCheatCodeEditDlg)
DLG_ON_MESSAGE( WM_INITDIALOG, OnInitDialog )
DLG_COMMAND_BEGIN()
DLG_ON_COMMAND( IDOK, OnOK )
DLG_ON_COMMAND( IDCANCEL, OnCancel )
DLG_COMMAND_END()
DLG_MESSAGE_END()
INT CCheatCodeEditDlg::DoModal( HWND hWndParent )
{
return ::DialogBoxParam( CApp::GetPlugin(), MAKEINTRESOURCE(IDD_CODEEDIT),
hWndParent, g_DlgProc, (LPARAM)this );
}
DLGMSG CCheatCodeEditDlg::OnInitDialog( DLGMSGPARAM )
{
// DEBUGOUT( "CCheatCodeEditDlg::OnInitDialog\n" );
CHAR szStr[256], szTemp[256];
// アドレス
::wsprintf( szStr, "%04X", m_Code.address );
::SetDlgItemText( m_hWnd, IDC_CED_ADDR, szStr );
// データ
if( m_nRadix == 10 ) {
::wsprintf( szStr, "%d", m_Code.data );
} else {
::wsprintf( szTemp, "%%0%dX", (m_Code.length+1)*2 );
::wsprintf( szStr, szTemp, m_Code.data );
}
::SetDlgItemText( m_hWnd, IDC_CED_DATA, szStr );
// コメント
::SetDlgItemText( m_hWnd, IDC_CED_COMMENT, m_Code.comment.c_str() );
// ラジオボタン
BTNCHECK( (m_nRadix==10)?IDC_CED_RADIX_DEC:IDC_CED_RADIX_HEX, TRUE );
BTNCHECK( (IDC_CED_LENGTH_1BYTE+m_Code.length), TRUE );
if( m_Code.type == CHEAT_TYPE_ALWAYS ) {
BTNCHECK( IDC_CED_TYPE_ALWAYS, TRUE );
} else
if( m_Code.type == CHEAT_TYPE_ONCE ) {
BTNCHECK( IDC_CED_TYPE_ONCE, TRUE );
} else
if( m_Code.type == CHEAT_TYPE_GREATER ) {
BTNCHECK( IDC_CED_TYPE_GREATER, TRUE );
} else
if( m_Code.type == CHEAT_TYPE_LESS ) {
BTNCHECK( IDC_CED_TYPE_LESS, TRUE );
}
::PostMessage( CApp::GetHWnd(), WM_VNS_SHORTCUTENABLE, (WPARAM)FALSE, 0 );
return TRUE;
}
DLGCMD CCheatCodeEditDlg::OnOK( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeEditDlg::OnOK\n" );
CHAR szStr[256];
DWORD data;
::GetDlgItemText( m_hWnd, IDC_CED_DATA, szStr, sizeof(szStr) );
if( IsBTNCHECK( IDC_CED_RADIX_DEC ) ) {
data = (DWORD)::strtoul( szStr, NULL, 10 );
} else {
data = (DWORD)::strtoul( szStr, NULL, 16 );
}
if( IsBTNCHECK( IDC_CED_LENGTH_1BYTE ) ) {
data &= 0x000000FF;
m_Code.length = CHEAT_LENGTH_1BYTE;
} else
if( IsBTNCHECK( IDC_CED_LENGTH_2BYTE ) ) {
data &= 0x0000FFFF;
m_Code.length = CHEAT_LENGTH_2BYTE;
} else
if( IsBTNCHECK( IDC_CED_LENGTH_3BYTE ) ) {
data &= 0x00FFFFFF;
m_Code.length = CHEAT_LENGTH_3BYTE;
} else
if( IsBTNCHECK( IDC_CED_LENGTH_4BYTE ) ) {
m_Code.length = CHEAT_LENGTH_4BYTE;
}
m_Code.data = data;
if( IsBTNCHECK( IDC_CED_TYPE_ALWAYS ) ) {
m_Code.type = CHEAT_TYPE_ALWAYS;
} else
if( IsBTNCHECK( IDC_CED_TYPE_ONCE ) ) {
m_Code.type = CHEAT_TYPE_ONCE;
} else
if( IsBTNCHECK( IDC_CED_TYPE_GREATER ) ) {
m_Code.type = CHEAT_TYPE_GREATER;
} else
if( IsBTNCHECK( IDC_CED_TYPE_LESS ) ) {
m_Code.type = CHEAT_TYPE_LESS;
}
::GetDlgItemText( m_hWnd, IDC_CED_COMMENT, szStr, sizeof(szStr) );
m_Code.comment = szStr;
::EndDialog( m_hWnd, IDOK );
}
DLGCMD CCheatCodeEditDlg::OnCancel( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeEditDlg::OnCancel\n" );
::EndDialog( m_hWnd, IDCANCEL );
}
//
// チートコード入力ダイアログ
//
DLG_MESSAGE_BEGIN(CCheatCodeInputDlg)
DLG_ON_MESSAGE( WM_INITDIALOG, OnInitDialog )
DLG_COMMAND_BEGIN()
DLG_ON_COMMAND( IDOK, OnOK )
DLG_ON_COMMAND( IDCANCEL, OnCancel )
DLG_COMMAND_END()
DLG_MESSAGE_END()
INT CCheatCodeInputDlg::DoModal( HWND hWndParent )
{
return ::DialogBoxParam( CApp::GetPlugin(), MAKEINTRESOURCE(IDD_CODEINPUT),
hWndParent, g_DlgProc, (LPARAM)this );
}
DLGMSG CCheatCodeInputDlg::OnInitDialog( DLGMSGPARAM )
{
// DEBUGOUT( "CCheatCodeInputDlg::OnInitDialog\n" );
::SetDlgItemText( m_hWnd, IDC_CHC_CODE, m_Codes.c_str() );
::SetDlgItemText( m_hWnd, IDC_CHC_COMMENT, m_Comment.c_str() );
return TRUE;
}
DLGCMD CCheatCodeInputDlg::OnOK( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeInputDlg::OnOK\n" );
CHAR szStr[256];
::GetDlgItemText( m_hWnd, IDC_CHC_CODE, szStr, sizeof(szStr) );
m_Codes = szStr;
::GetDlgItemText( m_hWnd, IDC_CHC_COMMENT, szStr, sizeof(szStr) );
m_Comment = szStr;
::EndDialog( m_hWnd, IDOK );
}
DLGCMD CCheatCodeInputDlg::OnCancel( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeInputDlg::OnCancel\n" );
::EndDialog( m_hWnd, IDCANCEL );
}
//
// チートコードダイアログ
//
// メッセージ
DLG_MESSAGE_BEGIN(CCheatCodeDlg)
DLG_ON_MESSAGE( WM_INITDIALOG, OnInitDialog )
DLG_ON_MESSAGE( WM_DESTROY, OnDestroy )
DLG_ON_MESSAGE( WM_TIMER, OnTimer )
// コマンド
DLG_COMMAND_BEGIN()
DLG_ON_COMMAND( IDOK, OnOK )
DLG_ON_COMMAND( IDCANCEL, OnCancel )
DLG_ON_COMMAND( IDC_CHT_ENABLE, OnEnable )
DLG_ON_COMMAND( IDC_CHT_DISABLE, OnDisable )
DLG_ON_COMMAND( IDC_CHT_CLEAR, OnClear )
DLG_ON_COMMAND( IDC_CHT_REMOVE, OnRemove )
DLG_ON_COMMAND( IDC_CHT_INPUT, OnInput )
DLG_ON_COMMAND( IDC_CHT_EDIT, OnEdit )
DLG_ON_COMMAND( IDC_CHT_LOAD, OnLoad )
DLG_ON_COMMAND( IDC_CHT_SAVE, OnSave )
DLG_COMMAND_END()
// Notify メッセージ
DLG_NOTIFY_BEGIN()
DLG_ON_NOTIFY( IDC_CHT_CODE_LIST, LVN_KEYDOWN, OnKeyDownListView )
DLG_ON_NOTIFY( IDC_CHT_CODE_LIST, NM_CLICK, OnClickListView )
DLG_ON_NOTIFY( IDC_CHT_CODE_LIST, NM_DBLCLK, OnDblClkListView )
DLG_NOTIFY_END()
DLG_MESSAGE_END()
INT CCheatCodeDlg::DoModal( HWND hWndParent )
{
m_hImageList = NULL;
return ::DialogBoxParam( CApp::GetPlugin(), MAKEINTRESOURCE(IDD_CHEAT),
hWndParent, g_DlgProc, (LPARAM)this );
}
void CCheatCodeDlg::OnListUpdate()
{
HWND hWndCtrl = ::GetDlgItem( m_hWnd, IDC_CHT_CODE_LIST );
ListView_DeleteAllItems( hWndCtrl );
INT i;
CHAR szStr[256], szTemp[256];
LVITEM lvitem;
lvitem.mask = LVIF_TEXT;
lvitem.iSubItem = 0;
INT codenum = Emu.GetNES()->GetCheatCodeNum();
for( i = 0; i < codenum; i++ ) {
CHEATCODE code;
Emu.GetNES()->GetCheatCode( i, code );
// Code
::wsprintf( szTemp, "%%04X-%%01d%%01d-%%0%dX", (code.length+1)*2 );
::wsprintf( szStr, szTemp, code.address, code.type, code.length+1, code.data );
lvitem.pszText = szStr;
lvitem.iItem = i;
ListView_InsertItem( hWndCtrl, &lvitem );
// Comment
ListView_SetItemText( hWndCtrl, i, 1, (LPSTR)code.comment.c_str() );
// State
ListView_SetItemState( hWndCtrl, i, INDEXTOSTATEIMAGEMASK(code.enable+1), LVIS_STATEIMAGEMASK );
}
}
DLGMSG CCheatCodeDlg::OnInitDialog( DLGMSGPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnInitDialog\n" );
HWND hWndCtrl;
CHAR szStr[256];
// リストビュー
hWndCtrl = ::GetDlgItem( m_hWnd, IDC_CHT_CODE_LIST );
// ListView_SetExtendedListViewStyle( hWndCtrl, LVS_EX_CHECKBOXES|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES );
ListView_SetExtendedListViewStyle( hWndCtrl, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES );
ListView_DeleteAllItems( hWndCtrl );
// イメージリストの作成
m_hImageList = ImageList_LoadBitmap(
CApp::GetInstance(), MAKEINTRESOURCE(IDB_CHEATIMAGELIST),
16, 4, RGB(255,0,255) );
// イメージリストをリストビューに割り当て
ListView_SetImageList( hWndCtrl, m_hImageList, LVSIL_STATE );
// ヘッダコントロールの設定
LVCOLUMN lvColumn;
lvColumn.mask = LVCF_FMT|LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.pszText = szStr;
RECT rc;
::GetClientRect( hWndCtrl, &rc );
INT nWidth = RCWIDTH(rc) - ::GetSystemMetrics( SM_CXVSCROLL );
CApp::LoadString( IDS_CHT_CHEATCODE, szStr, sizeof(szStr) );
lvColumn.iSubItem = 0;
lvColumn.cx = nWidth*2/5;
ListView_InsertColumn( hWndCtrl, 0, &lvColumn );
CApp::LoadString( IDS_CHT_COMMENT, szStr, sizeof(szStr) );
lvColumn.iSubItem = 1;
lvColumn.cx = nWidth*3/5;
ListView_InsertColumn( hWndCtrl, 1, &lvColumn );
// チートコードをバックアップする(Cancel用)
INT codenum = Emu.GetNES()->GetCheatCodeNum();
if( codenum > 0 ) {
CHEATCODE code;
for( INT i = 0; i < codenum; i++ ) {
if( Emu.GetNES()->GetCheatCode( i, code ) ) {
m_CheatCode.push_back( code );
}
}
} else {
m_CheatCode.clear();
}
OnListUpdate();
m_uTimerID = ::SetTimer( m_hWnd, 0x0001, 1000, NULL ); // 1sec
return TRUE;
}
DLGMSG CCheatCodeDlg::OnDestroy( DLGMSGPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnDestroy\n" );
::KillTimer( m_hWnd, m_uTimerID );
m_uTimerID = 0;
if( m_hImageList ) {
ImageList_Destroy( m_hImageList );
m_hImageList = NULL;
}
return TRUE;
}
DLGMSG CCheatCodeDlg::OnTimer( DLGMSGPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnTimer\n" );
if( Emu.GetNES()->IsCheatCodeAdd() ) {
OnListUpdate();
}
return TRUE;
}
DLGNOTIFY CCheatCodeDlg::OnKeyDownListView( DLGNOTIFYPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnKeyDownListView\n" );
NMLVKEYDOWN* pNMKeyDown = (NMLVKEYDOWN*)pNMHDR;
if( pNMKeyDown->wVKey != VK_SPACE )
return;
INT codenum = Emu.GetNES()->GetCheatCodeNum();
for( INT i = 0; i < codenum; i++ ) {
if( ListView_GetItemState( pNMKeyDown->hdr.hwndFrom, i, LVIS_SELECTED ) ) {
UINT state = ListView_GetItemState( pNMKeyDown->hdr.hwndFrom, i, LVIS_STATEIMAGEMASK );
if( (state+=0x1000) > 0x4000 )
state = 0x1000;
ListView_SetItemState( pNMKeyDown->hdr.hwndFrom, i, state, LVIS_STATEIMAGEMASK );
// コード更新
CHEATCODE code;
if( Emu.GetNES()->GetCheatCode( i, code ) ) {
code.enable = (state>>12)-1;
Emu.GetNES()->ReplaceCheatCode( i, code );
}
break;
}
}
}
DLGNOTIFY CCheatCodeDlg::OnClickListView( DLGNOTIFYPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnClickListView\n" );
NMLISTVIEW* pNMListView = (NMLISTVIEW*)pNMHDR;
LVHITTESTINFO lvht;
lvht.pt = pNMListView->ptAction;
ListView_HitTest( pNMListView->hdr.hwndFrom, &lvht );
// ステートイメージ以外は帰る
if( (lvht.flags&LVHT_NOWHERE) || (lvht.flags&LVHT_ONITEMLABEL) || lvht.iItem < 0 )
return;
// ステートアイコンならば更新
if( lvht.flags & LVHT_ONITEMSTATEICON ) {
UINT state = ListView_GetItemState( pNMListView->hdr.hwndFrom, lvht.iItem, LVIS_STATEIMAGEMASK );
if( (state+=0x1000) > 0x4000 )
state = 0x1000;
ListView_SetItemState( pNMListView->hdr.hwndFrom, lvht.iItem, state, LVIS_STATEIMAGEMASK );
// コード更新
CHEATCODE code;
if( Emu.GetNES()->GetCheatCode( lvht.iItem, code ) ) {
code.enable = (state>>12)-1;
Emu.GetNES()->ReplaceCheatCode( lvht.iItem, code );
}
}
}
DLGNOTIFY CCheatCodeDlg::OnDblClkListView( DLGNOTIFYPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnClickListView\n" );
NMLISTVIEW* pNMListView = (NMLISTVIEW*)pNMHDR;
LVHITTESTINFO lvht;
lvht.pt = pNMListView->ptAction;
ListView_HitTest( pNMListView->hdr.hwndFrom, &lvht );
// ラベル以外は帰る
if( (lvht.flags&LVHT_NOWHERE) || !(lvht.flags&LVHT_ONITEMLABEL) || lvht.iItem < 0 )
return;
// エディットしてね…と。
::PostMessage( m_hWnd, WM_COMMAND, (WPARAM)IDC_CHT_EDIT, (LPARAM)0 );
}
DLGCMD CCheatCodeDlg::OnOK( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnOK\n" );
// 念のため
m_CheatCode.clear();
::EndDialog( m_hWnd, IDOK );
}
DLGCMD CCheatCodeDlg::OnCancel( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnCancel\n" );
// バックアップしていたチートコードを戻す
Emu.GetNES()->CheatInitial();
for( INT i = 0; i < m_CheatCode.size(); i++ ) {
Emu.GetNES()->AddCheatCode( m_CheatCode[i] );
}
// 念のため
m_CheatCode.clear();
::EndDialog( m_hWnd, IDCANCEL );
}
DLGCMD CCheatCodeDlg::OnEnable( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnEnable\n" );
Emu.GetNES()->SetCheatCodeAllFlag( TRUE, FALSE );
OnListUpdate();
}
DLGCMD CCheatCodeDlg::OnDisable( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnDisable\n" );
Emu.GetNES()->SetCheatCodeAllFlag( FALSE, FALSE );
OnListUpdate();
}
DLGCMD CCheatCodeDlg::OnClear( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnClear\n" );
Emu.GetNES()->CheatInitial();
OnListUpdate();
}
DLGCMD CCheatCodeDlg::OnRemove( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnRemove\n" );
HWND hWndCtrl = ::GetDlgItem( m_hWnd, IDC_CHT_CODE_LIST );
INT nCount = ListView_GetItemCount( hWndCtrl );
for( INT i = 0; i < nCount; i++ ) {
if( ListView_GetItemState( hWndCtrl, i, LVIS_SELECTED ) ) {
ListView_DeleteItem( hWndCtrl, i );
// 消す
Emu.GetNES()->DelCheatCode( i );
break;
}
}
}
DLGCMD CCheatCodeDlg::OnInput( DLGCMDPARAM )
{
DEBUGOUT( "CCheatCodeDlg::OnInput\n" );
CCheatCodeInputDlg dlg;
if( dlg.DoModal( m_hWnd ) == IDOK ) {
CHEATCODE code;
if( ::strlen( dlg.m_Codes.c_str() ) < 10 )
return;
const UCHAR seps[] = " -\t\n\0"; // セパレータ
CHAR szStr[256];
::wsprintf( szStr, "%s", dlg.m_Codes.c_str() );
CHAR* pToken;
// 初期状態でイネーブルにする
code.enable = CHEAT_ENABLE;
// Initial state
if( szStr[0] == '#' ) {
if( (pToken = (CHAR*)_mbstok( (UCHAR*)szStr, seps )) ) {
if( ::strlen(pToken) == 2 ) {
if( pToken[1] >= '0' && pToken[1] <= '3' ) {
code.enable = pToken[1] - '0';
}
}
}
}
// Address
if( szStr[0] != '#' ) {
if( !(pToken = (CHAR*)_mbstok( (UCHAR*)szStr, seps )) )
return;
} else {
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
return;
}
code.address = ::strtoul( pToken, NULL, 16 );
// Type & Length
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
return;
code.type = pToken[0]-'0';
code.length = pToken[1]-'1';
if( code.type < CHEAT_TYPE_ALWAYS )
code.type = CHEAT_TYPE_ALWAYS;
if( code.type > CHEAT_TYPE_LESS )
code.type = CHEAT_TYPE_ALWAYS;
if( code.length < CHEAT_LENGTH_1BYTE )
code.length = CHEAT_LENGTH_1BYTE;
if( code.length > CHEAT_LENGTH_4BYTE )
code.length = CHEAT_LENGTH_1BYTE;
// Data
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
return;
code.data = ::strtoul( pToken, NULL, 16 );
// Comment
code.comment = dlg.m_Comment;
// 追加
Emu.GetNES()->AddCheatCode( code );
// タイマーで検知しないようにフラグ消し
(void)Emu.GetNES()->IsCheatCodeAdd();
// リスト更新
OnListUpdate();
}
}
DLGCMD CCheatCodeDlg::OnEdit( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnEdit\n" );
HWND hWndCtrl = ::GetDlgItem( m_hWnd, IDC_CHT_CODE_LIST );
INT nCount = ListView_GetItemCount( hWndCtrl );
INT i;
for( i = 0; i < nCount; i++ ) {
if( ListView_GetItemState( hWndCtrl, i, LVIS_SELECTED ) ) {
CCheatCodeEditDlg dlg;
if( Emu.GetNES()->GetCheatCode( i, dlg.m_Code ) ) {
dlg.m_nRadix = 16;
if( dlg.DoModal( m_hWnd ) == IDOK ) {
Emu.GetNES()->ReplaceCheatCode( i, dlg.m_Code );
OnListUpdate();
}
}
break;
}
}
}
DLGCMD CCheatCodeDlg::OnLoad( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnLoad\n" );
string pathstr, tempstr;
if( Config.path.bCheatPath ) {
pathstr = CPathlib::CreatePath( CApp::GetModulePath(), Config.path.szCheatPath );
::CreateDirectory( pathstr.c_str(), NULL );
} else {
pathstr = Emu.GetNES()->rom->GetRomPath();
}
tempstr = CPathlib::MakePathExt( pathstr.c_str(), Emu.GetNES()->rom->GetRomName(), "vct" );
DEBUGOUT( "Path: %s\n", tempstr.c_str() );
OPENFILENAME ofn;
CHAR szFile[_MAX_PATH];
::strcpy( szFile, tempstr.c_str() );
ZEROMEMORY( &ofn, sizeof(ofn) );
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "Cheat Files(*.vct)\0*.vct\0All Files(*.*)\0*.*\0";
ofn.nFilterIndex = 1;
ofn.Flags = OFN_EXPLORER|OFN_PATHMUSTEXIST;
ofn.lpstrInitialDir = pathstr.c_str();
CHAR szTitle[256], szTemp[256];
CApp::LoadString( IDS_UI_LOADCHEATCODE, szTitle, sizeof(szTitle) );
ofn.lpstrTitle = szTitle;
if( ::GetOpenFileName( &ofn ) ) {
FILE* fp = NULL;
if( (fp = ::fopen( szFile, "r" )) ) {
// 一旦消す
Emu.GetNES()->CheatInitial();
while( ::fgets( szTemp, sizeof(szTemp), fp ) ) {
if( szTemp[0] == ';' )
continue;
CHEATCODE code;
if( ::strlen( szTemp ) < 10 )
continue;
const UCHAR seps[] = " -\t\n\0"; // セパレータ
const UCHAR seps2[] = "\t\n\0"; // セパレータ
const UCHAR seps3[] = "-\t\n\0"; // セパレータ
CHAR* pToken;
code.enable = CHEAT_ENABLE;
// Initial state
if( szTemp[0] == '#' ) {
if( !(pToken = (CHAR*)_mbstok( (UCHAR*)szTemp, seps )) )
continue;
if( ::strlen(pToken) == 2 ) {
if( pToken[1] >= '0' && pToken[1] <= '3' ) {
code.enable = pToken[1] - '0';
}
}
}
// Address
if( szTemp[0] != '#' ) {
if( !(pToken = (CHAR*)_mbstok( (UCHAR*)szTemp, seps )) )
continue;
} else {
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
continue;
}
if( ::strlen( pToken ) == 4 ) {
// VirtuaNES code
code.address = ::strtoul( pToken, NULL, 16 );
// Type & Length
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
continue;
if( ::strlen( pToken ) == 2 ) {
// VirtuaNES code
code.type = pToken[0]-'0';
code.length = pToken[1]-'1';
} else {
// NNNesterJ code?
code.type = CHEAT_TYPE_ALWAYS;
code.length = pToken[0]-'1';
}
if( code.type < CHEAT_TYPE_ALWAYS )
code.type = CHEAT_TYPE_ALWAYS;
if( code.type > CHEAT_TYPE_LESS )
code.type = CHEAT_TYPE_ALWAYS;
if( code.length < CHEAT_LENGTH_1BYTE )
code.length = CHEAT_LENGTH_1BYTE;
if( code.length > CHEAT_LENGTH_4BYTE )
code.length = CHEAT_LENGTH_1BYTE;
// Data
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
continue;
code.data = ::strtoul( pToken, NULL, 16 );
// Comment
if( (pToken = (CHAR*)_mbstok( NULL, seps2 )) ) {
code.comment = pToken;
} else {
code.comment = "";
}
} else if( ::strlen( pToken ) == 5 ) {
// NNNesterJ code?
if( pToken[0] == '0' ) {
code.address = ::strtoul( pToken+1, NULL, 16 );
} else if( pToken[0] == '1' ) {
code.address = ::strtoul( pToken+1, NULL, 16 );
code.address += 0x6000;
}
// Length
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
continue;
code.type = CHEAT_TYPE_ALWAYS;
code.length = pToken[1]-'1';
if( code.length < CHEAT_LENGTH_1BYTE )
code.length = CHEAT_LENGTH_1BYTE;
if( code.length > CHEAT_LENGTH_4BYTE )
code.length = CHEAT_LENGTH_1BYTE;
// Data
if( !(pToken = (CHAR*)_mbstok( NULL, seps )) )
continue;
code.data = ::strtoul( pToken, NULL, 16 );
// Comment
if( (pToken = (CHAR*)_mbstok( NULL, seps3 )) ) {
code.comment = pToken;
} else {
code.comment = "";
}
}
// 追加
Emu.GetNES()->AddCheatCode( code );
// タイマーで検知しないようにフラグ消し
(void)Emu.GetNES()->IsCheatCodeAdd();
}
// リスト更新
OnListUpdate();
}
FCLOSE( fp );
}
}
DLGCMD CCheatCodeDlg::OnSave( DLGCMDPARAM )
{
// DEBUGOUT( "CCheatCodeDlg::OnSave\n" );
INT codenum = Emu.GetNES()->GetCheatCodeNum();
if( !codenum )
return;
string pathstr, tempstr;
if( Config.path.bCheatPath ) {
pathstr = CPathlib::CreatePath( CApp::GetModulePath(), Config.path.szCheatPath );
::CreateDirectory( pathstr.c_str(), NULL );
} else {
pathstr = Emu.GetNES()->rom->GetRomPath();
}
tempstr = CPathlib::MakePathExt( pathstr.c_str(), Emu.GetNES()->rom->GetRomName(), "vct" );
DEBUGOUT( "Path: %s\n", tempstr.c_str() );
OPENFILENAME ofn;
CHAR szFile[_MAX_PATH];
::strcpy( szFile, tempstr.c_str() );
ZEROMEMORY( &ofn, sizeof(ofn) );
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "Cheat Files(*.vct)\0*.vct\0All Files(*.*)\0*.*\0";
ofn.nFilterIndex = 1;
ofn.Flags = OFN_EXPLORER|OFN_PATHMUSTEXIST;
ofn.lpstrInitialDir = pathstr.c_str();
CHAR szTitle[256], szTemp[256], szTemp2[256];
ofn.Flags |= OFN_OVERWRITEPROMPT;
CApp::LoadString( IDS_UI_SAVECHEATCODE, szTitle, sizeof(szTitle) );
ofn.lpstrTitle = szTitle;
if( ::GetSaveFileName( &ofn ) ) {
FILE* fp = NULL;
if( (fp = ::fopen( szFile, "w" )) ) {
::fprintf( fp, "; %s\n", Emu.GetNES()->rom->GetRomName() );
// コードをファイルに保存
CHEATCODE code;
for( INT i = 0; i < codenum; i++ ) {
Emu.GetNES()->GetCheatCode( i, code );
// Code
::wsprintf( szTemp, "#%01d %%04X-%%01d%%01d-%%0%dX", code.enable, (code.length+1)*2 );
::wsprintf( szTemp2, szTemp, code.address, code.type, code.length+1, code.data );
::fputs( szTemp2, fp );
if( ::strlen(szTemp2) >= 16 )
::fprintf( fp, "\t%s\n", code.comment.c_str() );
else
::fprintf( fp, "\t\t%s\n", code.comment.c_str() );
}
}
FCLOSE( fp );
}
}