#include "YaRRIncludes.h"


/************************************** 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 *****************************************/


#define SendIRC(message) IRC::Send("PRIVMSG %s :%s\n", Channel, message) 
//i'm lazy, get over it ^^

Stacker<ChatCommand *> *YaRRCommands::CommandList = 0;


void Debug::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	
}

void Debug::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;

	if(Tokens->Length() < 2)
	{
		return;
	}
	else if(strcmp((*Tokens)[1], "promote") == 0)
	{
		Player *p = Find(1);
		p->Rank.VetScore += 1000;

	}
	else if(strcmp((*Tokens)[1], "presett") == 0)
	{	
		IRC::SendC(Channel, "I have %d presets loaded. Extra health: %d%%", YaRRSettings::GetPremotionInfo(1)->Powerups->Length(), YaRRSettings::GetPremotionInfo(1)->Health);

	}
	else if(strcmp((*Tokens)[1], "channels") == 0)
	{
		char *db = (char *)CAlloc(1);
		*db = 0;

		IterateStack(c, ircChannel *, (&YaRRGlobal::IRC->Channels))
		{
			db = (char *)RAlloc(db, strlen(c->Name)+strlen(db)+3);
			strcat(db, " ");
			strcat(db, c->Name);
		}

		IRC::SendC(Channel, "[DEBUG] %s", db);
		CDealloc(db);
	}
	else if(strcmp((*Tokens)[1], "sound") == 0)
	{
		char tmp[128];
		sprintf(tmp, "%d,1", Award_Demolition_Sound);
		Attach_Script_Once(Get_GameObj(1), "YaRR_PlaySound", tmp);
	}
	else if(strcmp((*Tokens)[1], "ranks") == 0)
	{
		//Player *p = Find(1);

		//IRC::SendC(Channel, "Building_Damage: %.3f, Building_Damage_CoEfficient: %.3f, RankScore: %.3f", p->Rank.Building_Damage, RankInfo::Building_Damage_CoEfficient, p->Rank.RankScore);
	}
	else if(strcmp((*Tokens)[1], "memory") == 0)
	{
		float KiB = float(YaRRMemory::Usage(1) / 1024);
		IRC::Send("PRIVMSG %s :using %.4f KiB of memory\n", Channel, KiB);
		return;
	}
	else if(strcmp((*Tokens)[1], "commands") == 0)
	{
		IRC::Send("PRIVMSG %s :I have %d commands registered\n", Channel, YaRRCommands::CommandList->Length());
		return;
	}
	else if(strcmp((*Tokens)[1], "worker") == 0)
	{
		char f = YaRRWorker::Flags();
		IRC::Send("PRIVMSG %s :worker flags: %s %s %s\n", Channel, (f & WORKER_RUNNING) == 0 ? "" : "WORKER_RUNNING", (f & WORKER_BUSY) == 0 ? "" : "WORKER_BUSY", (f & WORKER_IDLE) == 0 ? "" : "WORKER_IDLE");
		return;
	}
	else if(strcmp((*Tokens)[1], "irc") == 0)
	{

		if(user->Modes == 0)
		{
			IRC::Send("PRIVMSG %s :You have no status in this channel\n", Channel);
		}
		else
		{
			IRC::Send("PRIVMSG %s :Your access is: %c\n", Channel, user->Modes);
		}
	}
	else if(strcmp((*Tokens)[1], "chat") == 0)
	{
		YaRRFunctions::SendMessageF(-1, 0, 0, 1, "hello world!");
	}
	else if(strcmp((*Tokens)[1], "find_hook") == 0)
	{

		DWORD addr = 0, addr2 = 0, loc = 0;
		if(sscanf(*Tokens->At(2), "%x", &addr) == 0)
		{
			IRC::SendC(Channel, "Invalid address: \"%s\"", *Tokens->At(2));
			return;
		}

		if(sscanf(*Tokens->At(3), "%x", &addr2) == 0)
		{
			IRC::SendC(Channel, "Invalid address: \"%s\"", *Tokens->At(3));
			return;
		}


		for(int i = 0;;i++)
		{
			ReadMemory(addr+(i*4), (void *)&loc, 4);
			if(loc == addr2)
			{
				IRC::SendC(Channel, "Install your hook at: 0x%x\n", addr+(i*4));
				return;
			}
		}
	}
	else if(strcmp((*Tokens)[1], "pend") == 0)
	{
		Player *p = Find(1);
		cPlayer *x = p->data;

		//DWORD Set_Is_In_Game = 0x4130D0;
		DWORD Mark_As_Modified = 0x40D540;
		//DWORD Set_Rhost_Is_In_Game = 0x61A620;

		//DWORD operator_new_ren = 0x672410;
		//DWORD update_ctor = 0x4B6600; 
		//DWORD update_init = 0x4B6660;
		x->IsWaitingForIntermission = 1;

		__asm
		{
			//push 0;
			//mov ecx, x;
			//call Set_Is_In_Game;
			/*mov eax, x;
			add eax, 0x75C;
			mov ecx, 0x81FF84;
			push 0;
			push eax;
			call Set_Rhost_Is_In_Game;*/

			mov ecx, x;
			call Mark_As_Modified;	
		}



	}
	else if(strcmp((*Tokens)[1], "pend2") == 0)
	{
		Player *p = Find(1);
		cPlayer *x = p->data;

		DWORD Set_Is_In_Game = 0x4130D0;
		DWORD Mark_As_Modified = 0x40D540;
		//DWORD operator_new_ren = 0x672410;
		//DWORD update_ctor = 0x4B6600; 
		//DWORD update_init = 0x4B6660;

		__asm
		{
			push 1;
			mov ecx, x;
			call Set_Is_In_Game;

			mov ecx, x;
			call Mark_As_Modified;	
		}


	}
	else
	{
		const char *Msg = Implode(Tokens, 1);
		Stacker<Row *> result;
		const char *err = Query(&result, "%s", Msg);
		if(err)
		{
			IRC::Send("PRIVMSG %s :\x03%dSqlite Error:\x03 %s\n", Channel, 4, err);
			if(!result.Empty())
			{
				DeleteResult(&result);
			}
			CDealloc(err);
			return;
		}
		
		int Rowhash = 1;
		if(!result.Empty())
		{
			result.Reset();
			Row *r;
			while(result.Iterate(&r))
			{
				IRC::Send("PRIVMSG %s :Row #%d\n", Channel, Rowhash);
				Rowhash++;
				r->Columns->Reset();
				Column *c;
				while(r->Columns->Iterate(&c))
				{
					IRC::Send("PRIVMSG %s :%s: %s\n", Channel, c->Name, c->Data);
				}
			}
		}
		DeleteResult(&result);
		CDealloc(Msg);
	}
	
}


void Message::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	const char *Msg = Implode(Tokens, 1);
	ConsoleInputF("msg (%s) %s", user->Nick, Msg);
	CDealloc(Msg);
}


void Gameinfo::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	time_t t = (time_t)The_Game()->TimeRemaining_Seconds;
	tm *tstr = localtime(&t);


	char TimeStr[256];
	sprintf(TimeStr, "%d.%d.%d", tstr->tm_hour, tstr->tm_min, tstr->tm_sec);

	char NodStr[256];
	char GDIStr[256];
	sprintf(NodStr, "%d/%d players", GetTeamPlayerCount(0), The_Game()->MaxPlayers);
	sprintf(GDIStr, "%d/%d players", GetTeamPlayerCount(1), The_Game()->MaxPlayers);

	IRC::SendC(Channel, "%6s : %-10s\n", "Map", The_Game()->MapName);
	IRC::SendC(Channel, "%6s : %-10s\n", "Time", TimeStr);
	IRC::SendC(Channel, "%6s : %-10d\n", "FPS", IRCThinkScript::sfps);
	IRC::SendC(Channel, "%6s : %-10s %4s %.0f points\n", "GDI", GDIStr, " ", Get_Team_Score(1));
	IRC::SendC(Channel, "%6s : %-10s %4s %.0f points\n", "Nod", NodStr, " ", Get_Team_Score(0));
}

void Ban::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	int pID = FindPlayer(*Tokens->At(1));
	if(pID == -1)
	{
		PNOT;
	}
	else if(pID == -2)
	{
		PMANY;
	}

	const char *pName = Get_Player_Name_By_ID(pID);
	const char *Nick = Get_Player_Name_By_ID(ID);
	const char *pIP = Get_IP_Address(pID);
	const char *Msg = Implode(Tokens, 2);

	int TimeStamp = (int)time(0);
	
	Query(0, "INSERT INTO Bans(Nick, IP, WhoBy, Reason, Time) VALUES('%q', '%q', '%q', '%q', %d);", pName, pIP, Nick, Msg, TimeStamp);

	BootPlayer(pID, "You were banned by %s for '%s'", Nick, Msg);
	Query(0, "INSERT INTO Log(Type, Action, time) VALUES('BAN', '%s was banned by %s for: %s', '%d');", pName, Nick, Msg, time(0));
	ConsoleInputF("msg %S was banned by %s for: %s", Get_Wide_Player_Name_By_ID(pID), Nick, Msg);

	delete []pName;
	delete []pIP;
	delete []Nick;
	CDealloc(Msg);
}




void Ban::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		IRCArgs;
	}

	int ID = FindPlayer(*Tokens->At(1));
	if(ID == -1)
	{
		IRCPNOT;
	}
	else if(ID == -2)
	{
		IRCPMANY;
	}

	const char *pName = Get_Player_Name_By_ID(ID);
	const char *pIP = Get_IP_Address(ID);
	const char *Msg = Implode(Tokens, 2);

	int TimeStamp = (int)time(0);
	
	Query(0, "INSERT INTO Bans(Nick, IP, WhoBy, Reason, Time) VALUES('%q', '%q', '%s@IRC', '%q', %d);", pName, pIP, user->Nick, Msg, TimeStamp);
	BootPlayer(ID, "You were banned by %s for '%q'", user->Nick, Msg);
	Query(0, "INSERT INTO Log(Type, Action, time) VALUES('BAN', '%s was banned by %s@IRC for: %s', '%d');", pName, user->Nick, Msg, time(0));
	delete []pName;
	delete []pIP;
	CDealloc(Msg);
}

void Help::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	char *x = strdup2("");
	int count = 0;
	
	Player *p = YaRRPlayers::Find(ID);
	if(!p)
	{
		CDealloc(x);
		return;
	}

	YaRRCommands::CommandList->Reset();
	ChatCommand *c;
	while(YaRRCommands::CommandList->Iterate(&c))
	{
		if(GetStatus(c->Access) > GetStatus(p->Access))
		{
			continue;
		}
		if(!(c->Use & FLAG_GAME))
		{
			continue;
		}
		if((strlen(x)+strlen(c->Triggers[0])+2) > 80)
		{
			PPage(ID, "%s", x);
			CDealloc(x);
			x = strdup2("");
			count = 0;
		}
		else
		{
			x = (char *)RAlloc((void *)x, strlen(x)+strlen(c->Triggers[0])+2);
			strcat(x, c->Triggers[0]);
			strcat(x, " ");
			count++;
		}

	}
	if(count > 0)
	{
		PPage(ID, "%s", x);
	}
	CDealloc(x);
}

void Help::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char *x = (char *)CAlloc(1);
	int count = 0;

	Moderator m;
	bool found = 0;
	ModeratorList->Reset();
	while(ModeratorList->Iterate(&m))
	{
		if(stricmp(user->Nick, m.IRCNick) == 0)
		{
			found = 1;
			break;
		}	
	}
	if(!found)
	{
		m.Access = 'p';
	}

	YaRRCommands::CommandList->Reset();
	ChatCommand *c;
	while(YaRRCommands::CommandList->Iterate(&c))
	{
		if((GetStatus(user->Modes) < GetStatus(c->Access)) || (GetStatus(m.Access) < GetStatus(c->Access)))
		{
			continue;
		}
		if(!(c->Use & FLAG_IRC))
		{
			continue;
		}
		x = (char *)RAlloc((void *)x, strlen(x)+strlen(c->Triggers[0])+2);
		strcat(x, c->Triggers[0]);
		strcat(x, " ");
	}

	Stacker<char *> sortlist;
	Explode(x, ' ', &sortlist);
	Sort(sortlist, sortalpha, 1);
	CDealloc(x);
	x = (char *)CAlloc(1);

	IterateStack(com, char *, (&sortlist))
	{
		if((strlen(x)+strlen(com)+2) > 75)
		{
			IRC::Send("NOTICE %s :%s\n", user->Nick, x);
			CDealloc(x);
			x = (char *)CAlloc(1);
			count = 0;
		}
		else
		{
			x = (char *)RAlloc((void *)x, strlen(x)+strlen(com)+2);
			strcat(x, com);
			strcat(x, " ");
			count++;
		}
		CDealloc(com);
	}


	if(count > 0)
	{
		IRC::Send("NOTICE %s :%s\n", user->Nick, x);
	}
	CDealloc(x);
}


void Auth::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char c;
	if(!IRC::FindStatus(user->Nick, Channel, &c))
	{
		char *nfstatus = Replace(Replace(strdup2(Fetch(IRC_AUTHNSTATUS)), ":nick:", user->Nick), ":command:", *Tokens->At(0));
		IRC::Send("PRIVMSG %s :%s\n", Channel, nfstatus);
		CDealloc(nfstatus);
		return;
	}
	char pname[40];
	
	if(!YaRRSettings::GetPlayerInGameNick(user->Nick, pname))
	{
		char *nmod = Replace(Replace(strdup2(Fetch(IRC_NMOD)), ":nick:", user->Nick), ":command:", *Tokens->At(0));
		IRC::Send("PRIVMSG %s :%s\n", Channel, nmod);
		CDealloc(nmod);
		return;
	}

	IterateStack(m, Moderator, YaRRSettings::ModeratorList)
	{
		if(strcmp(m.IRCNick, user->Nick) == 0)
		{
			int ircs = GetStatus(c);
			int mods = GetStatus(m.Access);
			if(ircs > mods)
			{
				c = m.Access;
			}
		}
	}

	int ret = FindPlayer(pname);
	if(ret > 0)
	{
		Player *p = YaRRPlayers::Find(ret);
		p->Access = c;
		char buffer[16];
		GetStatusName(c, buffer);
		ConsoleInputF("msg %s is a%s %s.", pname, (strcspn(buffer, "aeiou") == 0 ? "n" : ""), buffer);
	}
	else
	{
		char *EFIG = Replace(Replace(strdup2(Fetch(IRC_EFIG)), ":nick:", user->Nick), ":command:", *Tokens->At(0));
		IRC::Send("PRIVMSG %s :%s\n", Channel, EFIG);
		CDealloc(EFIG);
	}

}


void Save::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	char team[64], buffer[256], file[256];
	strcpy(team, (stricmp((*Tokens)[1], "nod") == 0 ? "NodDefence" : "GDIDefence"));
	GetCurrentDirectory(128, file);
	strcat(file, "\\config\\YaRR.ini");
	GetPrivateProfileString(The_Game()->MapName, team, "", buffer, 256, file);
	Vector3 pos = Commands->Get_Position(Get_GameObj(ID));
	sprintf(buffer, "%s (%.3f,%.3f,%.3f)", buffer, pos.X, pos.Y, (strcmp(team, "GDIDefence") == 0 ? pos.Z += 7 : pos.Z));
	WritePrivateProfileString(The_Game()->MapName, team, buffer, file);
}

void Setjoin::Activate(int ID, int Type, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	const char *Msg = Implode(Tokens, 1);
	Query(0, "UPDATE Players SET JOINMSG = '%q' WHERE Nick = '%q';", Msg, GetPlayerName(ID));
	PPage(ID, "Your join message was set to: %s", Msg);
	CDealloc(Msg);
}

void FDS::Activate(int ID, int Type, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	const char *Msg = Implode(Tokens, 1);
	ConsoleInputF("%s", Msg);
	CDealloc(Msg);
}

void FDS::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	const char *Msg = Implode(Tokens, 1);
	ConsoleInputF("%s", Msg);
	CDealloc(Msg);
}

void Boot::Activate(int ID, int Type, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		const char  *Reason = Implode(Tokens, 2);
		BootPlayer(ret, "%s", Reason);
		char msg[512];
		sprintf(msg, "%S was kicked (auto-allow) by %S for: %s", Get_Wide_Player_Name_By_ID(ret), Get_Wide_Player_Name_By_ID(ID), Reason);
		ConsoleInputF("msg %s", msg);
		Query(0, "INSERT INTO Log(Type, Action, time) VALUES('KICK', '%q', '%d');", msg, time(0));
		CDealloc(Reason);
	}
}

void Boot::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		const char  *Reason = Implode(Tokens, 2);
		BootPlayer(ret, "%s", Reason);
		char msg[512];
		sprintf(msg, "%S was kicked (auto-allow) by (%s@IRC) for: %s", Get_Wide_Player_Name_By_ID(ret), user->Nick, Reason);
		ConsoleInputF("msg %s", msg);
		Query(0, "INSERT INTO Log(Type, Action, time) VALUES('KICK', '%q', '%d');", msg, time(0));
		CDealloc(Reason);
	}
}

void Unban::Activate(int ID, int Type, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	Stacker<Row *> results;
	Query(&results, "SELECT * FROM Bans WHERE Nick = '%q' or IP = '%q';", *Tokens->At(1), *Tokens->At(1));
	if(results.Empty())
	{
		PPageErr(ID, "A player with this name or IP was not banned.");
	}
	else
	{
		Query(0, "DELETE FROM Bans WHERE Nick = '%q' or IP = '%q';", *Tokens->At(1), *Tokens->At(1));
		DeleteResult(&results);

		PPage(ID, "Deleted from database.");
		Query(&results, "INSERT INTO Log(Type, Action, time) VALUES('UNBAN', '%s was unbanned by %S', '%d');", *Tokens->At(1), Get_Wide_Player_Name_By_ID(ID), time(0));
	}
}

void Unban::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	Stacker<Row *> results;
	Query(&results, "SELECT * FROM Bans WHERE Nick = '%q' or IP = '%q';", *Tokens->At(1), *Tokens->At(1));
	if(results.Empty())
	{
		IRC::Send("PRIVMSG %s :A player with this name or IP was not banned.\n", Channel);
	}
	else
	{
		Query(0, "DELETE FROM Bans WHERE Nick = '%q' or IP = '%s';", *Tokens->At(1), *Tokens->At(1));
		DeleteResult(&results);

		IRC::Send("PRIVMSG %s :Deleted from database.\n", Channel);
		Query(0, "INSERT INTO Log(Type, Action, time) VALUES('UNBAN', '%s was unbanned by %s@IRC', '%d');", *Tokens->At(1), user->Nick, time(0));
	}
}

void Logsearch::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}
	Stacker<Row *> results;
	Query(&results, "SELECT * FROM Log WHERE Action LIKE '%%%s%%' LIMIT 10;", *Tokens->At(1));
	
	if(results.Empty())
	{
		IRC::Send("PRIVMSG %s :No results found.\n", Channel);
	}
	else
	{
		IterateStack(x, Row *, (&results))
		{
			const char *time = GetColumnData("time", x->Columns);
			const char *Action = GetColumnData("Action", x->Columns);
			const char *Type = GetColumnData("Type", x->Columns);

			time_t t = (time_t)atol(time);
			char buf[64];
			FormatTime(t, buf, 64);

			IRC::Send("PRIVMSG %s :[%s][%s] %s\n", Channel, buf, Type, Action);
		
		}

		DeleteResult(&results);
	}


}

void Edit::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char*> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 4)
	{
		IRCArgs;
	}

	const char *Data = Implode(Tokens, 3);
	Change(*Tokens->At(1), *Tokens->At(2), Data);

	IRC::Send("PRIVMSG %s :Edit saved.\n", Channel);

	CDealloc(Data);
}

void ShowMods::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	char modlist[256];
	strcpy(modlist, "Moderators in-game:");
	bool Found = 0;

	for(int i = 0; i < 128; i++)
	{
		Player *x = Players[i];
		if(!x)
		{
			continue;
		}
		if(GetStatus(x->Access) > 0)
		{
			Found = 1;
			if(strlen(modlist) > 128)
			{
				ConsoleInputF("msg %s", modlist);
				strcpy(modlist, "Moderators in-game:"); 
			}


			sprintf(modlist, "%s %c%s", modlist, x->Access, x->Nick);
		}
	}

	if(Found)
	{
		ConsoleInputF("msg %s", modlist);
	}
	else
	{
		ConsoleInputF("msg No moderators in-game.", modlist);
	}
}

void ShowMods::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char modlist[256];
	strcpy(modlist, "Moderators in-game:");
	bool Found = 0;

	for(int i = 0; i < 128; i++)
	{
		Player *x = Players[i];
		if(!x)
		{
			continue;
		}
		if(GetStatus(x->Access) > 0)
		{
			Found = 1;
			if(strlen(modlist) > 128)
			{
				IRC::Send("PRIVMSG %s :%s\n", Channel, modlist);
				strcpy(modlist, "Moderators in-game:"); 
			}


			sprintf(modlist, "%s %c%s", modlist, x->Access, x->Nick);
		}
	}

	if(Found)
	{
		IRC::Send("PRIVMSG %s :%s\n", Channel, modlist);
	}
	else
	{
		IRC::Send("PRIVMSG %s :No moderators in-game.\n", Channel, modlist);
	}
}

void ListPlayers::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char plist[256];
	strcpy(plist, "Players in-game:");
	bool Found = 0;

	for(int i = 0; i < 128; i++)
	{
		Player *x = Players[i];
		if(!x || !x->data->IsInGame)
		{
			continue;
		}
		Found = 1;
		if(strlen(plist) > 128)
		{
			IRC::Send("PRIVMSG %s :%s\n", Channel, plist);
			strcpy(plist, ""); 
		}
		
		if(GetStatus(x->Access) > 0)
		{
			sprintf(plist, "%s \x03%d%c%s\x03", plist, (x->data->PlayerType.Get() == 0 ? 4 : 8), x->Access, x->Nick);
		}
		else
		{
			sprintf(plist, "%s \x03%d%s\x03", plist, (x->data->PlayerType.Get() == 0 ? 4 : 8), x->Nick);
		}
	}

	if(Found)
	{
		IRC::Send("PRIVMSG %s :%s\n", Channel, plist);
	}
	else
	{
		IRC::Send("PRIVMSG %s :No players in-game.\n", Channel);
	}
}


void Mute::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "Internal error, please report.\n");
			return;
		}
		else
		{
			PPage(ret, p->Muted == 1 ? "%S has unmuted you." : "%S has muted you, you are unable to use F2 or F3", Get_Wide_Player_Name_By_ID(ID));
			PPage(ID, p->Muted == 1 ? "%S has been unmuted." : "%S has been muted.", Get_Wide_Player_Name_By_ID(ret));
			p->Muted = p->Muted == 1 ? 0 : 1;
		}
	}
}

void Mute::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			IRC::Send("PRIVMSG %s :Internal error, please report.\n", Channel);
			return;
		}
		else
		{
			PPage(ret, p->Muted == 1 ? "%s@IRC has unmuted you." : "%s@IRC has muted you, you are unable to use F2 or F3", user->Nick);
			IRC::Send(p->Muted == 1 ? "PRIVMSG %s :%S has been umuted.\n" : "PRIVMSG %s :%S has been muted.\n", Channel, Get_Wide_Player_Name_By_ID(ret));
			p->Muted = p->Muted == 1 ? 0 : 1;
		}

	}
}

void Killme::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	Attach_Script_Once(Get_GameObj(ID), "YaRRKill", "");
}

void Kill::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		PPage(ret, "%S has killed you.", Get_Wide_Player_Name_By_ID(ID));
		Attach_Script_Once(Get_GameObj(ret), "YaRRKill", "");
	}
}

void Kill::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		PPage(ret, "%s@IRC has killed you.", user->Nick);
		Attach_Script_Once(Get_GameObj(ret), "YaRRKill", "");
	}
}

void Block::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "YaRR internal error. Please report.");
			return;
		}
		bool chr = 0;
		bool veh = 0;
		bool bec = 0;

		const char *x = *(Tokens->At(2));
		int it = 2;
		while(it < Tokens->Length())
		{
			if(stricmp(x, "beacon") == 0 || stricmp(x, "bec") == 0)
			{
				bec = 1;
			}
			else if(stricmp(x, "character") == 0 || stricmp(x, "char") == 0)
			{
				chr = 1;
			}
			else if(stricmp(x, "vehicle") == 0 || stricmp(x, "veh") == 0)
			{
				veh = 1;
			}

			x = *(Tokens->At(++it));
		}
		
		p->BlockBeacons = bec;
		p->BlockCharacters = chr;
		p->BlockVehicles = veh;

		
		if(bec && chr && veh)
		{
			PPage(ret, "You have been blocked from purchasing any items.");
		}
		else
		{
			char buffer[256];
			strcpy(buffer, "");
			if(bec)
			{
				strcat(buffer, "beacons ");
			}
			if(chr)
			{
				strcat(buffer, "characters ");
			}
			if(veh)
			{
				strcat(buffer, "vehicles ");
			}

			PPage(ret, "You were blocked from purchasing: %s", buffer);
			PPage(ID, "%S was blocked from purchasing: %s", Get_Wide_Player_Name_By_ID(ret), buffer);
		}

		
	}
}

void Block::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			SendIRC("YaRR internal error. Please report.");
			return;
		}
		bool chr = 0;
		bool veh = 0;
		bool bec = 0;

		const char *x = Implode(Tokens, 2);

		if(stricmp(x, "beacon") == 0 || stricmp(x, "bec") == 0)
		{
			bec = 1;
		}
		else if(stricmp(x, "character") == 0 || stricmp(x, "char") == 0)
		{
			chr = 1;
		}
		else if(stricmp(x, "vehicle") == 0 || stricmp(x, "veh") == 0)
		{
			veh = 1;
		}
		
		p->BlockBeacons = bec;
		p->BlockCharacters = chr;
		p->BlockVehicles = veh;

		
		if(bec && chr && veh)
		{
			PPage(ret, "You have been blocked from purchasing any items.");
			IRC::Send("PRIVMSG %s :%S was blocked from purchasing any items\n", Channel, Get_Wide_Player_Name_By_ID(ret));
		}
		else
		{
			char buffer[256];
			strcpy(buffer, "");
			if(bec)
			{
				strcat(buffer, "beacons ");
			}
			if(chr)
			{
				strcat(buffer, "characters ");
			}
			if(veh)
			{
				strcat(buffer, "vehicles ");
			}

			PPage(ret, "You were blocked from purchasing: %s", buffer);
			IRC::Send("PRIVMSG %s :%S was blocked from purchasing: %s\n", Channel, Get_Wide_Player_Name_By_ID(ret), buffer);
		}

	}
}



void Unblock::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "YaRR internal error. Please report.");
			return;
		}

		char buffer[256];
		*buffer = 0;

		if(p->BlockBeacons)
		{
			p->BlockBeacons = 0;
			strcat(buffer, "beacons ");
		}
		if(p->BlockCharacters)
		{
			p->BlockCharacters = 0;
			strcat(buffer, "characters ");
		}
		if(p->BlockVehicles)
		{
			p->BlockVehicles = 0;
			strcat(buffer, "vehicles ");
		}

		if(*buffer == 0)
		{
			PPageErr(ID, "Player has nothing to unblock.");
		}
		else
		{
			PPage(ID, "%S can now purchase: %s\n", Get_Wide_Player_Name_By_ID(ret), buffer);
			PPage(ret, "You can now purchase: %s", buffer);
		}
	}
}

void Unblock::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			SendIRC("YaRR internal error. Please report.");
			return;
		}

		char buffer[256];
		*buffer = 0;

		if(p->BlockBeacons)
		{
			p->BlockBeacons = 0;
			strcat(buffer, "beacons ");
		}
		if(p->BlockCharacters)
		{
			p->BlockCharacters = 0;
			strcat(buffer, "characters ");
		}
		if(p->BlockVehicles)
		{
			p->BlockVehicles = 0;
			strcat(buffer, "vehicles ");
		}

		if(*buffer == 0)
		{
			SendIRC("Player has nothing to unblock.");
		}
		else
		{
			IRC::Send("PRIVMSG %s :%S can now purchase: %s\n", Channel, Get_Wide_Player_Name_By_ID(ret), buffer);
			PPage(ret, "You can now purchase: %s", buffer);
		}
	}
}

void Version::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	PPage(ID, "YaRR version %s written by RoShamBo.", YARR_VERSION);
}

void Version::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	IRC::Send("PRIVMSG %s :YaRR version %s written by RoShamBo.\n", Channel, YARR_VERSION);
}

void Gameover::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("gameover");
}

void Gameover::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("gameover");
}

void Restart::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("restart");
	PPage(ID, "Restarting");
}

void Restart::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("restart");
	IRC::Send("PRIVMSG %s :Restarting\n", Channel);
}

void Quit::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("quit");
	PPage(ID, "Quitting");
}

void Quit::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("quit");
	IRC::Send("PRIVMSG %s :Quitting\n", Channel);
}

void Allow::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}
	ConsoleInputF("allow %s", *Tokens->At(1));
	PPage(ID, "Allowed \"%s\"", *Tokens->At(1));
}

void Allow::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}
	ConsoleInputF("allow %s", *Tokens->At(1));
	IRC::Send("PRIVMSG %s :Allowed \"%s\"\n", Channel, *Tokens->At(1));
}


void Buildings::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char *gdi = (char *)CAlloc(1);
	char *nod = (char *)CAlloc(1);
	*gdi = 0;
	*nod = 0;


	for(GenericSLNode *x = BuildingGameObjList->HeadNode; x != 0; x = x->NodeNext)
	{
		GameObject *o = (GameObject *)x->NodeData;
		if(!o)
		{
			continue;
		}

		const char *name = GetPresetScreenName(o);
		if(!name)
		{
			continue;
		}
		float hpperc = (Commands->Get_Health(o) / Commands->Get_Max_Health(o)) * 100;
		if(hpperc == 0)
		{
			CDealloc((void *)name);
			continue;
		}

		char tmp[256];
		sprintf(tmp, "%s (%.1f%%), ", name, hpperc);

		if(Get_Object_Type(o) == 0)
		{
			nod = (char *)RAlloc((void *)nod, strlen(nod)+strlen(tmp)+1);
			strcat(nod, tmp);
		}
		else
		{
			gdi = (char *)RAlloc((void *)gdi, strlen(gdi)+strlen(tmp)+1);
			strcat(gdi, tmp);
		}
		

		CDealloc((void *)name);
	}

	if(!*gdi && !*nod)
	{
		IRC::SendC(Channel, "No buildings found in-game.");
	}
	else
	{
		gdi[strlen(gdi)-2] = 0;
		nod[strlen(nod)-2] = 0;
		IRC::SendC(Channel, "\x03%d%s", 8, gdi);
		IRC::SendC(Channel, "\x03%d%s", 4, nod);
		CDealloc((void *)gdi);
		CDealloc((void *)nod);
	}
}

void Vehicles::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char *buffer = (char *)CAlloc(1);
	*buffer = 0;


	for(GenericSLNode *x = SmartGameObjList->HeadNode; x != 0; x = x->NodeNext)
	{
		GameObject *o = (GameObject *)x->NodeData;
		if((!o || !As_VehicleGameObj(o)) || Get_Vehicle_Mode(o) == TURRET)
		{
			continue;
		}

		const char *name = GetPresetScreenName(o);
		if(!name)
		{
			continue;
		}
		float hpperc = ((Commands->Get_Health(o)+Commands->Get_Shield_Strength(o)) / (Commands->Get_Max_Health(o)+Commands->Get_Max_Shield_Strength(o))) * 100;

		char driver[64];
		*driver = 0;
		GameObject *drobj = Get_Vehicle_Driver(o);
		if(drobj)
		{
			strcat(driver, " ");
			strcat(driver, GetPlayerName(Get_Player_ID(drobj)));
		}
		char tmp[256];
		int colour = 15;
		if(Get_Object_Type(o) == 0)
		{
			colour = 4;
		}
		else if(Get_Object_Type(o) == 1)
		{
			colour = 8;
		}
		sprintf(tmp, "\x03%d%s (%.1f%%%s)\x03, ", colour, name, hpperc, driver);
		buffer = (char *)RAlloc((void *)buffer, strlen(buffer)+strlen(tmp)+1);
		strcat(buffer, tmp);

		CDealloc((void *)name);
	}

	if(strlen(buffer) == 0)
	{
		IRC::SendC(Channel, "No vehicles found in-game.");
	}
	else
	{
		buffer[strlen(buffer)-2] = 0;
		IRC::SendC(Channel, "%s", buffer);
		CDealloc((void *)buffer);
	}
}

void ForceTeamChange::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		PPage(ID, "You have changed %S to team %S", Get_Wide_Player_Name_By_ID(ret), Get_Wide_Team_Name(Get_Team(ret) == 0 ? 1 : 0));
		PPage(ret, "%S has changed you to team %S", Get_Wide_Player_Name_By_ID(ID), Get_Wide_Team_Name(Get_Team(ret) == 0 ? 1 : 0));
		ConsoleInputF("team2 %d %d", ret, Get_Team(ret) == 0 ? 1 : 0); 
	}
}

void ForceTeamChange::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		IRC::SendC(Channel, "You have changed %S to team %S", Get_Wide_Player_Name_By_ID(ret), Get_Wide_Team_Name(Get_Team(ret) == 0 ? 1 : 0));
		PPage(ret, "%s@IRC has changed you to team %S", user->Nick, Get_Wide_Team_Name(Get_Team(ret) == 0 ? 1 : 0));
		ConsoleInputF("team2 %d %d", ret, Get_Team(ret) == 0 ? 1 : 0); 
	}
}

void Bandwidth::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}
	else if(Tokens->Length() == 2)
	{
		int ret = FindPlayer((*Tokens)[1]);
		if(ret == -1)
		{
			PNOT;
		}
		else if(ret == -2)
		{
			PMANY;
		}
		else
		{
			PPage(ID, "%S's bandwidth is currently set to: %d. Ping is: %d. KBPS is: %d", Get_Wide_Player_Name_By_ID(ret), Get_Bandwidth(ret), Get_Ping(ret), Get_Kbits(ret));
		}
	}
	else if(Tokens->Length() > 2)
	{
		int ret = FindPlayer((*Tokens)[1]);
		if(ret == -1)
		{
			PNOT;
		}
		else if(ret == -2)
		{
			PMANY;
		}
		else
		{
			if(!IsNumber(*Tokens->At(2)))
			{
				PPageErr(ID, "Invalid number entered.");
				return;
			}
			else
			{
				ConsoleInputF("setbw %d %s", ret, *Tokens->At(2));
				PPage(ID, "Set %S's bandwidth to %s", Get_Wide_Player_Name_By_ID(ret), *Tokens->At(2));
			}
		}
	}
}

void Bandwidth::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}
	else if(Tokens->Length() == 2)
	{
		int ret = FindPlayer((*Tokens)[1]);
		if(ret == -1)
		{
			IRCPNOT;
		}
		else if(ret == -2)
		{
			IRCPMANY;
		}
		else
		{
			IRC::SendC(Channel, "%S's bandwidth is currently set to: %d. Ping is: %d. KBPS is: %d", Get_Wide_Player_Name_By_ID(ret), Get_Bandwidth(ret), Get_Ping(ret), Get_Kbits(ret));
		}
	}
	else if(Tokens->Length() > 2)
	{
		int ret = FindPlayer((*Tokens)[1]);
		if(ret == -1)
		{
			IRCPNOT;
		}
		else if(ret == -2)
		{
			IRCPMANY;
		}
		else
		{
			if(!IsNumber(*Tokens->At(2)))
			{
				IRC::SendC(Channel, "Invalid number entered.");
				return;
			}
			else
			{
				ConsoleInputF("setbw %d %s", ret, *Tokens->At(2));
				IRC::SendC(Channel, "Set %S's bandwidth to %s", Get_Wide_Player_Name_By_ID(ret), *Tokens->At(2));
			}
		}
	}
}

void VehicleLimit::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		PPage(ID, "Vehicle limit is: %d", Get_Vehicle_Limit());
	}
	else
	{
		if(!IsNumber(*Tokens->At(1)) || atoi(*Tokens->At(1)) > 255 || atoi(*Tokens->At(1)) < 0)
		{
			PPageErr(ID, "Invalid number entered. 0 - 255");
			
		}
		else
		{
			Set_Vehicle_Limit(atoi(*Tokens->At(1)));
			PPage(ID, "Set the vehicle limit to %s", *Tokens->At(1));
		}
	}
}

void VehicleLimit::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRC::SendC(Channel, "Vehicle limit is: %d", Get_Vehicle_Limit());
	}
	else
	{
		if(!IsNumber(*Tokens->At(1)) || atoi(*Tokens->At(1)) > 255 || atoi(*Tokens->At(1)) < 0)
		{
			IRC::SendC(Channel, "Invalid number entered. 0 - 255");
		}
		else
		{
			Set_Vehicle_Limit(atoi(*Tokens->At(1)));
			IRC::SendC(Channel, "Set the vehicle limit to %s", *Tokens->At(1));
		}
	}
}

void MineLimit::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		PPage(ID, "Mine limit is: %d", *Mine_Limit);
	}
	else
	{
		if(!IsNumber(*Tokens->At(1)) || atoi(*Tokens->At(1)) > 255 || atoi(*Tokens->At(1)) < 0)
		{
			PPageErr(ID, "Invalid number entered. 0 - 255");
			
		}
		else
		{
			ConsoleInputF("mlimit %s", *Tokens->At(1));
			PPage(ID, "Set the mine limit to %s", *Tokens->At(1));
		}
	}
}

void MineLimit::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRC::SendC(Channel, "Mine limit is: %d", *Mine_Limit);
	}
	else
	{
		if(!IsNumber(*Tokens->At(1)) || atoi(*Tokens->At(1)) > 255 || atoi(*Tokens->At(1)) < 0)
		{
			IRC::SendC(Channel, "Invalid number entered. 0 - 255");
		}
		else
		{
			ConsoleInputF("mlimit %s", *Tokens->At(1));
			IRC::SendC(Channel, "Set the mine limit to %s", *Tokens->At(1));
		}
	}
}

void AdminMessage::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}
	const char *Message = Implode(Tokens, 1);
	ConsoleInputF("amsg %s", Message);
	CDealloc(Message);
}

void AdminMessage::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	const char *Message = Implode(Tokens, 1);
	ConsoleInputF("amsg %s", Message);
	CDealloc(Message);
}

void Spectate::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	/*Player *p = Find(ID);
	if(!p)
	{
		return;
	}
	GameObject *o = Get_GameObj(ID);
	if(Tokens->Length() < 2)
	{
		if(p->Spectating)
		{
			Commands->Set_Is_Visible(o, 1);
			Commands->Destroy_Object(o);
			p->Spectating = 0;
			return;
		}
		else
		{
			Args;
		}
	}
	else
	{
		int ret = FindPlayer((*Tokens)[1]);
		if(ret == -1)
		{
			PNOT;
		}
		else if(ret == -2)
		{
			PMANY;
		}
		else
		{
			if(ret == ID)
			{
				PPageErr(ID, "You cannot spectate yourself!");
				return;
			}

			if(p->Spectating)
			{
				PPageErr(ID, "You are already spectating somebody. Use !spectate to finish.");
				return;
			}

			
			GameObject *sv = Get_GameObj(ret);
			Commands->Set_Model(o, "null");
			Commands->Clear_Weapons(o);
			Commands->Set_Is_Visible(o, 0);
			Commands->Disable_All_Collisions(o);
			Commands->Disable_Physical_Collisions(sv);
			
			Commands->Attach_To_Object_Bone(o, sv, "");
			p->Spectating = 1;
		}
	}*/
}

void PlayerAdminMessage::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		const char *Message = Implode(Tokens, 2);
		ConsoleInputF("pamsg %d %s", ret, Message);
		CDealloc(Message);
	}
}

void PlayerAdminMessage::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		const char *Message = Implode(Tokens, 2);
		ConsoleInputF("pamsg %d %s", ret, Message);
		CDealloc(Message);
	}
}

void Eject::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		GameObject *vec = Get_Vehicle(Get_GameObj(ret));
		if(!vec)
		{
			PPageErr(ID, "%S is not in a vehicle.", Get_Wide_Player_Name_By_ID(ret));
		}
		else
		{
			Soldier_Transition_Vehicle(Get_GameObj(ret));
			PPage(ID, "%S was kicked from the vehicle he was in.", Get_Wide_Player_Name_By_ID(ret));
		}
	}
}

void Eject::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		GameObject *vec = Get_Vehicle(Get_GameObj(ret));
		if(!vec)
		{
			IRC::SendC(Channel, "%S is not in a vehicle.", Get_Wide_Player_Name_By_ID(ret));
		}
		else
		{
			Soldier_Transition_Vehicle(Get_GameObj(ret));
			IRC::SendC(Channel, "%S was kicked from the vehicle he was in.", Get_Wide_Player_Name_By_ID(ret));
		}
	}
}

void Stats::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			return;
		}
		char TimeStr[256];
		FormatTime((time_t)p->data->GameTime, "%H:%M:%S", TimeStr, 256);
		IRC::SendC(Channel, "\x03%dStats for %S: Scripts: %.2f YaRR points: %d Kills: %d Deaths: %d Money: %.0f Ping: %d Total time: %s\x03", Get_Team(p->ID) == 0 ? 4 : 8, Get_Wide_Player_Name_By_ID(ret), p->BHS, p->Points, p->data->Kills.Get(), p->data->Deaths.Get(), p->data->Money.Get(), p->data->Ping, TimeStr);
	}
}

void Rotation::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	char *rot = (char *)CAlloc(1);
	for(int i = 0; (i < 100) && (*The_Game()->MapList[i] != 0); i++)
	{
		if(strlen(rot)+strlen(The_Game()->MapList[i])+2 > 75)
		{
			PPage(ID, "%s", rot);
			rot = (char *)RAlloc((void *)rot, 1);
			*rot = 0;
		}
		if(strcmp(The_Game()->MapName, The_Game()->MapList[i]) == 0)
		{
			rot = (char *)RAlloc((void *)rot, strlen(rot)+strlen(The_Game()->MapList[i])+4);
			strcat(rot, "[");
			strcat(rot, The_Game()->MapList[i]);
			strcat(rot, "] ");
		}
		else
		{
			rot = (char *)RAlloc((void *)rot, strlen(rot)+strlen(The_Game()->MapList[i])+2);
			strcat(rot, The_Game()->MapList[i]);
			strcat(rot, " ");
		}
	}
	if(*rot != 0)
	{
		PPage(ID, "%s", rot);
	}
	CDealloc((void *)rot);
}

void Rotation::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char *rot = (char *)CAlloc(1);
	for(int i = 0; (i < 100) && (*The_Game()->MapList[i] != 0); i++)
	{
		if(strlen(rot)+strlen(The_Game()->MapList[i])+2 > 75)
		{
			IRC::SendC(Channel, "%s", rot);
			rot = (char *)RAlloc((void *)rot, 1);
			*rot = 0;
		}
		if(strcmp(The_Game()->MapName, The_Game()->MapList[i]) == 0)
		{
			rot = (char *)RAlloc((void *)rot, strlen(rot)+strlen(The_Game()->MapList[i])+4);
			strcat(rot, "[");
			strcat(rot, The_Game()->MapList[i]);
			strcat(rot, "] ");
		}
		else
		{
			rot = (char *)RAlloc((void *)rot, strlen(rot)+strlen(The_Game()->MapList[i])+2);
			strcat(rot, The_Game()->MapList[i]);
			strcat(rot, " ");
		}
	}
	if(*rot != 0)
	{
		IRC::SendC(Channel, "%s", rot);
	}
	CDealloc((void *)rot);
}

void Nextmap::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	PPage(ID, "The next map will be: %s", (*The_Game()->MapList[The_Game()->MapNumber+1]) == 0 ? The_Game()->MapList[0] : The_Game()->MapList[The_Game()->MapNumber+1]);
}

void Nextmap::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	IRC::SendC(Channel, "The next map will be: %s", (*The_Game()->MapList[The_Game()->MapNumber+1]) == 0 ? The_Game()->MapList[0] : The_Game()->MapList[The_Game()->MapNumber+1]);
}

void Refund::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		if(!IsNumber((*Tokens)[2]))
		{
			PPageErr(ID, "Invalid number");
			return;
		}
		PPage(ID, "You have refunded %S with %s credits", Get_Wide_Player_Name_By_ID(ret), (*Tokens)[2]);
		PPage(ret, "%S has refunded you with %s credits", Get_Wide_Player_Name_By_ID(ID), (*Tokens)[2]);
		Set_Money(ret, Get_Money(ret)+atoi((*Tokens)[2]));
	}
}

void Refund::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;

	if(Tokens->Length() < 3)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		if(!IsNumber((*Tokens)[2]))
		{
			IRC::SendC(Channel, "Invalid number");
			return;
		}
		IRC::SendC(Channel, "You have refunded %S with %s credits", Get_Wide_Player_Name_By_ID(ret), (*Tokens)[2]);
		PPage(ret, "%s@IRC has refunded you with %s credits", user->Nick, (*Tokens)[2]);
		Set_Money(ret, Get_Money(ret)+atoi((*Tokens)[2]));
	}
}

void DestroyVehicle::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		GameObject *vec = Get_Vehicle(Get_GameObj(ret));
		if(vec)
		{
			PPage(ret, "Your vehicle was destroyed by %S.", Get_Wide_Player_Name_By_ID(ID));
			PPage(ID, "You destroyed %S's vehicle", Get_Wide_Player_Name_By_ID(ret));
			Commands->Apply_Damage(vec, 9999.9, "blamokiller", NULL);
		}
		else
		{
			PPageErr(ID, "%S isn't in a vehicle.", Get_Wide_Player_Name_By_ID(ret));
		}
	}
}

void DestroyVehicle::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		GameObject *vec = Get_Vehicle(Get_GameObj(ret));
		if(vec)
		{
			PPage(ret, "Your vehicle was destroyed by %s@IRC.", user->Nick);
			IRC::SendC(Channel, "You destroyed %S's vehicle", Get_Wide_Player_Name_By_ID(ret));
			Commands->Apply_Damage(vec, 9999.9, "blamokiller", NULL);
		}
		else
		{
			IRC::SendC(Channel, "%S isn't in a vehicle.", Get_Wide_Player_Name_By_ID(ret));
		}
	}
}

void DeleteTempModerator::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Moderator m;
		ModeratorList->Reset();
		while(ModeratorList->Iterate(&m))
		{
			if(strcmp(m.Nick, GetPlayerName(ret)) == 0)
			{
				PPageErr(ID, "You cannot remove status from a moderator.");
				return;
			}
		}

		Player *p = Find(ret);
		if(p->Access != '%')
		{
			PPageErr(ID, "This player isn't a temporary moderator.");
			return;
		}
		else
		{
			p->Access = 'p';
			ConsoleInputF("msg %S is no longer a temporary moderator", Get_Wide_Player_Name_By_ID(ret));
		}
	}
}

void DeleteTempModerator::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Moderator m;
		ModeratorList->Reset();
		while(ModeratorList->Iterate(&m))
		{
			if(strcmp(m.Nick, GetPlayerName(ret)) == 0)
			{
				IRC::SendC(Channel, "You cannot remove status from a moderator.");
				return;
			}
		}

				Player *p = Find(ret);
		if(p->Access != '%')
		{
			IRC::SendC(Channel, "This player isn't a temporary moderator.");
			return;
		}
		else
		{
			p->Access = 'p';
			ConsoleInputF("msg %S is no longer a temporary moderator", Get_Wide_Player_Name_By_ID(ret));
		}
	}
}

void AddTempModerator::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "Internal error, please report.");
			return;
		}
		Moderator m;
		ModeratorList->Reset();
		while(ModeratorList->Iterate(&m))
		{
			if(strcmp(m.Nick, p->Nick) == 0)
			{
				PPageErr(ID, "%s is a moderator already! He should use !auth.", p->Nick);
				return;
			}
		}		
		p->Access = '%';
		ConsoleInputF("msg %s has been made a temporary moderator.", p->Nick);
	}
}

void AddTempModerator::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			IRC::SendC(Channel, "Internal error, please report.");
			return;
		}
		Moderator m;
		ModeratorList->Reset();
		while(ModeratorList->Iterate(&m))
		{
			if(strcmp(m.Nick, p->Nick) == 0)
			{
				IRC::SendC(Channel, "%s is a moderator already! He should use !auth.", p->Nick);
				return;
			}
		}		
		p->Access = '%';
		ConsoleInputF("msg %s has been made a temporary moderator.", p->Nick);
	}
}

void PlayerInfo::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	bool tmp = 0;
	for(int i = 0; i < 128; i++)
	{
		if(Players[i] != 0)
		{
			tmp = 1;
			Player *p = Players[i];
			char TimeStr[256];
			FormatTime((time_t)p->data->GameTime, "%H:%M:%S", TimeStr, 256);
			IRC::SendC(Channel, "\x03%d%S: Scripts: %.2f YaRR points: %d Kills: %d Deaths: %d Money: %.0f Ping: %d Total time: %s\x03", Get_Team(p->ID) == 0 ? 4 : 8, Get_Wide_Player_Name_By_ID(p->ID), p->BHS, p->Points, p->data->Kills.Get(), p->data->Deaths.Get(), p->data->Money.Get(), p->data->Ping, TimeStr);
		}
	}
	if(!tmp)
	{
		IRC::SendC(Channel, "There are no players in-game.");
	}
}

void ModList::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	bool tmp = 0;
	Moderator m;
	ModeratorList->Reset();
	while(ModeratorList->Iterate(&m))
	{
		tmp = 1;
		IRC::SendC(Channel, "In-Game: %s  IRC: %s  Status: %c", m.Nick, m.IRCNick, m.Access);
	}
	if(!tmp)
	{
		IRC::SendC(Channel, "No moderators found.");
	}
}

void Rules::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("msg %s", GlobRules);
	ConsoleInputF("msg Map rules: %s", MapRules);
}

void Rules::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	ConsoleInputF("msg %s", GlobRules);
	ConsoleInputF("msg Map rules: %s", MapRules);
}

void Shun::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "Internal error, please report.");
			return;
		}

		if(p->Shunned == 1)
		{
			PPageErr(ID, "Player is already shunned");
			return;
		}
		else
		{
			p->Shunned = 1;
			PPage(ID, "Player %S has been shunned", Get_Wide_Player_Name_By_ID(ret));
			PPage(ret, "You have been shunned by %S. You cannot use any commands.", Get_Wide_Player_Name_By_ID(ID));
		}
			
	}
}

void Shun::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			IRC::SendC(Channel, "Internal error, please report.");
			return;
		}

		if(p->Shunned == 1)
		{
			IRC::SendC(Channel, "Player is already shunned");
			return;
		}
		else
		{
			p->Shunned = 1;
			IRC::SendC(Channel, "Player %S has been shunned", Get_Wide_Player_Name_By_ID(ret));
			PPage(ret, "You have been shunned by %s@IRC. You cannot use any commands.", user->Nick);
		}
	}
}

void Unshun::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "Internal error, please report.");
			return;
		}

		if(p->Shunned == 0)
		{
			PPageErr(ID, "Player isn't shunned");
			return;
		}
		else
		{
			p->Shunned = 0;
			PPage(ID, "Player %S has been unshunned", Get_Wide_Player_Name_By_ID(ret));
			PPage(ret, "You have been unshunned by %S. You can use commands again.", Get_Wide_Player_Name_By_ID(ID));
		}
	}
}

void Unshun::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			IRC::SendC(Channel, "Internal error, please report.");
			return;
		}

		if(p->Shunned == 0)
		{
			IRC::SendC(Channel, "Player isn't shunned");
			return;
		}
		else
		{
			p->Shunned = 0;
			IRC::SendC(Channel, "Player %S has been unshunned", Get_Wide_Player_Name_By_ID(ret));
			PPage(ret, "You have been unshunned by %s@IRC. You can use commands again.", user->Nick);
		}
	}
}

void SetNextMap::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}
	
	for(int i = 0; i < 100; i++)
	{
		if(stristr(The_Game()->MapList[i], (*Tokens)[1]))
		{
			The_Game()->MapNumber = i-1;
			ConsoleInputF("msg Next map will be: %s", The_Game()->MapList[i]);
			return;
		}
	}
	PPageErr(ID, "Map not found.");
}	

void SetNextMap::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}
	
	for(int i = 0; i < 100; i++)
	{
		if(stristr(The_Game()->MapList[i], (*Tokens)[1]))
		{
			The_Game()->MapNumber = i-1;
			ConsoleInputF("msg Next map will be: %s", The_Game()->MapList[i]);
			return;
		}
	}
	IRC::SendC(Channel, "Map not found.");
}

void Banlog::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	Stacker<Row *> Result;
	Query(&Result, "SELECT * FROM Log WHERE Type = 'BAN' ORDER BY Time DESC LIMIT 5 ;");
	IterateStack(r, Row *, (&Result))
	{
		IRC::SendC(Channel, "%s", GetColumnData("Action", r->Columns));
	}
}

void Donate::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		if(!IsNumber((*Tokens)[2]))
		{
			PPageErr(ID, "Not a valid amount.");
			return;
		}

		int Amount = atoi((*Tokens)[2]);

		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "Internal YaRR error, please report");
			return;
		}

		if(Get_Team(p->ID) != Get_Team(ID))
		{
			PPageErr(ID, "%s is not on your team.", p->Nick);
			return;
		}

		if(p->ID == ID)
		{
			PPageErr(ID, "You cannot donate to yourself!");
			return;
		}

		if(!Purchase_Item(Get_GameObj(ID), Amount))
		{
			PPageErr(ID, "You don't have enough credits.");
			return;
		}

		p->data->Increment_Money((float)Amount);

		PPage(ID, "You have donated %d to %s", Amount, p->Nick);
		PPage(ret, "%S has donated %d to you", Get_Wide_Player_Name_By_ID(ID), Amount);
	}
}

void SellVehicle::Activate(int ID, int Type, Stacker<char *> *Tokens)
{

	DLOG;
}

void Rehash::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	UnloadGlob();
	LoadGlob();

	YaRRStrings::Shutdown();
	YaRRStrings::Startup();

	PPage(ID, "Rehashed");
}

void Rehash::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	UnloadGlob();
	LoadGlob();

	YaRRStrings::Shutdown();
	YaRRStrings::Startup();

	IRC::SendC(Channel, "Rehashed");
}

void Raw::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}
	const char *Msg = Implode(Tokens, 1);
	IRC::Send("%s\n", Msg);
	CDealloc(Msg);
}

void Raw::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	const char *Msg = Implode(Tokens, 1);
	IRC::Send("%s\n", Msg);
	CDealloc(Msg);
}

void Stop::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	Pause();
}

void Stop::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	Pause();
}

void Start::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	Resume();
}

void Start::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	Resume();
}

void Zero::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "Internal error. Please report.");
			return;
		}

		p->Points = 0;
		int s = 0;
		float s_ = 0;
		p->data->Score.Set(s_);
		p->data->Deaths.Set(s);
		p->data->EnemiesKilled = 0;
		p->data->Kills.Set(s);

		PPage(ret, "%S has set your score to zero.", Get_Wide_Player_Name_By_ID(ID));
		PPage(ID, "You have set %S's score to zero.", Get_Wide_Player_Name_By_ID(ret));
	}
}

void Zero::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			IRC::SendC(Channel, "\x03%dInternal error. Please report.", 4);
			return;
		}

		p->Points = 0;
		int s = 0;
		float s_ = 0;
		p->data->Score.Set(s_);
		p->data->Deaths.Set(s);
		p->data->EnemiesKilled = 0;
		p->data->Kills.Set(s);

		PPage(ret, "%s@irc has set your score to zero.", user->Nick);
		IRC::SendC(Channel, "You have set %S's score to zero.", Get_Wide_Player_Name_By_ID(ret));
	}
}

void Server::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	time_t t_ = time(0)-YaRRGlobal::StartTime;
	int Seconds = (int)(t_ % 60);
	int Minutes = (int)((t_ / 60) % 60);
	int Hours = (int)((t_ /(60 * 60)) % 24);
	int Days = (int)(t_ / (60 * 60 * 24));
	PPage(ID, "\x03%d%S : %S : Uptime %d day%s %d hour%s, %d minute%s and %d second%s.", 3, (const wchar_t *)The_Game()->Owner, (const wchar_t *)The_Game()->GameTitle, Days, Days == 1 ? "" : "s", Hours, Hours == 1 ? "" : "s", Minutes, Minutes == 1 ? "" : "s", Seconds, Seconds == 1 ? "" : "s");
}

void Server::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	time_t t_ = time(0)-YaRRGlobal::StartTime;
	int Seconds = (int)(t_ % 60);
	int Minutes = (int)((t_ / 60) % 60);
	int Hours = (int)((t_ /(60 * 60)) % 24);
	int Days = (int)(t_ / (60 * 60 * 24));
	IRC::SendC(Channel, "\x03%d%S : %S : Uptime %d day%s %d hour%s, %d minute%s and %d second%s.", 3, (const wchar_t *)The_Game()->Owner, (const wchar_t *)The_Game()->GameTitle, Days, Days == 1 ? "" : "s", Hours, Hours == 1 ? "" : "s", Minutes, Minutes == 1 ? "" : "s", Seconds, Seconds == 1 ? "" : "s");
}


void Website_::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	PPage(ID, "%s", YaRRSettings::Website);
}

void Website_::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	IRC::SendC(Channel, "%s", YaRRSettings::Website);
}

void Page::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	const char *Message = Implode(Tokens, 2);
	ConsoleInputF("page %s %s", *Tokens->At(1), Message);
	CDealloc(Message);
}

void Page::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		IRCArgs;
	}

	const char *Message = Implode(Tokens, 2);
	ConsoleInputF("page %s %s", *Tokens->At(1), Message);
	CDealloc(Message);
}

void Viewjoin::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	Stacker<Row *> result;
	Player *p = Find(ID);
	if(!p)
	{
		PPageErr(ID, "Internal error, please report");
		return;
	}
	YaRRDatabase::Query(&result, "SELECT JOINMSG FROM Players WHERE Nick = '%q';", p->Nick);
	char *jm = GetColumnData("JOINMSG", result[0]->Columns);
	if(result.Empty() || !*jm)
	{
		PPage(ID, "You have no join message set.");
	}
	else
	{
		PPage(ID, "Your join message is: %s", jm);
	}
	DeleteResult(&result);
}

void Viewjoin::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	Stacker<Row *> result;
	YaRRDatabase::Query(&result, "SELECT JOINMSG FROM Players WHERE Nick = '%q';", *Tokens->At(1));
	char *jm = GetColumnData("JOINMSG", result[0]->Columns);
	if(result.Empty() || !*jm)
	{
		IRC::SendC(Channel, "%s has no join message set.", *Tokens->At(1));
	}
	else
	{
		IRC::SendC(Channel, "%s's join message is: %s", *Tokens->At(1), jm);
	}
	DeleteResult(&result);
}

void Time::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	char buffer[256];
	FormatTime(time(0), buffer, 256);
	PPage(ID, "Server local time: %s", buffer);
}

void Time::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char buffer[256];
	FormatTime(time(0), buffer, 256);
	IRC::SendC(Channel, "Server local time: %s", buffer);
}

void Eteam::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	int cGDI = GetTeamPlayerCount(1);
	int cNod = GetTeamPlayerCount(0);
	int diff = cGDI < cNod ? cNod-cGDI : cGDI-cNod;
	bool changed = 0;
	if(diff > 2)
	{
		bool even = Get_Player_Count() % 2 == 1 ? 1 : 0;
		for(int i = 0; i < diff-(even == 0 ? 2 : 1); i++)
		{
			int LowestID = 0;
			for(GenericSLNode *x = PlayerList->HeadNode; x != 0; x = x->NodeNext)
			{
				cPlayer *p = (cPlayer *)x->NodeData;
				if(!p->IsInGame || Get_Team(p->PlayerId) != (cGDI > cNod ? 1 : 0))
				{
					continue;
				}
				if(LowestID == 0 || p->Score.Get() < Get_Score(LowestID))
				{
					LowestID = p->PlayerId;
				}
			}
			Change_Player_Team(Get_GameObj(LowestID), 1, 1, 0);
			PPage(LowestID, "You have been moved to %S to even the teams.", Get_Wide_Team_Name((cGDI > cNod ? 1 : 0)));
			changed = 1;
		}
	}
	if(changed)
	{
		PPage(ID, "Teams were evened");
	}
	else
	{
		PPageErr(ID, "Teams are already even");
	}
}

void Eteam::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	int cGDI = GetTeamPlayerCount(1);
	int cNod = GetTeamPlayerCount(0);
	int diff = cGDI < cNod ? cNod-cGDI : cGDI-cNod;
	bool changed = 0;
	if(diff > 2)
	{
		bool even = Get_Player_Count() % 2 == 1 ? 1 : 0;
		for(int i = 0; i < diff-(even == 0 ? 2 : 1); i++)
		{
			int LowestID = 0;
			for(GenericSLNode *x = PlayerList->HeadNode; x != 0; x = x->NodeNext)
			{
				cPlayer *p = (cPlayer *)x->NodeData;
				if(!p->IsInGame || Get_Team(p->PlayerId) != (cGDI > cNod ? 1 : 0))
				{
					continue;
				}
				if(LowestID == 0 || p->Score.Get() < Get_Score(LowestID))
				{
					LowestID = p->PlayerId;
				}
			}
			Change_Player_Team(Get_GameObj(LowestID), 1, 1, 0);
			PPage(LowestID, "You have been moved to %S to even the teams.", Get_Wide_Team_Name((cGDI > cNod ? 1 : 0)));
			changed = 1;
		}
	}
	if(changed)
	{
		IRC::SendC(Channel, "Teams were evened");
	}
	else
	{
		IRC::SendC(Channel, "Teams are already even");
	}
}

void Ping::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	PPage(ID, "Your ping is: %ld", Get_Ping(ID));
}

void Ping::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	int count = 0;
	int total = 0;
	for(int i = 0; i < 128; i++)
	{
		if(Players[i] != 0)
		{
			count += Get_Ping(i);
			total++;
		}
	}
	if(count != 0)
	{
		IRC::SendC(Channel, "Average ping: %.1f", (float)(count/total));
	}
	else
	{
		IRC::SendC(Channel, "No players in-game");
	}
}

void Tdonate::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int Amount = atoi(*Tokens->At(1));
	if(Amount == 0)
	{
		if(stricmp(*Tokens->At(1), "all") == 0)
		{
			Amount = (int)Get_Money(ID);
			if(Amount == 0)
			{
				PPageErr(ID, "You don't have enough money.");
				return;
			}
		}
		if(stricmp(*Tokens->At(1), "half") == 0)
		{
			Amount = (int)Get_Money(ID);
			if(Amount == 0)
			{
				PPageErr(ID, "You don't have enough money.");
				return;
			}
			if(Amount % 2 != 0)
			{
				Amount++;
			}
			Amount /= 2;
		}
		PPageErr(ID, "Invalid amount");
		return;
	}

	Player *p = Find(ID);
	if(!p)
	{
		PPageErr(ID, "Internal error, please report.");
		return;
	}

	if(Amount < p->data->Money.Get())
	{
		PPageErr(ID, "You don't have enough money.");
		return;
	}

	int tcount = GetPCount(Get_Team(ID));
	float tam = floor((float)(Amount/(tcount-1)));

	for (GenericSLNode* x = PlayerList->HeadNode; x != 0; x = x->NodeNext)
	{
		cPlayer *p = (cPlayer *)x->NodeData;
		if (!p->IsActive)
		{
			continue;
		}
		if((Commands->Get_Player_Type((GameObject *)p->Owner.Reference->obj) == Get_Team(ID)) && p->PlayerId != ID)
		{
			p->Increment_Money(tam);
			PPage(p->PlayerId, "%s has donated %.0f to you.", tam);
		}
	}

	PPage(ID, "You have donated %d to your team.", Amount);
}

void SetColour::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	Player *p = Find(ID);
	if(!p)
	{
		PPage(ID, "Internal error, please report.");
		return;
	}
	const char *tok = *Tokens->At(1);
	if(stricmp(tok, "default") == 0)
	{
		char hex[32];
		RGBToHex(YaRRSettings::MessageColour, hex);
		Query(0, "UPDATE Players SET PPageC = '%q' WHERE Nick = '%q';", hex, p->Nick);
		p->PPageColour = YaRRSettings::MessageColour;
	}
	else
	{
		Colour::CRGB rgb;
		if(!HexToRGB(&rgb, *Tokens->At(1)))
		{
			PPage(ID, "Invalid colour, please use HTML style colour codes.");
			return;
		}
		Query(0, "UPDATE Players SET PPageC = '%q' WHERE Nick = '%q';", *Tokens->At(1), p->Nick);
		p->PPageColour = rgb;						
	}
}

void SetSound::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	Player *p = Find(ID);
	if(!p)
	{
		PPage(ID, "Internal error, please report.");
		return;
	}

	const char *tok = *Tokens->At(1);
	if(stricmp(tok, "default") == 0)
	{
		Query(0, "UPDATE Players SET PPageS = '%q' WHERE Nick = '%q';", YaRRSettings::PPageSound, p->Nick);
		strcpy(p->PPageSound, YaRRSettings::PPageSound);
	}
	else
	{
		Query(0, "UPDATE Players SET PPageS = '%q' WHERE Nick = '%q';", tok, p->Nick);
		strcpy(p->PPageSound, tok);
	}
}

void Disarm::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		PPage(ret, "All your C4 and beacons have been disarmed by %S", Get_Wide_Player_Name_By_ID(ID));
		PPage(ID, "All of %S's C4 and beacons have been disarmed.", Get_Wide_Player_Name_By_ID(ret));
		Disarm_All_C4(ret);
		Disarm_All_Proxy_C4(ret);
		Disarm_Beacons(ret);
	}

}

void Disarm::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}
	
	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		PPage(ret, "All your C4 and beacons have been disarmed by %s@IRC", user->Nick);
		IRC::SendC(Channel, "All of %S's C4 and beacons have been disarmed.", Get_Wide_Player_Name_By_ID(ret));
		Disarm_All_C4(ret);
		Disarm_All_Proxy_C4(ret);
		Disarm_Beacons(ret);

	}	
}

void RequestTeamChange::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	int Team = Get_Team(ID);
	if(Team != 0 || Team != 1)
	{
		PPage(ID, "You are not on any changeable teams.");
		return;
	}
	Stacker<int> *pteam = Team == 0 ? YaRRGlobal::NodTeamChange : YaRRGlobal::GDITeamChange;
	Stacker<int> *oteam = Team == 1 ? YaRRGlobal::NodTeamChange : YaRRGlobal::GDITeamChange;

	IterateStack(x, int, pteam)
	{
		if(x == ID)
		{
			PPage(ID, "You are already in the queue to change teams.");
			return;
		}
	}

	if(oteam->Length() == 0)
	{
		PPage(ID, "You will change over as soon as a place is avaliable.");
		pteam->Push(ID);
		return;
	}
	else
	{
		oteam->Reset();
		int i = 0;
		oteam->Iterate(&i);

		ConsoleInputF("team2 %d %d", ID, Team == 1 ? 0 : 1);
		ConsoleInputF("team2 %d %d", i, Team);

		PPage(ID, "You have swapped places with %S", Get_Wide_Player_Name_By_ID(i));
		PPage(i, "You have swapped places with %S", Get_Wide_Player_Name_By_ID(ID));

		Disarm_All_C4(i);
		Disarm_All_Proxy_C4(i);
		Disarm_Beacons(i);
		Disarm_All_C4(ID);
		Disarm_All_Proxy_C4(ID);
		Disarm_Beacons(ID);
	}
}

void NodeBan::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		PNOT;
	}
	else if(ret == -2)
	{
		PMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPageErr(ID, "Internal error, please report.");
			return;
		}

		if(*p->Node == 0)
		{
			PPageErr(ID, "YaRR was unable to retreive %s's node, sorry.", p->Nick);
			return;
		}

		const char *Reason;
		if(Tokens->Length() >= 2)
		{
			Reason = Implode(Tokens, 2);
		}
		else
		{
			Reason = strdup2("None");
		}

		Stacker<Row *> Result;
		Query(&Result, "SELECT * FROM NodeBans WHERE Node = '%q';", p->Node);
		if(!Result.Empty())
		{
			PPageErr(ID, "This node is already banned.");
			PPage(ID, "Ban ID: %.3d Nick: %s Node: %s By: %s on %s for: \"%s\"", GetColumnData("uID", Result[0]->Columns), GetColumnData("Nick", Result[0]->Columns), GetColumnData("Node", Result[0]->Columns), GetColumnData("Banner", Result[0]->Columns), GetColumnData("Date", Result[0]->Columns), GetColumnData("Reason", Result[0]->Columns));
			DeleteResult(&Result);
			return;
		}

		char Date[256];
		FormatTime(time(0), "%x", Date, 256);
		Query(0, "INSERT INTO NodeBans(Nick, Node, Reason, Banner, Date) VALUES('%q', '%q', '%q', '%q', '%q');", p->Nick, p->Node, Reason, GetPlayerName(ID), Date);
		Query(0, "INSERT INTO Log(Type, Action, time) VALUES('NODEBAN', '%s was banned by %s for: %s', '%s');", p->Nick, GetPlayerName(ID), Reason);

		Query(&Result, "SELECT COUNT(*) FROM NodeBans;");
		PPage(ID, "Ban ID: %.3d added for %s. Node: %s. Reason: \"%s\"", atoi(GetColumnData("COUNT(*)", Result[0]->Columns)), p->Nick, p->Node, Reason);
		BootPlayer(ret, "You were banned by %s for: %s", GetPlayerName(ID), Reason);
		
		ConsoleInputF("msg %s was kicked from the game (banned)", p->Nick);
		CDealloc(Reason);
		DeleteResult(&Result);
	}
}

