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);
}
}