WIP Gecko(ocarina) code support: There are a bunch code types that need coding/fixing/cleanup, but many codes should be functional. The game properties and "Cheats Manager"(formally Action Replay Manager) dialogs now have a "Gecko Codes" tab to view/enable/disable codes. Currently, you must click "Edit Config" and manually add your codes to the [Gecko] inifile section of your gameinis for them to be displayed.(same format as the AR codes) I'm going to add Add/Edit dialogs similar to the AR codes and support codes with modifiers. I added the new files to scons as best as I could without testing :p.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5930 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
a103576a54
commit
fb36de2338
|
@ -1359,6 +1359,26 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="GeckoCode"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\Src\GeckoCode.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\GeckoCode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\GeckoCodeConfig.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\GeckoCodeConfig.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\Src\ConfigManager.cpp"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,852 @@
|
|||
|
||||
#include "GeckoCode.h"
|
||||
|
||||
#include "Thread.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
#include "vector"
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
// Code Types
|
||||
CODETYPE_WRITE_FILL = 0x0,
|
||||
CODETYPE_IF = 0x1,
|
||||
CODETYPE_BA_PO_OPS = 0x2,
|
||||
CODETYPE_FLOW_CONTROL = 0x3,
|
||||
CODETYPE_REGISTER_OPS = 0x4,
|
||||
CODETYPE_SPECIAL_IF = 0x5,
|
||||
CODETYPE_ASM_SWITCH_RANGE = 0x6,
|
||||
CODETYPE_END_CODES = 0x7,
|
||||
|
||||
// Data Types
|
||||
DATATYPE_8BIT = 0x0,
|
||||
DATATYPE_16BIT = 0x1,
|
||||
DATATYPE_32BIT = 0x2,
|
||||
};
|
||||
|
||||
// globals
|
||||
static u32 base_address = 0;
|
||||
static u32 pointer_address = 0;
|
||||
static u32 gecko_register[0x10] = {0};
|
||||
static struct
|
||||
{
|
||||
u32 address;
|
||||
u32 number;
|
||||
} block[0x10];
|
||||
|
||||
// codes execute when counter is 0
|
||||
static int code_execution_counter = 0;
|
||||
|
||||
// the currently active codes
|
||||
std::vector<GeckoCode> active_codes;
|
||||
|
||||
// return true if code execution is on
|
||||
inline bool CodeExecution()
|
||||
{
|
||||
return (0 == code_execution_counter);
|
||||
}
|
||||
|
||||
u32 GeckoCode::Code::GetAddress() const
|
||||
{
|
||||
return gcaddress + (use_po ? pointer_address : (base_address & 0xFE000000));
|
||||
}
|
||||
|
||||
static Common::CriticalSection active_codes_lock;
|
||||
|
||||
// currently running code
|
||||
static GeckoCode::Code current_code;
|
||||
|
||||
// Functions for each code type
|
||||
bool RamWriteAndFill();
|
||||
bool RegularIf();
|
||||
bool BaPoOps();
|
||||
bool FlowControl();
|
||||
bool RegisterOps();
|
||||
bool SpecialIf();
|
||||
bool AsmSwitchRange();
|
||||
bool EndCodes();
|
||||
|
||||
bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type);
|
||||
|
||||
void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
|
||||
{
|
||||
active_codes_lock.Enter();
|
||||
|
||||
active_codes.clear();
|
||||
// add enabled codes
|
||||
std::vector<GeckoCode>::const_iterator
|
||||
gcodes_iter = gcodes.begin(),
|
||||
gcodes_end = gcodes.end();
|
||||
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
|
||||
if (gcodes_iter->enabled)
|
||||
{
|
||||
// TODO: apply modifiers
|
||||
// TODO: don't need description or creator string, just takin up memory
|
||||
active_codes.push_back(*gcodes_iter);
|
||||
}
|
||||
|
||||
active_codes_lock.Leave();
|
||||
}
|
||||
|
||||
bool RunGeckoCode(const GeckoCode& gecko_code)
|
||||
{
|
||||
static bool (*code_type_funcs[])(void) =
|
||||
{ RamWriteAndFill, RegularIf, BaPoOps, FlowControl, RegisterOps, SpecialIf, AsmSwitchRange, EndCodes };
|
||||
|
||||
base_address = 0x80000000;
|
||||
pointer_address = 0x80000000;
|
||||
code_execution_counter = 0;
|
||||
|
||||
std::vector<GeckoCode::Code>::const_iterator
|
||||
codes_iter = gecko_code.codes.begin(),
|
||||
codes_end = gecko_code.codes.end();
|
||||
for (; codes_iter != codes_end; ++codes_iter)
|
||||
{
|
||||
const GeckoCode::Code& code = *codes_iter;
|
||||
|
||||
current_code = code;
|
||||
|
||||
bool result = true;
|
||||
|
||||
switch (code.type)
|
||||
{
|
||||
// These codetypes run even if code_execution is off
|
||||
case CODETYPE_IF :
|
||||
case CODETYPE_FLOW_CONTROL :
|
||||
case CODETYPE_SPECIAL_IF :
|
||||
case CODETYPE_ASM_SWITCH_RANGE :
|
||||
case CODETYPE_END_CODES :
|
||||
result = code_type_funcs[code.type]();
|
||||
break;
|
||||
|
||||
// The rest of the codetypes only run if code_execution is on
|
||||
default :
|
||||
if (CodeExecution())
|
||||
result = code_type_funcs[code.type]();
|
||||
break;
|
||||
}
|
||||
|
||||
// code failed
|
||||
if (false == result)
|
||||
{
|
||||
PanicAlert("GeckoCode failed to run (CT%i CST%i) (%s)"
|
||||
"(Either a bad code or the code type is not yet supported.)"
|
||||
, code.type, code.subtype, gecko_code.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RunActiveCodes()
|
||||
{
|
||||
if (false == active_codes_lock.TryEnter())
|
||||
return true;
|
||||
|
||||
std::vector<GeckoCode>::const_iterator
|
||||
gcodes_iter = active_codes.begin(),
|
||||
gcodes_end = active_codes.end();
|
||||
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
|
||||
{
|
||||
RunGeckoCode(*gcodes_iter);
|
||||
// we don't need to stop all codes if one fails, maybe
|
||||
//if (false == RunGeckoCode(*gcodes_iter))
|
||||
//return false;
|
||||
}
|
||||
|
||||
active_codes_lock.Leave();
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT0: Direct ram write/fill
|
||||
// NOT COMPLETE, last 2 subtypes not started
|
||||
bool RamWriteAndFill()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
u32 new_addr = code.GetAddress();
|
||||
const u32& data = code.data;
|
||||
|
||||
u16 count = (data >> 16) + 1;
|
||||
|
||||
switch (code.subtype)
|
||||
{
|
||||
// CST0: 8bits Write & Fill
|
||||
case 0x0 :
|
||||
while (count--)
|
||||
{
|
||||
Memory::Write_U16((u16)data, new_addr);
|
||||
++new_addr;
|
||||
}
|
||||
break;
|
||||
|
||||
// CST1: 16bits Write & Fill
|
||||
case 0x1 :
|
||||
while (count--)
|
||||
{
|
||||
Memory::Write_U16((u16)data, new_addr);
|
||||
new_addr += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
// CST2: 32bits Write
|
||||
case 0x2 :
|
||||
Memory::Write_U32((u32)data, new_addr);
|
||||
break;
|
||||
|
||||
// CST3: String Code
|
||||
case 0x3 :
|
||||
// TODO:
|
||||
return false;
|
||||
break;
|
||||
|
||||
// CST4: Serial Code
|
||||
case 0x4 :
|
||||
{
|
||||
// TODO: complete
|
||||
u32 new_data = data;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
// INVALID SUBTYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT1 Regular If codes (16/32 bits)
|
||||
// COMPLETE
|
||||
bool RegularIf()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
|
||||
const bool is_endif = !!(code.address & 0x1);
|
||||
|
||||
// if code_execution is off and this is an endif, decrease the execution counter
|
||||
if (false == CodeExecution())
|
||||
{
|
||||
if (is_endif)
|
||||
--code_execution_counter;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
// if code_execution is on, execute the conditional
|
||||
if (CodeExecution())
|
||||
{
|
||||
const u32 new_addr = code.GetAddress() & ~0x1;
|
||||
const u32& data = code.data;
|
||||
|
||||
s32 read_value = 0;
|
||||
s32 data_value = 0;
|
||||
|
||||
// 16bit vs 32bit
|
||||
if (code.subtype & 0x4)
|
||||
{
|
||||
// 16bits
|
||||
read_value = Memory::Read_U16(new_addr) & ~(data >> 16);
|
||||
data_value = (data & 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 32bits
|
||||
read_value = Memory::Read_U32(new_addr);
|
||||
data_value = data;
|
||||
}
|
||||
|
||||
switch (code.subtype & 0x3)
|
||||
{
|
||||
// CST0 : 32bits (endif, then) If equal
|
||||
// CST4 : 16bits (endif, then) If equal
|
||||
case 0x0 :
|
||||
result = (read_value == data_value);
|
||||
break;
|
||||
|
||||
// CST1 : 32bits (endif, then) If not equal
|
||||
// CST5 : 16bits (endif, then) If not equal
|
||||
case 0x1 :
|
||||
result = (read_value != data_value);
|
||||
break;
|
||||
|
||||
// CST2 : 32bits (endif, then) If greater
|
||||
// CST6 : 16bits (endif, then) If greater
|
||||
case 0x2 :
|
||||
result = (read_value > data_value);
|
||||
break;
|
||||
|
||||
// CST3 : 32bits (endif, then) If lower
|
||||
// CST7 : 16bits (endif, then) If lower
|
||||
case 0x3 :
|
||||
result = (read_value < data_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if the conditional returned false, or it never ran because execution is off,
|
||||
// increase the code execution counter
|
||||
if (false == result)
|
||||
++code_execution_counter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT2 Base Address/Pointer Operations
|
||||
// NOT COMPLETE, last 2 subtypes aren't done
|
||||
bool BaPoOps()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
|
||||
// base_address vs pointer (ba vs po)
|
||||
u32& change_address = (code.subtype & 0x4) ? pointer_address : base_address;
|
||||
|
||||
// 4STYZ00N XXXXXXXX
|
||||
u32 new_data = code.data;
|
||||
|
||||
// append grN
|
||||
if (code.z)
|
||||
new_data += gecko_register[code.n];
|
||||
|
||||
// append ba or po (depending on last nibble's first bit)
|
||||
if (code.y)
|
||||
new_data += (code.use_po ? pointer_address : base_address);
|
||||
|
||||
// append to current value (not used in all subtypes, T will be 0 in those)
|
||||
if (code.t)
|
||||
new_data += change_address;
|
||||
|
||||
switch (code.subtype & 0x3)
|
||||
{
|
||||
// CST0 : Load into Base Address
|
||||
// CST4 : Load into Pointer
|
||||
case 0x0 :
|
||||
change_address = Memory::Read_U32(new_data);
|
||||
break;
|
||||
|
||||
// CST1 : Set Base Address to
|
||||
// CST5 : Set Pointer to
|
||||
case 0x1 :
|
||||
change_address = new_data;
|
||||
break;
|
||||
|
||||
// CST2 : Save Base Address to
|
||||
// CST6 : Save Pointer to
|
||||
case 0x2 :
|
||||
Memory::Write_U32(change_address, new_data);
|
||||
break;
|
||||
|
||||
// CST3 : Put next line of code location into the Base Address
|
||||
// CST7 : Put grN's location into the Pointer
|
||||
|
||||
// conflicting documentation, one doc says CST7 is the same as CST3 but with po
|
||||
case 0x3 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT3 Repeat/Goto/Gosub/Return
|
||||
// NOT COMPLETE
|
||||
bool FlowControl()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
|
||||
// only the return subtype runs when code execution is off
|
||||
if (false == CodeExecution() && code.subtype != 0x2)
|
||||
return true;
|
||||
|
||||
// not all of these are used in all subtypes
|
||||
const u8 block_num = (u8)(code.data & 0xF);
|
||||
const s16 code_offset = (s16)code.address;
|
||||
|
||||
switch (code.subtype)
|
||||
{
|
||||
// CST0 : Set Repeat
|
||||
case 0x0 :
|
||||
// TODO: store address of next code as well
|
||||
block[block_num].address = code.address & 0xFFFF;
|
||||
// block[block_num].number = ;
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST1 : Execute Repeat
|
||||
case 0x1 :
|
||||
if (block[block_num].number)
|
||||
{
|
||||
--block[block_num].number;
|
||||
// TODO: jump to code block
|
||||
}
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST2 : Return
|
||||
case 0x2 :
|
||||
if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
|
||||
// TODO: jump to block[block_num].number
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST3 : Goto
|
||||
case 0x3 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST4 : Gosub
|
||||
case 0x4 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// INVALID SUBTYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT4 Gecko Register Operations
|
||||
// NOT COMPLETE, need to do memory copy 1,2
|
||||
bool RegisterOps()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
|
||||
// 80TYZZZN XXXXXXXX
|
||||
|
||||
u32 new_data = code.data;
|
||||
|
||||
// append ba or po (depending on last nibble's first bit)
|
||||
if (code.y)
|
||||
new_data += (code.use_po ? pointer_address : base_address);
|
||||
|
||||
u32& geckreg = gecko_register[code.n];
|
||||
|
||||
switch (code.subtype)
|
||||
{
|
||||
// CST0 : Set Gecko Register to
|
||||
case 0x0 :
|
||||
// append to or set register
|
||||
geckreg = new_data + (code.t ? geckreg : 0);
|
||||
break;
|
||||
|
||||
// CST1 : Load into Gecko Register
|
||||
case 0x1 :
|
||||
switch (code.t)
|
||||
{
|
||||
// 8bit
|
||||
case DATATYPE_8BIT :
|
||||
geckreg = Memory::Read_U8(new_data);
|
||||
break;
|
||||
|
||||
// 16bit
|
||||
case DATATYPE_16BIT :
|
||||
geckreg = Memory::Read_U16(new_data);
|
||||
break;
|
||||
|
||||
// 32bit
|
||||
case DATATYPE_32BIT :
|
||||
geckreg = Memory::Read_U32(new_data);
|
||||
break;
|
||||
|
||||
// INVALID DATATYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// CST2 : Save Gecko Register to
|
||||
case 0x2 :
|
||||
switch (code.t)
|
||||
{
|
||||
// 8bit
|
||||
case DATATYPE_8BIT :
|
||||
for (u16 i = 0; i <= code.z; ++i)
|
||||
Memory::Write_U8((u8)geckreg, new_data + i);
|
||||
break;
|
||||
|
||||
// 16bit
|
||||
case DATATYPE_16BIT :
|
||||
for (u16 i = 0; i <= code.z; ++i)
|
||||
Memory::Write_U16((u16)geckreg, new_data + (i << 1));
|
||||
break;
|
||||
|
||||
// 32bit
|
||||
case DATATYPE_32BIT :
|
||||
for (u16 i = 0; i <= code.z; ++i)
|
||||
Memory::Write_U32((u32)geckreg, new_data + (i << 2));
|
||||
break;
|
||||
|
||||
// INVALID DATATYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// CST3 : Gecko Register / Direct Value operations
|
||||
// CST4 : Gecko Registers operations
|
||||
case 0x3 :
|
||||
case 0x4 :
|
||||
{
|
||||
// subtype 3 uses value in .data subtype 4 uses register
|
||||
u32 right_val = (code.subtype & 0x1 ? code.data : gecko_register[code.data & 0xF]);
|
||||
if (code.y & 0x2)
|
||||
right_val = Memory::Read_U32(right_val);
|
||||
|
||||
u32 left_val = geckreg;
|
||||
if (code.y & 0x1)
|
||||
left_val = Memory::Read_U32(left_val);
|
||||
|
||||
if (false == MathOperation(geckreg, left_val, right_val, code.t))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
// CST5 : Memory Copy 1
|
||||
case 0x5 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST6 : Memory Copy 2
|
||||
case 0x6 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// INVALID SUBTYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOT COMPLETE, at least one op needs to be coded/fixed
|
||||
bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type)
|
||||
{
|
||||
// ? = T :
|
||||
switch (type)
|
||||
{
|
||||
// 0 : add (+)
|
||||
case 0x0 :
|
||||
ret = left + right;
|
||||
break;
|
||||
|
||||
// 1 : mul (*)
|
||||
case 0x1 :
|
||||
ret = left * right;
|
||||
break;
|
||||
|
||||
// 2 : or (|)
|
||||
case 0x2 :
|
||||
ret = left | right;
|
||||
break;
|
||||
|
||||
// 3 : and (&)
|
||||
case 0x3 :
|
||||
ret = left & right;
|
||||
break;
|
||||
|
||||
// 4 : xor (^)
|
||||
case 0x4 :
|
||||
ret = left ^ right;
|
||||
break;
|
||||
|
||||
// 5 : slw (<<)
|
||||
case 0x5 :
|
||||
ret = left << right;
|
||||
break;
|
||||
|
||||
// 6 : srw (>>)
|
||||
case 0x6 :
|
||||
ret = left >> right;
|
||||
break;
|
||||
|
||||
// TODO: this one good?
|
||||
// 7 : rol (rotate left)
|
||||
case 0x7 :
|
||||
ret = (left << right) | (left >> (8 - right));
|
||||
break;
|
||||
|
||||
// 8 : asr (arithmetic shift right)
|
||||
case 0x8 :
|
||||
// TODO: wuts this
|
||||
return false;
|
||||
break;
|
||||
|
||||
// TODO: these float ops good?
|
||||
// A : fadds (single float add)
|
||||
case 0xA :
|
||||
*(float*)&ret = *(float*)&left + *(float*)&right;
|
||||
break;
|
||||
|
||||
// B : fmuls (single float mul)
|
||||
case 0xB :
|
||||
*(float*)&ret = *(float*)&left * *(float*)&right;
|
||||
break;
|
||||
|
||||
// INVALID OPERATION TYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT5: Special If codes (16bits)
|
||||
// NOT COMPLETE, part 2 (counter stuff) not started
|
||||
bool SpecialIf()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
|
||||
const bool is_endif = !!(code.address & 0x1);
|
||||
|
||||
// if code_execution is off and this is an endif, decrease the execution counter
|
||||
if (false == CodeExecution())
|
||||
{
|
||||
if (is_endif)
|
||||
--code_execution_counter;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
// if code_execution is on, execute the conditional
|
||||
if (CodeExecution())
|
||||
{
|
||||
const u32 addr = code.GetAddress() & ~0x1;
|
||||
const u32& data = code.data;
|
||||
|
||||
// A-______ NM00YYYY
|
||||
|
||||
if (code.subtype ^ 0x4)
|
||||
{
|
||||
// CT5 Part1 : Unknown values comparison
|
||||
|
||||
const u8 n = (u8)(data >> 28);
|
||||
const u8 m = (u8)((data >> 24) & 0xF);
|
||||
const u16 y = (u16)data;
|
||||
|
||||
// TODO: should these be signed? probably?
|
||||
const s16 left_val = Memory::Read_U16(((0xF == n) ? addr : gecko_register[n]) & ~y);
|
||||
const s16 right_val = Memory::Read_U16(((0xF == m) ? addr : gecko_register[m]) & ~y);
|
||||
|
||||
switch (code.subtype)
|
||||
{
|
||||
// CST0 : 16bits (endif, then) If equal
|
||||
case 0x0 :
|
||||
result = (left_val == right_val);
|
||||
break;
|
||||
|
||||
// CST1 : 16bits (endif, then) If not equal
|
||||
case 0x1 :
|
||||
result = (left_val != right_val);
|
||||
break;
|
||||
|
||||
// CST2 : 16bits (endif, then) If greater
|
||||
case 0x2 :
|
||||
result = (left_val > right_val);
|
||||
break;
|
||||
|
||||
// CST3 : 16bits (endif, then) If lower
|
||||
case 0x3 :
|
||||
result = (left_val < right_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// CT5 Part2 : 16bits Counter check
|
||||
// TODO:
|
||||
|
||||
const u16 z = (u16)(data >> 16);
|
||||
|
||||
switch (code.subtype)
|
||||
{
|
||||
// CST4 : 16bits (endif, then) If counter value equal
|
||||
case 0x4 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST5 : 16bits (endif, then) If counter value not equal
|
||||
case 0x5 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST6 : 16bits (endif, then) If counter value greater
|
||||
case 0x6 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST7 : 16bits (endif, then) If counter value lower
|
||||
case 0x7 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the conditional returned false, or it never ran because execution is off, increase the code execution counter
|
||||
if (false == result)
|
||||
++code_execution_counter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT6 ASM Codes, On/Off switch and Address Range Check
|
||||
// NOT COMPLETE, hardly started
|
||||
// fix the logic flow in this one
|
||||
bool AsmSwitchRange()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
|
||||
// only used for the last 2 subtypes
|
||||
const bool is_endif = !!(code.address & 0x1);
|
||||
|
||||
// only run if code_execution is set or this code is a switch or rangecheck subtype
|
||||
// the switch and rangecheck run if exectution_counter is 1 (directly inside the failed if) if they are an endif
|
||||
if (false == CodeExecution())
|
||||
{
|
||||
if (code.subtype < 0x6)
|
||||
return true;
|
||||
else if (false == (1 == code_execution_counter && is_endif))
|
||||
return true;
|
||||
}
|
||||
|
||||
const u32& data = code.data;
|
||||
|
||||
switch (code.subtype)
|
||||
{
|
||||
// CST0 : Execute following ASM Code
|
||||
case 0x0 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST1 : Insert ASM code in the game
|
||||
case 0x1 :
|
||||
// TODO:
|
||||
return false;
|
||||
break;
|
||||
|
||||
// CST3 : Create a branch
|
||||
case 0x3 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST6 : On/Off switch
|
||||
case 0x6 :
|
||||
// TODO:
|
||||
return false; //
|
||||
break;
|
||||
|
||||
// CST7 : Address range check (If... code)
|
||||
case 0x7 :
|
||||
if (code_execution_counter)
|
||||
{
|
||||
const u32 addr = (code.use_po ? pointer_address : base_address);
|
||||
if (addr >= (data & 0xFFFF0000) && addr <= (data << 16))
|
||||
--code_execution_counter;
|
||||
}
|
||||
break;
|
||||
|
||||
// INVALID SUBTYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CT7 End of codes, Endif (Else)
|
||||
// COMPLETE, maybe
|
||||
bool EndCodes()
|
||||
{
|
||||
const GeckoCode::Code& code = current_code;
|
||||
const u32& data = code.data;
|
||||
|
||||
const u32 x = (data & 0xFFFF0000);
|
||||
const u32 y = (data << 16);
|
||||
|
||||
// these 2 do not happen in the "CST7 : End of Code", but in that subtype they will be 0
|
||||
if (x)
|
||||
base_address = x;
|
||||
if (y)
|
||||
pointer_address = y;
|
||||
|
||||
switch (code.subtype)
|
||||
{
|
||||
// CST0 : Full Terminator
|
||||
case 0x0 :
|
||||
// clears the code execution status
|
||||
// TODO: should this always stop all codes, even if execution is off?
|
||||
if (CodeExecution())
|
||||
code_execution_counter = -1; // silly maybe
|
||||
break;
|
||||
|
||||
// CST1 : Endif (+else)
|
||||
case 0x1 :
|
||||
{
|
||||
// apply endifs
|
||||
const u8 v = (u8)code.address;
|
||||
if (code_execution_counter >= v)
|
||||
code_execution_counter -= v;
|
||||
else
|
||||
{
|
||||
// too many endifs
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool is_else = !!(code.address & 0x00100000);
|
||||
// apply else
|
||||
if (is_else)
|
||||
if (code_execution_counter <= 1)
|
||||
code_execution_counter ^= 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// CST7 : End of Code
|
||||
case 0x7 :
|
||||
// tell the code handler that there are no more codes in the code list
|
||||
// TODO: should this always stop all codes, even if execution is off?
|
||||
if (CodeExecution())
|
||||
code_execution_counter = -1; // silly maybe
|
||||
break;
|
||||
|
||||
// INVALID SUBTYPE
|
||||
default :
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Gecko
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
#ifndef __GECKOCODE_h__
|
||||
#define __GECKOCODE_h__
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
||||
class GeckoCode
|
||||
{
|
||||
public:
|
||||
|
||||
GeckoCode() : enabled(false) {}
|
||||
|
||||
struct Code
|
||||
{
|
||||
union
|
||||
{
|
||||
u32 address;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 gcaddress : 25;
|
||||
u32 subtype: 3;
|
||||
u32 use_po : 1;
|
||||
u32 type: 3;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 n : 4;
|
||||
u32 z : 12;
|
||||
u32 y : 4;
|
||||
u32 t : 4;
|
||||
//u32 s : 4;
|
||||
//u32 : 4;
|
||||
};// subsubtype;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
u32 data;
|
||||
//struct
|
||||
//{
|
||||
//
|
||||
//};
|
||||
};
|
||||
|
||||
u32 GetAddress() const;
|
||||
};
|
||||
|
||||
std::vector<Code> codes;
|
||||
std::string name, description, creator;
|
||||
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
|
||||
bool RunActiveCodes();
|
||||
|
||||
} // namespace Gecko
|
||||
|
||||
#endif
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
#include "GeckoCodeConfig.h"
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#define GECKO_CODE_INI_SECTION "Gecko"
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
||||
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
inifile.GetLines(GECKO_CODE_INI_SECTION, lines);
|
||||
|
||||
GeckoCode gcode;
|
||||
|
||||
std::vector<std::string>::const_iterator
|
||||
lines_iter = lines.begin(),
|
||||
lines_end = lines.end();
|
||||
for (; lines_iter!=lines_end; ++lines_iter)
|
||||
{
|
||||
if (lines_iter->empty())
|
||||
continue;
|
||||
|
||||
std::istringstream ss(*lines_iter);
|
||||
|
||||
switch ((*lines_iter)[0])
|
||||
{
|
||||
|
||||
// enabled or disabled code
|
||||
case '+' :
|
||||
ss.seekg(1);
|
||||
case '$' :
|
||||
if (gcode.name.size())
|
||||
gcodes.push_back(gcode);
|
||||
gcode = GeckoCode();
|
||||
gcode.enabled = (1 == ss.tellg()); // silly
|
||||
ss.seekg(1, std::ios_base::cur);
|
||||
// read the code name
|
||||
std::getline(ss, gcode.name, '['); // stop at [ character (begining of contributer name)
|
||||
gcode.name = StripSpaces(gcode.name);
|
||||
// read the code creator name
|
||||
std::getline(ss, gcode.creator, ']');
|
||||
break;
|
||||
|
||||
// description
|
||||
case '*':
|
||||
ss.seekg(1);
|
||||
std::getline(ss, gcode.description);
|
||||
break;
|
||||
|
||||
// start of code option list
|
||||
case ':':
|
||||
// TODO:
|
||||
break;
|
||||
|
||||
// either part of the code, or an option choice
|
||||
default :
|
||||
// TODO: check if we are reading an option list
|
||||
{
|
||||
GeckoCode::Code new_code;
|
||||
// TODO: support options
|
||||
ss >> std::hex >> new_code.address >> new_code.data;
|
||||
gcode.codes.push_back(new_code);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// add the last code
|
||||
if (gcode.name.size())
|
||||
gcodes.push_back(gcode);
|
||||
}
|
||||
|
||||
// used by the SaveGeckoCodes function
|
||||
void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
if (gcode.enabled)
|
||||
name += '+';
|
||||
|
||||
// save the name
|
||||
name += '$';
|
||||
name += gcode.name;
|
||||
|
||||
// save the creator name
|
||||
if (gcode.creator.size())
|
||||
{
|
||||
name += " [";
|
||||
name += gcode.creator;
|
||||
name += ']';
|
||||
}
|
||||
|
||||
lines.push_back(name);
|
||||
|
||||
// save the description
|
||||
if (gcode.description.size())
|
||||
lines.push_back(std::string("*") + gcode.description);
|
||||
|
||||
// save all the code lines
|
||||
std::vector<GeckoCode::Code>::const_iterator
|
||||
codes_iter = gcode.codes.begin(),
|
||||
codes_end = gcode.codes.end();
|
||||
for (; codes_iter!=codes_end; ++codes_iter)
|
||||
{
|
||||
//ss << std::hex << codes_iter->address << ' ' << codes_iter->data;
|
||||
lines.push_back(StringFromFormat("%08X %08X", codes_iter->address, codes_iter->data));
|
||||
//ss.clear();
|
||||
}
|
||||
|
||||
//lines.push_back("BLAH");
|
||||
|
||||
// TODO: save the options
|
||||
}
|
||||
|
||||
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
|
||||
std::vector<GeckoCode>::const_iterator
|
||||
gcodes_iter = gcodes.begin(),
|
||||
gcodes_end = gcodes.end();
|
||||
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
|
||||
{
|
||||
SaveGeckoCode(lines, *gcodes_iter);
|
||||
}
|
||||
|
||||
inifile.SetLines(GECKO_CODE_INI_SECTION, lines);
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
#ifndef __GECKOCODECONFIG_h__
|
||||
#define __GECKOCODECONFIG_h__
|
||||
|
||||
#include "GeckoCode.h"
|
||||
|
||||
#include "IniFile.h"
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
||||
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes);
|
||||
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes);
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -34,6 +34,8 @@
|
|||
#include "PatchEngine.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "ActionReplay.h"
|
||||
#include "GeckoCode.h";
|
||||
#include "GeckoCodeConfig.h";
|
||||
#include "FileUtil.h"
|
||||
|
||||
using namespace Common;
|
||||
|
@ -154,6 +156,12 @@ void LoadPatches(const char *gameID)
|
|||
if (ini.Load(filename.c_str())) {
|
||||
LoadPatchSection("OnFrame", onFrame, ini);
|
||||
ActionReplay::LoadCodes(ini, false);
|
||||
|
||||
// lil silly
|
||||
std::vector<Gecko::GeckoCode> gcodes;
|
||||
Gecko::LoadCodes(ini, gcodes);
|
||||
Gecko::SetActiveCodes(gcodes);
|
||||
|
||||
LoadSpeedhacks("Speedhacks", speedHacks, ini);
|
||||
LoadDiscList("DiscList", discList, ini);
|
||||
}
|
||||
|
@ -197,6 +205,8 @@ void ApplyFramePatches()
|
|||
void ApplyARPatches()
|
||||
{
|
||||
ActionReplay::RunAllActive();
|
||||
// w/e this can be changed later
|
||||
Gecko::RunActiveCodes();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -6,6 +6,8 @@ import sys
|
|||
files = [
|
||||
"ActionReplay.cpp",
|
||||
"ARDecrypt.cpp",
|
||||
"GeckoCode.cpp",
|
||||
"GeckoCodeConfig.cpp",
|
||||
"ConfigManager.cpp",
|
||||
"Console.cpp",
|
||||
"Core.cpp",
|
||||
|
|
|
@ -864,6 +864,14 @@
|
|||
RelativePath=".\src\GameListCtrl.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\GeckoCodeDiag.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\GeckoCodeDiag.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\Globals.h"
|
||||
>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ActionReplay.h"
|
||||
#include "Core.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "VolumeHandler.h"
|
||||
#include "ISOProperties.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
|
@ -43,6 +44,17 @@ wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
|||
// Load Data
|
||||
Load_ARCodes();
|
||||
|
||||
// Load Gecko Codes :/
|
||||
{
|
||||
const DiscIO::IVolume* const vol = VolumeHandler::GetVolume();
|
||||
if (vol)
|
||||
{
|
||||
m_gameini_path = std::string(File::GetUserPath(D_GAMECONFIG_IDX)) + vol->GetUniqueID() + ".ini";
|
||||
m_gameini.Load(m_gameini_path);
|
||||
m_geckocode_panel->LoadCodes(m_gameini);
|
||||
}
|
||||
}
|
||||
|
||||
Center();
|
||||
Show();
|
||||
}
|
||||
|
@ -65,9 +77,6 @@ void wxCheatsWindow::Init_ChildControls()
|
|||
m_Label_Codename = new wxStaticText(m_Tab_Cheats, wxID_ANY, _T("Name: "), wxDefaultPosition, wxDefaultSize);
|
||||
m_GroupBox_Info = new wxStaticBox(m_Tab_Cheats, wxID_ANY, _T("Code Info"), wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
wxButton* const button_applycodes = new wxButton(m_Tab_Cheats, wxID_ANY, _T("Apply Changes"), wxDefaultPosition, wxDefaultSize);
|
||||
_connect_macro_(button_applycodes, wxCheatsWindow::OnEvent_ButtonUpdateCodes_Press, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||
|
||||
m_Label_NumCodes = new wxStaticText(m_Tab_Cheats, wxID_ANY, _T("Number Of Codes: "), wxDefaultPosition, wxDefaultSize);
|
||||
m_ListBox_CodesList = new wxListBox(m_Tab_Cheats, wxID_ANY, wxDefaultPosition, wxSize(120, 150), 0, 0, wxLB_HSCROLL);
|
||||
|
||||
|
@ -76,13 +85,9 @@ void wxCheatsWindow::Init_ChildControls()
|
|||
sGroupBoxInfo->Add(m_Label_NumCodes, 0, wxALL, 5);
|
||||
sGroupBoxInfo->Add(m_ListBox_CodesList, 1, wxALL, 5);
|
||||
|
||||
wxBoxSizer* sB1 = new wxBoxSizer(wxVERTICAL);
|
||||
sB1->Add(button_applycodes, 0, wxALL | wxEXPAND, 5);
|
||||
sB1->Add(sGroupBoxInfo, 1, wxALL, 5);
|
||||
|
||||
wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_tab_cheats->Add(m_CheckListBox_CheatsList, 1, wxEXPAND | wxTOP | wxBOTTOM | wxLEFT, 10);
|
||||
sizer_tab_cheats->Add(sB1, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5);
|
||||
sizer_tab_cheats->Add(sGroupBoxInfo, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5);
|
||||
|
||||
m_Tab_Cheats->SetSizerAndFit(sizer_tab_cheats);
|
||||
|
||||
|
@ -112,14 +117,19 @@ void wxCheatsWindow::Init_ChildControls()
|
|||
m_Tab_Log->SetSizerAndFit(sTabLog);
|
||||
|
||||
// Add Tabs to Notebook
|
||||
m_Notebook_Main->AddPage(m_Tab_Cheats, _T("Codes List"));
|
||||
m_Notebook_Main->AddPage(m_Tab_Cheats, _T("AR Codes"));
|
||||
m_geckocode_panel = new Gecko::CodeConfigPanel(m_Notebook_Main);
|
||||
m_Notebook_Main->AddPage(m_geckocode_panel, wxT("Gecko Codes"));
|
||||
m_Notebook_Main->AddPage(tab_cheat_search, _T("Cheat Search"));
|
||||
m_Notebook_Main->AddPage(m_Tab_Log, _T("Logging"));
|
||||
|
||||
// Button Strip
|
||||
wxButton* const button_apply = new wxButton(panel, wxID_ANY, _T("Apply"), wxDefaultPosition, wxDefaultSize);
|
||||
_connect_macro_(button_apply, wxCheatsWindow::OnEvent_ApplyChanges_Press, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||
wxButton* const button_close = new wxButton(panel, wxID_ANY, _T("Close"), wxDefaultPosition, wxDefaultSize);
|
||||
_connect_macro_(button_close, wxCheatsWindow::OnEvent_ButtonClose_Press, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||
wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL);
|
||||
sButtons->Add(button_apply, 1, wxRIGHT, 5);
|
||||
sButtons->Add(button_close, 1, 0, 0);
|
||||
|
||||
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
|
||||
|
@ -280,12 +290,23 @@ void wxCheatsWindow::OnEvent_CheatsList_ItemToggled(wxCommandEvent& WXUNUSED (ev
|
|||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ButtonUpdateCodes_Press(wxCommandEvent& WXUNUSED (event))
|
||||
void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
// Appply AR Code changes
|
||||
for (size_t i = 0; i < indexList.size(); i++)
|
||||
{
|
||||
ActionReplay::SetARCode_IsActive(m_CheckListBox_CheatsList->IsChecked(indexList[i].uiIndex), indexList[i].index);
|
||||
}
|
||||
|
||||
// Apply Gecko Code changes
|
||||
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());
|
||||
|
||||
// save gameini, with changed gecko codes
|
||||
if (m_gameini_path.size())
|
||||
{
|
||||
Gecko::SaveCodes(m_gameini, m_geckocode_panel->GetCodes());
|
||||
m_gameini.Save(m_gameini_path);
|
||||
}
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent& WXUNUSED (event))
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
#include "ActionReplay.h"
|
||||
|
||||
#include "GeckoCodeDiag.h"
|
||||
|
||||
#include "Filesystem.h"
|
||||
#include "IniFile.h"
|
||||
|
||||
|
@ -143,6 +145,10 @@ class wxCheatsWindow : public wxFrame
|
|||
|
||||
std::vector<ARCodeIndex> indexList;
|
||||
|
||||
Gecko::CodeConfigPanel *m_geckocode_panel;
|
||||
IniFile m_gameini;
|
||||
std::string m_gameini_path;
|
||||
|
||||
void Init_ChildControls();
|
||||
|
||||
void Load_ARCodes();
|
||||
|
@ -156,8 +162,8 @@ class wxCheatsWindow : public wxFrame
|
|||
void OnEvent_CheatsList_ItemSelected(wxCommandEvent& event);
|
||||
void OnEvent_CheatsList_ItemToggled(wxCommandEvent& event);
|
||||
|
||||
// $ Update Active Codes Button
|
||||
void OnEvent_ButtonUpdateCodes_Press(wxCommandEvent& event);
|
||||
// $ Apply Changes Button
|
||||
void OnEvent_ApplyChanges_Press(wxCommandEvent& event);
|
||||
|
||||
// $ Update Log Button
|
||||
void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event);
|
||||
|
|
|
@ -186,7 +186,7 @@ void CFrame::CreateMenu()
|
|||
toolsMenu->Append(IDM_LUA, _T("New &Lua Console"));
|
||||
toolsMenu->Append(IDM_MEMCARD, _T("&Memcard Manager (GC)"));
|
||||
toolsMenu->Append(IDM_IMPORTSAVE, _T("Wii Save Import"));
|
||||
toolsMenu->Append(IDM_CHEATS, _T("Action &Replay Manager"));
|
||||
toolsMenu->Append(IDM_CHEATS, _T("&Cheats Manager"));
|
||||
|
||||
toolsMenu->Append(IDM_NETPLAY, _T("Start &NetPlay"));
|
||||
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
#include "GeckoCodeDiag.h"
|
||||
|
||||
#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler(f), (wxObject*)0, (wxEvtHandler*)s)
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
||||
static const wxString wxstr_name(wxT("Name: ")),
|
||||
wxstr_description(wxT("Description: ")),
|
||||
wxstr_creator(wxT("Creator: "));
|
||||
|
||||
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
|
||||
: wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize)
|
||||
{
|
||||
m_listbox_gcodes = new wxCheckListBox(this, -1, wxDefaultPosition, wxDefaultSize);
|
||||
_connect_macro_(m_listbox_gcodes, CodeConfigPanel::UpdateInfoBox, wxEVT_COMMAND_LISTBOX_SELECTED, this);
|
||||
_connect_macro_(m_listbox_gcodes, CodeConfigPanel::ToggleCode, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, this);
|
||||
|
||||
m_infobox.label_name = new wxStaticText(this, -1, wxstr_name);
|
||||
m_infobox.label_creator = new wxStaticText(this, -1, wxstr_creator);
|
||||
m_infobox.label_description = new wxStaticText(this, -1, wxstr_description);
|
||||
m_infobox.listbox_codes = new wxListBox(this, -1, wxDefaultPosition, wxSize(-1, 64));
|
||||
|
||||
// TODO: buttons to add/edit codes
|
||||
|
||||
// sizers
|
||||
wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_infobox->Add(m_infobox.label_name, 0, wxLEFT | wxBOTTOM, 5);
|
||||
sizer_infobox->Add(m_infobox.label_creator, 0, wxLEFT | wxBOTTOM, 5);
|
||||
sizer_infobox->Add(m_infobox.label_description, 0, wxLEFT | wxBOTTOM, 5);
|
||||
sizer_infobox->Add(m_infobox.listbox_codes, 0, wxLEFT | wxBOTTOM, 5);
|
||||
|
||||
//wxBoxSizer* const sizer_horz = new wxBoxSizer(wxHORIZONTAL);
|
||||
//sizer_horz->Add(sizer_infobox, 1, 0);
|
||||
|
||||
// silly
|
||||
//if (show_apply_button)
|
||||
//{
|
||||
// wxButton* const btn_apply = new wxButton(this, -1, wxT("Apply Changes"), wxDefaultPosition, wxSize(128, -1));
|
||||
// _connect_macro_(btn_apply, CodeConfigPanel::ApplyChanges, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||
// sizer_horz->Add(btn_apply, 0, wxALIGN_RIGHT | wxALIGN_BOTTOM);
|
||||
//}
|
||||
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5);
|
||||
sizer_main->Add(sizer_infobox, 0, wxALL | wxEXPAND, 5);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
}
|
||||
|
||||
void CodeConfigPanel::LoadCodes(const IniFile& inifile)
|
||||
{
|
||||
m_gcodes.clear();
|
||||
Gecko::LoadCodes(inifile, m_gcodes);
|
||||
|
||||
m_listbox_gcodes->Clear();
|
||||
// add the codes to the listbox
|
||||
std::vector<GeckoCode>::const_iterator
|
||||
gcodes_iter = m_gcodes.begin(),
|
||||
gcodes_end = m_gcodes.end();
|
||||
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
|
||||
{
|
||||
m_listbox_gcodes->Append(wxString::FromAscii(gcodes_iter->name.c_str()));
|
||||
if (gcodes_iter->enabled)
|
||||
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount()-1, true);
|
||||
}
|
||||
|
||||
wxCommandEvent evt;
|
||||
UpdateInfoBox(evt);
|
||||
}
|
||||
|
||||
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
|
||||
{
|
||||
const int sel = evt.GetInt(); // this right?
|
||||
if (sel > -1)
|
||||
m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel);
|
||||
}
|
||||
|
||||
void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
|
||||
{
|
||||
m_infobox.listbox_codes->Clear();
|
||||
const int sel = m_listbox_gcodes->GetSelection();
|
||||
|
||||
if (sel > -1)
|
||||
{
|
||||
m_infobox.label_name->SetLabel(wxstr_name + wxString::FromAscii(m_gcodes[sel].name.c_str()));
|
||||
m_infobox.label_description->SetLabel(wxstr_description + wxString::FromAscii(m_gcodes[sel].description.c_str()));
|
||||
m_infobox.label_creator->SetLabel(wxstr_creator + wxString::FromAscii(m_gcodes[sel].creator.c_str()));
|
||||
|
||||
// add codes to info listbox
|
||||
std::vector<GeckoCode::Code>::const_iterator
|
||||
codes_iter = m_gcodes[sel].codes.begin(),
|
||||
codes_end = m_gcodes[sel].codes.end();
|
||||
for (; codes_iter!=codes_end; ++codes_iter)
|
||||
m_infobox.listbox_codes->Append(wxString::Format(wxT("%08X %08X"), codes_iter->address, codes_iter->data));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_infobox.label_name->SetLabel(wxstr_name);
|
||||
m_infobox.label_description->SetLabel(wxstr_description);
|
||||
m_infobox.label_creator->SetLabel(wxstr_creator);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeConfigPanel::ApplyChanges(wxCommandEvent&)
|
||||
{
|
||||
Gecko::SetActiveCodes(m_gcodes);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
#ifndef __GECKOCODEDIAG_h__
|
||||
#define __GECKOCODEDIAG_h__
|
||||
|
||||
#include "GeckoCode.h"
|
||||
#include "GeckoCodeConfig.h"
|
||||
|
||||
#include "wx/wx.h"
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
||||
|
||||
class CodeConfigPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
CodeConfigPanel(wxWindow* const parent);
|
||||
|
||||
|
||||
void LoadCodes(const IniFile& inifile);
|
||||
const std::vector<GeckoCode>& GetCodes() const { return m_gcodes; }
|
||||
|
||||
protected:
|
||||
void UpdateInfoBox(wxCommandEvent&);
|
||||
void ToggleCode(wxCommandEvent& evt);
|
||||
void ApplyChanges(wxCommandEvent&);
|
||||
|
||||
private:
|
||||
std::vector<GeckoCode> m_gcodes;
|
||||
|
||||
// wxwidgets stuff
|
||||
wxCheckListBox *m_listbox_gcodes;
|
||||
struct
|
||||
{
|
||||
wxStaticText *label_name, *label_description, *label_creator;
|
||||
wxListBox *listbox_codes;
|
||||
} m_infobox;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -24,6 +24,7 @@
|
|||
#include "ISOProperties.h"
|
||||
#include "PatchAddEdit.h"
|
||||
#include "ARCodeAddEdit.h"
|
||||
#include "GeckoCodeDiag.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
|
@ -268,6 +269,8 @@ void CISOProperties::CreateGUIControls(bool IsWad)
|
|||
m_Notebook->AddPage(m_PatchPage, _("Patches"));
|
||||
m_CheatPage = new wxPanel(m_Notebook, ID_ARCODE_PAGE, wxDefaultPosition, wxDefaultSize);
|
||||
m_Notebook->AddPage(m_CheatPage, _("AR Codes"));
|
||||
m_geckocode_panel = new Gecko::CodeConfigPanel(m_Notebook);
|
||||
m_Notebook->AddPage(m_geckocode_panel, wxT("Gecko Codes"));
|
||||
m_Information = new wxPanel(m_Notebook, ID_INFORMATION, wxDefaultPosition, wxDefaultSize);
|
||||
m_Notebook->AddPage(m_Information, _("Info"));
|
||||
m_Filesystem = new wxPanel(m_Notebook, ID_FILESYSTEM, wxDefaultPosition, wxDefaultSize);
|
||||
|
@ -879,6 +882,7 @@ void CISOProperties::LoadGameConfig()
|
|||
|
||||
PatchList_Load();
|
||||
ActionReplayList_Load();
|
||||
m_geckocode_panel->LoadCodes(GameIni);
|
||||
}
|
||||
|
||||
bool CISOProperties::SaveGameConfig()
|
||||
|
@ -966,6 +970,7 @@ bool CISOProperties::SaveGameConfig()
|
|||
|
||||
PatchList_Save();
|
||||
ActionReplayList_Save();
|
||||
Gecko::SaveCodes(GameIni, m_geckocode_panel->GetCodes());
|
||||
|
||||
return GameIni.Save(GameIniFile.c_str());
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "IniFile.h"
|
||||
#include "PatchEngine.h"
|
||||
#include "ActionReplay.h"
|
||||
#include "GeckoCodeDiag.h"
|
||||
|
||||
class CISOProperties : public wxDialog
|
||||
{
|
||||
|
@ -145,6 +146,8 @@ class CISOProperties : public wxDialog
|
|||
wxTreeItemId RootId;
|
||||
wxImageList *m_iconList;
|
||||
|
||||
Gecko::CodeConfigPanel *m_geckocode_panel;
|
||||
|
||||
enum
|
||||
{
|
||||
ID_CLOSE = 1000,
|
||||
|
|
|
@ -23,6 +23,7 @@ if env['HAVE_WX']:
|
|||
files += [
|
||||
'AboutDolphin.cpp',
|
||||
'ARCodeAddEdit.cpp',
|
||||
'GeckoCodeDiag.cpp',
|
||||
'ConfigMain.cpp',
|
||||
'Frame.cpp',
|
||||
'FrameAui.cpp',
|
||||
|
|
Loading…
Reference in New Issue