Cheats: Auto-convert between the different types of cheat codes (when possible)
This commit is contained in:
parent
f5bc7b48ae
commit
a29cc4c8d0
1 changed files with 194 additions and 8 deletions
|
@ -102,25 +102,27 @@ namespace Mesen.GUI.Forms.Cheats
|
|||
}
|
||||
|
||||
if(radGameGenie.Checked) {
|
||||
if(txtGameGenie.Text.Length != frmCheat.GGShortCodeLength && txtGameGenie.Text.Length != frmCheat.GGLongCodeLength) {
|
||||
string ggCode = txtGameGenie.Text.Trim();
|
||||
if(ggCode.Length != frmCheat.GGShortCodeLength && ggCode.Length != frmCheat.GGLongCodeLength) {
|
||||
return false;
|
||||
}
|
||||
if(txtGameGenie.Text.Count(c => !"APZLGITYEOXUKSVN".Contains(c.ToString().ToUpper())) > 0) {
|
||||
if(ggCode.Count(c => !"APZLGITYEOXUKSVN".Contains(c.ToString().ToUpper())) > 0) {
|
||||
return false;
|
||||
}
|
||||
} else if(radProActionRocky.Checked) {
|
||||
if(txtProActionRocky.Text.Length != frmCheat.PARCodeLength) {
|
||||
string parCode = txtProActionRocky.Text.Trim();
|
||||
if(parCode.Length != frmCheat.PARCodeLength) {
|
||||
return false;
|
||||
}
|
||||
if(!UInt32.TryParse(txtProActionRocky.Text, System.Globalization.NumberStyles.AllowHexSpecifier, null, out val)) {
|
||||
if(!UInt32.TryParse(parCode, System.Globalization.NumberStyles.AllowHexSpecifier, null, out val)) {
|
||||
return false;
|
||||
}
|
||||
if(txtProActionRocky.Text.Count(c => !"1234567890ABCDEF".Contains(c.ToString().ToUpper())) > 0) {
|
||||
if(parCode.Count(c => !"1234567890ABCDEF".Contains(c.ToString().ToUpper())) > 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Byte byteVal;
|
||||
if(!UInt32.TryParse(txtAddress.Text, System.Globalization.NumberStyles.AllowHexSpecifier, null, out val)) {
|
||||
if(!UInt32.TryParse(txtAddress.Text.Trim(), System.Globalization.NumberStyles.AllowHexSpecifier, null, out val)) {
|
||||
return false;
|
||||
}
|
||||
if(radRelativeAddress.Checked && val > 0xFFFF) {
|
||||
|
@ -128,18 +130,52 @@ namespace Mesen.GUI.Forms.Cheats
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!Byte.TryParse(txtValue.Text, System.Globalization.NumberStyles.AllowHexSpecifier, null, out byteVal)) {
|
||||
if(!Byte.TryParse(txtValue.Text.Trim(), System.Globalization.NumberStyles.AllowHexSpecifier, null, out byteVal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Byte.TryParse(txtCompare.Text, System.Globalization.NumberStyles.AllowHexSpecifier, null, out byteVal)) {
|
||||
if(!string.IsNullOrWhiteSpace(txtCompare.Text.Trim()) && !Byte.TryParse(txtCompare.Text.Trim(), System.Globalization.NumberStyles.AllowHexSpecifier, null, out byteVal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ConvertCode();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ConvertCode()
|
||||
{
|
||||
//Automatically update the other fields to match the active code (when possible)
|
||||
UpdateObject();
|
||||
|
||||
CheatInfo cheat = (CheatInfo)this.Entity;
|
||||
if(cheat.CheatType == CheatType.GameGenie) {
|
||||
CheatData convertedData = ConvertGameGenieCode(cheat.GameGenieCode.ToUpper());
|
||||
txtProActionRocky.Text = ToProActionReplayCode(convertedData.Address, convertedData.Value, convertedData.CompareValue);
|
||||
txtAddress.Text = convertedData.Address.ToString("X4");
|
||||
txtValue.Text = convertedData.Value.ToString("X2");
|
||||
txtCompare.Text = convertedData.CompareValue >= 0 ? convertedData.CompareValue.ToString("X2") : "";
|
||||
chkCompareValue.Checked = convertedData.CompareValue >= 0;
|
||||
} else if(cheat.CheatType == CheatType.ProActionRocky) {
|
||||
CheatData convertedData = ConvertProActionReplayCode(cheat.ProActionRockyCode);
|
||||
txtGameGenie.Text = ToGameGenieCode(convertedData.Address, convertedData.Value, convertedData.CompareValue);
|
||||
txtAddress.Text = convertedData.Address.ToString("X4");
|
||||
txtValue.Text = convertedData.Value.ToString("X2");
|
||||
txtCompare.Text = convertedData.CompareValue.ToString("X2");
|
||||
radRelativeAddress.Checked = true;
|
||||
chkCompareValue.Checked = true;
|
||||
} else {
|
||||
if(cheat.IsRelativeAddress && cheat.Address >= 0x8000) {
|
||||
txtGameGenie.Text = ToGameGenieCode((int)cheat.Address, cheat.Value, cheat.UseCompareValue ? cheat.CompareValue : -1);
|
||||
txtProActionRocky.Text = ToProActionReplayCode((int)cheat.Address, cheat.Value, cheat.UseCompareValue ? cheat.CompareValue : -1);
|
||||
} else {
|
||||
txtProActionRocky.Text = "";
|
||||
txtGameGenie.Text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void txtGameGenie_Enter(object sender, EventArgs e)
|
||||
{
|
||||
radGameGenie.Checked = true;
|
||||
|
@ -159,5 +195,155 @@ namespace Mesen.GUI.Forms.Cheats
|
|||
{
|
||||
txtCompare.Enabled = chkCompareValue.Checked;
|
||||
}
|
||||
|
||||
private int DecodeValue(int code, int[] bitIndexes)
|
||||
{
|
||||
int result = 0;
|
||||
for(int i = 0; i < bitIndexes.Length; i++) {
|
||||
result <<= 1;
|
||||
result |= (code >> bitIndexes[i]) & 0x01;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int EncodeValue(int code, int[] bitIndexes)
|
||||
{
|
||||
int result = 0;
|
||||
for(int i = 0; i < bitIndexes.Length; i++) {
|
||||
result |= ((code >> i) & 0x01) << bitIndexes[bitIndexes.Length - i - 1];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private CheatData ConvertGameGenieCode(string ggCode)
|
||||
{
|
||||
string ggLetters = "APZLGITYEOXUKSVN";
|
||||
|
||||
int rawCode = 0;
|
||||
for(int i = 0, len = ggCode.Length; i < len; i++) {
|
||||
rawCode |= ggLetters.IndexOf(ggCode[i]) << (i * 4);
|
||||
}
|
||||
|
||||
int[] addressBits = { 14, 13, 12, 19, 22, 21, 20, 7, 10, 9, 8, 15, 18, 17, 16 };
|
||||
int[] valueBits = { 3, 6, 5, 4, 23, 2, 1, 0 };
|
||||
int compareValue = -1;
|
||||
if(ggCode.Length == 8) {
|
||||
//Bit 5 of the value is stored in a different location for 8-character codes
|
||||
valueBits[4] = 31;
|
||||
|
||||
int[] compareValueBits = { 27, 30, 29, 28, 23, 26, 25, 24 };
|
||||
compareValue = DecodeValue(rawCode, compareValueBits);
|
||||
}
|
||||
int address = DecodeValue(rawCode, addressBits) + 0x8000;
|
||||
int value = DecodeValue(rawCode, valueBits);
|
||||
|
||||
return new CheatData() {
|
||||
Address = address,
|
||||
Value = value,
|
||||
CompareValue = compareValue
|
||||
};
|
||||
}
|
||||
|
||||
private string ToGameGenieCode(int address, int value, int compareValue)
|
||||
{
|
||||
string ggLetters = "APZLGITYEOXUKSVN";
|
||||
|
||||
int[] addressBits = { 14, 13, 12, 19, 22, 21, 20, 7, 10, 9, 8, 15, 18, 17, 16 };
|
||||
int[] valueBits = { 3, 6, 5, 4, 23, 2, 1, 0 };
|
||||
int[] compareValueBits = { 27, 30, 29, 28, 23, 26, 25, 24 };
|
||||
|
||||
if(compareValue >= 0) {
|
||||
//Bit 5 of the value is stored in a different location for 8-character codes
|
||||
valueBits[4] = 31;
|
||||
}
|
||||
|
||||
UInt32 encodedAddress = (UInt32)(EncodeValue(address - 0x8000, addressBits) | 0x800);
|
||||
UInt32 encodedValue = (UInt32)EncodeValue(value, valueBits);
|
||||
|
||||
UInt32 encodedCode = encodedValue | encodedAddress;
|
||||
if(compareValue >= 0) {
|
||||
UInt32 encodedCompareValue = (UInt32)EncodeValue(compareValue, compareValueBits);
|
||||
encodedCode |= encodedCompareValue;
|
||||
}
|
||||
|
||||
int codeSize = compareValue >= 0 ? 8 : 6;
|
||||
string codeString = "";
|
||||
for(int i = 0; i < codeSize; i++) {
|
||||
codeString += ggLetters[(int)encodedCode & 0x0F];
|
||||
encodedCode >>= 4;
|
||||
}
|
||||
|
||||
return codeString;
|
||||
}
|
||||
|
||||
private CheatData ConvertProActionReplayCode(UInt32 parCode)
|
||||
{
|
||||
int[] shiftValues = {
|
||||
3, 13, 14, 1, 6, 9, 5, 0, 12, 7, 2, 8, 10, 11, 4, //address
|
||||
19, 21, 23, 22, 20, 17, 16, 18, //compare
|
||||
29, 31, 24, 26, 25, 30, 27, 28 //value
|
||||
};
|
||||
UInt32 key = 0x7E5EE93A;
|
||||
UInt32 xorValue = 0x5C184B91;
|
||||
|
||||
//Throw away bit 0, not used.
|
||||
parCode >>= 1;
|
||||
|
||||
UInt32 result = 0;
|
||||
for(int i = 30; i >= 0; i--) {
|
||||
if((((key ^ parCode) >> 30) & 0x01) != 0) {
|
||||
result |= (UInt32)(0x01 << shiftValues[i]);
|
||||
key ^= xorValue;
|
||||
}
|
||||
parCode <<= 1;
|
||||
key <<= 1;
|
||||
}
|
||||
|
||||
return new CheatData() {
|
||||
Address = (int)((result & 0x7fff) + 0x8000),
|
||||
Value = (int)(result >> 24) & 0xFF,
|
||||
CompareValue = (int)(result >> 16) & 0xFF
|
||||
};
|
||||
}
|
||||
|
||||
private string ToProActionReplayCode(int address, int value, int compareValue)
|
||||
{
|
||||
if(compareValue < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
int[] shiftValues = {
|
||||
3, 13, 14, 1, 6, 9, 5, 0, 12, 7, 2, 8, 10, 11, 4, //address
|
||||
19, 21, 23, 22, 20, 17, 16, 18, //compare
|
||||
29, 31, 24, 26, 25, 30, 27, 28 //value
|
||||
};
|
||||
|
||||
int encodedValue = (address & 0x7FFF) | (compareValue << 16) | (value << 24);
|
||||
|
||||
UInt32 key = 0x7E5EE93A;
|
||||
UInt32 xorValue = 0x5C184B91;
|
||||
|
||||
UInt32 result = 0;
|
||||
for(int i = 30; i >= 0; i--) {
|
||||
int bit = (int)(encodedValue >> shiftValues[i]) & 0x01;
|
||||
if((((key >> 30) ^ bit) & 0x01) != 0) {
|
||||
result |= (UInt32)2 << i;
|
||||
}
|
||||
if((bit & 0x01) != 0) {
|
||||
key ^= xorValue;
|
||||
}
|
||||
|
||||
key <<= 1;
|
||||
}
|
||||
|
||||
return result.ToString("X8");
|
||||
}
|
||||
|
||||
struct CheatData
|
||||
{
|
||||
public int Address;
|
||||
public int Value;
|
||||
public int CompareValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue