//=============================================================================
// CTFGame.
//=============================================================================
class CTFGame expands TeamGamePlus
	config;

#exec AUDIO IMPORT FILE="Sounds\CTF\RockOnDude.wav" NAME="CaptureSound" GROUP="CTF"
#exec AUDIO IMPORT FILE="Sounds\CTF\ctf5.wav" NAME="CaptureSound2" GROUP="CTF"
#exec AUDIO IMPORT FILE="Sounds\CTF\ctf6.wav" NAME="CaptureSound3" GROUP="CTF"

var	  int   GrowTimer;
var localized string[128] returnstring;
var localized string[128] capturestring;
var() sound CaptureSound[3];
var float LastGotFlag;
var float LastSeeFlagCarrier;

function Logout(pawn Exiting)
{
	local CTFFlag aFlag;
	local int i;

	Super.Logout(Exiting);
	for ( i=0; i<2; i++ )
	{
		aFlag=CTFReplicationInfo(GameReplicationInfo).FlagList[i];
		if ( aFlag.Holder == Exiting )
			aFlag.Drop(0.5 * Exiting.Velocity);	
	}
}

event InitGame( string[200] Options, out string[55] Error )
{
	Super.InitGame(Options, Error);
	log("Init game with "$Remainingbots);
	if ( bRatedGame )
	{
		GoalTeamScore = 5;
	}
}

function ScoreKill(pawn Killer, pawn Other)
{
	local CTFFlag aFlag;
	local int i;

	if ( Other.bIsPlayer )
		for ( i=0; i<2; i++ )
		{
			aFlag=CTFReplicationInfo(GameReplicationInfo).FlagList[i];
			if ( aFlag.Holder == Other )
			{
				if ( Bot(Killer) != None )
					Bot(killer).SendGlobalMessage(None, 'TAUNT', 0, 5);
				aFlag.Drop(0.5 * Other.Velocity);	
			}
		}

	if ( Killer != None )					
		Killer.killCount++;
}	

function ScoreFlag(Pawn Scorer, CTFFlag theFlag)
{
	local pawn TeamMate;
	local Actor A;

	if ( Scorer.PlayerReplicationInfo.Team == theFlag.Team )
	{
		BroadcastMessage(Scorer.PlayerReplicationInfo.PlayerName$returnstring$Teams[theFlag.Team].TeamName$" flag", true, 'CriticalEvent');
		return;
	}

	if ( bRatedGame && Scorer.IsA('PlayerPawn') )
		bFulfilledSpecial = true;
	Scorer.PlayerReplicationInfo.Score += 1;
	Teams[Scorer.PlayerReplicationInfo.Team].Score += 1.0;
	if ( Scorer.PlayerReplicationInfo.Team == 0 )
		CTFReplicationInfo(GameReplicationInfo).Team0Score += 1;
	else if ( Scorer.PlayerReplicationInfo.Team == 1 )
		CTFReplicationInfo(GameReplicationInfo).Team1Score += 1;

	for ( TeamMate=Level.PawnList; TeamMate!=None; TeamMate=TeamMate.NextPawn )
		if ( (TeamMate.PlayerReplicationInfo.Team == Scorer.PlayerReplicationInfo.Team)
			&& TeamMate.IsA('PlayerPawn') )
			PlayerPawn(TeamMate).ClientPlaySound(CaptureSound[Rand(3)]);

	BroadcastMessage(Scorer.PlayerReplicationInfo.PlayerName$capturestring$Teams[theFlag.Team].TeamName$" Flag!", true, 'CriticalEvent');
	if ( theFlag.HomeBase.Event != '' )
		foreach allactors(class'Actor', A, theFlag.HomeBase.Event )
			A.Trigger(theFlag.HomeBase,	Scorer);
	if ( (GoalTeamScore != 0) && (Teams[Scorer.PlayerReplicationInfo.Team].Score >= GoalTeamScore) )
		EndGame();
	
	// PlaySound on client side for all clients
}
 
function Actor SetDefenseFor(Bot aBot)
{
	return CTFReplicationInfo(GameReplicationInfo).FlagList[aBot.PlayerReplicationInfo.Team].HomeBase;
}


