#include "Common.h"

GameAddresses activeGA;

/*
 * v1.0 US gta_sa.exe Game Addresses
 */
static const GameAddresses aV1_US = {
	(PDirect3DCreate9*) 0x8E3ED4U,
	(PVOID) 0x807C10U,
#ifdef HOOK_SCRIPT_FROM_PRESENT
	(PBYTE) 0xB7CB49U,
#endif
	(PVOID) 0x469F00U,
	(PDWORD) 0xB7CB84U,
#if 0
	(PFLOAT) 0xB7CB58U,
#endif
	(PDWORD) 0xC8D4C0U,
	(PVOID) 0x747483U,
	(PDWORD) 0xA48960U,
	(PDWORD) 0xA49960U,
#ifndef HOOK_SCRIPT_FROM_PRESENT
	(PBYTE) 0x46A22EU,
#endif
#ifdef DO_GXT_HOOK
	(PBYTE) 0X6A0050U,
#endif
#ifdef DO_FULL_THREAD_CONTROL
	(PBYTE) 0x46A1F0U,
	(PWORD) 0xA447F8U,
#endif
	(PDIRECT3DDEVICE9*) 0xC97C28U,
#if 0
	(PDIRECT3D9*) 0xC97C20U,
#endif
	(PFLOAT) 0x863984U,
	(PBYTE) 0x6DADE8U,
	(PBYTE) 0x67F268U,
	(PBYTE) 0x6D261DU
};

/*
 * v1.0 EU gta_sa.exe Game Addresses
 */
static const GameAddresses aV1_EU = {
	(PDirect3DCreate9*) 0x8E3ED4U,
	(PVOID) 0x807C50U,
#ifdef HOOK_SCRIPT_FROM_PRESENT
	(PBYTE) 0xB7CB49U,
#endif
	(PVOID) 0x469F00U,
	(PDWORD) 0xB7CB84U,
#if 0
	(PFLOAT) 0xB7CB58U,
#endif
	(PDWORD) 0xC8D4C0U,
	(PVOID) 0x7474D3U,
	(PDWORD) 0xA48960U,
	(PDWORD) 0xA49960U,
#ifndef HOOK_SCRIPT_FROM_PRESENT
	(PBYTE) 0x46A22EU,
#endif
#ifdef DO_GXT_HOOK
	(PBYTE) 0X6A0050U,
#endif
#ifdef DO_FULL_THREAD_CONTROL
	(PBYTE) 0x46A1F0U,
	(PWORD) 0xA447F8U,
#endif
	(PDIRECT3DDEVICE9*) 0xC97C28U,
#if 0
	(PDIRECT3D9*) 0xC97C20U,
#endif
	(PFLOAT) 0x863984U,
	(PBYTE) 0x6DADE8U,
	(PBYTE) 0x67F268U,
	(PBYTE) 0x6D261DU
};

/*
 * sig1 is the code that should be at GA(SPLASH_CODE_DISABLE)
 */
static const BYTE sig1[] = {0x89U, 0x35U, 0xC0U, 0xD4U, 0xC8U, 0};

const GameAddresses* remoteDetectVersion(HANDLE processHandle)
{
	const GameAddresses* g;
	DWORD i, bytesRead;
	PVOID p;

	for (i = 0; i < 2; i++) {
		g = i ? &aV1_EU : &aV1_US;
		if (!ReadProcessMemory(
				processHandle,
				g->IAT_ENTRY_Direct3DCreate9,
				&p,
				sizeof(PVOID),
				&bytesRead) ||
			bytesRead < sizeof(PVOID) ||
			p != g->IAT_ENTRY_Direct3DCreate9_Initial_Value)
			continue;
		return g;
	}
	return NULL;
}

const GameAddresses* localDetectVersion()
{
	const GameAddresses* g;
	DWORD i;

	for (i = 0; i < 2; i++) {
		g = i ? &aV1_EU : &aV1_US;
		if (memcmp(sig1, g->SPLASH_CODE_DISABLE, sizeof(sig1)))
			continue;
		return g;
	}
	return NULL;
}

void selectVersion(const GameAddresses* pGameAddresses)
{
	memcpy(
		&activeGA,
		pGameAddresses ? pGameAddresses : &aV1_US,
		sizeof(GameAddresses));
}