
/************************************** Polite Request ***************************************
** I have put a lot of time and effort into YaRR. If you want to use some of the source     **
** please tell me. Anything used from YaRR must be open source, as is scripts.dll.          **
***************************************** Thank you *****************************************/


#include "YaRRIncludes.h"


FILE *ScopeLog::f = 0;
int ScopeLog::level = 0;
int ScopeLog::ref = 0;
DWORD ScopeLog::thread = 0;
char *YaRRInterface::MapName = 0;
bool YaRRInterface::YaRRLoaded = 0;

#ifdef _YaRRDebug
ScopeLog glog("Global", 0);
#endif

unsigned int YaRRInterface::GetHostName(void *id)
{
	const char *IP = Get_IP_Address(*(int *)id);
	if(!IP)
	{
		return 0;
	}
	Stacker<char *> result;
	const char *ret = YaRRTrace::Trace(IP, &result);
	
	EnterCriticalSection(&YaRRPlayers::Mutex);
	Player *p = YaRRPlayers::Find(*(int *)id);
	if(!p)
	{	
		LeaveCriticalSection(&YaRRPlayers::Mutex);
		return 0;
	}	
	
	char *tmp[256];
	int i = 0;
	if(ret)
	{
		IRC::SendC('a', "%s", ret);
		YaRRFunctions::DeleteList(&result);
		CDealloc(ret);
		delete []IP;
		*p->Node = 0;
		LeaveCriticalSection(&YaRRPlayers::Mutex);
		return 0;
	}
	else
	{
		IterateStack(x, char *, (&result))
		{
			if(x)
			{
				tmp[i++] = x;
			}
		}
	}

	for(int z = i-1; z >= 0; z--)
	{
		if(strcmp(tmp[z], IP) != 0)
		{
			if(strcmp(tmp[z], "TimeOut") != 0)
			{
				IRC::SendC('a', "%S's node is: %s", Get_Wide_Player_Name_By_ID(*(int *)id), tmp[z]);
				strcpy(p->Node, tmp[z]);
				YaRRFunctions::DeleteList(&result);
				YaRRFunctions::CheckNodeBan(p);
				delete []IP;
				LeaveCriticalSection(&YaRRPlayers::Mutex);
				return 0;
			}
		}
	}
	YaRRFunctions::DeleteList(&result);
	IRC::SendC('a', "%S's IP is: %s", Get_Wide_Player_Name_By_ID(*(int *)id), IP);
	delete []IP;
	*p->Node = 0;
	LeaveCriticalSection(&YaRRPlayers::Mutex);
	return 0;
}


void YaRRInterface::ObjectCreate(void *stub, GameObject *o)
{
	DLOG;
	if(stricmp(Commands->Get_Preset_Name(o), "Invisible_Object") == 0)
	{
		Vector3 pos = Commands->Get_Position(o);
		for(GenericSLNode *x = BaseGameObjList->HeadNode; x != 0; x = x->NodeNext)
		{
			GameObject *obj = (GameObject *)x->NodeData;
			if(obj && As_BeaconGameObj(obj) != 0)
			{
				Vector3 objp = Commands->Get_Position(obj);
				if((pos.X == objp.X) && (pos.Y == objp.Y))
				{
					o = obj;
					break;
				}
			}
		}
	}

	if(Commands->Is_A_Star(o) && Is_Soldier(o))
	{
		Attach_Script_Once(o, "YaRRPlayer", "");
		Attach_Script_Once(o, "YaRRVeteran", "");
	}
	else if(Is_Vehicle(o))
	{
		Attach_Script_Once(o, "YaRRVehicle", "");
	}
	else if(Is_Beacon(o))
	{
		Attach_Script_Once(o, "YaRRBeacon",  "");
	}
	else if(Is_C4(o))
	{
		Attach_Script_Once(o, "YaRRC4", "");
	}
}

float BHS_Versions[128];