function float GameThreatAdd(Bot aBot, Pawn Other)
{
	local CTFFlag aFlag;

	if ( Other.PlayerReplicationInfo.HasFlag != None )
		return 10;
	else
		return 0;
}

function bool FindPathToBase(Bot aBot, FlagBase aBase)
{
	if ( (aBot.AlternatePath != None) 
		&& (aBot.AlternatePath.team == aBase.team) )
	{
		if ( aBot.ActorReachable(aBot.AlternatePath) )
		{
			aBot.MoveTarget = aBot.AlternatePath;
			aBot.AlternatePath = None;
		}
		else
		{
			aBot.MoveTarget = aBot.FindPathToward(aBot.AlternatePath);
			if ( aBot.MoveTarget == None )
			{
				aBot.AlternatePath = None;
				aBot.MoveTarget = aBot.FindPathToward(aBase);
			}
		}
	}
	else						
		aBot.MoveTarget = aBot.FindPathToward(aBase);

	return (aBot.bNoClearSpecial || (aBot.MoveTarget != None));
}

function byte AssessBotAttitude(Bot aBot, Pawn Other)
{
	if ( aBot.PlayerReplicationInfo.Team == Other.PlayerReplicationInfo.Team )
		return 3; //teammate
	else if ( (Other.bIsPlayer && (Other.PlayerReplicationInfo.HasFlag != None)) 
				|| (aBot.PlayerReplicationInfo.HasFlag != None) )
		return 1;
	else 
		return Super.AssessBotAttitude(aBot, Other);
}

