#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
#include maps\mp\agents\_agent_utility;
#include maps\mp\gametypes\_damage;


//===========================================
// 				constants
//===========================================
CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_GAME		= 3;
CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_PLAYER 	= 3;
CONST_MAX_ACTIVE_KILLSTREAK_AGENTS_PER_PLAYER 	= 3;
CONST_DOG_KILL_COUNT_LIMIT = 2;
CONST_STREAK_TIMEOUT = 60;
CONST_STREAK_RETREAT_TIMEOUT=20;

init()
{
	level.killstreakFuncs["mp_instinct"] = ::tryUseMPInstinct;
	level.mapKillStreak = "mp_instinct";
	
	level.InstinctDogs = [];
	
	//PreCacheModel( "sb_pig_table_noguts" );
	PreCacheModel( "animal_iw6_dog_a" );
	
	level.killstreakWieldWeapons[ "killstreak_instinct_mp" ] = "mp_instinct";
	
	level.InstinctDogSpawnPoints =[];
	
	SpawnPoints = GetNodeArray( "InstinctDogSpawnPoint", "targetname" );
	
	foreach( point in SpawnPoints)
	{
		tempPoint = SpawnStruct();
		tempPoint.SpawnPoint = point;
		tempPoint.Weight = 0;
		
		level.InstinctDogSpawnPoints = add_to_array(level.InstinctDogSpawnPoints, tempPoint);
	}
	
	OnPlayerConnect();
}

tryUseMPInstinct(lifeId, streakName)
{
	return spawnInstinctDogs();
}  


setMPInstinctPlayer( player )
{
	level.mp_instinct_owner = player;
	
	thread teamPlayerCardSplash( "used_mp_instinct", player );
	
	return true;
}


OnPlayerConnect()
{
	connectCount =0;
	for(;;)
	{
		level waittill("connected", player);
		
		if(connectCount==0)
		{
			if ( !IsDefined(level.isHorde) || !level.isHorde )
			{
				level.agent_funcs["dog"]["think"] 				= maps\mp\agents\dog\_instinct_dog_think::main;
				level.agent_funcs["dog"]["on_killed"]			= ::on_agent_dog_killed;
			}
		}
		
		connectCount++;
		player thread onPlayerSpawned();
	}
}


onPlayerSpawned()
{
	self endon("disconnect");

	self waittill( "spawned_player" );

	self thread MonitorKills();
}


//===========================================
// 				spawnInstinctDogs				//spawn three from smart spawn locations around the map.  
//===========================================
spawnInstinctDogs()
{
	// limit the number of active "dog" agents allowed per game
	if( getNumActiveAgents( "dog" ) >= CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_GAME )
	{
		self iPrintLnBold( &"KILLSTREAKS_TOO_MANY_DOGS" );
		return false;
	}
	// limit the number of active "dog" agents allowed per player
	if( getNumOwnedActiveAgentsByType( self, "dog" ) >= CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_PLAYER )
	{
		self iPrintLnBold( &"KILLSTREAKS_ALREADY_HAVE_DOG" );
		return false;
	}
	// limit the number of active agents allowed per player
	if( getNumOwnedActiveAgents( self ) >= CONST_MAX_ACTIVE_KILLSTREAK_AGENTS_PER_PLAYER )
	{
		self iPrintLnBold( &"KILLSTREAKS_AGENT_MAX" );
		return false;
	}
	
	// TODO: we should probably do a queue system for these, so the player can call it but it'll go into a queue for when an agent dies to open up a spot
	// limit the number of active agents allowed per player
	maxagents = GetMaxAgents();
	if( getNumActiveAgents() >= maxagents )
	{
		self iPrintLnBold( &"KILLSTREAKS_UNAVAILABLE" );
		return false;
	}
		
	// make sure the player is still alive before the agent trys to spawn on the player
	if( !isReallyAlive( self ) )
	{
		return false;
	}
	
	ConnectAndSpawnInstinctDogPack();
	
	return true;
}

SortInstinctDogSpawnPoints()
{
	foreach(point in level.InstinctDogSpawnPoints)
	{
		point.Weight=0;
		//rate points by distance from owner
		tempDistance = Distance(point.SpawnPoint.origin,self.origin);
		if(tempDistance<1500)
			point.Weight=1;
		else if(tempDistance>1500 && tempDistance<2000)
			point.Weight=2;
		else if(tempDistance>2000 && tempDistance<2500)
			point.Weight=3;
		else if(tempDistance>2500)
			point.Weight=4;
		
		//rate points by los and distance to other players
		foreach(player in level.players)
		{
			start_pos = point.SpawnPoint.origin;
			target_pos = player.origin;
			LineOfSightCheck = SightTracePassed(start_pos ,target_pos , false, player);
			
			if( LineOfSightCheck )
				point.Weight--;
			
			tempDistance = Distance(point.SpawnPoint.origin,player.origin);
			if(tempDistance<256)
				point.Weight--;
		}
	}
	
	level.InstinctDogSpawnPoints = array_sort_with_func(level.InstinctDogSpawnPoints, ::isPointAScoredHigherThanB);	
}

