diff --git a/src/core/cheats.cpp b/src/core/cheats.cpp index 8bda6816c..5a0dec6f4 100644 --- a/src/core/cheats.cpp +++ b/src/core/cheats.cpp @@ -15,6 +15,7 @@ #include #include Log_SetChannel(Cheats); +static std::array temp_variable; //Used for D7 ,51 & 52 cheat types using KeyValuePairVector = std::vector>; @@ -138,6 +139,58 @@ static u32 GetControllerButtonBits() return translated_bits; } +static u32 GetControllerAnalogBits() +{ + // 0x010000 - Right Thumb Up + // 0x020000 - Right Thumb Right + // 0x040000 - Right Thumb Down + // 0x080000 - Right Thumb Left + // 0x100000 - Left Thumb Up + // 0x200000 - Left Thumb Right + // 0x400000 - Left Thumb Down + // 0x800000 - Left Thumb Left + + u32 bits = 0; + u8 l_ypos = 0; + u8 l_xpos = 0; + u8 r_ypos = 0; + u8 r_xpos = 0; + + std::optional analog = 0; + for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) + { + Controller* controller = System::GetController(i); + if (!controller) + continue; + + analog = controller->GetAnalogInputBytes(); + if (analog.has_value()) + { + l_ypos = Truncate8((analog.value() & 0xFF000000u) >> 24); + l_xpos = Truncate8((analog.value() & 0x00FF0000u) >> 16); + r_ypos = Truncate8((analog.value() & 0x0000FF00u) >> 8); + r_xpos = Truncate8(analog.value() & 0x000000FFu); + if (l_ypos < 0x50) + bits |= 0x100000; + else if (l_ypos > 0xA0) + bits |= 0x400000; + if (l_xpos < 0x50) + bits |= 0x800000; + else if (l_xpos > 0xA0) + bits |= 0x200000; + if (r_ypos < 0x50) + bits |= 0x10000; + else if (r_ypos > 0xA0) + bits |= 0x40000; + if (r_xpos < 0x50) + bits |= 0x80000; + else if (r_xpos > 0xA0) + bits |= 0x20000; + } + } + return bits; +} + CheatList::CheatList() = default; CheatList::~CheatList() = default; @@ -632,11 +685,8 @@ bool CheatList::LoadFromString(const std::string& str, Format format) return LoadFromPCSXRString(str); else if (format == Format::Libretro) return LoadFromLibretroString(str); - else if (format == Format::EPSXe) - return LoadFromEPSXeString(str); - - Log_ErrorPrintf("Invalid or unknown cheat format"); - return false; + format = Format::EPSXe; + return LoadFromEPSXeString(str); } bool CheatList::SaveToPCSXRFile(const char* filename) @@ -1420,10 +1470,109 @@ void CheatCode::Apply() const } break; + case InstructionCode::ExtTempVariable: // 51 + { + const u32 poke_value = inst.address; + const u8 temp_variable_number1 = Truncate8(inst.value32 & 0xFFu); + const u8 temp_variable_number2 = Truncate8((inst.value32 & 0xFF00u) >> 8); + const u8 sub_type = Truncate8((inst.value32 & 0xFF0000u) >> 16); + + switch (sub_type) + { + case 0x00: // Write the u8 from temp_variable[temp_variable_number1] to address + DoMemoryWrite(inst.address, Truncate8(temp_variable[temp_variable_number1])); + index++; + break; + case 0x01: // Read the u8 from address to temp_variable[temp_variable_number1] + temp_variable[temp_variable_number1] = DoMemoryRead(inst.address); + index++; + break; + case 0x02: // Write the u8 from address field to the address stored in temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], Truncate8(poke_value)); + index++; + break; + + case 0x10: // Write the u16 from temp_variable[temp_variable_number1] to address + DoMemoryWrite(inst.address, Truncate16(temp_variable[temp_variable_number1])); + index++; + break; + case 0x11: // Read the u16 from address to temp_variable[temp_variable_number1] + temp_variable[temp_variable_number1] = DoMemoryRead(inst.address); + index++; + break; + case 0x12: // Write the u16 from address field to the address stored in temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], Truncate16(poke_value)); + index++; + break; + + case 0x30: // Write the u32 from temp_variable[temp_variable_number1] to address + DoMemoryWrite(inst.address, temp_variable[temp_variable_number1]); + index++; + break; + case 0x31: // Read the u32 from address to temp_variable[temp_variable_number1] + temp_variable[temp_variable_number1] = DoMemoryRead(inst.address); + index++; + break; + case 0x32: // Write the u16 from address field to the address stored in temp_variable[temp_variable_number] + DoMemoryWrite(temp_variable[temp_variable_number1], poke_value); + index++; + break; + + case 0x04: // Write the u8 from temp_variable[temp_variable_number2] to the address stored in + // temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], Truncate8(temp_variable[temp_variable_number2])); + index++; + break; + case 0x14: // Write the u16 from temp_variable[temp_variable_number2] to the address stored in + // temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], Truncate16(temp_variable[temp_variable_number2])); + index++; + break; + case 0x24: // Write the u32 from temp_variable[temp_variable_number2] to the address stored in + // temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], temp_variable[temp_variable_number2]); + index++; + break; + case 0x34: // Write the u16 from address field to the address stored in temp_variable[temp_variable_number] + DoMemoryWrite(temp_variable[temp_variable_number1], poke_value); + index++; + break; + + case 0x05: // Write the u8 from the address stored in temp_variable[temp_variable_number2] to the address + // stored in temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], + DoMemoryRead(temp_variable[temp_variable_number2])); + index++; + break; + case 0x15: // Write the u16 from the address stored in temp_variable[temp_variable_number2] to the address + // stored in temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], + DoMemoryRead(temp_variable[temp_variable_number2])); + index++; + break; + case 0x25: // Write the u32 from the address stored in temp_variable[temp_variable_number2] to the address + // stored in temp_variable[temp_variable_number1] + DoMemoryWrite(temp_variable[temp_variable_number1], + DoMemoryRead(temp_variable[temp_variable_number2])); + index++; + break; + + // Lots of options exist for expanding into this space + default: + index++; + break; + } + } + break; + case InstructionCode::SkipIfNotEqual16: // C0 case InstructionCode::ExtSkipIfNotEqual32: // A4 case InstructionCode::SkipIfButtonsNotEqual: // D5 case InstructionCode::SkipIfButtonsEqual: // D6 + case InstructionCode::ExtSkipIfNotLess8: // C3 + case InstructionCode::ExtSkipIfNotGreater8: // C4 + case InstructionCode::ExtSkipIfNotLess16: // C5 + case InstructionCode::ExtSkipIfNotGreater16: // C6 { index++; @@ -1442,6 +1591,18 @@ void CheatCode::Apply() const case InstructionCode::SkipIfButtonsEqual: // D6 activate_codes = (GetControllerButtonBits() != inst.value16); break; + case InstructionCode::ExtSkipIfNotLess8: // C3 + activate_codes = (DoMemoryRead(inst.address) < inst.value8); + break; + case InstructionCode::ExtSkipIfNotGreater8: // C4 + activate_codes = (DoMemoryRead(inst.address) > inst.value8); + break; + case InstructionCode::ExtSkipIfNotLess16: // C5 + activate_codes = (DoMemoryRead(inst.address) < inst.value16); + break; + case InstructionCode::ExtSkipIfNotGreater16: // C6 + activate_codes = (DoMemoryRead(inst.address) > inst.value16); + break; default: activate_codes = false; break; @@ -1465,6 +1626,69 @@ void CheatCode::Apply() const } break; + case InstructionCode::ExtBitCompareButtons: // D7 + { + index++; + bool activate_codes; + const u32 frame_compare_value = inst.address & 0xFFFFu; + const u8 temp_variable_number = Truncate8((inst.value32 & 0xFF000000u)>>24); + const bool bit_comparison_type = ((inst.address & 0x100000u) >>20); + const u8 frame_comparison = Truncate8((inst.address & 0xF0000u) >>16); + const u32 check_value = (inst.value32 & 0xFFFFFFu); + const u32 value1 = GetControllerButtonBits(); + const u32 value2 = GetControllerAnalogBits(); + u32 value = value1 | value2; + + if ((bit_comparison_type==false && check_value==(value & check_value))//Check Bits are set + || (bit_comparison_type==true && check_value!=(value & check_value))) //Check Bits are clear + { + temp_variable[temp_variable_number]+=1; + switch (frame_comparison) + { + case 0x0: // No comparison on frame count, just do it + activate_codes = true; + break; + case 0x1: // Check if frame_compare_value == current count + activate_codes = (temp_variable[temp_variable_number] == frame_compare_value); + break; + case 0x2: // Check if frame_compare_value < current count + activate_codes = (temp_variable[temp_variable_number] < frame_compare_value); + break; + case 0x3: // Check if frame_compare_value > current count + activate_codes = (temp_variable[temp_variable_number] > frame_compare_value); + break; + case 0x4: // Check if frame_compare_value != current count + activate_codes = (temp_variable[temp_variable_number] != frame_compare_value); + break; + default: + activate_codes = false; + break; + } + } + else + { + temp_variable[temp_variable_number]=0; + activate_codes = false; + } + + if (activate_codes) + { + // execute following instructions + continue; + } + + // skip to the next separator (00000000 FFFF), or end + constexpr u64 separator_value = UINT64_C(0x000000000000FFFF); + while (index < count) + { + // we don't want to execute the separator instruction + const u64 bits = instructions[index++].bits; + if (bits == separator_value) + break; + } + } + break; + case InstructionCode::DelayActivation: // C1 { // A value of around 4000 or 5000 will usually give you a good 20-30 second delay before codes are activated. @@ -1588,6 +1812,7 @@ void CheatCode::ApplyOnDisable() const case InstructionCode::ExtConstantForceRangeRollRound16: case InstructionCode::DelayActivation: // C1 case InstructionCode::ExtConstantWriteIfMatch16: + case InstructionCode::ExtTempVariable: index++; break; @@ -1621,6 +1846,11 @@ void CheatCode::ApplyOnDisable() const case InstructionCode::ExtSkipIfNotEqual32: // A4 case InstructionCode::SkipIfButtonsNotEqual: // D5 case InstructionCode::SkipIfButtonsEqual: // D6 + case InstructionCode::ExtBitCompareButtons: // D7 + case InstructionCode::ExtSkipIfNotLess8: // C3 + case InstructionCode::ExtSkipIfNotGreater8: // C4 + case InstructionCode::ExtSkipIfNotLess16: // C5 + case InstructionCode::ExtSkipIfNotGreater16: // C6 index++; break; diff --git a/src/core/cheats.h b/src/core/cheats.h index 805a155d2..6af7167b7 100644 --- a/src/core/cheats.h +++ b/src/core/cheats.h @@ -69,6 +69,14 @@ struct CheatCode ExtConstantBitClear16 = 0x82, ExtConstantBitSet32 = 0x91, ExtConstantBitClear32 = 0x92, + + ExtBitCompareButtons = 0xD7, + ExtSkipIfNotLess8 = 0xC3, + ExtSkipIfNotGreater8 = 0xC4, + ExtSkipIfNotLess16 = 0xC5, + ExtSkipIfNotGreater16 = 0xC6, + + ExtTempVariable = 0x51, }; union Instruction