//checked includes match cerberus output
#include maps/mp/gametypes/_gameobjects;
#include maps/mp/bots/_bot_combat;
#include maps/mp/bots/_bot;
#include maps/mp/_utility;
#include common_scripts/utility;
#include maps/mp/gametypes/ctf;

bot_ctf_think() //checked changed to match cerberus output changed at own discretion
{
	time = getTime();
	if ( time < self.bot.update_objective )
	{
		return;
	}
	self.bot.update_objective = time + randomintrange( 500, 1500 );
	if ( maps/mp/bots/_bot::bot_get_difficulty() != "easy" )
	{
		flag_mine = ctf_get_flag( self.team );
		if ( flag_mine ishome() && distancesquared( self.origin, flag_mine.curorigin ) < 262144 )
		{
			nodes = getnodesinradius( flag_mine.curorigin, 256, 0, 64, "any", 8 );
			node = random( nodes );
			if ( cointoss() )
			{
				self maps/mp/bots/_bot_combat::bot_combat_throw_proximity( node.origin );
			}
			if ( cointoss() )
			{
				self maps/mp/bots/_bot_combat::bot_combat_toss_frag( node.origin );
			}
			if ( cointoss() )
			{
				self maps/mp/bots/_bot_combat::bot_combat_toss_flash( node.origin );
			}
		}
	}
	if ( bot_should_patrol_flag() )
	{
		bot_patrol_flag();
		return;
	}
	self cancelgoal( "ctf_flag_patrol" );
	if ( !bot_ctf_defend() )
	{
		bot_ctf_capture();
	}
	flag_mine = ctf_get_flag( self.team );
	flag_enemy = ctf_get_flag( getotherteam( self.team ) );
	home_mine = flag_mine ctf_flag_get_home();
	if ( ctf_has_flag( flag_enemy ) && self issprinting() && distancesquared( self.origin, home_mine ) < 36864 )
	{
		if ( bot_dot_product( home_mine ) > 0.9 )
		{
			self bot_dive_to_prone( "stand" );
		}
	}
	else if ( !flag_mine ishome() && !isDefined( flag_mine.carrier ) )
	{
		if ( self issprinting() && distancesquared( self.origin, flag_mine.curorigin ) < 36864 )
		{
			if ( bot_dot_product( flag_mine.curorigin ) > 0.9 )
			{
				self bot_dive_to_prone( "stand" );
			}
		}
	}
}

