#include "stinc.h"
#include "stmisc.h"
#include "stgame.h"
#include "stvehicle.h"
#include "stweapon.h"
#include "stchat.h"
#include "stconsolecommands.h"
#include "sttranslate.h"
#include "stanticheat.h"
#include "sttestzone.h"
#include "stveteran.h"
#include "strewards.h"
#include "stplayer.h"

// Forward
class gzChat_Here;
class gzChat_Stuck;


/***************/
/* Player data */
/***************/
void gzPlayer::SetDeletePending()
{
	this->m_chatFlood->SetDeletePending();
	this->m_radioFlood->SetDeletePending();
	this->m_weaponPack->SetDeletePending();
	this->m_vehOwnData->SetDeletePending();
	this->m_antiCheatRoF->SetDeletePending();
	this->m_antiCheatHitLog->SetDeletePending();
	this->m_antiCheatSpec->SetDeletePending();
	this->m_veteran->SetDeletePending();
#if VERC(1, 1, 0)
	this->m_rewards->SetDeletePending();
#endif

	this->gzBase::SetDeletePending();
}
gzPlayer::gzPlayer(nc_cPlayer *pData)
{
	this->RegisterEvent(EVT_GAME_LEVEL_LOADED);
	this->RegisterEvent(EVT_GAME_THINK);
	this->RegisterEvent(EVT_PLAYER_LEFT);
	this->RegisterEvent(EVT_PLAYER_BANDWIDTH);
	this->RegisterEvent(EVT_PLAYER_SUICIDE);
	this->RegisterEvent(EVT_PLAYER_TEAMCHANGE);
	this->RegisterEvent(EVT_PLAYER_SERIALHASH);
	this->RegisterEvent(EVT_PLAYER_PURCHASE);
	this->RegisterEvent(EVT_OBJECT_DAMAGE, EVT_PRIORITY_TOP);
	this->RegisterEvent(EVT_OBJECT_TRANSITION);
	this->RegisterEvent(EVT_OBJECT_FIRE);
	this->RegisterEvent(EVT_NET_SERIAL_AUTH);
	this->RegisterEvent(EVT_OBJECT_JUMP_COMPLETE);
	this->RegisterEvent(EVT_BHS_POKE);

	this->m_gameData        = pData;
	this->m_name            = this->GetPlayerData()->PlayerName.m_Buffer;
	this->m_isActive        = true;
	this->m_chatFlood       = new gzChatFloodClass(this->GetPlayerData());
	this->m_radioFlood      = new gzRadioFloodClass(this->GetPlayerData());
	this->m_weaponPack      = new gzWeaponPackClass(this);
	this->m_vehOwnData      = new gzVehicleOwnerClass(this);
	this->m_antiCheatRoF    = new gzAntiCheatWeapons(this);
	this->m_antiCheatSpec   = new gzAntiCheatSpec(this);
	this->m_antiCheatHitLog = new gzAntiCheatHitLog(this);
	this->m_veteran         = new gzVeteranClass(this);
	this->m_tibCrystal      = NULL;
#if VERC(1, 1, 0)
	this->m_rewards         = new stRewardsClass(this);
#endif

	this->m_ammoCheckInt   = 0.0f;
	this->m_numpadMode     = NUMPAD_TAUNT;
	this->m_afk_prevScore  = 0.0f;
	this->m_afk_time       = 0.0f;
	this->m_afk_warnSent   = false;
	this->m_afk_countDelay = 0.0f;
	this->m_slowLoad       = false;
	this->m_bhsVersion     = 0.0f;
	this->m_isSpectator    = false;
	this->m_lastPokeProxy  = 0;
	this->m_lastPokeTime   = 0;
	this->m_pokeProxyCount = 0;

#if VERC(1, 1, 0)
	this->m_stId           = -1;
#endif

	this->SetChildOwner(gzPlayerMgr);
}
void gzPlayer::Level_Loaded()
{
	this->SetAfkPrevScore(0.0f);
	this->SetAfkDelay(10.0f); // Giving 10 seconds spawn delay
	this->SetIsSpectator(false);

	this->m_lastPokeProxy  = 0;
	this->m_lastPokeTime   = 0;
	this->m_pokeProxyCount = 0;
}
void gzPlayer::Think()
{
	if (this->m_isActive)
	{
		this->m_lastPacketMs = nc_cNetwork::PServerConnection->RemoteList[this->GetPlayerData()->PlayerId]->LastReceivePacketMs;
		if (gzGameMgr->m_settings->m_EnableInfAmmo)
		{
			SubFrameTime(this->m_ammoCheckInt, true);
			if (this->m_ammoCheckInt < 0.0f)
			{
				if (this->GetPlayerData()->Owner.Reference)
				{
					nc_SoldierGameObj *soldier = this->GetPlayerData()->Owner.Reference->obj->As_SoldierGameObj();
					if (soldier)
					{
						for (int i = 1; i < soldier->WeaponBag->Vector.Count(); i++)
						{
							if (soldier->WeaponBag->Vector[i]->WeaponDef->Style != 0 && soldier->WeaponBag->Vector[i]->WeaponDef->Style != 6)
							{
								int ammo[2] = {
									soldier->WeaponBag->Vector[i]->LoadedBullets.Get(),
									soldier->WeaponBag->Vector[i]->InventoryBullets.Get(),
								};
								if (gzGameMgr->m_settings->m_NoReload)
									ammo[0] = soldier->WeaponBag->Vector[i]->WeaponDef->ClipSize.Get();
								else
									ammo[1] = soldier->WeaponBag->Vector[i]->WeaponDef->MaxInventoryRounds.Get();
								soldier->WeaponBag->Vector[i]->LoadedBullets = ammo[0];
								soldier->WeaponBag->Vector[i]->InventoryBullets = ammo[1];
								soldier->Set_Object_Dirty_Bit(nc_DB_OCCASIONAL, true);
							}
						}
					}
					this->m_ammoCheckInt = INFAMMO_CHECK;
				}
			}
		}
		// Game for current map has ended. Waiting for next map load
		if (!gzGameMgr->IsGameOver())
		{
			// AFK checker
			SubFrameTime(this->m_afk_countDelay, (this->m_afk_countDelay > 0.0f));

			// Delay expired
			if (this->m_afk_countDelay <= 0.0f && gzTestZoneMgr->IsActive())
			{
				if (this->GetPlayerData()->Score.Get() != this->m_afk_prevScore)
				{
					this->m_afk_prevScore	= this->GetPlayerData()->Score.Get();
					this->m_afk_time		= 0.0f;
				}
				else
				{
					AddFrameTime(this->m_afk_time, true);

					// Make sure warn is sent first
					if (!this->m_afk_warnSent)
					{
						if ((gzGameMgr->m_settings->m_AllowAfkSeconds - this->m_afk_time) <= 30.0f)
						{
							stConsole::In("pamsg %d You are being marked as AFK and will be kicked in 30 seconds. Type \"!here\" to remove yourself from AFK kick queue.", this->GetPlayerData()->PlayerId);
							this->SetAfkIsWarnSent(true);
						}
					}
					else if (this->m_afk_time > gzGameMgr->m_settings->m_AllowAfkSeconds)
					{
						stConsole::In("kick %d", this->GetPlayerData()->PlayerId);
						stConsole::In("allow %ls", this->m_name.GetString());
						stConsole::In("msg %ls was kicked for AFK.", this->m_name.GetString());
						this->SetAfkTime(0.0f);
					}
				}
			}
		}

		if (this->m_slowLoad)
		{
			// Player is loaded
			if (this->GetPlayerData()->IsInGame)
			{
				// Slow loading refunds
				if (cGame->GameDuration_Seconds > 0 && cGame->Is_Gameplay_Permitted())
				{
					nc_BuildingGameObj *ref = nc_BaseControllerClass::Find_Base(this->GetPlayerData()->PlayerType.Get())->Find_Building(nc_REFINERY);
					if (ref)
						this->GetPlayerData()->Increment_Money(cGame->GameDuration_Seconds * floor(((nc_RefineryGameObjDef *)ref->definition)->FundsDistribedPerSec));
				}
				this->m_slowLoad = false;

				// Giving it an addition AFK check delay because most players won't get score in 30 secs after new map is loaded
				this->SetAfkDelay(30.0f);
			}
		}
	}
}
void gzPlayer::Player_Left(gzEventPlayerBase &evt)
{
	if (this->GetPlayerData() == evt.GetPlayer())
	{
		this->m_isActive = false;
		if (evt.GetInt() == LEFT_DISCONNECT)
		{
			nc_Vector3 color = { 50.0f, 225.0f, 50.0f };
			SendBhsColorMsg(color, "Connection broken to player: %ls", this->m_name.GetString());
#ifdef DEVMSG
			stConsole::Out("Last received packet from %ls was %f sec(s) ago.\n",
				this->m_name.GetString(),
				(GetTickCount() - SystemTime - this->m_lastPacketMs) / 1000.0f
			);
#endif
		}

		this->m_vehOwnData->UnsetAll();
		this->m_bhsVersion  = 0.0f;
		this->m_isSpectator = false;
		this->m_lastPokeProxy  = 0;
		this->m_pokeProxyCount = 0;
		this->m_lastPokeTime   = 0;

		for (nc_GenericSLNode<nc_BaseGameObj> *objList = nc_GameObjManager::GameObjList->HeadNode; objList != NULL; objList = objList->NodeNext)
		{
			if (objList->NodeData->As_ScriptableGameObj())
				objList->NodeData->As_ScriptableGameObj()->Start_Custom_Timer(objList->NodeData->As_ScriptableGameObj(), 0.0f, 10001, evt.GetPlayer()->PlayerId);
		}
	}
}
void gzPlayer::Player_BandwidthChange(gzEventPlayerBandwidth &evt)
{
	if (this->GetPlayerData() == evt.GetPlayer())
	{
		if (evt.GetInt() < gzGameMgr->GetSettings()->m_MinimumBandwidth)
		{
			stConsole::Out("[ST] %ls attempted to set bandwidth to %d and denied by server; Minimum: %d\n",
				evt.GetPlayer()->PlayerName.m_Buffer,
				evt.GetInt(),
				gzGameMgr->GetSettings()->m_MinimumBandwidth
			);
			evt.SetInt(gzGameMgr->GetSettings()->m_MinimumBandwidth);
			evt.Skip();
		}
	}
}
void gzPlayer::Player_Suicide(gzEventPlayerBase &evt)
{
	if (this->GetPlayerData() == evt.GetPlayer())
		this->m_weaponPack->m_list.Clear();
}
void gzPlayer::Player_TeamChange(gzEventPlayerBase &evt)
{
	if (this->GetPlayerData() == evt.GetPlayer())
		this->m_weaponPack->m_list.Clear();
}
void gzPlayer::Player_SerialHash(gzEventPlayerSerialHash &evt)
{
	if (this->GetPlayerData() == evt.GetPlayer())
		stConsole::Out("Serial hash from %ls(ID: %d): %.32s\n", evt.GetPlayer()->PlayerName.m_Buffer, evt.GetPlayer()->PlayerId, evt.m_hash.GetString());
}
void gzPlayer::Player_Purchase(gzEventPlayerPurchase &evt)
{
	if (evt.GetPlayer() == this->GetPlayerData())
		this->m_afk_time = 0.0f;
}
void gzPlayer::Object_Damaged(gzEventObjectDamage &evt)
{
	if (this->m_isSpectator && evt.m_defender == this->GetSoldier())
		evt.Skip();
}
void gzPlayer::Object_Transition(gzEventObjectTransition &evt)
{
	if (evt.m_soldier->Player == this->GetPlayerData())
		this->m_afk_time = 0.0f;
}
void gzPlayer::Object_JumpComplete(gzEventObjectJump &evt)
{
	if (evt.m_soldier->Player == this->GetPlayerData())
	{
		for (int i = 0; i < evt.m_soldier->Observers.Count(); i++)
		{
			if (!stricmp(evt.m_soldier->Observers[i]->Get_Name(), "gzObserver_Parachute"))
			{
				evt.m_soldier->Start_Observer_Timer(evt.m_soldier->Observers[i]->GetID(), 0.0001f, 2);
				break;
			}
		}
	}
}
void gzPlayer::Object_Fire(gzEventObjectFire &evt)
{
	this->m_primaryFire = evt.m_primaryFire;
}
void gzPlayer::Net_SerialAuth(gzEventNetSerialAuth &evt)
{
	if (this->GetPlayerData() == evt.GetPlayer())
	{
		if (!strncmp(evt.m_message.GetString(), "Your CD Key is disabled.", 24))
			stConsole::Out("[ST] CD key from %ls is banned by GameSpy. (%s)\n", evt.GetPlayer()->PlayerName.m_Buffer, evt.GetPlayer()->GameSpyHashId.m_Buffer);

		else if (!stricmp(evt.m_message.GetString(), "Invalid CD Key"))
			stConsole::Out("[ST] %ls is using an invalid serial. (%s)\n", evt.GetPlayer()->PlayerName.m_Buffer, evt.GetPlayer()->GameSpyHashId.m_Buffer);

		else if (!strcmp(evt.m_message.GetString(), "CD Key in use") || !strcmp(evt.m_message.GetString(), "Validation Timeout"))
		{
			stConsole::Out("[ST] %ls is using an invalid serial. (%s)\n", evt.GetPlayer()->PlayerName.m_Buffer, evt.GetPlayer()->GameSpyHashId.m_Buffer);
		}
		else if (!strcmp(evt.m_message.GetString(), "Validated"))
		{
			stConsole::Out("[ST] %ls is using a gamespy verified serial. (%s)\n", evt.GetPlayer()->PlayerName.m_Buffer, evt.GetPlayer()->GameSpyHashId.m_Buffer);
		}
	}
}
void gzPlayer::Bhs_Poke(gzEventBhsPoke &evt)
{
	if (evt.GetPlayer() == this)
	{
		if (evt.GetPoked()->definition->Get_Class_ID() == 0x3006)
		{
			nc_C4GameObj *c4 = gzStatic_Cast(nc_C4GameObj, evt.GetPoked());
			if (c4->AmmoDef->AmmoType.Get() == 3) // Proximity C4
			{
				if (c4->Player == this->GetPlayerData())
				{
					if (c4->NetworkID == this->m_lastPokeProxy && (cGame->GameDuration_Seconds - this->m_lastPokeTime) <= 2)
					{
						this->m_pokeProxyCount++;
						if (this->m_pokeProxyCount == 3)
						{
							c4->Defuse();
							PagePlayer(this->GetPlayerData()->PlayerId, "Your Proximity C4 has been defused.");
						}
					}
					else
					{
						this->m_lastPokeProxy  = c4->NetworkID;
						this->m_lastPokeTime   = cGame->GameDuration_Seconds;
						this->m_pokeProxyCount = 1;
					}
				}
			}
		}
	}
}
nc_SoldierGameObj *gzPlayer::GetSoldier()
{
	if (this->m_gameData->Owner.Reference)
		return this->m_gameData->Owner.Reference->obj->As_SoldierGameObj();
	return NULL;
}

