#using scripts\shared\ai_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\fx_shared;
#using scripts\shared\laststand_shared;
#using scripts\shared\math_shared;
#using scripts\shared\scene_shared;
#using scripts\shared\spawner_shared;
#using scripts\shared\util_shared;
#using scripts\shared\array_shared;
#using scripts\shared\system_shared;

#using scripts\shared\ai\systems\animation_state_machine_utility;
#using scripts\shared\ai\systems\animation_state_machine_notetracks;
#using scripts\shared\ai\archetype_utility;
#using scripts\shared\ai\systems\behavior_tree_utility;
#using scripts\shared\ai\systems\blackboard;
#using scripts\shared\ai\systems\debug;
#using scripts\shared\ai\systems\gib;
#using scripts\codescripts\struct;
#using scripts\shared\ai\archetype_mocomps_utility;

                                                                                                            	  	  	              	   	                                                                                                                                       	                                                                                                                                                            	                                                                                                                                                                
   	     	                                                                                                                                                                                                                                                                                                                                                                                                                                                             	                                                                                                                	         	    	                                                                                                    
        	                                                                                                                                                	                                                                                                                      	                                                                                     	                                                                                     	                                                            	                                                                                   	                                                                                     	                                                                                               	                                                                                                 	                                                                   	                                                                   	                                                                                                                 	                                                                                                                              	                                                                                                                       	                                                   	                                                                           	                                                                                 	                                       	                             	                                             	                                  	                                                                                 	                                                                                                                                                	      
                                                                                                                                               	
           	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              	  	                                 	                  	    	                                                      	   	        	                                                                         	                      	             	                                                                                                                                       	  	                                                                                                          	     	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                      	                                                                                                     	                                                                                                     	                                                                                                	     	                                                                                                                                                                                                                                                                                                                                                                                                                                	     	    	                                                                                                                                    	                      	              	  	             	  
                                                                                                                                                                                                          	     	                                                                                   
                                                                  	                             	  	                                      
                                                                                                           	                                                                                                                                                                                                                    
    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   

#namespace SkeletonBehavior;

function autoexec __init__sytem__() {     system::register("skeleton",&__init__,undefined,undefined);    }

function __init__()
{
	// INIT BEHAVIORS
	InitSkeletonBehaviorsAndASM();
	
	// INIT BLACKBOARD	
	spawner::add_archetype_spawn_function( "skeleton", &ArchetypeSkeletonBlackboardInit );
	
	// INIT SKELETON ON SPAWN
	spawner::add_archetype_spawn_function( "skeleton", &skeletonSpawnSetup ); 

	if( ai::shouldRegisterClientFieldForArchetype( "skeleton" ) )
	{
		clientfield::register(
			"actor",
			"skeleton",
			1,
			1,
			"int");
	}
}

function skeletonSpawnSetup()
{
	self.zombie_move_speed = "walk";
	if(randomint( 2 ) == 0)
		self.zombie_arms_position = "up";
	else
		self.zombie_arms_position = "down";
	self.missingLegs = false;
	self setAvoidanceMask( "avoid none" );	
	self PushActors( true );

	clientfield::set( "skeleton", true );
}


function private InitSkeletonBehaviorsAndASM()
{
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("skeletonTargetService",&skeletonTargetService);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("skeletonShouldMelee",&skeletonShouldMeleeCondition);;
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("skeletonGibLegsCondition",&skeletonGibLegsCondition);; 
	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("isSkeletonWalking",&isSkeletonWalking);; 

	BehaviorTreeNetworkUtility::RegisterBehaviorTreeScriptAPI("skeletonDeathAction",&skeletonDeathAction);; 
		
	AnimationStateNetwork::RegisterNotetrackHandlerFunction("contact",&skeletonNotetrackMeleeFire);;
}

