118 lines
3.2 KiB
C#
118 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace BizHawk.Client.Common.cheats
|
|
{
|
|
public static class NesGameGenieDecoder
|
|
{
|
|
private static readonly Dictionary<char, int> GameGenieTable = new Dictionary<char, int>
|
|
{
|
|
['A'] = 0, // 0000
|
|
['P'] = 1, // 0001
|
|
['Z'] = 2, // 0010
|
|
['L'] = 3, // 0011
|
|
['G'] = 4, // 0100
|
|
['I'] = 5, // 0101
|
|
['T'] = 6, // 0110
|
|
['Y'] = 7, // 0111
|
|
['E'] = 8, // 1000
|
|
['O'] = 9, // 1001
|
|
['X'] = 10, // 1010
|
|
['U'] = 11, // 1011
|
|
['K'] = 12, // 1100
|
|
['S'] = 13, // 1101
|
|
['V'] = 14, // 1110
|
|
['N'] = 15 // 1111
|
|
};
|
|
|
|
public static IDecodeResult Decode(string code)
|
|
{
|
|
if (code == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(code));
|
|
}
|
|
|
|
if (code.Length != 6 && code.Length != 8)
|
|
{
|
|
return new InvalidCheatCode("Game Genie codes need to be six or eight characters in length.");
|
|
}
|
|
|
|
var result = new DecodeResult { Size = WatchSize.Byte };
|
|
// char 3 bit 3 denotes the code length.
|
|
if (code.Length == 6)
|
|
{
|
|
// Char # | 1 | 2 | 3 | 4 | 5 | 6 |
|
|
// Bit # |3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|
|
|
// maps to|1|6|7|8|H|2|3|4|-|I|J|K|L|A|B|C|D|M|N|O|5|E|F|G|
|
|
result.Value = 0;
|
|
result.Address = 0x8000;
|
|
|
|
GameGenieTable.TryGetValue(code[0], out var x);
|
|
result.Value |= x & 0x07;
|
|
result.Value |= (x & 0x08) << 4;
|
|
|
|
GameGenieTable.TryGetValue(code[1], out x);
|
|
result.Value |= (x & 0x07) << 4;
|
|
result.Address |= (x & 0x08) << 4;
|
|
|
|
GameGenieTable.TryGetValue(code[2], out x);
|
|
result.Address |= (x & 0x07) << 4;
|
|
|
|
GameGenieTable.TryGetValue(code[3], out x);
|
|
result.Address |= (x & 0x07) << 12;
|
|
result.Address |= x & 0x08;
|
|
|
|
GameGenieTable.TryGetValue(code[4], out x);
|
|
result.Address |= x & 0x07;
|
|
result.Address |= (x & 0x08) << 8;
|
|
|
|
GameGenieTable.TryGetValue(code[5], out x);
|
|
result.Address |= (x & 0x07) << 8;
|
|
result.Value |= x & 0x08;
|
|
}
|
|
else
|
|
{
|
|
// Char # | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
|
// Bit # |3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|3|2|1|0|
|
|
// maps to|1|6|7|8|H|2|3|4|-|I|J|K|L|A|B|C|D|M|N|O|%|E|F|G|!|^|&|*|5|@|#|$|
|
|
result.Value = 0;
|
|
result.Address = 0x8000;
|
|
result.Compare = 0;
|
|
|
|
GameGenieTable.TryGetValue(code[0], out var x);
|
|
result.Value |= x & 0x07;
|
|
result.Value |= (x & 0x08) << 4;
|
|
|
|
GameGenieTable.TryGetValue(code[1], out x);
|
|
result.Value |= (x & 0x07) << 4;
|
|
result.Address |= (x & 0x08) << 4;
|
|
|
|
GameGenieTable.TryGetValue(code[2], out x);
|
|
result.Address |= (x & 0x07) << 4;
|
|
|
|
GameGenieTable.TryGetValue(code[3], out x);
|
|
result.Address |= (x & 0x07) << 12;
|
|
result.Address |= x & 0x08;
|
|
|
|
GameGenieTable.TryGetValue(code[4], out x);
|
|
result.Address |= x & 0x07;
|
|
result.Address |= (x & 0x08) << 8;
|
|
|
|
GameGenieTable.TryGetValue(code[5], out x);
|
|
result.Address |= (x & 0x07) << 8;
|
|
result.Compare |= x & 0x08;
|
|
|
|
GameGenieTable.TryGetValue(code[6], out x);
|
|
result.Compare |= x & 0x07;
|
|
result.Compare |= (x & 0x08) << 4;
|
|
|
|
GameGenieTable.TryGetValue(code[7], out x);
|
|
result.Compare |= (x & 0x07) << 4;
|
|
result.Value |= x & 0x08;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|