void NodeBan::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRCPNOT;
	}
	else if(ret == -2)
	{
		IRCPMANY;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			IRC::SendC(Channel, "Internal error, please report.");
			return;
		}

		if(*p->Node == 0)
		{
			IRC::SendC(Channel, "YaRR was unable to retreive %s's node, sorry.", p->Nick);
			return;
		}

		const char *Reason;
		if(Tokens->Length() > 2)
		{
			Reason = Implode(Tokens, 2);
		}
		else
		{
			Reason = strdup2("None");
		}

		Stacker<Row *> Result;
		Query(&Result, "SELECT * FROM NodeBans WHERE Node = '%q';", p->Node);
		if(!Result.Empty())
		{
			IRC::SendC(Channel, "This node is already banned.");
			IRC::SendC(Channel, "Ban ID: %.3d Nick: %s Node: %s By: %s on %s for: \"%s\"", GetColumnData("uID", Result[0]->Columns), GetColumnData("Nick", Result[0]->Columns), GetColumnData("Node", Result[0]->Columns), GetColumnData("Banner", Result[0]->Columns), GetColumnData("Date", Result[0]->Columns), GetColumnData("Reason", Result[0]->Columns));
			DeleteResult(&Result);
			return;
		}

		char Date[256];
		FormatTime(time(0), "%x", Date, 256);
		Query(0, "INSERT INTO NodeBans(Nick, Node, Reason, Banner, Date) VALUES('%q', '%q', '%q', '%q@IRC', '%q');", p->Nick, p->Node, Reason, user->Nick, Date);
		Query(0, "INSERT INTO Log(Type, Action, time) VALUES('NODEBAN', '%s was banned by %s@IRC for: %s', '%s');", p->Nick, user->Nick, Reason);

		Query(&Result, "SELECT COUNT(*) FROM NodeBans;");
		IRC::SendC(Channel, "Ban ID: %.3d added for %s. Node: %s. Reason: \"%s\"", atoi(GetColumnData("COUNT(*)", Result[0]->Columns)), p->Nick, p->Node, Reason);
		BootPlayer(ret, "You were banned by %s@IRC for: %s", user->Nick, Reason);
		ConsoleInputF("msg %s was kicked from the game (banned)", p->Nick);
		CDealloc(Reason);
		DeleteResult(&Result);
	}
}

void FindNodeBan::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}
	
	Stacker<Row *> Result;
	Query(&Result, "SELECT * FROM NodeBans WHERE Nick LIKE '%%%q%%' OR Node LIKE '%%%q%%' LIMIT 10;", *Tokens->At(1), *Tokens->At(1));
	if(Result.Empty())
	{
		IRC::SendC(Channel, "No results found.");
		return;
	}

	IRC::SendC(Channel, "Found %d result%s.", Result.Length(), Result.Length() == 1 ? "" : "s");
	IterateStack(r, Row *, (&Result))
	{
		IRC::SendC(Channel, "ID: %.3d Nick: %s Node: %s By: %s Date: %s Reason: %s", atoi(GetColumnData("uID", r->Columns)), GetColumnData("Nick", r->Columns), GetColumnData("Node", r->Columns), GetColumnData("Banner", r->Columns), GetColumnData("Date", r->Columns), GetColumnData("Reason", r->Columns));
	}
}

void DeleteNodeBan::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	const char  *t = *Tokens->At(1);
	Stacker<Row *> Result;
	Query(&Result, "SELECT * FROM NodeBans WHERE uID = %d OR Nick LIKE '%%%q%%' OR Node = '%q';", t, t, t);
	if(Result.Empty())
	{
		PPageErr(ID, "No bans matching your search found");
	}
	else if(Result.Length() > 1)
	{
		PPageErr(ID, "More than 1 ban found. Please refine your search.");
	}
	else
	{
		Query(0, "DELETE FROM NodeBans WHERE uID = %s", GetColumnData("uID", Result[0]->Columns));
		PPage(ID, "Ban ID: %s Nick: %s was lifted.", GetColumnData("uID", Result[0]->Columns), GetColumnData("Nick", Result[0]->Columns));
	}
	DeleteResult(&Result);
	
}

void DeleteNodeBan::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	const char  *t = *Tokens->At(1);
	Stacker<Row *> Result;
	Query(&Result, "SELECT * FROM NodeBans WHERE uID = %d OR Nick LIKE '%%%q%%' OR Node = '%q';", t, t, t);
	if(Result.Empty())
	{
		IRC::SendC(Channel, "No bans matching your search found");
	}
	else if(Result.Length() > 1)
	{
		IRC::SendC(Channel, "More than 1 ban found. Please refine your search.");
	}
	else
	{
		Query(0, "DELETE FROM NodeBans WHERE uID = %s", GetColumnData("uID", Result[0]->Columns));
		IRC::SendC(Channel, "Ban ID: %s Nick: %s was lifted.", GetColumnData("uID", Result[0]->Columns), GetColumnData("Nick", Result[0]->Columns));
	}
	DeleteResult(&Result);
}

void SetGlobal::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		Args;
	}

	const char *data = Implode(Tokens, 2);

	IterateStack(g, Global, YaRRGlobal::Globals)
	{
		if(strcmp(g.Name, *Tokens->At(1)) == 0)
		{
			if(g.Protected)
			{
				PPageErr(ID, "You cannot change this global.");
				CDealloc(data);
				return;
			}
			g.Data = RAlloc(g.Data, strlen(data)+1);
			strcpy((char *)g.Data, data);
			PPage(ID, "Overwritten global \"%s\"", g.Name);
			CDealloc(data);
			return;
		}
	}
	
	Global glob;
	strcpy(glob.Name, *Tokens->At(1));
	glob.Data = CAlloc(strlen(data)+1);
	glob.Protected = 0;
	strcpy((char *)glob.Data, data);
	YaRRGlobal::Globals->Push(glob);
}

void SetGlobal::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 3)
	{
		IRCArgs;
	}

	const char *data = Implode(Tokens, 2);

	IterateStack(g, Global, YaRRGlobal::Globals)
	{
		if(strcmp(g.Name, *Tokens->At(1)) == 0)
		{
			if(g.Protected)
			{
				IRC::SendC(Channel, "You cannot change this global.");
				CDealloc(data);
				return;
			}
			g.Data = RAlloc(g.Data, strlen(data)+1);
			strcpy((char *)g.Data, data);
			IRC::SendC(Channel, "Overwritten global \"%s\"", g.Name);
			CDealloc(data);
			return;
		}
	}
	
	Global glob;
	strcpy(glob.Name, *Tokens->At(1));
	glob.Data = CAlloc(strlen(data)+1);
	glob.Protected = 0;
	strcpy((char *)glob.Data, data);
	YaRRGlobal::Globals->Push(glob);
	IRC::SendC(Channel, "New global \"%s\" created.", glob.Name);
}

void GetGlobal::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}

	IterateStack(g, Global, YaRRGlobal::Globals)
	{
		if(strcmp(g.Name, *Tokens->At(1)) == 0)
		{
			int off = 0;
			if(strcmp(g.Name, "MostKills") == 0)
			{
				off = 4;
			}
			if(strcmp(g.Name, "MostDeaths") == 0)
			{
				off = 4;
			}
			if(strcmp(g.Name, "VehiclesDestroyed") == 0)
			{
				off = 4;
			}
			if(strcmp(g.Name, "MVP") == 0)
			{
				off = 4;
			}
			PPage(ID, "%s: %s", g.Name, (char *)g.Data+off);
			return;
		}
	}

	PPage(ID, "No global with this name found.", g.Name, g.Data);
}

void GetGlobal::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	IterateStack(g, Global, YaRRGlobal::Globals)
	{
		if(strcmp(g.Name, *Tokens->At(1)) == 0)
		{
			int off = 0;
			if(strcmp(g.Name, "MostKills") == 0)
			{
				off = 4;
			}
			if(strcmp(g.Name, "MostDeaths") == 0)
			{
				off = 4;
			}
			if(strcmp(g.Name, "VehiclesDestroyed") == 0)
			{
				off = 4;
			}
			if(strcmp(g.Name, "MVP") == 0)
			{
				off = 4;
			}
			IRC::SendC(Channel, "%s: %s", g.Name, (char *)g.Data+off);
			return;
		}
	}

	IRC::SendC(Channel, "No global with this name found.", g.Name, g.Data);
}

void Rank::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	const char *PName;
	bool y = 0;
	if(Tokens->Length() > 1)
	{
		PName = strdup2((*Tokens)[1]);
	}
	else
	{
		PName = strdup2(GetPlayerName(ID));
		y = 1;
	}

	Stacker<Row *> Result;
	Query(&Result, "SELECT COUNT(*) FROM Ranks WHERE Score >= (SELECT Score FROM Ranks WHERE Nick = '%q');", PName);
	if(Result.Empty())
	{
		PPage(ID, "%s is not yet ranked.");
	}
	else
	{	
		int Rank = atoi(GetColumnData("COUNT(*)", (Result[0]->Columns)));
		DeleteResult(&Result);

		Query(&Result, "SELECT Score FROM Ranks WHERE Nick = '%q';", PName);

		char Postfix[4];
		if(Rank % 10 == 1)
		{
			strcpy(Postfix, "st");
		}
		else if(Rank % 10 == 2)
		{
			strcpy(Postfix, "nd");
		}
		else if(Rank % 10 == 3)
		{
			strcpy(Postfix, "rd");
		}
		else
		{
			strcpy(Postfix, "th");
		}
		float Score = (float)atof(GetColumnData("Score", Result[0]->Columns));
		if(y)
		{
			PPage(ID, "%s is ranked %d%s with a score of %.0f points", PName, Rank, Postfix, Score);
		}
		else
		{
			PPage(ID, "You are ranked %d%s with a score of %.0f points", Rank, Postfix, Score);
		}
		
		DeleteResult(&Result);
	}
	CDealloc(PName);
}

void Rank::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	const char *PName;
	if(Tokens->Length() > 1)
	{
		PName = strdup2((*Tokens)[1]);
	}
	else
	{
		IRCArgs;
	}

	if(IsNumber(PName))
	{
		Stacker<Row *> Result;
		Query(&Result, "SELECT Nick, Score FROM Ranks ORDER BY Score DESC LIMIT %d,1;", atoi(PName)-1);
		if(Result.Empty())
		{
			IRC::SendC(Channel, "Rank number too high");
			return;
		}
		else
		{	
			int Rank = atoi(PName);
			char Postfix[4];
			if(Rank % 10 == 1)
			{
				strcpy(Postfix, "st");
			}
			else if(Rank % 10 == 2)
			{
				strcpy(Postfix, "nd");
			}
			else if(Rank % 10 == 3)
			{
				strcpy(Postfix, "rd");
			}
			else
			{
				strcpy(Postfix, "th");
			}
			float Score = (float)atof(GetColumnData("Score", Result[0]->Columns));
			const char *Nick = GetColumnData("Nick", Result[0]->Columns);
			IRC::SendC(Channel, "%s is ranked %d%s with a score of %.0f point%s", Nick, Rank, Postfix, Score, Score == 1 ? "" : "s");
			
			DeleteResult(&Result);
		}
	}
	else
	{
		Stacker<Row *> Result;
		Query(&Result, "SELECT COUNT(*) FROM Ranks WHERE Score >= (SELECT Score FROM Ranks WHERE Nick = '%q');", PName);
		if(Result.Empty())
		{
			IRC::SendC(Channel, "\"%s\" is not yet ranked.");
			return;
		}
		else
		{	
			int Rank = atoi(GetColumnData("COUNT(*)", (Result[0]->Columns)));
			DeleteResult(&Result);

			Query(&Result, "SELECT Score FROM Ranks WHERE Nick = '%q';", PName);
			if(Result.Empty())
			{
				IRC::SendC(Channel, "\"%s\" is not yet ranked.", PName);
				return;
			}

			char Postfix[4];
			if(Rank % 10 == 1)
			{
				strcpy(Postfix, "st");
			}
			else if(Rank % 10 == 2)
			{
				strcpy(Postfix, "nd");
			}
			else if(Rank % 10 == 3)
			{
				strcpy(Postfix, "rd");
			}
			else
			{
				strcpy(Postfix, "th");
			}
			float Score = (float)atof(GetColumnData("Score", Result[0]->Columns));
			IRC::SendC(Channel, "%s is ranked %d%s with a score of %.0f point%s", PName, Rank, Postfix, Score, Score == 1 ? "" : "s");
			
			DeleteResult(&Result);
		}
	}
	CDealloc(PName);
}

void RankIgnore::Activate(int ID, int Type, Stacker<char *> *Tokens)
{

}

void RankIgnore::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{

}

void RankAllow::Activate(int ID, int Type, Stacker<char *> *Tokens)
{

}

void RankAllow::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{

}

void SQL::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	const char *Statement = Implode(Tokens, 1);
	Stacker<Row *> Result;
	Query(&Result, "%s", Statement);
	CDealloc(Statement);

	char *Header = (char *)CAlloc(1);
	IterateStack(r, Row *, (&Result))
	{
		r->Columns->Reset();
		Column *c;
		
		*Header = 0;
		while(r->Columns->Iterate(&c))
		{
			Header = (char *)RAlloc(Header, strlen(Header)+strlen(c->Name)+2);
			strcat(Header, c->Name);
			strcat(Header, "|");
		}
	}
	IRC::SendC(Channel, "%s", Header);
	CDealloc(Header);
}

void RankDetail::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

	Stacker<Row *> Result;

	int ret = FindPlayer((*Tokens)[1]);
	if(ret == -1)
	{
		IRC::SendC(Channel, "Player not found in-game. Searching database.");
	}
	else if(ret == -2)
	{
		IRC::SendC(Channel, "Player not found in-game. Searching database.");
	}
	const char *Nick;
	if(ret < 0)
	{
		Query(&Result, "SELECT Nick, PresetReadName, Kills, VehicleDestroyed, BuildingsDestroyed, Purchased, DestroyedBuilding+DestroyedVehicle+DestroyedSoldier FROM PresetKills WHERE Nick LIKE '%%%q%%' AND Type != 0 ORDER BY Type DESC;", *Tokens->At(1));
	}
	else
	{
		Nick = Get_Player_Name_By_ID(ret);
		Query(&Result, "SELECT Nick, PresetReadName, Kills, VehicleDestroyed, BuildingsDestroyed, Purchased, DestroyedBuilding+DestroyedVehicle+DestroyedSoldier FROM PresetKills WHERE Nick = '%q' AND Type != 0 ORDER BY Type DESC;", Nick);
		delete []Nick;
	}

	if(Result.Empty())
	{
		IRC::SendC(Channel, "\x03%dNo results found.", 4);
		return;
	}
	
	Nick = GetColumnData("Nick", (*Result.At(0))->Columns);
	IRC::SendC(Channel, "Showing kills data for: '%s'", Nick);
	IRC::SendC(Channel, "%-16s|%-9s|%-8s|%-8s|%-8s|%-5s", "Preset", "Purchased", "Soldier", "Vehicle", "Building", "Lost");
	
	IterateStack(x, Row *, (&Result))
	{
		char *Bld = 0, *Sol = 0, *Veh = 0, *Pur = 0, *PRN = 0, *Lost = 0;
		IterateStack(col, Column *, x->Columns)
		{
			if(strcmp(col->Name, "PresetReadName") == 0)
			{
				PRN = col->Data;
			}
			if(strcmp(col->Name, "Kills") == 0)
			{
				Sol = col->Data;
			}
			if(strcmp(col->Name, "VehicleDestroyed") == 0)
			{
				Veh = col->Data;
			}
			if(strcmp(col->Name, "BuildingsDestroyed") == 0)
			{
				Bld = col->Data;
			}
			if(strcmp(col->Name, "Purchased") == 0)
			{
				Pur = col->Data;
			}
			if(strcmp(col->Name, "DestroyedBuilding+DestroyedVehicle+DestroyedSoldier") == 0)
			{
				Lost = col->Data;
			}
		}
		IRC::SendC(Channel, "%-16s|%-9s|%-8s|%-8s|%-8s|%-5s", PRN, Pur, Sol, Veh, Bld, Lost);
	}

	DeleteResult(&Result);

}