void YaRRInterface::VersionHook(int PlayerID,float Version)
{
	DLOG;
	BHS_Versions[PlayerID] = Version;
}

int YaRRInterface::Purchase_Hook(BaseControllerClass *base,GameObject *purchaser,unsigned int cost,unsigned int preset,const char *data)
{
	DLOG;
	Player *p = YaRRPlayers::Find(Get_Player_ID(purchaser));
	if(!p)
	{
		return -1;
	}

	if(data[0] == '0')
	{
		if(p->BlockBeacons == 1)
		{
			YaRRFunctions::PPage(p->ID, "You have been blocked from buying beacons.");
			return 1;
		}
	}
	else if(data[0] == '1')
	{
		if(p->BlockCharacters == 1)
		{
			YaRRFunctions::PPage(p->ID, "You have been blocked from buying characters.");
			return 1;
		}
	}
	else if(data[0] == '2')
	{
		if(p->BlockVehicles == 1)
		{
			YaRRFunctions::PPage(p->ID, "You have been blocked from buying vehicles.");
			return 1;
		}
	}	
	return -1;
	
}	

void YaRRInterface::Purchase_Mon_Hook(BaseControllerClass *base,GameObject *purchaser,unsigned int cost,unsigned int preset, unsigned int purchaseret, const char *data)
{
	DLOG;
	if(YaRRGlobal::NoOutput)
	{
		return;
	}
	if(purchaseret == 0)
	{
		const char *t = WideCharToChar(Translate_Preset_ID_To_PT_String_Name(base->team,preset));
		const char *p = YaRRFunctions::strdup2(t);
		delete []t;
		if(strcmp(p, "No String") == 0)
		{
			p = YaRRFunctions::GetPresetScreenName(Get_Definition_Name(preset));
		}
		YaRRVeteran::Purchased(Get_Definition_Name(preset), atoi(data), Get_Player_ID(purchaser));
		IRC::SendC('a', "\x03%d%S bought a%s %s\x03", Get_Team(Get_Player_ID(purchaser)) == 0 ? 4 : 8, Get_Wide_Player_Name(purchaser), YaRRFunctions::Vowel(p[0]) == 1 ? "n" : "", p);
		CDealloc(p);
	}
}

void YaRRInterface::Load()
{
	DLOG;
	if(!AddObjectCreateHook)
	{
		return;	
	}
	YaRRLoaded = 1;
	YaRRMemory::Load();

#ifdef _YaRRDebug
	YaRRMemory::LogMemory(1);
#endif
	YaRRGlobal::Startup();
	YaRRStrings::Startup();
	YaRRSettings::Load();
	IRC::Load();
	YaRRDatabase::Startup();
	YaRRPlayers::Startup();
	YaRRWorker::Startup();
	YaRRTrace::Startup();
	YaRRVeteran::Startup();
	YaRRCommands::Startup();
	YaRRThink::Startup();
	

	ObjectCreateHookStruct *ochs = new ObjectCreateHookStruct;
	ochs->data = 0;
	ochs->hook = ObjectCreate;
	
	AddObjectCreateHook(ochs);
	AddVersionHook(VersionHook);

	memset((void *)BHS_Versions, 0, 128*sizeof(float));

	YaRRHooking::Install();

	if(YaRRSettings::NoPending == 1)
	{
		YaRRFunctions::ApplyNoPendingPatch();
	}
	if(YaRRSettings::StartButtonFix == 1)
	{
		YaRRFunctions::ApplyStartButtonFix();
	}
	AddPowerupPurchaseHook(Purchase_Hook, "0");
	AddCharacterPurchaseHook(Purchase_Hook, "1");
	AddVehiclePurchaseHook(Purchase_Hook, "2");

	AddPowerupPurchaseMonHook(Purchase_Mon_Hook, "0");
	AddCharacterPurchaseMonHook(Purchase_Mon_Hook, "2");
	AddVehiclePurchaseMonHook(Purchase_Mon_Hook, "1");	

	AddHostHook(Host_Hook);
	AddGameOverHook(GameOver_Hook);
	AddPlayerJoinHook(Player_Join_Hook);
	AddPlayerLeaveHook(Player_Leave_Hook);

	YaRRPHP::Start();
}

