/*
Gamebots Pogamut derivation Copyright (c) 2010-2011, Michal Bida, Radek Pibil

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This software must also be in compliance with the Epic Games Inc. license for mods which states the following: "Your mods must be distributed solely for free, period. Neither you, nor any other person or party, may sell them to anyone, commercially exploit them in any way, or charge anyone for receiving or using them without prior written consent of Epic Games Inc. You may exchange them at no charge among other end-users and distribute them to others over the Internet, on magazine cover disks, or otherwise for free." Please see http://www.epicgames.com/ut2k4_eula.html for more information.

*/

class ControlConnection extends GBClientClass
	config(GameBotsUDK);

//Parent server
var ControlServer Parent;

var config float UpdateTime;

//switches for exporting information after READY command
var config bool bExportGameInfo;
var config bool bExportMutators;
var config bool bExportITC;
var config bool bExportNavPoints;
var config bool bExportMovers;
var config bool bExportInventory;
var config bool bExportPlayers;
var config bool bExportVehicles;

//var bool bExportHumanPlayers;
//var bool bExportRemoteBots;
//var bool bExportUnrealBots;

var bool bOK;
var bool bReadyReceived;

//Accepted connection to a socket
event Accepted()
{
	bOK = true;
	`log("Control Connection established. " $ IpAddrToString(RemoteAddr));

	SendLine("HELLO_CONTROL_SERVER");

    if (GBGameInterface(WorldInfo.Game).GetGameHandler().bPasswordProtected)
		gotoState('checkingPassword', 'Waiting');
	else
		gotoState('waitingForReady', 'Waiting');

}

//Connection closed at remote end
event Closed()
{
	Destroy();
}

event Destroyed()
{
	SendLine("FIN");
}

function SendLine(string text, optional bool bNoCRLF)
{
	if (bOK)
		super.SendLine(text, bNoCRLF);
}

function PostBeginPlay()
{
	Parent = ControlServer(Owner);
	if(bDebug)
		`log("Spawned ControlConnection");
}

//triggered when weve gotten ready message from client, or after succesfull password check
//we will send game nfo, all navpoints and all items in a map
function ExportStatus()
{
    SendLine("SHS"); //HandShake start
	if (bExportGameInfo)
		SendGameInfo();
	if (bExportMutators)
		ExportMutators(); //SMUT, MUT, EMUT messages
	if (bExportITC)
		ExportItemClasses();//SITC, ITC, EITC messages
	if (bExportNavPoints)
		ExportNavPoints();
	if (bExportMovers)
		ExportMovers();
	if (bExportInventory)
		ExportInventory();
	if (bExportPlayers) {
		SendLine("SPLR");
		ExportPlayers(false); //false for all info
		SendLine("EPLR");
	}
	//if (bExportVehicles)
	//	ExportVehicles();
    SendLine("EHS"); //HandShake end
}

//Handles commands for ControlServer
function ProcessAction(string cmdType)
{
	if(bDebug)
		`log("commandType:"@cmdType);

	if (IsInState('checkingPassword') || IsInState('waitingForReady'))
	{
		switch(cmdType)
		{
			case "PASSWORD":
				ReceivedPassword();
			break;
			case "READY":
				ReceivedReady();
			break;
		}
	}
	else
	{
            ProcessRegularAction(cmdType);
	}//end if
}

function ProcessRegularAction(string cmdType){
		switch(cmdType)
		{
			case "ADDCAMKEYPOINT":
				ReceivedAddCamKeyPoint();
			break;
			case "ADDBOT":
				ReceivedAddBot();
			break;
			case "ADDINV":
				ReceivedAddInv();
			break;
			case "CHANGEMAP":
				ReceivedChangeMap();
			break;
			case "CHANGETEAM":
				ReceivedChangeTeam();
			break;
			case "CHATTR":
				ReceivedChAttr();
			break;
			case "CLEAR":
				ReceivedClear();
			case "CONF":
				ReceivedConf();
			break;
			case "CONFGAME":
				ReceivedConfGame();
			break;
			case "CONSOLE":
				ReceivedConsole();
			break;
			case "ENDPLRS":
				gotoState('running','Waiting');
			break;
			case "FORCECAM":
				ReceivedForceCam();
			break;
			case "GETINVS":
				ExportInventory();
			break;
			case "GETMAPS":
				ReceivedGetMaps();
			break;
			case "GETNAVS":
				ExportNavPoints();
			break;
			case "GETPLRS":
			    SendLine("SPLR");
				ExportPlayers();
				SendLine("EPLR");
			break;
			case "PAUSE":
				ReceivedPause();
			break;
			case "PING":
				SendLine("PONG");
			break;
			case "QUIT":
				bOK = false;
				Close();
			break;
			case "KICK":
				ReceivedKick();
			break;
			case "READY":
				// no meaning here
			break;
			case "REC":
				ReceivedRec();
			break;
			case "RESPAWN":
				ReceivedRespawn();
			break;
			case "SETGAMESPEED":
				ReceivedSetGameSpeed();
			break;
			case "SETLOCK":
				ReceivedSetLock();
			break;
			case "SETPASS":
				ReceivedSetPass();
			break;
			case "SPAWNACTOR":
				ReceivedSpawnActor();
			break;
			case "STARTPLRS":
				ReceivedStartPlrs();
			break;
			case "STOPREC":
				ReceivedStopRec();
			break;
                        default :
                            `log("Unrecognized command: "$cmdType);
                        break;
		}//end switch

}

