#pragma once

#include <stddef.h>
#ifdef STDIO_SUPPORT
#include <stdio.h>
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef NEED_D3D
#include <d3d9.h>
typedef PDIRECT3D9 (WINAPI *PDirect3DCreate9)(UINT SDKVersion);
#else
typedef PVOID (WINAPI *PDirect3DCreate9)(UINT SDKVersion);
typedef PVOID PDIRECT3DDEVICE9;
#endif

//#define DO_CALL_COUNTS
#define DO_HOTKEYS
//#define DO_CUSTOM_PRESENT
#define DO_CUSTOM_KEYS
//#define DO_CUSTOM_SCRIPT_HOOK
//#define DO_GXT_HOOK
//#define DO_FULL_THREAD_CONTROL
//#define HOOK_SCRIPT_FROM_PRESENT
//#define HAVE_TOOLHELP32

/*
 * Hardwired addresses in gta_sa.exe
 */
struct GameAddresses {
	/*
	 * This is the address of the IAT entry for
	 *   Direct3DCreate9().  It's in a read/write
	 *   data section of gta_sa.exe.
	 * 
	 * This pointer can be found by running
	 *     dumpbin /imports gta_sa.exe
	 *   and looking for "Import Address Table"
	 *   value of d3d9.dll/Direct3DCreate9
	 */
	PDirect3DCreate9* IAT_ENTRY_Direct3DCreate9;
	/*
	 * Initial value in IAT_ENTRY_Direct3DCreate9
	 */
	PVOID IAT_ENTRY_Direct3DCreate9_Initial_Value;
#ifdef HOOK_SCRIPT_FROM_PRESENT
	/*
	 * The following is a BYTE that indicates
	 *   if the game is in the main menu.
	 *   data section - read/write
	 */
	PBYTE IN_MENU;
#endif
	/*
	 * Script's ProcessOneCommand (from gtaforums.com)
	 *   code section - read only
	 */
	PVOID PROCESS_ONE_COMMAND;
	/*
	 * A global timer used to time the
	 *   threads, a DWORD in milliseconds (from gtaforums.com)
	 *   data section - read/write
	 */
	PDWORD GLOBAL_TIMER;
#if 0	// not used
	/*
	 * A float used to hold the size of a
	 *   script time tick in the unit
	 *   of 20 msec.  It's set to 0 when
	 *   the script is suspended, and
	 *   adjusts dynamically to sync real
	 *   time when the script is running.
	 *   data section - read/write
	 */
	PFLOAT SCRIPT_TIME_TICK;
#endif
	/*
	 * Hold's the running state of the game's
	 *   main application loop, values 0 - 9
	 *   data section - read/write
	 */
	PDWORD MAIN_LOOP_GAME_STATE;
	/*
	 * Some code to NOP in order to disable
	 *   the splash screens (from gtaforums.com)
	 *   code section - read only
	 */
	PVOID SPLASH_CODE_DISABLE;
	/*
	 * 4096 byte buffer where mission
	 *   local variables are stored
	 *   data section - read/write
	 */
	PDWORD MISSION_LOCAL_VARS;
	/*
	 * Script base - where main.scm and
	 *   the global variables are.
	 *   data section - read/write
	 */
	PDWORD SCRIPT_BASE;
#ifndef HOOK_SCRIPT_FROM_PRESENT
	/*
	 * Point inside the script tick for
	 *   hooking the script engine
	 *   code section - read only
	 */
	PBYTE SCRIPT_TICK_HOOK_POINT;
#endif
#ifdef DO_GXT_HOOK
	/*
	 * The read_GXT() routine that translates
	 *   GXT labels to text.
	 *   code section - read only
	 */
	PBYTE READ_GXT;
#endif
#ifdef DO_FULL_THREAD_CONTROL
	/*
	 * Position of the script tick loop that
	 *   iterates over the linked list
	 *   of threads and calls ProcessOneCommand
	 *   on each.
	 *   code section - read only
	 */
	PBYTE THREAD_LOOP;
	/*
	 * A counter used by the thread loop to
	 *   count the number of threads executed.
	 *   data section - read/write
	 */
	PWORD THREAD_LOOP_COUNTER;
#endif
	/*
	 * Place where game keeps a pointer
	 *   to its IDirect3DDevice9 interface
	 *   data section - read/write
	 */
	PDIRECT3DDEVICE9* GAME_DIRECT3DDEVICE9;
#if 0	// not used
	/*
	 * Place where game keeps a pointer
	 *   to its IDirect3D9 interface
	 *   data section - read/write
	 */
	PDIRECT3D9* GAME_DIRECT3D9;
#endif
	/*
	 * Game's gravity constant (from gtaforums.com)
	 *   rdata section - read only
	 */
	PFLOAT GRAVITY;
	/*
	 * Used to set unlimited speed on the Hydra
	 *   code section - read only
	 */
	PBYTE HYDRA_SPEED_PATCH;
	/*
	 * Used to set unlimited height on the jetpack
	 *   code section - read only
	 */
	PBYTE JETPACK_HEIGHT_PATCH;
	/*
	 * Used to set unlimited height on aircraft
	 *   code section - read only
	 */
	PBYTE AIRCRAFT_HEIGHT_PATCH;
};

const GameAddresses* remoteDetectVersion(HANDLE processHandle);
const GameAddresses* localDetectVersion();
void selectVersion(const GameAddresses* pGameAddresses);
extern GameAddresses activeGA;
#define GA(FIELD) activeGA.FIELD

char errorText[];
extern int bWindow;
extern int bSplashScreens;
extern PDirect3DCreate9 originalDirect3DCreate9;
extern HWND hWnd_GTASA;
extern DWORD dwThreadId_GTASA;