#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;

CreateObjectiveForManger( sName, fpFinder, fpExecuter, iProcessRate )
{
	Answer = SpawnStruct();

	Answer.sName = sName;
	Answer.fpFinder = fpFinder;
	Answer.fpExecuter = fpExecuter;

	Answer.aBotProcessTimes = [];
	Answer.iProcessRate = iProcessRate;

	return Answer;
}

CreateFinderObjective( eObj, sName, eEnt, fPriority )
{
	Answer = SpawnStruct();

	Answer.eParentObj = eObj;
	Answer.sName = sName;
	Answer.eEnt = eEnt;
	Answer.fPriority = fPriority;
	Answer.GUID = eEnt GetEntityNumber();

	Answer.bWasSuccessful = false;
	Answer.sReason = "canceled";

	return Answer;
}

/*
	Checks whether the path generated by the ASTAR path finding is inaccessible
*/
GetPathIsInaccessible( from, to, team, best_effort )
{
	if ( isDefined( best_effort ) )
	{
		path = generatePath( from, to, team, level.bot_allowed_negotiation_links, best_effort );
	}
	else
	{
		path = generatePath( from, to, team, level.bot_allowed_negotiation_links );
	}

	return ( !isDefined( path ) || ( path.size <= 0 ) );
}

get_path_dist( start, end, team )
{
	path = generatePath( start, end, team, level.bot_allowed_negotiation_links, 192.0 );

	if ( !isDefined( path ) || path.size <= 0 )
	{
		return 999999999;
	}

	dist = 0;
	prev_node = undefined;

	for ( i = 0; i < path.size; i++ )
	{
		if ( i == 0 )
		{
			prev_node = path[ i ];
			continue;
		}

		dist += distance( prev_node.origin, path[ i ].origin );
		prev_node = path[ i ];
	}

	return dist;
}

ClampLerp( dist, min_dist, max_dist, max_bonus, min_bonus )
{
	answer = 0;

	if ( dist <= min_dist )
	{
		answer += max_bonus;
	}
	else if ( dist >= max_dist )
	{
		answer += min_bonus;
	}
	else
	{
		dist_multi = 1 - ( ( dist - min_dist ) / ( max_dist - min_dist ) );
		answer += min_bonus + ( ( max_bonus - min_bonus ) * dist_multi );
	}

	return answer;
}

GetBotsAmountForEntity( eEnt )
{
	if ( !isDefined( eEnt.bots ) )
	{
		eEnt.bots = 0;
	}

	return eEnt.bots;
}

IncrementBotsForEntity( eEnt )
{
	self endon( "bots_for_entity_cleanup" );

	eEnt.bots++;

	self waittill_either( "disconnect", "zombified" );

	if ( isDefined( eEnt ) )
	{
		eEnt.bots--;
	}
}

DecrementBotsForEntity( eEnt )
{
	self notify( "bots_for_entity_cleanup" );

	if ( isDefined( eEnt ) )
	{
		eEnt.bots--;
	}
}

CleanupBotsForEntity( eEnt )
{
	self notify( "bots_for_entity_cleanup" );
}

CancelObjective( reason )
{
	self notify( "cancel_bot_objective", reason );
}

CompletedObjective( successful, reason )
{
	self notify( "completed_bot_objective", successful, reason );
}

HasBotObjective()
{
	return isDefined( self.bot_current_objective );
}

get_angle_offset_node( forward_size, angle_offset, offset )
{
	if ( !isDefined( forward_size ) )
	{
		forward_size = 40;
	}

	if ( !isDefined( angle_offset ) )
	{
		angle_offset = ( 0, 0, 0 );
	}

	if ( !isDefined( offset ) )
	{
		offset = ( 0, 0, 0 );
	}

	angles = ( 0, self.angles[ 1 ], 0 );
	angles += angle_offset;
	node = self.origin + ( AnglesToForward( angles ) * forward_size ) + offset;
	node = clamp_to_ground( node );

	self thread debug_offset_line( node );
	return node;
}

debug_offset_line( node )
{
	self notify( "debug_offset_line" );
	self endon( "debug_offset_line" );

	for ( ;; )
	{
		line( self.origin, node );
		wait 0.05;
	}
}

PointInsideUseTrigger( point )
{
	self thread debug_bounding_box_for_ent();

	mins = self getmins();
	maxs = self getmaxs();

	box = spawnstruct();
	box.x0 = self.origin[0] + mins[0];
	box.x1 = self.origin[0] + maxs[0];
	box.y0 = self.origin[1] + mins[1];
	box.y1 = self.origin[1] + maxs[1];
	box.z0 = self.origin[2] + mins[2];
	box.z1 = self.origin[2] + maxs[2];

	if ( box RectDistanceSquared( self.origin ) > 72 * 72 )
	{
		return false;
	}

	if ( !bulletTracePassed( point, self.origin, false, undefined ) )
	{
		return false;
	}

	return true;
}

debug_bounding_box_for_ent( color )
{
	self endon( "death" );
	self notify( "debug_bounding_box_for_ent" );
	self endon( "debug_bounding_box_for_ent" );

	if ( !isDefined( color ) )
		color = ( randomFloatRange( 0, 1 ), randomFloatRange( 0, 1 ), randomFloatRange( 0, 1 ) );

	while ( isDefined( self ) )
	{
		mins = self getmins();
		maxs = self getmaxs();

		line( self.origin + ( mins[0], mins[1], mins[2] ), self.origin + ( mins[0], mins[1], maxs[2] ), color );
		line( self.origin + ( mins[0], mins[1], mins[2] ), self.origin + ( mins[0], maxs[1], mins[2] ), color );
		line( self.origin + ( mins[0], mins[1], mins[2] ), self.origin + ( maxs[0], mins[1], mins[2] ), color );

		line( self.origin + ( maxs[0], maxs[1], maxs[2] ), self.origin + ( maxs[0], maxs[1], mins[2] ), color );
		line( self.origin + ( maxs[0], maxs[1], maxs[2] ), self.origin + ( maxs[0], mins[1], maxs[2] ), color );
		line( self.origin + ( maxs[0], maxs[1], maxs[2] ), self.origin + ( mins[0], maxs[1], maxs[2] ), color );

		line( self.origin + ( maxs[0], mins[1], mins[2] ), self.origin + ( maxs[0], maxs[1], mins[2] ), color );
		line( self.origin + ( maxs[0], mins[1], mins[2] ), self.origin + ( maxs[0], mins[1], maxs[2] ), color );

		line( self.origin + ( mins[0], mins[1], maxs[2] ), self.origin + ( maxs[0], mins[1], maxs[2] ), color );
		line( self.origin + ( mins[0], mins[1], maxs[2] ), self.origin + ( mins[0], maxs[1], maxs[2] ), color );

		line( self.origin + ( mins[0], maxs[1], mins[2] ), self.origin + ( maxs[0], maxs[1], mins[2] ), color );
		line( self.origin + ( mins[0], maxs[1], mins[2] ), self.origin + ( mins[0], maxs[1], maxs[2] ), color );

		wait 0.05;
	}
}

clamp_to_ground( org )
{
	trace = playerPhysicsTrace( org + ( 0, 0, 20 ), org - ( 0, 0, 2000 ) );
	return trace;
}