function ReceivedAddCamKeyPoint()
{
	local string target;
	local vector camTargetLoc;
	local rotator camTargetRot;
	local int order, intStartTime, intDuration;
	local bool bMyStatic, bClearAll;
	local Controller C;

	target = GetArgVal("Id");

	if (target == "")
		return;

    bClearAll = bool(GetArgVal("ClearAll"));
	if (GetArgVal("TargetLoc") != "")
		ParseVector(camTargetLoc,"TargetLoc");
	if (GetArgVal("TargetRot") != "")
		ParseRot(camTargetRot,"TargetRot");
	if (GetArgVal("StartTime") != "")
		intStartTime = int(GetArgVal("StartTime"));
	else
		intStartTime = -1;
	order = int(GetArgVal("Order"));
    bMyStatic = bool(GetArgVal("Static"));
	intDuration = int(GetArgVal("Duration"));
	if (intDuration <= 0) {
		intDuration = -1;
		bMyStatic = true;
	}
	foreach WorldInfo.AllControllers(class'Controller', C) {
		if (target == string(C))
			break;
	}
	if (C != none ) {
		if( C.IsA('GBPlayer') && (string(C) == target) ) {
			if (bClearAll)
				GBPlayer(C).ClearCameraKeyPoints();
            GBPlayer(C).AddCameraKeyPoint(order, intStartTime, intDuration, camTargetLoc, camTargetRot, bMyStatic);
		}
	}
}

function ReceivedAddBot()
{
	local string target;
	local vector botLocation;
	local rotator botRotation;
	local float skill;
	local int team;

	target = GetArgVal("Name");
	ParseVector(botLocation, "StartLocation");
	ParseRot(botRotation, "StartRotation");
	skill = float(GetArgVal("Skill"));
	team = int(GetArgVal("Team"));
	GBGameInterface(WorldInfo.Game).GetGameHandler().AddEpicBot(target, team, skill);
}

function ReceivedAddInv()
{
	
	//local string target, type;
	//local Controller C;
	//local PickupFactory pickupFactory;

	//target = GetArgVal("Id");

	//if (target == "")
	//{
	//	return;
	//}
	//type = GetArgVal("Type");

	//setPropertyText("tempPickupClass",string1);
	

	//Allow to add just Pickup classes
	/*
	if (pickupFactory != None)
		foreach WorldInfo.AllControllers(class'Controller', C)
		{   
			if( string(C) == target )
			{
				pickupFactory = RemoteBot(C).myConnection.GetPickupFactoryFromPickupType(type);
				`log("Added inventory will be " $ pickupFactory.InventoryType);
				RemoteBot(C).myConnection.ExportPickup(pickupFactory);
				RemoteBot(C).SpawnInventory(pickupFactory);
				pickupFactory.Destroy();
				break;
			}

		} //end for
*/
}