void YaRRInterface::Unload()
{
	DLOG;
	if(!YaRRInterface::YaRRLoaded)
	{
		return;
	}
	YaRRPHP::Stop();
	YaRRThink::Shutdown();
	YaRRCommands::Shutdown();
	YaRRVeteran::Shutdown();
	YaRRTrace::Shutdown();
	YaRRWorker::Shutdown();
	YaRRHooking::Uninstall();
	YaRRPlayers::Shutdown();
	YaRRDatabase::Shutdown();
	
	IRC::Unload();
	YaRRSettings::Unload();
	YaRRGlobal::Shutdown();
	YaRRMemory::Unload();
	YaRRLoaded = 0;
}

void YaRRInterface::Host_Hook(int ID, TextMessageEnum Type, const char *Msg) 
{
	DLOG;
	if(Type != 0)
	{
		return;
	}
	if(YaRRGlobal::NoOutput && *Msg != '(')
	{
		return;
	}
	IRC::SendC('b', "\x03%dHost:\x03 %s", 14, Msg);
}


void YaRRInterface::Player_Join_Hook(int ID, const char *Nick)
{
	DLOG;
	if(BHS_Versions[ID] < YaRRSettings::Minimum_BHS)
	{
		YaRRFunctions::BootPlayer(ID, "The minimum required custom scripts.dll is %.2f. Please get it at www.game-maps.net", YaRRSettings::Minimum_BHS);
		BHS_Versions[ID] = 0;
		return;
	}
	const char *ip = Get_IP_Address(ID);
	bool IsNickB = YaRRFunctions::IsNickBanned(Nick);
	bool IsIPB = YaRRFunctions::IsIPBanned(ip);
	if(IsNickB || IsIPB)
	{
		YaRRFunctions::BanInfo ifo;
		YaRRFunctions::GetBanInfo(&ifo, Nick, ip);
		YaRRFunctions::ConsoleInputF("msg %s was banned for %s\n", Nick, ifo.Reason);
		YaRRFunctions::BootPlayer(ID, "You were banned by %s for: %s", ifo.Banner, ifo.Reason);

		if((IsNickB && !IsIPB) || (!IsNickB && IsIPB))
		{
			YaRRDatabase::Query(0, "INSERT INTO Bans(Nick, IP, WhoBy, Reason, Time) VALUES ('%q', '%q', '%q', '%q', %d);", Nick, ip, ifo.Banner, ifo.Reason, ifo.Time);
		}
		BHS_Versions[ID] = 0;
		return;
	}	

	IRC::SendC('b', "\x03%d%s\x03%d has joined the game.", (Get_Team(ID) == 0 ? 4 : 8), Nick, 3);

	Stacker<YaRRDatabase::Row *> Result;
	YaRRDatabase::Query(&Result, "SELECT * FROM Players WHERE Nick = '%q';", Nick);
	if(Result.Empty())
	{
		char hex[64];
		YaRRFunctions::RGBToHex(YaRRSettings::MessageColour, hex);
		YaRRDatabase::Query(0, "INSERT INTO Players(Nick, JOINMSG, PPageC, PPageS) VALUES('%q', '', '%s', '%s');", Nick, hex, YaRRSettings::PPageSound);
	}
	else
	{
		if(strcmp(YaRRDatabase::GetColumnData("JOINMSG", Result[0]->Columns), "") != 0)
		{
			YaRRFunctions::ConsoleInputF("msg [%s]: %s", Nick, YaRRDatabase::GetColumnData("JOINMSG", Result[0]->Columns));
		}

	}

	YaRRDatabase::DeleteResult(&Result);
	delete []ip;

	YaRRPlayers::Joined(ID);
	Player *p = YaRRPlayers::Find(ID);
	if(!p)
	{
		BHS_Versions[ID] = 0;
		return;
	}
	else
	{
		p->BHS = BHS_Versions[ID];
		BHS_Versions[ID] = 0;
	}
	Task GetHost;
	GetHost.CALL = GetHostName;
	strcpy(GetHost.Name, "CALL");
	GetHost.Param = CAlloc(4);
	*(int *)GetHost.Param = ID;
	GetHost.Count = 1;
	YaRRWorker::Addtask(GetHost);

	YaRRVeteran::PlayerJoined(ID);
}

