Added a button to the "Gecko Codes" panel to download/parse codes from geckocodes.org. Codes that require modifiers (the XXXX business) will still not work properly, though they should load/save fine. A few more code types should work now. (All non-ASM type codes should at least attempt to run :p) Hacked a param into IniFile::GetLines to disable removal of text after # chars, so codes with # in the name/notes should load fine.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5949 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
2e6c5b36ab
commit
a3e3155678
|
@ -350,7 +350,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a list of all lines in a section
|
// Return a list of all lines in a section
|
||||||
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
|
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines, const bool remove_comments) const
|
||||||
{
|
{
|
||||||
const Section* section = GetSection(sectionName);
|
const Section* section = GetSection(sectionName);
|
||||||
if (!section)
|
if (!section)
|
||||||
|
@ -360,15 +360,19 @@ bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines)
|
||||||
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
||||||
{
|
{
|
||||||
std::string line = StripSpaces(*iter);
|
std::string line = StripSpaces(*iter);
|
||||||
int commentPos = (int)line.find('#');
|
|
||||||
if (commentPos == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commentPos != (int)std::string::npos)
|
if (remove_comments)
|
||||||
{
|
{
|
||||||
line = StripSpaces(line.substr(0, commentPos));
|
int commentPos = (int)line.find('#');
|
||||||
|
if (commentPos == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commentPos != (int)std::string::npos)
|
||||||
|
{
|
||||||
|
line = StripSpaces(line.substr(0, commentPos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
|
|
|
@ -123,7 +123,7 @@ public:
|
||||||
bool GetKeys(const char* sectionName, std::vector<std::string>& keys) const;
|
bool GetKeys(const char* sectionName, std::vector<std::string>& keys) const;
|
||||||
|
|
||||||
void SetLines(const char* sectionName, const std::vector<std::string> &lines);
|
void SetLines(const char* sectionName, const std::vector<std::string> &lines);
|
||||||
bool GetLines(const char* sectionName, std::vector<std::string>& lines) const;
|
bool GetLines(const char* sectionName, std::vector<std::string>& lines, const bool remove_comments = true) const;
|
||||||
|
|
||||||
bool DeleteKey(const char* sectionName, const char* key);
|
bool DeleteKey(const char* sectionName, const char* key);
|
||||||
bool DeleteSection(const char* sectionName);
|
bool DeleteSection(const char* sectionName);
|
||||||
|
|
|
@ -57,7 +57,8 @@ u32 GeckoCode::Code::GetAddress() const
|
||||||
static Common::CriticalSection active_codes_lock;
|
static Common::CriticalSection active_codes_lock;
|
||||||
|
|
||||||
// currently running code
|
// currently running code
|
||||||
static GeckoCode::Code current_code;
|
static GeckoCode::Code *codes_start = NULL, *current_code = NULL;
|
||||||
|
static const GeckoCode::Code *codes_end = NULL;
|
||||||
|
|
||||||
// Functions for each code type
|
// Functions for each code type
|
||||||
bool RamWriteAndFill();
|
bool RamWriteAndFill();
|
||||||
|
@ -91,7 +92,7 @@ void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
|
||||||
active_codes_lock.Leave();
|
active_codes_lock.Leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunGeckoCode(const GeckoCode& gecko_code)
|
bool RunGeckoCode(GeckoCode& gecko_code)
|
||||||
{
|
{
|
||||||
static bool (*code_type_funcs[])(void) =
|
static bool (*code_type_funcs[])(void) =
|
||||||
{ RamWriteAndFill, RegularIf, BaPoOps, FlowControl, RegisterOps, SpecialIf, AsmSwitchRange, EndCodes };
|
{ RamWriteAndFill, RegularIf, BaPoOps, FlowControl, RegisterOps, SpecialIf, AsmSwitchRange, EndCodes };
|
||||||
|
@ -100,14 +101,11 @@ bool RunGeckoCode(const GeckoCode& gecko_code)
|
||||||
pointer_address = 0x80000000;
|
pointer_address = 0x80000000;
|
||||||
code_execution_counter = 0;
|
code_execution_counter = 0;
|
||||||
|
|
||||||
std::vector<GeckoCode::Code>::const_iterator
|
current_code = codes_start = &*gecko_code.codes.begin();
|
||||||
codes_iter = gecko_code.codes.begin(),
|
codes_end = &*gecko_code.codes.end();
|
||||||
codes_end = gecko_code.codes.end();
|
for (; current_code < codes_end; ++current_code)
|
||||||
for (; codes_iter != codes_end; ++codes_iter)
|
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = *codes_iter;
|
const GeckoCode::Code& code = *current_code;
|
||||||
|
|
||||||
current_code = code;
|
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
|
@ -133,16 +131,12 @@ bool RunGeckoCode(const GeckoCode& gecko_code)
|
||||||
if (false == result)
|
if (false == result)
|
||||||
{
|
{
|
||||||
PanicAlert("GeckoCode failed to run (CT%i CST%i) (%s)"
|
PanicAlert("GeckoCode failed to run (CT%i CST%i) (%s)"
|
||||||
"(Either a bad code or the code type is not yet supported.)"
|
"\n(either a bad code or the code type is not yet supported.)"
|
||||||
, code.type, code.subtype, gecko_code.name.c_str());
|
, code.type, code.subtype, gecko_code.name.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +145,7 @@ bool RunActiveCodes()
|
||||||
if (false == active_codes_lock.TryEnter())
|
if (false == active_codes_lock.TryEnter())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::vector<GeckoCode>::const_iterator
|
std::vector<GeckoCode>::iterator
|
||||||
gcodes_iter = active_codes.begin(),
|
gcodes_iter = active_codes.begin(),
|
||||||
gcodes_end = active_codes.end();
|
gcodes_end = active_codes.end();
|
||||||
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
|
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
|
||||||
|
@ -167,19 +161,19 @@ bool RunActiveCodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CT0: Direct ram write/fill
|
// CT0: Direct ram write/fill
|
||||||
// NOT COMPLETE, last 2 subtypes not started
|
// COMPLETE, maybe
|
||||||
bool RamWriteAndFill()
|
bool RamWriteAndFill()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
const GeckoCode::Code& code = *current_code;
|
||||||
u32 new_addr = code.GetAddress();
|
u32 new_addr = code.GetAddress();
|
||||||
const u32& data = code.data;
|
const u32& data = code.data;
|
||||||
|
|
||||||
u16 count = (data >> 16) + 1;
|
u16 count = (data >> 16) + 1; // note: +1
|
||||||
|
|
||||||
switch (code.subtype)
|
switch (code.subtype)
|
||||||
{
|
{
|
||||||
// CST0: 8bits Write & Fill
|
// CST0: 8bits Write & Fill
|
||||||
case 0x0 :
|
case DATATYPE_8BIT :
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
Memory::Write_U16((u16)data, new_addr);
|
Memory::Write_U16((u16)data, new_addr);
|
||||||
|
@ -188,7 +182,7 @@ bool RamWriteAndFill()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST1: 16bits Write & Fill
|
// CST1: 16bits Write & Fill
|
||||||
case 0x1 :
|
case DATATYPE_16BIT :
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
Memory::Write_U16((u16)data, new_addr);
|
Memory::Write_U16((u16)data, new_addr);
|
||||||
|
@ -197,23 +191,76 @@ bool RamWriteAndFill()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST2: 32bits Write
|
// CST2: 32bits Write
|
||||||
case 0x2 :
|
case DATATYPE_32BIT :
|
||||||
Memory::Write_U32((u32)data, new_addr);
|
Memory::Write_U32((u32)data, new_addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST3: String Code
|
// CST3: String Code
|
||||||
case 0x3 :
|
case 0x3 :
|
||||||
// TODO:
|
count = code.data; // count is different from the other subtypes
|
||||||
return false;
|
while (count)
|
||||||
|
{
|
||||||
|
if (codes_end == ++current_code)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// write bytes from address
|
||||||
|
int byte_num = 4;
|
||||||
|
while (byte_num-- && count)
|
||||||
|
{
|
||||||
|
Memory::Write_U8((u8)(current_code->address >> byte_num * 8), new_addr);
|
||||||
|
++new_addr;
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write bytes from data
|
||||||
|
byte_num = 4;
|
||||||
|
while (byte_num-- && count)
|
||||||
|
{
|
||||||
|
Memory::Write_U8((u8)(current_code->data >> byte_num * 8), new_addr);
|
||||||
|
++new_addr;
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST4: Serial Code
|
// CST4: Serial Code
|
||||||
case 0x4 :
|
case 0x4 :
|
||||||
{
|
{
|
||||||
// TODO: complete
|
if (codes_end == ++current_code)
|
||||||
// u32 new_data = data;
|
return false;
|
||||||
|
u32 new_data = data; // starting value of data
|
||||||
|
const u8 data_type = current_code->address >> 28;
|
||||||
|
const u32 data_inc = current_code->data; // amount to increment the data
|
||||||
|
const u16 addr_inc = (u16)current_code->address; // amount to increment the address
|
||||||
|
count = (current_code->address >> 16) & 0xFFF + 1; // count is different from the other subtypes, note: +1
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
// switch inside the loop, :/ o well
|
||||||
|
switch (data_type)
|
||||||
|
{
|
||||||
|
case DATATYPE_8BIT :
|
||||||
|
Memory::Write_U8((u8)new_data, new_addr);
|
||||||
|
new_data = (u8)new_data + (u8)data_inc;
|
||||||
|
break;
|
||||||
|
|
||||||
return false;
|
case DATATYPE_16BIT :
|
||||||
|
Memory::Write_U16((u16)new_data, new_addr);
|
||||||
|
new_data = (u16)new_data + (u16)data_inc;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATATYPE_32BIT :
|
||||||
|
Memory::Write_U32((u32)new_data, new_addr);
|
||||||
|
new_data += data_inc;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// INVALID DATATYPE
|
||||||
|
default :
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_addr += addr_inc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -230,7 +277,7 @@ bool RamWriteAndFill()
|
||||||
// COMPLETE
|
// COMPLETE
|
||||||
bool RegularIf()
|
bool RegularIf()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
const GeckoCode::Code& code = *current_code;
|
||||||
|
|
||||||
const bool is_endif = !!(code.address & 0x1);
|
const bool is_endif = !!(code.address & 0x1);
|
||||||
|
|
||||||
|
@ -306,7 +353,7 @@ bool RegularIf()
|
||||||
// NOT COMPLETE, last 2 subtypes aren't done
|
// NOT COMPLETE, last 2 subtypes aren't done
|
||||||
bool BaPoOps()
|
bool BaPoOps()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
const GeckoCode::Code& code = *current_code;
|
||||||
|
|
||||||
// base_address vs pointer (ba vs po)
|
// base_address vs pointer (ba vs po)
|
||||||
u32& change_address = (code.subtype & 0x4) ? pointer_address : base_address;
|
u32& change_address = (code.subtype & 0x4) ? pointer_address : base_address;
|
||||||
|
@ -360,10 +407,10 @@ bool BaPoOps()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CT3 Repeat/Goto/Gosub/Return
|
// CT3 Repeat/Goto/Gosub/Return
|
||||||
// NOT COMPLETE
|
// COMPLETE, maybe
|
||||||
bool FlowControl()
|
bool FlowControl()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
const GeckoCode::Code& code = *current_code;
|
||||||
|
|
||||||
// only the return subtype runs when code execution is off
|
// only the return subtype runs when code execution is off
|
||||||
if (false == CodeExecution() && code.subtype != 0x2)
|
if (false == CodeExecution() && code.subtype != 0x2)
|
||||||
|
@ -376,10 +423,8 @@ bool FlowControl()
|
||||||
{
|
{
|
||||||
// CST0 : Set Repeat
|
// CST0 : Set Repeat
|
||||||
case 0x0 :
|
case 0x0 :
|
||||||
// TODO: store address of next code as well
|
block[block_num].number = code.address & 0xFFFF;
|
||||||
block[block_num].address = code.address & 0xFFFF;
|
block[block_num].address = (u32)(current_code - codes_start + 1);
|
||||||
// block[block_num].number = ;
|
|
||||||
return false; //
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST1 : Execute Repeat
|
// CST1 : Execute Repeat
|
||||||
|
@ -387,7 +432,8 @@ bool FlowControl()
|
||||||
if (block[block_num].number)
|
if (block[block_num].number)
|
||||||
{
|
{
|
||||||
--block[block_num].number;
|
--block[block_num].number;
|
||||||
// TODO: jump to code block
|
// needs -1 cause iterator gets ++ after code runs
|
||||||
|
current_code = codes_start + block[block_num].address - 1;
|
||||||
}
|
}
|
||||||
return false; //
|
return false; //
|
||||||
break;
|
break;
|
||||||
|
@ -395,20 +441,43 @@ bool FlowControl()
|
||||||
// CST2 : Return
|
// CST2 : Return
|
||||||
case 0x2 :
|
case 0x2 :
|
||||||
if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
|
if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
|
||||||
// TODO: jump to block[block_num].number
|
{
|
||||||
return false; //
|
// needs -1 cause iterator gets ++ after code runs
|
||||||
|
current_code = codes_start + block[block_num].address - 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST3 : Goto
|
// CST3 : Goto
|
||||||
case 0x3 :
|
case 0x3 :
|
||||||
// TODO:
|
if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
|
||||||
return false; //
|
{
|
||||||
|
GeckoCode::Code* const target_code = current_code + (s16)(code.address & 0xFFFF);
|
||||||
|
|
||||||
|
if (target_code >= codes_start && target_code < codes_end)
|
||||||
|
{
|
||||||
|
// needs -1 cause iterator gets ++ after code runs
|
||||||
|
current_code = target_code - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false; // trying to GOTO to bad address
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST4 : Gosub
|
// CST4 : Gosub
|
||||||
case 0x4 :
|
case 0x4 :
|
||||||
// TODO:
|
if (((code.address >> 20) & 0xF) ^ (u32)CodeExecution())
|
||||||
return false; //
|
{
|
||||||
|
GeckoCode::Code* const target_code = current_code + (s16)(code.address & 0xFFFF);
|
||||||
|
|
||||||
|
if (target_code >= codes_start && target_code < codes_end)
|
||||||
|
{
|
||||||
|
block[block_num].address = u32(current_code - codes_start + 1);
|
||||||
|
// needs -1 cause iterator gets ++ after code runs
|
||||||
|
current_code = target_code - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false; // trying to GOSUB to bad address
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// INVALID SUBTYPE
|
// INVALID SUBTYPE
|
||||||
|
@ -421,10 +490,10 @@ bool FlowControl()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CT4 Gecko Register Operations
|
// CT4 Gecko Register Operations
|
||||||
// NOT COMPLETE, need to do memory copy 1,2
|
// COMPLETE, maybe
|
||||||
bool RegisterOps()
|
bool RegisterOps()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
const GeckoCode::Code& code = *current_code;
|
||||||
|
|
||||||
// 80TYZZZN XXXXXXXX
|
// 80TYZZZN XXXXXXXX
|
||||||
|
|
||||||
|
@ -519,15 +588,27 @@ bool RegisterOps()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST5 : Memory Copy 1
|
// CST5 : Memory Copy 1
|
||||||
case 0x5 :
|
|
||||||
// TODO:
|
|
||||||
return false; //
|
|
||||||
break;
|
|
||||||
|
|
||||||
// CST6 : Memory Copy 2
|
// CST6 : Memory Copy 2
|
||||||
|
case 0x5 :
|
||||||
case 0x6 :
|
case 0x6 :
|
||||||
// TODO:
|
{
|
||||||
return false; //
|
const u8 src_gr = (code.z & 0xF);
|
||||||
|
const u8 dst_gr = (code.n);
|
||||||
|
|
||||||
|
u16 count = (u16)(code.address >> 8);
|
||||||
|
|
||||||
|
// docs don't specify allowing 0xF for source and dest, but it can't hurt
|
||||||
|
u32 src_addr = ((0xF == src_gr) ? (code.use_po ? pointer_address : base_address) : gecko_register[src_gr]);
|
||||||
|
u32 dst_addr = ((0xF == dst_gr) ? (code.use_po ? pointer_address : base_address) : gecko_register[dst_gr]);
|
||||||
|
|
||||||
|
if (0x5 == code.subtype)
|
||||||
|
dst_addr += new_data;
|
||||||
|
else
|
||||||
|
src_addr += new_data;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
Memory::Write_U8(Memory::Read_U8(src_addr++), dst_addr++);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// INVALID SUBTYPE
|
// INVALID SUBTYPE
|
||||||
|
@ -589,8 +670,7 @@ bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type)
|
||||||
|
|
||||||
// 8 : asr (arithmetic shift right)
|
// 8 : asr (arithmetic shift right)
|
||||||
case 0x8 :
|
case 0x8 :
|
||||||
// TODO: wuts this
|
ret = (left >> right) | (left & 0x80000000);
|
||||||
return false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO: these float ops good?
|
// TODO: these float ops good?
|
||||||
|
@ -614,10 +694,11 @@ bool MathOperation(u32& ret, const u32 left, const u32 right, const u8 type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CT5: Special If codes (16bits)
|
// CT5: Special If codes (16bits)
|
||||||
// NOT COMPLETE, part 2 (counter stuff) not started
|
// COMPLETE, maybe (ugly)
|
||||||
bool SpecialIf()
|
bool SpecialIf()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
// counter can modify the code :/
|
||||||
|
GeckoCode::Code& code = *current_code;
|
||||||
|
|
||||||
const bool is_endif = !!(code.address & 0x1);
|
const bool is_endif = !!(code.address & 0x1);
|
||||||
|
|
||||||
|
@ -630,99 +711,87 @@ bool SpecialIf()
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
|
// TODO: should these be signed? probably?
|
||||||
|
s16 left_val = 0, right_val = 0;
|
||||||
|
|
||||||
// if code_execution is on, execute the conditional
|
// if code_execution is on, execute the conditional
|
||||||
if (CodeExecution())
|
if (CodeExecution())
|
||||||
{
|
{
|
||||||
const u32 addr = code.GetAddress() & ~0x1;
|
const u32 addr = code.GetAddress() & ~0x1;
|
||||||
const u32& data = code.data;
|
const u32& data = code.data;
|
||||||
|
|
||||||
// A-______ NM00YYYY
|
|
||||||
|
|
||||||
if (code.subtype ^ 0x4)
|
if (code.subtype ^ 0x4)
|
||||||
{
|
{
|
||||||
// CT5 Part1 : Unknown values comparison
|
// CT5 Part1 : Unknown values comparison
|
||||||
|
// A-______ NM00YYYY
|
||||||
|
|
||||||
const u8 n = (u8)(data >> 28);
|
const u8 n = (u8)(data >> 28);
|
||||||
const u8 m = (u8)((data >> 24) & 0xF);
|
const u8 m = (u8)((data >> 24) & 0xF);
|
||||||
const u16 y = (u16)data;
|
const u16 y = (u16)data;
|
||||||
|
|
||||||
// TODO: should these be signed? probably?
|
left_val = Memory::Read_U16(((0xF == n) ? addr : gecko_register[n]) & ~y);
|
||||||
const s16 left_val = Memory::Read_U16(((0xF == n) ? addr : gecko_register[n]) & ~y);
|
right_val = Memory::Read_U16(((0xF == m) ? addr : gecko_register[m]) & ~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
|
else
|
||||||
{
|
{
|
||||||
// CT5 Part2 : 16bits Counter check
|
// CT5 Part2 : 16bits Counter check
|
||||||
// TODO:
|
// A-0ZZZZT MMMMXXXX
|
||||||
|
|
||||||
switch (code.subtype)
|
left_val = (u16)(data) & ~(u16)(data >> 16);
|
||||||
{
|
right_val = (u16)(addr >> 4);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (code.subtype & 0x3)
|
||||||
|
{
|
||||||
|
// 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 if (code.subtype & 0x4)
|
||||||
|
{
|
||||||
|
// counters get reset if code execution is off
|
||||||
|
code.address &= ~0x000FFFF0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the conditional returned false, or it never ran because execution is off, increase the code execution counter
|
// if the conditional returned false, or it never ran because execution is off, increase the code execution counter
|
||||||
if (false == result)
|
if (false == result)
|
||||||
++code_execution_counter;
|
++code_execution_counter;
|
||||||
|
else if (code.subtype & 0x4)
|
||||||
|
{
|
||||||
|
// counters gets advanced if condition was true
|
||||||
|
// right_val is the value of the counter
|
||||||
|
|
||||||
|
code.address &= ~0x000FFFF0;
|
||||||
|
code.address |= ((right_val+1) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CT6 ASM Codes, On/Off switch and Address Range Check
|
// CT6 ASM Codes, On/Off switch and Address Range Check
|
||||||
// NOT COMPLETE, hardly started
|
// NOT COMPLETE, asm stuff not started
|
||||||
// fix the logic flow in this one
|
// fix the uglyness
|
||||||
bool AsmSwitchRange()
|
bool AsmSwitchRange()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
// the switch subtype modifies the code :/
|
||||||
|
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
|
// 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
|
// the switch and rangecheck run if exectution_counter is 1 (directly inside the failed if) if they are an endif
|
||||||
|
@ -730,11 +799,11 @@ bool AsmSwitchRange()
|
||||||
{
|
{
|
||||||
if (code.subtype < 0x6)
|
if (code.subtype < 0x6)
|
||||||
return true;
|
return true;
|
||||||
else if (false == (1 == code_execution_counter && is_endif))
|
else if (1 != code_execution_counter)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32& data = code.data;
|
u32& data = code.data;
|
||||||
|
|
||||||
switch (code.subtype)
|
switch (code.subtype)
|
||||||
{
|
{
|
||||||
|
@ -752,24 +821,47 @@ bool AsmSwitchRange()
|
||||||
|
|
||||||
// CST3 : Create a branch
|
// CST3 : Create a branch
|
||||||
case 0x3 :
|
case 0x3 :
|
||||||
// TODO:
|
// watever
|
||||||
|
//if (code.data)
|
||||||
return false; //
|
return false; //
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST6 : On/Off switch
|
// CST6 : On/Off switch
|
||||||
case 0x6 :
|
case 0x6 :
|
||||||
// TODO:
|
// in the 1st bit of code.data, i store if code execution was previously off
|
||||||
return false; //
|
// in the 2nd bit of code.data, i store the switch's on/off state
|
||||||
|
if (CodeExecution())
|
||||||
|
{
|
||||||
|
if (data & 0x1)
|
||||||
|
data ^= 0x2; // if code exec was previously off, flip the switch
|
||||||
|
|
||||||
|
// mark code execution as previously on
|
||||||
|
data &= ~0x1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// mark code execution as previously off
|
||||||
|
data |= 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set code execution to the state of the switch
|
||||||
|
code_execution_counter = !(data & 0x2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST7 : Address range check (If... code)
|
// CST7 : Address range check (If... code)
|
||||||
case 0x7 :
|
case 0x7 :
|
||||||
if (code_execution_counter)
|
{
|
||||||
|
const bool is_endif = !!(code.address & 0x1);
|
||||||
|
if (is_endif)
|
||||||
|
--code_execution_counter;
|
||||||
|
|
||||||
|
if (CodeExecution())
|
||||||
{
|
{
|
||||||
const u32 addr = (code.use_po ? pointer_address : base_address);
|
const u32 addr = (code.use_po ? pointer_address : base_address);
|
||||||
if (addr >= (data & 0xFFFF0000) && addr <= (data << 16))
|
if (addr < (data & 0xFFFF0000) || addr > (data << 16))
|
||||||
--code_execution_counter;
|
++code_execution_counter;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// INVALID SUBTYPE
|
// INVALID SUBTYPE
|
||||||
|
@ -785,7 +877,7 @@ bool AsmSwitchRange()
|
||||||
// COMPLETE, maybe
|
// COMPLETE, maybe
|
||||||
bool EndCodes()
|
bool EndCodes()
|
||||||
{
|
{
|
||||||
const GeckoCode::Code& code = current_code;
|
const GeckoCode::Code& code = *current_code;
|
||||||
const u32& data = code.data;
|
const u32& data = code.data;
|
||||||
|
|
||||||
const u32 x = (data & 0xFFFF0000);
|
const u32 x = (data & 0xFFFF0000);
|
||||||
|
@ -802,9 +894,7 @@ bool EndCodes()
|
||||||
// CST0 : Full Terminator
|
// CST0 : Full Terminator
|
||||||
case 0x0 :
|
case 0x0 :
|
||||||
// clears the code execution status
|
// clears the code execution status
|
||||||
// TODO: should this always stop all codes, even if execution is off?
|
code_execution_counter = 0;
|
||||||
if (CodeExecution())
|
|
||||||
code_execution_counter = -1; // silly maybe
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CST1 : Endif (+else)
|
// CST1 : Endif (+else)
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace Gecko
|
||||||
|
|
||||||
struct Code
|
struct Code
|
||||||
{
|
{
|
||||||
|
Code() : address(0), data(0) {}
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
u32 address;
|
u32 address;
|
||||||
|
@ -50,11 +52,14 @@ namespace Gecko
|
||||||
//};
|
//};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string original_line;
|
||||||
|
|
||||||
u32 GetAddress() const;
|
u32 GetAddress() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Code> codes;
|
std::vector<Code> codes;
|
||||||
std::string name, description, creator;
|
std::string name, creator;
|
||||||
|
std::vector<std::string> notes;
|
||||||
|
|
||||||
bool enabled;
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Gecko
|
||||||
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
inifile.GetLines(GECKO_CODE_INI_SECTION, lines);
|
inifile.GetLines(GECKO_CODE_INI_SECTION, lines, false);
|
||||||
|
|
||||||
GeckoCode gcode;
|
GeckoCode gcode;
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
||||||
|
|
||||||
std::istringstream ss(*lines_iter);
|
std::istringstream ss(*lines_iter);
|
||||||
|
|
||||||
|
int read_state = 0;
|
||||||
|
|
||||||
switch ((*lines_iter)[0])
|
switch ((*lines_iter)[0])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -46,30 +48,24 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
||||||
gcode.name = StripSpaces(gcode.name);
|
gcode.name = StripSpaces(gcode.name);
|
||||||
// read the code creator name
|
// read the code creator name
|
||||||
std::getline(ss, gcode.creator, ']');
|
std::getline(ss, gcode.creator, ']');
|
||||||
|
read_state = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// description
|
// notes
|
||||||
case '*':
|
case '*':
|
||||||
ss.seekg(1);
|
gcode.notes.push_back(std::string(++lines_iter->begin(), lines_iter->end()));
|
||||||
std::getline(ss, gcode.description);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// start of code option list
|
|
||||||
case ':':
|
|
||||||
// TODO:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// either part of the code, or an option choice
|
// either part of the code, or an option choice
|
||||||
default :
|
default :
|
||||||
// TODO: check if we are reading an option list
|
|
||||||
{
|
{
|
||||||
GeckoCode::Code new_code;
|
GeckoCode::Code new_code;
|
||||||
// TODO: support options
|
// TODO: support options
|
||||||
|
new_code.original_line = *lines_iter;
|
||||||
ss >> std::hex >> new_code.address >> new_code.data;
|
ss >> std::hex >> new_code.address >> new_code.data;
|
||||||
gcode.codes.push_back(new_code);
|
gcode.codes.push_back(new_code);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -101,10 +97,6 @@ void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
|
||||||
|
|
||||||
lines.push_back(name);
|
lines.push_back(name);
|
||||||
|
|
||||||
// save the description
|
|
||||||
if (gcode.description.size())
|
|
||||||
lines.push_back(std::string("*") + gcode.description);
|
|
||||||
|
|
||||||
// save all the code lines
|
// save all the code lines
|
||||||
std::vector<GeckoCode::Code>::const_iterator
|
std::vector<GeckoCode::Code>::const_iterator
|
||||||
codes_iter = gcode.codes.begin(),
|
codes_iter = gcode.codes.begin(),
|
||||||
|
@ -112,13 +104,17 @@ void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
|
||||||
for (; codes_iter!=codes_end; ++codes_iter)
|
for (; codes_iter!=codes_end; ++codes_iter)
|
||||||
{
|
{
|
||||||
//ss << std::hex << codes_iter->address << ' ' << codes_iter->data;
|
//ss << std::hex << codes_iter->address << ' ' << codes_iter->data;
|
||||||
lines.push_back(StringFromFormat("%08X %08X", codes_iter->address, codes_iter->data));
|
//lines.push_back(StringFromFormat("%08X %08X", codes_iter->address, codes_iter->data));
|
||||||
|
lines.push_back(codes_iter->original_line);
|
||||||
//ss.clear();
|
//ss.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
//lines.push_back("BLAH");
|
// save the notes
|
||||||
|
std::vector<std::string>::const_iterator
|
||||||
// TODO: save the options
|
notes_iter = gcode.notes.begin(),
|
||||||
|
notes_end = gcode.notes.end();
|
||||||
|
for (; notes_iter!=notes_end; ++notes_iter)
|
||||||
|
lines.push_back(std::string("*") + *notes_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes)
|
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes)
|
||||||
|
|
|
@ -34,7 +34,7 @@ extern std::vector<ActionReplay::ARCode> arCodes;
|
||||||
static wxCheatsWindow *g_cheat_window;
|
static wxCheatsWindow *g_cheat_window;
|
||||||
|
|
||||||
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
||||||
: wxFrame(parent, wxID_ANY, wxT("Action Replay"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
|
: wxFrame(parent, wxID_ANY, wxT("Cheats Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
|
||||||
{
|
{
|
||||||
::g_cheat_window = this;
|
::g_cheat_window = this;
|
||||||
|
|
||||||
|
@ -201,8 +201,8 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent)
|
||||||
// filter types in the compare dropdown
|
// filter types in the compare dropdown
|
||||||
static const wxString searches[] = {
|
static const wxString searches[] = {
|
||||||
wxT("Unknown"),
|
wxT("Unknown"),
|
||||||
wxT("Not Equals"),
|
wxT("Not Equal"),
|
||||||
wxT("Equals"),
|
wxT("Equal"),
|
||||||
wxT("Greater Than"),
|
wxT("Greater Than"),
|
||||||
wxT("Less Than"),
|
wxT("Less Than"),
|
||||||
// TODO: Implement between search.
|
// TODO: Implement between search.
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
|
|
||||||
#include "GeckoCodeDiag.h"
|
#include "GeckoCodeDiag.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _WINSOCK2API_
|
||||||
|
#endif
|
||||||
|
#include <SFML/Network/Http.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler(f), (wxObject*)0, (wxEvtHandler*)s)
|
#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler(f), (wxObject*)0, (wxEvtHandler*)s)
|
||||||
|
|
||||||
namespace Gecko
|
namespace Gecko
|
||||||
{
|
{
|
||||||
|
|
||||||
static const wxString wxstr_name(wxT("Name: ")),
|
static const wxString wxstr_name(wxT("Name: ")),
|
||||||
wxstr_description(wxT("Description: ")),
|
wxstr_notes(wxT("Notes: ")),
|
||||||
wxstr_creator(wxT("Creator: "));
|
wxstr_creator(wxT("Creator: "));
|
||||||
|
|
||||||
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
|
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
|
||||||
|
@ -19,41 +26,40 @@ CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
|
||||||
|
|
||||||
m_infobox.label_name = new wxStaticText(this, -1, wxstr_name);
|
m_infobox.label_name = new wxStaticText(this, -1, wxstr_name);
|
||||||
m_infobox.label_creator = new wxStaticText(this, -1, wxstr_creator);
|
m_infobox.label_creator = new wxStaticText(this, -1, wxstr_creator);
|
||||||
m_infobox.label_description = new wxStaticText(this, -1, wxstr_description);
|
m_infobox.label_notes = new wxStaticText(this, -1, wxstr_notes);
|
||||||
|
m_infobox.textctrl_notes = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY);
|
||||||
m_infobox.listbox_codes = new wxListBox(this, -1, wxDefaultPosition, wxSize(-1, 64));
|
m_infobox.listbox_codes = new wxListBox(this, -1, wxDefaultPosition, wxSize(-1, 64));
|
||||||
|
|
||||||
// TODO: buttons to add/edit codes
|
// TODO: buttons to add/edit codes
|
||||||
|
|
||||||
// sizers
|
// sizers
|
||||||
wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer_infobox->Add(m_infobox.label_name, 0, wxLEFT | wxBOTTOM, 5);
|
sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5);
|
||||||
sizer_infobox->Add(m_infobox.label_creator, 0, wxLEFT | wxBOTTOM, 5);
|
sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5);
|
||||||
sizer_infobox->Add(m_infobox.label_description, 0, wxLEFT | wxBOTTOM, 5);
|
sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5);
|
||||||
sizer_infobox->Add(m_infobox.listbox_codes, 0, wxLEFT | wxBOTTOM, 5);
|
sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5);
|
||||||
|
sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5);
|
||||||
|
|
||||||
//wxBoxSizer* const sizer_horz = new wxBoxSizer(wxHORIZONTAL);
|
// button sizer
|
||||||
//sizer_horz->Add(sizer_infobox, 1, 0);
|
wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxVERTICAL);
|
||||||
|
wxButton* const btn_download = new wxButton(this, -1, wxT("Download Codes (WiiRD Database)"), wxDefaultPosition, wxSize(128, -1));
|
||||||
|
_connect_macro_(btn_download, CodeConfigPanel::DownloadCodes, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||||
|
sizer_buttons->Add(btn_download, 0, wxEXPAND);
|
||||||
|
|
||||||
// silly
|
// horizontal sizer
|
||||||
//if (show_apply_button)
|
wxBoxSizer* const sizer_horz = new wxBoxSizer(wxHORIZONTAL);
|
||||||
//{
|
sizer_horz->Add(sizer_infobox, 1, wxEXPAND);
|
||||||
// wxButton* const btn_apply = new wxButton(this, -1, wxT("Apply Changes"), wxDefaultPosition, wxSize(128, -1));
|
sizer_horz->Add(sizer_buttons, 1, wxLEFT | wxALIGN_BOTTOM, 5);
|
||||||
// _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);
|
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5);
|
sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5);
|
||||||
sizer_main->Add(sizer_infobox, 0, wxALL | wxEXPAND, 5);
|
sizer_main->Add(sizer_horz, 0, wxALL | wxEXPAND, 5);
|
||||||
|
|
||||||
SetSizerAndFit(sizer_main);
|
SetSizerAndFit(sizer_main);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeConfigPanel::LoadCodes(const IniFile& inifile)
|
void CodeConfigPanel::UpdateCodeList()
|
||||||
{
|
{
|
||||||
m_gcodes.clear();
|
|
||||||
Gecko::LoadCodes(inifile, m_gcodes);
|
|
||||||
|
|
||||||
m_listbox_gcodes->Clear();
|
m_listbox_gcodes->Clear();
|
||||||
// add the codes to the listbox
|
// add the codes to the listbox
|
||||||
std::vector<GeckoCode>::const_iterator
|
std::vector<GeckoCode>::const_iterator
|
||||||
|
@ -70,6 +76,16 @@ void CodeConfigPanel::LoadCodes(const IniFile& inifile)
|
||||||
UpdateInfoBox(evt);
|
UpdateInfoBox(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeConfigPanel::LoadCodes(const IniFile& inifile, const std::string& gameid)
|
||||||
|
{
|
||||||
|
m_gameid = gameid;
|
||||||
|
|
||||||
|
m_gcodes.clear();
|
||||||
|
Gecko::LoadCodes(inifile, m_gcodes);
|
||||||
|
|
||||||
|
UpdateCodeList();
|
||||||
|
}
|
||||||
|
|
||||||
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
|
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
|
||||||
{
|
{
|
||||||
const int sel = evt.GetInt(); // this right?
|
const int sel = evt.GetInt(); // this right?
|
||||||
|
@ -85,7 +101,16 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
|
||||||
if (sel > -1)
|
if (sel > -1)
|
||||||
{
|
{
|
||||||
m_infobox.label_name->SetLabel(wxstr_name + wxString::FromAscii(m_gcodes[sel].name.c_str()));
|
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()));
|
|
||||||
|
// notes textctrl
|
||||||
|
m_infobox.textctrl_notes->Clear();
|
||||||
|
std::vector<std::string>::const_iterator
|
||||||
|
notes_iter = m_gcodes[sel].notes.begin(),
|
||||||
|
notes_end = m_gcodes[sel].notes.end();
|
||||||
|
for (; notes_iter!=notes_end; ++notes_iter)
|
||||||
|
m_infobox.textctrl_notes->AppendText(wxString::FromAscii(notes_iter->c_str()));
|
||||||
|
m_infobox.textctrl_notes->ScrollLines(-99); // silly
|
||||||
|
|
||||||
m_infobox.label_creator->SetLabel(wxstr_creator + wxString::FromAscii(m_gcodes[sel].creator.c_str()));
|
m_infobox.label_creator->SetLabel(wxstr_creator + wxString::FromAscii(m_gcodes[sel].creator.c_str()));
|
||||||
|
|
||||||
// add codes to info listbox
|
// add codes to info listbox
|
||||||
|
@ -98,15 +123,135 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_infobox.label_name->SetLabel(wxstr_name);
|
m_infobox.label_name->SetLabel(wxstr_name);
|
||||||
m_infobox.label_description->SetLabel(wxstr_description);
|
m_infobox.textctrl_notes->Clear();
|
||||||
m_infobox.label_creator->SetLabel(wxstr_creator);
|
m_infobox.label_creator->SetLabel(wxstr_creator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeConfigPanel::ApplyChanges(wxCommandEvent&)
|
//void CodeConfigPanel::ApplyChanges(wxCommandEvent&)
|
||||||
|
//{
|
||||||
|
// Gecko::SetActiveCodes(m_gcodes);
|
||||||
|
//}
|
||||||
|
|
||||||
|
void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
|
||||||
{
|
{
|
||||||
Gecko::SetActiveCodes(m_gcodes);
|
if (m_gameid.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
sf::Http::Request req;
|
||||||
|
req.SetURI("/txt.php?txt=" + m_gameid);
|
||||||
|
|
||||||
|
sf::Http http;
|
||||||
|
http.SetHost("geckocodes.org");
|
||||||
|
|
||||||
|
const sf::Http::Response resp = http.SendRequest(req, 5.0f);
|
||||||
|
|
||||||
|
if (sf::Http::Response::Ok == resp.GetStatus())
|
||||||
|
{
|
||||||
|
// temp vector containing parsed codes
|
||||||
|
std::vector<GeckoCode> gcodes;
|
||||||
|
|
||||||
|
// parse the codes
|
||||||
|
std::istringstream ss(resp.GetBody());
|
||||||
|
|
||||||
|
// debug
|
||||||
|
//PanicAlert("File size is %i bytes.", ss.str().size());
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
// make sure the txt file is for this game
|
||||||
|
// eh w/e
|
||||||
|
//std::getline(ss, line);
|
||||||
|
//if (line != m_gameid)
|
||||||
|
// PanicAlert("Bad code file.");
|
||||||
|
|
||||||
|
// seek past the header, get to the first code
|
||||||
|
std::getline(ss, line);
|
||||||
|
std::getline(ss, line);
|
||||||
|
std::getline(ss, line);
|
||||||
|
|
||||||
|
int read_state = 0;
|
||||||
|
GeckoCode gcode;
|
||||||
|
|
||||||
|
while ((std::getline(ss, line).good()))
|
||||||
|
{
|
||||||
|
// empty line
|
||||||
|
if (0 == line.size() || line == "\r" || line == "\n") // \r\n checks might not be needed
|
||||||
|
{
|
||||||
|
// add the code
|
||||||
|
if (gcode.codes.size())
|
||||||
|
gcodes.push_back(gcode);
|
||||||
|
gcode = GeckoCode();
|
||||||
|
read_state = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (read_state)
|
||||||
|
{
|
||||||
|
// read new code
|
||||||
|
case 0 :
|
||||||
|
gcode.name = line; // TODO: parse creator name in []s
|
||||||
|
read_state = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// read code lines
|
||||||
|
case 1 :
|
||||||
|
{
|
||||||
|
std::istringstream ssline(line);
|
||||||
|
std::string addr, data;
|
||||||
|
ssline >> addr >> data;
|
||||||
|
ssline.seekg(0);
|
||||||
|
|
||||||
|
// check if this line a code, silly, but the dumb txt file comment lines can start with valid hex chars :/
|
||||||
|
if (8 == addr.length() && 8 == data.length())
|
||||||
|
{
|
||||||
|
GeckoCode::Code new_code;
|
||||||
|
new_code.original_line = line;
|
||||||
|
ssline >> std::hex >> new_code.address >> new_code.data;
|
||||||
|
gcode.codes.push_back(new_code);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gcode.notes.push_back(line);
|
||||||
|
read_state = 2; // start reading comments
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// read comment lines
|
||||||
|
case 2 :
|
||||||
|
// append comment line
|
||||||
|
gcode.notes.push_back(line);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the last code
|
||||||
|
if (gcode.codes.size())
|
||||||
|
gcodes.push_back(gcode);
|
||||||
|
|
||||||
|
if (gcodes.size())
|
||||||
|
{
|
||||||
|
PanicAlert("Downloaded %i codes.", gcodes.size());
|
||||||
|
|
||||||
|
// append the codes to the code list
|
||||||
|
std::vector<GeckoCode>::const_iterator
|
||||||
|
gcodes_iter = gcodes.begin(),
|
||||||
|
gcodes_end = gcodes.end();
|
||||||
|
for (; gcodes_iter!= gcodes_end; ++gcodes_iter)
|
||||||
|
m_gcodes.push_back(*gcodes_iter);
|
||||||
|
|
||||||
|
// refresh the list
|
||||||
|
UpdateCodeList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PanicAlert("File contained no codes.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PanicAlert("Failed to download codes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,22 +17,28 @@ public:
|
||||||
CodeConfigPanel(wxWindow* const parent);
|
CodeConfigPanel(wxWindow* const parent);
|
||||||
|
|
||||||
|
|
||||||
void LoadCodes(const IniFile& inifile);
|
void LoadCodes(const IniFile& inifile, const std::string& gameid = "");
|
||||||
const std::vector<GeckoCode>& GetCodes() const { return m_gcodes; }
|
const std::vector<GeckoCode>& GetCodes() const { return m_gcodes; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void UpdateInfoBox(wxCommandEvent&);
|
void UpdateInfoBox(wxCommandEvent&);
|
||||||
void ToggleCode(wxCommandEvent& evt);
|
void ToggleCode(wxCommandEvent& evt);
|
||||||
void ApplyChanges(wxCommandEvent&);
|
void DownloadCodes(wxCommandEvent&);
|
||||||
|
//void ApplyChanges(wxCommandEvent&);
|
||||||
|
|
||||||
|
void UpdateCodeList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<GeckoCode> m_gcodes;
|
std::vector<GeckoCode> m_gcodes;
|
||||||
|
|
||||||
|
std::string m_gameid;
|
||||||
|
|
||||||
// wxwidgets stuff
|
// wxwidgets stuff
|
||||||
wxCheckListBox *m_listbox_gcodes;
|
wxCheckListBox *m_listbox_gcodes;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
wxStaticText *label_name, *label_description, *label_creator;
|
wxStaticText *label_name, *label_notes, *label_creator;
|
||||||
|
wxTextCtrl *textctrl_notes;
|
||||||
wxListBox *listbox_codes;
|
wxListBox *listbox_codes;
|
||||||
} m_infobox;
|
} m_infobox;
|
||||||
|
|
||||||
|
@ -43,3 +49,4 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -882,7 +882,7 @@ void CISOProperties::LoadGameConfig()
|
||||||
|
|
||||||
PatchList_Load();
|
PatchList_Load();
|
||||||
ActionReplayList_Load();
|
ActionReplayList_Load();
|
||||||
m_geckocode_panel->LoadCodes(GameIni);
|
m_geckocode_panel->LoadCodes(GameIni, OpenISO->GetUniqueID());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CISOProperties::SaveGameConfig()
|
bool CISOProperties::SaveGameConfig()
|
||||||
|
|
Loading…
Reference in New Issue