function ReceivedChangeMap()
{
	local string target;
	local bool bResult;
	local GBClientClass G;
	local RemoteBot C;
	local int i;
        local bool skipGameNotify;

	target = GetArgVal("MapName");
        skipGameNotify = !bool(GetArgVal("NotifyGame"));
        `log("Changing map to: " $ target);
	if (target != "")
	{
		//Check if the map exists in current map list
//		bResult = false;
//		for (i = 0; i < GBGameInterface(WorldInfo.Game).GetGameHandler().Maps.Length; ++i ) {
//			if (target == GBGameInterface(WorldInfo.Game).GetGameHandler().Maps[i]) {
//			 	bResult = true;
//			 	break;
//			}
//		}
    	//Change just when the map is in MapList
//		if (bResult) {
			//SendLine("MAPCHANGE"$ib$as$"MapName"$ib$target$ae);

			foreach WorldInfo.AllControllers(class'RemoteBot', C) {
				C.myConnection.SendLine("MAPCHANGE {MapName "$target$"}");
				C.myConnection.SendLine("FIN");
			}

			for (G = Parent.ChildList; G != None; G = G.Next ) {
				G.SendLine("MAPCHANGE {MapName "$target$"}");
				G.SendLine("FIN");
			}			

    		//We refuse another connections when changing map
			GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.bClosed = true;
			GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.Close();

			GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.bClosed = true;
			GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.Close();

			WorldInfo.ServerTravel(target, true, skipGameNotify);
	}
//        else {
//            `log("Map not found, change map ignored: " $ target);
//        }
//    }
}

// this will do a dirty clear, sometimes bots remain on the server after disconnect
// this delete all actors that are pawns or controllers on the server
//
function ReceivedClear()
{
	local GBPawn P;
	local RemoteBot R;
	local BotConnection C;
	//local Controller C;

    foreach AllActors (class 'BotConnection', C, )
	{
		C.Destroy();
	}

	foreach AllActors (class 'RemoteBot', R, )
	{
		R.Destroy();
	}

	foreach AllActors (class 'GBPawn', P, )
	{
		P.Destroy();
	}


}

function ReceivedConf()
{
	local string target, string1;
	local float floatNumber;
	local Controller C;
	local bool tempBool;

	target = GetArgVal("Id");
	if (target == "")
		return;

	foreach WorldInfo.AllControllers(class'Controller', C)
		if( string(C) == target )
			break;

	if (C == none)
		return;

	if (GetArgVal("AutoTrace") != "") {
		tempBool = bool(GetArgVal("AutoTrace"));
		RemoteBot(C).bAutoTrace = tempBool;
		if (tempBool == false)
			RemoteBot(C).myConnection.RayManager.StopRays();
	}
	if (GetArgVal("DrawTraceLines") != "") {
		tempBool = bool(GetArgVal("DrawTraceLines"));
		RemoteBot(C).bDrawTraceLines = tempBool;
		if (tempBool == false)
			RemoteBot(C).myConnection.RayManager.StopRays();		
	}
	if (GetArgVal("ManualSpawn") != "")
		RemoteBot(C).bAutoSpawn = !bool(GetArgVal("ManualSpawn"));
	if (GetArgVal("ShowFocalPoint")!="")
		RemoteBot(C).bShowFocalPoint = bool(GetArgVal("ShowFocalPoint"));
	if (GetArgVal("ShowDebug")!="")
		RemoteBot(C).bDebug = bool(GetArgVal("ShowDebug"));
	if (GetArgVal("Name") != "")
	{
		string1 = GetArgVal("Name");
    	C.PlayerReplicationInfo.PlayerName = string1;
		WorldInfo.Game.changeName( C, string1, true );
	}
	if (GetArgVal("SpeedMultiplier") != "")
	{
		floatNumber = float(GetArgVal("SpeedMultiplier"));
		if ( (floatNumber >= 0.1) && (floatNumber <= RemoteBot(C).MaxSpeed) )
		{
			RemoteBot(C).SpeedMultiplier = floatNumber;
		    if (RemoteBot(C).Pawn != none) {
				RemoteBot(C).Pawn.GroundSpeed = floatNumber * RemoteBot(C).Pawn.Default.GroundSpeed;
				RemoteBot(C).Pawn.AirSpeed = floatNumber * RemoteBot(C).Pawn.Default.AirSpeed;
				RemoteBot(C).Pawn.WaterSpeed = floatNumber * RemoteBot(C).Pawn.Default.WaterSpeed;
				RemoteBot(C).Pawn.LadderSpeed = floatNumber * RemoteBot(C).Pawn.Default.LadderSpeed;
		    }
		}
	}
	if (GetArgVal("VisionTime") != "")
	{
		floatNumber = float(GetArgVal("VisionTime"));
		if ((floatNumber >= 0.1) && (floatNumber <= 2))
			RemoteBot(C).myConnection.visionTime = floatNumber;
	}
	if (GetArgVal("Invulnerable") != "")
		RemoteBot(C).bGodMode = bool(GetArgVal("Invulnerable"));
	if (GetArgVal("SynchronousOff") != "")
	{
		RemoteBot(C).myConnection.bSynchronousMessagesOff = bool(GetArgVal("SynchronousOff"));
	}
	if (GetArgVal("AutoPickupOff") != "")
	{
		RemoteBot(C).bDisableAutoPickup = bool(GetArgVal("AutoPickupOff"));
		if (RemoteBot(C).Pawn != none)
			RemoteBot(C).Pawn.bCanPickupInventory = !RemoteBot(C).bDisableAutoPickup;
	}

	SendNotifyConf(RemoteBot(C));

}

