#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		= 5;
CONST_MAX_ACTIVE_KILLSTREAK_DOGS_PER_PLAYER 	= 1;
CONST_MAX_ACTIVE_KILLSTREAK_AGENTS_PER_PLAYER 	= 2;

//===========================================
// 					init
//===========================================
init()
{
	PreCacheModel( "animal_dobernan" );
	
	level.killStreakFuncs["guard_dog"] = ::tryUseDog;
}


//===========================================
// 				setup_callbacks
//===========================================
setup_callbacks()
{
	level.agent_funcs["dog"] = level.agent_funcs["player"];
	
	level.agent_funcs["dog"]["spawn"]				= ::spawn_dog;
	level.agent_funcs["dog"]["on_killed"]			= ::on_agent_dog_killed;
	level.agent_funcs["dog"]["on_damaged"]			= maps\mp\agents\_agents::on_agent_generic_damaged;
	level.agent_funcs["dog"]["on_damaged_finished"] = ::on_damaged_finished;
	level.agent_funcs["dog"]["think"] 				= maps\mp\agents\dog\_dog_think::main;
	
	level.killstreakWieldWeapons["agent_mp"] = "agent_mp";
	
}


//===========================================
// 				tryUseDog
//===========================================
tryUseDog( lifeId, streakName )
{
	return useDog();
}


//===========================================
// 				useDog
//===========================================
useDog()
{
	// 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;
	}
	
	// try to spawn the agent on a path node near the player
	nearestPathNode = self getValidSpawnPathNodeNearPlayer( true );
	if( !IsDefined(nearestPathNode) )
	{
		return false;
	}

	// find an available agent
	agent = maps\mp\agents\_agent_common::connectNewAgent( "dog" , self.team );
	if( !IsDefined( agent ) )
	{
		return false;
	}
	
	// set the agent to the player's team
	agent set_agent_team( self.team, self );
	
	spawnOrigin = nearestPathNode.origin;
	spawnAngles = VectorToAngles( self.origin - nearestPathNode.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" );
	}
	
	return true;
}


//=======================================================
//				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_killed" );
		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_doberman_death" );

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

	self notify( "killanimscript" );
}


on_damaged_finished( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset )
{
	if( !IsDefined( self.playing_pain_sound ) )
		self thread play_pain_sound( 2.5 );

	// damage needs to be modified depending on the weapon and hit location because the head is really easy to hit when the dog is running at you
	//	assuming 1.4 modifier for head shots
	damageModified = iDamage;
	if( IsDefined( sHitLoc ) && sHitLoc == "head" && level.gametype != "horde" )
	{
		damageModified = int( damageModified * 0.6 );
		if ( iDamage > 0 && damageModified <= 0 )
			damageModified = 1;
	}
	
	if ( self.health - damageModified > 0 )
	{
		self maps\mp\agents\dog\_dog_think::OnDamage( eInflictor, eAttacker, damageModified, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset );
	}
	
	// attack the player that has damaged them
	if( IsPlayer( eAttacker ) )
	{
		// is the dog already attacking?
		if ( IsDefined( self.attackState ) && self.attackState != "attacking" )
		{
			// is the attacker within the dog damaged range?
			if( DistanceSquared( self.origin, eAttacker.origin ) <= self.dogDamagedRadiusSq )
			{
				self.favoriteEnemy = eAttacker;
				self.forceAttack = true;
				self thread maps\mp\agents\dog\_dog_think::watchFavoriteEnemyDeath();
			}
		}
	}

	maps\mp\agents\_agents::agent_damage_finished( eInflictor, eAttacker, damageModified, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset );
}

play_pain_sound( delay ) // self == dog
{
	self endon( "death" );
	
	self PlaySound( "anml_doberman_pain" );
	self.playing_pain_sound = true;
	wait( delay );
	self.playing_pain_sound = undefined;
}

spawn_dog( optional_spawnOrigin, optional_spawnAngles, optional_owner ) // self == agent
{
	if ( IsHairRunning() )
		self SetModel( "animal_dobernan" );
	else
		self SetModel( "animal_dobernan" );

	self.species = "dog";

	self.OnEnterAnimState = maps\mp\agents\dog\_dog_think::OnEnterAnimState;

	// allow killstreaks to pass in specific spawn locations
	if( IsDefined(optional_spawnOrigin) && IsDefined(optional_spawnAngles) )
	{
		spawnOrigin = optional_spawnOrigin;
		spawnAngles = optional_spawnAngles;
	}
	else
	{
		spawnPoint 	= self [[level.getSpawnPoint]]();
		spawnOrigin = spawnpoint.origin;
		spawnAngles = spawnpoint.angles;
	}
	self activateAgent();
	self.spawnTime 	= GetTime();
	self.lastSpawnTime = GetTime();

	self maps\mp\agents\dog\_dog_think::init();

	// called from code when an agent is done initializing after AddAgent is called
	// this should set up any state specific to this agent and game
	self SpawnAgent( spawnOrigin, spawnAngles, "dog_animclass", 15, 40, optional_owner );
	level notify( "spawned_agent", self );
	
	self maps\mp\agents\_agent_common::set_agent_health( 250 );
	
	// must set the team after SpawnAgent to fix a bug with weapon crosshairs and nametags
	if( IsDefined(optional_owner) )
	{
		self set_agent_team( optional_owner.team, optional_owner );
	}
	
	self SetThreatBiasGroup( "Dogs" );

	self TakeAllWeapons();

	// hide the dog, let the whistle happen, then show the dog
	if( IsDefined(self.owner) )
	{
		self Hide();
		wait( 1.0 ); // not sure what to endon for this
		
		// The dog could have died during the 1 second wait (for example if he spawned in a kill trigger), so if that happened,
		//  don't start thinking since it will cause SREs due to him missing a self.agent_type
		if ( !IsAlive(self) )
			return;
		
		self Show();
		wait( 0.1 );
	}
	
	self thread [[ self agentFunc("think") ]]();

	wait( 0.1 );
	if ( IsHairRunning() )
		PlayFXOnTag( level.furFX, self, "tag_origin" );
}
