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
{
2016-02-06 04:33:21 +00:00
public enum COMPARISONTYPE
{
2016-02-10 04:33:44 +00:00
NONE ,
EQUAL ,
2016-02-06 04:33:21 +00:00
GREATER_THAN ,
GREATER_THAN_OR_EQUAL ,
LESS_THAN ,
LESS_THAN_OR_EQUAL ,
NOT_EQUAL
} ;
2016-02-03 04:32:46 +00:00
2014-02-03 20:48:01 +00:00
private readonly Watch _watch ;
private int? _compare ;
private int _val ;
private bool _enabled ;
2016-02-06 03:33:31 +00:00
private COMPARISONTYPE _comparisonType ;
2016-02-03 04:32:46 +00:00
2013-10-25 00:59:34 +00:00
2016-02-10 04:33:44 +00:00
public Cheat ( Watch watch , int value , int? compare = null , bool enabled = true , COMPARISONTYPE comparisonType = COMPARISONTYPE . 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 ,
cheat . Name
2016-02-17 01:02:57 +00:00
) ;
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
2013-10-25 00:59:34 +00:00
public static Cheat Separator
{
get { return new Cheat ( SeparatorWatch . Instance , 0 , null , false ) ; }
}
public bool IsSeparator
{
get { return _watch . IsSeparator ; }
}
public bool Enabled
{
2013-11-28 22:06:38 +00:00
get { return ! IsSeparator & & _enabled ; }
2013-10-25 00:59:34 +00:00
}
2015-01-18 18:59:23 +00:00
public long? Address
2013-10-25 00:59:34 +00:00
{
get { return _watch . Address ; }
}
public int? Value
{
2014-01-01 03:19:08 +00:00
get { return IsSeparator ? ( int? ) null : _val ; }
2013-10-25 00:59:34 +00:00
}
public bool? BigEndian
{
2013-11-28 22:06:38 +00:00
get { return IsSeparator ? ( bool? ) null : _watch . BigEndian ; }
2013-10-25 00:59:34 +00:00
}
public int? Compare
{
2013-11-28 22:06:38 +00:00
get { return _compare . HasValue & & ! IsSeparator ? _compare : null ; }
2013-10-25 00:59:34 +00:00
}
public MemoryDomain Domain
{
get { return _watch . Domain ; }
}
2015-11-28 21:47:16 +00:00
public WatchSize Size
2013-10-25 00:59:34 +00:00
{
get { return _watch . Size ; }
}
public char SizeAsChar
{
get { return _watch . SizeAsChar ; }
}
2015-11-28 21:47:16 +00:00
public DisplayType Type
2013-10-25 00:59:34 +00:00
{
get { return _watch . Type ; }
}
public char TypeAsChar
{
get { return _watch . TypeAsChar ; }
}
public string Name
{
2014-02-03 20:48:01 +00:00
get { return IsSeparator ? string . Empty : _watch . Notes ; }
2013-10-25 00:59:34 +00:00
}
public string AddressStr
{
get { return _watch . AddressString ; }
}
public string ValueStr
{
2013-11-05 19:33:06 +00:00
get
{
switch ( _watch . Size )
{
default :
2015-11-28 21:47:16 +00:00
case WatchSize . Separator :
2014-02-03 20:48:01 +00:00
return string . Empty ;
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 :
2014-02-03 20:48:01 +00:00
return string . Empty ;
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
return string . Empty ;
2013-10-25 00:59:34 +00:00
}
}
2016-02-06 03:33:31 +00:00
public COMPARISONTYPE ComparisonType
{
get { return _comparisonType ; }
}
2014-03-01 16:30:06 +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-02-25 21:08:20 +00:00
case COMPARISONTYPE . 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
2016-02-17 01:02:57 +00:00
case COMPARISONTYPE . EQUAL :
2016-02-08 04:56:40 +00:00
if ( _compare . Value = = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
break ;
2016-02-17 01:02:57 +00:00
case COMPARISONTYPE . GREATER_THAN :
2016-02-08 04:56:40 +00:00
if ( _compare . Value > _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
break ;
2016-02-17 01:02:57 +00:00
case COMPARISONTYPE . GREATER_THAN_OR_EQUAL :
2016-02-08 04:56:40 +00:00
if ( _compare . Value > = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
break ;
2016-02-17 01:02:57 +00:00
case COMPARISONTYPE . LESS_THAN :
2016-02-08 04:56:40 +00:00
if ( _compare . Value < _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
break ;
2016-02-17 01:02:57 +00:00
case COMPARISONTYPE . LESS_THAN_OR_EQUAL :
2016-02-08 04:56:40 +00:00
if ( _compare . Value < = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
break ;
2016-02-17 01:02:57 +00:00
case COMPARISONTYPE . NOT_EQUAL :
2016-02-08 04:56:40 +00:00
if ( _compare . Value ! = _watch . ValueNoFreeze )
{
_watch . Poke ( GetStringForPulse ( _val ) ) ;
}
break ;
2016-02-08 05:40:14 +00:00
}
2013-10-25 00:59:34 +00:00
}
else
{
2014-08-02 01:54:07 +00:00
switch ( _watch . Size )
{
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 :
2015-12-01 21:16:28 +00:00
return ( addr = = _watch . Address ) | | ( addr = = ( _watch . Address ) + 1 ) ;
2015-11-28 21:47:16 +00:00
case WatchSize . DWord :
2015-12-01 21:16:28 +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 :
2015-12-01 21:16:28 +00:00
if ( addr = = ( _watch . Address ) )
2014-04-11 16:45:05 +00:00
{
return ( byte ) ( _val > > 8 ) ;
}
return ( byte ) ( _val & 0xFF ) ;
2015-11-28 21:47:16 +00:00
case WatchSize . DWord :
2015-12-01 21:16:28 +00:00
if ( addr = = ( _watch . Address ) )
2014-04-11 16:45:05 +00:00
{
return ( byte ) ( ( _val > > 24 ) & 0xFF ) ;
}
2015-12-01 21:16:28 +00:00
else if ( addr = = ( _watch . Address ) + 1 )
2014-04-11 16:45:05 +00:00
{
return ( byte ) ( ( _val > > 16 ) & 0xFF ) ;
}
2015-12-01 21:16:28 +00:00
else if ( addr = = ( ( _watch . Address ) ) + 2 )
2014-04-11 16:45:05 +00:00
{
return ( byte ) ( ( _val > > 8 ) & 0xFF ) ;
}
return ( byte ) ( _val & 0xFF ) ;
}
}
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 ( )
{
if ( Changed ! = null )
{
Changed ( this ) ;
}
}
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
}
}