function ReceivedConfGame()
{
	local int intNumber;

	if (GetArgVal("WeaponStay") != "")
	{
		UTGame(WorldInfo.Game).bWeaponStay = bool(GetArgVal("WeaponStay"));
	}/*
	if (GetArgVal("WeaponThrowing") != "")
	{
		UTGame(WorldInfo.Game).bAllowWeaponThrowing = bool(GetArgVal("WeaponThrowing"));
	}*/
	if (GetArgVal("GoalScore") != "")
	{
		intNumber = int(GetArgVal("GoalScore"));
		if (intNumber >= 1)
			WorldInfo.Game.GoalScore = intNumber;
	}
	if (GetArgVal("TimeLimit") != "")
	{
		intNumber = int(GetArgVal("TimeLimit"));
		if (intNumber >= 1)
			WorldInfo.Game.TimeLimit = intNumber;
	}
	if (GetArgVal("MaxLives") != "")
	{
		intNumber = int(GetArgVal("MaxLives"));
		if (intNumber >= 1)
			WorldInfo.Game.MaxLives = intNumber;
	}
	WorldInfo.Game.SaveConfig();
	WorldInfo.Game.GameReplicationInfo.SaveConfig();

}

function ReceivedConsole()
{
	local string target;

	target = GetArgVal("Command");

	ConsoleCommand(target);
}

function ReceivedGetMaps()
{
	local int i;

	SendLine("SMAP");
	for (i=0; i < GBGameInterface(WorldInfo.Game).GetGameHandler().Maps.Length; i++ ) {
		SendLine("IMAP {Name " $ GBGameInterface(WorldInfo.Game).GetGameHandler().Maps[i] $ "}");
	}
	SendLine("EMAP");
}

function ReceivedForceCam()
{
	local string target;
	local vector spawnLocation;
	local rotator spawnRotation;
	local bool bRelease, bCamActive;
	local Controller C;

	target = GetArgVal("Id");

	if (target == "")
		return;

	ParseVector(spawnLocation,"Location");
	ParseRot(spawnRotation,"Rotation");
	bRelease = bool(GetArgVal("Release"));
	bCamActive = bool(GetArgVal("Active"));

	foreach WorldInfo.AllControllers(class'Controller', C) {
		if (target == string(C))
			break;
	}
	if (C != none) {
		if( C.IsA('GBPlayer') ) {
			if (bRelease){
				GBPlayer(C).bStoryCamera = false;
				GBPlayer(C).bStoryCameraActive = false;
				return;
			}

        	if (!GBPlayer(C).bStoryCamera) {
				GBPlayer(C).ServerClientBecomeStoryCamera();
				//GBPlayer(C).ServerViewSelf(); //need to reset view target
				//GBPlayer(C).Pawn = None;
			}

			if (GetArgVal("Location") != "") {
				GBPlayer(C).SetLocation(spawnLocation);
				GBPlayer(C).SetRotation(spawnRotation);
				GBPlayer(C).ClientSetLocation(spawnLocation, spawnRotation);
			}
			if (GetArgVal("Rotation") != "") {
				GBPlayer(C).SetRotation(spawnRotation);
				GBPlayer(C).ClientSetRotation(spawnRotation, true);
			}
			
			if (GetArgVal("Active") != "") {
				GBPlayer(C).bStoryCameraActive = bCamActive;
				if (bCamActive)
					GBPlayer(C).CurrentKeyPointIndex = 0; //setting index to 0 once more
			}
		}
	}
}

