/****************************************************************************
File    : CheatServer.cpp
/*
@(#) #SY# Atari800Win PLus
@(#) #IS# CCheatServer implementation file
@(#) #BY# Tomasz Szymankowski
@(#) #LM# 21.03.2002
*/

#include "StdAfx.h"
#include "CheatServer.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define MAX_ITEM_LENGTH		16
#define LOCK_MASK			0x80000000
#define ADDR_MASK			0x7fffffff


/////////////////////////////////////////////////////////////////////////////
// CCheatServer class

/*========================================================
Method   : CCheatServer::CCheatServer
=========================================================*/
/* #FN#
   Standard constructor */
CCheatServer::
CCheatServer()
	: m_pMemory   ( NULL ),
	  m_dwSize    ( 0 ),
	  m_nMemoCount( 0 ),
	  m_nAddrCount( 0 ),
	  m_nLockCount( 0 )
{
} /* #OF# CCheatServer::CCheatServer */

/*========================================================
Method   : CCheatServer::CCheatServer
=========================================================*/
/* #FN#
   Copy constructor */
CCheatServer::
CCheatServer(
	CCheatServer& refCheatServer /* #IN# Reference to a source object */
)
	: m_pMemory   ( refCheatServer.m_pMemory ),
	  m_dwSize    ( refCheatServer.m_dwSize ),
	  m_nMemoCount( refCheatServer.m_nMemoCount ),
	  m_nAddrCount( refCheatServer.m_nAddrCount ),
	  m_nLockCount( refCheatServer.m_nLockCount )
{
	CopyAddressList( &m_listMemo, &refCheatServer.m_listMemo );
	CopyAddressList( &m_listAddr, &refCheatServer.m_listAddr );
} /* #OF# CCheatServer::CCheatServer */

/*========================================================
Method   : CCheatServer::~CCheatServer
=========================================================*/
/* #FN#
   Destructor */
CCheatServer::
~CCheatServer()
{
	ResetState();
} /* #OF# CCheatServer::~CCheatServer */


/////////////////////////////////////////////////////////////////////////////
// CCheatServer implementation

/*========================================================
Method   : CCheatServer::operator=
=========================================================*/
/* #FN#
   Overloads the operator= */
CCheatServer&
/* #AS#
   Reference to the target object */
CCheatServer::
operator=(
	CCheatServer& refCheatServer /* #IN# Reference to a source object */
)
{
	m_pMemory    = refCheatServer.m_pMemory;
	m_dwSize     = refCheatServer.m_dwSize;
	m_nMemoCount = refCheatServer.m_nMemoCount;
	m_nAddrCount = refCheatServer.m_nAddrCount;
	m_nLockCount = refCheatServer.m_nLockCount;

	CopyAddressList( &m_listMemo, &refCheatServer.m_listMemo );
	CopyAddressList( &m_listAddr, &refCheatServer.m_listAddr );

	return *this;
} /* #OF# CCheatServer::operator= */

/*========================================================
Method   : CCheatServer::CopyAddressList
=========================================================*/
/* #FN#
   Copies one address list to another */
void
/* #AS#
   Nothing */
CCheatServer::
CopyAddressList(
	CAddressList *pTargetList, /* #OUT# Destination list of addresses */
	const CAddressList *pSourceList /* #IN# Source list of addresses */
)
{
	if( pTargetList != pSourceList )
	{
		POSITION pos = pSourceList->GetHeadPosition();
		pTargetList->RemoveAll();

		while( pos )
			pTargetList->AddTail( pSourceList->GetNext( pos ) );
	}
} /* #OF# CCheatServer::CopyAddressList */

/*========================================================
Method   : CCheatServer::ResetState
=========================================================*/
/* #FN#
   Resets state of the object */
void
/* #AS#
   Nothing */
CCheatServer::
ResetState()
{
	m_pMemory    = NULL;
	m_dwSize     = 0;
	m_nMemoCount = 0;
	m_nAddrCount = 0;
	m_nLockCount = 0;

	m_listMemo.RemoveAll();
	m_listAddr.RemoveAll();
} /* #OF# CCheatServer::ResetState */

/*========================================================
Method   : CCheatServer::ShotMemo
=========================================================*/
/* #FN#
   Finds out memory addresses that contain a given value */
int
/* #AS#
   Number of found memory addresses */
