diff --git a/src/core/cheats.cpp b/src/core/cheats.cpp index 329c8e209..58909c7aa 100644 --- a/src/core/cheats.cpp +++ b/src/core/cheats.cpp @@ -2281,7 +2281,12 @@ std::unique_ptr Cheats::GamesharkCheatCode::Parse(Me return code; } -static std::array cht_register; // Used for D7 ,51 & 52 cheat types +static std::array cht_register; // 0-255 Used for D7 ,51 & 52 cheat types. 256-1023 for stealth cheats + +const std::array& Cheats::GetChtRegister() +{ + return cht_register; +} template NEVER_INLINE static T DoMemoryRead(VirtualMemoryAddress address) @@ -2983,7 +2988,7 @@ void Cheats::GamesharkCheatCode::Apply() const // set // (safety valve) // cht_offset = the index of the individual array to change (so must be 0 to cht_register[cht_reg_no1+1]) - if ((cht_reg_no1 <= (std::size(cht_register) - 4)) && cht_register[cht_reg_no1 + 3] == 0xD0D0 && + if (cht_reg_no1 <= 252 && cht_register[cht_reg_no1 + 3] == 0xD0D0 && cht_register[cht_reg_no1 + 2] > 0 && cht_register[cht_reg_no1 + 1] >= cht_offset) { DoMemoryWrite((cht_register[cht_reg_no1] - cht_register[cht_reg_no1 + 1]) + @@ -3027,7 +3032,7 @@ void Cheats::GamesharkCheatCode::Apply() const // set // (safety valve) // cht_offset = the index of the individual array to change (so must be 0 to cht_register[cht_reg_no1+1]) - if ((cht_reg_no1 <= (std::size(cht_register) - 4)) && cht_register[cht_reg_no1 + 3] == 0xD0D0 && + if (cht_reg_no1 <= 252 && cht_register[cht_reg_no1 + 3] == 0xD0D0 && cht_register[cht_reg_no1 + 2] > 0 && cht_register[cht_reg_no1 + 1] >= cht_offset) { DoMemoryWrite((cht_register[cht_reg_no1] - cht_register[cht_reg_no1 + 1]) + @@ -3101,6 +3106,17 @@ void Cheats::GamesharkCheatCode::Apply() const case 0xCA: // Reg3 = Reg1 >> X cht_register[cht_reg_no3] = cht_register[cht_reg_no1] >> cht_reg_no2; break; + case 0xE1: // Stealth Cheat - PC Address - uses registers 256-511 + cht_register[cht_reg_no1+256] = poke_value; + if (cht_register[1024] < (u32)(cht_reg_no1 + 1)) //Set to highest reg if any Stealth cheat is ever enabled for a game + cht_register[1024] = cht_reg_no1 + 1; + break; + case 0xE2: // Stealth Cheat - Actual Contents of PC Address - uses registers 512-767 + cht_register[cht_reg_no1+512] = poke_value; + break; + case 0xE3: // Stealth Cheat - Stealth Contents of PC Address - uses registers 768-1023 + cht_register[cht_reg_no1+768] = poke_value; + break; // Lots of options exist for expanding into this space default: break; @@ -4306,10 +4322,21 @@ void Cheats::GamesharkCheatCode::ApplyOnDisable(RollbackLog* rollback_list) cons case InstructionCode::ExtConstantSwap16: case InstructionCode::DelayActivation: // C1 case InstructionCode::ExtConstantWriteIfMatch16: - case InstructionCode::ExtCheatRegisters: index++; break; - + case InstructionCode::ExtCheatRegisters: // 51 + { + const u8 cht_reg_no = Truncate8(inst.first & 0xFFu); + const u8 sub_type = Truncate8((inst.first & 0xFF0000u) >> 16); + if (sub_type == 0xE1) //Stealth Cheat, clear all 3 registers on disable for all three parts + { + cht_register[cht_reg_no + 256] = 0; + cht_register[cht_reg_no + 512] = 0; + cht_register[cht_reg_no + 768] = 0; + } + index++; + break; + } case InstructionCode::ExtConstantForceRange16: case InstructionCode::Slide: case InstructionCode::ExtImprovedSlide: diff --git a/src/core/cheats.h b/src/core/cheats.h index 7363f7e92..5388ba9ab 100644 --- a/src/core/cheats.h +++ b/src/core/cheats.h @@ -5,6 +5,7 @@ #include "types.h" +#include #include #include #include @@ -191,4 +192,6 @@ extern const char* PATCHES_CONFIG_SECTION; extern const char* CHEATS_CONFIG_SECTION; extern const char* PATCH_ENABLE_CONFIG_KEY; +const std::array& GetChtRegister(); + } // namespace Cheats diff --git a/src/core/cpu_recompiler.cpp b/src/core/cpu_recompiler.cpp index fb9da9856..411b1e8bd 100644 --- a/src/core/cpu_recompiler.cpp +++ b/src/core/cpu_recompiler.cpp @@ -7,6 +7,7 @@ #include "cpu_disasm.h" #include "cpu_pgxp.h" #include "settings.h" +#include "cheats.h" #include "common/assert.h" #include "common/log.h" @@ -1195,6 +1196,22 @@ void CPU::Recompiler::Recompiler::CompileInstruction() UpdateLoadDelay(); return; } + + //Stealth Cheats + const auto& cht_reg = Cheats::GetChtRegister(); + if (cht_reg[1024] > 0) + { + for (unsigned int i = 0; i < cht_reg[1024]; i++) + { + if (m_current_instruction_pc == cht_reg[i + 256] && inst->bits == cht_reg[i + 512]) + { + // inst is intentionally const - we cast away const only for the single asm changes needed. + const_cast(inst)->bits = cht_reg[i + 768]; + break; + } + } + } + switch (inst->op) {