function private ArchetypeSkeletonBlackboardInit()
{
	// CREATE BLACKBOARD
	Blackboard::CreateBlackBoardForEntity( self );
	
	// USE UTILITY BLACKBOARD
	self AiUtility::RegisterUtilityBlackboardAttributes();
	
	// CREATE SKELETON BLACKBOARD
	Blackboard::RegisterBlackBoardAttribute(self,"_arms_position","arms_up",&BB_GetArmsPosition);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_arms_position");#/    };
	Blackboard::RegisterBlackBoardAttribute(self,"_locomotion_speed","locomotion_speed_walk",&BB_GetLocomotionSpeedType);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_locomotion_speed");#/    };
	Blackboard::RegisterBlackBoardAttribute(self,"_has_legs","has_legs_yes",&BB_GetHasLegsStatus);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_has_legs");#/    };
	Blackboard::RegisterBlackBoardAttribute(self,"_which_board_pull",undefined,undefined);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_which_board_pull");#/    };
	Blackboard::RegisterBlackBoardAttribute(self,"_board_attack_spot",undefined,undefined);   if( IsActor(self) )    {    /#self TrackBlackBoardAttribute("_board_attack_spot");#/    };	
	
	// REGISTER ANIMSCRIPTED CALLBACK
	self.___ArchetypeOnAnimscriptedCallback = &ArchetypeSkeletonOnAnimscriptedCallback;
	
	// ENABLE DEBUGGING IN ODYSSEY
	/#self FinalizeTrackedBlackboardAttributes();#/;
}

function private ArchetypeSkeletonOnAnimscriptedCallback( entity )
{
	// UNREGISTER THE BLACKBOARD
	entity.__blackboard = undefined;
	
	// REREGISTER BLACKBOARD
	entity ArchetypeSkeletonBlackboardInit();
}

// ------- BLACKBOARD -----------//

function BB_GetArmsPosition()
{
	if( IsDefined( self.skeleton_arms_position ) )
	{
		if( self.zombie_arms_position == "up" )
			return "arms_up";
		return "arms_down";
	}
	
	return "arms_up";
}

function BB_GetLocomotionSpeedType()
{
	if ( IsDefined( self.zombie_move_speed ) )
	{
		if( self.zombie_move_speed == "walk" )
		{
			return "locomotion_speed_walk";
		}
		else if( self.zombie_move_speed == "run" )
		{
			return "locomotion_speed_run";
		}
		else if( self.zombie_move_speed == "sprint" )
		{
			return "locomotion_speed_sprint";
		}
		else if( self.zombie_move_speed == "super_sprint" )
		{
			return "locomotion_speed_super_sprint";
		}
	}
	return "locomotion_speed_walk";
}

function BB_GetHasLegsStatus()
{
	if( self.missingLegs )
		return "has_legs_no";
	return "has_legs_yes";
}

// ------- BLACKBOARD -----------//



function isSkeletonWalking( behaviorTreeEntity )
{
	if( !isdefined(behaviorTreeEntity.zombie_move_speed))
		return true;
	return behaviorTreeEntity.zombie_move_speed == "walk" && !( isdefined( behaviorTreeEntity.missingLegs ) && behaviorTreeEntity.missingLegs ) && behaviorTreeEntity.zombie_arms_position == "up";
}

function skeletonGibLegsCondition( behaviorTreeEntity)
{
	return GibServerUtils::IsGibbed( behaviorTreeEntity, 256) || GibServerUtils::IsGibbed( behaviorTreeEntity, 128);
}

function skeletonNotetrackMeleeFire( animationEntity )
{
	hitEnt = animationentity Melee();
	if(isDefined(hitEnt) && isDefined(animationentity.aux_melee_damage) && self.team != hitEnt.team )
	{
		animationentity [[animationentity.aux_melee_damage]](hitEnt);
	}
}

function is_within_fov( start_origin, start_angles, end_origin, fov )
{
	normal = VectorNormalize( end_origin - start_origin ); 
	forward = AnglesToForward( start_angles ); 
	dot = VectorDot( forward, normal ); 

	return dot >= fov; 
}



function skeletonCanSeePlayer( player )
{
	self endon( "death" );

	if(!isDefined(self.players_visCache))
	{
		self.players_visCache = [];
	}
	entNum = player GetEntityNumber();
	if(!isDefined(self.players_visCache[entNum]))
	{
		self.players_visCache[entNum] = 0;
	}
	if (self.players_visCache[entNum] > GetTime() )
	{
		return true;
	}
	
	//zombie_eye = self GetTagOrigin( "tag_eye" );
	zombie_eye = self.origin + ( 0, 0, 40);
	player_pos = player.origin + ( 0, 0, 40);
	
	//as_debug::drawDebugCross( zombie_eye, 5.0, ( 0.0, 0.0, 1.0 ), 1 );
	//as_debug::drawDebugCross( player_pos, 5.0, ( 0.0, 1.0, 1.0 ), 1 );
	
	distanceSq = DistanceSquared( zombie_eye, player_pos );
	
	//Check to see if the skeleton is super close OR super far
	if( distanceSq < 64 * 64 )
	{
		self.players_visCache[entNum] = GetTime() + 3000;
		return true;
	}	
	else if( distanceSq > 1024*1024 )
	{
		return false;
	}	
	
	if( is_within_fov( zombie_eye, self.angles, player_pos, cos(60.0) ) )
	{
		trace = GroundTrace( zombie_eye, player_pos, false, undefined );
	
		if( trace["fraction"] < 1.0 )
		{
			return false;
		}
		else
		{
			//as_debug::debugLine( zombie_eye, player_pos, ( 0.0, 1.0, 1.0 ), 1 );
			self.players_visCache[entNum] = GetTime() + 3000;
			return true;
		}
	}
	return false;
}


function is_player_valid( player, checkIgnoreMeFlag, ignore_laststand_players )
{
	if( !IsDefined( player ) ) 
	{
		return false; 
	}

	if( !IsAlive( player ) )
	{
		return false; 
	} 

	if( !IsPlayer( player ) )
	{
		return false;
	}

	if( IsDefined(player.is_zombie) && player.is_zombie == true )
	{
		return false; 
	}

	if( player.sessionstate == "spectator" )
	{
		return false; 
	}

	if( player.sessionstate == "intermission" )
	{
		return false; 
	}
	
	if( ( isdefined( self.intermission ) && self.intermission ) )
	{
		return false;
	}
	
	if(!( isdefined( ignore_laststand_players ) && ignore_laststand_players ))
	{
		if(  player laststand::player_is_in_laststand() )
		{
			return false; 
		}
	}

//T6.5todo	if ( player isnotarget() )
//T6.5todo	{
//T6.5todo		return false;
//T6.5todo	}
	
	//We only want to check this from the zombie attack script
	if( ( isdefined( checkIgnoreMeFlag ) && checkIgnoreMeFlag ) && player.ignoreme )
	{
		return false;
	}
	
	//for additional level specific checks
	if( IsDefined( level.is_player_valid_override ) )
	{
		return [[ level.is_player_valid_override ]]( player );
	}
	
	return true; 
}

function get_closest_valid_player( origin, ignore_player )
{
	valid_player_found = false; 
	
	players = GetPlayers();	

	if( IsDefined( ignore_player ) )
	{
		//PI_CHANGE_BEGIN - 7/2/2009 JV Reenabling change 274916 (from DLC3)
		for(i = 0; i < ignore_player.size; i++ )
		{
			ArrayRemoveValue( players, ignore_player[i] );
		}
		//PI_CHANGE_END
	}

	// pre-cull any players that are in last stand 
	done = false; 
	while ( players.size && !done )
	{
		done = true;
		for(i = 0; i < players.size; i++ )
		{
			player = players[i];
			if( !is_player_valid( player, true ) )
			{
				ArrayRemoveValue( players, player ); 
				done = false;
				break;
			}
		}
	}
	
	if( players.size == 0 )
	{
		return undefined; 
	}
	
	while( !valid_player_found )
	{
		// find the closest player
		if( IsDefined( self.closest_player_override ) )
		{
			player = [[ self.closest_player_override ]]( origin, players );
		}
		else if( isdefined( level.closest_player_override ) )
		{
			player = [[ level.closest_player_override ]]( origin, players );
		}
		else
		{
			player = ArrayGetClosest( origin, players );
		} 

		if( !isdefined( player ) || players.size == 0 )
		{
			return undefined; 
		}
		
		// make sure they're not a zombie or in last stand
		if( !is_player_valid( player, true ) )
		{
			// unlikely to get here unless there is a wait in one of the closest player overrides
			ArrayRemoveValue( players, player ); 
			if( players.size == 0 )
			{
				return undefined;
			}
		
			continue;
		}
		
		return player; 
	}
}


function skeletonSetGoal(goal)
{
	if(isDefined(self.setGoalOverrideCB))
	{
		return [[self.setGoalOverrideCB]](goal);
	}
	else
	{
		self SetGoal(goal);
	}
}
function skeletonTargetService( behaviorTreeEntity)
{

	self endon( "death" );
	
	if ( ( isdefined( behaviorTreeEntity.ignoreall ) && behaviorTreeEntity.ignoreall ) )
	{
		return false;
	}
	if(isDefined(behaviorTreeEntity.enemy) && behaviorTreeEntity.enemy.team == behaviorTreeEntity.team )
		behaviorTreeEntity ClearEntityTarget();
	
	if(behaviorTreeEntity.team == "allies")
	{
		if(isDefined(behaviorTreeEntity.favoriteenemy))
		{
			behaviorTreeEntity skeletonSetGoal( behaviorTreeEntity.favoriteenemy.origin );	
			return true;			
		}
		if(isDefined(behaviorTreeEntity.enemy))
		{
			behaviorTreeEntity skeletonSetGoal( behaviorTreeEntity.enemy.origin );	
			return true;			
		}
		target = getClosestToMe(GetAITeamArray( "axis" ));
		if(isDefined(target))
		{
			behaviorTreeEntity skeletonSetGoal( target.origin );		
			return true;
		}
		else
		{
			behaviorTreeEntity skeletonSetGoal( behaviorTreeEntity.origin );		
			return false;
		}
	}
	else
	{
	
		player = get_closest_valid_player( behaviorTreeEntity.origin, behaviorTreeEntity.ignore_player );
		
		if( !isDefined( player ) )
		{
			if( IsDefined( behaviorTreeEntity.ignore_player )  )
			{
				if(isDefined(level._should_skip_ignore_player_logic) && [[level._should_skip_ignore_player_logic]]() )
				{
					return;
				}
				behaviorTreeEntity.ignore_player = [];
			}
		
			behaviorTreeEntity skeletonSetGoal( behaviorTreeEntity.origin );		
			return false;
		}
		else
		{
			if ( IsDefined( player.last_valid_position ) )
			{
				canSEE = self skeletonCanSeePlayer( player );
			
				//Fill in influence map
				if( canSEE )
				{
					//self SetInfluenceAt( 5, player.last_valid_position, 1.0 );
					behaviorTreeEntity skeletonSetGoal( player.last_valid_position );		
					//as_debug::drawDebugCross( player.last_valid_position, 5.0, ( 0.0, 1.0, 0.0 ), 5 );
					return true;
				}
				else
				{
					influencePos = undefined;
					//try to find player - get hottest point on influence map and go there
					//influencePos = self GetBestInfluencepos( 5, 0.01, 1.0 );
					
					if( isdefined(influencePos) )
					{
						//as_debug::drawDebugCross( influencePos, 5.0, ( 1.0, 0.0, 0.0 ), 5 );
						
						//Are we close to our goal?
						if( DistanceSquared( influencePos, behaviorTreeEntity.origin ) > 32*32 )
						{
							behaviorTreeEntity skeletonSetGoal( influencePos );
							return true;
						}
						//self SetGoal( self.origin );	
						behaviorTreeEntity ClearPath();
						return false;
					}
					else
					{
						//self SetGoal( self.origin );		
						behaviorTreeEntity ClearPath();
						return false;
					}
				}
	
				/*attackPlayer = false;
				if( DistanceSquared( player.last_valid_position, self.origin ) < (512*512) )
				{
					if( canSEE )
					{
						behaviorTreeEntity SetGoal( player.last_valid_position );		
						attackPlayer = true;
					}
				}		
				
				if( !attackPlayer )
				{	
					//Get hottest point on influence map and go there
					influencePos = self GetBestInfluencepos( 5, 0.01, 1.0 );
					if( isdefined(influencePos) )
					{
						as_debug::drawDebugCross( influencePos, 5.0, ( 1.0, 0.0, 0.0 ), 5 );
						self SetGoal( influencePos );		
						return true;
					}
					else
					{
						self SetGoal( self.origin );		
						return false;
					}
				}*/
				return true;
			}
			else
			{
				behaviorTreeEntity skeletonSetGoal( behaviorTreeEntity.origin );
				return false;
			}
		}
	}
}

function isValidEnemy( enemy )
{
	if ( !isdefined( enemy ) )
	{
		return false;
	}
	
	return true;
}

function GetYaw(org)
{
	angles = VectorToAngles(org-self.origin);
	return angles[1];
}

// warning! returns (my yaw - yaw to enemy) instead of (yaw to enemy - my yaw)
function GetYawToEnemy()
{
	pos = undefined;
	if ( isValidEnemy( self.enemy ) )
	{
		pos = self.enemy.origin;
	}
	else
	{
		forward = AnglesToForward(self.angles);
		forward = VectorScale (forward, 150);
		pos = self.origin + forward;
	}
	
	yaw = self.angles[1] - GetYaw(pos);
	yaw = AngleClamp180( yaw );
	return yaw;
}

function skeletonShouldMeleeCondition( behaviorTreeEntity )
{
	if( !IsDefined( behaviortreeentity.enemy ) )
    {
		return false;
	}

	if( IsDefined( behaviorTreeEntity.marked_for_death ) )
	{
		return false;
	}
	
	if( ( isdefined( behaviorTreeEntity.stunned ) && behaviorTreeEntity.stunned ) )
	{
		return false;
	}
	
	yaw = abs( getYawToEnemy() );
	if( ( yaw > 45 ) )
	{
		return false;
	}
	if( DistanceSquared( behaviorTreeEntity.origin, behaviorTreeEntity.enemy.origin ) < 64 * 64 )
	{
		return true;
	}
	
	return false;
}

function skeletonDeathAction( behaviorTreeEntity )
{
	if ( IsDefined( behaviorTreeEntity.deathFunction ) )
	{
		behaviorTreeEntity [[ behaviorTreeEntity.deathFunction ]]();
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getClosestTo(origin,entArray)
{
	if (!isDefined(entArray) )
		return;

	if (entArray.size == 0 )
		return;

	return ArrayGetClosest( origin, entArray );
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getClosestToMe(entArray)
{
	return getClosestTo(self.origin,entArray);
}