Added new cheat cheat types: C3, C4, C5, C6, D7&52
C3-C7 are variants of C0 D7 is a BIT based joker to rule them all. It includes the analog sticks (@ggrtk thanks for adding the analog reading capability). Also added the facility of making dual single key joker by varying the amount of time a button is held down. 51 is a complicated beast that I still need to document * C3XXXXXX 00YY - 8-Bit Master Code, if ($XXXXXX) is less than 0xYY poke all 00000000 FFFF following codes for rest of the cheat or until it reaches the 00000000 FFFF line. * C4XXXXXX 00YY - 8-Bit Master Code, if ($XXXXXX) is greater than 0xYY poke all 00000000 FFFF following codes for rest of the cheat or until it reaches the 00000000 FFFF line. * C5XXXXXX YYYY - 16-Bit Master Code, if ($XXXXXX) is less than 0xYYYY poke all 00000000 FFFF following codes for rest of the cheat or until it reaches the 00000000 FFFF line. * C6XXXXXX YYYY - 16-Bit Master Code, if ($XXXXXX) is greater than 0xYYYY poke all 00000000 FFFF following codes for rest of the cheat or until it reaches the 00000000 FFFF line. * D7PQRRRR TTYYYYYY - 24-Bit Universal BIT Joker, OR the hex values to combine into a multi-button joker. Because it is BIT based it is better than D4, D5, D6 or using a D0 joker as you do not need to worry about any other buttons being pressed at the same time and you get both analog sticks for extra functionality. Note if you want to use it just as a enhanced joker just use D7000000 00YYYYYY when the buttons/directions are pressed or D7100000 00YYYYYY when you want to ensure they are not all pressed. QRRRR TT provides the capability of only activating the following codes after the keys have been held in for a set amount of frames. 003C = 60 Frames = 1 Second at 100% Speed YYYYYY = 000001 L2 Button YYYYYY = 000002 R2 Button YYYYYY = 000004 L1 Button YYYYYY = 000008 R1 Button YYYYYY = 000010 Triangle Button YYYYYY = 000020 Circle Button YYYYYY = 000040 X Button YYYYYY = 000080 Square Button YYYYYY = 000100 Select Button YYYYYY = 000200 L3 Button YYYYYY = 000400 R3 Button YYYYYY = 000800 Start Button YYYYYY = 001000 Up (Digital) YYYYYY = 002000 Right (Digital) YYYYYY = 004000 Down (Digital) YYYYYY = 008000 Left (Digital) YYYYYY = 010000 Up (Right Thumb) YYYYYY = 020000 Right (Right Thumb) YYYYYY = 040000 Down (Right Thumb) YYYYYY = 080000 Left (Right Thumb) YYYYYY = 100000 Up (Left Thumb) YYYYYY = 200000 Right (Left Thumb) YYYYYY = 400000 Down (Left Thumb) YYYYYY = 800000 Left (Left Thumb) NOTE: The 0s in the code are reserved for possible future use. TT=Temp Internal Variable 00-FF, 00 will mean it wont be used, if it's not 00 do not use the same value for jokers using different keypress combinations for the same game. P = 0 or 1. 0 = Check ALL YYYYYY Bits are ON 1 = Check ALL YYYYYY Bits are OFF Q = Frame Comparison 0 = Dont do any comparison 1 = Check that the button combination has been held down for exactly RRRR frames. 2 = Check that the button combination has been held down for more than RRRR frames. 3 = Check that the button combination has been held down for less than RRRR frames. 4 = Check that the button combination has been held down for anything but RRRR frames. RRRR = 0000 to FFFF, Frame Comparison Value It will then poke all following codes for rest of cheat 00000000 FFFF or until it reaches the 00000000 FFFF line.
This commit is contained in:
parent
21e53016d7
commit
74b2b2ddfe
|
@ -15,6 +15,7 @@
|
|||
#include <iomanip>
|
||||
#include <sstream>
|
||||
Log_SetChannel(Cheats);
|
||||
static std::array<u32, 256> temp_variable; //Used for D7 ,51 & 52 cheat types
|
||||
|
||||
using KeyValuePairVector = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
|
@ -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<u32> 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;
|
||||
|
@ -629,11 +682,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)
|
||||
format = Format::EPSXe;
|
||||
return LoadFromEPSXeString(str);
|
||||
|
||||
Log_ErrorPrintf("Invalid or unknown cheat format");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheatList::SaveToPCSXRFile(const char* filename)
|
||||
|
@ -1417,10 +1467,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<u8>(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<u8>(inst.address);
|
||||
index++;
|
||||
break;
|
||||
case 0x02: // Write the u8 from address field to the address stored in temp_variable[temp_variable_number1]
|
||||
DoMemoryWrite<u8>(temp_variable[temp_variable_number1], Truncate8(poke_value));
|
||||
index++;
|
||||
break;
|
||||
|
||||
case 0x10: // Write the u16 from temp_variable[temp_variable_number1] to address
|
||||
DoMemoryWrite<u16>(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<u16>(inst.address);
|
||||
index++;
|
||||
break;
|
||||
case 0x12: // Write the u16 from address field to the address stored in temp_variable[temp_variable_number1]
|
||||
DoMemoryWrite<u16>(temp_variable[temp_variable_number1], Truncate16(poke_value));
|
||||
index++;
|
||||
break;
|
||||
|
||||
case 0x30: // Write the u32 from temp_variable[temp_variable_number1] to address
|
||||
DoMemoryWrite<u32>(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<u32>(inst.address);
|
||||
index++;
|
||||
break;
|
||||
case 0x32: // Write the u16 from address field to the address stored in temp_variable[temp_variable_number]
|
||||
DoMemoryWrite<u32>(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<u8>(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<u16>(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<u32>(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<u32>(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<u8>(temp_variable[temp_variable_number1],
|
||||
DoMemoryRead<u8>(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<u16>(temp_variable[temp_variable_number1],
|
||||
DoMemoryRead<u16>(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<u32>(temp_variable[temp_variable_number1],
|
||||
DoMemoryRead<u32>(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++;
|
||||
|
||||
|
@ -1439,6 +1588,18 @@ void CheatCode::Apply() const
|
|||
case InstructionCode::SkipIfButtonsEqual: // D6
|
||||
activate_codes = (GetControllerButtonBits() != inst.value16);
|
||||
break;
|
||||
case InstructionCode::ExtSkipIfNotLess8: // C3
|
||||
activate_codes = (DoMemoryRead<u8>(inst.address) < inst.value8);
|
||||
break;
|
||||
case InstructionCode::ExtSkipIfNotGreater8: // C4
|
||||
activate_codes = (DoMemoryRead<u8>(inst.address) > inst.value8);
|
||||
break;
|
||||
case InstructionCode::ExtSkipIfNotLess16: // C5
|
||||
activate_codes = (DoMemoryRead<u16>(inst.address) < inst.value16);
|
||||
break;
|
||||
case InstructionCode::ExtSkipIfNotGreater16: // C6
|
||||
activate_codes = (DoMemoryRead<u16>(inst.address) > inst.value16);
|
||||
break;
|
||||
default:
|
||||
activate_codes = false;
|
||||
break;
|
||||
|
@ -1462,6 +1623,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.
|
||||
|
@ -1585,6 +1809,7 @@ void CheatCode::ApplyOnDisable() const
|
|||
case InstructionCode::ExtConstantForceRangeRollRound16:
|
||||
case InstructionCode::DelayActivation: // C1
|
||||
case InstructionCode::ExtConstantWriteIfMatch16:
|
||||
case InstructionCode::ExtTempVariable:
|
||||
index++;
|
||||
break;
|
||||
|
||||
|
@ -1618,6 +1843,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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue