www.pudn.com > Nestopia137src.zip > NstApiCheats.cpp


//////////////////////////////////////////////////////////////////////////////////////// 
// 
// Nestopia - NES/Famicom emulator written in C++ 
// 
// Copyright (C) 2003-2007 Martin Freij 
// 
// This file is part of Nestopia. 
// 
// Nestopia is free software; you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation; either version 2 of the License, or 
// (at your option) any later version. 
// 
// Nestopia is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
// 
// You should have received a copy of the GNU General Public License 
// along with Nestopia; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
// 
//////////////////////////////////////////////////////////////////////////////////////// 
 
#include  
#include "../NstMachine.hpp" 
#include "../NstCheats.hpp" 
#include "NstApiCheats.hpp" 
#include "NstApiMachine.hpp" 
 
namespace Nes 
{ 
	namespace Api 
	{ 
		#ifdef NST_MSVC_OPTIMIZE 
		#pragma optimize("s", on) 
		#endif 
 
		Result NST_CALL Cheats::GameGenieEncode(const Code& code,char (&characters)[9]) throw() 
		{ 
			if (code.address < 0x8000) 
				return RESULT_ERR_INVALID_PARAM; 
 
			const byte codes[8] = 
			{ 
				(code.value   >>  0 & 0x7U) | (code.value   >> 4 & 0x8U), 
				(code.value   >>  4 & 0x7U) | (code.address >> 4 & 0x8U), 
				(code.address >>  4 & 0x7U) | (code.useCompare   ? 0x8U : 0x0U), 
				(code.address >> 12 & 0x7U) | (code.address >> 0 & 0x8U), 
				(code.address >>  0 & 0x7U) | (code.address >> 8 & 0x8U), 
				(code.address >>  8 & 0x7U) | ((code.useCompare ? code.compare : code.value) & 0x8U), 
				(code.useCompare ? ((code.compare >> 0 & 0x7U) | (code.compare >> 4 & 0x8U)) : 0), 
				(code.useCompare ? ((code.compare >> 4 & 0x7U) | (code.value   >> 0 & 0x8U)) : 0) 
			}; 
 
			uint i = (code.useCompare ? 8 : 6); 
 
			characters[i--] = '\0'; 
 
			do 
			{ 
				static const char lut[] = 
				{ 
					'A','P','Z','L','G','I','T','Y', 
					'E','O','X','U','K','S','V','N' 
				}; 
 
				characters[i] = lut[codes[i]]; 
			} 
			while (i--); 
 
			return RESULT_OK; 
		} 
 