CCheatServer::
ShotMemo(
	const UBYTE  nMatch,
	const UBYTE *pMemory,
	const DWORD  dwSize
)
{
	m_nMemoCount = 0;
	m_listMemo.RemoveAll();

	if( pMemory )
	{
		m_pMemory = (UBYTE *)pMemory;
		m_dwSize  = dwSize;

		for( DWORD dwAddr = 0; dwAddr < dwSize; dwAddr++ )
		{
			if( nMatch == pMemory[ dwAddr ] )
			{
				m_listMemo.AddTail( dwAddr );
				m_nMemoCount++;
			}
		}
	}
	return m_nMemoCount;
} /* #OF# CCheatServer::ShotMemo */

/*========================================================
Method   : CCheatServer::ShotAddr
=========================================================*/
/* #FN#
   Finds out memory addresses with changed value */
int
/* #AS#
   Number of found memory addresses */
CCheatServer::
ShotAddr(
	const UBYTE nMatch
)
{
	POSITION pos = m_listMemo.GetHeadPosition();
	DWORD dwAddr = 0;

	m_nAddrCount = m_nLockCount = 0;
	m_listAddr.RemoveAll();

	while( pos )
	{
		dwAddr = m_listMemo.GetNext( pos );

		if( dwAddr < m_dwSize && nMatch == m_pMemory[ dwAddr ] )
		{
			m_listAddr.AddTail( dwAddr );
			m_nAddrCount++;
		}
	}
	return m_nAddrCount;
} /* #OF# CCheatServer::ShotAddr */

/*========================================================
Method   : CCheatServer::ListToCtrl
=========================================================*/
/* #FN#
   Polulates a list control basing on state of the object */
int
/* #AS#
   Number of inserted items */
CCheatServer::
ListToCtrl(
	CListCtrl *pList
)
{
	int nCount = 0;
	if( pList )
	{
		POSITION pos = m_listAddr.GetHeadPosition();
		DWORD  dwAddr = 0;
		char   szAddr[ MAX_ITEM_LENGTH ];

		LVITEM itemAddr;
		ZeroMemory( &itemAddr, sizeof(LVITEM) );

		pList->DeleteAllItems();

		while( pos )
		{
			dwAddr = m_listAddr.GetNext( pos );
			sprintf( szAddr, "$%.4X (%.5ld)", dwAddr & ADDR_MASK, dwAddr & ADDR_MASK );

			itemAddr.mask    = LVIF_TEXT | LVIF_PARAM;
			itemAddr.iItem   = nCount;
			itemAddr.pszText = (LPTSTR)szAddr;
			itemAddr.lParam  = dwAddr;

			pList->InsertItem( &itemAddr );

			if( dwAddr & LOCK_MASK )
				pList->SetCheck( nCount );

			nCount++;
		}
	}
	TRACE1("CCheatServer::ListToCtrl: %d items\n", nCount);
	return nCount;
} /* #OF# CCheatServer::ListToCtrl */

/*========================================================
Method   : CCheatServer::CtrlToList
=========================================================*/
/* #FN#
   Updates a state of the object basing on a list control */
int
/* #AS#
   Number of updated items */
CCheatServer::
CtrlToList(
	CListCtrl *pList
)
{
	int nCount = 0;

	m_nLockCount = 0;
	if( pList )
	{
		POSITION pos = m_listAddr.GetHeadPosition();
		DWORD dwAddr = 0;

		while( pos )
		{
			dwAddr = pList->GetItemData( nCount );

			if( dwAddr == m_listAddr.GetAt( pos ) )
			{
				if( pList->GetCheck( nCount ) )
				{
					m_listAddr.SetAt( pos, dwAddr |= LOCK_MASK );
					m_nLockCount++;
				}
				else
					m_listAddr.SetAt( pos, dwAddr &= ADDR_MASK );

				nCount++;
			}
			m_listAddr.GetNext( pos );
		}
	}
	return nCount;
} /* #OF# CCheatServer::CtrlToList */

/*========================================================
Method   : CCheatServer::Frame
=========================================================*/
/* #FN#
   Updates memory registers basing on a state of the object */
void
/* #AS#
   Nothing */
CCheatServer::
Frame()
{
	if( m_nLockCount > 0 )
	{
		POSITION pos = m_listAddr.GetHeadPosition();
		DWORD dwAddr = 0;

		while( pos )
		{
			dwAddr = m_listAddr.GetNext( pos );
			if( dwAddr & LOCK_MASK )
				m_pMemory[ dwAddr & ADDR_MASK ] = (UBYTE)g_Misc.Cheat.nLock;
		}
	}
} /* #OF# CCheatServer::Frame */