function ReceivedKick()
{
	local string target;
	local RemoteBot C;

	target = GetArgVal("Id");
	if (target == "")
		return;

    foreach WorldInfo.AllControllers(class'RemoteBot', C) {
		if( C.PlayerReplicationInfo.PlayerName == target ) {
			//TODO: Send "Kicked"?
			C.myConnection.SendLine("FIN");
			C.myConnection.Closed();
			break;
		}
	}
}

function ReceivedPause()
{
	local bool bWasPaused;

	if (!bAllowPause)
		return;
	if ((WorldInfo.bPlayersOnly == true) || (WorldInfo.Pauser != none))
		bWasPaused = true;
	else
		bWasPaused = false;


	if (GetArgVal("PauseBots")!="") {
		WorldInfo.bPlayersOnly = bool(GetArgVal("PauseBots"));
	}
	if (GetArgVal("PauseAll")!="") {
		if (bool(GetArgVal("PauseAll"))) {
			if (WorldInfo.Pauser == None) {
				WorldInfo.Pauser = GBGameInterface(WorldInfo.Game).GetGameHandler().LevelPauserFeed;
			}
		} else {
			WorldInfo.Pauser = None;
		}
	}

	if (bWasPaused == true) {
		if ((WorldInfo.bPlayersOnly == false) && (WorldInfo.Pauser == none))
			SendNotifyPause(false); //send resume message
	} else {
		if ((WorldInfo.bPlayersOnly == true) || (WorldInfo.Pauser != none))
			SendNotifyPause(true); //send pause message
	}

}

function ReceivedPassword()
{
	local string target;

	target = GetArgVal("Password");

	if (target == GBGameInterface(WorldInfo.Game).GetGameHandler().Password)
	{
		bReadyReceived = true;
		SendLine("PASSWDOK");
		ExportStatus();
		gotoState('running','Waiting');
	} else {
		SendLine("PASSWDWRONG");
		Closed();
	}
}

function ReceivedReady()
{
	bReadyReceived = true;
	if ( IsInState('checkingPassword') )
		SendLine("PASSWORD {BlockedByIp " $ GBGameInterface(WorldInfo.Game).GetGameHandler().PasswordByIP $ "}");
	else {
		ExportStatus();
		gotoState('running','Waiting');		
	}
}

function ReceivedRec()
{
	local string fileName;

	fileName = GetArgVal("FileName");
	ConsoleCommand("demorec " $ fileName);
	sendLine("RECSTART");
}

function ReceivedRespawn() {
	local string target;
	local vector v;
	local rotator r;
	local RemoteBot C;
	local bool hasVector, hasRotator;

	target = GetArgVal("Id");

	if (target == "") {
		return;
	}
	ParseVector(v, "Location");
	ParseRot(r, "Rotation");
	foreach WorldInfo.AllControllers(class'RemoteBot', C) {
		if ( string(C) == target ) {
			if (GetArgVal("StartLocation") != "") {
				ParseVector(v, "FirstLocation");
				hasVector = true;
			}
			if (GetArgVal("StartRotation") != "") {
				ParseRot(r, "StartRotation");
				hasRotator = true;
			}
			if (hasVector && hasRotator) {
				C.RespawnPlayer(v, r);
			} else if (hasVector) {
				C.RespawnPlayer(v);
			} else {
				C.RespawnPlayer();
			}	
		}
	}
}

