#include "Windows.h"
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#include "Hooks.h"



_SerialHook SerialHooks[32];
_LoadingEHook LoadingEHooks[32];
_DamageHook DamageHooks[32];
_ChatHook ChatHooks[32];
_PingHook PingHooks[32];
_SuicideHook SuicideHooks[32];
_RadioHook RadioHooks[32];
_ThinkHook ThinkHooks[32];


extern "C" __declspec(dllexport) void AddSerialHook(_SerialHook SH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!SerialHooks[i])
		{
			SerialHooks[i] = SH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void AddLoadingEHook(_LoadingEHook LEH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!LoadingEHooks[i])
		{
			LoadingEHooks[i] = LEH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void AddDamageHook(_DamageHook DH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!DamageHooks[i])
		{
			DamageHooks[i] = DH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void AddChatHook(_ChatHook CH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!ChatHooks[i])
		{
			ChatHooks[i] =CH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void AddPingHook(_PingHook PH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!PingHooks[i])
		{
			PingHooks[i] = PH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void AddSuicideHook(_SuicideHook SH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!SuicideHooks[i])
		{
			SuicideHooks[i] = SH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void AddRadioHook(_RadioHook RH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!RadioHooks[i])
		{
			RadioHooks[i] = RH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void AddThinkHook(_ThinkHook TH)
{
	for(int i = 0; i < 32; i++)
	{
		if(!ThinkHooks[i])
		{
			ThinkHooks[i] = TH;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemoveSerialHook(_SerialHook SH)
{
	for(int i = 0; i < 32; i++)
	{
		if(SerialHooks[i] == SH)
		{
			SerialHooks[i] = 0;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemoveLoadingEHook(_LoadingEHook LEH)
{
	for(int i = 0; i < 32; i++)
	{
		if(LoadingEHooks[i] == LEH)
		{
			LoadingEHooks[i] = 0;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemoveDamageHook(_DamageHook DH)
{
	for(int i = 0; i < 32; i++)
	{
		if(DamageHooks[i] == DH)
		{
			DamageHooks[i] = 0;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemoveChatHook(_ChatHook CH)
{
	for(int i = 0; i < 32; i++)
	{
		if(ChatHooks[i] == CH)
		{
			ChatHooks[i] = 0;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemovePingHook(_PingHook PH)
{
	for(int i = 0; i < 32; i++)
	{
		if(PingHooks[i] == PH)
		{
			PingHooks[i] = 0;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemoveSuicideHook(_SuicideHook SH)
{
	for(int i = 0; i < 32; i++)
	{
		if(SuicideHooks[i] == SH)
		{
			SuicideHooks[i] = 0;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemoveRadioHook(_RadioHook RH)
{
	for(int i = 0; i < 32; i++)
	{
		if(RadioHooks[i] == RH)
		{
			RadioHooks[i] = 0;
			break;
		}
	}
}

extern "C" __declspec(dllexport) void RemoveThinkHook(_ThinkHook TH)
{
	for(int i = 0; i < 32; i++)
	{
		if(ThinkHooks[i] == TH)
		{
			ThinkHooks[i] = 0;
			break;
		}
	}
}



class cGameSpyCsChallengeResponseEvent
{
	char stub[0x6B4];
	int PlayerID;
	StringClass Serial;
	void Act()
	{
		char s[33];
		s[32] = 0;
		memcpy((void *)s, (void *)Serial.c, 32);

		for(int i = 0; i < 32; i++)
		{
			if(SerialHooks[i])
			{
				SerialHooks[i](PlayerID, s);

			}
		}

		DWORD loc = 0x4B6ED0;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};

extern "C" __declspec(dllexport) void RequestSerial(int ID, StringClass &_str)
{
	__asm
	{
		mov eax, 6B8h;
		push eax;

		mov eax, 0x672410;
		call eax;

		add esp, 4;

		mov ecx, eax;
		push ecx;

		mov eax, 0x4B7220;
		call eax;

		pop ecx;

		mov eax, _str;
		push eax;

		mov eax, ID;
		push ID;

		mov eax, 0x4B72C0;
		call eax;
	}
}

class cLoadingEvent
{
	char stub[0x6B4];

	int PlayerID;
	bool IsInGame;

	void Act()
	{
		for(int i = 0; i < 32; i++)
		{
			if(LoadingEHooks[i])
			{
				LoadingEHooks[i](PlayerID, IsInGame);
			}
		}
		DWORD loc = 0x4B7860;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};

class cCsDamageEvent
{
	char stub[0x6B4];
	int PlayerId;
	int Damager;
	int Target;
	float Damage;
	unsigned int Warhead;
	void Act()
	{
		bool ret = 1;
		for(int i = 0; i < 32; i++)
		{
			if(DamageHooks[i])
			{
				if(!DamageHooks[i](PlayerId, Damager, Target, Damage, Warhead))
				{
					ret = 0;
				}
			}
		}

		if(!ret)
		{
			return;
		}
		DWORD loc = 0x6F3F10;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};


class cCsTextObj
{
	char stub[0x6B4];
	int PlayerID;
	int Type;
	WideStringClass Message;
	int Target;
public:
	void Act()
	{
		bool ret = 1;
		for(int i = 0; i < 32; i++)
		{
			if(ChatHooks[i])
			{
				if(!ChatHooks[i](PlayerID, Type, Message, Target))
				{
					ret = 0;
				}
			}
		}

		if(!ret)
		{
			return;
		}

		DWORD loc = 0x4B5C10;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};




class cCsPingRequestEvent
{
	char stub[0x6B4];

	int ID;
	int PingID;

	void Act()
	{
		for(int i = 0; i < 32; i++)
		{
			if(PingHooks[i])
			{
				PingHooks[i](ID, PingID);
			}
		}

		DWORD loc = 0x4B5900;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};

class cSuicideEvent
{
	char stub[0x6B4];
public:
	int PlayerID;
	void Act()
	{
		bool ret = 1;
		for(int i = 0; i < 32; i++)
		{
			if(SuicideHooks[i])
			{
				if(!SuicideHooks[i](PlayerID))
				{
					ret = 0;
				}
			}
		}

		if(!ret)
		{
			return;
		}

		DWORD loc = 0x4BA140;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};

class CSAnnouncement
{
	char stub[0x6B4];
public:
	int Team;
	int PlayerId;
	int a;
	int RadioId;
	int b;

	void Act()
	{
		bool ret = 1;
		for(int i = 0; i < 32; i++)
		{
			if(RadioHooks[i])
			{
				if(!RadioHooks[i](Team, PlayerId, a, RadioId, b))
				{
					ret = 0;
				}
			}
		}

		if(!ret)
		{
			return;
		}

		DWORD loc = 0x4B3660;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};

class cBioEvent
{
	char stub[0x6B4];
	int ID;
	WideStringClass Nick;
	const char *a;
	char stub2[0x104];

public:

	void Act()
	{
		printf("%d - %S\n", ID, Nick.w);

		DWORD loc = 0x4B4400;//x4B46F00;
		__asm
		{
			mov ecx, this;
			call loc;
		}
	}
};

void Main_Think()
{
	for(int i = 0; i < 32; i++)
	{
		if(ThinkHooks[i])
		{
			ThinkHooks[i]();
		}
	}
}


void __declspec(naked) main_loop_glue()
{
	__asm
	{
		call Main_Think;

		pop edi;
		pop esi;
		add esp, 0Ch;
		ret;
	}

}


bool  __stdcall DllMain(HINSTANCE, DWORD call, LPVOID)
{
	if(call == DLL_PROCESS_ATTACH)
	{

		DWORD loc = 0;
		memset((void *)SerialHooks, 0, 4*32);
		memset((void *)LoadingEHooks, 0, 4*32);
		memset((void *)DamageHooks, 0, 4*32);
		memset((void *)ChatHooks, 0, 4*32);
		memset((void *)PingHooks, 0, 4*32);
		memset((void *)SuicideHooks, 0, 4*32);
		memset((void *)RadioHooks, 0, 4*32);

		char op = '\xE9';

		unsigned int set = (int)main_loop_glue - 0x0043BAC8 - 5;
		WriteMemory((LPVOID)0x0043BAC8 , &op, 1);
		WriteMemory((LPVOID)(0x0043BAC8+1), &set, 4);

		__asm
		{
			mov eax, cGameSpyCsChallengeResponseEvent::Act
			mov loc, eax
		}
		if(!WriteMemory((LPVOID)0x007D4E30, (void *)&loc, 4))
		{
			printf("[Hooks] Error installing serial hook - %d\n", GetLastError());
		}
		
		__asm
		{
			mov eax, cCsTextObj::Act;
			mov loc, eax;
		}
		if(!WriteMemory((LPVOID)0x7D4B98, (void *)&loc, 4))
		{
			printf("[Hooks] Error installing chat hook - %d\n", GetLastError());
		}

		__asm
		{
			mov eax, cCsDamageEvent::Act;
			mov loc, eax;
		}
		if(!WriteMemory((LPVOID)0x7E4230, (void *)&loc, 4))
		{
			printf("[Hooks] Error installing damage hook - %d\n", GetLastError());
		}

		__asm
		{
			mov eax, cSuicideEvent::Act;
			mov loc, eax;
		}
		if(!WriteMemory((LPVOID)0x7D5468, (void *)&loc, 4))
		{
			printf("[Hooks] Error installing suicide hook - %d\n", GetLastError());
		}

		__asm
		{
			mov eax, CSAnnouncement::Act;
			mov loc, eax;
		}
		if(!WriteMemory((LPVOID)0x7D45FC, (void *)&loc, 4))
		{
			printf("[Hooks] Error installing radio hook - %d\n", GetLastError());
		}

		__asm
		{
			mov eax, cCsPingRequestEvent::Act;
			mov loc, eax;
		}
		if(!WriteMemory((LPVOID)0x7D4B14, (void *)&loc, 4))
		{
			printf("[Hooks] Error installing ping hook - %d\n", GetLastError());
		}

		__asm
		{
			mov eax, cLoadingEvent::Act;
			mov loc, eax;
		}
		if(!WriteMemory((LPVOID)0x7D4FBC, (void *)&loc, 4))
		{
			printf("[Hooks] Error installing loading hook - %d\n", GetLastError());
		}

		/*__asm
		{
			mov eax, cBioEvent::Act;
			mov loc, eax;
		}
		WriteMemory((LPVOID)0x7D46FC, (void *)&loc, 4);*/
		printf("Finished installing hooks.\n");
	}
	return 1;
}

bool ReadMemory(LPVOID Address, void* Buffer, int Size)
{
	DWORD old  = 0;
	bool ret = VirtualProtect((void *)Address, 1, PAGE_EXECUTE_READWRITE, &old);
	if(ret)
	{
		memcpy((void *)Address, Buffer, Size);
		VirtualProtect((void *)Address, 1, old, &old);
	}
	return ret;
}
 
bool WriteMemory(LPVOID Address, const void* Buffer, int Size)
{
	DWORD old  = 0;
	bool ret = VirtualProtect((void *)Address, 1, PAGE_EXECUTE_READWRITE, &old);
	if(ret)
	{
		memcpy((void *)Buffer, Address, Size);
		VirtualProtect((void *)Address, 1, old, &old);
	}
	return ret;
}