#include maps/mp/bots/_bot_combat;
#include maps/mp/bots/_bot;
#include maps/mp/_utility;
#include common_scripts/utility;
#include maps/mp/gametypes/koth;

bot_koth_think() //checked matches cerberus output
{
	if ( !isDefined( level.zone.trig.goal_radius ) )
	{
		maxs = level.zone.trig getmaxs();
		maxs = level.zone.trig.origin + maxs;
		level.zone.trig.goal_radius = distance( level.zone.trig.origin, maxs );
		/*
/#
		println( "distance: " + level.zone.trig.goal_radius );
#/
		*/
		ground = bullettrace( level.zone.gameobject.curorigin, level.zone.gameobject.curorigin - vectorScale( ( 0, 0, 1 ), 1024 ), 0, undefined );
		level.zone.trig.goal = ground[ "position" ] + vectorScale( ( 0, 0, 1 ), 8 );
	}
	if ( !bot_has_hill_goal() )
	{
		self bot_move_to_hill();
	}
	if ( self bot_is_at_hill() )
	{
		self bot_capture_hill();
	}
	bot_hill_tactical_insertion();
	bot_hill_grenade();
}

bot_has_hill_goal() //checked matches cerberus output
{
	origin = self getgoal( "koth_hill" );
	if ( isDefined( origin ) )
	{
		if ( distance2dsquared( level.zone.gameobject.curorigin, origin ) < level.zone.trig.goal_radius * level.zone.trig.goal_radius )
		{
			return 1;
		}
	}
	return 0;
}

bot_is_at_hill() //checked matches cerberus output
{
	return self atgoal( "koth_hill" );
}

bot_move_to_hill() //checked changed to match cerberus output
{
	if ( getTime() < ( self.bot.update_objective + 4000 ) )
	{
		return;
	}
	self clearlookat();
	self cancelgoal( "koth_hill" );
	if ( self getstance() == "prone" )
	{
		self setstance( "crouch" );
		wait 0.25;
	}
	if ( self getstance() == "crouch" )
	{
		self setstance( "stand" );
		wait 0.25;
	}
	nodes = getnodesinradiussorted( level.zone.trig.goal, level.zone.trig.goal_radius, 0, 128 );
	foreach ( node in nodes )
	{
		if ( self maps/mp/bots/_bot::bot_friend_goal_in_radius( "koth_hill", node.origin, 64 ) == 0 )
		{
			if ( findpath( self.origin, node.origin, self, 0, 1 ) )
			{
				self addgoal( node, 24, 3, "koth_hill" );
				self.bot.update_objective = getTime();
				return;
			}
		}
	}
}

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 ) > 1024 )
		{
			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 ) > 1024 )
		{
			return node.origin;
		}
	}
	spawn = random( level.spawnpoints );
	node = getvisiblenode( self.origin, spawn.origin );
	if ( isDefined( node ) && distancesquared( self.origin, node.origin ) > 1024 )
	{
		return node.origin;
	}
	return level.zone.gameobject.curorigin;
}

bot_capture_hill() //checked changed to match cerberus output
{
	self addgoal( self.origin, 24, 3, "koth_hill" );
	self setstance( "crouch" );
	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 );
		if ( cointoss() && lengthsquared( self getvelocity() ) < 2 )
		{
			nodes = getnodesinradius( level.zone.trig.goal, level.zone.trig.goal_radius + 128, 0, 128 );
			for ( i = randomintrange( 0, nodes.size ); i < nodes.size; i++ )
			{
				node = nodes[ i ];
				if ( distancesquared( node.origin, self.origin ) > 1024 )
				{
					if ( self maps/mp/bots/_bot::bot_friend_goal_in_radius( "koth_hill", node.origin, 128 ) == 0 )
					{
						if ( findpath( self.origin, node.origin, self, 0, 1 ) )
						{
							self addgoal( node, 24, 3, "koth_hill" );
							self.bot.update_objective = getTime();
							break;
						}
					}
				}
			}
		}
		self.bot.update_lookat = getTime() + randomintrange( 1500, 3000 );
	}
}