function ReceivedSetGameSpeed()
{
	local float floatNumber;

	floatNumber = float(GetArgVal("Speed"));
	if ( (floatNumber >= 0.01) && (floatNumber <= 50 ) ) {
		WorldInfo.Game.SetGameSpeed(floatNumber);
		WorldInfo.Game.SaveConfig();
		WorldInfo.Game.GameReplicationInfo.SaveConfig();
	}
}

function ReceivedSetLock()
{
	local string target;

	target = GetArgVal("BotServer");
	if (target != "")
	{
		if (bool(target)) {
			if (GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.LinkState == STATE_Listening) {
				GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.bClosed = true;
				GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.Close();
			}
		} else {
			if (GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.LinkState != STATE_Listening) {
				GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.bClosed = false;
				GBGameInterface(WorldInfo.Game).GetGameHandler().theBotServer.Listen();
			}
		}
	}

	target = GetArgVal("ControlServer");
	if (target != "") {
		if (bool(target)) {
			if (GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.LinkState == STATE_Listening) {
				GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.bClosed = true;
				GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.Close();
			}
		} else {
			if (GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.LinkState != STATE_Listening) {
				GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.bClosed = false;
				GBGameInterface(WorldInfo.Game).GetGameHandler().theControlServer.Listen();
			}
		}
	}

}

function ReceivedSetPass()
{
	local string target;

	target = GetArgVal("Password");

	if (target != "") {
		GBGameInterface(WorldInfo.Game).GetGameHandler().bPasswordProtected = true;
		GBGameInterface(WorldInfo.Game).GetGameHandler().PasswordByIP =
			string(RemoteAddr.Addr) $ ":" $ string(RemoteAddr.Port);
		GBGameInterface(WorldInfo.Game).GetGameHandler().Password = target;
	} else {
		GBGameInterface(WorldInfo.Game).GetGameHandler().bPasswordProtected = false;
		GBGameInterface(WorldInfo.Game).GetGameHandler().PasswordByIP = "";
		GBGameInterface(WorldInfo.Game).GetGameHandler().Password = "";
	}
}

function ReceivedSpawnActor()
{
	local string tmp;
	local vector v;
	local rotator r;
	//local Actor SpawnedActor;

	ParseVector(v,"Location");
	ParseRot(r,"Rotation");
	tmp = GetArgVal("Type");

	if (tmp != "") {
		//SpawnedActor =
		Spawn(class<Actor>(DynamicLoadObject(tmp, class'Class')),self,,v,r);		
	}
}

function ReceivedStartPlrs()
{
	local string tmp;

	tmp = GetArgVal("Humans");
	if (tmp != "") {
		bExportHumanPlayers = bool(tmp);
	}
	tmp = GetArgVal("GBBots");
	if (tmp != "") {
		bExportRemoteBots = bool(tmp);
	}
	tmp = GetArgVal("UnrealBots");
	if (tmp != "") {
		bExportUnrealBots = bool(tmp);
	}
	gotoState('running','Running');
}

function ReceivedStopRec()
{
	ConsoleCommand("stopdemo");
	sendLine("RECEND");
}

function SendNotifyPause ( bool bGamePaused )
{
	local RemoteBot C;
	local GBClientClass G;

	foreach WorldInfo.AllControllers(class'RemoteBot', C) {
		if (bGamePaused)
			C.myConnection.SendLine("PAUSED");
		else
			C.myConnection.SendLine("RESUMED");
	}

	for (G = Parent.ChildList; G != None; G = G.Next )
	{
		if (bGamePaused)
			G.SendLine("PAUSED");
		else
			G.SendLine("RESUMED");
	}

}

function ReceivedChAttr()
{
	local string Id, Health;
	local RemoteBot C;

	Id = GetArgVal("Id");
	if (Id == "")
		return;

	Health = GetArgVal("Health");
	
	foreach WorldInfo.AllControllers(class'RemoteBot', C)
	{
		if (C.PlayerReplicationInfo.PlayerName == Id)
		{
			C.SetHealth(int(Health));
			break;
		}
	}
}