		Result NST_CALL Cheats::GameGenieDecode(const char* const characters,Code& code) throw() 
		{ 
			if (characters == NULL) 
				return RESULT_ERR_INVALID_PARAM; 
 
			byte codes[8]; 
 
			uint length = 6; 
 
			for (uint i=0; i < length; ++i) 
			{ 
				switch (characters[i]) 
				{ 
					case 'A': case 'a': codes[i] = 0x0; break; 
					case 'P': case 'p': codes[i] = 0x1; break; 
					case 'Z': case 'z': codes[i] = 0x2; break; 
					case 'L': case 'l': codes[i] = 0x3; break; 
					case 'G': case 'g': codes[i] = 0x4; break; 
					case 'I': case 'i': codes[i] = 0x5; break; 
					case 'T': case 't': codes[i] = 0x6; break; 
					case 'Y': case 'y': codes[i] = 0x7; break; 
					case 'E': case 'e': codes[i] = 0x8; break; 
					case 'O': case 'o': codes[i] = 0x9; break; 
					case 'X': case 'x': codes[i] = 0xA; break; 
					case 'U': case 'u': codes[i] = 0xB; break; 
					case 'K': case 'k': codes[i] = 0xC; break; 
					case 'S': case 's': codes[i] = 0xD; break; 
					case 'V': case 'v': codes[i] = 0xE; break; 
					case 'N': case 'n': codes[i] = 0xF; break; 
 
					default: return RESULT_ERR_INVALID_PARAM; 
				} 
 
				if (i == 2 && codes[2] & 0x8U) 
					length = 8; 
			} 
 
			code.address = 0x8000 | 
			( 
				( codes[4] & 0x1U ) << 0x0 | 
				( codes[4] & 0x2U ) << 0x0 | 
				( codes[4] & 0x4U ) << 0x0 | 
				( codes[3] & 0x8U ) << 0x0 | 
				( codes[2] & 0x1U ) << 0x4 | 
				( codes[2] & 0x2U ) << 0x4 | 
				( codes[2] & 0x4U ) << 0x4 | 
				( codes[1] & 0x8U ) << 0x4 | 
				( codes[5] & 0x1U ) << 0x8 | 
				( codes[5] & 0x2U ) << 0x8 | 
				( codes[5] & 0x4U ) << 0x8 | 
				( codes[4] & 0x8U ) << 0x8 | 
				( codes[3] & 0x1U ) << 0xC | 
				( codes[3] & 0x2U ) << 0xC | 
				( codes[3] & 0x4U ) << 0xC 
			); 
 
			code.value = 
			( 
				( codes[0] & 0x1U ) << 0x0 | 
				( codes[0] & 0x2U ) << 0x0 | 
				( codes[0] & 0x4U ) << 0x0 | 
				( codes[1] & 0x1U ) << 0x4 | 
				( codes[1] & 0x2U ) << 0x4 | 
				( codes[1] & 0x4U ) << 0x4 | 
				( codes[0] & 0x8U ) << 0x4 
			); 
 
			if (length == 8) 
			{ 
				code.useCompare = true; 
				code.value |= codes[7] & 0x8U; 
				code.compare = 
				( 
					( codes[6] & 0x1U ) << 0x0 | 
					( codes[6] & 0x2U ) << 0x0 | 
					( codes[6] & 0x4U ) << 0x0 | 
					( codes[5] & 0x8U ) << 0x0 | 
					( codes[7] & 0x1U ) << 0x4 | 
					( codes[7] & 0x2U ) << 0x4 | 
					( codes[7] & 0x4U ) << 0x4 | 
					( codes[6] & 0x8U ) << 0x4 
				); 
			} 
			else 
			{ 
				code.useCompare = false; 
				code.value |= codes[5] & 0x8U; 
				code.compare = 0x00; 
			} 
 
			return RESULT_OK; 
		} 
 
		struct Cheats::Lut 
		{ 
			static const byte rocky[]; 
		}; 
 
		const byte Cheats::Lut::rocky[] = 
		{ 
			3,  13, 14,  1,  6,  9,  5,  0, 
			12,  7,  2,  8, 10, 11,  4, 19, 
			21, 23, 22, 20, 17, 16, 18, 29, 
			31, 24, 26, 25, 30, 27, 28 
		}; 
 
		Result NST_CALL Cheats::ProActionRockyEncode(const Code& code,char (&characters)[9]) throw() 
		{ 
			if (code.address < 0x8000 || !code.useCompare) 
				return RESULT_ERR_INVALID_PARAM; 
 
			const dword input = (code.address & 0x7FFFU) | dword(code.compare) << 16 | dword(code.value) << 24; 
			dword output = 0; 
 
			for (dword i=31, key=0xFCBDD274; i--; key = key << 1 & 0xFFFFFFFF) 
			{ 
				const uint ctrl = input >> Lut::rocky[i] & 0x1; 
				output |= (key >> 31 ^ ctrl) << (i+1); 
 
				if (ctrl) 
					key ^= 0xB8309722; 
			} 
 
			characters[8] = '\0'; 
 
			for (uint i=0; i < 8; ++i) 
			{ 
				const int value = (output >> (i * 4)) & 0xF; 
				characters[i ^ 7] = (value >= 0xA) ? (value - 0xA + 'A') : (value + '0'); 
			} 
 
			return RESULT_OK; 
		} 
 
