2016-02-17 01:02:57 +00:00
using BizHawk.Emulation.Common ;
2013-10-25 00:59:34 +00:00
namespace BizHawk.Client.Common
{
public class Cheat
{
2017-05-18 20:16:02 +00:00
public enum CompareType
2016-02-06 04:33:21 +00:00
{
2017-05-18 20:16:02 +00:00
None ,
Equal ,
GreaterThan ,
GreaterThanOrEqual ,
LessThan ,
LessThanOrEqual ,
NotEqual
2017-05-09 18:19:55 +00:00
}
2016-02-03 04:32:46 +00:00
2014-02-03 20:48:01 +00:00
private readonly Watch _watch ;
2017-05-18 20:16:02 +00:00
private readonly CompareType _comparisonType ;
2014-02-03 20:48:01 +00:00
private int? _compare ;
private int _val ;
private bool _enabled ;
2013-10-25 00:59:34 +00:00
2017-05-18 20:16:02 +00:00
public Cheat ( Watch watch , int value , int? compare = null , bool enabled = true , CompareType comparisonType = CompareType . None )
2016-02-03 04:32:46 +00:00
{
_enabled = enabled ;
_watch = watch ;
_compare = compare ;
_val = value ;
_comparisonType = comparisonType ;
Pulse ( ) ;
}
2013-10-25 00:59:34 +00:00
public Cheat ( Cheat cheat )
{
if ( cheat . IsSeparator )
{
_enabled = false ;
_watch = SeparatorWatch . Instance ;
_compare = null ;
}
else
{
_enabled = cheat . Enabled ;
2013-11-28 22:06:38 +00:00
_watch = Watch . GenerateWatch (
cheat . Domain ,
2013-10-25 00:59:34 +00:00
cheat . Address ? ? 0 ,
cheat . Size ,
2016-02-17 01:02:57 +00:00
cheat . Type ,
2015-11-28 21:47:16 +00:00
cheat . BigEndian ? ? false ,
2017-04-10 15:29:51 +00:00
cheat . Name ) ;
2013-10-25 00:59:34 +00:00
_compare = cheat . Compare ;
_val = cheat . Value ? ? 0 ;
Pulse ( ) ;
}
}
2013-11-28 22:06:38 +00:00
public delegate void CheatEventHandler ( object sender ) ;
2014-02-03 20:48:01 +00:00
public event CheatEventHandler Changed ;
2013-11-28 22:06:38 +00:00
2017-04-10 15:29:51 +00:00
public static Cheat Separator = > new Cheat ( SeparatorWatch . Instance , 0 , null , false ) ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public bool IsSeparator = > _watch . IsSeparator ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public bool Enabled = > ! IsSeparator & & _enabled ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public long? Address = > _watch . Address ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public int? Value = > IsSeparator ? ( int? ) null : _val ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public bool? BigEndian = > IsSeparator ? ( bool? ) null : _watch . BigEndian ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public int? Compare = > _compare . HasValue & & ! IsSeparator ? _compare : null ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public MemoryDomain Domain = > _watch . Domain ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public WatchSize Size = > _watch . Size ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public char SizeAsChar = > _watch . SizeAsChar ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public DisplayType Type = > _watch . Type ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public char TypeAsChar = > _watch . TypeAsChar ;
2013-10-25 00:59:34 +00:00
2017-05-10 11:45:23 +00:00
public string Name = > IsSeparator ? "" : _watch . Notes ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public string AddressStr = > _watch . AddressString ;
2013-10-25 00:59:34 +00:00
2017-04-15 20:37:30 +00:00
public string ValueStr
2013-10-25 00:59:34 +00:00
{
2013-11-05 19:33:06 +00:00
get
{
switch ( _watch . Size )
{
default :
2015-11-28 21:47:16 +00:00
case WatchSize . Separator :
2017-05-10 11:45:23 +00:00
return "" ;
2015-11-28 21:47:16 +00:00
case WatchSize . Byte :
2013-11-05 19:33:06 +00:00
return ( _watch as ByteWatch ) . FormatValue ( ( byte ) _val ) ;
2015-11-28 21:47:16 +00:00
case WatchSize . Word :
2013-11-05 19:33:06 +00:00
return ( _watch as WordWatch ) . FormatValue ( ( ushort ) _val ) ;
2015-11-28 21:47:16 +00:00
case WatchSize . DWord :
2013-11-05 19:33:06 +00:00
return ( _watch as DWordWatch ) . FormatValue ( ( uint ) _val ) ;
}
}
2013-10-25 00:59:34 +00:00
}
public string CompareStr
{
get
{
if ( _compare . HasValue )
{
switch ( _watch . Size )
{
default :
2015-11-28 21:47:16 +00:00
case WatchSize . Separator :
2017-05-10 11:45:23 +00:00
return "" ;
2015-11-28 21:47:16 +00:00
case WatchSize . Byte :
2013-10-25 00:59:34 +00:00
return ( _watch as ByteWatch ) . FormatValue ( ( byte ) _compare . Value ) ;
2015-11-28 21:47:16 +00:00
case WatchSize . Word :
2013-10-25 00:59:34 +00:00
return ( _watch as WordWatch ) . FormatValue ( ( ushort ) _compare . Value ) ;
2015-11-28 21:47:16 +00:00
case WatchSize . DWord :
2013-10-25 00:59:34 +00:00
return ( _watch as DWordWatch ) . FormatValue ( ( uint ) _compare . Value ) ;
}
}
2014-02-03 20:48:01 +00:00
2017-05-10 11:45:23 +00:00
return "" ;
2013-10-25 00:59:34 +00:00
}
}
2017-05-18 20:16:02 +00:00
public CompareType ComparisonType = > _comparisonType ;
2016-02-06 03:33:31 +00:00
2017-04-15 20:37:30 +00:00
public void Enable ( bool handleChange = true )
2013-10-25 00:59:34 +00:00
{
if ( ! IsSeparator )
{
2013-11-28 22:06:38 +00:00
var wasEnabled = _enabled ;
2013-10-25 00:59:34 +00:00
_enabled = true ;
2014-03-01 16:30:06 +00:00
if ( ! wasEnabled & & handleChange )
2013-11-04 15:52:59 +00:00
{
Changes ( ) ;
}
2013-10-25 00:59:34 +00:00
}
}
2014-03-01 16:30:06 +00:00
public void Disable ( bool handleChange = true )
2013-10-25 00:59:34 +00:00
{
if ( ! IsSeparator )
{
2013-11-28 22:06:38 +00:00
var wasEnabled = _enabled ;
2013-10-25 00:59:34 +00:00
_enabled = false ;
2014-03-01 16:30:06 +00:00
if ( wasEnabled & & handleChange )
2013-11-04 15:52:59 +00:00
{
Changes ( ) ;
}
2013-10-25 00:59:34 +00:00
}
}
2014-03-01 16:30:06 +00:00
public void Toggle ( bool handleChange = true )
2013-10-25 00:59:34 +00:00
{
if ( ! IsSeparator )
{
_enabled ^ = true ;
2014-03-01 16:30:06 +00:00
if ( handleChange )
{
Changes ( ) ;
}
2013-10-25 00:59:34 +00:00
}
}
2014-02-22 23:59:52 +00:00
private string GetStringForPulse ( int val )
2014-02-05 20:05:44 +00:00
{
2015-11-28 21:47:16 +00:00
if ( _watch . Type = = DisplayType . Hex )
2014-02-22 23:59:52 +00:00
{
2014-02-05 20:05:44 +00:00
return val . ToString ( "X8" ) ;
2014-02-22 23:59:52 +00:00
}
return val . ToString ( ) ;
2014-02-05 20:05:44 +00:00
}
2013-10-25 00:59:34 +00:00
public void Pulse ( )
{
if ( ! IsSeparator & & _enabled )
{
if ( _compare . HasValue )
{
2016-02-08 04:56:40 +00:00
switch ( _comparisonType )
2013-10-25 00:59:34 +00:00
{
2016-02-17 01:02:57 +00:00
default :
2017-05-18 20:16:02 +00:00
case CompareType . None : // This should never happen, but it's here just in case. adelikat: And yet it does! Cheat Code converter doesn't do this. Changing this to default to equal since 99.9999% of all cheats are going to be equals
case CompareType . Equal :
2016-02-08 04:56:40 +00:00
if ( _compare . Value = = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
2017-05-17 18:18:26 +00:00
2016-02-08 04:56:40 +00:00
break ;
2017-05-18 20:16:02 +00:00
case CompareType . GreaterThan :
2016-02-08 04:56:40 +00:00
if ( _compare . Value > _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
2017-05-17 18:18:26 +00:00
2016-02-08 04:56:40 +00:00
break ;
2017-05-18 20:16:02 +00:00
case CompareType . GreaterThanOrEqual :
2016-02-08 04:56:40 +00:00
if ( _compare . Value > = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
2017-05-17 18:18:26 +00:00
2016-02-08 04:56:40 +00:00
break ;
2017-05-18 20:16:02 +00:00
case CompareType . LessThan :
2016-02-08 04:56:40 +00:00
if ( _compare . Value < _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
2017-05-17 18:18:26 +00:00
2016-02-08 04:56:40 +00:00
break ;
2017-05-18 20:16:02 +00:00
case CompareType . LessThanOrEqual :
2016-02-08 04:56:40 +00:00
if ( _compare . Value < = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
2017-05-17 18:18:26 +00:00
2016-02-08 04:56:40 +00:00
break ;
2017-05-18 20:16:02 +00:00
case CompareType . NotEqual :
2016-02-08 04:56:40 +00:00
if ( _compare . Value ! = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
2017-05-17 18:18:26 +00:00
2016-02-08 04:56:40 +00:00
break ;
2017-05-17 18:18:26 +00:00
}
2013-10-25 00:59:34 +00:00
}
else
{
2017-04-10 15:29:51 +00:00
switch ( _watch . Size )
2014-08-02 01:54:07 +00:00
{
2015-11-28 21:47:16 +00:00
case WatchSize . Byte :
2014-08-02 01:54:07 +00:00
_watch . Poke ( ( _watch as ByteWatch ) . FormatValue ( ( byte ) _val ) ) ;
break ;
2015-11-28 21:47:16 +00:00
case WatchSize . Word :
2014-08-02 01:54:07 +00:00
_watch . Poke ( ( _watch as WordWatch ) . FormatValue ( ( ushort ) _val ) ) ;
break ;
2015-11-28 21:47:16 +00:00
case WatchSize . DWord :
2014-08-02 01:54:07 +00:00
_watch . Poke ( ( _watch as DWordWatch ) . FormatValue ( ( uint ) _val ) ) ;
break ;
}
2013-10-25 00:59:34 +00:00
}
}
}
2015-01-18 18:59:23 +00:00
public bool Contains ( long addr )
2013-10-25 00:59:34 +00:00
{
switch ( _watch . Size )
{
default :
2015-11-28 21:47:16 +00:00
case WatchSize . Separator :
2013-10-25 00:59:34 +00:00
return false ;
2015-11-28 21:47:16 +00:00
case WatchSize . Byte :
2015-12-01 21:16:28 +00:00
return _watch . Address = = addr ;
2015-11-28 21:47:16 +00:00
case WatchSize . Word :
2017-04-10 15:29:51 +00:00
return ( addr = = _watch . Address ) | | ( addr = = _watch . Address + 1 ) ;
2015-11-28 21:47:16 +00:00
case WatchSize . DWord :
2017-04-10 15:29:51 +00:00
return ( addr = = _watch . Address ) | | ( addr = = _watch . Address + 1 ) | |
( addr = = _watch . Address + 2 ) | | ( addr = = _watch . Address + 3 ) ;
2013-10-25 00:59:34 +00:00
}
}
2015-01-18 18:59:23 +00:00
public byte? GetByteVal ( long addr )
2014-04-11 16:45:05 +00:00
{
if ( ! Contains ( addr ) )
{
return null ;
}
switch ( _watch . Size )
{
default :
2015-11-28 21:47:16 +00:00
case WatchSize . Separator :
case WatchSize . Byte :
2014-04-11 16:45:05 +00:00
return ( byte? ) _val ;
2015-11-28 21:47:16 +00:00
case WatchSize . Word :
2017-10-19 13:48:27 +00:00
if ( _watch . BigEndian )
2014-04-11 16:45:05 +00:00
{
2017-10-19 13:48:27 +00:00
if ( addr = = _watch . Address )
{
2017-11-21 14:58:16 +00:00
return ( byte ) ( _val > > 8 ) ;
2017-10-19 13:48:27 +00:00
}
2017-11-21 14:58:16 +00:00
return ( byte ) ( _val & 0xFF ) ;
2014-04-11 16:45:05 +00:00
}
2017-10-19 13:48:27 +00:00
else
2014-04-11 16:45:05 +00:00
{
2017-10-19 13:48:27 +00:00
if ( addr = = _watch . Address )
{
2017-11-21 14:58:16 +00:00
return ( byte ) ( _val & 0xFF ) ;
2017-10-19 13:48:27 +00:00
}
2017-11-21 14:58:16 +00:00
return ( byte ) ( _val > > 8 ) ;
2014-04-11 16:45:05 +00:00
}
2017-10-19 13:48:27 +00:00
case WatchSize . DWord :
if ( _watch . BigEndian )
2014-04-11 16:45:05 +00:00
{
2017-10-19 13:48:27 +00:00
if ( addr = = _watch . Address )
{
return ( byte ) ( ( _val > > 24 ) & 0xFF ) ;
}
if ( addr = = _watch . Address + 1 )
{
return ( byte ) ( ( _val > > 16 ) & 0xFF ) ;
}
if ( addr = = _watch . Address + 2 )
{
return ( byte ) ( ( _val > > 8 ) & 0xFF ) ;
}
return ( byte ) ( _val & 0xFF ) ;
2014-04-11 16:45:05 +00:00
}
2017-10-19 13:48:27 +00:00
else
2014-04-11 16:45:05 +00:00
{
2017-10-19 13:48:27 +00:00
if ( addr = = _watch . Address )
{
return ( byte ) ( _val & 0xFF ) ;
}
if ( addr = = _watch . Address + 1 )
{
return ( byte ) ( ( _val > > 8 ) & 0xFF ) ;
}
if ( addr = = _watch . Address + 2 )
{
return ( byte ) ( ( _val > > 16 ) & 0xFF ) ;
}
2014-04-11 16:45:05 +00:00
2017-10-19 13:48:27 +00:00
return ( byte ) ( ( _val > > 24 ) & 0xFF ) ;
}
2014-04-11 16:45:05 +00:00
}
}
2014-09-27 21:52:15 +00:00
public void PokeValue ( int val )
{
if ( ! IsSeparator )
{
_val = val ;
}
}
2013-10-25 00:59:34 +00:00
public void Increment ( )
{
if ( ! IsSeparator )
{
_val + + ;
2014-08-16 14:44:40 +00:00
if ( _val > _watch . MaxValue )
{
_val = 0 ;
}
2013-10-25 00:59:34 +00:00
Pulse ( ) ;
2013-11-04 15:52:59 +00:00
Changes ( ) ;
2013-10-25 00:59:34 +00:00
}
}
public void Decrement ( )
{
if ( ! IsSeparator )
{
_val - - ;
2014-08-16 14:44:40 +00:00
if ( ( uint ) _val > _watch . MaxValue )
{
_val = ( int ) _watch . MaxValue ;
}
2013-10-25 00:59:34 +00:00
Pulse ( ) ;
2013-11-04 15:52:59 +00:00
Changes ( ) ;
2013-10-25 00:59:34 +00:00
}
}
2015-11-28 21:47:16 +00:00
public void SetType ( DisplayType type )
{
if ( _watch . IsDiplayTypeAvailable ( type ) )
2013-10-25 00:59:34 +00:00
{
_watch . Type = type ;
2013-11-04 15:52:59 +00:00
Changes ( ) ;
2013-10-25 00:59:34 +00:00
}
}
2014-02-03 20:48:01 +00:00
private void Changes ( )
{
2017-04-15 20:37:30 +00:00
Changed ? . Invoke ( this ) ;
2014-02-03 20:48:01 +00:00
}
2014-03-01 16:30:06 +00:00
public override bool Equals ( object obj )
{
if ( obj is Watch )
{
var watch = obj as Watch ;
2016-02-17 01:02:57 +00:00
return Domain = = watch . Domain & & Address = = watch . Address ;
2014-03-01 16:30:06 +00:00
}
if ( obj is Cheat )
{
var cheat = obj as Cheat ;
2016-02-17 01:02:57 +00:00
return Domain = = cheat . Domain & & Address = = cheat . Address ;
2014-03-01 16:30:06 +00:00
}
return base . Equals ( obj ) ;
}
public override int GetHashCode ( )
{
2016-02-17 01:02:57 +00:00
return Domain . GetHashCode ( ) + ( int ) ( Address ? ? 0 ) ;
2014-03-01 16:30:06 +00:00
}
public static bool operator = = ( Cheat a , Cheat b )
{
// If one is null, but not both, return false.
if ( ( ( object ) a = = null ) | | ( ( object ) b = = null ) )
{
return false ;
}
return a . Domain = = b . Domain & & a . Address = = b . Address ;
}
public static bool operator ! = ( Cheat a , Cheat b )
{
return ! ( a = = b ) ;
}
public static bool operator = = ( Cheat a , Watch b )
{
// If one is null, but not both, return false.
if ( ( ( object ) a = = null ) | | ( ( object ) b = = null ) )
{
return false ;
}
return a . Domain = = b . Domain & & a . Address = = b . Address ;
}
public static bool operator ! = ( Cheat a , Watch b )
{
return ! ( a = = b ) ;
}
2013-10-25 00:59:34 +00:00
}
}