PickInstinctDogSpawnPoint()
{
	SpawnPoint = level.InstinctDogSpawnPoints[0];
	
	level.InstinctDogSpawnPoints = array_remove(level.InstinctDogSpawnPoints, level.InstinctDogSpawnPoints[0]);
	
	return SpawnPoint;
}

isPointAScoredHigherThanB( a, b )
{
	return ( a.Weight > b.Weight );
}

WaitForTimeout()
{
	self waittill_any_timeout( CONST_STREAK_TIMEOUT, "KillCountMet" );
	self notify("retreat");
	DeleteNodes = GetNodeArray("DeletePoint", "targetname");
	Node = getClosest(self.origin, DeleteNodes);
	self notify("timeoutRetreat");
	self ScrAgentSetGoalPos( Node.origin );
	
	//waits till dog hits retreat node or a timeout for dogs who get stuck...
	self waittill_any_timeout(CONST_STREAK_RETREAT_TIMEOUT, "stop_soon" );
	
	//TODO kill the dog gracefully...
	self Suicide();
	self notify("death");
}

ConnectAndSpawnInstinctDogPack()
{
	SortInstinctDogSpawnPoints();
	for(i=0;i<3;i++)
	{
		// try to spawn the agent on a path node near the player
		nearestPathNode = self PickInstinctDogSpawnPoint( );
		
		if( !IsDefined(nearestPathNode) )
		{
			return false;
		}
	
		// find an available agent
		agent = maps\mp\agents\_agent_common::connectNewAgent( "dog" , self.team );
		if( !IsDefined( agent ) )
		{
			return false;
		}
		
		oldHealth = self.health;
		newHealth = 25;
		self.agenthealth 	= newHealth;
		self.health 		= newHealth;
		self.maxhealth		= newHealth;
		
		level.InstinctDogs = array_add(level.InstinctDogs,agent);

		agent thread WaitForDeath( nearestPathNode );
		
		// set the agent to the player's team
		agent set_agent_team( self.team, self );
		
		spawnOrigin = nearestPathNode.SpawnPoint.origin;
		spawnAngles = VectorToAngles( self.origin - nearestPathNode.SpawnPoint.origin );
	
		agent thread [[ agent agentFunc("spawn") ]]( spawnOrigin, spawnAngles, self );
		
		//agent _setNameplateMaterial( "player_name_bg_green_dog", "player_name_bg_red_dog" );
		
		if ( IsDefined( self.ballDrone ) && self.ballDrone.ballDroneType == "ball_drone_backup" )
		{
			self maps\mp\gametypes\_missions::processChallenge( "ch_twiceasdeadly" );
		}
		
		agent thread WaitForTimeout();
	}
}

WaitForDeath( PathNode )
{
	self waittill_any( "death", "retreat" );
	level.InstinctDogSpawnPoints = array_add(level.InstinctDogSpawnPoints, PathNode );
	level.InstinctDogs =array_remove(level.InstinctDogs, self);
}

MonitorKills()
{
	while(true)
	{
		self waittill("death",instigator);
		
		foreach(dog in level.InstinctDogs)
		{
			if(instigator == dog)
			{
				if(!IsDefined(dog.EnemyKills))
					dog.EnemyKills =0;
				
				dog.EnemyKills++;	
				
				if(dog.EnemyKills>=CONST_DOG_KILL_COUNT_LIMIT)
					dog notify("KillCountMet");
			}
		}
	}
}

//=======================================================
//				on_agent_dog_killed
//=======================================================
on_agent_dog_killed( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration )
{
	self.isActive 	= false;
	self.hasDied 	= false;

	eAttacker.lastKillDogTime = GetTime();
	
	if ( IsDefined( self.animCBs.OnExit[ self.aiState ] ) )
		self [[ self.animCBs.OnExit[ self.aiState ] ]] ();
	
	// award XP for killing agents
	if( isPlayer( eAttacker ) && IsDefined(self.owner) && (eAttacker != self.owner) )
	{
		self.owner leaderDialogOnPlayer( "dog_kia_mp_instinct" );
		self maps\mp\gametypes\_damage::onKillstreakKilled( eAttacker, sWeapon, sMeansOfDeath, iDamage, "destroyed_guard_dog" );
		
		if ( IsPlayer( eAttacker ) )
		{
			eAttacker maps\mp\gametypes\_missions::processChallenge( "ch_notsobestfriend" );
			
			// assume jumping?
			if ( !self IsOnGround() )
			{
				eAttacker maps\mp\gametypes\_missions::processChallenge( "ch_hoopla" );
			}
		}
	}

	self SetAnimState( "death" );
	animEntry = self GetAnimEntry();
	animLength = GetAnimLength( animEntry );
	
	deathAnimDuration = int( animLength * 1000 ); // duration in milliseconds
	
	self.body = self CloneAgent( deathAnimDuration );

	self PlaySound( "anml_dog_shot_death" );

	self maps\mp\agents\_agent_utility::deactivateAgent();

	self notify( "killanimscript" );
}