class FindClosestScavengeTarget extends AIbehaviortaskScript
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		var owner : NPCPuppet;
		var scavengeComponent : ScavengeComponent;
		var scavengeTargets : array< weak< GameObject > >;
		var closestTarget : weak< GameObject >;
		owner = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		scavengeComponent = owner.GetScavengeComponent();
		scavengeTargets = scavengeComponent.GetScavengeTargets();
		closestTarget = GetClosestTarget( context, scavengeTargets );
		ScriptExecutionContext.SetArgumentObject( context, 'ScavengeTarget', closestTarget );
		ScriptExecutionContext.SetArgumentVector( context, 'ScavengeTargetPos', Vector4( 0.0, 0.0, 0.0, 0.0 ) );
	}

	private function GetClosestTarget( context : ScriptExecutionContext, const targets : ref< array< weak< GameObject > > > ) : weak< GameObject >
	{
		var i : Int32;
		var currentTargetDistance : Float;
		var shortestDistance : Float;
		var closestTarget : weak< GameObject >;
		for( i = 0; i < targets.Size(); i += 1 )
		{
			currentTargetDistance = Vector4.Distance( ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), targets[ i ].GetWorldPosition() );
			if( ( currentTargetDistance < shortestDistance ) || ( shortestDistance == 0.0 ) )
			{
				shortestDistance = currentTargetDistance;
				closestTarget = targets[ i ];
			}
		}
		return closestTarget;
	}

}

class MoveToScavengeTarget extends AIbehaviortaskScript
{
	private var m_lastTime : Float;
	default m_lastTime = -1.f;
	private var m_timeout : Float;
	private var m_timeoutDuration : Float;
	default m_timeoutDuration = 0.1f;

	protected override function Activate( context : ScriptExecutionContext )
	{
		m_timeout = m_timeoutDuration;
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var scavengeTarget : weak< GameObject >;
		var changeDestinationEvent : gameChangeDestination;
		var actionEvent : ActionEvent;
		var dt : Float;
		if( m_lastTime < 0.0 )
		{
			m_lastTime = EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) );
		}
		dt = EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) - m_lastTime;
		m_lastTime = EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) );
		m_timeout -= dt;
		if( m_timeout > 0.0 )
		{
			return AIbehaviorUpdateOutcome.IN_PROGRESS;
		}
		m_timeout = m_timeoutDuration;
		scavengeTarget = ScriptExecutionContext.GetArgumentObject( context, 'ScavengeTarget' );
		ScriptExecutionContext.SetArgumentVector( context, 'ScavengeTargetPos', scavengeTarget.GetWorldPosition() );
		changeDestinationEvent = new gameChangeDestination;
		changeDestinationEvent.destination = scavengeTarget.GetWorldPosition();
		actionEvent = new ActionEvent;
		actionEvent.name = 'actionEvent';
		actionEvent.internalEvent = ( ( ActionInternalEvent )( changeDestinationEvent ) );
		ScriptExecutionContext.GetOwner( context ).QueueEvent( actionEvent );
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	protected override function Deactivate( context : ScriptExecutionContext )
	{
		m_lastTime = -1.0;
		m_timeout = m_timeoutDuration;
	}

}

class ScavengeTarget extends AIbehaviortaskScript
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		var scavengeTarget : weak< GameObject >;
		var targetDisassembleEvent : DisassembleEvent;
		scavengeTarget = ScriptExecutionContext.GetArgumentObject( context, 'ScavengeTarget' );
		targetDisassembleEvent = new DisassembleEvent;
		scavengeTarget.QueueEvent( targetDisassembleEvent );
	}

}

class HaveScavengeTargets extends AIbehaviorconditionScript
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 1.0 ) );
	}

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		var owner : NPCPuppet;
		var scavengeComponent : ScavengeComponent;
		var scavengeTargets : array< weak< GameObject > >;
		owner = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		scavengeComponent = owner.GetScavengeComponent();
		scavengeTargets = scavengeComponent.GetScavengeTargets();
		return scavengeTargets.Size() > 0;
	}

}

class AITakedownHandler extends AIbehaviortaskScript
{
	editable inlined var m_inCommand : AIArgumentMapping;

