2015-01-27 22:15:05 +00:00
# include "i18n/i18n.h"
2013-12-29 22:28:31 +00:00
# include "Common/StringUtils.h"
# include "Common/ChunkFile.h"
2013-05-18 22:04:01 +00:00
# include "Common/FileUtil.h"
2013-12-29 22:28:31 +00:00
# include "Core/CoreTiming.h"
# include "Core/CoreParameter.h"
# include "Core/CwCheat.h"
2013-05-30 07:08:20 +00:00
# include "Core/Config.h"
2016-05-28 05:00:14 +00:00
# include "Core/Host.h"
2013-12-29 22:28:31 +00:00
# include "Core/MIPS/MIPS.h"
2013-12-29 23:11:29 +00:00
# include "Core/ELF/ParamSFO.h"
# include "Core/System.h"
2014-06-26 02:23:56 +00:00
# include "Core/HLE/sceCtrl.h"
2016-05-01 08:35:37 +00:00
# include "Core/MIPS/JitCommon/JitCommon.h"
2015-02-02 22:26:25 +00:00
2014-06-05 02:41:42 +00:00
# ifdef _WIN32
# include "util/text/utf8.h"
# endif
2013-05-18 22:52:24 +00:00
2013-05-18 04:49:44 +00:00
static int CheatEvent = - 1 ;
2013-06-18 22:50:28 +00:00
std : : string gameTitle ;
2013-08-23 02:58:37 +00:00
std : : string activeCheatFile ;
2013-05-23 11:10:39 +00:00
static CWCheatEngine * cheatEngine ;
2013-10-14 00:49:05 +00:00
static bool cheatsEnabled ;
2013-05-23 11:10:39 +00:00
void hleCheat ( u64 userdata , int cyclesLate ) ;
void trim2 ( std : : string & str ) ;
2013-05-18 04:49:44 +00:00
2013-10-14 00:49:05 +00:00
static void __CheatStop ( ) {
if ( cheatEngine ! = 0 ) {
cheatEngine - > Exit ( ) ;
delete cheatEngine ;
cheatEngine = 0 ;
}
cheatsEnabled = false ;
}
static void __CheatStart ( ) {
__CheatStop ( ) ;
2013-06-18 22:50:28 +00:00
gameTitle = g_paramSFO . GetValueString ( " DISC_ID " ) ;
2013-10-14 00:50:14 +00:00
2016-06-20 09:32:31 +00:00
if ( gameTitle ! = " " ) { //this only generates ini files on boot, let's leave homebrew ini file for UI
cheatEngine - > CreateCheatFile ( ) ;
}
2013-10-07 14:46:18 +00:00
2013-10-14 00:49:05 +00:00
cheatEngine = new CWCheatEngine ( ) ;
cheatEngine - > CreateCodeList ( ) ;
g_Config . bReloadCheats = false ;
cheatsEnabled = true ;
}
2013-06-01 05:24:25 +00:00
2013-10-14 00:49:05 +00:00
void __CheatInit ( ) {
// Always register the event, want savestates to be compatible whether cheats on or off.
CheatEvent = CoreTiming : : RegisterEvent ( " CheatEvent " , & hleCheat ) ;
2013-05-30 07:08:20 +00:00
2013-10-14 00:49:05 +00:00
if ( g_Config . bEnableCheats ) {
__CheatStart ( ) ;
2013-05-18 22:04:01 +00:00
}
2013-10-14 00:49:05 +00:00
2015-01-26 23:50:50 +00:00
int refresh = g_Config . iCwCheatRefreshRate ;
2013-10-14 00:49:05 +00:00
// Only check once a second for cheats to be enabled.
2015-01-26 23:50:50 +00:00
CoreTiming : : ScheduleEvent ( msToCycles ( cheatsEnabled ? refresh : 1000 ) , CheatEvent , 0 ) ;
2013-05-18 04:49:44 +00:00
}
2013-05-23 11:10:39 +00:00
2013-05-18 04:49:44 +00:00
void __CheatShutdown ( ) {
2013-10-14 00:49:05 +00:00
__CheatStop ( ) ;
2013-05-18 04:49:44 +00:00
}
2013-10-07 14:46:18 +00:00
void __CheatDoState ( PointerWrap & p ) {
2013-10-14 01:03:23 +00:00
auto s = p . Section ( " CwCheat " , 0 , 2 ) ;
2013-10-07 14:46:18 +00:00
if ( ! s ) {
return ;
}
p . Do ( CheatEvent ) ;
CoreTiming : : RestoreRegisterEvent ( CheatEvent , " CheatEvent " , & hleCheat ) ;
2013-10-14 01:03:23 +00:00
2015-01-26 23:50:50 +00:00
int refresh = g_Config . iCwCheatRefreshRate ;
2013-10-14 01:03:23 +00:00
if ( s < 2 ) {
// Before this we didn't have a checkpoint, so reset didn't work.
// Let's just force one in.
CoreTiming : : RemoveEvent ( CheatEvent ) ;
2015-01-26 23:50:50 +00:00
CoreTiming : : ScheduleEvent ( msToCycles ( cheatsEnabled ? refresh : 1000 ) , CheatEvent , 0 ) ;
2013-10-14 01:03:23 +00:00
}
2013-10-07 14:46:18 +00:00
}
2013-05-18 04:49:44 +00:00
void hleCheat ( u64 userdata , int cyclesLate ) {
2013-10-14 00:49:05 +00:00
if ( cheatsEnabled ! = g_Config . bEnableCheats ) {
// Okay, let's move to the desired state, then.
if ( g_Config . bEnableCheats ) {
__CheatStart ( ) ;
} else {
__CheatStop ( ) ;
}
}
2013-05-30 07:08:20 +00:00
2015-01-26 23:50:50 +00:00
int refresh = g_Config . iCwCheatRefreshRate ;
2013-10-14 00:49:05 +00:00
// Only check once a second for cheats to be enabled.
2015-01-26 23:50:50 +00:00
CoreTiming : : ScheduleEvent ( msToCycles ( cheatsEnabled ? refresh : 1000 ) , CheatEvent , 0 ) ;
2013-10-14 00:49:05 +00:00
if ( ! cheatEngine | | ! cheatsEnabled )
2013-06-24 08:31:29 +00:00
return ;
if ( g_Config . bReloadCheats ) { //Checks if the "reload cheats" button has been pressed.
2013-05-30 07:08:20 +00:00
cheatEngine - > CreateCodeList ( ) ;
g_Config . bReloadCheats = false ;
2013-06-01 05:24:25 +00:00
}
2013-10-14 00:49:05 +00:00
cheatEngine - > Run ( ) ;
2013-05-18 04:49:44 +00:00
}
2013-05-18 22:04:01 +00:00
CWCheatEngine : : CWCheatEngine ( ) {
2013-05-18 04:49:44 +00:00
}
2013-05-18 22:04:01 +00:00
void CWCheatEngine : : Exit ( ) {
2013-05-18 04:49:44 +00:00
exit2 = true ;
}
2014-02-15 23:28:13 +00:00
2014-12-25 03:20:21 +00:00
// Takes a single code line and creates a two-part vector for each code. Feeds to CreateCodeList
static inline std : : vector < std : : string > makeCodeParts ( const std : : vector < std : : string > & CodesList ) {
2014-02-15 23:28:13 +00:00
std : : string currentcode ;
std : : vector < std : : string > finalList ;
char split_char = ' \n ' ;
char empty = ' ' ;
for ( size_t i = 0 ; i < CodesList . size ( ) ; i + + ) {
currentcode = CodesList [ i ] ;
2015-11-25 11:05:32 +00:00
for ( size_t j = 0 ; j < currentcode . length ( ) ; j + + ) {
2014-02-15 23:28:13 +00:00
if ( currentcode [ j ] = = empty ) {
currentcode [ j ] = ' \n ' ;
}
}
trim2 ( currentcode ) ;
std : : istringstream iss ( currentcode ) ;
std : : string each ;
while ( std : : getline ( iss , each , split_char ) ) {
finalList . push_back ( each ) ;
}
}
return finalList ;
}
2016-06-19 22:18:35 +00:00
void CWCheatEngine : : CreateCheatFile ( ) {
activeCheatFile = GetSysDirectory ( DIRECTORY_CHEATS ) + gameTitle + " .ini " ;
File : : CreateFullPath ( GetSysDirectory ( DIRECTORY_CHEATS ) ) ;
if ( ! File : : Exists ( activeCheatFile ) ) {
FILE * f = File : : OpenCFile ( activeCheatFile , " wb " ) ;
if ( f ) {
fwrite ( " \xEF \xBB \xBF \n " , 1 , 4 , f ) ;
fclose ( f ) ;
}
if ( ! File : : Exists ( activeCheatFile ) ) {
I18NCategory * err = GetI18NCategory ( " Error " ) ;
host - > NotifyUserMessage ( err - > T ( " Unable to create cheat file, disk may be full " ) ) ;
}
}
}
2013-06-17 22:44:41 +00:00
void CWCheatEngine : : CreateCodeList ( ) { //Creates code list to be used in function GetNextCode
2013-06-16 22:59:59 +00:00
initialCodesList = GetCodesList ( ) ;
std : : string currentcode , codename ;
std : : vector < std : : string > codelist ;
for ( size_t i = 0 ; i < initialCodesList . size ( ) ; i + + ) {
2013-06-18 22:50:28 +00:00
if ( initialCodesList [ i ] . substr ( 0 , 2 ) = = " _S " ) {
continue ; //Line indicates Disc ID, not needed for cheats
}
if ( initialCodesList [ i ] . substr ( 0 , 2 ) = = " _G " ) {
2013-11-11 10:01:44 +00:00
continue ; //Line indicates game Title, also not needed for cheats
}
if ( initialCodesList [ i ] . substr ( 0 , 2 ) = = " // " ) {
continue ; //Line indicates comment, also not needed for cheats.
2013-06-18 22:50:28 +00:00
}
2013-06-16 22:59:59 +00:00
if ( initialCodesList [ i ] . substr ( 0 , 3 ) = = " _C1 " ) {
cheatEnabled = true ;
codename = initialCodesList [ i ] ;
codename . erase ( codename . begin ( ) , codename . begin ( ) + 4 ) ;
2013-06-18 22:50:28 +00:00
codeNameList . push_back ( codename ) ; //Import names for GUI, will be implemented later.
2013-06-16 22:59:59 +00:00
continue ;
}
if ( initialCodesList [ i ] . substr ( 0 , 2 ) = = " _L " ) {
if ( cheatEnabled = = true ) {
currentcode = initialCodesList [ i ] ;
2016-10-24 02:37:49 +00:00
std : : size_t comment = currentcode . find ( " // " ) ;
if ( comment ! = std : : string : : npos ) {
currentcode . erase ( currentcode . begin ( ) + comment , currentcode . end ( ) ) ;
//Purge comments after code lines before adding them to codelist
}
2013-06-16 22:59:59 +00:00
currentcode . erase ( currentcode . begin ( ) , currentcode . begin ( ) + 3 ) ;
codelist . push_back ( currentcode ) ;
}
continue ;
}
if ( initialCodesList [ i ] . substr ( 0 , 3 ) = = " _C0 " ) {
cheatEnabled = false ;
codename = initialCodesList [ i ] ;
codename . erase ( codename . begin ( ) , codename . begin ( ) + 4 ) ;
2013-06-18 22:50:28 +00:00
codeNameList . push_back ( codename ) ; //Import names for GUI, will be implemented later.
2013-06-16 22:59:59 +00:00
continue ;
}
}
parts = makeCodeParts ( codelist ) ;
}
2014-02-15 23:28:13 +00:00
2013-06-17 22:44:41 +00:00
std : : vector < int > CWCheatEngine : : GetNextCode ( ) { // Feeds a size-2 vector of ints to Run() which contains the address and value of one cheat.
2013-05-30 07:08:20 +00:00
std : : string code1 ;
std : : string code2 ;
std : : vector < std : : string > splitCode ;
2013-05-30 08:49:15 +00:00
std : : vector < int > finalCode ;
2013-05-30 07:08:20 +00:00
std : : string modifier2 = " 0 " ;
2013-05-18 04:49:44 +00:00
while ( true ) {
2015-11-25 11:05:32 +00:00
// Shouldn't splitCode be cleared here? Otherwise var1 and var2 will always be set to the first two codes.. I don't get it
2015-11-25 13:23:39 +00:00
if ( currentCode > = parts . size ( ) ) {
2013-05-30 07:08:20 +00:00
code1 . clear ( ) ;
code2 . clear ( ) ;
2013-05-18 04:49:44 +00:00
break ;
}
2013-05-30 08:49:15 +00:00
code1 = parts [ currentCode + + ] ;
trim2 ( code1 ) ;
2015-11-25 13:23:39 +00:00
if ( currentCode > = parts . size ( ) ) {
code1 . clear ( ) ;
code2 . clear ( ) ;
break ;
}
2013-05-30 08:49:15 +00:00
code2 = parts [ currentCode + + ] ;
trim2 ( code2 ) ;
splitCode . push_back ( code1 ) ;
splitCode . push_back ( code2 ) ;
2013-05-30 07:08:20 +00:00
2013-05-30 08:49:15 +00:00
int var1 = ( int ) parseHexLong ( splitCode [ 0 ] ) ;
int var2 = ( int ) parseHexLong ( splitCode [ 1 ] ) ;
finalCode . push_back ( var1 ) ;
finalCode . push_back ( var2 ) ;
2013-06-16 22:59:59 +00:00
if ( splitCode [ 0 ] . substr ( 0 , 1 ) = = modifier2 ) {
2013-05-18 04:49:44 +00:00
break ;
}
}
2013-05-30 08:49:15 +00:00
return finalCode ;
2013-05-18 04:49:44 +00:00
}
2013-05-23 11:10:39 +00:00
void CWCheatEngine : : SkipCodes ( int count ) {
2013-05-18 04:49:44 +00:00
for ( int i = 0 ; i < count ; i + + ) {
2015-01-10 21:56:27 +00:00
auto code = GetNextCode ( ) ;
if ( code . empty ( ) )
{
WARN_LOG ( COMMON , " CWCHEAT: Tried to skip more codes than there are, the cheat is most likely wrong " ) ;
break ;
}
if ( code [ 0 ] = = 0 ) {
2013-05-18 04:49:44 +00:00
break ;
}
}
}
2013-05-18 22:04:01 +00:00
2013-05-23 11:10:39 +00:00
void CWCheatEngine : : SkipAllCodes ( ) {
2015-02-05 14:14:54 +00:00
currentCode = codes . size ( ) - 1 ;
2013-05-18 04:49:44 +00:00
}
2013-06-17 22:44:41 +00:00
int CWCheatEngine : : GetAddress ( int value ) { //Returns static address used by ppsspp. Some games may not like this, and causes cheats to not work without offset
2013-06-18 22:50:28 +00:00
int address = ( value + 0x08800000 ) & 0x3FFFFFFF ;
return address ;
2013-05-18 04:49:44 +00:00
}
2013-05-23 11:10:39 +00:00
inline void trim2 ( std : : string & str ) {
size_t pos = str . find_last_not_of ( ' ' ) ;
if ( pos ! = std : : string : : npos ) {
2013-05-18 22:04:01 +00:00
str . erase ( pos + 1 ) ;
pos = str . find_first_not_of ( ' ' ) ;
2013-05-23 11:10:39 +00:00
if ( pos ! = std : : string : : npos ) str . erase ( 0 , pos ) ;
2013-05-18 22:04:01 +00:00
}
else str . erase ( str . begin ( ) , str . end ( ) ) ;
2013-05-18 04:49:44 +00:00
}
2016-06-21 04:29:26 +00:00
std : : vector < std : : string > CWCheatEngine : : GetCodesList ( ) { //Reads the entire cheat list from the appropriate .ini.
2013-05-23 11:10:39 +00:00
std : : string line ;
std : : vector < std : : string > codesList ; // Read from INI here
2014-06-05 02:41:42 +00:00
# ifdef _WIN32
std : : ifstream list ( ConvertUTF8ToWString ( activeCheatFile ) ) ;
# else
2013-06-01 05:24:25 +00:00
std : : ifstream list ( activeCheatFile . c_str ( ) ) ;
2014-06-05 02:41:42 +00:00
# endif
2013-10-14 00:56:52 +00:00
if ( ! list ) {
return codesList ;
}
2013-05-18 22:04:01 +00:00
for ( int i = 0 ; ! list . eof ( ) ; i + + ) {
2013-05-23 11:10:39 +00:00
getline ( list , line , ' \n ' ) ;
2013-11-11 15:23:37 +00:00
if ( line . length ( ) > 3 & & ( line . substr ( 0 , 1 ) = = " _ " | | line . substr ( 0 , 2 ) = = " // " ) ) {
2013-08-30 00:08:31 +00:00
codesList . push_back ( line ) ;
}
2013-05-18 22:04:01 +00:00
}
2013-06-02 11:54:54 +00:00
for ( size_t i = 0 ; i < codesList . size ( ) ; i + + ) {
2013-05-18 22:52:24 +00:00
trim2 ( codesList [ i ] ) ;
2013-05-18 22:04:01 +00:00
}
return codesList ;
2013-05-18 04:49:44 +00:00
}
2015-02-02 22:26:25 +00:00
void CWCheatEngine : : InvalidateICache ( u32 addr , int size ) {
2015-07-19 20:04:06 +00:00
currentMIPS - > InvalidateICache ( addr & ~ 3 , size ) ;
2015-02-02 22:26:25 +00:00
}
2013-05-18 22:04:01 +00:00
void CWCheatEngine : : Run ( ) {
2013-05-18 08:21:57 +00:00
exit2 = false ;
2013-05-18 04:49:44 +00:00
while ( ! exit2 ) {
currentCode = 0 ;
2013-05-18 22:04:01 +00:00
2013-05-18 04:49:44 +00:00
while ( true ) {
2013-05-30 08:49:15 +00:00
std : : vector < int > code = GetNextCode ( ) ;
2013-05-30 07:08:20 +00:00
if ( code . size ( ) < 2 ) {
2013-05-18 22:04:01 +00:00
Exit ( ) ;
break ;
}
2013-05-18 04:49:44 +00:00
int value ;
2013-05-30 08:49:15 +00:00
unsigned int comm = code [ 0 ] ;
2014-01-19 15:55:42 +00:00
u32 arg = code [ 1 ] ;
2013-05-23 11:10:39 +00:00
int addr = GetAddress ( comm & 0x0FFFFFFF ) ;
2013-05-18 04:49:44 +00:00
switch ( comm > > 28 ) {
2014-01-19 12:49:08 +00:00
case 0 : // 8-bit write.But need more check
2015-02-02 22:26:25 +00:00
if ( Memory : : IsValidAddress ( addr ) ) {
InvalidateICache ( addr & ~ 3 , 4 ) ;
2014-01-19 13:13:51 +00:00
if ( arg < 0x00000100 ) // 8-bit
2014-01-19 12:49:08 +00:00
Memory : : Write_U8 ( ( u8 ) arg , addr ) ;
2014-01-19 13:13:51 +00:00
else if ( arg < 0x00010000 ) // 16-bit
2014-01-19 12:49:08 +00:00
Memory : : Write_U16 ( ( u16 ) arg , addr ) ;
else // 32-bit
Memory : : Write_U32 ( ( u32 ) arg , addr ) ;
}
break ;
2013-05-18 04:49:44 +00:00
case 0x1 : // 16-bit write
2015-02-02 22:26:25 +00:00
if ( Memory : : IsValidAddress ( addr ) ) {
InvalidateICache ( addr & ~ 3 , 4 ) ;
2014-01-19 12:49:08 +00:00
Memory : : Write_U16 ( ( u16 ) arg , addr ) ;
}
break ;
2013-05-18 04:49:44 +00:00
case 0x2 : // 32-bit write
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 04:49:44 +00:00
Memory : : Write_U32 ( ( u32 ) arg , addr ) ;
}
break ;
case 0x3 : // Increment/Decrement
{
2013-09-28 22:33:37 +00:00
addr = GetAddress ( arg & 0x0FFFFFFF ) ;
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 22:04:01 +00:00
value = 0 ;
int increment = 0 ;
// Read value from memory
switch ( ( comm > > 20 ) & 0xF ) {
case 1 :
case 2 : // 8-bit
value = Memory : : Read_U8 ( addr ) ;
increment = comm & 0xFF ;
break ;
case 3 :
case 4 : // 16-bit
value = Memory : : Read_U16 ( addr ) ;
increment = comm & 0xFFFF ;
break ;
case 5 :
case 6 : // 32-bit
value = Memory : : Read_U32 ( addr ) ;
code = GetNextCode ( ) ;
2013-07-06 09:09:08 +00:00
if ( code [ 0 ] ! = 0 ) {
2013-05-30 08:49:15 +00:00
increment = code [ 0 ] ;
2013-05-18 22:04:01 +00:00
}
break ;
2013-05-18 04:49:44 +00:00
}
2013-05-18 22:04:01 +00:00
// Increment/Decrement value
switch ( ( comm > > 20 ) & 0xF ) {
case 1 :
case 3 :
case 5 : // increment
value + = increment ;
break ;
case 2 :
case 4 :
case 6 : // Decrement
value - = increment ;
break ;
}
// Write value back to memory
switch ( ( comm > > 20 ) & 0xF ) {
case 1 :
case 2 : // 8-bit
Memory : : Write_U8 ( ( u8 ) value , addr ) ;
break ;
case 3 :
case 4 : // 16-bit
Memory : : Write_U16 ( ( u16 ) value , addr ) ;
break ;
case 5 :
case 6 : // 32-bit
Memory : : Write_U32 ( ( u32 ) value , addr ) ;
break ;
}
2013-05-23 11:10:39 +00:00
break ;
}
2013-05-18 04:49:44 +00:00
case 0x4 : // 32-bit patch code
code = GetNextCode ( ) ;
2013-07-19 01:42:02 +00:00
if ( true ) {
2013-05-30 08:49:15 +00:00
int data = code [ 0 ] ;
int dataAdd = code [ 1 ] ;
2013-05-18 04:49:44 +00:00
2015-02-04 09:56:38 +00:00
int count = ( arg > > 16 ) & 0xFFFF ;
2013-05-18 04:49:44 +00:00
int stepAddr = ( arg & 0xFFFF ) * 4 ;
2015-02-02 22:26:25 +00:00
2015-02-04 09:56:38 +00:00
InvalidateICache ( addr , count * stepAddr ) ;
for ( int a = 0 ; a < count ; a + + ) {
2013-05-18 04:49:44 +00:00
if ( Memory : : IsValidAddress ( addr ) ) {
Memory : : Write_U32 ( ( u32 ) data , addr ) ;
}
addr + = stepAddr ;
data + = dataAdd ;
}
}
break ;
case 0x5 : // Memcpy command
code = GetNextCode ( ) ;
2013-07-19 01:42:02 +00:00
if ( true ) {
2013-09-21 15:12:34 +00:00
int destAddr = GetAddress ( code [ 0 ] ) ;
2015-02-02 22:26:25 +00:00
int len = arg ;
InvalidateICache ( destAddr , len ) ;
2013-05-18 04:49:44 +00:00
if ( Memory : : IsValidAddress ( addr ) & & Memory : : IsValidAddress ( destAddr ) ) {
2015-04-06 01:03:50 +00:00
Memory : : MemcpyUnchecked ( destAddr , addr , len ) ;
2013-05-18 04:49:44 +00:00
}
}
break ;
case 0x6 : // Pointer commands
code = GetNextCode ( ) ;
2015-02-06 18:36:54 +00:00
if ( code . size ( ) > = 2 ) {
2013-05-30 08:49:15 +00:00
int arg2 = code [ 0 ] ;
int offset = code [ 1 ] ;
2013-05-18 04:49:44 +00:00
int baseOffset = ( arg2 > > 20 ) * 4 ;
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr + baseOffset , 4 ) ;
2013-05-18 04:49:44 +00:00
int base = Memory : : Read_U32 ( addr + baseOffset ) ;
int count = arg2 & 0xFFFF ;
int type = ( arg2 > > 16 ) & 0xF ;
for ( int i = 1 ; i < count ; i + + ) {
if ( i + 1 < count ) {
code = GetNextCode ( ) ;
2015-02-06 18:36:54 +00:00
if ( code . size ( ) < 2 ) {
// Code broken. Should warn but would be very spammy...
break ;
}
2013-05-30 08:49:15 +00:00
int arg3 = code [ 0 ] ;
int arg4 = code [ 1 ] ;
2013-05-18 04:49:44 +00:00
int comm3 = arg3 > > 28 ;
switch ( comm3 ) {
case 0x1 : // type copy byte
{
2013-05-18 22:04:01 +00:00
int srcAddr = Memory : : Read_U32 ( addr ) + offset ;
int dstAddr = Memory : : Read_U16 ( addr + baseOffset ) + ( arg3 & 0x0FFFFFFF ) ;
2015-04-06 01:03:50 +00:00
if ( Memory : : IsValidAddress ( dstAddr ) & & Memory : : IsValidAddress ( srcAddr ) ) {
Memory : : MemcpyUnchecked ( dstAddr , srcAddr , arg ) ;
}
2013-05-18 22:04:01 +00:00
type = - 1 ; //Done
break ; }
2013-05-18 04:49:44 +00:00
case 0x2 :
case 0x3 : // type pointer walk
{
2013-05-18 22:04:01 +00:00
int walkOffset = arg3 & 0x0FFFFFFF ;
if ( comm3 = = 0x3 ) {
2013-05-18 04:49:44 +00:00
walkOffset = - walkOffset ;
}
base = Memory : : Read_U32 ( base + walkOffset ) ;
2013-05-18 22:04:01 +00:00
int comm4 = arg4 > > 28 ;
switch ( comm4 ) {
case 0x2 :
case 0x3 : // type pointer walk
walkOffset = arg4 & 0x0FFFFFFF ;
if ( comm4 = = 0x3 ) {
walkOffset = - walkOffset ;
}
base = Memory : : Read_U32 ( base + walkOffset ) ;
break ;
}
break ; }
2013-05-18 04:49:44 +00:00
case 0x9 : // type multi address write
base + = arg3 & 0x0FFFFFFF ;
arg + = arg4 ;
break ;
2013-08-14 02:24:35 +00:00
default :
break ;
2013-05-18 04:49:44 +00:00
}
}
}
2013-05-18 22:04:01 +00:00
switch ( type ) {
case 0 : // 8 bit write
Memory : : Write_U8 ( ( u8 ) arg , base + offset ) ;
break ;
case 1 : // 16-bit write
Memory : : Write_U16 ( ( u16 ) arg , base + offset ) ;
break ;
case 2 : // 32-bit write
Memory : : Write_U32 ( ( u32 ) arg , base + offset ) ;
break ;
case 3 : // 8 bit inverse write
Memory : : Write_U8 ( ( u8 ) arg , base - offset ) ;
break ;
case 4 : // 16-bit inverse write
Memory : : Write_U16 ( ( u16 ) arg , base - offset ) ;
break ;
case 5 : // 32-bit inverse write
Memory : : Write_U32 ( ( u32 ) arg , base - offset ) ;
break ;
case - 1 : // Operation already performed, nothing to do
break ;
}
2013-05-18 04:49:44 +00:00
}
break ;
case 0x7 : // Boolean commands.
switch ( arg > > 16 ) {
case 0x0000 : // 8-bit OR.
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 04:49:44 +00:00
int val1 = ( int ) ( arg & 0xFF ) ;
int val2 = ( int ) Memory : : Read_U8 ( addr ) ;
Memory : : Write_U8 ( ( u8 ) ( val1 | val2 ) , addr ) ;
}
break ;
case 0x0002 : // 8-bit AND.
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 04:49:44 +00:00
int val1 = ( int ) ( arg & 0xFF ) ;
int val2 = ( int ) Memory : : Read_U8 ( addr ) ;
Memory : : Write_U8 ( ( u8 ) ( val1 & val2 ) , addr ) ;
}
break ;
case 0x0004 : // 8-bit XOR.
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 04:49:44 +00:00
int val1 = ( int ) ( arg & 0xFF ) ;
int val2 = ( int ) Memory : : Read_U8 ( addr ) ;
Memory : : Write_U8 ( ( u8 ) ( val1 ^ val2 ) , addr ) ;
}
break ;
case 0x0001 : // 16-bit OR.
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 04:49:44 +00:00
short val1 = ( short ) ( arg & 0xFFFF ) ;
short val2 = ( short ) Memory : : Read_U16 ( addr ) ;
Memory : : Write_U16 ( ( u16 ) ( val1 | val2 ) , addr ) ;
}
break ;
case 0x0003 : // 16-bit AND.
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 04:49:44 +00:00
short val1 = ( short ) ( arg & 0xFFFF ) ;
short val2 = ( short ) Memory : : Read_U16 ( addr ) ;
Memory : : Write_U16 ( ( u16 ) ( val1 & val2 ) , addr ) ;
}
break ;
case 0x0005 : // 16-bit OR.
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr & ~ 3 , 4 ) ;
2013-05-18 04:49:44 +00:00
short val1 = ( short ) ( arg & 0xFFFF ) ;
short val2 = ( short ) Memory : : Read_U16 ( addr ) ;
Memory : : Write_U16 ( ( u16 ) ( val1 ^ val2 ) , addr ) ;
}
break ;
}
break ;
case 0x8 : // 8-bit and 16-bit patch code
code = GetNextCode ( ) ;
2015-02-06 18:36:54 +00:00
if ( code . size ( ) > = 2 ) {
2013-05-30 08:49:15 +00:00
int data = code [ 0 ] ;
int dataAdd = code [ 1 ] ;
2013-05-18 04:49:44 +00:00
bool is8Bit = ( data > > 16 ) = = 0x0000 ;
2015-02-05 15:29:23 +00:00
int count = ( arg > > 16 ) & 0xFFFF ;
2013-05-18 04:49:44 +00:00
int stepAddr = ( arg & 0xFFFF ) * ( is8Bit ? 1 : 2 ) ;
2015-02-05 15:29:23 +00:00
InvalidateICache ( addr , count * stepAddr ) ;
for ( int a = 0 ; a < count ; a + + ) {
2013-05-18 04:49:44 +00:00
if ( Memory : : IsValidAddress ( addr ) ) {
if ( is8Bit ) {
2013-05-18 22:04:01 +00:00
Memory : : Write_U8 ( ( u8 ) ( data & 0xFF ) , addr ) ;
2013-05-18 04:49:44 +00:00
}
else {
2013-05-18 22:04:01 +00:00
Memory : : Write_U16 ( ( u16 ) ( data & 0xFFFF ) , addr ) ;
2013-05-18 04:49:44 +00:00
}
}
addr + = stepAddr ;
data + = dataAdd ;
}
}
break ;
case 0xB : // Time command (not sure what to do?)
break ;
case 0xC : // Code stopper
if ( Memory : : IsValidAddress ( addr ) ) {
2015-02-02 22:26:25 +00:00
InvalidateICache ( addr , 4 ) ;
2013-05-18 04:49:44 +00:00
value = Memory : : Read_U32 ( addr ) ;
2014-03-03 08:08:32 +00:00
if ( ( u32 ) value ! = arg ) {
2013-05-23 11:10:39 +00:00
SkipAllCodes ( ) ;
2013-05-18 04:49:44 +00:00
}
}
break ;
2014-06-28 05:19:42 +00:00
case 0xD : // Test commands & Jocker codes
2015-02-04 14:26:39 +00:00
if ( ( arg > > 28 ) = = 0x0 | | ( arg > > 28 ) = = 0x2 ) { // 8Bit & 16Bit ignore next line cheat code
2014-06-26 02:23:56 +00:00
bool is8Bit = ( arg > > 28 ) = = 0x2 ;
addr = GetAddress ( comm & 0x0FFFFFFF ) ;
if ( Memory : : IsValidAddress ( addr ) ) {
2016-06-19 22:18:35 +00:00
InvalidateICache ( addr , 4 ) ;
2014-06-26 02:23:56 +00:00
int memoryValue = is8Bit ? Memory : : Read_U8 ( addr ) : Memory : : Read_U16 ( addr ) ;
int testValue = arg & ( is8Bit ? 0xFF : 0xFFFF ) ;
bool executeNextLines = false ;
switch ( ( arg > > 20 ) & 0xF ) {
case 0x0 : // Equal
executeNextLines = memoryValue = = testValue ;
break ;
case 0x1 : // Not Equal
executeNextLines = memoryValue ! = testValue ;
break ;
case 0x2 : // Less Than
executeNextLines = memoryValue < testValue ;
break ;
case 0x3 : // Greater Than
executeNextLines = memoryValue > testValue ;
break ;
default :
break ;
}
if ( ! executeNextLines )
SkipCodes ( 1 ) ;
}
break ;
}
2015-02-04 14:26:39 +00:00
else if ( ( arg > > 28 ) = = 0x1 | | ( arg > > 28 ) = = 0x3 ) { // Buttons dependent ignore cheat code
2014-06-26 02:23:56 +00:00
// Button Code
// SELECT 0x00000001
// START 0x00000008
// DPAD UP 0x00000010
// DPAD RIGHT 0x00000020
// DPAD DOWN 0x00000040
// DPAD LEFT 0x00000080
// L TRIGGER 0x00000100
// R TRIGGER 0x00000200
// TRIANGLE 0x00001000
// CIRCLE 0x00002000
// CROSS 0x00004000
// SQUARE 0x00008000
// HOME 0x00010000
// HOLD 0x00020000
// WLAN 0x00040000
// REMOTE HOLD 0x00080000
// VOLUME UP 0x00100000
// VOLUME DOWN 0x00200000
// SCREEN 0x00400000
// NOTE 0x00800000
u32 buttonStatus = __CtrlPeekButtons ( ) ;
int skip = ( comm & 0xFF ) + 1 ;
2015-02-04 14:26:39 +00:00
u32 mask = arg & 0x0FFFFFFF ;
if ( ( arg > > 28 ) = = 0x1 )
// Old, too specific check: if (buttonStatus == (arg & 0x0FFFFFFF)) // cheat code likes: 0xD00000nn 0x1bbbbbbb;
if ( ( buttonStatus & mask ) = = mask ) // cheat code likes: 0xD00000nn 0x1bbbbbbb;
2014-06-26 02:23:56 +00:00
break ;
else
SkipCodes ( skip ) ;
2015-02-04 14:26:39 +00:00
else // (arg >> 28) == 2?
// Old, too specific check: if (buttonStatus != (arg & 0x0FFFFFFF)) // cheat code likes: 0xD00000nn 0x3bbbbbbb;
if ( ( buttonStatus & mask ) = = mask ) // cheat code likes: 0xD00000nn 0x3bbbbbbb;
2014-06-26 02:23:56 +00:00
SkipCodes ( skip ) ;
2015-02-04 14:26:39 +00:00
else
break ;
2014-06-26 02:23:56 +00:00
break ;
}
2015-02-04 14:26:39 +00:00
else if ( ( arg > > 28 ) = = 0x4 | | ( arg > > 28 ) = = 0x5 | | ( arg > > 28 ) = = 0x6 | | ( arg > > 28 ) = = 0x7 ) {
2014-06-26 02:23:56 +00:00
int addr1 = GetAddress ( comm & 0x0FFFFFFF ) ;
2014-07-25 11:11:28 +00:00
int addr2 = GetAddress ( arg & 0x0FFFFFFF ) ;
2014-06-26 02:23:56 +00:00
code = GetNextCode ( ) ;
2015-02-06 18:36:54 +00:00
if ( code . size ( ) > = 2 )
2014-06-26 02:23:56 +00:00
if ( Memory : : IsValidAddress ( addr1 ) & & Memory : : IsValidAddress ( addr2 ) ) {
int comm2 = code [ 0 ] ;
int arg2 = code [ 1 ] ;
int skip = ( comm2 & 0xFFFFFFFF ) ;
int memoryValue1 = 0 ;
int memoryValue2 = 0 ;
2014-06-28 05:19:42 +00:00
switch ( arg2 & 0xF ) {
2014-06-26 02:23:56 +00:00
case 0x0 : // 8Bit
memoryValue1 = Memory : : Read_U8 ( addr1 ) ;
memoryValue2 = Memory : : Read_U8 ( addr2 ) ;
break ;
case 0x1 : // 16Bit
memoryValue1 = Memory : : Read_U16 ( addr1 ) ;
memoryValue2 = Memory : : Read_U16 ( addr2 ) ;
break ;
case 0x2 : // 32Bit
memoryValue1 = Memory : : Read_U32 ( addr1 ) ;
memoryValue2 = Memory : : Read_U32 ( addr2 ) ;
break ;
default :
break ;
}
switch ( arg > > 28 ) {
case 0x4 : // Equal
if ( memoryValue1 ! = memoryValue2 )
SkipCodes ( skip ) ;
break ;
case 0x5 : // Not Equal
if ( memoryValue1 = = memoryValue2 )
SkipCodes ( skip ) ;
break ;
case 0x6 : // Less Than
if ( memoryValue1 > = memoryValue2 )
SkipCodes ( skip ) ;
break ;
case 0x7 : // Greater Than
if ( memoryValue1 < = memoryValue2 )
SkipCodes ( skip ) ;
break ;
default :
break ;
}
}
}
else
break ;
2013-05-18 04:49:44 +00:00
case 0xE : // Test commands, multiple skip
2013-05-18 08:21:57 +00:00
{
2013-10-10 13:57:04 +00:00
bool is8Bit = ( comm > > 24 ) = = 0xE1 ;
2013-05-23 11:10:39 +00:00
addr = GetAddress ( arg & 0x0FFFFFFF ) ;
2013-05-18 22:04:01 +00:00
if ( Memory : : IsValidAddress ( addr ) ) {
2016-06-19 22:18:35 +00:00
InvalidateICache ( addr , 4 ) ;
2013-05-18 22:04:01 +00:00
int memoryValue = is8Bit ? Memory : : Read_U8 ( addr ) : Memory : : Read_U16 ( addr ) ;
int testValue = comm & ( is8Bit ? 0xFF : 0xFFFF ) ;
bool executeNextLines = false ;
switch ( arg > > 28 ) {
case 0x0 : // Equal
executeNextLines = memoryValue = = testValue ;
break ;
case 0x1 : // Not Equal
executeNextLines = memoryValue ! = testValue ;
break ;
case 0x2 : // Less Than
executeNextLines = memoryValue < testValue ;
break ;
case 0x3 : // Greater Than
executeNextLines = memoryValue > testValue ;
break ;
}
if ( ! executeNextLines ) {
int skip = ( comm > > 16 ) & ( is8Bit ? 0xFF : 0xFFF ) ;
2013-05-23 11:10:39 +00:00
SkipCodes ( skip ) ;
2013-05-18 22:04:01 +00:00
}
2013-05-18 04:49:44 +00:00
}
2013-05-18 22:04:01 +00:00
break ;
2013-05-18 04:49:44 +00:00
}
2013-08-30 00:08:31 +00:00
default :
{
break ;
}
2013-05-18 22:04:01 +00:00
}
}
}
// exiting...
Exit ( ) ;
}
2013-05-18 04:49:44 +00:00
2014-02-15 23:28:13 +00:00
bool CWCheatEngine : : HasCheats ( ) {
return ! parts . empty ( ) ;
}
2013-05-18 04:49:44 +00:00
2014-02-15 23:28:13 +00:00
bool CheatsInEffect ( ) {
if ( ! cheatEngine | | ! cheatsEnabled )
return false ;
return cheatEngine - > HasCheats ( ) ;
}
2013-05-16 20:43:06 +00:00