function bool FindSpecialAttractionFor(Bot aBot)
{
	local CTFFlag FriendlyFlag, EnemyFlag;
	local bool bSeeFlag, bReachHome;

	//log(aBot$" find special attraction in state "$aBot.GetStateName()$" at "$Level.TimeSeconds);	
	FriendlyFlag = CTFReplicationInfo(GameReplicationInfo).FlagList[aBot.PlayerReplicationInfo.Team];
	
	if ( aBot.PlayerReplicationInfo.Team == 0 )
		EnemyFlag = CTFReplicationInfo(GameReplicationInfo).FlagList[1];
	else
		EnemyFlag = CTFReplicationInfo(GameReplicationInfo).FlagList[0];
	
	if ( !FriendlyFlag.bHome  )
	{
		bSeeFlag = aBot.LineOfSightTo(FriendlyFlag);
		FriendlyFlag.bKnownLocation = FriendlyFlag.bKnownLocation || bSeeFlag;

		if ( bSeeFlag && (FriendlyFlag.Holder == None) && aBot.ActorReachable(FriendlyFlag) )
		{
			if ( Level.TimeSeconds - LastGotFlag > 6 )
			{	
				LastGotFlag = Level.TimeSeconds;
				aBot.SendTeamMessage(None, 'OTHER', 8, 20);
			}
			aBot.MoveTarget = FriendlyFlag;
			SetAttractionStateFor(aBot);
			return true;
		}

		if ( EnemyFlag.Holder != aBot )
		{
			if ( bSeeFlag && (FriendlyFlag.Holder != None) )
			{	
				if ( Level.TimeSeconds - LastSeeFlagCarrier > 6 )
				{
					LastSeeFlagCarrier = Level.TimeSeconds;
					aBot.SendTeamMessage(None, 'OTHER', 12, 20);
				}
				aBot.SetEnemy(FriendlyFlag.Holder);
				if ( aBot.Orders == 'Attack' )
					aBot.Orders = 'Freelance';
				aBot.MoveTarget = FriendlyFlag.Holder;
				if ( aBot.IsInState('Attacking') )
					return false;
				else
				{
					aBot.GotoState('Attacking');
					return true;
				}
			}
			else if ( FriendlyFlag.bKnownLocation || (FRand() < 0.1) )
			{
				FriendlyFlag.bKnownLocation = true;
				aBot.MoveTarget = aBot.FindPathToward(FriendlyFlag);
				if ( aBot.MoveTarget != None )
				{
				// aBot.SendTeamMessage(None, 'OTHER', X, 25); //"going after our flag"
					SetAttractionStateFor(aBot);
					return true;
				}
			}
		}
	}

	if ( EnemyFlag.Holder == aBot )
	{
		bReachHome = aBot.ActorReachable(FriendlyFlag.HomeBase);
		if ( bReachHome && !FriendlyFlag.bHome )
		{
			aBot.SendTeamMessage(None, 'OTHER', 1, 25);
			aBot.Orders = 'Freelance';
			return false;
		}
		if ( aBot.Enemy != None )
		{
			if ( aBot.Health < 60 )
				aBot.SendTeamMessage(None, 'OTHER', 13, 25);
			if ( !aBot.IsInState('FallBack') )
			{
				aBot.bNoClearSpecial = true;
				aBot.GotoState('Fallback', 'SpecialNavig');
			}
			if ( bReachHome )
				aBot.MoveTarget = FriendlyFlag.HomeBase;
			else
				return FindPathToBase(aBot, FriendlyFlag.HomeBase);
		}
		else
		{
			if ( !aBot.IsInState('Roaming') )
			{
				aBot.bNoClearSpecial = true;
				aBot.GotoState('Roaming', 'SpecialNavig');
			}
			if ( bReachHome )
				aBot.MoveTarget = FriendlyFlag.HomeBase;
			else
				return FindPathToBase(aBot, FriendlyFlag.HomeBase);
		}		
		return true;
	}

	if ( EnemyFlag.Holder == None )
	{
		if ( aBot.ActorReachable(EnemyFlag) )
		{
			aBot.SendTeamMessage(None, 'OTHER', 2, 25);
			aBot.MoveTarget = EnemyFlag;
			SetAttractionStateFor(aBot);
			return true;
		}
		else if ( aBot.Orders == 'Attack' )
		{
			if ( (aBot.Health < 30) || (aBot.Weapon == None) || (aBot.Weapon.AIRating < 0.4) )
				return false;

			if ( (aBot.Enemy != None) 
				&& (aBot.Enemy.IsA('PlayerPawn') || (aBot.Enemy.IsA('Bot') && (Bot(aBot.Enemy).Orders == 'Attack')))
				&& ((aBot.Enemy.Region.Zone == FriendlyFlag.HomeBase.Region.Zone) 
					|| (VSize(aBot.Enemy.Location - FriendlyFlag.HomeBase.Location) < 0.8 * VSize(aBot.Location - EnemyFlag.HomeBase.Location))) )
				{
					aBot.SendTeamMessage(None, 'OTHER', 2, 25);
					aBot.Orders = 'Freelance';
					return false;
				}

			if ( EnemyFlag.bHome )
				FindPathToBase(aBot, EnemyFlag.HomeBase);
			else
				aBot.MoveTarget = aBot.FindPathToward(EnemyFlag);
			if ( aBot.MoveTarget != None )
			{
				SetAttractionStateFor(aBot);
				return true;
			}
			else
				return false;
		}
		return false;
	}

	if ( aBot.Health < 25 )
	{
		aBot.Orders = 'Freelance';
		return false;
	}
	if ( (aBot.Weapon == None) || (aBot.Weapon.AIRating < 0.4) )
		return false;

	if ( (aBot.Enemy == None) && (aBot.Orders != 'Defend') )
	{
		if ( ((VSize(aBot.Location - EnemyFlag.Holder.Location) > 800) 
			|| !aBot.LineOfSightTo(EnemyFlag.Holder)) )
		{
			aBot.MoveTarget = aBot.FindPathToward(EnemyFlag.Holder);
			if ( !aBot.IsInState('Roaming') )
			{
				aBot.bNoClearSpecial = true;
				aBot.GotoState('Roaming', 'SpecialNavig');
				return true;
			}
			return (aBot.MoveTarget != None);
		}
		else
		{
			if ( !aBot.bInitLifeMessage )
			{
				aBot.bInitLifeMessage = true;
				aBot.SendTeamMessage(EnemyFlag.Holder.PlayerReplicationInfo, 'OTHER', 3, 10);
			}
			if ( FRand() < 0.35 )
				aBot.GotoState('Wandering');
			else
			{
				aBot.CampTime = 1.0;
				aBot.GotoState('Roaming', 'Camp');
			}
			return true;
		}
	}
	return false;
}		