	protected override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var rawCommand : IScriptable;
		var takedownCommand : AIFollowerTakedownCommand;
		if( !( m_inCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		rawCommand = ScriptExecutionContext.GetScriptableMappingValue( context, m_inCommand );
		takedownCommand = ( ( AIFollowerTakedownCommand )( rawCommand ) );
		if( !( takedownCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( takedownCommand.target ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( ScriptExecutionContext.GetArgumentObject( context, 'TakedownTarget' ) != takedownCommand.target )
		{
			ScriptExecutionContext.SetArgumentObject( context, 'TakedownTarget', takedownCommand.target );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	private override final function Deactivate( context : ScriptExecutionContext )
	{
		var rawCommand : IScriptable;
		var takedownCommand : AIFollowerTakedownCommand;
		var aiComponent : AIHumanComponent;
		rawCommand = ScriptExecutionContext.GetScriptableMappingValue( context, m_inCommand );
		takedownCommand = ( ( AIFollowerTakedownCommand )( rawCommand ) );
		aiComponent = GetPuppet( context ).GetAIControllerComponent();
		if( takedownCommand )
		{
			aiComponent.StopExecutingCommand( takedownCommand, true );
		}
		ScriptExecutionContext.SetMappingValue( context, m_inCommand, NULL );
	}

}

class AICommandDeviceHandler extends AIbehaviortaskScript
{
	editable inlined var m_inCommand : AIArgumentMapping;

	protected override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var rawCommand : IScriptable;
		var deviceCommand : AIFollowerDeviceCommand;
		if( !( m_inCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		rawCommand = ScriptExecutionContext.GetScriptableMappingValue( context, m_inCommand );
		deviceCommand = ( ( AIFollowerDeviceCommand )( rawCommand ) );
		if( !( deviceCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( deviceCommand.target ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( ScriptExecutionContext.GetArgumentObject( context, 'Target' ) != deviceCommand.target )
		{
			ScriptExecutionContext.SetArgumentObject( context, 'Target', deviceCommand.target );
		}
		if( ( deviceCommand.overrideMovementTarget != NULL ) && ( ScriptExecutionContext.GetArgumentObject( context, 'MovementTarget' ) != deviceCommand.overrideMovementTarget ) )
		{
			ScriptExecutionContext.SetArgumentObject( context, 'MovementTarget', deviceCommand.overrideMovementTarget );
		}
		else if( deviceCommand.overrideMovementTarget == NULL )
		{
			ScriptExecutionContext.SetArgumentObject( context, 'MovementTarget', deviceCommand.target );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

}

class AISetSoloModeHandler extends AIbehaviortaskScript
{
	editable inlined var m_inCommand : AIArgumentMapping;

	protected override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var rawCommand : IScriptable;
		var soloModeCommand : AIFlatheadSetSoloModeCommand;
		if( !( m_inCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		rawCommand = ScriptExecutionContext.GetScriptableMappingValue( context, m_inCommand );
		soloModeCommand = ( ( AIFlatheadSetSoloModeCommand )( rawCommand ) );
		if( !( soloModeCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		ScriptExecutionContext.SetArgumentBool( context, 'SoloMode', soloModeCommand.soloModeState );
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	private override final function Deactivate( context : ScriptExecutionContext )
	{
		ScriptExecutionContext.SetMappingValue( context, m_inCommand, NULL );
	}

}

class IsCombatModuleEquipped extends AIAutonomousConditions
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		var owner : NPCPuppet;
		owner = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		return GameInstance.GetStatsSystem( owner.GetGame() ).GetStatBoolValue( owner.GetEntityID(), gamedataStatType.CanPickUpWeapon );
	}

}

class AIPrepareTakedownData extends AIbehaviortaskScript
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		TakedownGameEffectHelper.FillTakedownData( GetPuppet( context ), GetPuppet( context ), ScriptExecutionContext.GetArgumentObject( context, 'TakedownTarget' ), 'takedowns', 'kill' );
	}

}

class AIDeviceFeedbackData extends AIbehaviortaskScript
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		ScriptExecutionContext.GetArgumentObject( context, 'Target' ).QueueEvent( new SpiderbotOrderCompletedEvent );
	}

}

class AIFindForwardPositionAround extends AIbehaviortaskScript
{

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var angleStep : Float;
		var angle : Float;
		var angleRad : Float;
		var orientation : Quaternion;
		var quat : Quaternion;
		var findWallEndPos : Vector4;
		var fw : NavigationFindWallResult;
		angleStep = 30.0;
		orientation = ScriptExecutionContext.GetOwner( context ).GetWorldOrientation();
		for( angle = 0.0; angle < 360.0; angle += angleStep )
		{
			Quaternion.SetIdentity( quat );
			angleRad = Deg2Rad( angle );
			Quaternion.SetZRot( quat, angleRad );
			quat = orientation * quat;
			findWallEndPos = ScriptExecutionContext.GetOwner( context ).GetWorldPosition() + ( Quaternion.GetForward( quat ) * 1.0 );
			fw = GameInstance.GetAINavigationSystem( GetGame( context ) ).FindWallInLineForCharacter( ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), findWallEndPos, 0.2, ScriptExecutionContext.GetOwner( context ) );
			if( fw.status == worldNavigationRequestStatus.OK && !( fw.isHit ) )
			{
				ScriptExecutionContext.SetArgumentVector( context, 'ForwardPosition', findWallEndPos );
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
		}
		if( fw.status != worldNavigationRequestStatus.OK )
		{
			ScriptExecutionContext.SetArgumentVector( context, 'ForwardPosition', ScriptExecutionContext.GetOwner( context ).GetWorldPosition() );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

}

class AIFindPositionAroundSelf extends AIbehaviortaskScript
{
	editable inlined var m_distanceMin : AIArgumentMapping;
	editable inlined var m_distanceMax : AIArgumentMapping;
	editable inlined var m_angle : Float;
	editable inlined var m_angleOffset : Float;
	editable inlined var m_outPositionArgument : AIArgumentMapping;
	protected var m_finalPosition : Vector4;

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var currentAngle : Float;
		var initialAngle : Float;
		var angleRad : Float;
		var orientation : Quaternion;
		var quat : Quaternion;
		var fw : NavigationFindWallResult;
		var i : Int32;
		var distance : Float;
		orientation = ScriptExecutionContext.GetOwner( context ).GetWorldOrientation();
		initialAngle = m_angleOffset - ( m_angle / 2.0 );
		for( i = 0; i < 5; i += 1 )
		{
			currentAngle = RandRangeF( initialAngle, initialAngle + m_angle );
			Quaternion.SetIdentity( quat );
			angleRad = Deg2Rad( currentAngle );
			Quaternion.SetZRot( quat, angleRad );
			quat = orientation * quat;
			distance = RandRangeF( ( ( Float )( ScriptExecutionContext.GetMappingValue( context, m_distanceMin ) ) ), ( ( Float )( ScriptExecutionContext.GetMappingValue( context, m_distanceMax ) ) ) );
			m_finalPosition = ScriptExecutionContext.GetOwner( context ).GetWorldPosition() + ( Quaternion.GetForward( quat ) * distance );
			fw = GameInstance.GetAINavigationSystem( GetGame( context ) ).FindWallInLineForCharacter( ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), m_finalPosition, 0.2, ScriptExecutionContext.GetOwner( context ) );
			if( ( fw.status == worldNavigationRequestStatus.OK && !( fw.isHit ) ) && AdditionalOutcomeVerification( context ) )
			{
				ScriptExecutionContext.SetMappingValue( context, m_outPositionArgument, m_finalPosition );
				return AIbehaviorUpdateOutcome.SUCCESS;
			}
		}
		return AIbehaviorUpdateOutcome.FAILURE;
	}

	protected virtual function AdditionalOutcomeVerification( context : ScriptExecutionContext ) : Bool
	{
		return true;
	}

}

class AISpiderbotFindBoredMovePosition extends AIFindPositionAroundSelf
{
	editable inlined var m_maxWanderDistance : AIArgumentMapping;

	protected override function Activate( context : ScriptExecutionContext )
	{
		m_angle = 330.0;
		m_angleOffset = 180.0;
	}

	protected override function AdditionalOutcomeVerification( context : ScriptExecutionContext ) : Bool
	{
		if( Vector4.Distance( ScriptExecutionContext.GetArgumentObject( context, 'FriendlyTarget' ).GetWorldPosition(), m_finalPosition ) > ( ( Float )( ScriptExecutionContext.GetMappingValue( context, m_maxWanderDistance ) ) ) )
		{
			return false;
		}
		return true;
	}

}

class AISpiderbotCheckIfFriendlyMoved extends AIAutonomousConditions
{
	editable inlined var m_maxAllowedDelta : AIArgumentMapping;

	protected override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		return Vector4.Distance( ScriptExecutionContext.GetArgumentObject( context, 'FriendlyTarget' ).GetWorldPosition(), ScriptExecutionContext.GetArgumentVector( context, 'FriendlyTargetLastPosition' ) ) > ( ( Float )( ScriptExecutionContext.GetMappingValue( context, m_maxAllowedDelta ) ) );
	}

}

class AIFindPositionAroundTarget extends AIbehaviortaskScript
{

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var angleStep : Float;
		var angle : Float;
		var orientation : Quaternion;
		var quat : Quaternion;
		var currentPosition : Vector4;
		var potentialPosition : Vector4;
		var bestPosition : Vector4;
		var navigationPath : NavigationPath;
		var fw : NavigationFindWallResult;
		var target : weak< GameObject >;
		var friendlyTarget : weak< GameObject >;
		angleStep = 15.0;
		target = ScriptExecutionContext.GetArgumentObject( context, 'CombatTarget' );
		friendlyTarget = ScriptExecutionContext.GetArgumentObject( context, 'FriendlyTarget' );
		if( !( target ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		orientation = target.GetWorldOrientation();
		currentPosition = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		for( angle = 90.0; angle < 270.0; angle += angleStep )
		{
			Quaternion.SetIdentity( quat );
			Quaternion.SetZRot( quat, Deg2Rad( angle ) );
			quat = orientation * quat;
			potentialPosition = target.GetWorldPosition() + ( Quaternion.GetForward( quat ) * RandRangeF( 2.5, 3.5 ) );
			navigationPath = GameInstance.GetAINavigationSystem( GetGame( context ) ).CalculatePathForCharacter( ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), potentialPosition, 0.2, ScriptExecutionContext.GetOwner( context ) );
			fw = GameInstance.GetAINavigationSystem( GetGame( context ) ).FindWallInLineForCharacter( target.GetWorldPosition(), potentialPosition, 0.2, ScriptExecutionContext.GetOwner( context ) );
			if( ( ( ( navigationPath != NULL ) && fw.status == worldNavigationRequestStatus.OK ) && !( fw.isHit ) ) && ( Vector4.Distance( currentPosition, friendlyTarget.GetWorldPosition() ) < 25.0 ) )
			{
				if( Vector4.IsZero( bestPosition ) || ( Vector4.Distance( currentPosition, potentialPosition ) < Vector4.Distance( currentPosition, bestPosition ) ) )
				{
					bestPosition = potentialPosition;
				}
			}
		}
		if( !( Vector4.IsZero( bestPosition ) ) )
		{
			ScriptExecutionContext.SetArgumentVector( context, 'ForwardPosition', bestPosition );
			return AIbehaviorUpdateOutcome.SUCCESS;
		}
		return AIbehaviorUpdateOutcome.FAILURE;
	}

}

class AISetHealthRegenerationState extends AIbehaviortaskScript
{
	editable var healthRegeneration : Bool;

	protected override function Activate( context : ScriptExecutionContext )
	{
		var emptyModifier : StatPoolModifier;
		if( healthRegeneration )
		{
			GameInstance.GetStatPoolsSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RequestResetingModifier( ScriptExecutionContext.GetOwner( context ).GetEntityID(), gamedataStatPoolType.Health, gameStatPoolModificationTypes.Regeneration );
		}
		else
		{
			GameInstance.GetStatPoolsSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).RequestSettingModifier( ScriptExecutionContext.GetOwner( context ).GetEntityID(), gamedataStatPoolType.Health, gameStatPoolModificationTypes.Regeneration, emptyModifier );
		}
	}

}

class AISetAutocraftingState extends AIbehaviortaskScript
{
	editable var newState : Bool;

	protected override function Activate( context : ScriptExecutionContext )
	{
		var autocraftSystem : AutocraftSystem;
		var autocraftActivateRequest : AutocraftActivateRequest;
		var autocraftDeactivateRequest : AutocraftDeactivateRequest;
		autocraftSystem = ( ( AutocraftSystem )( GameInstance.GetScriptableSystemsContainer( ScriptExecutionContext.GetOwner( context ).GetGame() ).Get( 'AutocraftSystem' ) ) );
		if( newState )
		{
			autocraftActivateRequest = new AutocraftActivateRequest;
			autocraftSystem.QueueRequest( autocraftActivateRequest );
		}
		else
		{
			autocraftDeactivateRequest = new AutocraftDeactivateRequest;
			autocraftDeactivateRequest.resetMemory = false;
			autocraftSystem.QueueRequest( autocraftDeactivateRequest );
		}
	}

}

class SelectClosestPlayerThreat extends AIbehaviortaskScript
{

	protected override function Activate( context : ScriptExecutionContext )
	{
		var trackerComponent : TargetTrackerComponent;
		var threats : array< TrackedLocation >;
		var playerPosition : Vector4;
		var tempDistance : Float;
		var closestDistance : Float;
		var closestThreat : Entity;
		var i : Int32;
		trackerComponent = GetPuppet( context ).GetTargetTrackerComponent();
		threats = trackerComponent.GetHostileThreats( false );
		playerPosition = GameInstance.GetPlayerSystem( GetGame( context ) ).GetLocalPlayerMainGameObject().GetWorldPosition();
		for( i = 0; i < threats.Size(); i += 1 )
		{
			tempDistance = Vector4.Distance( playerPosition, threats[ i ].location.position );
			if( ( tempDistance <= closestDistance ) || ( closestDistance == 0.0 ) )
			{
				closestDistance = tempDistance;
				closestThreat = threats[ i ].entity;
			}
		}
		ScriptExecutionContext.SetArgumentObject( context, 'ClosestThreat', ( ( GameObject )( closestThreat ) ) );
	}

}

class SetManouverPosition extends AIbehaviortaskScript
{
	editable var m_distance : Float;
	editable var m_angle : Float;

	protected override function Activate( context : ScriptExecutionContext )
	{
		var manouverDestination : Vector4;
		manouverDestination = ScriptExecutionContext.GetOwner( context ).GetWorldPosition() + ( Vector4.RotByAngleXY( ScriptExecutionContext.GetOwner( context ).GetWorldForward(), m_angle ) * m_distance );
		ScriptExecutionContext.SetArgumentVector( context, 'ManouverPosition', manouverDestination );
	}

}

class IsAnyThreatClose extends AIAutonomousConditions
{
	editable var m_distance : Float;

	protected override function Activate( context : ScriptExecutionContext )
	{
		SetUpdateInterval( context, RandomizeOffsetForUpdateInterval( 0.2 ) );
	}

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		var trackerComponent : TargetTrackerComponent;
		var threats : array< TrackedLocation >;
		var puppetPosition : Vector4;
		var distance : Float;
		var i : Int32;
		trackerComponent = GetPuppet( context ).GetTargetTrackerComponent();
		threats = trackerComponent.GetThreats( false );
		puppetPosition = ScriptExecutionContext.GetOwner( context ).GetWorldPosition();
		for( i = 0; i < threats.Size(); i += 1 )
		{
			distance = Vector4.Distance( puppetPosition, threats[ i ].location.position );
			if( distance <= m_distance )
			{
				ScriptExecutionContext.SetArgumentObject( context, 'ClosestThreat', ( ( GameObject )( threats[ i ].entity ) ) );
				return true;
			}
		}
		return false;
	}

}

class RemoveCommand extends AIbehaviortaskScript
{
	protected editable inlined var m_inCommand : AIArgumentMapping;

	protected override function Activate( context : ScriptExecutionContext )
	{
		ScriptExecutionContext.SetMappingValue( context, m_inCommand, NULL );
	}

}