gzPlayerManager *gzPlayerMgr = NULL;
aList<gzPlayer> gzPlayerManager::m_list;
void gzPlayerManager::Delete()
{
	this->m_list.RemoveAll();
}
void gzPlayerManager::ChildObjCreation(gzBase *obj)
{
	this->m_list.AddTail(gzStatic_Cast(gzPlayer, obj));
}
void gzPlayerManager::ChildObjDeletion(gzBase *obj)
{
	this->m_list.Remove(gzStatic_Cast(gzPlayer, obj));
}
gzPlayerManager::gzPlayerManager()
{
	this->RegisterEvent(EVT_GAME_LEVEL_LOADED);
	this->RegisterEvent(EVT_PLAYER_JOIN);
	this->RegisterEvent(EVT_BHS_VERSION);

	gzChatCommand_Reg<gzChat_Here> gzChat_Here_Reg("!here");
	gzChatCommand_Reg<gzChat_Stuck> gzChat_Stuck_Reg("!stuck");
}
void gzPlayerManager::Level_Loaded()
{
	aListNode<gzPlayer> *pList = gzPlayerManager::m_list.GetHead();
	while (pList)
	{
		if (!pList->GetData()->IsActive())
			pList->GetData()->SetDeletePending();
		else
		{
			pList->GetData()->GetWeaponPack()->m_list.Clear();
			pList->GetData()->SetAfkPrevScore(0.0f);
			pList->GetData()->SetIsSlowLoading(true);
		}
		pList = pList->GetNext();
	}
}
void gzPlayerManager::Player_Joined(gzEventPlayerBase &evt)
{
	gzPlayer *gzData = this->Find(evt.GetPlayer());
	if (!gzData)
	{
		gzPlayer *newData = new gzPlayer(evt.GetPlayer());
		newData->SetBHSVersion(this->m_bhsVersion[evt.GetPlayer()->PlayerId]);

#if VERC(1, 1, 0)
		aSQLite3Result stid;
		if (stDb->Exec(aString::Format("SELECT * FROM player_id WHERE name = '%ls'", evt.GetPlayer()->PlayerName.m_Buffer), &stid) > -1)
		{
			if (stid.GetFirst() == NULL)
			{
				if (stDb->Exec(aString::Format("INSERT INTO player_id (name) VALUES ('%ls')", evt.GetPlayer()->PlayerName.m_Buffer), NULL) > -1)
					newData->SetStId((int)stDb->GetLastInsertId());
				else
					stDb->PrintError();
			}
			else
				newData->SetStId((int)(*stid.GetFirst())["id"].ToLong());
		}
		else
			stDb->PrintError();
#endif
		if (Get_Game_Mode() != 4)
			Request_Serial(evt.GetPlayer()->PlayerId);
	}
	else
	{
		gzData->SetIsActive(true);
		gzData->SetAfkPrevScore(evt.GetPlayer()->Score.Get());
		gzData->SetAfkTime(0.0f);
		gzData->SetAfkIsWarnSent(false);
		gzData->SetBHSVersion(this->m_bhsVersion[evt.GetPlayer()->PlayerId]);
	}
	this->m_bhsVersion[evt.GetPlayer()->PlayerId] = 0.0f;
}
void gzPlayerManager::Bhs_Version(gzEventBhsVersion &evt)
{
	this->m_bhsVersion[evt.GetInt()] = evt.GetVersion();
}
gzPlayer *gzPlayerManager::Find(int pID)
{
	if (pID >= 1 && pID <= 127 && nc_cNetwork::PServerConnection->RemoteList[pID])
	{
		for (aListNode<gzPlayer> *pList = gzPlayerManager::m_list.GetHead(); pList != NULL; pList = pList->GetNext())
		{
			if (pList->GetData()->GetPlayerData()->IsActive && pList->GetData()->GetPlayerData()->PlayerId == pID)
				return pList->GetData();
		}
	}
	return NULL;
}
gzPlayer *gzPlayerManager::Find(nc_cPlayer *pData)
{
	for (aListNode<gzPlayer> *pList = gzPlayerManager::m_list.GetHead(); pList != NULL; pList = pList->GetNext())
	{
		if (pList->GetData()->GetPlayerData() == pData)
			return pList->GetData();
	}
	return NULL;
}
gzPlayer* gzPlayerManager::Find(const aString& name)
{
	for (aListNode<gzPlayer> *pList = gzPlayerManager::m_list.GetHead(); pList != NULL; pList = pList->GetNext())
	{
		if (pList->GetData()->GetPlayerName().Compare(name))
			return pList->GetData();
	}
	return NULL;
}
gzPlayer* gzPlayerManager::FindByPartName(const aString& name)
{
	for (aListNode<gzPlayer> *pList = gzPlayerManager::m_list.GetHead(); pList != NULL; pList = pList->GetNext())
	{
		if (pList->GetData()->GetPlayerData()->IsActive && pList->GetData()->GetPlayerName().Contain(name))
			return pList->GetData();
	}
	return NULL;
}
int gzPlayerManager::FindByPartNameCount(const aString& name)
{
	int count = 0;
	for (aListNode<gzPlayer> *pList = gzPlayerManager::m_list.GetHead(); pList != NULL; pList = pList->GetNext())
	{
		if (pList->GetData()->GetPlayerData()->IsActive && pList->GetData()->GetPlayerName().Contain(name))
			count++;
	}
	return count;
}


