abstract class AIActionHelperTask extends AIbehaviortaskScript
{
	editable inlined var m_actionTweakIDMapping : AIArgumentMapping;
	private var m_actionStringName : String;
	private var m_initialized : Bool;
	private var m_actionName : CName;
	private var m_actionID : TweakDBID;

	private function GetActionStringName( context : ScriptExecutionContext ) : String
	{
		var actionTweakID : String;
		if( m_actionTweakIDMapping )
		{
			actionTweakID = NameToString( ( ( CName )( ScriptExecutionContext.GetMappingValue( context, m_actionTweakIDMapping ) ) ) );
		}
		return actionTweakID;
	}

	private constexpr function GetActionPackageType() : AIactionParamsPackageTypes
	{
		return AIactionParamsPackageTypes.Default;
	}

	protected function Initialize( context : ScriptExecutionContext )
	{
		var actionName : CName;
		if( m_initialized )
		{
			return;
		}
		m_actionID = AIActionParams.CreateActionID( context, GetPuppet( context ), GetActionStringName( context ), GetActionPackageType(), actionName );
		m_initialized = true;
	}

	protected function GetActionID() : TweakDBID
	{
		return m_actionID;
	}

}

class DestroyWeakspot extends AIActionHelperTask
{
	editable inlined var m_weakspotIndex : Int32;
	var m_weakspotComponent : WeakspotComponent;
	var m_weakspotArray : array< weak< WeakspotObject > >;

	protected override function Activate( context : ScriptExecutionContext )
	{
		m_weakspotComponent = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetWeakspotComponent();
		m_weakspotComponent.GetWeakspots( m_weakspotArray );
		DestroyWeakspot( context, m_weakspotArray, m_weakspotIndex );
	}

	protected function DestroyWeakspot( context : ScriptExecutionContext, const weakspots : ref< array< weak< WeakspotObject > > >, index : Int32 )
	{
		GameInstance.GetStatPoolsSystem( GetGame( context ) ).RequestSettingStatPoolValue( weakspots[ index ].GetEntityID(), gamedataStatPoolType.WeakspotHealth, 0.0, NULL, true );
	}

}

class SetAppearance extends AIActionHelperTask
{
	editable inlined var m_appearance : CName;

	protected override function Activate( context : ScriptExecutionContext )
	{
		ApplyAppearance( context, m_appearance );
	}

	protected function ApplyAppearance( context : ScriptExecutionContext, appearance : CName )
	{
		if( !( IsNameValid( appearance ) ) )
		{
			return;
		}
		ScriptExecutionContext.GetOwner( context ).ScheduleAppearanceChange( m_appearance );
	}

}

class MonitorMeleeCombo extends AIActionHelperTask
{
	editable var ExitComboBoolArgumentRef : CName;
	editable var PreviousReactionIntArgumentRef : CName;
	editable var CurrentAttackIntArgumentRef : CName;
	editable var ComboCountIntArgumentRef : CName;
	editable var ComboToIdleBoolArgumentRef : CName;

	protected override function Deactivate( context : ScriptExecutionContext )
	{
		ScriptExecutionContext.SetArgumentBool( context, ExitComboBoolArgumentRef, false );
		ScriptExecutionContext.SetArgumentInt( context, PreviousReactionIntArgumentRef, 0 );
		ScriptExecutionContext.SetArgumentInt( context, CurrentAttackIntArgumentRef, 0 );
		ScriptExecutionContext.SetArgumentInt( context, ComboCountIntArgumentRef, 0 );
		ScriptExecutionContext.SetArgumentBool( context, ComboToIdleBoolArgumentRef, false );
	}

}

class SetDestinationWaypoint extends AIActionHelperTask
{
	editable var m_refTargetType : EAITargetType;
	editable inlined var m_findClosest : Bool;
	editable inlined var m_waypointsName : CName;
	private var m_destinations : array< Vector4 >;
	private var m_finalDestinations : array< Vector4 >;

	protected override function Activate( context : ScriptExecutionContext )
	{
		GameInstance.FindWaypointsByTag( ScriptExecutionContext.GetOwner( context ).GetGame(), m_waypointsName, m_destinations );
		GetPuppet( context ).GetAIControllerComponent().SetBehaviorArgument( 'MovementTarget', GetFinalDestination( context ) );
	}

