using System; using System.Collections.Generic; namespace BizHawk.Client.Common.cheats { public static class NesGameGenieDecoder { private static readonly Dictionary GameGenieTable = new Dictionary { ['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; } } }