function bool RestartPlayer(Pawn aPlayer)
{
	local NavigationPoint N;
	local int num;
	local bool bResult;

	bResult = Super.RestartPlayer(aPlayer);

	if ( !aPlayer.IsA('Bot') )
		return bResult;

	Bot(aPlayer).AlternatePath = None;
	if ( Bot(aPlayer).Orders != 'Attack' )
		return bResult;

	if ( FRand() < 0.5 )
		for ( N=Level.NavigationPointList; N!=None; N=N.nextNavigationPoint )
			if ( N.IsA('AlternatePath') && (AlternatePath(N).team != aPlayer.PlayerReplicationInfo.team) )
			{
				num++;
				if ( (num == 1) || (Rand(num) == 1) )
					Bot(aPlayer).AlternatePath = AlternatePath(N);
			}

	return bResult;
}

function SetBotOrders(Bot NewBot)
{
	if ( CurrentOrders[NewBot.PlayerReplicationInfo.Team] == 'Defend' )
		CurrentOrders[NewBot.PlayerReplicationInfo.Team] = 'Attack';
	else 
		CurrentOrders[NewBot.PlayerReplicationInfo.Team] = 'Defend';		

	NewBot.SetOrders(CurrentOrders[NewBot.PlayerReplicationInfo.Team], None);
}

// AllowTranslocation - return true if Other can teleport to Dest
function bool AllowTranslocation(Pawn Other, vector Dest )
{
	local CTFFlag aFlag;
	local bool bSeeFlag, bReachHome;
	local int i;

	for ( i=0; i<2; i++ )
	{
		aFlag=CTFReplicationInfo(GameReplicationInfo).FlagList[i];
		// drop flag before translocation
		if ( aFlag.Holder == Other )
			aFlag.Drop(0.5 * Other.Velocity);
	}

	return true;
}


// ShouldTranslocate - return true if abot should use translocation
function bool CanTranslocate(Bot aBot)
{
	local CTFFlag aFlag;
	local int i;

	for ( i=0; i<2; i++ )
		if ( CTFReplicationInfo(GameReplicationInfo).FlagList[i].Holder == aBot )
			return false;

	return Super.CanTranslocate(aBot);
}

function int ReduceDamage(int Damage, name DamageType, pawn injured, pawn instigatedBy)
{
	local int i;
	local bool bSpeak;

	if ( (instigatedBy != None) 
		&& (injured.PlayerReplicationInfo.Team != instigatedBy.PlayerReplicationInfo.Team)
		&& injured.IsA('Bot') ) 
	{
		if ( injured.health < 35 )
			bSpeak = true;
		else
			for ( i=0; i<2; i++ )
				if ( CTFReplicationInfo(GameReplicationInfo).FlagList[i].Holder == injured )
					bSpeak = true;

		if ( bSpeak )
		{
			Bot(injured).SendTeamMessage(None, 'OTHER', 4, 15);
		}
	}
	return Super.ReduceDamage(Damage, DamageType, injured, instigatedBy);
}

function bool PriorityObjective(Bot aBot)
{
	return ( (aBot.PlayerReplicationInfo.HasFlag != None)
		|| (CTFReplicationInfo(GameReplicationInfo).FlagList[aBot.PlayerReplicationInfo.Team].Holder != None) );
}

defaultproperties
{
	 CaptureSound(0)=sound'CaptureSound'
	 CaptureSound(1)=sound'CaptureSound2'
	 CaptureSound(2)=sound'CaptureSound3'
	 returnstring=" returns the "
	 capturestring=" captured the "
     bNoMonsters=False
     bHumansOnly=True
     bUseTranslocator=True
     bSpawnInTeamArea=True
	 bNoMonsters=False
	 bScoreTeamKills=false
     MaxTeams=2
	 InitialBots=0
	 BeaconName="CTF"
	 StartUpMessage="This server is playing Unreal Challenge Capture the Flag."
	 GameName="Capture the Flag"
     MapPrefix="CTF"
     BotConfigType=Class'BotPack.ChallengeBotInfo'
	 GameMenuType=ChallengeCTFMenu
     MapListType=Class'BotPack.CTFmaplist'
	 HUDType=Class'BotPack.ChallengeCTFHUD'
     GameReplicationInfoClass=Class'BotPack.CTFReplicationInfo'
	 ScoreBoardType=Class'BotPack.UnrealCTFScoreboard'
	 LadderMenuType=Class'BotPack.CTFLadder'
}