void Log::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		Args;
	}
#ifdef _YaRRDebug
	if(stricmp(*Tokens->At(1), "memory") == 0 || stricmp(*Tokens->At(1), "mem") == 0)
	{
		PPage(ID, "Memory logging is now %s", YaRRMemory::LogMem_ == 0 ? "on" : "off");
		YaRRMemory::LogMem_ = YaRRMemory::LogMem_ == 0 ? 1 : 0;
	}
#else
	PPage(ID, "Logging is not avaliable on this build.");
#endif
}

void Log::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 2)
	{
		IRCArgs;
	}

#ifdef _YaRRDebug
	if(stricmp(*Tokens->At(1), "memory") == 0 || stricmp(*Tokens->At(1), "mem") == 0)
	{
		IRC::SendC(Channel, "Memory logging is now %s", YaRRMemory::LogMem_ == 0 ? "on" : "off");
		YaRRMemory::LogMem_ = YaRRMemory::LogMem_ == 0 ? 1 : 0;
	}
#else
	IRC::SendC(Channel, "Logging is not avaliable on this build.");
#endif
}

void Root::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	Player *p = Find_Check_Arguments(ID, 1, 1);

	if(p->Rooted)
	{
		Commands->Send_Custom_Event(Get_GameObj(p->ID), Get_GameObj(p->ID), 20, 20, 0.0);
	}
	else
	{
		Attach_Script_Once(Get_GameObj(p->ID), "YaRRRoot", "");
	}
}
void Root::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	Player *p = Find_Check_Arguments(Channel, 1, 1);

	if(p->Rooted)
	{
		Commands->Send_Custom_Event(Get_GameObj(p->ID), Get_GameObj(p->ID), 20, 20, 0.0);
	}
	else
	{
		Attach_Script_Once(Get_GameObj(p->ID), "YaRRRoot", "");
	}
}

void Protect::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	Player *p = Find_Check_Arguments(ID, 1, 1);

	if(p->Protected)
	{
		Commands->Send_Custom_Event(Get_GameObj(p->ID), Get_GameObj(p->ID), 21, 21, 0.0);
	}
	else
	{
		Attach_Script_Once(Get_GameObj(p->ID), "YaRRProtect", "");
	}
}

void Protect::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	Player *p = Find_Check_Arguments(Channel, 1, 1);

	if(p->Protected)
	{
		Commands->Send_Custom_Event(Get_GameObj(p->ID), Get_GameObj(p->ID), 21, 21, 0.0);
	}
	else
	{
		Attach_Script_Once(Get_GameObj(p->ID), "YaRRProtect", "");
	}
}

void _PlaySound::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 1)
	{
		Args;
	}

	Stacker<WavSound> *tmp = 0;

	char buffer[128];
	GetCurrentDirectory(50, buffer);
	strcat(buffer, "\\config\\Sounds.ini");
	
	INIClass *ini = Get_INI(buffer);
	if(!ini)
	{
		PPageErr(ID, "Sounds.ini not found.");
		return;
	}

	YaRRSettings::LoadSound(&tmp, *Tokens->At(1), ini);

	if(!tmp)
	{
		PPageErr(ID, "Internal error, please report.");
		return;
	}
	if(tmp->Empty())
	{
		PPageErr(ID, "Sound not found.");
		return;
	}

	PlaySound((void *)tmp, 1, 0, ID);

	Dealloc(Stacker<WavSound>, tmp);
}

void _PlaySound::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 1)
	{
		IRCArgs;
	}

	Stacker<WavSound> *tmp = 0;

	char buffer[128];
	GetCurrentDirectory(50, buffer);
	strcat(buffer, "\\config\\Sounds.ini");
	
	INIClass *ini = Get_INI(buffer);
	if(!ini)
	{
		IRC::SendC(Channel, "Sounds.ini not found.");
		return;
	}

	YaRRSettings::LoadSound(&tmp, *Tokens->At(1), ini);

	if(!tmp)
	{
		IRC::SendC(Channel, "Internal error, please report.");
		return;
	}
	if(tmp->Empty())
	{
		IRC::SendC(Channel, "Sound not found.");
		return;
	}

	PlaySound((void *)tmp, 1, 0, 0);

	Dealloc(Stacker<WavSound>, tmp);
}

void Calculate::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	if(Tokens->Length() < 1)
	{
		IRCArgs;
	}

	Stacker<Row *> Result;

	const char *imp = Implode(Tokens, 1);
	const char *err = Query(&Result, "SELECT %s ANS;", imp);

	if(err)
	{
		IRC::SendC(Channel, "0");
		CDealloc(err);
	}
	else
	{
		IRC::SendC(Channel, "%s", GetColumnData("ANS", Result[0]->Columns));
	}
	CDealloc(imp);

	DeleteResult(&Result);
}

void Say::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	Player *p = Find_Check_Arguments(ID, 1, 4);

	int Type_ = atoi(*Tokens->At(2));
	if(!IsNumber(*Tokens->At(2)) || Type_ < 0 || Type_ > 1)
	{
		PPageErr(ID, "Invalid type, 0 = all, 1 = team");
		return;
	}

	const char *Msg = Implode(Tokens, 3);
	YaRRFunctions::SendMessageF(p->ID, Type_, 0, -1, "%s", Msg);
	CDealloc(Msg);
}

void Say::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	Player *p = Find_Check_Arguments(Channel, 1, 4);

	int Type = atoi(*Tokens->At(2));
	if(!IsNumber(*Tokens->At(2)) || Type < 0 || Type > 1)
	{
		IRC::SendC(Channel, "Invalid type, 0 = all, 1 = team");
		return;
	}

	const char *Msg = Implode(Tokens, 3);
	YaRRFunctions::SendMessageF(p->ID, Type, 0, -1, "%s", Msg);
	CDealloc(Msg);
}

void LockDown::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	YaRRHooking::Locked = (YaRRHooking::Locked == 0 ? 1 : 0);
}

void LockDown::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	YaRRHooking::Locked = (YaRRHooking::Locked == 0 ? 1 : 0);
}


/**********************************************************************************************************************************
***********************************************************************************************************************************
**********************************************************************************************************************************/

void YaRRCommands::Startup()
{
	DLOG;
	if(!CommandList)
	{
		CommandList = Alloc(Stacker<ChatCommand *>);
	}

	RegisterCommand(Message, 2, "message", MessageCommandRegistrant);	
	RegisterCommand(Debug, 3, "debug", DebugCommandRegistrant);
	RegisterCommand(Gameinfo, 2, "gameinfo", GameinfoCommandRegistrant);
	RegisterCommand(Ban, 3, "ban", BanCommandRegistrant);
	RegisterCommand(Help, 3, "help", HelpCommandRegistrant);
	RegisterCommand(Auth, 2, "auth", AuthCommandRegistrant);
	RegisterCommand(Save, 1, "save", SaveCommandRegistrant);
	RegisterCommand(Setjoin, 1, "setjoin", SetjoinCommandRegistrant);
	RegisterCommand(FDS, 3, "fds", FDSCommandRegistrant);
	RegisterCommand(Boot, 3, "boot", BootCommandRegistrant);
	RegisterCommand(Unban, 3, "unban", UnbanCommandRegistrant);
	RegisterCommand(Logsearch, 2, "logsearch", LogsearchCommandRegistrant);
	RegisterCommand(Edit, 2, "edit", EditCommandRegistrant);
	RegisterCommand(ShowMods, 3, "showmods", ShowModsCommandRegistrant);
	RegisterCommand(ListPlayers, 2, "listplayers", ListPlayersCommandRegistrant);
	RegisterCommand(Mute, 3, "mute", MuteCommandRegistrant);
	RegisterCommand(Killme, 1, "killme", KillmeCommandRegistrant);
	RegisterCommand(Kill, 3, "kill", KillCommandRegistrant);
	RegisterCommand(Block, 2, "block", BlockCommandRegistrant);
	RegisterCommand(Unblock, 3, "unblock", UnblockCommandRegistrant);
	RegisterCommand(Version, 3, "version", VersionCommandRegistrant);
	RegisterCommand(Gameover, 3, "gameover", GameoverCommandRegistrant);
	RegisterCommand(Restart, 3, "restart", RestartCommandRegistrant);
	RegisterCommand(Quit, 3, "quit", QuitCommandRegistrant);
	RegisterCommand(Allow, 3, "allow", AllowCommandRegistrant);
	RegisterCommand(Buildings, 2, "buildings", BuildingsCommandRegistrant);
	RegisterCommand(Vehicles, 2, "vehicles", VehiclesCommandRegistrant);
	RegisterCommand(ForceTeamChange, 3, "forceteamchange", ForceTeamChangeCommandRegistrant);
	RegisterCommand(Bandwidth, 3, "bandwidth", BandwidthCommandRegistrant);
	RegisterCommand(VehicleLimit, 3, "vehiclelimit", VehicleLimitCommandRegistrant);
	RegisterCommand(MineLimit, 3, "minelimit", MineLimitCommandRegistrant);
	RegisterCommand(AdminMessage, 3, "adminmessage", AdminMessageCommandRegistrant);
	RegisterCommand(Spectate, 3, "spectate", SpectateCommandRegistrant);
	RegisterCommand(PlayerAdminMessage, 3, "playeradminmessage", PlayerAdminMessageCommandRegistrant);
	RegisterCommand(Eject, 3, "eject", EjectCommandRegistrant);
	RegisterCommand(Stats, 2, "stats", StatsCommandRegistrant);
	RegisterCommand(Rotation, 3, "rotation", RotationCommandRegistrant);
	RegisterCommand(Nextmap, 3, "nextmap", NextmapCommandRegistrant);
	RegisterCommand(Refund, 3, "refund", RefundCommandRegistrant);
	RegisterCommand(DestroyVehicle, 3, "destroyvehicle", DestroyVehicleCommandRegistrant);
	RegisterCommand(DeleteTempModerator, 3, "deletetempmoderator", DeleteTempModeratorCommandRegistrant);
	RegisterCommand(AddTempModerator, 3, "addtempmoderator", AddTempModeratorCommandRegistrant);
	RegisterCommand(PlayerInfo, 2, "playerinfo", PlayerInfoCommandRegistrant);
	RegisterCommand(ModList, 2, "modlist", ModlistCommandRegistrant);
	RegisterCommand(Rules, 3, "rules", RulesCommandRegistrant);
	RegisterCommand(Shun, 3, "shun", ShunCommandRegistrant);
	RegisterCommand(Unshun, 3, "unshun", UnshunCommandRegistrant);
	RegisterCommand(SetNextMap, 3, "setnextmap", SetNextMapCommandRegistrant);
	RegisterCommand(Banlog, 2, "banlog", BanlogCommandRegistrant);
	RegisterCommand(Donate, 1, "donate", DonateCommandRegistrant);
	RegisterCommand(Rehash, 3, "rehash", RehashCommandRegistrant);
	RegisterCommand(Raw, 3, "raw", RawCommandRegistrant);
	RegisterCommand(Stop, 3, "stop", StopCommandRegistrant);
	RegisterCommand(Start, 3, "start", StartCommandRegistrant);
	RegisterCommand(Zero, 3, "zero", ZeroCommandRegistrant);
	RegisterCommand(Server, 3, "server", ServerCommandRegistrant);
	RegisterCommand(Website_, 3, "website", Website_CommandRegistrant);
	RegisterCommand(Page, 3, "page", PageCommandRegistrant);
	RegisterCommand(Viewjoin, 3, "viewjoin", ViewjoinCommandRegistrant);
	RegisterCommand(Time, 3, "time", TimeCommandRegistrant);
	RegisterCommand(Ping, 3, "ping", PingCommandRegistrant);
	RegisterCommand(Tdonate, 1, "tdonate", TDonateCommandRegistrant);
	RegisterCommand(SetColour, 1, "setcolour", SetColourCommandRegistrant);
	RegisterCommand(SetSound, 1, "setsound", SetSoundCommandRegistrant);
	RegisterCommand(Disarm, 3, "disarm", DisarmCommandRegistrant);
	RegisterCommand(RequestTeamChange, 1, "requestteamchange", RequestTeamChangeCommandRegistrant);
	RegisterCommand(NodeBan, 3, "nodeban", NodeBanCommandRegistrant);
	RegisterCommand(FindNodeBan, 2, "findnodeban", FindNodeBanCommandRegistrant);
	RegisterCommand(DeleteNodeBan, 3, "deletenodeban", DeleteNodeBanCommandRegistrant);
	RegisterCommand(SetGlobal, 3, "setglobal", SetGlobalCommandRegistrant);
	RegisterCommand(GetGlobal, 3, "getglobal", GetGlobalCommandRegistrant);
	//RegisterCommand(SQL, 2, "sql", SQLCommandRegistrant);
	RegisterCommand(Rank, 3, "rank", RankCommandRegistrant);
	RegisterCommand(RankDetail, 2, "rankdetail", RankDetailCommandRegistrant);
	RegisterCommand(Log, 3, "log", LogCommandRegistrant);
	RegisterCommand(Root, 3, "root", RootCommandRegistrant);
	RegisterCommand(Protect, 3, "protect", ProtectCommandRegistrant);
	RegisterCommand(_PlaySound, 3, "sound", PlaySoundCommandRegistrant);
	//RegisterCommand(Calculate, 2, "calculate", CalculateCommandRegistrant);
	RegisterCommand(Say, 3, "say", SayCommandRegistrant);
	RegisterCommand(LockDown, 3, "lockdown", LockDownCommandRegistrant);

	//RegisterCommand(RankAllow, 3, "rankallow", RankAllowCommandRegistrant);
	//RegisterCommand(RankIgnore, 3, "rankignore", RankIgnoreCommandRegistrant);
	/*
	RegisterCommand(SellVehicle, 1, "sellvehicle", SellVehicleCommandRegistrant);
	RegisterCommand(TeamPlayers, 3, "teamplayers", TeamPlayersCommandRegistrant);
	RegisterCommand(Nicksearch, 2, "nicksearch", NicksearchCommandRegistrant);
	*/
	
}
//RegisterCommand(, , "", CommandRegistrant);