function ReceivedChangeTeam()
{
	local string team, Id;
	local RemoteBot C;
	local bool result;
	local int teamId;

	if (!WorldInfo.Game.IsA('BotTeamGame'))
		return;

	team = GetArgVal("Team");

	if (team == "")
		return;

	teamId = int(team);

	if (teamId == 0 && team != "0")
		return;

	Id = GetArgVal("Id");

	if (Id == "")
		return;

	foreach WorldInfo.AllControllers(class'RemoteBot', C)
	{
		if (C.PlayerReplicationInfo.PlayerName == Id)
		{						
    		result = BotTeamGame(WorldInfo.Game).ChangeTeam(C, teamId, true);
			if (result) {
				C.myConnection.SendLine("TEAMCHANGE {Success " $ result $
					"} {DesiredTeam " $ teamId $
					"}");

				GlobalSendLine("TEAMCHANGE {Id " $ C.PlayerReplicationInfo.PlayerName $
					"} {Success " $ result $
					"} {DesiredTeam " $ teamId $ "}", true, false);

				if (C.Pawn != none)
					C.Pawn.Suicide();
			}
			break;
		}
	}
}

//from CheatManager class - for inspiration
/*
function Summon( string ClassName )
{
	local class<actor> NewClass;
	local vector SpawnLoc;

	//if (!areCheatsEnabled()) return;

	`log( "Fabricate " $ ClassName );
	NewClass = class<actor>( DynamicLoadObject( ClassName, class'Class' ) );
	if( NewClass != None )
	{
		if ( Pawn != None )
			SpawnLoc = Pawn.Location;
		else
			SpawnLoc = Location;
		Spawn( NewClass,,,SpawnLoc + 72 * Vector(Rotation) + vect(0,0,1) * 15 );
	}
	ReportCheat("Summon");
}
*/
//Default State for receiving commands
auto state running
{
Begin:
	sleep(5.0);
	goto 'Begin';
Waiting:
	sleep(1.0);
	SendLine("ALIVE {Time " $ WorldInfo.TimeSeconds $ "}");
	goto 'Waiting';
Running:
	SendLine("ALIVE {Time " $ WorldInfo.TimeSeconds $ "}");
	SendLine("BEG {Time " $ WorldInfo.TimeSeconds $"}");
	ExportPlayers();
	SendLine("END {Time " $ WorldInfo.TimeSeconds $"}");
	sleep(UpdateTime);
	goto 'Running';
}

function bool isValidCommandInState(string command) { return true; }

state waitingState
{

	function SendLine(string text, optional bool bNoCRLF)
	{
		if (bOK && isValidCommandInState(text))
			super.SendLine(text, bNoCRLF);
	}

Begin:
Waiting:
	sleep(5.0);
	goto 'Waiting';
}

state checkingPassword extends waitingState
{
	function bool isValidCommandInState(string command)
	{
		return bReadyReceived || command == "PASSWDWRONG";
	}
}

state waitingForReady extends waitingState
{
	function bool isValidCommandInState(string command)
	{
		return bReadyReceived;
	}
}

function SendNotifyConf(RemoteBot theBot)
{
	local string outstring;
	local string confchId;

	confchId = theBot $ "_CONFCH";

	outstring="CONFCH {Id " $ confchId $
		"} {BotId " $ string(theBot) $
		"} {ManualSpawn " $ !theBot.bAutoSpawn $
		"} {AutoTrace " $ theBot.bAutoTrace $
		"} {Invulnerable " $ theBot.bGodMode $
		"} {Name " $ theBot.PlayerReplicationInfo.PlayerName $
		"} {SpeedMultiplier " $ theBot.SpeedMultiplier $
		"} {RotationRate " $ theBot.RotationRate $
		"} {VisionTime " $ theBot.myConnection.VisionTime $
		"} {ShowDebug " $ theBot.bDebug $
		"} {ShowFocalPoint " $ theBot.bShowFocalPoint $
		"} {DrawTraceLines " $ theBot.bDrawTraceLines $
		"} {SynchronousOff " $ theBot.myConnection.bSynchronousMessagesOff $
		"} {AutoPickupOff " $ theBot.bDisableAutoPickup $
		"}";


	//Notify bot about his variables changing
	theBot.myConnection.SendLine(outstring);

	//Notify all control servers about bot variables chaning
	GlobalSendLine(outstring,true,false);
}

defaultproperties
{
	bDebug=false
}