	protected function GetFinalDestination( context : ScriptExecutionContext ) : Vector4
	{
		var value : Vector4;
		var randomInt : Int32;
		var closestWPToTarget : Int32;
		var closestWPToOwner : Int32;
		m_finalDestinations = m_destinations;
		closestWPToOwner = GetLowestDistanceIndex( GetDistances( ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) );
		closestWPToTarget = GetLowestDistanceIndex( GetDistances( GetCombatTarget( context ).GetWorldPosition() ) );
		if( !( m_findClosest ) )
		{
			if( m_refTargetType == EAITargetType.AITT_Owner )
			{
				if( closestWPToOwner == closestWPToTarget )
				{
					m_finalDestinations.Erase( GetLowestDistanceIndex( GetDistances( ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) ) );
				}
				else
				{
					m_finalDestinations.Erase( GetLowestDistanceIndex( GetDistances( ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) ) );
					m_destinations.Erase( GetLowestDistanceIndex( GetDistances( ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) ) );
					m_finalDestinations.Erase( GetLowestDistanceIndex( GetDistances( GetCombatTarget( context ).GetWorldPosition() ) ) );
				}
			}
			else if( m_refTargetType == EAITargetType.AITT_CombatTarget )
			{
				m_finalDestinations.Erase( GetLowestDistanceIndex( GetDistances( GetCombatTarget( context ).GetWorldPosition() ) ) );
			}
			randomInt = RandRange( 0, m_finalDestinations.Size() );
			value = m_finalDestinations[ randomInt ];
		}
		else if( m_findClosest )
		{
			if( m_refTargetType == EAITargetType.AITT_Owner )
			{
				value = m_finalDestinations[ GetLowestDistanceIndex( GetDistances( ScriptExecutionContext.GetOwner( context ).GetWorldPosition() ) ) ];
			}
			else if( m_refTargetType == EAITargetType.AITT_CombatTarget )
			{
				value = m_finalDestinations[ GetLowestDistanceIndex( GetDistances( GetCombatTarget( context ).GetWorldPosition() ) ) ];
			}
		}
		return value;
	}

	protected function GetLowestDistanceIndex( const distances : ref< array< Float > > ) : Int32
	{
		var lowestValue : Float;
		var j, k : Int32;
		for( j = 0; j < distances.Size(); j += 1 )
		{
			if( ( distances[ j ] < lowestValue ) || ( lowestValue == 0.0 ) )
			{
				lowestValue = distances[ j ];
				k = j;
			}
		}
		return k;
	}

	protected function GetDistances( refVector : Vector4 ) : array< Float >
	{
		var distances : array< Float >;
		var i : Int32;
		distances.Clear();
		distances.Resize( m_destinations.Size() );
		for( i = 0; i < m_destinations.Size(); i += 1 )
		{
			distances[ i ] = Vector4.Distance( refVector, m_destinations[ i ] );
		}
		return distances;
	}

}

class KillEntity extends AIActionHelperTask
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		var forcedDeathEvent : ForcedDeathEvent;
		forcedDeathEvent = new ForcedDeathEvent;
		forcedDeathEvent.hitIntensity = 1;
		forcedDeathEvent.hitSource = 1;
		forcedDeathEvent.hitType = 7;
		forcedDeathEvent.hitBodyPart = 1;
		forcedDeathEvent.hitNpcMovementSpeed = 0;
		forcedDeathEvent.hitDirection = 4;
		forcedDeathEvent.hitNpcMovementDirection = 0;
		ScriptExecutionContext.GetOwner( context ).QueueEvent( forcedDeathEvent );
	}

}

class SetPhaseState extends AIActionHelperTask
{
	editable var m_phaseStateValue : ENPCPhaseState;

	protected override function Activate( context : ScriptExecutionContext )
	{
		ScriptExecutionContext.GetOwner( context ).GetBlackboard().SetInt( GetAllBlackboardDefs().PuppetState.PhaseState, ( ( Int32 )( m_phaseStateValue ) ) );
	}

}

