using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using BizHawk.Common.NumberExtensions; using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { /// /// This class holds a byte (8 bits) /// public sealed class ByteWatch : Watch { private byte _previous; private byte _value; /// /// Initializes a new instance of the class. /// /// where you want to track /// The address you want to track /// How you you want to display the value See /// Specify the endianess. true for big endian /// A custom note about the /// Current value /// Previous value /// How many times value has changed /// Occurs when a is incompatible with internal ByteWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string note, byte value, byte previous, int changeCount) : base(domain, address, WatchSize.Byte, type, bigEndian, note) { _value = value == 0 ? GetByte() : value; _previous = previous; ChangeCount = changeCount; } /// /// Gets an enumeration of that are valid for a /// public static IEnumerable ValidTypes { get { yield return DisplayType.Unsigned; yield return DisplayType.Signed; yield return DisplayType.Hex; yield return DisplayType.Binary; } } /// /// Get a list a that can be used for this /// /// An enumeration that contains all valid public override IEnumerable AvailableTypes() { return ValidTypes; } /// /// Reset the previous value; set it to the current one /// public override void ResetPrevious() { _previous = GetByte(); } /// /// Try to sets the value into the /// at the current address /// /// Value to set /// True if value successfully sets; otherwise, false public override bool Poke(string value) { try { byte val = 0; switch (Type) { case DisplayType.Unsigned: if (value.IsUnsigned()) { val = (byte)int.Parse(value); } else { return false; } break; case DisplayType.Signed: if (value.IsSigned()) { val = (byte)(sbyte)int.Parse(value); } else { return false; } break; case DisplayType.Hex: if (value.IsHex()) { val = (byte)int.Parse(value, NumberStyles.HexNumber); } else { return false; } break; case DisplayType.Binary: if (value.IsBinary()) { val = (byte)Convert.ToInt32(value, 2); } else { return false; } break; } if (Global.CheatList.Contains(Domain, Address)) { var cheat = Global.CheatList.FirstOrDefault(c => c.Address == Address && c.Domain == Domain); if (cheat != (Cheat)null) { cheat.PokeValue(val); PokeByte(val); return true; } } PokeByte(val); return true; } catch { return false; } } /// /// Update the Watch (read it from /// public override void Update() { switch (Global.Config.RamWatchDefinePrevious) { case PreviousType.Original: return; case PreviousType.LastChange: var temp = _value; _value = GetByte(); if (_value != temp) { _previous = _value; ChangeCount++; } break; case PreviousType.LastFrame: _previous = _value; _value = GetByte(); if (_value != Previous) { ChangeCount++; } break; } } // TODO: Implements IFormattable public string FormatValue(byte val) { switch (Type) { default: case DisplayType.Unsigned: return val.ToString(); case DisplayType.Signed: return ((sbyte)val).ToString(); case DisplayType.Hex: return val.ToHexString(2); case DisplayType.Binary: return Convert.ToString(val, 2).PadLeft(8, '0').Insert(4, " "); } } /// /// Get a string representation of difference /// between current value and the previous one /// public override string Diff { get { string diff = ""; int diffVal = _value - _previous; if (diffVal > 0) { diff = "+"; } else if (diffVal < 0) { diff = "-"; } return $"{diff}{((byte)Math.Abs(diffVal))}"; } } /// /// Get the maximum possible value /// public override uint MaxValue => byte.MaxValue; /// /// Get the current value /// public override int Value => GetByte(); /// /// Gets the current value /// but with stuff I don't understand /// /// zero 15-nov-2015 - bypass LIAR LOGIC, see fdc9ea2aa922876d20ba897fb76909bf75fa6c92 https://github.com/TASVideos/BizHawk/issues/326 public override int ValueNoFreeze => GetByte(true); /// /// Get a string representation of the current value /// public override string ValueString => FormatValue(GetByte()); /// /// Get the previous value /// public override int Previous => _previous; /// /// Get a string representation of the previous value /// public override string PreviousStr => FormatValue(_previous); } }