// This script contains functionality to allow covert op to steal uniforms from corpses.

// Usage: 

// TODO:

// The null check is just in case the script is executed multiple times
if(ScriptGoals.disguise_goal == null)
{
	// For cleanliness, we're going to store all our functions and variables inside a table,
	// within the ScriptGoals global table.
	// The ScriptGoals is a global table created by the bot by default, as a standardized storage location
	// for goals implemented in script. Script goals should make their own table under the ScriptGoals global table.

	ScriptGoals.disguise_goal = table();
	
	// The name for this goal
	ScriptGoals.disguise_goal.Name = "steal_uniform";
	
	// A debug flag for enabling/disabling printed messages. Useful for debugging this goal.
	ScriptGoals.disguise_goal.Debug = false;
		
	// We'll store the goal check delay for the thread function here, just to put most of the
	// configuration options neatly at the top of the script for readability.
	ScriptGoals.disguise_goal.ThreadCheckDelay = 2;
	
	// This function just holds the functionality to search a corpse table for the closest one.
	// It returns a gameentity
	ScriptGoals.disguise_goal.LookForClosestCorpse = function( _bot )
	{		
		// Get a table containing all players and corpses.
		corpseList = table();
		_bot.GetAllType( CAT.PLAYER, 0, corpseList );
		_bot.GetAllType( CAT.MISC, CLASS.CORPSE, corpseList );
		
		// Some debug messages
		if( ScriptGoals.disguise_goal.Debug )
		{
			//print("tableCount(corpseList) before health check", tableCount(corpseList));					
		}
		
		botPos = _bot.GetPosition();
		
		nearestCorpse = null;
		nearestCorpseDist = 10000;
		
		// Filter out all players that are alive, or on the other team.
		foreach ( index and entity in corpseList )
		{
			if( ScriptGoals.disguise_goal.Debug )
			{
				DrawEntityAABB ( entity, COLOR.RED );
			}
						
			// What's my current health/armor.
			healthArmorTable = GetEntHealthAndArmor( entity );	
			
			corpseFlags = GetEntFlags( entity );
			
			// Skip invalid corpses.
			if( ( healthArmorTable.CurrentHealth <= 0 ) && 
				!( corpseFlags & ENTFLAG.DISABLED ) &&
				!_bot.IsAllied( entity ) )
			{
				entPos = GetEntPosition( entity );
			
				distSq = (entPos - botPos).LengthSq();
				if( nearestCorpse == null || distSq < nearestCorpseDist )
				{
					nearestCorpse = entity;
					nearestCorpseDist = distSq;					
				}
			}
		}
		
		// Some debug messages
		if( ScriptGoals.disguise_goal.Debug )
		{
			//print("tableCount(corpseList) after health check", tableCount(corpseList));					
		}
		
		return nearestCorpse;
	};
	
	// This function should be called when the goal is finished so that it can do cleanup.
	ScriptGoals.disguise_goal.LookForDisguiseGoalThread = function()
	{
		// The loop condition can check the class, so if the bot changes class this script goal will end cleanly.
		while( this.GetClass() == CLASS.COVERTOPS )
		{
			// Some debug messages
			if( ScriptGoals.disguise_goal.Debug )
			{
				print("ScriptGoals.disguise_goal");
			}
			
			// Check if this bot is already disguised. If so, we can skip a big section of this code.
			// Entity flags is an integer value where each bit represents a true/false property.
			// The global table ENTFLAG contains all the available bit enumerations.
			botEntFlags = GetEntFlags( this.GetGameEntity() );
			if( !(botEntFlags & ENTFLAG.DISGUISED) && !(botEntFlags & ENTFLAG.CARRYINGGOAL) )
			{
				// Look for a corpse we can steal a uniform from.
				nearestCorpse = ScriptGoals.disguise_goal.LookForClosestCorpse( this );
				
				if( nearestCorpse != null )
				{	
					// Some debug messages
					if( ScriptGoals.disguise_goal.Debug )
					{
						print("Heading to a corpse.", nearestCorpse);
					}
					
					// Set a script goal for this function, so other script goals can not attempt to
					// take control.
					this.scriptgoal = ScriptGoals.disguise_goal.Name;
					
					// Go to the goal.
					corpsePosition = GetEntPosition( nearestCorpse );
					
					this.SetScriptControlled( true );
					this.GoTo( corpsePosition );					
					if( block(EVENT.GOAL_SUCCESS, EVENT.GOAL_FAILED) == EVENT.GOAL_SUCCESS )
					{
						// Some debug messages
						if( ScriptGoals.disguise_goal.Debug )
						{
							print("Attempting to steal uniform.", nearestCorpse);
						}
						
						// Take control of the weapons now.
						this.SetScriptControlledWeapons( true );
						
						// Keep doing this until we're disguised							
						while ( !(botEntFlags & ENTFLAG.DISGUISED) && !(botEntFlags & ENTFLAG.CARRYINGGOAL)  )
						{
							if( ScriptGoals.disguise_goal.Debug )
							{
								DrawEntityAABB ( nearestCorpse, COLOR.RED );
							}							
						
							this.MoveTowards( corpsePosition );								
							this.TurnToPosition( corpsePosition );
						
							this.PressButton( BTN.USE );
						
							// Get our flags again to compare in the loop condition.
							botEntFlags = GetEntFlags( this.GetGameEntity() );
							yield();
						}
						
						if(botEntFlags & ENTFLAG.DISGUISED)
						{
							// Some debug messages
							if( ScriptGoals.disguise_goal.Debug )
							{
								print("Stole uniform.");
							}
						}							
					}
					
					// Null the script goal, so other script goals can possibly use this bot.
					this.scriptgoal = null;
					this.SetScriptControlledWeapons( false );
					this.SetScriptControlled( false );								
				}
			}
			else
			{
				// We are disguised, so do whatever.
			}
			
			sleep( ScriptGoals.disguise_goal.ThreadCheckDelay );
		}
		
		// Clear the goal on the way out.
		if( this.scriptgoal == ScriptGoals.disguise_goal.Name )
		{
			this.scriptgoal = null;
		}		
	};	
}
