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)