diff --git a/BizHawk.Client.Common/cheats/IDecodeResult.cs b/BizHawk.Client.Common/cheats/IDecodeResult.cs new file mode 100644 index 0000000000..ee195b4202 --- /dev/null +++ b/BizHawk.Client.Common/cheats/IDecodeResult.cs @@ -0,0 +1,51 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common.cheats +{ + /// + /// Represents a decoded cheat value + /// + public interface IDecodeResult + { + int Address { get; } + int Value { get; } + int? Compare { get; } + WatchSize Size { get; } + bool IsValid { get; } + } + + public class DecodeResult : IDecodeResult + { + public int Address { get; internal set; } + public int Value { get; internal set; } + public int? Compare { get; internal set; } + public WatchSize Size { get; internal set; } + public bool IsValid => true; + } + + public class InvalidResult : IDecodeResult + { + public int Address => int.MaxValue; + public int Value => int.MaxValue; + public int? Compare => null; + public WatchSize Size => WatchSize.Separator; + public bool IsValid => false; + } + + public static class DecodeResultExtensions + { + public static Cheat ToCheat(this IDecodeResult result, MemoryDomain domain, string description) + { + var watch = Watch.GenerateWatch( + domain, + result.Address, + result.Size, + DisplayType.Hex, + domain.EndianType == MemoryDomain.Endian.Big, + description); + return result.Compare.HasValue + ? new Cheat(watch, result.Value, result.Compare.Value, true, Cheat.CompareType.Equal) + : new Cheat(watch, result.Value); + } + } +} diff --git a/BizHawk.Client.Common/cheats/NesGameGenieDecoder.cs b/BizHawk.Client.Common/cheats/NesGameGenieDecoder.cs index 24c38cf31d..e65686ed08 100644 --- a/BizHawk.Client.Common/cheats/NesGameGenieDecoder.cs +++ b/BizHawk.Client.Common/cheats/NesGameGenieDecoder.cs @@ -1,12 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace BizHawk.Client.Common.cheats { - public class NesGameGenieDecoder + public static class NesGameGenieDecoder { - private readonly string _code; - - private readonly Dictionary _gameGenieTable = new Dictionary + private static readonly Dictionary GameGenieTable = new Dictionary { ['A'] = 0, // 0000 ['P'] = 1, // 0001 @@ -26,90 +25,93 @@ namespace BizHawk.Client.Common.cheats ['N'] = 15 // 1111 }; - public NesGameGenieDecoder(string code) + public static IDecodeResult Decode(string code) { - _code = code; - Decode(); - } + if (code == null) + { + throw new ArgumentNullException(nameof(code)); + } - public int Address { get; private set; } - public int Value { get; private set; } - public int? Compare { get; private set; } + if (code.Length != 6 && code.Length != 8) + { + return new InvalidResult(); + } - public void Decode() - { + var result = new DecodeResult { Size = WatchSize.Byte }; // char 3 bit 3 denotes the code length. - if (_code.Length == 6) + 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| - Value = 0; - Address = 0x8000; + result.Value = 0; + result.Address = 0x8000; - _gameGenieTable.TryGetValue(_code[0], out var x); - Value |= x & 0x07; - Value |= (x & 0x08) << 4; + GameGenieTable.TryGetValue(code[0], out var x); + result.Value |= x & 0x07; + result.Value |= (x & 0x08) << 4; - _gameGenieTable.TryGetValue(_code[1], out x); - Value |= (x & 0x07) << 4; - Address |= (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); - Address |= (x & 0x07) << 4; + GameGenieTable.TryGetValue(code[2], out x); + result.Address |= (x & 0x07) << 4; - _gameGenieTable.TryGetValue(_code[3], out x); - Address |= (x & 0x07) << 12; - Address |= x & 0x08; + GameGenieTable.TryGetValue(code[3], out x); + result.Address |= (x & 0x07) << 12; + result.Address |= x & 0x08; - _gameGenieTable.TryGetValue(_code[4], out x); - Address |= x & 0x07; - Address |= (x & 0x08) << 8; + GameGenieTable.TryGetValue(code[4], out x); + result.Address |= x & 0x07; + result.Address |= (x & 0x08) << 8; - _gameGenieTable.TryGetValue(_code[5], out x); - Address |= (x & 0x07) << 8; - Value |= x & 0x08; + GameGenieTable.TryGetValue(code[5], out x); + result.Address |= (x & 0x07) << 8; + result.Value |= x & 0x08; } - else if (_code.Length == 8) + 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|@|#|$| - Value = 0; - Address = 0x8000; - Compare = 0; + result.Value = 0; + result.Address = 0x8000; + result.Compare = 0; - _gameGenieTable.TryGetValue(_code[0], out var x); - Value |= x & 0x07; - Value |= (x & 0x08) << 4; + GameGenieTable.TryGetValue(code[0], out var x); + result.Value |= x & 0x07; + result.Value |= (x & 0x08) << 4; - _gameGenieTable.TryGetValue(_code[1], out x); - Value |= (x & 0x07) << 4; - Address |= (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); - Address |= (x & 0x07) << 4; + GameGenieTable.TryGetValue(code[2], out x); + result.Address |= (x & 0x07) << 4; - _gameGenieTable.TryGetValue(_code[3], out x); - Address |= (x & 0x07) << 12; - Address |= x & 0x08; + GameGenieTable.TryGetValue(code[3], out x); + result.Address |= (x & 0x07) << 12; + result.Address |= x & 0x08; - _gameGenieTable.TryGetValue(_code[4], out x); - Address |= x & 0x07; - Address |= (x & 0x08) << 8; + GameGenieTable.TryGetValue(code[4], out x); + result.Address |= x & 0x07; + result.Address |= (x & 0x08) << 8; - _gameGenieTable.TryGetValue(_code[5], out x); - Address |= (x & 0x07) << 8; - Compare |= x & 0x08; + GameGenieTable.TryGetValue(code[5], out x); + result.Address |= (x & 0x07) << 8; + result.Compare |= x & 0x08; - _gameGenieTable.TryGetValue(_code[6], out x); - Compare |= x & 0x07; - Compare |= (x & 0x08) << 4; + GameGenieTable.TryGetValue(code[6], out x); + result.Compare |= x & 0x07; + result.Compare |= (x & 0x08) << 4; - _gameGenieTable.TryGetValue(_code[7], out x); - Compare |= (x & 0x07) << 4; - Value |= x & 0x08; + GameGenieTable.TryGetValue(code[7], out x); + result.Compare |= (x & 0x07) << 4; + result.Value |= x & 0x08; } + + return result; } } } diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.NES.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.NES.cs index cb2e19a97f..c5998bfa2f 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.NES.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.NES.cs @@ -45,19 +45,11 @@ namespace BizHawk.Client.Common { if (NESAvailable && MemoryDomains != null) { - var decoder = new NesGameGenieDecoder(code); - var watch = Watch.GenerateWatch( - MemoryDomains["System Bus"], - decoder.Address, - WatchSize.Byte, - DisplayType.Hex, - false, - code); - - Global.CheatList.Add(new Cheat( - watch, - decoder.Value, - decoder.Compare)); + var result = NesGameGenieDecoder.Decode(code); + if (result.IsValid) + { + Global.CheatList.Add(result.ToCheat(MemoryDomains.SystemBus, "")); + } } } @@ -127,9 +119,12 @@ namespace BizHawk.Client.Common { if (NESAvailable) { - var decoder = new NesGameGenieDecoder(code); - Global.CheatList.RemoveRange( - Global.CheatList.Where(c => c.Address == decoder.Address)); + var decoder = NesGameGenieDecoder.Decode(code); + if (decoder.IsValid) + { + Global.CheatList.RemoveRange( + Global.CheatList.Where(c => c.Address == decoder.Address)); + } } } diff --git a/BizHawk.Client.EmuHawk/tools/GameShark.cs b/BizHawk.Client.EmuHawk/tools/GameShark.cs index c074d8f587..c835b4c193 100644 --- a/BizHawk.Client.EmuHawk/tools/GameShark.cs +++ b/BizHawk.Client.EmuHawk/tools/GameShark.cs @@ -277,21 +277,23 @@ namespace BizHawk.Client.EmuHawk Global.CheatList.Add(new Cheat(watch, decoder.Value)); } - private void Nes(string cheat) + private void Nes(string code) { - if (cheat.Length != 6 && cheat.Length != 8) + if (code.Length != 6 && code.Length != 8) { InputError("Game Genie codes need to be six or eight characters in length."); } - var description = Description(cheat); - var decoder = new NesGameGenieDecoder(cheat); - - var watch = Watch.GenerateWatch(MemoryDomains["System Bus"], decoder.Address, WatchSize.Byte, Common.DisplayType.Hex, false, description); - Global.CheatList.Add( - decoder.Compare.HasValue - ? new Cheat(watch, decoder.Value, decoder.Compare.Value, true, Cheat.CompareType.Equal) - : new Cheat(watch, decoder.Value)); + var description = Description(code); + var result = NesGameGenieDecoder.Decode(code); + if (result.IsValid) + { + Global.CheatList.Add(result.ToCheat(MemoryDomains.SystemBus, description)); + } + else + { + InputError("Invalid Game Genie code"); + } } private void Psx(string cheat)