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 double word (32 bits) /// public sealed class DWordWatch : Watch { #region Fields private uint _value; private uint _previous; #endregion #region cTor(s) /// /// Inialize a new instance of /// /// 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 DWordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string note, uint value, uint previous, int changeCount) : base(domain, address, WatchSize.DWord, type, bigEndian, note) { if (value == 0) { _value = GetDWord(); } else { _value = value; } _previous = previous; _changecount = changeCount; } #endregion #region Methods /// /// Enumerate wich 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; yield return DisplayType.FixedPoint_20_12; yield return DisplayType.FixedPoint_16_16; yield return DisplayType.Float; } } #region Implements /// /// 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 = GetWord(); } /// /// Try to sets the value into the /// at the current address /// /// Value to set /// True if value successfully sets; othewise, false public override bool Poke(string value) { try { uint val = 0; switch (Type) { case DisplayType.Unsigned: if (value.IsUnsigned()) { val = (uint)int.Parse(value); } else { return false; } break; case DisplayType.Signed: if (value.IsSigned()) { val = (uint)int.Parse(value); } else { return false; } break; case DisplayType.Hex: if (value.IsHex()) { val = (uint)int.Parse(value, NumberStyles.HexNumber); } else { return false; } break; case DisplayType.FixedPoint_20_12: if (value.IsFixedPoint()) { val = (uint)(int)(double.Parse(value) * 4096.0); } else { return false; } break; case DisplayType.FixedPoint_16_16: if (value.IsFixedPoint()) { val = (uint)(int)(double.Parse(value) * 65536.0); } else { return false; } break; case DisplayType.Float: if (value.IsFloat()) { var bytes = BitConverter.GetBytes(float.Parse(value)); val = BitConverter.ToUInt32(bytes, 0); } 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((int)val); PokeDWord(val); return true; } } PokeDWord(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 = GetDWord(); if (_value != temp) { _previous = _value; _changecount++; } break; case PreviousType.LastFrame: _previous = _value; _value = GetDWord(); if (_value != Previous) { _changecount++; } break; } } #endregion Implements //TODO: Implements IFormattable public string FormatValue(uint val) { switch (Type) { default: case DisplayType.Unsigned: return val.ToString(); case DisplayType.Signed: return ((int)val).ToString(); case DisplayType.Hex: return val.ToHexString(8); case DisplayType.FixedPoint_20_12: return $"{val / 4096.0:0.######}"; case DisplayType.FixedPoint_16_16: return $"{val / 65536.0:0.######}"; case DisplayType.Float: var bytes = BitConverter.GetBytes(val); var _float = BitConverter.ToSingle(bytes, 0); //return string.Format("{0:0.######}", _float); return _float.ToString(); // adelikat: decided that we like sci notation instead of spooky rounding } } #endregion #region Properties #region Implements /// /// Get a string representation of difference /// between current value and the previous one /// public override string Diff => FormatValue(_previous - _value); /// /// Get the maximum possible value /// public override uint MaxValue => uint.MaxValue; /// /// Get the current value /// public override int Value => (int)GetDWord(); /// /// Gets the current value /// but with stuff I don't understand /// public override int ValueNoFreeze => (int)GetDWord(true); /// /// Get a string representation of the current value /// public override string ValueString => FormatValue(GetDWord()); /// /// Get the previous value /// public override int Previous => (int)_previous; /// /// Get a string representation of the previous value /// public override string PreviousStr => FormatValue(_previous); #endregion Implements #endregion } }