/******************/
/* Serial manager */
/******************/
gzSerialManager *gzSerialMgr = NULL;
gzSerialManager::gzSerialManager()
{
	this->RegisterEvent(EVT_PLAYER_SERIALHASH);

#if VERCL(1, 0, 1)
	FILE *list = fopen(SERIALBAN_FILE, "r");
	if (list)
	{
		char buf[512];
		buf[0] = '\0';
		while (!feof(list) && fgets(buf,511,list))
		{
			for (unsigned int i = strlen(buf) -1; i >= 0; i--)
			{
				if (buf[i] == '\n' || buf[i] == '\r')
					buf[i] = '\0';
				else
					break;
			}
			gzSerialBanStruct *sban = new gzSerialBanStruct;
			sban->hash.Printf("%.32s",buf);
			sban->reason = (buf + 32);
			this->m_banned.Add(sban);
		}
		fclose(list);
	}
#endif
}
void gzSerialManager::Delete()
{
#if VERCL(1, 0, 1)
	this->Save();
	for (unsigned int i = 0; i < this->m_banned.Count(); i++)
		delete this->m_banned[i];
	this->m_banned.Clear();
#endif
}
void gzSerialManager::Player_SerialHash(gzEventPlayerSerialHash &evt)
{
#if VERC(1, 1, 0)
	aSQLite3Result res;
	if (stDb->Exec(aString::Format("SELECT * FROM serial_ban WHERE hash = '%.32s'", evt.m_hash.GetString()), &res) > -1)
	{
		if (res.Count() > 0)
		{
			stConsole::Out("[ST] %ls is using serial %.32s and is in ban list.\n", evt.GetPlayer()->PlayerName.m_Buffer, evt.m_hash.GetString());
			stConsole::In("kick %d", evt.GetPlayer()->PlayerId);
			return;
		}
	}
	else
		stDb->PrintError();
#else
	char hash32[33];
	strncpy(hash32, evt.m_hash.GetString(), 32);
	hash32[32] = '\0';

	for (unsigned int i = 0; i < this->m_banned.Count(); i++)
	{
		if (this->m_banned[i]->hash == hash32)
		{
			stConsole::Out("[ST] %ls is using serial %.32s and is in ban list.\n", evt.GetPlayer()->PlayerName.m_Buffer, evt.m_hash.GetString());
			stConsole::In("kick %d", evt.GetPlayer()->PlayerId);
			return;
		}
	}
#endif
}
void gzSerialManager::Save()
{
#if VERCL(1, 0, 1)
	FILE *list = fopen("sBan.tmp", "w");
	if (list)
	{
		for (unsigned int i = 0; i < this->m_banned.Count(); i++)
			fprintf(list,"%s%ls\n", this->m_banned[i]->hash.GetString(), this->m_banned[i]->reason.GetString());
		fclose(list);
		remove("sBan.dat");
		if (rename("sBan.tmp", "sBan.dat") != 0)
			stConsole::Out("FATAL ERROR - Failed to save serial ban list.\n");
	}
#endif
}
bool gzSerialManager::Hash_Ban(const char *hash, const char *reason)
{
	if (!reason || !*reason)
		reason = "No reason";
#if VERC(1, 1, 0)
	aSQLite3Result res;
	if (stDb->Exec(aString::Format("SELECT * FROM serial_ban WHERE hash = '%.32s'", hash), &res) > -1)
	{
		if (res.Count() > 0)
		{
			stConsole::Out("[ST] Serial %.32s is already in the ban list.\n", hash);
			return false;
		}
		if (stDb->Exec(aString::Format("INSERT INTO serial_ban VALUES ('%.32s', '%s')", hash, reason), NULL) == -1)
		{
			stDb->PrintError();
			return false;
		}
	}
	else
		stDb->PrintError();
#else
	for (unsigned int i = 0; i < this->m_banned.Count(); i++)
	{
		if (this->m_banned[i]->hash == hash)
		{
			stConsole::Out("[ST] Serial %s is already in the ban list.\n", hash);
			return false;
		}
	}
	gzSerialBanStruct *sban = new gzSerialBanStruct;
	sban->hash = hash;
	sban->reason = (reason == NULL || *reason == '\0') ? "No reason" : reason;
	this->m_banned.Add(sban);
#endif
	return true;
}
bool gzSerialManager::Hash_Unban(const aString& hash)
{
#if VERC(1, 1, 0)
	if (stDb->Exec(aString::Format("DELETE FROM serial_ban WHERE hash = '%.32s'", hash.GetString())) > -1)
	{
		if (stDb->RecentChanges() > 0)
			return true;
	}
	else
		stDb->PrintError();
#else
	for (unsigned int i = 0; i < this->m_banned.Count(); i++)
	{
		if (this->m_banned[i]->hash == hash)
		{
			delete this->m_banned[i];
			this->m_banned.Delete(i);
			this->Save();
			return true;
		}
	}
#endif
	return false;
}
void gzSerialManager::Hash_Search(const aString& string, aVector<gzSerialBanStruct *> &buffer)
{
#if VERC(1, 1, 0)
	aSQLite3Result res;
	if (stDb->Exec(aString::Format("SELECT * FROM serial_ban WHERE hash LIKE '%%%s%%'", string.GetString()), &res) > -1)
	{
		for (aMap<aString>* row = res.GetFirst(); row != NULL; row = res.GetNext())
		{
			gzSerialBanStruct *sbs = new gzSerialBanStruct;
			sbs->hash = (*row)["hash"];
			sbs->reason = (*row)["reason"];
			buffer.Add(sbs);
		}
	}
	else
		stDb->PrintError();
#else
	for (unsigned int i = 0; i < this->m_banned.Count(); i++)
	{
		if (this->m_banned[i]->hash.Contain(string))
			buffer.Add(this->m_banned[i]);
	}
#endif
}


/*****************/
/* Chat commands */
/*****************/
class gzChat_Here : public gzChatCommandBase {
	void Activate(const wchar_t *msg, int type, int sender, int receiver, aWideString &ret)
	{
		gzPlayer *gzData = gzPlayerManager::Find(sender);
		if (gzData)
		{
			if ((gzGameMgr->m_settings->m_AllowAfkSeconds - gzData->GetAfkTime()) <= 30.0f)
			{
				gzData->SetAfkTime(0.0f);
				gzData->SetAfkIsWarnSent(false);
				PagePlayer(sender, "You've been removed AFK kick queue.");
			}
		}
	}
};