void YaRRInterface::Player_Leave_Hook(int ID)
{
	DLOG;
	IRC::SendC('b', "%c%d%S %c3has left the game.", 3, (Get_Team(ID) == 0 ? 4 : 8), Get_Wide_Player_Name_By_ID(ID), 3);
	YaRRPlayers::Leave(ID);
}

void YaRRInterface::Level_Loaded_Hook()
{
	DLOG;
	if(!YaRRInterface::YaRRLoaded)
	{
		YaRRInterface::Load();
	}
	YaRRGlobal::Mapload();
	YaRRPlayers::MapLoad();
	YaRRSettings::MapLoad(The_Game()->MapName);
	YaRRPHP::MapLoad();
	
	Attach_Script_Building("YaRRBuilding", "", 2);

	if(!YaRRGlobal::NoOutput)
	{
		IRC::SendC('b', "%c3%s has loaded.", 3, The_Game()->MapName);
	}
	if(MapName)
	{
		CDealloc(MapName);
	}
	MapName = YaRRFunctions::strdup2(The_Game()->MapName);

	GameObject *o = Commands->Create_Object("Invisible_Object", Vector3(0.0, 0.0, 0.0));
	Attach_Script_Once(o, "IRCThinkScript", "");

	int Chance = Commands->Get_Random_Int(0, 100);
	if(Chance > YaRRSettings::DefenceChance)
	{
		Commands->Send_Custom_Event(0,o,101,0,0);
		return;
	}

	Commands->Send_Custom_Event(0,o,100,0,0);

	IterateStack(pos, Vector3, YaRRSettings::GDIDefences)
	{
		GameObject *o = Commands->Create_Object("gdi_guard_tower", pos);
		if(o)
		{
			Attach_Script_Once(o, "YaRRDefenceRebuy", "");
		}
	}

	IterateStack(pos2, Vector3, YaRRSettings::NodDefences)
	{
		GameObject *o = Commands->Create_Object("nod_turret_mp_improved", pos2);
		if(o)
		{
			Attach_Script_Once(o, "YaRRDefenceRebuy", "");
		}
	}	
}

void YaRRInterface::GameOver_Hook()
{
	DLOG;
	YaRRGlobal::Mapend();
	if(!YaRRGlobal::NoOutput)
	{
		char Win[256];
		sprintf(Win, "\x03%d%S has won the game by ", 3, Get_Wide_Team_Name(Get_Team(The_Game()->WinnerID)));
		unsigned int type = The_Game()->WinType;
	
		if (type == 0)
		{
			strcat(Win,"server shutdown.");
		}
		else if (type == 2)
		{
			strcat(Win,"high score when time limit expired.");
		}
		else if (type == 3)
		{
			strcat(Win,"base destruction.");
		}
		else if (type == 4)
		{
			strcat(Win,"a pedestal beacon.");
		}
		IRC::SendC('b', "%s", Win);
		IRC::SendC('b', "\x03%dNod %.0f points\x03%d : \x03%dGDI %.0f points\x03%d : MVP: \x03%d%S*%d", 4, Get_Team_Score(0), 3, 8, Get_Team_Score(1), 3, Get_Team(The_Game()->WinnerID) == 0 ? 4 : 8, (const wchar_t *)The_Game()->MVPName, The_Game()->MVPCount);
		IRC::SendC('b', "%c3%s has ended. Next map will be %s.", 3, MapName, The_Game()->MapName);
	}
}