any_other_team_touching( skip_team ) //checked partially changed to match cerberus output did not use foreach see github for more info
{
	teams = getArrayKeys( level.teams );
	while ( i < teams.size )
	{
		if ( teams[ i ] == skip_team )
		{
			continue;
		}
		if ( level.zone.gameobject.numtouching[ teams[ i ] ] )
		{
			return 1;
		}
	}
	return 0;
}

is_hill_contested( skip_team ) //checked matches cerberus output
{
	if ( any_other_team_touching( skip_team ) )
	{
		return 1;
	}
	enemy = self maps/mp/bots/_bot::bot_get_closest_enemy( level.zone.gameobject.curorigin, 1 );
	if ( isDefined( enemy ) && distancesquared( enemy.origin, level.zone.gameobject.curorigin ) < 262144 )
	{
		return 1;
	}
	return 0;
}

bot_hill_grenade() //checked changed to match cerberus output
{
	enemies = bot_get_enemies();
	if ( !enemies.size )
	{
		return;
	}
	if ( self atgoal( "hill_patrol" ) || self atgoal( "koth_hill" ) )
	{
		if ( self getweaponammostock( "proximity_grenade_mp" ) > 0 )
		{
			origin = bot_get_look_at();
			if ( self maps/mp/bots/_bot_combat::bot_combat_throw_proximity( origin ) )
			{
				return;
			}
		}
	}
	if ( !is_hill_contested( self.team ) )
	{
		if ( !isDefined( level.next_smoke_time ) )
		{
			level.next_smoke_time = 0;
		}
		if ( getTime() > level.next_smoke_time )
		{
			if ( self maps/mp/bots/_bot_combat::bot_combat_throw_smoke( level.zone.gameobject.curorigin ) )
			{
				level.next_smoke_time = getTime() + randomintrange( 60000, 120000 );
			}
		}
		return;
	}
	enemy = self maps/mp/bots/_bot::bot_get_closest_enemy( level.zone.gameobject.curorigin, 0 );
	if ( isDefined( enemy ) )
	{
		origin = enemy.origin;
	}
	else
	{
		origin = level.zone.gameobject.curorigin;
	}
	dir = vectornormalize( self.origin - origin );
	dir = ( 0, dir[ 1 ], 0 );
	origin += vectorScale( dir, 128 );
	if ( maps/mp/bots/_bot::bot_get_difficulty() == "easy" )
	{
		if ( !isDefined( level.next_grenade_time ) )
		{
			level.next_grenade_time = 0;
		}
		if ( getTime() > level.next_grenade_time )
		{
			if ( !self maps/mp/bots/_bot_combat::bot_combat_throw_lethal( origin ) )
			{
				self maps/mp/bots/_bot_combat::bot_combat_throw_tactical( origin );
			}
			else
			{
				level.next_grenade_time = getTime() + randomintrange( 60000, 120000 );
			}
		}
	}
	else if ( !self maps/mp/bots/_bot_combat::bot_combat_throw_lethal( origin ) )
	{
		self maps/mp/bots/_bot_combat::bot_combat_throw_tactical( origin );
	}
}

bot_hill_tactical_insertion() //checked matches cerberus output
{
	if ( !self hasweapon( "tactical_insertion_mp" ) )
	{
		return;
	}
	dist = self getlookaheaddist();
	dir = self getlookaheaddir();
	if ( !isDefined( dist ) || !isDefined( dir ) )
	{
		return;
	}
	node = hill_nearest_node();
	mine = getnearestnode( self.origin );
	if ( isDefined( mine ) && !nodesvisible( mine, node ) )
	{
		origin = self.origin + vectorScale( dir, dist );
		next = getnearestnode( origin );
		if ( isDefined( next ) && nodesvisible( next, node ) )
		{
			bot_combat_tactical_insertion( self.origin );
		}
	}
}

hill_nearest_node() //checked matches cerberus output
{
	nodes = getnodesinradiussorted( level.zone.gameobject.curorigin, 256, 0 );
	/*
/#
	assert( nodes.size );
#/
	*/
	return nodes[ 0 ];
}


