2013-05-16 20:43:06 +00:00
# include "CwCheat.h"
2013-05-18 04:49:44 +00:00
# include "../Core/CoreTiming.h"
# include "../Core/CoreParameter.h"
2013-05-18 22:04:01 +00:00
# include "StringUtils.h"
# include "Common/FileUtil.h"
# include "Config.h"
2013-05-18 22:52:24 +00:00
# include "MIPS/MIPS.h"
2013-05-30 07:08:20 +00:00
# include "Core/Config.h"
2013-05-18 22:52:24 +00:00
2013-06-21 07:54:26 +00:00
const static std : : string CHEATS_DIR = " cheats " ;
2013-06-01 05:24:25 +00:00
static std : : string activeCheatFile ;
2013-05-18 04:49:44 +00:00
static int CheatEvent = - 1 ;
2013-06-18 22:50:28 +00:00
std : : string gameTitle ;
2013-05-23 11:10:39 +00:00
static CWCheatEngine * cheatEngine ;
void hleCheat ( u64 userdata , int cyclesLate ) ;
void trim2 ( std : : string & str ) ;
2013-05-18 04:49:44 +00:00
void __CheatInit ( ) {
2013-05-30 07:08:20 +00:00
//Moved createFullPath to CheatInit from the constructor because it spams the log and constantly checks if exists. In here, only checks once.
2013-07-29 20:19:53 +00:00
// Cheats aren't working on Android yet - need to figure out the directory structure
# ifndef ANDROID
2013-06-18 22:50:28 +00:00
gameTitle = g_paramSFO . GetValueString ( " DISC_ID " ) ;
2013-06-16 22:59:59 +00:00
activeCheatFile = CHEATS_DIR + " / " + gameTitle + " .ini " ;
2013-05-30 07:08:20 +00:00
2013-06-01 05:24:25 +00:00
File : : CreateFullPath ( CHEATS_DIR ) ;
2013-05-23 11:10:39 +00:00
if ( g_Config . bEnableCheats ) {
2013-06-01 05:24:25 +00:00
if ( ! File : : Exists ( activeCheatFile ) ) {
File : : CreateEmptyFile ( activeCheatFile ) ;
}
2013-05-30 07:08:20 +00:00
cheatEngine = new CWCheatEngine ( ) ;
cheatEngine - > CreateCodeList ( ) ;
g_Config . bReloadCheats = false ;
2013-05-23 11:10:39 +00:00
CheatEvent = CoreTiming : : RegisterEvent ( " CheatEvent " , & hleCheat ) ;
CoreTiming : : ScheduleEvent ( msToCycles ( 77 ) , CheatEvent , 0 ) ;
2013-05-18 22:04:01 +00:00
}
2013-07-29 20:19:53 +00:00
# endif
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-05-23 11:10:39 +00:00
if ( cheatEngine ! = 0 ) {
cheatEngine - > Exit ( ) ;
delete cheatEngine ;
2013-06-01 05:26:40 +00:00
cheatEngine = 0 ;
2013-05-23 11:10:39 +00:00
}
2013-05-18 04:49:44 +00:00
}
void hleCheat ( u64 userdata , int cyclesLate ) {
2013-05-18 22:04:01 +00:00
CoreTiming : : ScheduleEvent ( msToCycles ( 77 ) , CheatEvent , 0 ) ;
2013-05-30 07:08:20 +00:00
2013-06-24 08:31:29 +00:00
if ( ! cheatEngine )
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-06-24 08:31:29 +00:00
if ( g_Config . bEnableCheats ) {
2013-05-23 11:10:39 +00:00
cheatEngine - > Run ( ) ;
2013-05-18 22:04:01 +00:00
}
2013-05-18 04:49:44 +00:00
}
2013-05-18 22:04:01 +00:00
CWCheatEngine : : CWCheatEngine ( ) {
2013-05-23 11:10:39 +00:00
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 ;
}
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 " ) {
continue ; //Line indicates game Title, also not needed for cheats.
}
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 ] ;
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 ) ;
}
2013-06-18 22:50:28 +00:00
inline std : : vector < std : : string > makeCodeParts ( std : : vector < std : : string > CodesList ) { //Takes a single code line and creates a two-part vector for each code. Feeds to CreateCodeList
2013-06-16 22:59:59 +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 ] ;
for ( size_t j = 0 ; j < currentcode . length ( ) ; j + + ) {
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 ;
2013-05-30 07:08:20 +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 ) {
2013-05-30 07:08:20 +00:00
if ( currentCode > = parts . size ( ) ) {
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 ) ;
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 + + ) {
2013-06-01 05:40:50 +00:00
if ( GetNextCode ( ) [ 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 ( ) {
2013-05-18 04:49:44 +00:00
currentCode = codes . size ( ) ;
}
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 ;
2013-06-20 01:58:04 +00:00
if ( gameTitle = = " ULUS10563 " | | gameTitle = = " ULJS-00351 " | | gameTitle = = " NPJH50352 " ) //Offset to make God Eater Burst codes work
2013-06-18 22:50:28 +00:00
address - = 0x7EF00 ;
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
}
2013-06-17 22:44:41 +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
2013-06-01 05:24:25 +00:00
std : : ifstream list ( activeCheatFile . c_str ( ) ) ;
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-06-16 22:59:59 +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
}
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 ] ;
int 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 ) {
case 0 : // 8-bit write.
if ( Memory : : IsValidAddress ( addr ) ) {
Memory : : Write_U8 ( ( u8 ) arg , addr ) ;
}
break ;
case 0x1 : // 16-bit write
if ( Memory : : IsValidAddress ( addr ) ) {
Memory : : Write_U16 ( ( u16 ) arg , addr ) ;
}
break ;
case 0x2 : // 32-bit write
if ( Memory : : IsValidAddress ( addr ) ) {
Memory : : Write_U32 ( ( u32 ) arg , addr ) ;
}
break ;
case 0x3 : // Increment/Decrement
{
2013-05-23 11:10:39 +00:00
addr = GetAddress ( arg ) ;
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
int maxAddr = ( arg > > 16 ) & 0xFFFF ;
int stepAddr = ( arg & 0xFFFF ) * 4 ;
for ( int a = 0 ; a < maxAddr ; a + + ) {
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-05-30 08:49:15 +00:00
int destAddr = code [ 0 ] ;
2013-05-18 04:49:44 +00:00
if ( Memory : : IsValidAddress ( addr ) & & Memory : : IsValidAddress ( destAddr ) ) {
Memory : : Memcpy ( destAddr , Memory : : GetPointer ( addr ) , arg ) ;
}
}
break ;
case 0x6 : // Pointer commands
code = GetNextCode ( ) ;
2013-07-19 01:42:02 +00:00
if ( true ) {
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 ;
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 ( ) ;
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 ) ;
Memory : : Memcpy ( dstAddr , Memory : : GetPointer ( srcAddr ) , arg ) ;
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-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 ) ) {
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 ) ) {
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 ) ) {
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 ) ) {
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 ) ) {
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 ) ) {
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 ( ) ;
2013-07-19 00:22:16 +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
bool is8Bit = ( data > > 16 ) = = 0x0000 ;
int maxAddr = ( arg > > 16 ) & 0xFFFF ;
int stepAddr = ( arg & 0xFFFF ) * ( is8Bit ? 1 : 2 ) ;
for ( int a = 0 ; a < maxAddr ; a + + ) {
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 ) ) {
value = Memory : : Read_U32 ( addr ) ;
if ( value ! = arg ) {
2013-05-23 11:10:39 +00:00
SkipAllCodes ( ) ;
2013-05-18 04:49:44 +00:00
}
}
break ;
case 0xD : // Test commands & Jocker codes ( Someone will have to help me with these)
break ;
case 0xE : // Test commands, multiple skip
2013-05-18 08:21:57 +00:00
{
2013-05-18 22:04:01 +00:00
bool is8Bit = ( comm > > 24 ) = = 0x1 ;
2013-05-23 11:10:39 +00:00
addr = GetAddress ( arg & 0x0FFFFFFF ) ;
2013-05-18 22:04:01 +00:00
if ( Memory : : IsValidAddress ( addr ) ) {
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-05-18 22:04:01 +00:00
}
}
}
// exiting...
Exit ( ) ;
}
2013-05-18 04:49:44 +00:00
2013-05-16 20:43:06 +00:00