bot_should_patrol_flag() //checked matches cerberus output
{
	flag_mine = ctf_get_flag( self.team );
	flag_enemy = ctf_get_flag( getotherteam( self.team ) );
	home_mine = flag_mine ctf_flag_get_home();
	if ( self hasgoal( "ctf_flag" ) && !self atgoal( "ctf_flag" ) )
	{
		return 0;
	}
	if ( ctf_has_flag( flag_enemy ) )
	{
		if ( !flag_mine ishome() )
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	if ( !flag_mine ishome() )
	{
		return 0;
	}
	if ( distancesquared( self.origin, flag_enemy.curorigin ) < 262144 )
	{
		return 0;
	}
	if ( bot_get_friends().size && self maps/mp/bots/_bot::bot_friend_goal_in_radius( "ctf_flag_patrol", home_mine, 1024 ) == 0 )
	{
		return 1;
	}
	return 0;
}

ctf_get_flag( team ) //checked changed to match cerberus output
{
	foreach ( f in level.flags )
	{
		if ( f maps/mp/gametypes/_gameobjects::getownerteam() == team )
		{
			return f;
		}
	}
	return undefined;
}

ctf_flag_get_home() //checked matches cerberus output
{
	return self.trigger.baseorigin;
}

ctf_has_flag( flag ) //checked changed at own discretion
{
	if ( isDefined( flag.carrier ) && flag.carrier == self )
	{
		return 1;
	}
	return 0;
}

bot_ctf_capture() //checked changed to match cerberus output
{
	flag_enemy = ctf_get_flag( getotherteam( self.team ) );
	flag_mine = ctf_get_flag( self.team );
	home_enemy = flag_enemy ctf_flag_get_home();
	home_mine = flag_mine ctf_flag_get_home();
	if ( ctf_has_flag( flag_enemy ) )
	{
		self addgoal( home_mine, 16, 4, "ctf_flag" );
	}
	else if ( isDefined( flag_enemy.carrier ) )
	{
		if ( self atgoal( "ctf_flag" ) )
		{
			self cancelgoal( "ctf_flag" );
		}
		goal = self getgoal( "ctf_flag" );
		if ( isDefined( goal ) && distancesquared( goal, flag_enemy.carrier.origin ) < 589824 )
		{
			return;
		}
		nodes = getnodesinradius( flag_enemy.carrier.origin, 512, 64, 256, "any", 8 );
		if ( nodes.size )
		{
			self addgoal( random( nodes ), 16, 3, "ctf_flag" );
		}
		else
		{
			self addgoal( flag_enemy.carrier.origin, 16, 3, "ctf_flag" );
		}
	}
	else if ( self maps/mp/bots/_bot::bot_friend_goal_in_radius( "ctf_flag", flag_enemy.curorigin, 16 ) <= 1 )
	{
		self addgoal( flag_enemy.curorigin, 16, 3, "ctf_flag" );
	}
}

bot_ctf_defend() //checked changed to match cerberus output
{
	flag_enemy = ctf_get_flag( getotherteam( self.team ) );
	flag_mine = ctf_get_flag( self.team );
	home_enemy = flag_enemy ctf_flag_get_home();
	home_mine = flag_mine ctf_flag_get_home();
	if ( flag_mine ishome() )
	{
		return 0;
	}
	if ( ctf_has_flag( flag_enemy ) )
	{
		return 0;
	}
	if ( !isDefined( flag_mine.carrier ) )
	{
		if ( self maps/mp/bots/_bot::bot_friend_goal_in_radius( "ctf_flag", flag_mine.curorigin, 16 ) <= 1 )
		{
			return self bot_ctf_add_goal( flag_mine.curorigin, 4, "ctf_flag" );
		}
	}
	else if ( !flag_enemy ishome() || distance2dsquared( self.origin, home_enemy ) > 250000 )
	{
		return self bot_ctf_add_goal( flag_mine.curorigin, 4, "ctf_flag" );
	}
	else if ( self maps/mp/bots/_bot::bot_friend_goal_in_radius( "ctf_flag", home_enemy, 16 ) <= 1 )
	{
		self addgoal( home_enemy, 16, 4, "ctf_flag" );
	}
	return 1;
}

bot_ctf_add_goal( origin, goal_priority, goal_name ) //checked matches cerberus output
{
	goal = undefined;
	if ( findpath( self.origin, origin, undefined, 0, 1 ) )
	{
		goal = origin;
	}
	else
	{
		node = bot_ctf_random_visible_node( origin );
		if ( isDefined( node ) )
		{
			if ( findpath( self.origin, node.origin, undefined, 0, 1 ) )
			{
				goal = node;
				self.bot.update_objective += randomintrange( 3000, 5000 );
			}
		}
	}
	if ( isDefined( goal ) )
	{
		self addgoal( goal, 16, goal_priority, goal_name );
		return 1;
	}
	return 0;
}

bot_get_look_at() //checked matches cerberus output
{
	enemy = self maps/mp/bots/_bot::bot_get_closest_enemy( self.origin, 1 );
	if ( isDefined( enemy ) )
	{
		node = getvisiblenode( self.origin, enemy.origin );
		if ( isDefined( node ) && distancesquared( self.origin, node.origin ) > 16384 )
		{
			return node.origin;
		}
	}
	enemies = self maps/mp/bots/_bot::bot_get_enemies( 0 );
	if ( enemies.size )
	{
		enemy = random( enemies );
	}
	if ( isDefined( enemy ) )
	{
		node = getvisiblenode( self.origin, enemy.origin );
		if ( isDefined( node ) && distancesquared( self.origin, node.origin ) > 16384 )
		{
			return node.origin;
		}
	}
	flag_mine = ctf_get_flag( self.team );
	home_mine = flag_mine ctf_flag_get_home();
	return home_mine;
}

bot_patrol_flag() //checked changed to match cerberus output
{
	self cancelgoal( "ctf_flag" );
	flag_mine = ctf_get_flag( self.team );
	if ( self atgoal( "ctf_flag_patrol" ) )
	{
		node = getnearestnode( self.origin );
		if ( !isDefined( node ) )
		{
			self clearlookat();
			self cancelgoal( "ctf_flag_patrol" );
			return;
		}
		if ( node.type == "Path" )
		{
			self setstance( "crouch" );
		}
		else
		{
			self setstance( "stand" );
		}
		if ( getTime() > self.bot.update_lookat )
		{
			origin = self bot_get_look_at();
			z = 20;
			if ( distancesquared( origin, self.origin ) > 262144 )
			{
				z = randomintrange( 16, 60 );
			}
			self lookat( origin + ( 0, 0, z ) );
			if ( distancesquared( origin, self.origin ) > 65536 )
			{
				dir = vectornormalize( self.origin - origin );
				dir = vectorScale( dir, 256 );
				origin += dir;
			}
			self maps/mp/bots/_bot_combat::bot_combat_throw_proximity( origin );
			self.bot.update_lookat = getTime() + randomintrange( 1500, 3000 );
		}
		goal = self getgoal( "ctf_flag_patrol" );
		nearest = base_nearest_node( flag_mine );
		mine = getnearestnode( goal );
		if ( isDefined( mine ) && !nodesvisible( mine, nearest ) )
		{
			self clearlookat();
			self cancelgoal( "ctf_flag_patrol" );
		}
		if ( getTime() > self.bot.update_objective_patrol )
		{
			self clearlookat();
			self cancelgoal( "ctf_flag_patrol" );
		}
		return;
	}
	nearest = base_nearest_node( flag_mine );
	if ( self hasgoal( "ctf_flag_patrol" ) )
	{
		goal = self getgoal( "ctf_flag_patrol" );
		if ( distancesquared( self.origin, goal ) < 65536 )
		{
			origin = self bot_get_look_at();
			self lookat( origin );
		}
		if ( distancesquared( self.origin, goal ) < 16384 )
		{
			self.bot.update_objective_patrol = getTime() + randomintrange( 3000, 6000 );
		}
		mine = getnearestnode( goal );
		if ( isDefined( mine ) && !nodesvisible( mine, nearest ) )
		{
			self clearlookat();
			self cancelgoal( "ctf_flag_patrol" );
		}
		return;
	}
	if ( getTime() < self.bot.update_objective_patrol )
	{
		return;
	}
	nodes = getvisiblenodes( nearest );
	/*
/#
	assert( nodes.size );
#/
	*/
	for ( i = randomint(nodes.size); i < nodes.size; i++ )
	{
		if ( self maps/mp/bots/_bot::bot_friend_goal_in_radius( "ctf_flag_patrol", nodes[ i ].origin, 256 ) == 0 )
		{
			self addgoal( nodes[ i ], 24, 3, "ctf_flag_patrol" );
			self.bot.update_objective_patrol = getTime() + randomintrange( 3000, 6000 );
			return;
		}
	}
}

base_nearest_node( flag ) //checked matches cerberus output
{
	home = flag ctf_flag_get_home();
	nodes = getnodesinradiussorted( home, 256, 0 );
	/*
/#
	assert( nodes.size );
#/
	*/
	return nodes[ 0 ];
}

bot_ctf_random_visible_node( origin ) //checked changed to match cerberus output
{
	nodes = getnodesinradius( origin, 384, 0, 256 );
	nearest = maps/mp/bots/_bot_combat::bot_nearest_node( origin );
	if ( isDefined( nearest ) && nodes.size )
	{
		current = randomintrange( 0, nodes.size );
		for ( i = 0; i < nodes.size; i++ )
		{
			current = ( current + 1 ) % nodes.size;
			if ( nodesvisible( nodes[ current ], nearest ) )
			{
				return nodes[ current ];
			}
		}
	}
	return undefined;
}