class CheckPhaseState extends AIbehaviorconditionScript
{
	editable var m_phaseStateValue : ENPCPhaseState;

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		if( ScriptExecutionContext.GetOwner( context ).GetBlackboard().GetInt( GetAllBlackboardDefs().PuppetState.PhaseState ) == ( ( Int32 )( m_phaseStateValue ) ) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

}

class CheckPathToCombatTarget extends AIbehaviorconditionScript
{
	var path : NavigationPath;

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		path = GameInstance.GetAINavigationSystem( GetGame( context ) ).CalculatePathForCharacter( ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), GetCombatTarget( context ).GetWorldPosition(), 0.5, ScriptExecutionContext.GetOwner( context ) );
		if( path != NULL )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

}

class CheckFloatIsValid extends AIbehaviorconditionScript
{
	editable inlined var actionTweakIDMapping : AIArgumentMapping;
	var value : Float;

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		if( actionTweakIDMapping )
		{
			value = ( ( Float )( ScriptExecutionContext.GetMappingValue( context, actionTweakIDMapping ) ) );
			if( value <= 0.0 )
			{
				return false;
			}
		}
		return true;
	}

}

class CheckBoolisValid extends AIbehaviorconditionScript
{
	editable inlined var actionTweakIDMapping : AIArgumentMapping;

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		var value : Bool;
		if( actionTweakIDMapping )
		{
			value = ( ( Bool )( ScriptExecutionContext.GetMappingValue( context, actionTweakIDMapping ) ) );
			if( value == false )
			{
				return false;
			}
		}
		return true;
	}

}

class CheckVectorIsValid extends AIbehaviorconditionScript
{
	editable inlined var actionTweakIDMapping : AIArgumentMapping;
	var value : Vector4;

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		if( actionTweakIDMapping )
		{
			value = ( ( Vector4 )( ScriptExecutionContext.GetMappingValue( context, actionTweakIDMapping ) ) );
			if( Vector4.IsZero( value ) )
			{
				return false;
			}
		}
		return true;
	}

}

class CheckGameDifficulty extends AIbehaviorconditionScript
{
	editable var m_comparedDifficulty : gameDifficulty;
	editable var m_comparisonOperator : EComparisonOperator;
	var currentDifficulty : gameDifficulty;
	var currentDifficultyValue : Int32;
	var comparedDifficultyValue : Int32;

	protected export override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		currentDifficulty = GameInstance.GetStatsDataSystem( GetGame( context ) ).GetDifficulty();
		currentDifficultyValue = GetDifficultyValue( currentDifficulty );
		comparedDifficultyValue = GetDifficultyValue( m_comparedDifficulty );
		if( ( currentDifficultyValue > 0 ) && ( comparedDifficultyValue > 0 ) )
		{
			switch( m_comparisonOperator )
			{
				case EComparisonOperator.Equal:
					if( currentDifficultyValue == comparedDifficultyValue )
					{
						return true;
					}
				break;
				case EComparisonOperator.NotEqual:
					if( currentDifficultyValue != comparedDifficultyValue )
					{
						return true;
					}
				break;
				case EComparisonOperator.More:
					if( currentDifficultyValue > comparedDifficultyValue )
					{
						return true;
					}
				break;
				case EComparisonOperator.MoreOrEqual:
					if( currentDifficultyValue >= comparedDifficultyValue )
					{
						return true;
					}
				break;
				case EComparisonOperator.Less:
					if( currentDifficultyValue < comparedDifficultyValue )
					{
						return true;
					}
				break;
				case EComparisonOperator.LessOrEqual:
					if( currentDifficultyValue <= comparedDifficultyValue )
					{
						return true;
					}
				break;
				default:
					return false;
			}
			return false;
		}
		else
		{
			return false;
		}
	}

	private function GetDifficultyValue( difficulty : gameDifficulty ) : Int32
	{
		switch( difficulty )
		{
			case gameDifficulty.Story:
				return 1;
			case gameDifficulty.Easy:
				return 2;
			case gameDifficulty.Hard:
				return 3;
			case gameDifficulty.VeryHard:
				return 4;
			default:
				return 0;
		}
	}

}