class gzChat_Stuck : public gzChatCommandBase {
	void Activate(const wchar_t *msg, int type, int sender, int receiver, aWideString &ret)
	{
		gzPlayer *gzData = gzPlayerManager::Find(sender);
		if (gzData)
		{
			if (gzData->GetPlayerData()->Owner.Reference)
			{
				if (gzData->GetPlayerData()->Owner.Reference->obj->As_SoldierGameObj()->Vehicle)
					PagePlayer(sender, "You can not use this command while you are in vehicle.");
				else if (!gzData->GetPlayerData()->Owner.Reference->obj->As_PhysicalGameObj()->Physics->As_MoveablePhysClass()->Can_Teleport_And_Stand(*gzData->GetPlayerData()->Owner.Reference->obj->As_PhysicalGameObj()->Get_Transform(), gzData->GetPlayerData()->Owner.Reference->obj->As_PhysicalGameObj()->Get_Transform()))
				{
					gzData->GetPlayerData()->Deaths -= 1;
					gzData->GetPlayerData()->Owner.Reference->obj->Set_Delete_Pending();
					PagePlayer(sender, "You've been respawned because you issued \"!stuck\" command and confirmed you were stuck.");
				}
				else
					PagePlayer(sender, "You are not currently stuck.");
			}
		}
	}
};


/*************/
/* Observers */
/*************/
void gzObserverSoldier::Created(nc_ScriptableGameObj *obj)
{
	this->m_Soldier = obj->As_SoldierGameObj();

	// Bot
	if (!this->m_Soldier->Player)
	{
		this->Destroy_Script();
		return;
	}

	// Force team
	if (gzGameMgr->m_settings->m_ForceTeam > -1)
	{
		this->m_Soldier->Player->PlayerType = gzGameMgr->m_settings->m_ForceTeam;
		this->m_Soldier->Set_Delete_Pending();
		return;
	}

	// Game type check
	if (gzGameMgr->m_settings->m_GameMode != GAMEMODE_AOW)
		this->m_Soldier->IsVisible = false;

	this->m_tibDamage = false;
	this->m_fallDeath = false;
	this->m_squishDeath = false;
	this->m_killed = false;
	this->m_killer = NULL;

	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "VehBind,1");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "VehBL,2");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "VehStatus,3");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "C4Count,4");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "WeapDrop,5");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "HarvUplink,6");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "VetInfo,7");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "Parachute,8");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "RequestRepairs,9");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "VetInfo,10");
	gzCommands->Attach_Script(obj, "gzKeyHook_ProcCmd", "Parachute,11");
	gzCommands->Attach_Script(obj, "gzKeyHook_WriteLog", "VoteYes,!vote yes,0");
	gzCommands->Attach_Script(obj, "gzKeyHook_WriteLog", "VoteNo,!vote no,0");
	gzCommands->Attach_Script(obj, "gzKeyHook_NumpadToggle", "ToggleNumPad,1");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt1,0");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt2,1");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt3,2");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt4,3");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt5,4");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt6,5");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt7,6");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt8,7");
	gzCommands->Attach_Script(obj, "gzKeyHook_Numpad","Taunt9,8");

	if (!strstr(obj->definition->Get_Name(), "CnC_Visceroid"))
	{
		if (gzWeaponMgr->m_settings->Weapons.CarryOverOnCharacterPurchase)
		{
			gzPlayer *pData = gzPlayerManager::Find(this->m_Soldier->Player);
			if (pData)
				pData->GetWeaponPack()->Grant();
		}
	}

	if (gzGameMgr->m_settings->m_LogSoldierPurchase)
		gzLogger("_PURCHASE", "%ls purchased a %s",
		this->m_Soldier->Player->PlayerName.m_Buffer,
		gzTranslator->Get(this->m_Soldier)
	);
}
void gzObserverSoldier::Custom(nc_ScriptableGameObj *obj, int message, int param, nc_ScriptableGameObj *sender)
{
	bool timerExist = false;
	switch (message)
	{
		case 306491:
			obj->Get_Position(&this->m_fallPos);
			break;
		case 306492:
			this->m_squishDeath = param;
			break;
		case 306494:
			for (int i = 0; i < obj->ObserverTimers.Count(); i++)
			{
				if (obj->ObserverTimers[i]->TimerNum == 11)
				{
					obj->ObserverTimers[i]->Time = 3.0f;
					timerExist = true;
					break;
				}
			}
			this->m_tibDamage = param;
			if (!timerExist)
				obj->Start_Observer_Timer(this->GetID(), 3.0f, 11);
			break;

		case 1000000035:
			if ((obj->As_DamageableGameObj()->Defense.Health.Get() - (float)param) < 1.0f)
			{
				this->m_fallDeath = true;
				obj->Start_Observer_Timer(this->GetID(), 0.0f, 10);
			}
			break;
	}
}
void gzObserverSoldier::Damaged(nc_ScriptableGameObj *obj, nc_ScriptableGameObj *damager, float damage)
{
	this->m_lastDamage = damage;
}
void gzObserverSoldier::Destroyed(nc_ScriptableGameObj *obj)
{
	gzPlayer *pData = gzPlayerManager::Find(this->m_Soldier->Player);
	if (pData && this->m_killed)
	{
		if (gzWeaponMgr->m_settings->Weapons.DropOnDeath)
		{
			int bpDataIndex = -1;
			for (unsigned int i = 0; i < gzWeaponMgr->m_settings->Backpack.DropData.Count(); i++)
			{
				if (gzWeaponMgr->m_settings->Backpack.DropData[i]->preset == obj->definition->Get_Name() &&
					gzWeaponMgr->m_settings->Backpack.DropData[i]->totalpercent > 0)
				{
					bpDataIndex = i;
					break;
				}
			}
			if (pData->GetWeaponPack()->GetWeaponsCount() > 0 || bpDataIndex != -1)
			{
				gzWeaponPackClass *newPack = new gzWeaponPackClass(false);
				if (bpDataIndex != -1)
				{
					int randomPercent = stRandom.Get_Int(1, 100);
					int percent = 0;
					for (unsigned int i = 0; i < gzWeaponMgr->m_settings->Backpack.DropData[bpDataIndex]->m_weapons.Count(); i++)
					{
						percent += gzWeaponMgr->m_settings->Backpack.DropData[bpDataIndex]->m_weapons[i]->percent;
						if (percent >= randomPercent)
						{
							newPack->m_backpackData = gzWeaponMgr->m_settings->Backpack.DropData[bpDataIndex]->m_weapons[i];
							newPack->Add_Weapon(gzWeaponMgr->m_settings->Backpack.DropData[bpDataIndex]->m_weapons[i]->powerup);
							break;
						}
					}
				}
				newPack->Append(pData->GetWeaponPack());
				gzBackpackClass *backpack = new gzBackpackClass;
				backpack->SetWeaponPack(newPack);
				obj->Get_Position(&backpack->GetPosition());
				backpack->SetCanExpire(gzWeaponMgr->m_settings->Backpack.Live != -1.0f);
				backpack->SetLive(gzWeaponMgr->m_settings->Backpack.Live);
				backpack->SetOwner(this->m_killer);
				backpack->Create();
				newPack->SetChildOwner(backpack);
			}
		}
		pData->GetWeaponPack()->m_list.Clear();
	}
}
void gzObserverSoldier::Killed(nc_ScriptableGameObj *obj, nc_ScriptableGameObj *shooter)
{
	this->m_killed = true;
	if (shooter && shooter->As_SoldierGameObj() && shooter->As_SoldierGameObj()->Player)
		this->m_killer = shooter->As_SoldierGameObj()->Player;

	aString preset[] = {
		GetPresetInfo(obj->As_PhysicalGameObj(), false),
		GetPresetInfo(shooter ? shooter->As_PhysicalGameObj() : NULL, true)
	};

	aWideString pName = gzTranslator->Get(shooter);
	if (this->m_Soldier->Player)
		pName = this->m_Soldier->Player->PlayerName.m_Buffer;

	nc_Vector3 objColor;
	if (shooter && shooter->As_DamageableGameObj())
	{
		objColor.X = shooter->As_DamageableGameObj()->Get_Team_Color().X * 255.0f;
		objColor.Y = shooter->As_DamageableGameObj()->Get_Team_Color().Y * 255.0f;
		objColor.Z = shooter->As_DamageableGameObj()->Get_Team_Color().Z * 255.0f;
	}
	else
	{
		objColor.X = this->m_Soldier->Get_Team_Color().X * 255.0f;
		objColor.Y = this->m_Soldier->Get_Team_Color().Y * 255.0f;
		objColor.Z = this->m_Soldier->Get_Team_Color().Z * 255.0f;
	}

	if (gzGameMgr->m_settings->m_LogSoldierDeath)
	{
		if (this->m_squishDeath)
		{
			if (shooter->As_SoldierGameObj() && shooter->As_SoldierGameObj()->Player)
			{
				gzLogger("_PLAYERKILL", "%ls (%s) was squished by %ls (%s)",
					pName.GetString(),
					preset[0].GetString(),
					shooter->As_SoldierGameObj()->Player->PlayerName.m_Buffer,
					preset[1].GetString()
				);
			}
			else
			{
				gzLogger("_PLAYERKILL", "%ls (%s) was squished by %s",
					pName.GetString(),
					preset[0].GetString(),
					gzTranslator->Get(shooter)
				);
				SendBhsColorMsg(objColor, "%ls was squished by %s",
					pName.GetString(),
					gzTranslator->Get(shooter)
				);
			}
		}
		else if (!shooter)
		{
			if (this->m_tibDamage && this->m_lastDamage <= 0.5f)
			{
				gzLogger("_PLAYERKILL", "%ls (%s) was killed by Tiberium Poison", pName.GetString(), preset[0].GetString());
				SendBhsColorMsg(objColor, "%ls was killed by Tiberium Poison", pName.GetString());
			}

			else if (this->m_fallDeath)
			{
				gzLogger("_PLAYERKILL", "%ls has fallen down (%s); Fall distance: %.2f", pName.GetString(), preset[0].GetString(), this->m_fallPos.Z - gzCommands->Get_Position(obj).Z);
				SendBhsColorMsg(objColor, "%ls has fallen down; Fall distance: %.2f",
					pName.GetString(),
					this->m_fallPos.Z - gzCommands->Get_Position(obj).Z
				);
			}
			else
			{
				gzLogger("_PLAYERKILL", "%ls was killed (%s)", pName.GetString(), preset[0].GetString());
				SendBhsColorMsg(objColor, "%ls was killed", pName.GetString());
			}
		}

		else if (obj == shooter)
		{
			gzLogger("_PLAYERKILL", "%ls killed himself (%s)", pName.GetString(), preset[1].GetString());
			SendBhsColorMsg(objColor, "%ls killed himself", pName.GetString());
		}

		else if (!shooter->As_SoldierGameObj())
		{
			gzLogger("_PLAYERKILL", "The %s killed %ls (%s)", gzTranslator->Get(shooter), pName.GetString(), preset[0].GetString());
			SendBhsColorMsg(objColor, "The %s killed %ls",
				gzTranslator->Get(shooter),
				pName.GetString()
			);
		}

		else
		{
			gzPlayer *gzData = gzPlayerManager::Find(shooter->As_SoldierGameObj()->Player);
			if (gzData && gzData->GetHitLog() && gzData->GetHitLog()->GetHitCount(obj->NetworkID, 1) > 0)
			{
				gzHitLogStruct *hitData = gzData->GetHitLog()->GetLast(obj->NetworkID);
				gzLogger(
					"_PLAYERKILL",
					"%ls killed %ls (%s Vs. %s); LP: %c; RD: %.2f; Hits: %d",
					this->m_killer ? this->m_killer->PlayerName.m_Buffer : L"NotPlayer",
					pName.GetString(),
					preset[1].GetString(),
					preset[0].GetString(),
					gzData->IsLastPrimaryFire() ? 'P' : 'S',
					hitData->m_damage,
					gzData->GetHitLog()->GetHitCount(obj->NetworkID, 1)
				);
			}
			else
			{
				gzLogger(
					"_PLAYERKILL",
					"%ls killed %ls (%s Vs. %s)",
					this->m_killer ? this->m_killer->PlayerName.m_Buffer : L"NotPlayer",
					pName.GetString(),
					preset[1].GetString(),
					preset[0].GetString()
				);
			}
		}
	}
}
void gzObserverSoldier::Timer_Expired(nc_ScriptableGameObj *obj, int number)
{
	switch (number)
	{
		case 10:
			this->m_fallDeath = false;
			break;

		case 11:
			this->m_tibDamage = false;
			break;
	}
}
nc_ScriptRegistrant<gzObserverSoldier> gzObserverSoldier_Registrant("gzObserverSoldier", "");