void YaRRCommands::Shutdown()
{
	DLOG;
	if(CommandList)
	{
		ChatCommand *c;
		CommandList->Reset();

		while(CommandList->Iterate(&c))
		{
			DeleteList(&c->Triggers);
		}
		DeleteList(CommandList);

		Dealloc(Stacker<ChatCommand *>, CommandList);
		CommandList = 0;

	}
}


void YaRRCommands::IRCCallback(ircdata *irc, const char *Packet)
{
	DLOG;
	printf("%s\n", Packet);
	Stacker<char *> Tokens;
	Explode(Packet, ' ', &Tokens);

	irc->Ping = 0;
	if(Tokens.Empty())
	{
		return;
	}

	if(strcmp(Tokens[0], "PING") == 0)
	{
		IRC::Send("PONG %s\n", Tokens[1]);
	}

	if(strcmp(Tokens[1], "433") == 0)
	{
		IRC::Send("NICK %s\n", irc->Backup_Nick);
		IRC::Send("USER %s 0 * :YaRR-%s\n", irc->Backup_Nick, YARR_VERSION);
		irc->Ghost = 1;
	}

	if(strcmp(Tokens[1], "001") == 0)
	{
		IRC::Send("PRIVMSG NickServ :IDENTIFY %s\n", irc->NSPassword);

		irc->EXTCommands.Reset();
		char *com;
		while(irc->EXTCommands.Iterate(&com))
		{
			IRC::Send("%s\n", com);
		}


		ChannelData *c;
		YaRRSettings::IRCd->Channels->Reset();
		while(YaRRSettings::IRCd->Channels->Iterate(&c))
		{
			IRC::Send("JOIN %s %s\n", c->Name, c->Key);
			char *version = strdup2(YaRRStrings::Fetch(IRC_CHANNEL_JOIN));
			IRC::Send("PRIVMSG %s :%s\n", c->Name, Replace(version, ":version:", YARR_VERSION));
			CDealloc(version);
		}
	}

	if(strcmp(Tokens[1], "353") == 0)
	{

		const char *Users = Implode(&Tokens, 5);
		strcpy((char *)Users, (char *)Users+1);

		Stacker<char *> users;
		Explode(Users, ' ', &users);
		CDealloc(Users);

		ircChannel *channel = 0;
		IterateStack(c, ircChannel *, (&(irc->Channels)))
		{
			if(strcmp(c->Name, Tokens[4]) == 0)
			{
				channel = c;
				break;
			}
		}

		if(!channel)
		{
			channel = Alloc(ircChannel);
			strcpy(channel->Name, Tokens[4]);
			irc->Channels.Push(channel);
		}

		IterateStack(tmp, char *, (&users))
		{
			User *u = Alloc(User);
			if(GetStatus(*tmp) == 0)
			{
				strcpy(u->Nick, tmp);
				u->Modes = 0;
			}
			else
			{
				u->Modes = *tmp;
				strcpy(u->Nick, tmp+1);
			}
			channel->Users.Push(u);
			
		}	
		
		DeleteList(&users);
	}

	if(strcmp(Tokens[1], "MODE") == 0)
	{
		IRC::Send("NAMES %s\n", Tokens[2]);
	}
	if(strcmp(Tokens[1], "KICK") == 0)
	{
		IRC::Send("NAMES %s\n", Tokens[2]);
	}
	if(strcmp(Tokens[1], "PART") == 0)
	{
		IRC::Send("NAMES %s\n", Tokens[2]);
	}
	if(strcmp(Tokens[1], "NICK") == 0)
	{
		char OldNick[256];
		strcpy(OldNick, (Tokens[0])+1);
		*strstr(OldNick, "!") = 0;
		IterateStack(c, ircChannel *, (&irc->Channels))
		{
			IterateStack(u, User *, (&c->Users))
			{
				if(strcmp(u->Nick, OldNick) == 0)
				{
					strcpy(u->Nick, Tokens[2]);
				}
			}
		}
	}
	if(strcmp(Tokens[1], "PRIVMSG") == 0)
	{
		Stacker<char *> tok;
		Explode(Tokens[0], '!', &tok);

		const char *Nick = strdup2((tok[0])+1);

		DeleteList(&tok);

		const char *Msg = Implode(&Tokens, 3);
		IterateStack(c, ircChannel *, (&(irc->Channels)))
		{
			if(stricmp(c->Name, Tokens[2]) == 0)
			{
				IterateStack(u, User *, (&(c->Users)))
				{
					if(stricmp(u->Nick, Nick) == 0)
					{
						YaRRCommands::IRCChat(irc, u, Tokens[2], Msg+1);
						CDealloc(Msg);
						CDealloc(Nick);
						DeleteList(&Tokens);
						return;
					}
						
				}
				
			}
		}
		CDealloc(Msg);
		CDealloc(Nick);
		
		
	}
	DeleteList(&Tokens);
}

bool __stdcall YaRRCommands::GameChat(int ID, int Type, WideStringClass &_Message, int Target)
{
	DLOG;
	const char *Message = WideCharToChar((const wchar_t *)_Message);

	char *Message2 = strdup2(Message);
	Replace(Message2, "fuck", "f***");
	_Message.Convert_From(Message2);
	strcpy((char *)Message, Message2);

	CDealloc(Message2);

	int SendPM = -1;
	char prefix[2];
	prefix[1] = 0;
	
	Player *p = Find(ID);
	if(!p)
	{
		prefix[0] = 0;
	}
	else
	{
		prefix[0] = p->Access;
		if(prefix[0] == 'p')
		{
			prefix[0] = 0;
		}
	}

	if(Type == 0)
	{
		IRC::SendC(p->Muted == 1 ? 'a' : 'b', "\x03%d%s%S\x03%d: %S", (Get_Team(ID) == 0 ? 4 : 8), prefix, Get_Wide_Player_Name_By_ID(ID), 15, (const wchar_t *)_Message);
	}
	else if(Type == 1)
	{
		IRC::SendC('a', "\x03%d(Team) %s%S\x03%d: %S", (Get_Team(ID) == 0 ? 4 : 8), prefix, Get_Wide_Player_Name_By_ID(ID), 15, (const wchar_t *)_Message);
	}
	else if(Type == 2 && Target > 0)
	{
		SendPM = Target;
		IRC::SendC('a', "\x03%d%s%S\x03%d -> \x03%d%S\x03%d: %S", (Get_Team(ID) == 0 ? 4 : 8), prefix, Get_Wide_Player_Name_By_ID(ID), 5, (Get_Team(Target) == 0 ? 4 : 8), Get_Wide_Player_Name_By_ID(Target), 15, (const wchar_t *)_Message); 
	}
	if(!p || p->Shunned)
	{
		delete []Message;
		return 1;
	}

	Stacker<char *> Tokens;
	Explode(Message, ' ', &Tokens);

	CommandList->Reset();
	ChatCommand *x;
	while(CommandList->Iterate(&x))
	{
		char *c;
		x->Triggers.Reset();
		while(x->Triggers.Iterate(&c))
		{
			if(strcmp(c, Tokens[0]) == 0)
			{
				if((GetStatus(p->Access) >= GetStatus(x->Access)))
				{
					x->Activate(ID, Type, &Tokens);
					DeleteList(&Tokens);
					delete []Message;
					return 0;
				}
				else
				{
					char *nstatus = Replace(Replace(strdup2(Fetch(GAME_NSTATUS)), ":nick:", p->Nick), ":command:", c);
					PPageErr(ID, "%s", nstatus);
					CDealloc(nstatus);
					DeleteList(&Tokens);
					delete []Message;
					return 0;
				}
				
			}
		}
		
	}
	DeleteList(&Tokens);
	
	if(SendPM > 0)
	{
		PPage(SendPM, "[PM] %s: %S", p->Nick, Message);
		PPage(p->ID, "[PM] %s: %S", p->Nick, Message);
		delete []Message;
		return 0;
	}

	if(p->Muted)
	{
		delete []Message;
		return !p->Muted;
	}
	IterateStack(s, Sound, YaRRSettings::Sounds)
	{
		if(strstr(s.Trigger, Message))
		{
			ConsoleInputF("snda %s", s.File);
			break;
		}
	}
	
	
	delete []Message;
	return !p->Muted;
}

void YaRRCommands::IRCChat(ircdata *irc, User *user, const char *Channel, const char *Message)
{
	DLOG;
	
	
	if((*Message != '!') || !user)
	{
		return;
	}
	Moderator m;
	bool found = 0;
	ModeratorList->Reset();
	while(ModeratorList->Iterate(&m))
	{
		if(stricmp(user->Nick, m.IRCNick) == 0)
		{
			found = 1;
			break;
		}	
	}
	if(!found)
	{
		m.Access = 'p';
	}



	Stacker<char *> Tokens;
	Explode(Message, ' ', &Tokens);
	CommandList->Reset();
	ChatCommand *x;
	while(CommandList->Iterate(&x))
	{
		char *c;
		x->Triggers.Reset();
		while(x->Triggers.Iterate(&c))
		{
			if(stricmp(c, Tokens[0]) == 0)
			{
				if(GetStatus(user->Modes) >= GetStatus(x->Access) && GetStatus(m.Access) >= GetStatus(x->Access))
				{
					x->ActivateIRC(irc, user, Channel, &Tokens);
					DeleteList(&Tokens);
					return;
				}
				else
				{
					char *nstatus = Replace(Replace(strdup2(Fetch(IRC_NSTATUS)), ":nick:", m.IRCNick), ":command:", c);
					IRC::Send("NOTICE %s :%s\n", user->Nick, nstatus);
					CDealloc(nstatus);
				}
				
			}
		}
		
	}
	DeleteList(&Tokens);
}


void ChatCommand::Startup(const char *_Name, int _Use)
{
	DLOG;
	strcpy(this->Name, _Name);
	
	char buffer[256];
	char Access_;
	if(!YaRRSettings::GetCommandInfo(_Name, buffer, 256, &Access_))
	{
		char err[256];
		sprintf(err, "Unable to load command \"%s\" from ./config/YaRR.ini", _Name);
		YaRRError(err);
	}
	else
	{
		Stacker<char *> Tokens;
		Explode(buffer, ' ', &Tokens);
		Access = Access_;
		CopyStack((&Triggers), (&Tokens), char *);
		
		this->Use = _Use;
		YaRRCommands::Add(this);
	}


}

void YaRRCommands::Add(ChatCommand *Command)
{
	DLOG;
	if(!CommandList)
	{
		CommandList = Alloc(Stacker<ChatCommand *>);
	}
	CommandList->Push(Command);
}

inline Player *YaRRCommands::Find_Output(int ID, Stacker<char *> *Tokens, int Number, int Arguments)
{
	if(Tokens->Length() < Arguments)
	{
		char *arstr = strdup2(YaRRStrings::Fetch(GAME_ARGS)); 
		PPageErr(ID, "%s", Replace(arstr, ":command:", (*Tokens)[0])); 
		CDealloc(arstr); 
		return 0;
	}

	int ret = FindPlayer((*Tokens)[Number]);
	if(ret == -1)
	{
		char *arstr = strdup2(YaRRStrings::Fetch(GAME_PNOTFIND)); 
		PPageErr(ID, "%s", Replace(arstr, ":command:", (*Tokens)[0])); 
		CDealloc(arstr); 
		return 0;
	}
	else if(ret == -2)
	{
		char *arstr = strdup2(YaRRStrings::Fetch(GAME_PFMANY)); 
		PPageErr(ID, "%s", Replace(arstr, ":command:", (*Tokens)[0])); 
		CDealloc(arstr); 
		return 0;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			PPage(ID, "Internal error, please report.");
			return 0;
		}
		return p;
	}
}

inline Player *YaRRCommands::Find_Output(const char *Channel, Stacker<char *> *Tokens, int Number, int Arguments)
{
	if(Tokens->Length() < Arguments)
	{
		char *arstr = strdup2(YaRRStrings::Fetch(IRC_ARGS)); 
		IRC::SendC(Channel, "%s", Replace(arstr, ":command:", (*Tokens)[0])); 
		CDealloc(arstr); 
		return 0;
	}

	int ret = FindPlayer((*Tokens)[Number]);
	if(ret == -1)
	{
		char *arstr = strdup2(YaRRStrings::Fetch(IRC_PNOTFIND)); 
		IRC::SendC(Channel, "%s", Replace(arstr, ":command:", (*Tokens)[0])); 
		CDealloc(arstr); 
		return 0;
	}
	else if(ret == -2)
	{
		char *arstr = strdup2(YaRRStrings::Fetch(IRC_PFMANY)); 
		IRC::SendC(Channel, "%s", Replace(arstr, ":command:", (*Tokens)[0])); 
		CDealloc(arstr); 
		return 0;
	}
	else
	{
		Player *p = Find(ret);
		if(!p)
		{
			IRC::SendC(Channel, "Internal error, please report.");
			return 0;
		}
		return p;
	}
}

void ChatCommand::Activate(int ID, int Type, Stacker<char *> *Tokens)
{
	DLOG;
	char *ncom = Replace(Replace(strdup2(Fetch(GAME_NCOM)), ":nick:", GetPlayerName(ID)), ":command:", *Tokens->At(0));
	PPageErr(ID, "%s", ncom);
	CDealloc(ncom);
}
void ChatCommand::ActivateIRC(ircdata *irc, User *user, const char *Channel, Stacker<char *> *Tokens)
{
	DLOG;
	char *ncom = Replace(Replace(strdup2(Fetch(IRC_NCOM)), ":nick:", user->Nick), ":command:", *Tokens->At(0));
	IRC::Send("PRIVMSG %s :%s\n", Channel, ncom);
	CDealloc(ncom);
}