		Result NST_CALL Cheats::ProActionRockyDecode(const char* const characters,Code& code) throw() 
		{ 
			if (characters == NULL) 
				return RESULT_ERR_INVALID_PARAM; 
 
			dword input=0, output=0; 
 
			for (uint i=0; i < 8; ++i) 
			{ 
				dword num; 
				const int character = characters[i ^ 7]; 
 
				if (character >= '0' && character <= '9') 
				{ 
					num = character - '0'; 
				} 
				else if (character >= 'A' && character <= 'F') 
				{ 
					num = character - 'A' + 0xA; 
				} 
				else if (character >= 'a' && character <= 'f') 
				{ 
					num = character - 'a' + 0xA; 
				} 
				else 
				{ 
					return RESULT_ERR_INVALID_PARAM; 
				} 
 
				input |= num << (i * 4); 
			} 
 
			for (dword i=31, key=0xFCBDD274; i--; input <<= 1, key <<= 1) 
			{ 
				if ((key ^ input) & 0x80000000) 
				{ 
					output |= 1UL << Lut::rocky[i]; 
					key ^= 0xB8309722; 
				} 
			} 
 
			code.address    = output & 0x7FFF | 0x8000; 
			code.compare    = output >> 16 & 0xFF; 
			code.value      = output >> 24 & 0xFF; 
			code.useCompare = true; 
 
			return RESULT_OK; 
		} 
 
		Result Cheats::SetCode(const Code& code) throw() 
		{ 
			if (emulator.tracker.IsLocked( true )) 
				return RESULT_ERR_NOT_READY; 
 
			try 
			{ 
				if (emulator.cheats == NULL) 
					emulator.cheats = new Core::Cheats( emulator.cpu ); 
 
				return emulator.tracker.TryResync 
				( 
					emulator.cheats->SetCode 
					( 
						code.address, 
						code.value, 
						code.compare, 
						code.useCompare, 
						emulator.Is(Machine::GAME) 
					), 
					true 
				); 
			} 
			catch (const std::bad_alloc&) 
			{ 
				return RESULT_ERR_OUT_OF_MEMORY; 
			} 
			catch (...) 
			{ 
				return RESULT_ERR_GENERIC; 
			} 
		} 
 
		Result Cheats::DeleteCode(const ulong index) throw() 
		{ 
			if (emulator.tracker.IsLocked( true )) 
				return RESULT_ERR_NOT_READY; 
 
			if (!emulator.cheats) 
				return RESULT_ERR_INVALID_PARAM; 
 
			const Result result = emulator.tracker.TryResync( emulator.cheats->DeleteCode( index ), true ); 
 
			if (!emulator.cheats->NumCodes()) 
			{ 
				delete emulator.cheats; 
				emulator.cheats = NULL; 
			} 
 
			return result; 
		} 
 
		ulong Cheats::NumCodes() const throw() 
		{ 
			return emulator.cheats ? emulator.cheats->NumCodes() : 0; 
		} 
 
		Result Cheats::GetCode(ulong index,ushort* address,uchar* value,uchar* compare,bool* useCompare) const throw() 
		{ 
			if (emulator.cheats) 
				return emulator.cheats->GetCode( index, address, value, compare, useCompare ); 
			else 
				return RESULT_ERR_INVALID_PARAM; 
		} 
 
		Result Cheats::GetCode(ulong index,Code& code) const throw() 
		{ 
			return GetCode( index, &code.address, &code.value, &code.compare, &code.useCompare ); 
		} 
 
		Result Cheats::ClearCodes() throw() 
		{ 
			if (emulator.tracker.IsLocked( true )) 
				return RESULT_ERR_NOT_READY; 
 
			if (!emulator.cheats) 
				return RESULT_NOP; 
 
			if (emulator.cheats->NumCodes()) 
				emulator.tracker.Resync( true ); 
 
			delete emulator.cheats; 
			emulator.cheats = NULL; 
 
			return RESULT_OK; 
		} 
 
		Cheats::Ram Cheats::GetRam() const throw() 
		{ 
			return emulator.cpu.GetRam(); 
		} 
 
		#ifdef NST_MSVC_OPTIMIZE 
		#pragma optimize("", on) 
		#endif 
	} 
}