void gzObserverSpectator::Created(nc_ScriptableGameObj *obj) {
	if (!obj->As_SoldierGameObj())
	{
		this->Destroy_Script();
		return;
	}
	this->m_owner = gzPlayerManager::Find(obj->As_SoldierGameObj()->Player);
	if (this->m_owner == NULL)
	{
		this->Destroy_Script();
		return;
	}
	if (this->m_owner->GetSoldier()->Vehicle)
	{
		PagePlayer(this->m_owner->GetPlayerData()->PlayerId, "Please exit your vehicle first!");
		this->Destroy_Script();
		return;
	}
	this->m_owner->SetIsSpectator(true);
	this->Custom(obj, 2095, 0, 0);
	this->m_owner->GetSoldier()->Defense.HealthMax = 2000.0f;
	this->m_owner->GetSoldier()->Defense.ShieldStrengthMax = 2000.0f;
	this->m_owner->GetSoldier()->WeaponBag->Clear_Weapons();
	this->m_owner->GetSoldier()->Physics->Set_Model_By_Name("null");
	this->m_owner->GetSoldier()->IsVisible = false;
	this->m_owner->GetSoldier()->Toggle_Fly_Mode();
	gzCommands->Disable_All_Collisions(obj);
	this->Timer_Expired(obj, 1);
	this->Timer_Expired(obj, 2);
	for (nc_GenericSLNode<nc_BaseGameObj> *objList = nc_GameObjManager::GameObjList->HeadNode; objList != NULL; objList = objList->NodeNext)
	{
		nc_OffenseObjectClass *offense = 0;
		if (objList->NodeData->definition->Get_Class_ID() == 0x3006 &&
			((nc_C4GameObj *)objList->NodeData)->Owner.Reference &&
			((nc_C4GameObj *)objList->NodeData)->Owner.Reference->obj->NetworkID == obj->NetworkID)
		{
			objList->NodeData->As_PhysicalGameObj()->Completely_Damaged(*offense);
		}
		else if (objList->NodeData->definition->Get_Class_ID() == 0x3016 &&
			((nc_BeaconGameObj *)objList->NodeData)->Owner.Reference &&
			((nc_BeaconGameObj *)objList->NodeData)->Owner.Reference->obj->NetworkID == obj->NetworkID)
		{
			objList->NodeData->As_PhysicalGameObj()->Completely_Damaged(*offense);
		}
	}
	this->m_owner->GetSoldier()->Set_Object_Dirty_Bit(nc_DB_RARE, true);
	this->m_owner->GetSoldier()->Set_Object_Dirty_Bit(nc_DB_OCCASIONAL, true);
	PagePlayer(this->m_owner->GetPlayerData()->PlayerId, "You are now in Spectator Mode. You may use \"!setspeed [1-50]\" to change your moving speed.");
}
void gzObserverSpectator::Custom(nc_ScriptableGameObj *obj, int message, int param, nc_ScriptableGameObj *sender) {
	if (message == 2095)
	{
		if (Get_Int_Parameter("Type") == 1)
		{
			obj->DeletePending = true;
			for (nc_GenericSLNode<nc_cPlayer> *pList = nc_cPlayerManager::PlayerList->HeadNode; pList != NULL; pList = pList->NodeNext)
			{
				if (pList->NodeData->IsActive && pList->NodeData->PlayerId != this->m_owner->GetPlayerData()->PlayerId)
					nc_cNetwork::Send_Object_Update(obj, pList->NodeData->PlayerId);
			}
			obj->DeletePending = false;
		}
	}
}
void gzObserverSpectator::Destroyed(nc_ScriptableGameObj *obj)
{
	if (this->m_owner->GetSoldier())
		this->m_owner->SetIsSpectator(false);
}
void gzObserverSpectator::Timer_Expired(nc_ScriptableGameObj *obj, int number) {
	if (number == 1)
	{
		this->m_owner->GetSoldier()->WeaponBag->Clear_Weapons();
		obj->Start_Observer_Timer(this->GetID(), 1.0f, 1);
	}
	else if (number == 2)
	{
		this->Custom(obj, 2095, 0, 0);
		obj->Start_Observer_Timer(this->GetID(), 5.0f, 2);
	}
}
nc_ScriptRegistrant<gzObserverSpectator> gzObserverSpectator_Registrant("gzSpectator","Type:int");

void gzFreeze_Player::Created(nc_ScriptableGameObj *obj) {
	obj->Get_Position(&this->m_pos);
	this->Timer_Expired(obj, 1);
}
void gzFreeze_Player::Custom(nc_ScriptableGameObj *obj, int message, int param, nc_ScriptableGameObj *sender) {
	if (message == 703165)
	{
		this->Destroy_Script();
	}
}
void gzFreeze_Player::Timer_Expired(nc_ScriptableGameObj *obj,int number) {
	if (number == 1)
	{
		obj->As_PhysicalGameObj()->Set_Position(this->m_pos);
		obj->Start_Observer_Timer(this->GetID(), 0.0f, 1);
	}
}
nc_ScriptRegistrant<gzFreeze_Player> gzFreeze_Player_Registrant("gzFreeze_Player","");

void PagePlayer(int pID, const char *msg, ...)
{
	if (!*msg)
		return;
	va_list arg;
	va_start(arg, msg);
	int size = _vscprintf(msg, arg);
	char *fmsg = new char[size + 1];
	vsprintf(fmsg, msg, arg);
	va_end(arg);
	nc_WideStringClass wstr;
	wstr.Get_String(0, false);
	wstr.Convert_From(fmsg);
	Send_Text_Msg(wstr, 2, false, -1, pID);
	wstr.Free_String();
	delete [] fmsg;
}

/********************/
/* Console commands */
/********************/
class SpectateConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name() {
		return "spectate";
	}
	char *Get_Alias() {
		return "spec";
	}
	char *Get_Help() {
		return "SPECTATE <player> - Set/Remove <player> to/from Spectator Mode.";
	}
	void Activate(char *text) {
		if (!*text)
			return;

		gzPlayer *gzData = gzPlayerManager::Find(atoi(text));
		if (gzData == NULL || gzData->GetSoldier() == NULL)
			return;

		if (gzData->IsSpectator())
		{
			PagePlayer(gzData->GetPlayerData()->PlayerId, "You are no longer in Spectator Mode.");
			gzData->GetPlayerData()->Deaths -= 1;
			gzData->GetSoldier()->Set_Delete_Pending();
		}
		else
		{
			nc_ScriptImpClass *observer = nc_ScriptManager::Create_Script("gzSpectator");
			observer->Set_Parameters_String("0");
			gzData->GetSoldier()->Add_Observer(observer);
		}
	}
};
SpectateConsoleFunction spectate;

class NewSpectateConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name() {
		return "newspectate";
	}
	char *Get_Alias() {
		return "nspec";
	}
	char *Get_Help() {
		return "NEWSPECTATE <player> - Set/Remove <player> to/from Spectator Mode.";
	}
	void Activate(char *text) {
		if (!*text)
			return;

		gzPlayer *gzData = gzPlayerManager::Find(atoi(text));
		if (gzData == NULL || gzData->GetSoldier() == NULL)
			return;

		if (gzData->IsSpectator())
		{
			PagePlayer(gzData->GetPlayerData()->PlayerId, "You are no longer in Spectator Mode.");
			gzData->GetPlayerData()->Deaths -= 1;
			gzData->GetSoldier()->Set_Delete_Pending();
		}
		else
		{
			nc_ScriptImpClass *observer = nc_ScriptManager::Create_Script("gzSpectator");
			observer->Set_Parameters_String("1");
			gzData->GetSoldier()->Add_Observer(observer);
		}
	}
};
NewSpectateConsoleFunction newspectate;

class SetPlayerSpeedConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "setspeed";
	};
	char *Get_Alias(void)
	{
		return "speed";
	};
	char *Get_Help(void)
	{
		return "SETSPEED <player_id> <speed> - Set the speed for player with id <player_id> to <speed>.";
	};
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken token(text);
		if (token.numtok(' ') != 2)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(token.gettok(1, ' ').ToLong());
		if (!pData || !pData->Owner.Reference)
			return;
		int speed = token.gettok(2, ' ').ToLong();
		if (speed <= 0)
			return;
		pData->Owner.Reference->obj->As_SoldierGameObj()->Set_Max_Speed((float)speed);
		stConsole::Out("Speed for player %ls has been set to %d.\n", pData->PlayerName.m_Buffer, speed);
	}
};
SetPlayerSpeedConsoleFunction setspeed;

class GetPlayerSpeedConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "getspeed";
	}
	char *Get_Help(void)
	{
		return "GETSPEED <player_id> - Get the current speed of player with id <player_id>.";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken token(text);
		if (token.numtok(' ') != 2)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(token.gettok(1, ' ').ToLong());
		if (!pData || !pData->Owner.Reference)
			return;
		stConsole::Out("Current speed for player %ls is %.0f.\n", pData->PlayerName.m_Buffer, pData->Owner.Reference->obj->As_SoldierGameObj()->Get_Max_Speed());
	}
};
GetPlayerSpeedConsoleFunction getspeed;

class GiveCreditConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "givecredit";
	}
	char *Get_Alias(void)
	{
		return "credit";
	}
	char *Get_Help(void)
	{
		return "GIVECREDIT <player> <amount> - Give the <amount> of credit(s) to <player>. (Negative amount works too)";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken tok(text);

		if (tok.numtok(' ') != 2)
			return;

		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(tok.gettok(1, ' ').ToLong());
		if (pData)
			pData->Increment_Money((float)tok.gettok(2, ' ').ToDouble());
	}
};
GiveCreditConsoleFunction givecredit;

class GivePointConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "givescore";
	}
	char *Get_Alias(void)
	{
		return "score";
	}
	char *Get_Help(void)
	{
		return "GIVEPOINT <player> <amount> - Give the <amount> of point(s) to <player>. (Negative amount works too)";
	}
	void Activate(char *text){
		if (!*text)
			return;
		aToken tok(text);

		if (tok.numtok(' ') != 2)
			return;

		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(tok.gettok(1, ' ').ToLong());
		if (pData)
			pData->Increment_Score((float)tok.gettok(2, ' ').ToDouble());
	}
};
GivePointConsoleFunction givept;

class GetPosConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "getpos";
	}
	char *Get_Help(void)
	{
		return "GETPOS <player> - Display the current coordinates of <player>.";
	}
	void Activate(char *text){
		if (!*text)
			return;
		
		aString id = text;

		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(id.ToLong());
		if (pData && pData->Owner.Reference)
		{
			nc_Vector3 pos;
			pData->Owner.Reference->obj->Get_Position(&pos);
			stConsole::Out("Current position of %ls:\nX:%f\nY:%f\nZ:%f\n",
				pData->PlayerName.m_Buffer,
				pos.X,
				pos.Y,
				pos.Z
			);
		}
	}
};
GetPosConsoleFunction getpos;

class KillConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "kill";
	}
	char *Get_Help(void)
	{
		return "KILL <player> - Kill <player> and vehicle(if the driver is <player>).";
	}
	void Activate(char *text) {
		if (!*text)
			return;
		aToken str(text);
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(str.gettok(1,' ').ToLong());
		if (pData && pData->Owner.Reference)
		{
			if (pData->Owner.Reference->obj->As_SoldierGameObj()->Vehicle)
			{
				nc_VehicleGameObj *veh = pData->Owner.Reference->obj->As_SoldierGameObj()->Vehicle;

				// Driver check
				bool isDriver = false;
				if (veh->SeatsList[0] == pData->Owner.Reference->obj)
					isDriver = true;

				nc_TransitionManager::Check(pData->Owner.Reference->obj->As_SoldierGameObj(), true);
				if (isDriver)
					veh->Set_Delete_Pending();
			}
			nc_ScriptableGameObj *killer = NULL;
			if (str.gettok(2,' ').ToLong())
			{
				nc_cPlayer *kData = nc_cPlayerManager::Find_Player(str.gettok(2, ' ').ToLong());
				if (kData && kData->Owner.Reference)
					killer = kData->Owner.Reference->obj;
			}
			gzCommands->Apply_Damage(pData->Owner.Reference->obj, 9999.0f, "Death", killer);
		}
	}
};
KillConsoleFunction kill;

class FreezeConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name()
	{
		return "freeze";
	}
	char *Get_Help()
	{
		return "FREEZE <player> - Set/Remove <player> to/from Freeze Mode.";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		int id = atoi(text);
		if (id == 0)
			return;
		nc_SoldierGameObj *Soldier = nc_GameObjManager::Find_Soldier_Of_Client_ID(id);
		if (Soldier)
		{
			int observerID = -1;
			for (int i = 0; i < Soldier->Observers.Count(); i++)
			{
				if (!stricmp(Soldier->Observers[i]->Get_Name(),"gzFreeze_Player"))
				{
					observerID = i;
					break;
				}
			}
			if (observerID == -1)
			{
				nc_ScriptImpClass *observer = nc_ScriptManager::Create_Script("gzFreeze_Player");
				if (observer)
					Soldier->Add_Observer(observer);
			}
			else
				Soldier->Observers[observerID]->Custom(NULL, 703165, 0, NULL);
		}
	}
};
FreezeConsoleFunction freeze;

class TeamConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void) {
		return "team";
	}
	char *Get_Alias()
	{
		return "tc";
	};
	char *Get_Help(void) {
		return "TEAM <player> <team> - Changes a player team. Host only.\n0 = Nod\n1 = GDI";
	}
	void Activate(char *text) {
		if (!*text)
			return;
		aToken Token = text;
		if (Token.numtok(' ') != 2)
			return;
		int id = Token.gettok(1, ' ').ToLong(),
			team = Token.gettok(2, ' ').ToLong();
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(id);
		if (!pData || pData->PlayerType.Get() == team || !pData->Owner.Reference)
			return;
		pData->Deaths -= 1;
		pData->Money = 0.0f;
		pData->Score = 0.0f;
		pData->PlayerType = team;
		pData->Set_Object_Dirty_Bit(nc_DB_OCCASIONAL,true);
		pData->Set_Object_Dirty_Bit(nc_DB_RARE,true);
		for (nc_GenericSLNode<nc_BaseGameObj> *objList = nc_GameObjManager::GameObjList->HeadNode; objList != NULL; objList = objList->NodeNext)
		{
			nc_OffenseObjectClass *offense = NULL;
			if (objList->NodeData->definition->Get_Class_ID() == 0x3006 &&
				((nc_C4GameObj *)objList->NodeData)->Owner.Reference &&
				((nc_C4GameObj *)objList->NodeData)->Owner.Reference->obj->NetworkID == pData->Owner.Reference->obj->NetworkID)
			{
				objList->NodeData->As_PhysicalGameObj()->Completely_Damaged(*offense);
			}
			else if (objList->NodeData->definition->Get_Class_ID() == 0x3016 &&
				((nc_BeaconGameObj *)objList->NodeData)->Owner.Reference &&
				((nc_BeaconGameObj *)objList->NodeData)->Owner.Reference->obj->NetworkID == pData->Owner.Reference->obj->NetworkID)
			{
				objList->NodeData->As_PhysicalGameObj()->Completely_Damaged(*offense);
			}
		}
		pData->Owner.Reference->obj->Set_Delete_Pending();
	}
};
TeamConsoleFunction team;

class Team2ConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void){
		return "team2";
	}
	char *Get_Alias()
	{
		return "tc2";
	};
	char *Get_Help(void){
		return "TEAM2 <player> <team> - Changes a players team without taking cash/score Host only.\n0 = Nod\n1 = GDI";
	}
	void Activate(char *text) {
		if (!*text)
			return;
		aToken Token = text;
		if (Token.numtok(' ') != 2)
			return;
		int id = Token.gettok(1, ' ').ToLong(),
			team = Token.gettok(2, ' ').ToLong();
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(id);
		if (!pData || pData->PlayerType.Get() == team || !pData->Owner.Reference)
			return;

#if ISDEV()
		if (cGame->Is_Gameplay_Permitted())
			pData->Deaths -= 1;
#else
		pData->Deaths -= 1;
#endif
		pData->PlayerType = team;
		pData->Set_Object_Dirty_Bit(nc_DB_OCCASIONAL,true);
		pData->Set_Object_Dirty_Bit(nc_DB_RARE,true);
		for (nc_GenericSLNode<nc_BaseGameObj> *objList = nc_GameObjManager::GameObjList->HeadNode; objList != NULL; objList = objList->NodeNext)
		{
			nc_OffenseObjectClass *offense = 0;
			if (objList->NodeData->definition->Get_Class_ID() == 0x3006 &&
				((nc_C4GameObj *)objList->NodeData)->Owner.Reference &&
				((nc_C4GameObj *)objList->NodeData)->Owner.Reference->obj->NetworkID == pData->Owner.Reference->obj->NetworkID)
			{
				objList->NodeData->As_PhysicalGameObj()->Completely_Damaged(*offense);
			}
			else if (objList->NodeData->definition->Get_Class_ID() == 0x3016 &&
				((nc_BeaconGameObj *)objList->NodeData)->Owner.Reference &&
				((nc_BeaconGameObj *)objList->NodeData)->Owner.Reference->obj->NetworkID == pData->Owner.Reference->obj->NetworkID)
			{
				objList->NodeData->As_PhysicalGameObj()->Completely_Damaged(*offense);
			}
		}
		pData->Owner.Reference->obj->Set_Delete_Pending();
	}
};
Team2ConsoleFunction team2;

class PlayerInfoConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void) {
		return "player_info";
	}
	char *Get_Alias() {
		return "pi";
	}
	char *Get_Help(void) {
		return "PLAYER_INFO <string> - Print info about player name contains <string> if specified or all in the game to the console box";
	}
	void Activate(char *text) {
		if (nc_cNetwork::PServerConnection->Connection_Count == 0)
			stConsole::Out("No players\n");
		else
		{
			int Bandwidth = 0;
			stConsole::Out("\rId  Name           Score Side\tPing\tAddress               Kbits/s Time\n\n");
			for (unsigned int i = 1; i <= nc_cNetwork::PServerConnection->MaxConnections; i++)
			{
				nc_cPlayer *pData = nc_cPlayerManager::Find_Player(i);
				if (pData)
				{
					nc_cRemoteHost *RemoteHost = nc_cNetwork::PServerConnection->Get_Remote_Host(i);
					Bandwidth += PacketMgr->Get_Compressed_Bandwidth_Out(&RemoteHost->Address);
					aString name = pData->PlayerName.m_Buffer;
					if (!*text || name.Contain(text))
					{
						const char *format = "%3d %-14s %-6.0f %s\t%d\t%-21s %-7d %.3d.%.2d.%.2d\n";
						if (pData->Score.Get() < 0.0f)
							format = "%3d %-13s %-6.0f %s\t%d\t%-21s %-7d %.3d.%.2d.%.2d\n";
						unsigned long time = (GetTickCount() - SystemTime - RemoteHost->JoinTime) / 1000;
						nc_Vector3 color = pData->Get_Color();
						nc_WideStringClass wstr;
						wstr.Get_String(0, false);
						wstr.Convert_From(
							aString::Format(format,
								i,
								name.GetString(),
								pData->Score.Get(),
								(pData->PlayerType.Get() == 0 ? "NOD" : "GDI"),
								RemoteHost->Ping,
								aString::Format("%s;%d", inet_ntoa(RemoteHost->Address.sin_addr), htons(RemoteHost->Address.sin_port)).GetString(),
								PacketMgr->Get_Compressed_Bandwidth_Out(&RemoteHost->Address) >> 10,
								time / 3600,
								(time / 60) % 60,
								time % 60
							).GetString()
						);
						ConsoleMode->Add_Message(&wstr, &color, true);
						wstr.Free_String();
					}
				}
			}
			stConsole::Out("Total current bandwidth usage for players is %d kilobits per second\n", Bandwidth >> 10);
		}
	}
};
PlayerInfoConsoleFunction playerinfo;

class SetCreditConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "setcredit";
	}
	char *Get_Help(void)
	{
		return "SETCREDIT <player> <credit> - Set the current credit of <player> to <credit>.";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken Token = text;
		if (Token.numtok(' ') != 2)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(Token.gettok(1, ' ').ToLong());
		if (pData)
			pData->Set_Money((float)Token.gettok(2, ' ').ToDouble());
	}
};
SetCreditConsoleFunction setcredit;

class SetScoreConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "setscore";
	}
	char *Get_Help(void)
	{
		return "SETSCORE <player> <score> - Set the score of <player> to <score>.";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken Token = text;
		if (Token.numtok(' ') != 2)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(Token.gettok(1, ' ').ToLong());
		if (pData)
			pData->Set_Score((float)Token.gettok(2, ' ').ToDouble());
	}
};
SetScoreConsoleFunction setscore;

class SetPosConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "setpos";
	}
	char *Get_Help(void)
	{
		return "SETPOS <player> <X> <Y> <Z> - Set the position of <player> to XYZ.";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken Token = text;
		if (Token.numtok(' ') == 1)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(Token.gettok(1, ' ').ToLong());
		if (pData && pData->Owner.Reference)
		{
			nc_Vector3 newPos;
			pData->Owner.Reference->obj->Get_Position(&newPos);
			if (Token.numtok(' ') >= 2)
				newPos.X = (float)Token.gettok(2, ' ').ToDouble();
			if (Token.numtok(' ') >= 3)
				newPos.Y = (float)Token.gettok(3, ' ').ToDouble();
			if (Token.numtok(' ') == 4)
				newPos.Z = (float)Token.gettok(4, ' ').ToDouble();
			
			if (pData->Owner.Reference->obj->As_SoldierGameObj()->Vehicle)
			{
				nc_VehicleGameObj *Vehicle = pData->Owner.Reference->obj->As_SoldierGameObj()->Vehicle;
				if (Vehicle->SeatsList.Length() > 0 && Vehicle->SeatsList[0] && Vehicle->SeatsList[0]->NetworkID == pData->Owner.Reference->obj->NetworkID)
					Vehicle->Set_Position(newPos);
				else
				{
					nc_TransitionManager::Check(Vehicle->SeatsList[0], true);
					pData->Owner.Reference->obj->As_PhysicalGameObj()->Set_Position(newPos);
				}
			}
			else
				pData->Owner.Reference->obj->As_PhysicalGameObj()->Set_Position(newPos);
		}
	}
};
SetPosConsoleFunction setpos;

class SetNameConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "setname";
	}
	char *Get_Help(void)
	{
		return "SETNAME <player> <name> - Set the player name of <player> to <name>.\nNote: WOL players will be kicked due to the \"Idle at team selection screen -> kick\"";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken Token = text;
		if (Token.numtok(' ') != 2)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(Token.gettok(1, ' ').ToLong());
		if (pData)
		{
			aWideString newNick = Token.gettok(2, ' ').GetData();
			pData->PlayerName.Resize(newNick.GetLength());
			pData->PlayerName.Format(L"%ls", newNick.GetString());
			pData->Set_Object_Dirty_Bit(nc_DB_CREATION, true);
		}
	}
};
SetNameConsoleFunction setname;

class ResetPlayerConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "resetplayer";
	}
	char *Get_Alias(void)
	{
	 	return "rsp";
	}
	char *Get_Help(void)
	{
		return "RESETPLAYER <player> - Reset their score, kills, deaths and credits.";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		int id = atoi(text);
		if (!nc_cPlayerManager::Find_Player(id))
			return;
		nc_cPlayerManager::Find_Player(id)->Reset_Player();
	}
};
ResetPlayerConsoleFunction resetplayer;

class SerialBanConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "serialban";
	}
	char *Get_Alias()
	{
		return "sban";
	}
	char *Get_Help(void)
	{
		return "SERIALBAN <add/delete/search> <hash/[player id]> [reason] - Add hash/player hash to ban list, delete hash from ban list or search for hash.";
	}
	void Activate(char *text)
	{
		if (!text || !*text)
			return;
		aToken Tok(text);
		if (Tok.gettok(1,' ').GetData() == "add")
		{
			if (Tok.gettok(2,' ').GetData().Len() != 32)
			{
				for (int i = (Tok.gettok(2,' ').GetData().Len() - 1); i >= 0; i--)
				{
					if (!isdigit(Tok.gettok(2,' ').GetData()[i]))
					{
						stConsole::Out("[ST] Invalid parameter: %s\n", Tok.gettok(2,' ').GetData().GetString());
						return;
					}
				}
				nc_cPlayer *pData = nc_cPlayerManager::Find_Player(Tok.gettok(2,' ').ToLong());
				if (!pData)
					return;

				bool result = gzSerialMgr->Hash_Ban(pData->GameSpyHashId.m_Buffer, Tok.gettok(3,Tok.numtok(' ') - 2,' ').GetData().GetString());
				stConsole::In("kick %d", pData->PlayerId);
				if (result)
				{
					stConsole::Out("[ST] %ls is being serial banned. (%s)\n",
						pData->PlayerName.m_Buffer,
						pData->GameSpyHashId.m_Buffer
					);
				}
			}
			else if (gzSerialMgr->Hash_Ban(Tok.gettok(2,' ').GetData().GetString(), Tok.gettok(3,Tok.numtok(' ') - 2, ' ').GetData().GetString()))
				stConsole::Out("[ST] Serial %s has been added to ban list.\n", Tok.gettok(2, ' ').GetData().GetString());
		}
		else if (Tok.gettok(1,' ').GetData() == "delete")
		{
			if (gzSerialMgr->Hash_Unban(Tok.gettok(2,' ').GetData()))
				stConsole::Out("[ST] Serial %s has been unbanned.\n", Tok.gettok(2,' ').GetData().GetString());
			else
				stConsole::Out("[ST] Serial %s is not in ban list.\n", Tok.gettok(2,' ').GetData().GetString());
		}
		else if (Tok.gettok(1,' ').GetData() == "search")
		{
			aVector<gzSerialBanStruct *> list;
			gzSerialMgr->Hash_Search(Tok.gettok(2, ' ').GetData().GetString(), list);
			if (list.Count() == 0)
				stConsole::Out("[ST] No result for serial %s.\n", Tok.gettok(2, ' ').GetData().GetString());
			else
			{
				for (unsigned int i = 0; i < list.Count(); i++)
				{
#if VERC(1, 1, 0)
					stConsole::Out("[ST] Serial: %s; Reason: %s\n", list[i]->hash.GetString(), list[i]->reason.GetString());
					delete list[i];
#else
					stConsole::Out("[ST] Serial: %s; Reason: %ls\n", list[i]->hash.GetString(), list[i]->reason.GetString());
#endif
				}
#if VERC(1, 1, 0)
				list.Clear();
#endif
			}
		}
	}
};
SerialBanConsoleFunction serialban;

class TeleportConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "teleport";
	}
	char *Get_Help(void)
	{
		return "TELEPORT <player1> <player2> <X> <Y> <Z> - Teleport <player1> to <player2> plus XYZ. (XYZ are optional)";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken tok(text);
		if (tok.numtok(' ') < 2)
			return;
		nc_cPlayer *pData[2] = {
			nc_cPlayerManager::Find_Player(tok.gettok(1, ' ').ToLong()),
			nc_cPlayerManager::Find_Player(tok.gettok(2, ' ').ToLong())
		};
		if (!pData[0])
		{
			stConsole::Out("Player #%d not found\n", tok.gettok(1, ' ').ToLong());
			return;
		}
		if (!pData[1])
		{
			stConsole::Out("Player #%d not found\n", tok.gettok(2, ' ').ToLong());
			return;
		}
		if (!pData[0]->Owner.Reference || !pData[1]->Owner.Reference)
			return;
		nc_Vector3 pos;
		pData[1]->Owner.Reference->obj->Get_Position(&pos);
		pos.X += (float)tok.gettok(3, ' ').ToDouble();
		pos.Y += (float)tok.gettok(4, ' ').ToDouble();
		pos.Z += (float)tok.gettok(5, ' ').ToDouble() + 3.0f;
		pData[0]->Owner.Reference->obj->As_PhysicalGameObj()->Set_Position(pos);
	}
};
TeleportConsoleFunction teleport;

class MoveConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "move";
	}
	char *Get_Help(void)
	{
		return "MOVE <player> <X> <Y> <Z> - Move <player> based on current position +XYZ.";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken tok(text);
		if (tok.numtok(' ') < 2)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(tok.gettok(1, ' ').ToLong());
		if (!pData)
		{
			stConsole::Out("Player #%d not found\n", tok.gettok(1, ' ').ToLong());
			return;
		}
		if (!pData->Owner.Reference)
			return;
		nc_Vector3 newPos;
		pData->Owner.Reference->obj->Get_Position(&newPos);
		newPos.X += (float)tok.gettok(2, ' ').ToDouble();
		newPos.Y += (float)tok.gettok(3, ' ').ToDouble();
		newPos.Z += (float)tok.gettok(4, ' ').ToDouble();
		pData->Owner.Reference->obj->As_PhysicalGameObj()->Set_Position(newPos);
	}
};
MoveConsoleFunction move;

class SetSideConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "setside";
	}
	char *Get_Help(void)
	{
		return "SETSIDE <player> <team> - Set the team of <player> to <team> temporary until he dies.\n0 = Nod\n1 = GDI";
	}
	void Activate(char *text)
	{
		if (!*text)
			return;
		aToken tok(text);
		if (tok.numtok(' ') < 2)
			return;
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(tok.gettok(1, ' ').ToLong());
		if (!pData)
		{
			stConsole::Out("Player #%d not found\n", tok.gettok(1, ' ').ToLong());
			return;
		}
		if (!pData->Owner.Reference)
			return;
		int side = tok.gettok(2, ' ').ToLong();
		if (side < -4 || side > 2)
		{
			stConsole::Out("Invalid side: %d\n", side);
			return;
		}
		pData->Owner.Reference->obj->As_DamageableGameObj()->Set_Player_Type(side);
	}
};
SetSideConsoleFunction setside;

#if ISDEV()
class DestroyConsoleFunction : public gzConsoleCommand {
public:
	char *Get_Name(void)
	{
		return "destroy";
	}
	char *Get_Help(void)
	{
		return "";
	}
	void Activate(char *text) {
		if (!*text)
			return;
		aToken str(text);
		nc_cPlayer *pData = nc_cPlayerManager::Find_Player(str.gettok(1,' ').ToLong());
		if (pData && pData->Owner.Reference)
		{
			if (pData->Owner.Reference->obj->As_SoldierGameObj()->Vehicle)
			{
				if (pData->Owner.Reference->obj->As_SoldierGameObj()->Vehicle->SeatsList[0] == pData->Owner.Reference->obj)
					pData->Owner.Reference->obj->As_SoldierGameObj()->Vehicle->Set_Delete_Pending();
				else
					nc_TransitionManager::Check(pData->Owner.Reference->obj->As_SoldierGameObj(), true);
			}
			pData->Owner.Reference->obj->Set_Delete_Pending();
		}
	}
};
DestroyConsoleFunction destroy;
#endif
